diff --git a/pyproject.toml b/pyproject.toml index bdc2fb5..1ce04d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,6 +43,7 @@ dependencies = [ "rich", "attrs", "hickleable>=0.1.1", + "lunarsky>=0.2.5", ] [project.optional-dependencies] diff --git a/src/py21cmsense/_utils.py b/src/py21cmsense/_utils.py index f7b0944..4f5df71 100644 --- a/src/py21cmsense/_utils.py +++ b/src/py21cmsense/_utils.py @@ -41,7 +41,7 @@ def find_nearest(array, value): @un.quantity_input def phase_past_zenith( - time_past_zenith: un.day, bls_enu: np.ndarray, latitude, world, use_apparent: bool = True + time_past_zenith: un.day, bls_enu: np.ndarray, latitude, world: str = "earth", use_apparent: bool = True ): """Compute UVWs phased to a point rotated from zenith by a certain amount of time. @@ -59,7 +59,7 @@ def phase_past_zenith( latitude The latitude of the center of the array, in radians. world - Wether the telescope is on the Earth or Moon. + Whether the telescope is on the Earth or Moon. Returns ------- diff --git a/src/py21cmsense/observation.py b/src/py21cmsense/observation.py index ffea8ec..cb126c2 100644 --- a/src/py21cmsense/observation.py +++ b/src/py21cmsense/observation.py @@ -93,17 +93,16 @@ class Observation: observatory: obs.Observatory = attr.ib(validator=vld.instance_of(obs.Observatory)) time_per_day: tp.Time = attr.ib( - 6 * un.hour, - validator=(tp.vld_physical_type("time"), ut.between(0 * un.hour, 655.2 * un.hour)), + validator=(tp.vld_physical_type("time")), ) track: tp.Time | None = attr.ib( None, validator=attr.validators.optional( - [tp.vld_physical_type("time"), ut.between(0, 655.2 * un.hour)] + [tp.vld_physical_type("time")] ), ) lst_bin_size: tp.Time = attr.ib( - validator=(tp.vld_physical_type("time"), ut.between(0, 655.2 * un.hour)), + validator=(tp.vld_physical_type("time")), ) integration_time: tp.Time = attr.ib( 60 * un.second, validator=(tp.vld_physical_type("time"), ut.positive) @@ -164,8 +163,30 @@ def __sethstate__(self, d: dict[str, Any]) -> None: d["cosmo"] = Planck15.from_format(d["cosmo"]) self.__dict__.update(d) + @time_per_day.validator + def _time_per_day_vld(self, att, val): + day_length = 24*un.hour if self.observatory.world == 'earth' else 655.2*un.hour + + if not 0*un.hour <= val <= day_length: + raise ValueError(f"time_per_day should be between 0 and {day_length}") + + @track.validator + def _track_vld(self, att, val): + if val != None: + day_length = 24*un.hour if self.observatory.world == 'earth' else 655.2*un.hour + + if not 0*un.hour <= val <= day_length: + raise ValueError(f"track should be between 0 and {day_length}") + + @lst_bin_size.validator def _lst_bin_size_vld(self, att, val): + day_length = 24*un.hour if self.observatory.world == 'earth' else 655.2*un.hour + + if not 0*un.hour <= val <= day_length: + raise ValueError(f"lst_bin_size should be between 0 and {day_length}") + + if val > self.time_per_day: raise ValueError("lst_bin_size must be <= time_per_day") @@ -174,6 +195,13 @@ def _integration_time_vld(self, att, val): if val > self.lst_bin_size: raise ValueError("integration_time must be <= lst_bin_size") + @time_per_day.default + def _time_per_day_default(self): + if self.observatory.world == 'earth': + return 6 * un.hour + else: + return 163.8 * un.hour + @lst_bin_size.default def _lst_bin_size_default(self): # time it takes the sky to drift through beam FWHM diff --git a/src/py21cmsense/sensitivity.py b/src/py21cmsense/sensitivity.py index ff947d4..b9f0492 100644 --- a/src/py21cmsense/sensitivity.py +++ b/src/py21cmsense/sensitivity.py @@ -151,7 +151,7 @@ class PowerSpectrum(Sensitivity): horizon_buffer: tp.Wavenumber = attr.ib(default=0.1 * littleh / un.Mpc) foreground_model: str = attr.ib( - default="moderate", validator=vld.in_(["moderate", "optimistic", "ultra_optimistic"]) + default="moderate", validator=vld.in_(["moderate", "optimistic", "foreground_free"]) ) theory_model: TheoryModel = attr.ib() @@ -471,7 +471,7 @@ def horizon_limit(self, umag: float) -> tp.Wavenumber: return horizon + self.horizon_buffer elif self.foreground_model in ["optimistic"]: return horizon * np.sin(self.observation.observatory.beam.first_null / 2) - elif self.foreground_model in ["ultra_optimistic"]: + elif self.foreground_model in ["foreground_free"]: return 0 def _average_sense_to_1d( diff --git a/tests/test_observation.py b/tests/test_observation.py index 3e163ca..5295565 100644 --- a/tests/test_observation.py +++ b/tests/test_observation.py @@ -15,12 +15,16 @@ def bm(): return GaussianBeam(150.0 * units.MHz, dish_size=14 * units.m) +@pytest.fixture(scope="module", params=["earth","moon"]) +def wd(request): + return request.param @pytest.fixture(scope="module") -def observatory(bm): +def observatory(bm,wd): return Observatory( antpos=np.array([[0, 0, 0], [14, 0, 0], [28, 0, 0], [70, 0, 0]]) * units.m, beam=bm, + world=wd ) @@ -89,9 +93,10 @@ def test_from_yaml(observatory): Observation.from_yaml(3) -def test_huge_lst_bin_size(observatory: Observatory): +def test_huge_lst_bin_size(observatory: Observatory, wd): + lst = 23 * units.hour if wd=="earth" else 627.9 * units.hour with pytest.raises(ValueError, match="lst_bin_size must be <= time_per_day"): - Observation(observatory=observatory, lst_bin_size=23 * units.hour) + Observation(observatory=observatory, lst_bin_size=lst) def test_huge_integration_time(observatory: Observatory): diff --git a/tests/test_sensitivity.py b/tests/test_sensitivity.py index 38c1ec8..8b9ff01 100644 --- a/tests/test_sensitivity.py +++ b/tests/test_sensitivity.py @@ -15,12 +15,16 @@ def bm(): return GaussianBeam(150.0 * units.MHz, dish_size=14 * units.m) +@pytest.fixture(scope="module", params=["earth","moon"]) +def wd(request): + return request.param @pytest.fixture(scope="module") -def observatory(bm): +def observatory(bm, wd): return Observatory( antpos=np.array([[0, 0, 0], [14, 0, 0], [28, 0, 0], [70, 0, 0]]) * units.m, beam=bm, + world=wd )