-
Notifications
You must be signed in to change notification settings - Fork 40
Toast 3 Work in Progress #369
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
base: master
Are you sure you want to change the base?
Conversation
I think the easiest way to provide feedback would be to make an export of the notebook to a Python script in a separate pull request, so we can do line by line feedback there. Then the pull request can be closed without merging. |
Good idea @zonca, will do that soon. |
Ok @zonca, I enabled the
https://app.reviewnb.com//pull/369/files/
and comment on the per-cell level of the intro.ipynb file. Since a lot has changed, there is a switch to "hide previous version". Let me know if that works, since I can't tell if this plugin is usable by everyone. |
Note that the output of the notebook is stripped on github, so refer to the PDF attached to this issue to look at that. |
Updated notebook output, with config section. |
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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.
mention if you can modify this in place or it is read-only. If it is read-only, how do I modify it?
Reply via ReviewNB
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 point, some options are fixed by the OS runtime environment of python, but some can be changed after toast is imported. Will give more details.
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.
Added text about setting log level manually or through environment. Same with threading.
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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.
better specify that "traditional CPU systems" means a supercomputer, otherwise it seems it is also required on a laptop.
Reply via ReviewNB
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.
Well, if the user has an AMD Ryzen workstation with 16 cores (for example), then they probably want to use mpi4py if they are doing something more with toast than just running a notebook with a few samples. I will definitely clarify though. I have started an "intro_parallel.ipynb" where I am going to discuss using IPython.parallel with mpi4py. I'll reference that in the serial notebook.
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.
Tried to clarify that toast parallelism is mainly through MPI, so that any system with more than a few cores will benefit from having mpi4py installed.
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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.
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 idea. astropy.units are a new addition to toast, and currently only used in the new Operator traits. I need to systematically go through the codebase and add support.
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 converted the fake focalplane simulation and plotting functions to use units. However, I'll wait on the rest of the instrument classes until we can revisit the overall plan for those.
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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 detlabels
is None, you could use the keys as labels, so we avoid to build the trivial dict x:x
.
please use keyword arguments for all inputs, so people don't have to look at the help of plot_focalplane
For the color, what about using endswith("A")
instead of enumerating?
Reply via ReviewNB
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, this is cleaned up.
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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.
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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.
either it is an attribute, so other_simsat.config
or it is a method then needs to have a verb in the name:
other_simsat.get_config()
Reply via ReviewNB
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.
The methods are now get_config()
and get_class_config()
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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.
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 was inspired by the traitlets methods traits()
and class_traits()
, but I can add a "get_" in there if it is more clear.
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 please
tutorial/01_Introduction/intro.ipynb
Outdated
@@ -8,7 +8,7 @@ | |||
"source": [ |
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 heard about it but first time I used
@tskisner, I think the Toast interface looks really good, good job! I have a bit more feedback in the notebook. |
Thanks @zonca for the detailed review, just what I was looking for! On overall question for objects that act like a dictionary, but which have other state information. For example,
actually creates a
And then have setitem check that the number of samples matches that in the observation. This did not seem as convenient to me, but I do hate typing :-) For the MPI shared memory class, I could replace the set method like this:
or
or something else? |
inside def __setitem__(self, key, value):
# if key is undefined
data = DetectorData(self.detectors, (self.n_sample,)+ value.shape, dtype=value.dtype)
# set this into the dict for the set I don't understand, what do you need the |
I'll try to clarify... The For the MPIshared class, the |
I think I understand now- you want to allow
I can implement that, but still not sure it is more convenient. On the other hand, no reason not to support multiple ways of assignment! |
Ahhh, now I see- you can create the full-size DetectorData object first, and then the slicing notation can be applied when actually assigning from the RHS. Ok, I will try this out. I agree this would be a more convenient interface. I'll also try to modify the MPIshared package to make the set() method optional at the cost of a precalculation. |
I have added setitem support to the upstream https://github.com/tskisner/pshmem/releases/tag/0.2.5 And this new version is available on PyPI: https://pypi.org/project/pshmem/0.2.5/ So now I can work on using that syntax in toast. |
Ok, I think I have concluded that the import numpy as np
class DetData:
def __init__(self, ndet, shape, dtype):
self.dtype = np.dtype(dtype)
self.shape = [ndet]
self.flatshape = ndet
for s in shape:
self.shape.append(s)
self.flatshape *= s
self.flatdata = np.zeros(self.flatshape, dtype=self.dtype)
self.data = self.flatdata.reshape(self.shape)
def __getitem__(self, key):
print("DetData getitem {}".format(key))
return self.data[key]
def __setitem__(self, key, value):
print("DetData setitem {}".format(key))
self.data[key] = value
def __repr__(self):
return str(self.data)
class Mgr:
def __init__(self, ndet):
self.ndet = ndet
self.d = dict()
def create(self, name, shape, dtype):
self.d[name] = DetData(self.ndet, shape, dtype)
def __getitem__(self, key):
print("Calling Mgr getitem")
if key not in self.d:
# Cannot guess what shape and dtype the user wants
pass
return self.d[key]
def __setitem__(self, key, value):
print("Calling Mgr setitem")
self.d[key] = value
mgr = Mgr(2)
# This works fine, as expected:
mgr.create("A", (3, 4), np.int32)
mgr["A"][1, 0:2, 0:2] = 5
print("mgr['A'] = \n", mgr["A"])
# This works, but it is annoying, since the user has to know the name
# of the DetData class and also has to get information from the Mgr
# class:
mgr["B"] = DetData(mgr.ndet, (3, 4), np.int32)
mgr["B"][1, 0:2, 0:2] = 5
print("mgr['B'] = \n", mgr["B"])
# The code below is actually doing:
#
# Mgr.__getitem__("C").__setitem(tuple, 5)
#
# Which means that the DetData class would have to be instantiated in
# Mgr.__getitem__() where we don't know the correct shape of the buffer
# to create. Obviously this gives a key error:
mgr["C"][1, 0:2, 0:2] = 5
print("mgr['C'] = \n", mgr["C"]) The output of the above script is:
|
you first need to create the thing before slicing it: mgr = Mgr(2)
mgr["A"] = np.zeros((3,4), dtype=np.int32)
mgr["A"][1, 0:2, 0:2] = 5 It doesn't work now, but it should be implementable. |
Hi @zonca, thanks for your patience, and sorry if I am being dense :-) Below I updated the toy code to be closer to the real case. The central problem is that when assigning data (see the import numpy as np
class DetData:
def __init__(self, ndet, shape, dtype):
self.dtype = np.dtype(dtype)
self.shape = [ndet]
self.flatshape = ndet
for s in shape:
self.shape.append(s)
self.flatshape *= s
self.flatdata = np.zeros(self.flatshape, dtype=self.dtype)
self.data = self.flatdata.reshape(self.shape)
def __getitem__(self, key):
return self.data[key]
def __setitem__(self, key, value):
self.data[key] = value
def __repr__(self):
return str(self.data)
class Mgr:
def __init__(self, ndet, nsample):
self.ndet = ndet
self.nsample = nsample
self.d = dict()
def create(self, name, sample_shape, dtype):
self.d[name] = DetData(self.ndet, (self.nsample,) + sample_shape, dtype)
def __getitem__(self, key):
return self.d[key]
def __setitem__(self, key, value):
if isinstance(value, DetData):
self.d[key] = value
else:
# This is an array, verify that the number of dimensions match
sample_shape = None
if len(value.shape) < 2:
raise RuntimeError("Assigned array does not have sufficient dimensions")
elif len(value.shape) == 2:
# We assume the user meant one scalar value per sample...
sample_shape = (1,)
else:
# The first two dimensions are detector and sample. The rest of the
# dimensions are the data shape for every sample and must be fully
# specified when creating data like this.
sample_shape = value.shape[2:]
print(
"Creating DetData with {} dets, {} samples, {} samp shape".format(
self.ndet, self.nsample, sample_shape
)
)
self.d[key] = DetData(
self.ndet, (self.nsample,) + sample_shape, value.dtype
)
# If the value has the full size of the DetData object, then we can do the
# assignment, if not, then we cannot guess what detector / sample slice
# the user is trying to assign.
if (value.shape[0] == self.ndet) and (value.shape[1] == self.nsample):
# We can do it!
self.d[key][:] = value
# 2 detectors and 5 samples
mgr = Mgr(2, 5)
# This works fine, as expected:
mgr.create("A", (3, 4), np.int32)
mgr["A"][1, 2:3, 0:2, 0:2] = 5
print("mgr['A'] = \n", mgr["A"])
# This works, but it is annoying, since the user has to know the name
# of the DetData class and also has to get information from the Mgr
# class:
mgr["B"] = DetData(mgr.ndet, (mgr.nsample, 3, 4), np.int32)
mgr["B"][1, 2:3, 0:2, 0:2] = 5
print("mgr['B'] = \n", mgr["B"])
# This creates a buffer with the full number of detectors and samples and uses the
# last dimensions of the RHS to determine the shape of the data per sample. However,
# we have no information about what LHS slice we are assigning the RHS data to. UNLESS
# the user gives a RHS data with the full n_detector x n_sample data set:
# mgr["C"] is created by not assigned, since we don't know where to assign the data
# along the first 2 axes (detector and sample).
mgr["C"] = np.ones((1, 1, 3, 4), dtype=np.int32)
mgr["C"][1, 2:3, 0:2, 0:2] = 5
print("mgr['C'] = \n", mgr["C"])
# mgr["D"] is created AND assigned, since we specify data of the full size.
mgr["D"] = np.ones((mgr.ndet, mgr.nsample, 3, 4), dtype=np.int32)
mgr["D"][1, 2:3, 0:2, 0:2] = 5
print("mgr['D'] = \n", mgr["D"]) I think that the How about we support cases
Does that seem acceptable? |
here: # mgr["C"] is created by not assigned, since we don't know where to assign the data
# along the first 2 axes (detector and sample).
mgr["C"] = np.ones((1, 1, 3, 4), dtype=np.int32)
mgr["C"][1, 2:3, 0:2, 0:2] = 5
print("mgr['C'] = \n", mgr["C"]) This case is not supported, the user needs to initialize the array in 2 ways:
so the use case is: # provide just 1 timeline, it will be copied to all detectors, we should support both 3D and 4D
mgr["C"] = np.ones((mgr.n_samples, 3, 4), dtype=np.int32)
# or
mgr["C"] = np.ones((1, mgr.n_samples, 3, 4), dtype=np.int32)
mgr["C"][1, 2:3, 0:2, 0:2] = 5
print("mgr['C'] = \n", mgr["C"]) inside |
Ok, no problem that sounds good. Will work on implementing and addressing your other feedback. |
Check out this pull request on See visual diffs & provide feedback on Jupyter Notebooks. Powered by ReviewNB |
* fixing the detset error * adding a test for common mode * running format source * Add support for user-generated list of common mode detectors --------- Co-authored-by: GIUSEPPE PUGLISI <[email protected]> Co-authored-by: Reijo Keskitalo <[email protected]>
* support locking the azimuth range * Add SPECIAL tag for skipped schedule entries
* Allow writing out the noise-weighted observation matrix * Remove unnecessary messages from co-add * Add script to co-add obs matrices * Add a compiled kernel for co-adding observation matrices * Skip zeros in observation matrix calculation * Remove debug statements * Fix warning about map units * Fix index error * WIP * add unit test for noiseweighted matrices and fix issues that were found * Remove obsolete debugging statements * Fix a deadlock, add an explicit barrier to avoid a race condition in the unit test * Workaround for serial cases
* Update default StokesWeights operator which generates the elements of the pointing matrix: * Update sign convention to match accompanying document (to be added to documentation) given our recent formalization of the focalplane coordinate frame. * When using a HWP, require per-detector offsets in the focalplane table describing the fixed angle from focalplane frame X-axis to detector frame X-axis. * Correctly handle the cases of fixed HWP angle versus no HWP. * Add unit tests that cover several permutations of I/Q/U sky pixel values, fixed HWP angles, and detector orientations. * Small consistency fix for poles when doing quat to ISO conversion. Fix conviqt operator and tests. * Fix jax stokes_weights kernel. Address review comments. Additional changes made to clean up accelerator use: * Helper functions for printing OpenMP target buffer table * Clean up duplicate code in Data accelerator movement * Clean ups to DetectorData accelerator movement * Add use_accel argument to Calibrate operator, in analogy to mapmaking operator * Clean ups to TemplateMatrix accelerator use * Introduce new temporary object specification along with requires / provides. Useful for operators calling other operators for a subset of their products * Fix Pipeline logic tracking staged and unstaged data for hybrid host / accelerator operator case * Add new unit test for Offset template use within an accelerator enabled pipeline * Run format_source * Remove temporary object concept from operator * Clean up dependencies so that detector data which is optionally created by an operator is listed in requires(), so that it is moved if it exists.
* Collection of improvements for working with real ground data: * Add a new operator (AzimuthIntervals) which uses smoothed versions of the azimuth velocity and acceleration to detect azimuth scan patterns and define the typical intervals. * Add support for per-detector flags that apply to an entire observation. These can be set / updated and use the same masks as per-sample detector flags. These flags can now be used to optionally control selection of local detectors for processing. * Add new operator (FlagNoiseFit) which uses the analytic fit to the noise estimate to flag detectors for an observation. The current implementation can flag outliers in both the estimated NET and knee frequency values. * Visualization: small fixes to ipython widget and improvements to WCS and noise estimation plotting functions. * Set the SimGround bitmask to enable turnarounds in the unit tests * Allow optionally running with a single process group in the unit tests, even if using >= 2 processes. * Pull out duplicate code to compute the detector scan range for and observation. Use this common function in atmosphere simulation and WCS projection autoscaling. * When fitting an analytic 1/f model to estimated noise PSDs, allow overriding the frequency range that is considered the white noise plateau. * Address review comments
* Add tool to plot schedules * Add script to analyze schedules * Add background image to hitmap projection
* Add support for HWP in SSS by using InterpolateHealpixMap * SSS now requires stokes weights
Add error message
* Fully functional implementation * Use the helper function for string parsing
…s. (#835) * This work fixes the spt3g code in light of recent changes to intervals. - Add the new PyPI spt3g package to the CI test environment. - Fix stale docstring. - When redistributing intervals, use extra care with timestamps that fall fall on process boundaries. - Fix off-by-one when exporting intervals, due to new exclusive last sample. * Fix typo
* Add support for reading and writing WCS maps in HDF5 format * Add support for per-detector WCS maps * Add one more suffix * Add support for getting WCS from FITS header * Add unit test for HDF5 detector map scanning * WIP * Passing unit tests again * Remove debug statements * WIP * Fix unit test and a corner case it automatic bounds detection * Finally consistent * Fix allgather * Remove 'parallel' from the distributed WCS I/O method names and add 'serial' to the serial method names * Make row/column positions more explicit * Move I/O routines for the PixelData class. (#836) * Move I/O routines for the PixelData class. This creates `read()` and `write()` methods for the PixelData class that can work with both WCS and Healpix, as well as HDF5 and FITS formats. These use the existence of the PixelDistribution.wcs member to distinguish between WCS and Healpix data, and they use the filename extension to determine the format. The serial I/O routines can now claim the shorter names (read_wcs, write_healpix, etc) without conflicts. The low-level helper functions for gathering / broadcasting map chunks are left in their current place outside the PixelData class, since that class is becoming large. * Address review comments: - When creating a PixelDistribution with healpix pixelization, store the NEST / RING ordering similar to how we store the WCS information - Break up `PixelData.write()` and `PixelData.read()` into subroutines for each pixelization type and file format. - Remove `healpix_nest` argument to read / write throughout the code, since that is now tracked by the PixelDistribution. --------- Co-authored-by: Theodore Kisner <[email protected]>
- Update RELEASE file - Inside the cibuildwheel environment, restrict numpy to <2.3. That version was just released and some of our dependencies seem to trigger an attempted local compilation of numpy, which is a bad idea.
* Add binned ground template to filterbin * Use explicit indexing for very sparse templates * Update copyright * Clean up comments, relax definition of sparse template
* initial attempt at having demodulation return pol_only * Add support for QU mode in stokes weights * Stokes fix in demodulation qu only * replace pol_only with mode to support intensity-only processing * Update src/toast/ops/demodulation.py Co-authored-by: Copilot <[email protected]> * Add healpix support for scanning pure QU * Tiny unrelated tweaks that don't merit a separate PR --------- Co-authored-by: AERAdler <[email protected]> Co-authored-by: Copilot <[email protected]>
… writing out the covariance matrix (#842)
* Store Az min/max metadata in the AzimuthIntervals operator * Move azimuth range calculation into a separate operator (#844) * Fix broadcast pattern of min / max values --------- Co-authored-by: Reijo Keskitalo <[email protected]>
This situation may occur when demodulating data with cut detectors or situations where having many processes is useful for simulation operations that are independent of the number of detectors. Specific changes include: - In distribute_discrete(), lift the restriction on having more groups than work units. - In the DetectorData class, handle the case where there are no local detectors. - Remove various warning / errors for this situation - Add unit tests that test this "over distribution" of data with more processes than detectors.
* More robust handling of samples that fail to filter * Update src/toast/ops/filterbin.py Copilot-generated fix to my PR. Yay! Co-authored-by: Copilot <[email protected]> * Update src/toast/ops/filterbin.py Another useful catch by copilot. Co-authored-by: Copilot <[email protected]> * Fix a bug where nulling of a template for one detector affected subsequent detectors * Fix unit test * Docstring needs to be unformatted because it contains backslashes * Remember to install the new scripts * Make sure the weights passed to accumulate_observation_matrix is 2D * Another place where intensity-only covariance is returned in 1D * Add the trait to the pixel distribution to signifity it is a HEALPix pixelization * Fix a typo that broke distributed observation matrix building --------- Co-authored-by: Copilot <[email protected]>
* Initial implementation of an overlap script * Update src/toast/scripts/toast_overlap_schedule.py Co-authored-by: Copilot <[email protected]> * Update src/toast/scripts/toast_overlap_schedule.py Co-authored-by: Copilot <[email protected]> * Update src/toast/scripts/toast_overlap_schedule.py Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
* Fix that works for both intervals and spt3g * Fix another corner case in WCS auto_bounds * Change default ground simulation timespan to 2 hours in the unit test helpers * Small fixes to hwpss model operator * Remove debug statement that breaks serial operation --------- Co-authored-by: Theodore Kisner <[email protected]>
The qpoint conversion from AZ / EL to RA / DEC can make use of the temperature, pressure, and humidity of the environment. If a weather object is associated with a site, make use of this information.
* Bump version and run wheel tests * Macos homebrew env already has cmake installed * Restore normal testing workflow
* Add equivalencies to astropy temperature conversions. For conversion of normal temperatures between Kelvin and Celsius, make sure we specify the equivalencies to use. * Fix documentation * Install optional qpoint package for tests
* Add argument for selecting the reference time for boresight rotation; remove unnecessary keywords * Update src/toast/schedule_sim_ground.py Co-authored-by: Copilot <[email protected]> --------- Co-authored-by: Copilot <[email protected]>
* Add a simple operator to apply a "counter 1/f" filter. For (at least) 25 years, the inverse time domain noise covariance has been used as a "change of basis" when solving a generalized least squares problem for the maximum likelihood map in pixel space. For simpler "filter and bin" mapmaking techniques, application of this N_tt'^-1 filter may be useful. This work adds an operator which uses a given noise model for detector PSDs to compute the inverse noise covariance fourier domain kernels for each detector and convolve the timestreams by those. * Add initial unit test. Fix normalization. * More unit test improvements and cleanup
* Fix argument types and add optional rotation * use the user-provided alpha
Hi @zonca and @keskitalo, this PR is for your feedback on API changes that we discussed offline. In addition to looking at the source, I have been updating the
tutorials/01_Introduction/intro.ipynb
notebook as a "look and feel" example. I have attached a rendered version of the notebook:intro.pdf
Main features are:
Observation class as the new data model, with
detdata
,shared
,intervals
, andview
attributes as the key places where the contents are influenced.Improved processing model with changes to the
Operator
class and the newPipeline
operator. These classes are configured withtraitlets
.New distributed map classes (
PixelDistribution
andPixelData
) which split the calculation of the distribution from the actual data storage. These have the new Alltoallv communication pattern.There are only 2-3 operators that have been ported to the new API as a demo. I'll continue on some config file work that needs to be updated since the switch to traitlets.