-
Notifications
You must be signed in to change notification settings - Fork 279
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
BUG: calculate default depth for off axis projections #5081
base: main
Are you sure you want to change the base?
BUG: calculate default depth for off axis projections #5081
Conversation
@@ -101,15 +105,7 @@ def get_oblique_window_parameters( | |||
|
|||
w = tuple(el.in_units("code_length") for el in width) | |||
bounds = tuple(((2 * (i % 2)) - 1) * w[i // 2] / 2 for i in range(len(w) * 2)) | |||
if get3bounds and depth is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we initially calculate a depth equal to the diagonal + a bit, we don't need this extra logic here as the off-axis projection calls to this function will always have a depth.
@@ -639,7 +639,6 @@ def _generate_image_and_mask(self, item) -> None: | |||
self.bounds[5] - self.bounds[4], | |||
) | |||
) | |||
depth = dd.depth[0] if dd.depth is not None else None |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removing this because the depth sanitization before dd
creation takes care of this now.
if depth is None: | ||
# off-axis projection, depth not specified | ||
# -> set 'large enough' depth using half the box diagonal + margin | ||
depth = np.linalg.norm(ds.domain_width.in_units("code_length")) * 1.02 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why 1.02? Does it need to be an epsilon that large?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why 1.02?
Good question -- I was just preserving the 2% epsilon in this line
yt/yt/visualization/plot_window.py
Line 111 in e6e5f1f
bounds = bounds + (-0.51 * diag, 0.51 * diag) |
Does it need to be an epsilon that large?
I suspect it could be smaller, and for periodic datasets in particular a 2% epsilon might not be ideal... @nastasha-w was there reasoning behind the magnitude of margin you used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least for SPH data, periodicities are applied before rotation, and are never taken to be periodic in the rotated coordinates. Therefore, the large margin shouldn't cause trouble, but a smaller value ought to be fine as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I also figured that the half box diagonal would be a very large margin for most line of sight directions anyway
This seems to make sense overall; setting a default depth somewhere should be enough, although TBH it's probably not a great idea in most situations to project a whole box off-axis; in practice that means the depth will vary across the image. It's been a while since I looked into the code and checked what's called when here, but this does seem like something that would break the tests for SPH if done wrong. (I do have a few in there that test if at least roughly the right depth is used.) |
Thanks for looking into this! Should we maybe add an SPH and a grid code off-axis image test to look out for this sort of thing going forward? |
i don't disagree necessarily, but that's what was happening implicitly here: yt/yt/visualization/plot_window.py Lines 107 to 111 in e6e5f1f
So IMO it's clearer to set that default depth explicitly on initialization of the plot window (whether the default depth is the diagonal of the whole domain or something smaller).
I'm not positive on if that's the case for gridded datasets, I'll take a closer look to be sure.
ya, definitely -- I'm very surprised there wasn't already an off-axis image test for gridded data to catch this initially... |
Makes sense! I mostly used some of those more complicated things because I wanted to avoid breaking stuff for e.g., grid code projections. I very much appreciate a more logical/simplified approach.
There aren't for SPH either -- I have some off-axis tests for those, but those are for fake datasets with a small number of particles. I did do a quick visual test though; I'm pasting the code below. It's for off-axis projections and slices through an SPH dataset. I'm guessing something similar would work for other hydro methods. # looks good!
def visual_check_offaxis_projection():
'''
Plot projections along the x, z axes using the axis-aligned
methods, then check against just-off x, z and intermediate
lines of sight to see if we get a nice, continuous rotation.
Note that paths here are system-specific.
'''
simpath = '/Users/nastasha/code/ytdev_misc/sample_data/gizmo_mhd_mwdisk/'
simfile = 'gizmo_mhd_mwdisk.hdf5'
outdir = '/Users/nastasha/code/ytdev_misc/testimgs/'
outfilen_temp = 'sph_projection_test_lineofsight_{projdir}.pdf'
nsteps = 9
projdirs = ['x', 'z'] + [f'step{i}' for i in range(nsteps)]
epsilon = 1e-4
north_vector = [0., 1., 0.] #y-axis
ds = yt.load(simpath + simfile)
source = ds.all_data()
center = [0., 0., 0.]
for projdir in projdirs:
if projdir in ['x', 'y', 'z']:
outfilen = outdir + outfilen_temp.format(projdir=projdir)
projaxis = projdir
title = f'line of sight along the {projdir}-axis'
#dle = ds.domain_left_edge.to("kpc")
center = ds.arr(center, 'kpc')
le = center - ds.quan(30., 'kpc')
re = center + ds.quan(30, 'kpc')
reg = YTRegion(center.to('code_length'), le.to('code_length'),
re.to('code_length'), ds=ds)
# need to specify width *and* region because some giant SPH
# particle intersects the central region
prj = yt.ProjectionPlot(ds, projaxis, ("gas", "density"),
weight_field=None,
buff_size=(400, 400),
center=center,
width=(60, "kpc"),
data_source=reg)
else:
_projdir = projdir + f'of{nsteps}'
outfilen = outdir + outfilen_temp.format(projdir=_projdir)
stepnum = int(projdir[4:])
angle = stepnum / (nsteps - 1.) * 0.5 * np.pi
projaxis = [np.cos(angle + epsilon), 0., np.sin(angle + epsilon)]
title = f'line of sight x- to z-axis: step {stepnum} / {nsteps}'
prj = yt.ProjectionPlot(ds, projaxis, ("gas", "density"),
width=(60, "kpc"),
weight_field=None,
buff_size=(400, 400),
center=center,
data_source=source,
north_vector=north_vector,
depth=(60, 'kpc'))
prj.annotate_title(title)
prj.save(outfilen)
# looks ok, seems consisitent with projections
def visual_check_offaxis_slice():
'''
Plot projections along the x, z axes using the axis-aligned
methods, then check against just-off x, z and intermediate
lines of sight to see if we get a nice, continuous rotation.
Note that paths here are system-specific.
'''
simpath = '/Users/nastasha/code/ytdev_misc/sample_data/gizmo_mhd_mwdisk/'
simfile = 'gizmo_mhd_mwdisk.hdf5'
outdir = '/Users/nastasha/code/ytdev_misc/testimgs/'
outfilen_temp = 'sph_slice_test_lineofsight_{projdir}.pdf'
# bounding box recommended at loading
simbounds = [[-335.41967773, -305.92471313, -304.52108765],
[283.54318237, 300.88858032, 379.63751221]]
nsteps = 9
projdirs = ['x', 'z'] + [f'step{i}' for i in range(nsteps)]
epsilon = 1e-4
north_vector = [0., 1., 0.] #y-axis
ds = yt.load(simpath + simfile, bounding_box=simbounds)
center = ([0., 0., 0.], 'kpc')
width = (60., "kpc")
for projdir in projdirs:
if projdir in ['x', 'y', 'z']:
outfilen = outdir + outfilen_temp.format(projdir=projdir)
projaxis = projdir
title = f'line of sight along the {projdir}-axis'
slc = yt.SlicePlot(ds, projaxis, ("gas", "density"),
center=center, width=width,
buff_size=(400, 400),)
else:
_projdir = projdir + f'of{nsteps}'
outfilen = outdir + outfilen_temp.format(projdir=_projdir)
stepnum = int(projdir[4:])
angle = stepnum / (nsteps - 1.) * 0.5 * np.pi
projaxis = [np.cos(angle + epsilon), 0., np.sin(angle + epsilon)]
title = f'line of sight x- to z-axis: step {stepnum} / {nsteps}'
slc = yt.SlicePlot(ds, projaxis, ("gas", "density"),
center=center, width=width,
buff_size=(400, 400), north_vector=north_vector)
slc.annotate_title(title)
slc.save(outfilen)
if __name__ == '__main__':
visual_check_offaxis_projection()
visual_check_offaxis_slice() |
Thanks for the example tests! I think I'll open an issue for adding off axis projections tests so we can get this bug fix in a bit faster. I think I'd also like to address the magnitude of the margin in a follow up as well, @matthewturk how do you feel about that? |
sounds good to me |
Ok, so I think that this one is good to go then, but needs an official approval from someone (@matthewturk @nastasha-w or anyone) |
Close #5080
Pretty sure this won't break the SPH rendering.... we'll see how the tests go. but would be good to have confirmation from @nastasha-w