Skip to content

Commit

Permalink
Fix pickle issue for multiprocessing (#92)
Browse files Browse the repository at this point in the history
* Switch from custom dataclass to dictionary

* Update main script

* Update readme example

* API update

* Simplify API doc
  • Loading branch information
aboucaud authored Mar 22, 2022
1 parent 3a56cb9 commit a2f7471
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 62 deletions.
30 changes: 12 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,34 +56,28 @@ galcheat --refs -s HSC # HSC info with refs
API
---
```python
# The list of available surveys
from galcheat import available_surveys
import galcheat

# Getter method to retrieve a Survey dataclass
from galcheat import get_survey
# Start with the list of available surveys
galcheat.available_surveys

LSST = get_survey("LSST")
# Retrieve a Survey instance
LSST = galcheat.get_survey("LSST")

# Get the list of available filter names
# List the available survey filters
LSST.available_filters

# and then pick a Filter dataclass
# Pick a Filter instance
u_band = LSST.get_filter("u")

# Both Survey and Filter classes have physical attributes
# Both Survey and Filter objects have physical attributes
LSST.mirror_diameter
u_band.exposure_time

# Filters are also attributes of a Survey
LSST.filters.u.exposure_time # same attribute as above
u_band.exposure_time

# These attributes are Astropy Quantity objects with units
fwhm = u_band.psf_fwhm
# The value in the original units is obtained as
fwhm.value
# or it can be converted to other units
import astropy.units as u
fwhm.to_value(u.arcmin)
# These attributes are Astropy Quantity objects
# whose value can be retrieved in any desired unit
u_band.psf_fwhm.to_value('arcmin')
```

## Contributing ✨
Expand Down
28 changes: 9 additions & 19 deletions galcheat/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
\____|\__,_|_|\____|_| |_|\___|\__,_|\__|
The tiny library of galaxy surveys
most useful parameters (with units)
most useful parameters with units
The data can be viewed in a terminal with
Expand All @@ -26,32 +26,22 @@
>>> LSST.available_filters
Each `Filter` class is then accessible either
as an attribute from the `Survey`
>>> u_filter = LSST.filters.u
or through a method
Each `Filter` class is accessible through
>>> u_filter = LSST.get_filter('u')
For a given survey, a dictionary of the available
filters is returned by
>>> LSST.get_filters()
Parameter values can be converted to any physical
units using the `astropy.units` scheme
Parameter values are astropy Quantity objects
>>> u_filter.psf_fwhm
<Quantity 0.859 arcsec>
>>> u_filter.value
>>> u_filter.psf_fwhm.value
0.859
>>> u_filter.psf_fwhm.unit
Unit("arcsec")
>>> import astropy.units as u
>>> u_filter.psf_fwhm.to(u.arcmin).value
or
>>> u_filter.psf_fwhm.to_value(u.arcmin)
which can be converted to any physical units
using the `astropy.units` scheme
>>> u_filter.psf_fwhm.to_value('arcmin')
0.014316666666666667
Feel free to contribute by submitting
Expand Down
35 changes: 10 additions & 25 deletions galcheat/survey.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import copy
import math
from dataclasses import dataclass, field, make_dataclass
from typing import Any, Dict, List
from dataclasses import dataclass, field
from typing import Dict, List

import astropy.units as u
import yaml
Expand All @@ -14,7 +14,7 @@
class Survey:
name: str
description: str
_filters: Any
_filters: Dict[str, Filter]
pixel_scale: Quantity
mirror_diameter: Quantity
gain: Quantity
Expand All @@ -41,7 +41,7 @@ def from_yaml(cls, yaml_file):
with open(yaml_file) as f:
data = yaml.safe_load(f)

filters = Survey._construct_filter_list(data)
filters = Survey._construct_filter_dict(data)
pixel_scale = data["pixel_scale"] * u.arcsec
mirror_diameter = data["mirror_diameter"] * u.m
gain = data["gain"] * u.electron / u.adu
Expand Down Expand Up @@ -78,8 +78,8 @@ def __repr__(self):
return f"Survey {self.name}"

@staticmethod
def _construct_filter_list(survey_dict):
"""Create a custom container for the survey filters
def _construct_filter_dict(survey_dict):
"""Create a custom dictionary for the survey filters
Parameters
----------
Expand All @@ -88,36 +88,21 @@ def _construct_filter_list(survey_dict):
Returns
-------
Dynamically created dataclass whose attributes are the survey filters
Dictionary of the survey filters
"""
filter_data = {
return {
fname: Filter.from_dict(fdict)
for fname, fdict in survey_dict["filters"].items()
}
FList = make_dataclass(
survey_dict["name"] + "FilterList",
[(filter_name, Filter) for filter_name in filter_data.keys()],
namespace={
"__repr__": lambda self: "("
+ ", ".join([filt for filt in self.__dict__.keys()])
+ ")"
},
)

return FList(**filter_data)

def __post_init__(self):
"""Set attributes computed after class is constructed"""
self.available_filters = list(self._filters.__dict__.keys())
self.available_filters = list(self._filters.keys())

total_area = math.pi * (self.mirror_diameter * 0.5) ** 2
self.effective_area = (1 - self.obscuration) * total_area

def get_filters(self):
"""Getter method to retrieve the filters as a dictionary"""
return copy.deepcopy(self._filters.__dict__)

def get_filter(self, filter_name):
"""Getter method to retrieve a Filter object"""
if filter_name not in self.available_filters:
Expand All @@ -127,4 +112,4 @@ def get_filter(self, filter_name):
f"are {self.available_filters}"
)

return copy.deepcopy(self._filters.__dict__[filter_name])
return copy.deepcopy(self._filters[filter_name])

0 comments on commit a2f7471

Please sign in to comment.