ALL DEVELOPMENT AFTER COMMIT 4b05925 MOVED TO sofind
Simple, extendable framework for loading ACT products from disk.
Currently:
- from
simonsobs:pixell
All other dependencies (e.g. numpy etc.) are required by packages listed here, especially by pixell.
Clone this repo and cd to /path/to/actapack/:
$ pip install .or
$ pip install -e .to see changes to source code automatically updated in your environment.
All users must create a file .actapack_config.yaml in their system's HOME directory. This file encodes the location on their system of products implemented in the actapack package. It also groups a set of these locations under data model "names," such as act_dr6v3_default (see actapack/datamodels). This way, different data models may have their products in different locations on the system.
To facilitate setup, we have provided some .actapack_config.yaml files for common public systems, such as NERSC, in the actapack_configs folder for users to copy. However, we recommend reading this section regardless to understand these files in case changes are necessary, or if you'd like to install actapack on your laptop, for instance.
We'll start with a basic example. Let's assume you wish to interact with the act_dr6v3_default data model. Let's also assume that actapack currently implements map and beam products in actapack/products/maps and actapack/products/beams, along with possibly more products in different actapack/products modules as well. Then, your .actapack_config.yaml file might look like this:
act_dr6v3_default:
maps:
default_path: "/path/to/default/maps/on/this/system/"
pwv_split_path: "/path/to/pwv_split/maps/on/this/system/"
beams:
default_path: "/path/to/default/beams/on/this/system/"First, we must have a block for the data model (act_dr6v3_default) we wish to use. Under this block, we must have "product"-level blocks for each product implementation (e.g. maps, beams) we wish to interact with. The name of these "product" blocks must match the module in which the product is implemented (e.g. maps for actapack/products/maps/__init__.py). Finally, within each "product" block, we may have several "subproducts." These "subproducts" share the same code interface (again, in actapack/products/maps/__init__.py), but may just be different "kinds" of maps. The name of each "subproduct" is indicated by the words before _path. The system path for that product/subproduct pair is then listed. For example, all the possible files for pwv_split maps should be in the directory "/path/to/pwv_split/maps/on/this/system/".
A few notes:
- A user's
.actapack_config.yamlmay have several different "data model" blocks, so that they can select from their desired data model at runtime. - It is not necessary to have a "product" block for every product in a data model. In this example, if you omit the
beamsblock, then a call to load a beam from disk (for any beam "subproduct") would raise an error, but the other products, likemaps, would be unaffected. Thus, users do not need to make any other changes toactapackor their setup if some products do not exist on their system. - It is not necessary to have a "subproduct" path for every subproduct in a product. In this example, if you omit the
pwv_split_pathfrom themapsblock, then a call map methods with the keyword argumentsubproduct='pwv_split'would raise an error without affecting other subproducts. Thus, users do not need to make any other changes toactapackor their setup if some subproducts do not exist on their system. - By convention, the default "subproduct" passed to the methods in each product implementation (e.g.
read_mapinactapack/products/maps/__init__.py) is called "default". Thus, most "product" blocks in a.actapack_config.yamlfile will have, at minimum, adefault_path. However, there is nothing special about this name as far as whether it must be present or may be omitted from the.actapack_config.yamlfile.
All you need in your code is the following (e.g. for the act_dr6v3_default data model):
from actapack import DataModel
dm = DataModel.from_config('act_dr6v3_default')
my_default_map_filename = dm.get_map_fn(...)
my_pwv_split_map = dm.read_map(..., subproduct='pwv_split')
my_beam_fn = dm.get_beam_fn(...)Users should only ever interface with the high-level DataModel class. This class inherits from all implemented actapack products!
There are four steps:
-
Create a new product folder in the
actapack/productsdirectory. Add to this folder a python module named__init__.py.- The module should only contain a subclass of the
actapack.products.products.Productclass. - There is a minimum prescription your subclass implementation must follow. You should not modify the class declaration or
__init__method, and you must modify theactapack.products.products.Productmethods decorated with@productmethod. To make it easy, a template of this implementation (for a product calledHotDog) can be copied fromactapack/products/hotdogs/__init__.py. Note the template has more detail on how to implement your product class. You can also look at e.g.actpack.products.maps.Mapfor inspiration. - Anything beyond this minimal perscription can be added if your product has more complicated features!
- The module should only contain a subclass of the
-
Make sure your product is imported directly by the
actapack.productspackage. For instance, if your folder was namedhotdogs, then add this line toactapack.products.__init__.py:from .hotdogs import *
-
Add a config (or multiple configs if you have multiple product versions, or subproducts, etc.) to
actapack/products/{module_name}. Following the hotdog example, there is a config filehotdog_example.yamlinactapack/products/hotdogs.- This must be a
.yamlfile. - This should contain any information to help get filenames for your product or load them from disk, such as a template filename. For instance, given a set of keyword arguments
array='pa6', freq='f090', num_splits=8, condiment='mustard', thehotdog_file_templatestring inhotdog_example.yamlwould format topa6_f090_8way_mustard.txt(the actual formatting would occur in yourHotDogclass'sget_hotdog_fnmethod). - You must have an
allowed_qids_configsblock. If your subproduct is agnostic to qids, this can beall; otherwise, it must list the individualqids_configfiles (inactapack/qids) that this subproduct may work with. - You must have an
allowed_qidsblock. If your product methods use aqidto provide keywords to filename templates, then the permissibleqid(s) for that product must be listed here. May also beallor left blank if noqid(s) work with your subproduct. For instance, a call toHotDog.read_hotdogwill raise an error ifhotdog_example.yamlis used to configure the callingDataModelinstance and the suppliedqidis not one ofpa4a,pa5a, orpa6a. - You must have an
allowed_qids_extra_kwargsblock. If your template filename requires additional keywords for a givenqidthan are present in anyallowed_qids_configsfiles (seeactapack/qids), those keywords would need to be added here. For instance, theact_dr6_default_qids.yamlfile only containsarray,freq,patch, anddaynightkeywords. Thenum_splitskeyword required for thehotdog_file_templateis thus added for each permissible qid directly inhotdog_example.yaml, e.g.:Theallowed_qids_extra_kwargs: pa6a: num_splits: 8
allowed_qids_extra_kwargsblock may be empty if there are no extra keywords to add for any of theallowed_qids.
- This must be a
-
Clearly document product implementations and product configs. For example, see the docstrings in the
Mapclass (actapack/products/maps/__init__.py) as well as themapsreadme (actapack/products/maps/README.md).
Please commit and push your contribution to a new branch and open a PR on github! If you are updating an old config, please include it under a new file altogether so that historical products may still be loaded at runtime.
There are one (maybe two) steps:
- Create a new data model config in
actapack/datamodels.- Like the
.actapack_config.yamlfile, this config must have a block for each product this data model will load. Note, also like the.actapack_config.yamlfile, it is not necessary to have a block for every product inactapack, only those that will be functional in this data model. The same goes for subproducts of a product -- include only those that will be functional in this data model. To add a subproduct, include an entry under the associated product block like:wheredata_model_name: prod: subprod_config: config.yaml
prodandsubprodare the names of the product and subproduct that may be called by theDataModel. - As in the
.actapack_config.yamlfile, you should include adefaultsubproduct if this default is obvious. - This config file must also have an entry for a
qids_config(at the top-level), indicating one of the qid config files underactapack/qids.
- Like the
- Only if one of the included qid config files are not sufficient for your needs, you'll need to add another one with your qids.
Please commit and push your contribution to a new branch and open a PR on github! If you are updating an old config, please include it under a new file altogether so that historical products may still be loaded at runtime.