
Hi Nina, Thanks so much for the suggestions and the helpful tests! For method 2, I defined the disk to have a slightly larger height (e.g., 2.02 kpc) for selecting an isocontour surface of cylindrical_z = 2.0 kpc to avoid having all zeros. If I printed the selected values, it would be an array of [2.0, 2.0, ..., 2.0], because the ds.surface sampling method (marching cubes) interpolated to that exact planar value. So methods 1 and 2 will not have the same data selection by default (one is grid-based, the other from interpolation). I still wonder why these two surface-based methods would return different fluxes. Thanks for suggesting the volume-based solution using ds.include_above/below, I will try this! For the yt developers/community users, I would still love to hear your insights on the surface.calculate_flux method: It seems very useful for, e.g., calculating fluxes through curved surfaces like the side of a disk or a sphere, but since this test on a flat surface doesn't pass, I'm wondering how to interpret the results. Thanks again! Jingyao On Wed, Apr 26, 2023 at 8:08 AM Nina Akerman <akermannia@gmail.com> wrote:
Hi Jingyao,
Regarding the method 2, I have never worked with ds.surface, but looking at yt wiki I’m not sure it is what you need here. As a sanity check, I asked to print cylindrical_z of disk_upper_surf cells, and I think it’s all zeros, since I never got printed anything:
for i in range(len(disk_upper_surf['cylindrical_z'])): if disk_upper_surf['cylindrical_z'][i] < 0: print('gotcha’)
for i in range(len(disk_upper_surf['cylindrical_z'])): if disk_upper_surf['cylindrical_z'][i] > 0: print('gotcha')
So with ds.surface you select *exactly* the planar cells. The way I usually select data is with include_above/include_below:
my_disk = ds.disk(ds.domain_center, [0.0, 0.0, 1.0], 10 * kpc, 2.02 * kpc) disk_upper_surf = my_disk.include_above('cylindrical_z', 0, 'kpc')
Could you please check if it works? Then you I think it would be good to compare the results method 1 and method 2 give on *exactly* the same data selection, so mass_flux = np.sum(disk_upper_surf[‘density'], ...)
Finally, I haven’t used calculate_flux either, frankly, I didn’t know it even existed. Again, from the wiki it’s not quite clear how it works, especially if you’re interested in the flux specifically from velocity_z, not from all the velocities. Here is my (probably overly complicated) solution to this problem that I often use in my work:
from yt.units import kpc #(we’ll need it)
def _momentum(field, data): return data['cell_mass'] * data['velocity_cylindrical_z’]
ds.add_field(('gas', 'momentum'), units='kpc * Msun/yr', function=_momentum, sampling_type='cell’)
my_disk = ds.disk(ds.domain_center, [0.0, 0.0, 1.0], 10 * kpc, 2.02 * kpc) disk_upper_surf = my_disk.include_above('cylindrical_z', 0, 'kpc')
inflow = disk_upper_surf.include_below('momentum_z', 0) outflow = disk_upper_surf.include_above('momentum_z', 0)
mass_inf = inflow.sum('momentum_z') / (height * kpc) mass_outf = outflow.sum('momentum_z') / (height * kpc)
The idea here here is that mass flux is sum(m * v_z) / z So I first create a new cell type that is momentum p = m * v. inflow and outflow allow me to get negative and positive mass flux values separately, which I do with mass_outf and mass_outf, where height is the vertical height, which in your case is 2.02 kpc (from 0 to the height in your my_disk definition). Btw, why is it 2.02 not just 2? Mass flux is then simply mass_inf + mass_outf
Hope it helps! Let me know, Nina
-- Jingyao Zhu (she/her/hers) Columbia University | Dept of Astronomy