-
Notifications
You must be signed in to change notification settings - Fork 108
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
Datacube core #1669
Datacube core #1669
Conversation
Codecov Report
❗ Your organization needs to install the Codecov GitHub app to enable full functionality. @@ Coverage Diff @@
## develop #1669 +/- ##
===========================================
+ Coverage 41.05% 41.09% +0.03%
===========================================
Files 189 190 +1
Lines 43568 43621 +53
===========================================
+ Hits 17888 17926 +38
- Misses 25680 25695 +15
|
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.
Addressed PR comments
pypeit/coadd3d.py
Outdated
""" | ||
Utility function to provide the world coordinate system of the datacube | ||
""" | ||
return wcs.WCS(self.head0) |
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 can see the benefit of not computing ivar
repeatedly, but I worry that we'll then be carrying around self._ivar
and self.ivar
, which seems a little messy to me. I also suspect it's rare that the ivar
will ever be used... and it's also pretty quick to generate self.wcs
. Also, is there a point in having the @property
and function in this case? Couldn't we just have self.ivar = utils.inverse(self.sig**2)
when a DataCube gets loaded?
Overall, I'm tempted to leave things the way they are, but it might be that I'm not appreciating the full benefit of this, so if you think this really ought to be done, then should it be done in the from_file()
routine?
pypeit/coadd3d.py
Outdated
msgs.info("Adopting a square pixel spatial scale of {0:f} arcsec".format(3600.0 * self._dspat)) | ||
# If the user has not specified the spectral sampling, then set it now to the largest value | ||
if self._dwv is None: | ||
self._dwv = np.max(self._specscale) |
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.
Can you return these values instead of assigning to self. For a small number of return values that makes the control flow more transparent.
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.
Good catch - I agree 👍 Actually, I decided to move this entire section of code to core.
pypeit/coadd3d.py
Outdated
sensfunc = self.flux_spline(senswave) | ||
|
||
# Generate a datacube | ||
outfile = datacube.get_output_filename("", self.cubepar['output_filename'], True, -1) |
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.
My advice is to create the this outfile name int he init method or before coadd is called. And then have self.coadd(outfile) be the calling sequence, to make it clear that this coadds and writes to disk.
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.
This is a good idea, but there is also a method here that writes out separate datacubes (when align=True
and combine=False
). I've just realised that this is confusing, given that the routine is called "coadd"... So I've renamed the routine to run()
, which I think is more consistent with the rest of PypeIt anyway.
It has made me realise though that this routine is more about making datacubes, and not necessarily "coadding"... Coadding is just one possible outcome. So I wonder if this might be confusing, and we should name it something else (perhaps spec3dobj
is more apt)?
pypeit/coadd3d.py
Outdated
|
||
# If the user is aligning or combining, the spatial scale of the output cubes needs to be consistent. | ||
# Set the spatial and spectral scales of the output datacube | ||
self.set_voxel_sampling() |
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.
See my comments above, set_voxel_sampling should return something. As a general rule, control flows like
self.do_x()
self.do_y()
self.do_z()
Are not only inscrutable, but often do not manage variable scope and are prone to things changing accidentally changing behind the scenes, like if x changes variables that are then required for y. I know that everything is an attribute of the object, but actually that should not really be the case. The fewer global variables the better.
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.
Yep - good catch - as mentioned above, I've moved this function to core.
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.
Thanks for the major refactor @rcooke-ast. I have only a few relatively minor comments. Only one place self.compute_weights, where I think it makes more sense for a method to be in core. Many thanks!
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.
OK, I think that addresses all comments of @jhennawi and @kbwestfall. I'll run the dev suite again to make sure I haven't broken anything in the process!
pypeit/coadd3d.py
Outdated
msgs.info("Adopting a square pixel spatial scale of {0:f} arcsec".format(3600.0 * self._dspat)) | ||
# If the user has not specified the spectral sampling, then set it now to the largest value | ||
if self._dwv is None: | ||
self._dwv = np.max(self._specscale) |
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.
Good catch - I agree 👍 Actually, I decided to move this entire section of code to core.
pypeit/coadd3d.py
Outdated
produce a spec3d file, which is a DataCube representation of a PypeIt spec2d frame for SlicerIFU data. | ||
""" | ||
# Initialise variables | ||
wave_ref = 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.
Sounds good - If I understand correctly, I've added this information to the docstring.
pypeit/coadd3d.py
Outdated
|
||
# If the user is aligning or combining, the spatial scale of the output cubes needs to be consistent. | ||
# Set the spatial and spectral scales of the output datacube | ||
self.set_voxel_sampling() |
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.
Yep - good catch - as mentioned above, I've moved this function to core.
pypeit/coadd3d.py
Outdated
sensfunc = self.flux_spline(senswave) | ||
|
||
# Generate a datacube | ||
outfile = datacube.get_output_filename("", self.cubepar['output_filename'], True, -1) |
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.
This is a good idea, but there is also a method here that writes out separate datacubes (when align=True
and combine=False
). I've just realised that this is confusing, given that the routine is called "coadd"... So I've renamed the routine to run()
, which I think is more consistent with the rest of PypeIt anyway.
It has made me realise though that this routine is more about making datacubes, and not necessarily "coadding"... Coadding is just one possible outcome. So I wonder if this might be confusing, and we should name it something else (perhaps spec3dobj
is more apt)?
pypeit/coadd3d.py
Outdated
Compute the relative weights to apply to pixels that are collected into the voxels of the output DataCubes | ||
""" | ||
# Calculate the relative spectral weights of all pixels | ||
if self.numfiles == 1: |
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 do agree, and I started to rework this, but then realised that this routine calls generate_image_subpixel
, which is located at the bottom of this coadd3d.py
file (outside of this class). It required a big change throughout a lot of the code (and avoid circular imports), and I've now moved considerably more code over to core (for better or worse).
pypeit/coadd3d.py
Outdated
Compute the relative weights to apply to pixels that are collected into the voxels of the output DataCubes | ||
""" | ||
# Calculate the relative spectral weights of all pixels | ||
if self.numfiles == 1: |
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.
This was a painful change, but I think it's all there now.
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 had a couple of lingering comments/responses, but I'm happy to approve now.
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.
Thanks again @kbwestfall - all comments addressed... I think!
pypeit/coadd3d.py
Outdated
msgs.info("Loading skysub frame:" + msgs.newline() + opts_skysub) | ||
try: | ||
spec2DObj_sky = spec2dobj.Spec2DObj.from_file(opts_skysub, self.detname) | ||
skysub_exptime = fits.open(opts_skysub)[0].header['EXPTIME'] |
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.
Yes, that is a good point - it's included in the header 🤦♂️ so I've done that now... thanks for spotting that! Fixed throughout.
pypeit/coadd3d.py
Outdated
msgs.info("Spatial shift of cube #{0:d}:" + msgs.newline() + | ||
"RA, DEC (arcsec) = {1:+0.3f} E, {2:+0.3f} N".format(ff + 1, | ||
self.opts['ra_offset'][ff], | ||
self.opts['dec_offset'][ff])) |
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.
Sorry - I somehow missed this during the first pass!
This offset is usually something that the user sets at the telescope (i.e. it's usually a dither or sky offset - Like moving the telescope "5 arcsec East and 2 arcsec North", which already includes the cos(dec) factor). I think this is more practical than specifying two separate RA/Dec combinations (which is what appears to be needed by the SkyOffsetFrame).
Perhaps I need to clarify the docs on this?
pypeit/coadd3d.py
Outdated
""" | ||
Utility function to provide the world coordinate system of the datacube | ||
""" | ||
return wcs.WCS(self.head0) |
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.
Ahh, I think I see. No one will actually no about self._ivar
, it will just be a convenience variable so that when the @property
ivar is called, it doesn't (necessarily) compute the 1/sig**2
. I think this is a reasonable compromise. I've implemented the change you have suggested, and I initialise self._ivar=None
. Same for the WCS
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.
Thanks for all the hard work here @rcooke-ast
This looks like a large PR, but it's a relatively simple refactoring to make the CoAdd3D look a lot more like CoAdd2D. Here are the main changes:
IFU
reduction is replaced throughout the code bySlicerIFU
, with a view to possibly supportFiberIFU
as another reduction mode in the (distant) future.pypeit.core.datacube.py
has been refactored tocore
routines and code that usesPypeIt
-specific objects.pypeit.core.datacube.py
have been moved todeprecated
I should emphasise that there's virtually no new code here. It's just a reorganising of the code that makes datacubes so it's easier for others to read, improve, and it mostly just required writing a lot more docstrings... joy!
I'm pretty sure that nothing is broken, but I'll run the tests just to be sure...