PyTransit 2.9.0__tar.gz → 2.9.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytransit-2.9.0 → pytransit-2.9.1}/PKG-INFO +1 -1
- {pytransit-2.9.0 → pytransit-2.9.1}/PyTransit.egg-info/PKG-INFO +1 -1
- {pytransit-2.9.0 → pytransit-2.9.1}/PyTransit.egg-info/SOURCES.txt +5 -1
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/__init__.py +1 -1
- pytransit-2.9.1/pytransit/utils/io/__init__.py +20 -0
- pytransit-2.9.1/pytransit/utils/io/base.py +385 -0
- pytransit-2.9.1/pytransit/utils/io/lcdata.py +322 -0
- pytransit-2.9.1/pytransit/utils/io/rvdata.py +192 -0
- pytransit-2.9.1/tests/test_lcdata.py +526 -0
- pytransit-2.9.1/tests/test_rvdata.py +360 -0
- pytransit-2.9.0/pytransit/utils/io/__init__.py +0 -0
- pytransit-2.9.0/pytransit/utils/io/lightcurvedata.py +0 -22
- {pytransit-2.9.0 → pytransit-2.9.1}/LICENSE +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/MANIFEST.in +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/PyTransit.egg-info/dependency_links.txt +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/PyTransit.egg-info/requires.txt +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/PyTransit.egg-info/top_level.txt +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/README.md +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pyproject.toml +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/contamination/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/contamination/contamination.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/contamination/data/spectra.h5 +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/contamination/data/transmission.nc +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/contamination/filter.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/contamination/instrument.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/contamination/plotting.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/limb_darkening.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/baselines/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/baselines/legendrebaseline.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/baselines/linearbaseline.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/baselines/lstsqbaseline.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/cntlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/eclipselpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/loglikelihood/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/loglikelihood/celeriteloglikelihood.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/loglikelihood/clloglikelihood.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/loglikelihood/fmcloglikelihood.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/loglikelihood/logisticloglikelihood.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/loglikelihood/multiceleriteloglikelihood.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/loglikelihood/wnloglikelihood.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/logposteriorfunction.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/lpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/mclpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/mptlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/ocllpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/ocltdvlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/oclttvlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/phasecurvelpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/rvlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tdvlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tess/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tess/ctesslpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tess/tessttvlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tess/tgclpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tess/tgcmplpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tess/tmpclpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tesslpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/tessoclttvlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/transitanalysis.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/transitlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/lpf/ttvlpf.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/eclipse_model.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/gdmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/general.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/ldmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/ldtkldm.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/evaluation.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/exponential.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/general.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/linear.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/logarithmic.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/nonlinear.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/power_2.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/quadratic.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/quadratic_tri.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/square_root.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/limb_darkening/uniform.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/ma_chromosphere.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/ma_quadratic.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/ma_quadratic_cl.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/ma_uniform.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/ma_uniform_cl.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/new_eclipse_model.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/gdmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/general_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/ldmodels.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/ldtkldm.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/ma_chromosphere_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/ma_quadratic_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/ma_uniform_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/phasecurves.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/qpower2_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/spmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/numba/udmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/opencl/ma_quadratic.cl +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/opencl/ma_uniform.cl +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/opencl/orbits.cl +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/opencl/qpower2.cl +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/osmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/qpower2.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/qpower2_cl.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/common.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/ecintersection.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/esmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/model_eclipse.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/model_ecspec.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/model_full.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/model_simple.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/model_trspec.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/opmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/opmodel_full.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/rrmodel.cl +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/rrmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/rrmodel_cl.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/roadrunner/tsmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/transitmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/models/uniform.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/orbits/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/orbits/orbits.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/orbits/orbits_py.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/orbits/taylor_z.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/param/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/param/parameter.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/param/prior.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/param/utilities.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/stars/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/stars/btsettl.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/stars/data/avg_bt_settl.fits +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/stars/data/avg_husser2013.fits +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/stars/husser2013.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/__init__.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/astrometry.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/constants.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/de.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/downsample.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/eclipses.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/keplerlc.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/mdwarfs.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/misc.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/mocklc.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/octasphere.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/phasecurves.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/physics.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/rv.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/pytransit/utils/tess.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/requirements.txt +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/setup.cfg +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_contamination.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_ecintersection.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_limb_darkening.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_lstsqbaseline.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_ma_quadratic.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_ma_quadratic_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_opmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_qpower2_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_roadrunner_eclipse.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_rrmodel.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_uniform_model.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_uniform_model_nb.py +0 -0
- {pytransit-2.9.0 → pytransit-2.9.1}/tests/test_z.py +0 -0
|
@@ -141,9 +141,12 @@ pytransit/utils/physics.py
|
|
|
141
141
|
pytransit/utils/rv.py
|
|
142
142
|
pytransit/utils/tess.py
|
|
143
143
|
pytransit/utils/io/__init__.py
|
|
144
|
-
pytransit/utils/io/
|
|
144
|
+
pytransit/utils/io/base.py
|
|
145
|
+
pytransit/utils/io/lcdata.py
|
|
146
|
+
pytransit/utils/io/rvdata.py
|
|
145
147
|
tests/test_contamination.py
|
|
146
148
|
tests/test_ecintersection.py
|
|
149
|
+
tests/test_lcdata.py
|
|
147
150
|
tests/test_limb_darkening.py
|
|
148
151
|
tests/test_lstsqbaseline.py
|
|
149
152
|
tests/test_ma_quadratic.py
|
|
@@ -152,6 +155,7 @@ tests/test_opmodel.py
|
|
|
152
155
|
tests/test_qpower2_nb.py
|
|
153
156
|
tests/test_roadrunner_eclipse.py
|
|
154
157
|
tests/test_rrmodel.py
|
|
158
|
+
tests/test_rvdata.py
|
|
155
159
|
tests/test_uniform_model.py
|
|
156
160
|
tests/test_uniform_model_nb.py
|
|
157
161
|
tests/test_z.py
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# PyTransit: fast and easy exoplanet transit modelling in Python.
|
|
2
|
+
# Copyright (C) 2010-2026 Hannu Parviainen
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
from .lcdata import LCData, LCDataGroup
|
|
18
|
+
from .rvdata import RVData, RVDataGroup
|
|
19
|
+
|
|
20
|
+
__all__ = ['LCData', 'LCDataGroup', 'RVData', 'RVDataGroup']
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
# PyTransit: fast and easy exoplanet transit modelling in Python.
|
|
2
|
+
# Copyright (C) 2010-2026 Hannu Parviainen
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, either version 3 of the License, or
|
|
7
|
+
# (at your option) any later version.
|
|
8
|
+
#
|
|
9
|
+
# This program is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
12
|
+
# GNU General Public License for more details.
|
|
13
|
+
#
|
|
14
|
+
# You should have received a copy of the GNU General Public License
|
|
15
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
16
|
+
|
|
17
|
+
"""Shared machinery for the observation data containers.
|
|
18
|
+
|
|
19
|
+
`LCData`/`LCDataGroup` and `RVData`/`RVDataGroup` differ in the metadata
|
|
20
|
+
they carry but share their field validation and their container behaviour. The validators
|
|
21
|
+
here are plain functions each item class calls in order, so the classes stay flat and
|
|
22
|
+
readable, while `_Data` and `_DataGroup` hold the addition algebra and the container
|
|
23
|
+
protocol.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
import warnings
|
|
27
|
+
|
|
28
|
+
from collections.abc import Sequence
|
|
29
|
+
from typing import Callable, Optional, Union
|
|
30
|
+
|
|
31
|
+
from numpy import (ndarray, asarray, zeros, array, nan, isfinite, integer, bool_)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# Scalar conversion
|
|
35
|
+
# -----------------
|
|
36
|
+
def _as_float_array(x, name: str) -> ndarray:
|
|
37
|
+
"""Convert `x` into a float64 array, re-raising conversion failures informatively."""
|
|
38
|
+
try:
|
|
39
|
+
return asarray(x, 'd')
|
|
40
|
+
except (TypeError, ValueError) as e:
|
|
41
|
+
raise ValueError(f"Could not convert '{name}' into a float array: {e}") from e
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _as_int(v, name: str) -> int:
|
|
45
|
+
"""Convert `v` into an int, rejecting non-integral values."""
|
|
46
|
+
if isinstance(v, (bool, bool_)):
|
|
47
|
+
raise ValueError(f"'{name}' must be an integer, got a boolean.")
|
|
48
|
+
try:
|
|
49
|
+
iv = int(v)
|
|
50
|
+
except (TypeError, ValueError) as e:
|
|
51
|
+
raise ValueError(f"'{name}' must be an integer, got {v!r}.") from e
|
|
52
|
+
if iv != v:
|
|
53
|
+
raise ValueError(f"'{name}' must be an integer, got {v!r}.")
|
|
54
|
+
return iv
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _as_float(v, name: str) -> float:
|
|
58
|
+
try:
|
|
59
|
+
return float(v)
|
|
60
|
+
except (TypeError, ValueError) as e:
|
|
61
|
+
raise ValueError(f"'{name}' must be a float, got {v!r}.") from e
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
# Field validation
|
|
65
|
+
# ----------------
|
|
66
|
+
def _validate_time(time, name: str = 'time') -> ndarray:
|
|
67
|
+
"""Return `time` as a finite 1D float64 array."""
|
|
68
|
+
t = _as_float_array(time, name)
|
|
69
|
+
if t.ndim != 1:
|
|
70
|
+
raise ValueError(f"'{name}' must be a 1D array, got a {t.ndim}D one.")
|
|
71
|
+
if not isfinite(t).all():
|
|
72
|
+
raise ValueError(f"'{name}' contains non-finite values.")
|
|
73
|
+
return t
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _validate_series(values, npt: int, name: str) -> ndarray:
|
|
77
|
+
"""Return `values` as a 1D float64 array of length `npt`, warning on non-finite values."""
|
|
78
|
+
v = _as_float_array(values, name)
|
|
79
|
+
if v.ndim != 1:
|
|
80
|
+
raise ValueError(f"'{name}' must be a 1D array, got a {v.ndim}D one.")
|
|
81
|
+
if v.size != npt:
|
|
82
|
+
raise ValueError(f"'{name}' has {v.size} points but 'time' has {npt}.")
|
|
83
|
+
if not isfinite(v).all():
|
|
84
|
+
warnings.warn(f"'{name}' contains non-finite values.")
|
|
85
|
+
return v
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _validate_error(error, npt: int, name: str = 'error') -> Optional[ndarray]:
|
|
89
|
+
"""Return `error` as a positive 1D float64 array of length `npt`, or None."""
|
|
90
|
+
if error is None:
|
|
91
|
+
return None
|
|
92
|
+
e = _as_float_array(error, name)
|
|
93
|
+
if e.ndim != 1:
|
|
94
|
+
raise ValueError(f"'{name}' must be a 1D array, got a {e.ndim}D one.")
|
|
95
|
+
if e.size != npt:
|
|
96
|
+
raise ValueError(f"'{name}' has {e.size} points but 'time' has {npt}.")
|
|
97
|
+
finite = isfinite(e)
|
|
98
|
+
if not finite.all():
|
|
99
|
+
warnings.warn(f"'{name}' contains non-finite values.")
|
|
100
|
+
if (e[finite] <= 0.0).any():
|
|
101
|
+
raise ValueError(f"'{name}' contains non-positive values.")
|
|
102
|
+
return e
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _validate_covariates(covariates, npt: int, name: str = 'covariates') -> ndarray:
|
|
106
|
+
"""Return `covariates` as a 2D float64 array with `npt` rows, empty when None."""
|
|
107
|
+
if covariates is None:
|
|
108
|
+
return zeros((npt, 0))
|
|
109
|
+
cv = _as_float_array(covariates, name)
|
|
110
|
+
if cv.ndim == 1:
|
|
111
|
+
cv = cv.reshape((-1, 1))
|
|
112
|
+
elif cv.ndim != 2:
|
|
113
|
+
raise ValueError(f"'{name}' must be a 1D or 2D array, got a {cv.ndim}D one.")
|
|
114
|
+
if cv.shape[0] != npt:
|
|
115
|
+
raise ValueError(f"'{name}' has {cv.shape[0]} rows but 'time' has {npt} points.")
|
|
116
|
+
return cv
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _validate_names(names, name: str = 'passband') -> tuple:
|
|
120
|
+
"""Return `names` as a non-empty tuple of strings."""
|
|
121
|
+
if isinstance(names, str):
|
|
122
|
+
return (names,)
|
|
123
|
+
try:
|
|
124
|
+
out = tuple(str(n) for n in names)
|
|
125
|
+
except TypeError as e:
|
|
126
|
+
raise ValueError(f"'{name}' must be a string or a sequence of strings, "
|
|
127
|
+
f"got {names!r}.") from e
|
|
128
|
+
if len(out) == 0:
|
|
129
|
+
raise ValueError(f"'{name}' cannot be empty.")
|
|
130
|
+
return out
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _validate_pids(pids, name: str = 'pids') -> Optional[tuple]:
|
|
134
|
+
"""Return `pids` as a tuple of unique non-negative ints, or None.
|
|
135
|
+
|
|
136
|
+
Only `LCData` uses this: an RV signal always contains every planet in the
|
|
137
|
+
system, so there is no per-dataset subset to name. It lives here to keep the validators
|
|
138
|
+
in one place.
|
|
139
|
+
"""
|
|
140
|
+
if pids is None:
|
|
141
|
+
return None
|
|
142
|
+
if isinstance(pids, str):
|
|
143
|
+
raise ValueError(f"'{name}' must be an integer or a sequence of integers, "
|
|
144
|
+
f"got the string {pids!r}.")
|
|
145
|
+
if isinstance(pids, (int, integer)) and not isinstance(pids, (bool, bool_)):
|
|
146
|
+
pids = [pids]
|
|
147
|
+
try:
|
|
148
|
+
pl = tuple(_as_int(p, name) for p in pids)
|
|
149
|
+
except TypeError as e:
|
|
150
|
+
raise ValueError(f"'{name}' must be an integer or a sequence of integers, "
|
|
151
|
+
f"got {pids!r}.") from e
|
|
152
|
+
if any(p < 0 for p in pl):
|
|
153
|
+
raise ValueError(f"'{name}' cannot contain negative planet indices, got {pids!r}.")
|
|
154
|
+
if len(set(pl)) != len(pl):
|
|
155
|
+
raise ValueError(f"'{name}' contains duplicate planet indices: {pids!r}.")
|
|
156
|
+
return pl
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class _Data:
|
|
160
|
+
"""Addition algebra shared by the single-dataset containers.
|
|
161
|
+
|
|
162
|
+
Subclasses set `_group_type` to their group class once it is defined.
|
|
163
|
+
"""
|
|
164
|
+
|
|
165
|
+
_group_type = None
|
|
166
|
+
|
|
167
|
+
def __add__(self, other):
|
|
168
|
+
gt = self._group_type
|
|
169
|
+
if isinstance(other, gt):
|
|
170
|
+
return gt([self] + other.data)
|
|
171
|
+
if isinstance(other, gt._item_type):
|
|
172
|
+
return gt([self, other])
|
|
173
|
+
return NotImplemented
|
|
174
|
+
|
|
175
|
+
def __radd__(self, other):
|
|
176
|
+
if other == 0 or other is None:
|
|
177
|
+
return self._group_type([self])
|
|
178
|
+
return NotImplemented
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class _DataGroup:
|
|
182
|
+
"""Container protocol and metadata shared by the dataset groups.
|
|
183
|
+
|
|
184
|
+
Subclasses set `_item_type` to the class they hold. The datasets keep their insertion
|
|
185
|
+
order, which defines the dataset index a model will use. Nothing is sorted implicitly.
|
|
186
|
+
"""
|
|
187
|
+
|
|
188
|
+
_item_type = None
|
|
189
|
+
|
|
190
|
+
def __init__(self, data=()) -> None:
|
|
191
|
+
self.data: list = []
|
|
192
|
+
if isinstance(data, (self._item_type, _DataGroup)):
|
|
193
|
+
data = [data]
|
|
194
|
+
for d in data:
|
|
195
|
+
self._add_data(d)
|
|
196
|
+
|
|
197
|
+
def _add_data(self, d) -> None:
|
|
198
|
+
if isinstance(d, _DataGroup):
|
|
199
|
+
for x in d.data:
|
|
200
|
+
self._add_data(x)
|
|
201
|
+
return
|
|
202
|
+
if not isinstance(d, self._item_type):
|
|
203
|
+
raise TypeError(f"A {type(self).__name__} holds {self._item_type.__name__} objects, "
|
|
204
|
+
f"got {type(d).__name__}.")
|
|
205
|
+
if any(d is x for x in self.data):
|
|
206
|
+
raise ValueError(f"The same {self._item_type.__name__} instance cannot be added "
|
|
207
|
+
f"to a group twice.")
|
|
208
|
+
self.data.append(d)
|
|
209
|
+
|
|
210
|
+
# Bulk data
|
|
211
|
+
# ---------
|
|
212
|
+
@property
|
|
213
|
+
def times(self) -> list:
|
|
214
|
+
"""List of 1D time arrays."""
|
|
215
|
+
return [d.time for d in self.data]
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def covariates(self) -> list:
|
|
219
|
+
"""List of 2D covariate matrices."""
|
|
220
|
+
return [d.covariates for d in self.data]
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def errors(self) -> list:
|
|
224
|
+
"""List of 1D uncertainty arrays."""
|
|
225
|
+
return [d.error for d in self.data]
|
|
226
|
+
|
|
227
|
+
# Metadata
|
|
228
|
+
# --------
|
|
229
|
+
@property
|
|
230
|
+
def instruments(self) -> list:
|
|
231
|
+
"""List of instrument names."""
|
|
232
|
+
return [d.instrument for d in self.data]
|
|
233
|
+
|
|
234
|
+
# Sizes
|
|
235
|
+
# -----
|
|
236
|
+
@property
|
|
237
|
+
def size(self) -> int:
|
|
238
|
+
"""Number of datasets."""
|
|
239
|
+
return len(self.data)
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def npts(self) -> ndarray:
|
|
243
|
+
"""Array of per-dataset datapoint counts."""
|
|
244
|
+
return array([d.size for d in self.data], int)
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def ncovs(self) -> ndarray:
|
|
248
|
+
"""Array of per-dataset covariate counts."""
|
|
249
|
+
return array([d.ncov for d in self.data], int)
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def has_errors(self) -> bool:
|
|
253
|
+
"""True if every dataset was given an explicit uncertainty array."""
|
|
254
|
+
return all(d.has_error for d in self.data) if self.data else False
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def has_covariates(self) -> bool:
|
|
258
|
+
"""True if any dataset has at least one covariate."""
|
|
259
|
+
return bool((self.ncovs > 0).any())
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def tmin(self) -> float:
|
|
263
|
+
"""Earliest time in the group."""
|
|
264
|
+
return min((d.time.min() for d in self.data if d.size), default=nan)
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def tmax(self) -> float:
|
|
268
|
+
"""Latest time in the group."""
|
|
269
|
+
return max((d.time.max() for d in self.data if d.size), default=nan)
|
|
270
|
+
|
|
271
|
+
# Derived ids
|
|
272
|
+
# -----------
|
|
273
|
+
def _group_ids(self, *fields) -> ndarray:
|
|
274
|
+
"""Map tuples of per-dataset metadata into 0-based contiguous group ids.
|
|
275
|
+
|
|
276
|
+
The ids are numbered by first appearance, so they are contiguous by construction,
|
|
277
|
+
which `BaseLPF._init_data` asserts for the noise ids.
|
|
278
|
+
"""
|
|
279
|
+
keys = list(zip(*fields))
|
|
280
|
+
if not keys:
|
|
281
|
+
return zeros(0, int)
|
|
282
|
+
cats = {k: i for i, k in enumerate(dict.fromkeys(keys))}
|
|
283
|
+
return array([cats[k] for k in keys], int)
|
|
284
|
+
|
|
285
|
+
@property
|
|
286
|
+
def wnids(self) -> ndarray:
|
|
287
|
+
"""Noise block index per dataset, grouping the datasets by instrument."""
|
|
288
|
+
return self._group_ids(self.instruments)
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
def ins(self) -> list:
|
|
292
|
+
"""Instrument names, under the name `LinearModelBaseline` looks for."""
|
|
293
|
+
return self.instruments
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def piis(self) -> ndarray:
|
|
297
|
+
"""Running index of each dataset within its instrument."""
|
|
298
|
+
counts: dict = {}
|
|
299
|
+
out = []
|
|
300
|
+
for ins in self.instruments:
|
|
301
|
+
out.append(counts.get(ins, 0))
|
|
302
|
+
counts[ins] = out[-1] + 1
|
|
303
|
+
return array(out, int)
|
|
304
|
+
|
|
305
|
+
# Selection
|
|
306
|
+
# ---------
|
|
307
|
+
def select(self, **criteria) -> '_DataGroup':
|
|
308
|
+
"""Return a new group with the datasets matching all the given criteria.
|
|
309
|
+
|
|
310
|
+
Each keyword names an attribute of the contained objects. A tuple-valued attribute
|
|
311
|
+
such as `passband` or `pids` matches by membership, everything else by equality.
|
|
312
|
+
Criteria given as `None` are ignored.
|
|
313
|
+
"""
|
|
314
|
+
def matches(d) -> bool:
|
|
315
|
+
for k, v in criteria.items():
|
|
316
|
+
if v is None:
|
|
317
|
+
continue
|
|
318
|
+
if not hasattr(d, k):
|
|
319
|
+
raise ValueError(f"Unknown selection criterion {k!r} for "
|
|
320
|
+
f"{self._item_type.__name__}.")
|
|
321
|
+
a = getattr(d, k)
|
|
322
|
+
if isinstance(a, tuple):
|
|
323
|
+
if v not in a:
|
|
324
|
+
return False
|
|
325
|
+
elif a != v:
|
|
326
|
+
return False
|
|
327
|
+
return True
|
|
328
|
+
return type(self)([d for d in self.data if matches(d)])
|
|
329
|
+
|
|
330
|
+
def sorted_by(self, key: Union[str, Callable] = 'time') -> '_DataGroup':
|
|
331
|
+
"""Return a new group ordered by `key`.
|
|
332
|
+
|
|
333
|
+
Parameters
|
|
334
|
+
----------
|
|
335
|
+
key
|
|
336
|
+
'time', the name of any attribute of the contained objects, or a callable
|
|
337
|
+
taking one of them and returning a sort key.
|
|
338
|
+
"""
|
|
339
|
+
if callable(key):
|
|
340
|
+
f = key
|
|
341
|
+
elif key == 'time':
|
|
342
|
+
f = lambda d: d.time.min() if d.size else nan
|
|
343
|
+
else:
|
|
344
|
+
if not self.data:
|
|
345
|
+
return type(self)()
|
|
346
|
+
if not hasattr(self.data[0], key):
|
|
347
|
+
raise ValueError(f"Unknown sort key {key!r}, choose 'time', an attribute of "
|
|
348
|
+
f"{self._item_type.__name__}, or pass a callable.")
|
|
349
|
+
f = lambda d: getattr(d, key)
|
|
350
|
+
return type(self)(sorted(self.data, key=f))
|
|
351
|
+
|
|
352
|
+
# Container protocol
|
|
353
|
+
# ------------------
|
|
354
|
+
def __len__(self) -> int:
|
|
355
|
+
return self.size
|
|
356
|
+
|
|
357
|
+
def __iter__(self):
|
|
358
|
+
return iter(self.data)
|
|
359
|
+
|
|
360
|
+
def __getitem__(self, index):
|
|
361
|
+
if isinstance(index, (int, integer)):
|
|
362
|
+
return self.data[index]
|
|
363
|
+
if isinstance(index, slice):
|
|
364
|
+
return type(self)(self.data[index])
|
|
365
|
+
ix = asarray(index)
|
|
366
|
+
if ix.dtype == bool:
|
|
367
|
+
if ix.size != self.size:
|
|
368
|
+
raise IndexError(f"Boolean index has {ix.size} entries but the group has "
|
|
369
|
+
f"{self.size} datasets.")
|
|
370
|
+
return type(self)([d for d, m in zip(self.data, ix) if m])
|
|
371
|
+
if ix.dtype.kind in 'iu':
|
|
372
|
+
return type(self)([self.data[i] for i in ix])
|
|
373
|
+
raise TypeError(f"Cannot index a {type(self).__name__} with {type(index).__name__}.")
|
|
374
|
+
|
|
375
|
+
def __add__(self, other):
|
|
376
|
+
if isinstance(other, type(self)):
|
|
377
|
+
return type(self)(self.data + other.data)
|
|
378
|
+
if isinstance(other, self._item_type):
|
|
379
|
+
return type(self)(self.data + [other])
|
|
380
|
+
return NotImplemented
|
|
381
|
+
|
|
382
|
+
def __radd__(self, other):
|
|
383
|
+
if other == 0 or other is None:
|
|
384
|
+
return type(self)(self.data)
|
|
385
|
+
return NotImplemented
|