ExoIris 0.19.2__py3-none-any.whl → 0.20.0__py3-none-any.whl
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.
- exoiris/exoiris.py +85 -12
- exoiris/spotmodel.py +176 -0
- exoiris/tsdata.py +3 -3
- exoiris/tslpf.py +51 -5
- exoiris-0.20.0.dist-info/METADATA +118 -0
- exoiris-0.20.0.dist-info/RECORD +16 -0
- exoiris-0.19.2.dist-info/METADATA +0 -81
- exoiris-0.19.2.dist-info/RECORD +0 -15
- {exoiris-0.19.2.dist-info → exoiris-0.20.0.dist-info}/WHEEL +0 -0
- {exoiris-0.19.2.dist-info → exoiris-0.20.0.dist-info}/licenses/LICENSE +0 -0
- {exoiris-0.19.2.dist-info → exoiris-0.20.0.dist-info}/top_level.txt +0 -0
exoiris/exoiris.py
CHANGED
|
@@ -71,28 +71,38 @@ def load_model(fname: Path | str, name: str | None = None):
|
|
|
71
71
|
"""
|
|
72
72
|
with pf.open(fname) as hdul:
|
|
73
73
|
data = TSDataGroup.import_fits(hdul)
|
|
74
|
+
hdr = hdul[0].header
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
# Read the limb darkening model.
|
|
77
|
+
# ==============================
|
|
78
|
+
if hdr['LDMODEL'] == 'ldtk':
|
|
79
|
+
filters, teff, logg, metal, dataset = pickle.loads(codecs.decode(json.loads(hdr['LDTKLD']).encode(), "base64"))
|
|
77
80
|
ldm = LDTkLD(filters, teff, logg, metal, dataset=dataset)
|
|
78
81
|
else:
|
|
79
|
-
ldm =
|
|
82
|
+
ldm = hdr['LDMODEL']
|
|
80
83
|
|
|
84
|
+
# Read the interpolation model.
|
|
85
|
+
# =============================
|
|
81
86
|
try:
|
|
82
|
-
ip =
|
|
87
|
+
ip = hdr['INTERP']
|
|
83
88
|
except KeyError:
|
|
84
89
|
ip = 'bspline'
|
|
85
90
|
|
|
91
|
+
# Read the noise model.
|
|
92
|
+
# =====================
|
|
86
93
|
try:
|
|
87
|
-
noise_model =
|
|
94
|
+
noise_model = hdr['NOISE']
|
|
88
95
|
except KeyError:
|
|
89
96
|
noise_model = "white"
|
|
90
97
|
|
|
91
|
-
|
|
98
|
+
# Setup the analysis.
|
|
99
|
+
# ===================
|
|
100
|
+
a = ExoIris(name or hdr['NAME'], ldmodel=ldm, data=data, noise_model=noise_model, interpolation=ip)
|
|
92
101
|
a.set_radius_ratio_knots(hdul['K_KNOTS'].data.astype('d'))
|
|
93
102
|
a.set_limb_darkening_knots(hdul['LD_KNOTS'].data.astype('d'))
|
|
94
103
|
|
|
95
104
|
# Read the white light curve models if they exist.
|
|
105
|
+
# ================================================
|
|
96
106
|
try:
|
|
97
107
|
tb = Table.read(hdul['WHITE_DATA'])
|
|
98
108
|
white_ids = tb['id'].data
|
|
@@ -101,18 +111,28 @@ def load_model(fname: Path | str, name: str | None = None):
|
|
|
101
111
|
a._white_fluxes = [tb['flux_obs'].data[white_ids == i] for i in uids]
|
|
102
112
|
a._white_errors = [tb['flux_obs_err'].data[white_ids == i] for i in uids]
|
|
103
113
|
a._white_models = [tb['flux_mod'].data[white_ids == i] for i in uids]
|
|
104
|
-
|
|
105
114
|
except KeyError:
|
|
106
115
|
pass
|
|
107
116
|
|
|
117
|
+
# Read the ephemeris if it exists.
|
|
118
|
+
# ================================
|
|
108
119
|
try:
|
|
109
|
-
a.period =
|
|
110
|
-
a.zero_epoch =
|
|
111
|
-
a.transit_duration =
|
|
120
|
+
a.period = hdr['P']
|
|
121
|
+
a.zero_epoch = hdr['T0']
|
|
122
|
+
a.transit_duration = hdr['T14']
|
|
112
123
|
[d.mask_transit(a.zero_epoch, a.period, a.transit_duration) for d in a.data]
|
|
113
|
-
except KeyError:
|
|
124
|
+
except (KeyError, ValueError):
|
|
114
125
|
pass
|
|
115
126
|
|
|
127
|
+
# Read the spots if they exist.
|
|
128
|
+
# =============================
|
|
129
|
+
if 'SPOTS' in hdr and hdr['SPOTS'] is True:
|
|
130
|
+
a.initialize_spots(hdr["SP_TSTAR"], hdr["SP_REFWL"], hdr["SP_TLSE"])
|
|
131
|
+
for i in range(hdr['NSPOTS']):
|
|
132
|
+
a.add_spot(hdr[f'SP{i+1:02d}_EG'])
|
|
133
|
+
|
|
134
|
+
# Read the priors.
|
|
135
|
+
# ================
|
|
116
136
|
priors = pickle.loads(codecs.decode(json.loads(hdul['PRIORS'].header['PRIORS']).encode(), "base64"))
|
|
117
137
|
a._tsa.ps = ParameterSet([pickle.loads(p) for p in priors])
|
|
118
138
|
a._tsa.ps.freeze()
|
|
@@ -132,7 +152,7 @@ class ExoIris:
|
|
|
132
152
|
|
|
133
153
|
def __init__(self, name: str, ldmodel, data: TSDataGroup | TSData, nk: int = 50, nldc: int = 10, nthreads: int = 1,
|
|
134
154
|
tmpars: dict | None = None, noise_model: Literal["white", "fixed_gp", "free_gp"] = 'white',
|
|
135
|
-
interpolation: Literal['bspline', 'pchip', 'makima'] = '
|
|
155
|
+
interpolation: Literal['bspline', 'pchip', 'makima', 'nearest', 'linear'] = 'makima'):
|
|
136
156
|
"""
|
|
137
157
|
Parameters
|
|
138
158
|
----------
|
|
@@ -343,6 +363,36 @@ class ExoIris:
|
|
|
343
363
|
"""
|
|
344
364
|
self._tsa.set_gp_kernel(kernel)
|
|
345
365
|
|
|
366
|
+
def initialize_spots(self, tstar: float, wlref: float, include_tlse: bool = True):
|
|
367
|
+
"""Initialize star spot model using given stellar and wavelength reference values.
|
|
368
|
+
|
|
369
|
+
Parameters
|
|
370
|
+
----------
|
|
371
|
+
tstar
|
|
372
|
+
Effective stellar temperature [K].
|
|
373
|
+
wlref
|
|
374
|
+
Reference wavelength where spot amplitude matches the amplitude parameter.
|
|
375
|
+
"""
|
|
376
|
+
self._tsa.initialize_spots(tstar, wlref, include_tlse)
|
|
377
|
+
|
|
378
|
+
def add_spot(self, epoch_group: int) -> None:
|
|
379
|
+
"""Add a new star spot and associate it with an epoch group.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
epoch_group
|
|
384
|
+
Identifier for the epoch group to which the spot will be added.
|
|
385
|
+
"""
|
|
386
|
+
self._tsa.add_spot(epoch_group)
|
|
387
|
+
|
|
388
|
+
@property
|
|
389
|
+
def nspots(self) -> int:
|
|
390
|
+
"""Number of star spots."""
|
|
391
|
+
if self._tsa.spot_model is None:
|
|
392
|
+
return 0
|
|
393
|
+
else:
|
|
394
|
+
return self._tsa.spot_model.nspots
|
|
395
|
+
|
|
346
396
|
@property
|
|
347
397
|
def name(self) -> str:
|
|
348
398
|
"""Analysis name."""
|
|
@@ -1095,10 +1145,14 @@ class ExoIris:
|
|
|
1095
1145
|
pri.header['interp'] = self._tsa.interpolation
|
|
1096
1146
|
pri.header['noise'] = self._tsa.noise_model
|
|
1097
1147
|
|
|
1148
|
+
# Priors
|
|
1149
|
+
# ======
|
|
1098
1150
|
pr = pf.ImageHDU(name='priors')
|
|
1099
1151
|
priors = [pickle.dumps(p) for p in self.ps]
|
|
1100
1152
|
pr.header['priors'] = json.dumps(codecs.encode(pickle.dumps(priors), "base64").decode())
|
|
1101
1153
|
|
|
1154
|
+
# Limb darkening
|
|
1155
|
+
# ==============
|
|
1102
1156
|
if isinstance(self._tsa.ldmodel, LDTkLD):
|
|
1103
1157
|
ldm = self._tsa.ldmodel
|
|
1104
1158
|
pri.header['ldmodel'] = 'ldtk'
|
|
@@ -1107,11 +1161,15 @@ class ExoIris:
|
|
|
1107
1161
|
else:
|
|
1108
1162
|
pri.header['ldmodel'] = self._tsa.ldmodel
|
|
1109
1163
|
|
|
1164
|
+
# Knots
|
|
1165
|
+
# =====
|
|
1110
1166
|
k_knots = pf.ImageHDU(self._tsa.k_knots, name='k_knots')
|
|
1111
1167
|
ld_knots = pf.ImageHDU(self._tsa.ld_knots, name='ld_knots')
|
|
1112
1168
|
hdul = pf.HDUList([pri, k_knots, ld_knots, pr])
|
|
1113
1169
|
hdul += self.data.export_fits()
|
|
1114
1170
|
|
|
1171
|
+
# White light curve analysis
|
|
1172
|
+
# ==========================
|
|
1115
1173
|
if self._wa is not None and self._wa._local_minimization is not None:
|
|
1116
1174
|
wa_data = pf.BinTableHDU(
|
|
1117
1175
|
Table(
|
|
@@ -1140,6 +1198,19 @@ class ExoIris:
|
|
|
1140
1198
|
wa_params = pf.BinTableHDU(Table(self._wa._local_minimization.x, names=names), name='white_params')
|
|
1141
1199
|
hdul.append(wa_params)
|
|
1142
1200
|
|
|
1201
|
+
# Spots
|
|
1202
|
+
# =====
|
|
1203
|
+
if self._tsa.spot_model is not None:
|
|
1204
|
+
pri.header['spots'] = True
|
|
1205
|
+
pri.header["sp_tstar"] = self._tsa.spot_model.tphot
|
|
1206
|
+
pri.header["sp_refwl"] = self._tsa.spot_model.wlref
|
|
1207
|
+
pri.header["sp_tlse"] = self._tsa.spot_model.include_tlse
|
|
1208
|
+
pri.header["nspots"] = self.nspots
|
|
1209
|
+
for i in range(self.nspots):
|
|
1210
|
+
pri.header[f"sp{i+1:02d}_eg"] = self._tsa.spot_model.spot_epoch_groups[i]
|
|
1211
|
+
|
|
1212
|
+
# Global optimization results
|
|
1213
|
+
# ===========================
|
|
1143
1214
|
if self._tsa.de is not None:
|
|
1144
1215
|
de = pf.BinTableHDU(Table(self._tsa._de_population, names=self.ps.names), name='DE')
|
|
1145
1216
|
de.header['npop'] = self._tsa.de.n_pop
|
|
@@ -1147,6 +1218,8 @@ class ExoIris:
|
|
|
1147
1218
|
de.header['imin'] = self._tsa.de.minimum_index
|
|
1148
1219
|
hdul.append(de)
|
|
1149
1220
|
|
|
1221
|
+
# MCMC results
|
|
1222
|
+
# ============
|
|
1150
1223
|
if self._tsa.sampler is not None:
|
|
1151
1224
|
mc = pf.BinTableHDU(Table(self._tsa.sampler.flatchain, names=self.ps.names), name='MCMC')
|
|
1152
1225
|
mc.header['npop'] = self._tsa.sampler.nwalkers
|
exoiris/spotmodel.py
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# ExoIris: fast, flexible, and easy exoplanet transmission spectroscopy in Python.
|
|
2
|
+
# Copyright (C) 2025 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 copy import deepcopy
|
|
18
|
+
|
|
19
|
+
from numpy import (
|
|
20
|
+
exp,
|
|
21
|
+
fabs,
|
|
22
|
+
log,
|
|
23
|
+
inf,
|
|
24
|
+
array,
|
|
25
|
+
vstack,
|
|
26
|
+
atleast_2d,
|
|
27
|
+
nan,
|
|
28
|
+
unique,
|
|
29
|
+
linspace,
|
|
30
|
+
floor,
|
|
31
|
+
)
|
|
32
|
+
from scipy.interpolate import RegularGridInterpolator
|
|
33
|
+
from numba import njit
|
|
34
|
+
|
|
35
|
+
from pytransit.stars import create_bt_settl_interpolator, create_husser2013_interpolator
|
|
36
|
+
from pytransit.param import GParameter, UniformPrior as U
|
|
37
|
+
|
|
38
|
+
from exoiris.tsdata import TSData
|
|
39
|
+
from exoiris.util import bin2d
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@njit
|
|
43
|
+
def spot_model(x, center, amplitude, fwhm, shape):
|
|
44
|
+
c = fwhm / 2*(2*log(2))**(1/shape)
|
|
45
|
+
return amplitude*exp(-(fabs(x-center) / c)**shape)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@njit
|
|
49
|
+
def interpolate_spectrum(teff, values, tgrid):
|
|
50
|
+
t0 = tgrid[0]
|
|
51
|
+
dt = tgrid[1] - tgrid[0]
|
|
52
|
+
k = (teff - t0) / dt
|
|
53
|
+
i = int(floor(k))
|
|
54
|
+
a = k - floor(k)
|
|
55
|
+
return (1.0-a)*values[i] + a*values[i+1]
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@njit
|
|
59
|
+
def tlse(tphot, tspot, tfac, aspot, afac, spectra, tgrid):
|
|
60
|
+
fphot = interpolate_spectrum(tphot, spectra, tgrid)
|
|
61
|
+
fspot = interpolate_spectrum(tspot, spectra, tgrid)
|
|
62
|
+
ffac = interpolate_spectrum(tfac, spectra, tgrid)
|
|
63
|
+
return 1.0 / (1.0 - aspot*(1.0 - fspot/fphot) - afac*(1.0 - ffac/fphot))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def spot_contrast(tphot, tspot, spectra, spnorm):
|
|
67
|
+
fphot = interpolate_spectrum(tphot, spectra.values, spectra.grid[0])
|
|
68
|
+
fspot = interpolate_spectrum(tspot, spectra.values, spectra.grid[0])
|
|
69
|
+
norm = interpolate_spectrum(tspot, spnorm, spectra.grid[0])
|
|
70
|
+
return (fphot / fspot) / norm
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def bin_stellar_spectrum_model(sp: RegularGridInterpolator, data: TSData):
|
|
74
|
+
lrange = array(data.bbox_wl) * 1e3
|
|
75
|
+
ml = (sp.grid[1] >= lrange[0]) & (sp.grid[1] <= lrange[1])
|
|
76
|
+
|
|
77
|
+
teff = sp.grid[0]
|
|
78
|
+
wave = sp.grid[1][ml]
|
|
79
|
+
flux = sp.values[:, ml]
|
|
80
|
+
|
|
81
|
+
wl_l_edges = wave - 0.5
|
|
82
|
+
wl_r_edges = wave + 0.5
|
|
83
|
+
|
|
84
|
+
bflux = bin2d(flux.T, flux.T, wl_l_edges*1e-3, wl_r_edges*1e-3, vstack([data._wl_l_edges, data._wl_r_edges]).T)[0].T
|
|
85
|
+
return RegularGridInterpolator((teff, data.wavelength), bflux, bounds_error=False, fill_value=nan)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class SpotModel:
|
|
89
|
+
def __init__(self, tsa, tphot: float, wlref: float, include_tlse: bool = True):
|
|
90
|
+
self.tsa = tsa
|
|
91
|
+
self.tphot = tphot
|
|
92
|
+
self.wlref = wlref
|
|
93
|
+
self.include_tlse = include_tlse
|
|
94
|
+
|
|
95
|
+
ms = create_bt_settl_interpolator()
|
|
96
|
+
new_teff_grid = linspace(*ms.grid[0][[0, -1]], 117)
|
|
97
|
+
new_spectrum = array([ms((t, ms.grid[1])) for t in new_teff_grid])
|
|
98
|
+
self.full_spectrum = ms = RegularGridInterpolator((new_teff_grid, ms.grid[1]), new_spectrum, bounds_error=False, fill_value=nan)
|
|
99
|
+
|
|
100
|
+
wave = ms.grid[1] / 1e3
|
|
101
|
+
m = (wave > wlref - 0.025) & (wave < wlref + 0.025)
|
|
102
|
+
spot_norm = ms.values[:, m].mean(1)
|
|
103
|
+
self.spot_norm = interpolate_spectrum(tphot, spot_norm, ms.grid[0]) / spot_norm
|
|
104
|
+
|
|
105
|
+
self.binned_spectra = []
|
|
106
|
+
for d in tsa.data:
|
|
107
|
+
self.binned_spectra.append(bin_stellar_spectrum_model(self.full_spectrum, d))
|
|
108
|
+
|
|
109
|
+
if self.include_tlse:
|
|
110
|
+
self._init_tlse_parameters()
|
|
111
|
+
|
|
112
|
+
self.nspots = 0
|
|
113
|
+
self.spot_epoch_groups = []
|
|
114
|
+
self.spot_data_ids = []
|
|
115
|
+
self.spot_pv_slices = []
|
|
116
|
+
|
|
117
|
+
def use_tlse(self):
|
|
118
|
+
if self.include_tlse is False:
|
|
119
|
+
self.include_tlse = True
|
|
120
|
+
self._init_tlse_parameters()
|
|
121
|
+
|
|
122
|
+
def _init_tlse_parameters(self):
|
|
123
|
+
ps = [GParameter('tlse_tspot', 'Effective temperature of unocculted spots', 'K', U(1200, 7000), (1200, 7000))]
|
|
124
|
+
ps.append(GParameter('tlse_tfac', 'Effective temperature of unocculted faculae', 'K', U(1200, 7000), (1200, 7000)))
|
|
125
|
+
for e in unique(self.tsa.data.epoch_groups):
|
|
126
|
+
ps.append(GParameter(f"tlse_aspot_e{e:02d}", "Area fraction covered by unocculted spots", "", U(0,1), (0,1)))
|
|
127
|
+
ps.append(GParameter(f"tlse_afac_e{e:02d}", "Area fraction covered by unocculted faculae", "", U(0,1), (0,1)))
|
|
128
|
+
self.tsa.ps.thaw()
|
|
129
|
+
self.tsa.ps.add_global_block(f'tlse', ps)
|
|
130
|
+
setattr(self.tsa, "_start_tlse", self.tsa.ps.blocks[-1].start)
|
|
131
|
+
setattr(self.tsa, "_sl_tlse", self.tsa.ps.blocks[-1].slice)
|
|
132
|
+
self.tlse_pv_slice = self.tsa.ps.blocks[-1].slice
|
|
133
|
+
self.tsa.ps.freeze()
|
|
134
|
+
|
|
135
|
+
def add_spot(self, epoch_group: int):
|
|
136
|
+
self.nspots += 1
|
|
137
|
+
self.spot_epoch_groups.append(epoch_group)
|
|
138
|
+
self.spot_data_ids.append([i for i, d in enumerate(self.tsa.data) if d.epoch_group == epoch_group])
|
|
139
|
+
|
|
140
|
+
i = self.nspots
|
|
141
|
+
pspot = [GParameter(f"spc_{i:02d}", 'spot {i:02d} center', "d", U(0, 1), (0, inf)),
|
|
142
|
+
GParameter(f"spa_{i:02d}", 'spot {i:02d} amplitude', "", U(0, 1), (0, inf)),
|
|
143
|
+
GParameter(f"spw_{i:02d}", 'spot {i:02d} FWHM', "d", U(0, 1), (0, inf)),
|
|
144
|
+
GParameter(f"sps_{i:02d}", 'spot {i:02d} shape', "d", U(1, 5), (0, inf)),
|
|
145
|
+
GParameter(f"spt_{i:02d}", 'spot {i:02d} temperature', "K", U(3000, 6000), (0, inf))]
|
|
146
|
+
ps = self.tsa.ps
|
|
147
|
+
ps.thaw()
|
|
148
|
+
ps.add_global_block(f'spot_{i:02d}', pspot)
|
|
149
|
+
setattr(self.tsa, f"_start_spot_{i:02d}", ps.blocks[-1].start)
|
|
150
|
+
setattr(self.tsa, f"_sl_spot_{i:02d}", ps.blocks[-1].slice)
|
|
151
|
+
self.spot_pv_slices.append(ps.blocks[-1].slice)
|
|
152
|
+
ps.freeze()
|
|
153
|
+
|
|
154
|
+
def apply_tlse(self, pvp, models):
|
|
155
|
+
pvp = atleast_2d(pvp)[:, self.tlse_pv_slice]
|
|
156
|
+
npv = pvp.shape[0]
|
|
157
|
+
for d, m, sp in zip(self.tsa.data, models, self.binned_spectra):
|
|
158
|
+
for i in range(npv):
|
|
159
|
+
tspot = pvp[i, 0]
|
|
160
|
+
tfac = pvp[i, 1]
|
|
161
|
+
fspot = pvp[i, 2+d.epoch_group*2]
|
|
162
|
+
ffac = pvp[i, 3+d.epoch_group*2]
|
|
163
|
+
m[i, :, :] = (m[i, :, :] - 1.0) * tlse(self.tphot, tspot, tfac, fspot, ffac, sp.values, sp.grid[0])[:, None] + 1
|
|
164
|
+
|
|
165
|
+
def apply_spots(self, pvp, models):
|
|
166
|
+
pvp = atleast_2d(pvp)
|
|
167
|
+
npv = pvp.shape[0]
|
|
168
|
+
if models[0].shape[0] != npv:
|
|
169
|
+
raise ValueError('The _spot_models array has a wrong shape, it has not been initialized properly.')
|
|
170
|
+
|
|
171
|
+
for isp in range(self.nspots):
|
|
172
|
+
for ipv in range(npv):
|
|
173
|
+
center, amplitude, fwhm, shape, tspot = pvp[ipv, self.spot_pv_slices[isp]]
|
|
174
|
+
for idata in self.spot_data_ids[isp]:
|
|
175
|
+
models[idata][ipv, :, :] += (spot_model(self.tsa.data[idata].time, center, amplitude, fwhm, shape) *
|
|
176
|
+
spot_contrast(self.tphot, tspot, self.binned_spectra[idata], self.spot_norm)[:, None])
|
exoiris/tsdata.py
CHANGED
|
@@ -274,7 +274,7 @@ class TSData:
|
|
|
274
274
|
self.transit_mask = ones(self.fluxes.shape, bool)
|
|
275
275
|
self.transit_mask[:, elims[0]:elims[1]] = False
|
|
276
276
|
else:
|
|
277
|
-
raise ValueError("Transit masking requires either t0,
|
|
277
|
+
raise ValueError("Transit masking requires either t0, p, and t14, ephemeris, or transit limits in exposure indices.")
|
|
278
278
|
return self
|
|
279
279
|
|
|
280
280
|
def estimate_average_uncertainties(self):
|
|
@@ -568,8 +568,8 @@ class TSData:
|
|
|
568
568
|
axx2.set_xlabel('Exposure index')
|
|
569
569
|
axx2.xaxis.set_major_locator(LinearLocator())
|
|
570
570
|
axx2.xaxis.set_major_formatter('{x:.0f}')
|
|
571
|
-
|
|
572
|
-
|
|
571
|
+
ax.axx2 = axx2
|
|
572
|
+
ax.axy2 = axy2
|
|
573
573
|
return fig
|
|
574
574
|
|
|
575
575
|
def plot_white(self, ax: Axes | None = None, figsize: tuple[float, float] | None = None) -> Figure:
|
exoiris/tslpf.py
CHANGED
|
@@ -28,11 +28,20 @@ from pytransit.lpf.logposteriorfunction import LogPosteriorFunction
|
|
|
28
28
|
|
|
29
29
|
from pytransit.orbits import as_from_rhop, i_from_ba, fold, i_from_baew, d_from_pkaiews, epoch
|
|
30
30
|
from pytransit.param import ParameterSet, UniformPrior as UP, NormalPrior as NP, GParameter
|
|
31
|
-
from
|
|
31
|
+
from pytransit.stars import create_bt_settl_interpolator
|
|
32
|
+
from scipy.interpolate import (
|
|
33
|
+
pchip_interpolate,
|
|
34
|
+
splrep,
|
|
35
|
+
splev,
|
|
36
|
+
Akima1DInterpolator,
|
|
37
|
+
interp1d,
|
|
38
|
+
FloaterHormannInterpolator,
|
|
39
|
+
)
|
|
32
40
|
|
|
33
41
|
from .tsmodel import TransmissionSpectroscopyModel as TSModel
|
|
34
42
|
from .tsdata import TSDataGroup
|
|
35
43
|
from .ldtkld import LDTkLD
|
|
44
|
+
from .spotmodel import SpotModel
|
|
36
45
|
|
|
37
46
|
NM_WHITE = 0
|
|
38
47
|
NM_GP_FIXED = 1
|
|
@@ -81,6 +90,14 @@ def ip_makima(x, xk, yk):
|
|
|
81
90
|
return Akima1DInterpolator(xk, yk, method='makima', extrapolate=True)(x)
|
|
82
91
|
|
|
83
92
|
|
|
93
|
+
def ip_nearest(x, xk, yk):
|
|
94
|
+
return interp1d(xk, yk, kind='nearest', bounds_error=False, fill_value='extrapolate', assume_sorted=True)(x)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def ip_linear(x, xk, yk):
|
|
98
|
+
return interp1d(xk, yk, kind='linear', bounds_error=False, fill_value='extrapolate', assume_sorted=True)(x)
|
|
99
|
+
|
|
100
|
+
|
|
84
101
|
def add_knots(x_new, x_old):
|
|
85
102
|
return sort(concatenate([x_new, x_old]))
|
|
86
103
|
|
|
@@ -126,7 +143,7 @@ def clean_knots(knots, min_distance, lmin=0, lmax=inf):
|
|
|
126
143
|
class TSLPF(LogPosteriorFunction):
|
|
127
144
|
def __init__(self, runner, name: str, ldmodel, data: TSDataGroup, nk: int = 50, nldc: int = 10, nthreads: int = 1,
|
|
128
145
|
tmpars = None, noise_model: Literal["white", "fixed_gp", "free_gp"] = 'white',
|
|
129
|
-
interpolation: Literal['bspline', 'pchip', 'makima'] = '
|
|
146
|
+
interpolation: Literal['bspline', 'pchip', 'makima', 'nearest', 'linear'] = 'makima'):
|
|
130
147
|
super().__init__(name)
|
|
131
148
|
self._runner = runner
|
|
132
149
|
self._original_data: TSDataGroup | None = None
|
|
@@ -137,7 +154,8 @@ class TSLPF(LogPosteriorFunction):
|
|
|
137
154
|
self._baseline_models: list[ndarray] | None = None
|
|
138
155
|
self.interpolation: str = interpolation
|
|
139
156
|
|
|
140
|
-
self._ip = {'bspline': ip_bspline, 'pchip': ip_pchip, 'makima': ip_makima
|
|
157
|
+
self._ip = {'bspline': ip_bspline, 'pchip': ip_pchip, 'makima': ip_makima,
|
|
158
|
+
'nearest': ip_nearest, 'linear': ip_linear}[interpolation]
|
|
141
159
|
|
|
142
160
|
self._gp: Optional[list[GP]] = None
|
|
143
161
|
self._gp_time: Optional[list[ndarray]] = None
|
|
@@ -147,6 +165,9 @@ class TSLPF(LogPosteriorFunction):
|
|
|
147
165
|
self.set_data(data)
|
|
148
166
|
self.set_noise_model(noise_model)
|
|
149
167
|
|
|
168
|
+
self.spot_model: SpotModel | None = None
|
|
169
|
+
self.spot_model_fluxes = []
|
|
170
|
+
|
|
150
171
|
self.ldmodel = ldmodel
|
|
151
172
|
if isinstance(ldmodel, LDTkLD):
|
|
152
173
|
for tm in self.tms:
|
|
@@ -211,6 +232,19 @@ class TSLPF(LogPosteriorFunction):
|
|
|
211
232
|
self.ps.freeze()
|
|
212
233
|
self.ndim = len(self.ps)
|
|
213
234
|
|
|
235
|
+
def initialize_spots(self, tstar: float, wlref: float, include_tlse: bool = True) -> None:
|
|
236
|
+
self.spot_model = SpotModel(self, tstar, wlref, include_tlse)
|
|
237
|
+
|
|
238
|
+
def add_spot(self, epoch_group: int) -> None:
|
|
239
|
+
"""Adds a new star spot.
|
|
240
|
+
|
|
241
|
+
Parameters
|
|
242
|
+
----------
|
|
243
|
+
epoch_group : int
|
|
244
|
+
The identifier of the epoch group to which the spot belongs.
|
|
245
|
+
"""
|
|
246
|
+
self.spot_model.add_spot(epoch_group)
|
|
247
|
+
|
|
214
248
|
def set_noise_model(self, noise_model: str) -> None:
|
|
215
249
|
"""Sets the noise model for the analysis.
|
|
216
250
|
|
|
@@ -434,6 +468,14 @@ class TSLPF(LogPosteriorFunction):
|
|
|
434
468
|
sln = self._sl_rratios
|
|
435
469
|
ndn = self.ndim
|
|
436
470
|
|
|
471
|
+
# Check if we have spots
|
|
472
|
+
# ----------------------
|
|
473
|
+
if self.spot_model is not None:
|
|
474
|
+
spots = self.spot_model
|
|
475
|
+
self.initialize_spots(spots.tphot, spots.wlref, spots.include_tlse)
|
|
476
|
+
for eg in spots.spot_epoch_groups:
|
|
477
|
+
self.spot_model.add_spot(eg)
|
|
478
|
+
|
|
437
479
|
# Set the priors back as they were
|
|
438
480
|
# --------------------------------
|
|
439
481
|
for po in pso:
|
|
@@ -566,8 +608,8 @@ class TSLPF(LogPosteriorFunction):
|
|
|
566
608
|
ldp = [zeros((pvp.shape[0], npb, 2)) for npb in self.npb]
|
|
567
609
|
for ids in range(self.data.size):
|
|
568
610
|
for ipv in range(pvp.shape[0]):
|
|
569
|
-
ldp[ids][ipv, :, 0] =
|
|
570
|
-
ldp[ids][ipv, :, 1] =
|
|
611
|
+
ldp[ids][ipv, :, 0] = ip_bspline(self.wavelengths[ids], self.ld_knots, ldk[ipv, :, 0])
|
|
612
|
+
ldp[ids][ipv, :, 1] = ip_bspline(self.wavelengths[ids], self.ld_knots, ldk[ipv, :, 1])
|
|
571
613
|
return ldp
|
|
572
614
|
|
|
573
615
|
def transit_model(self, pv, copy=True):
|
|
@@ -642,6 +684,10 @@ class TSLPF(LogPosteriorFunction):
|
|
|
642
684
|
def flux_model(self, pv):
|
|
643
685
|
transit_models = self.transit_model(pv)
|
|
644
686
|
baseline_models = self.baseline_model(pv)
|
|
687
|
+
if self.spot_model is not None:
|
|
688
|
+
self.spot_model.apply_spots(pv, transit_models)
|
|
689
|
+
if self.spot_model.include_tlse:
|
|
690
|
+
self.spot_model.apply_tlse(pv, transit_models)
|
|
645
691
|
for i in range(self.data.size):
|
|
646
692
|
transit_models[i][:, :, :] *= baseline_models[i][:, :, newaxis]
|
|
647
693
|
return transit_models
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ExoIris
|
|
3
|
+
Version: 0.20.0
|
|
4
|
+
Summary: Easy and robust exoplanet transmission spectroscopy.
|
|
5
|
+
Author-email: Hannu Parviainen <hannu@iac.es>
|
|
6
|
+
License: GPLv3
|
|
7
|
+
Project-URL: homepage, https://github.com/hpparvi/ExoIris
|
|
8
|
+
Keywords: astronomy,astrophysics,exoplanets
|
|
9
|
+
Classifier: Topic :: Scientific/Engineering
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: pytransit>=2.6.15
|
|
20
|
+
Requires-Dist: ldtk>=1.8.5
|
|
21
|
+
Requires-Dist: numpy
|
|
22
|
+
Requires-Dist: scipy
|
|
23
|
+
Requires-Dist: numba
|
|
24
|
+
Requires-Dist: emcee
|
|
25
|
+
Requires-Dist: matplotlib
|
|
26
|
+
Requires-Dist: celerite2
|
|
27
|
+
Requires-Dist: pandas
|
|
28
|
+
Requires-Dist: xarray
|
|
29
|
+
Requires-Dist: seaborn
|
|
30
|
+
Requires-Dist: astropy
|
|
31
|
+
Requires-Dist: uncertainties
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# ExoIris: Fast and Flexible Transmission Spectroscopy in Python
|
|
35
|
+
|
|
36
|
+
[](https://exoiris.readthedocs.io)
|
|
37
|
+

|
|
38
|
+
[](CODE_OF_CONDUCT.md)
|
|
39
|
+
[](http://www.gnu.org/licenses/gpl-3.0.html)
|
|
40
|
+
[](https://pypi.org/project/ExoIris/)
|
|
41
|
+
|
|
42
|
+
**ExoIris** is a Python package for modeling exoplanet transmission spectroscopy. ExoIris removes the typical
|
|
43
|
+
limitations of the two-step workflow by modeling the full two-dimensional spectroscopic transit time series *directly*.
|
|
44
|
+
It supports combining transmission spectroscopy datasets from multiple instruments observed in different epochs, yielding
|
|
45
|
+
self-consistent wavelength-independent and wavelength-dependent parameters, simplifying joint analyses, and delivering
|
|
46
|
+
results quickly.
|
|
47
|
+
|
|
48
|
+

|
|
49
|
+
|
|
50
|
+
## Why ExoIris?
|
|
51
|
+
|
|
52
|
+
Transmission spectroscopy is often done following a **two-step workflow**: (1) fit a white light curve to infer
|
|
53
|
+
wavelength-independent parameters; (2) fit each spectroscopic light curve independently, constrained by the white-light
|
|
54
|
+
solution. This split can introduce approximations and inconsistencies.
|
|
55
|
+
|
|
56
|
+
**ExoIris takes a different approach.** It models spectrophotometric time series *end-to-end*, enabling:
|
|
57
|
+
|
|
58
|
+
- Self-consistent inference of shared (wavelength-independent) and spectral (wavelength-dependent) parameters.
|
|
59
|
+
- **Joint** modeling of multiple datasets from different instruments and epochs.
|
|
60
|
+
- Accounting for **transit timing variations** and dataset-dependent offsets within a unified framework.
|
|
61
|
+
|
|
62
|
+
This design is a natural fit for **JWST-class** data, where correlated noise, multi-epoch observations, and
|
|
63
|
+
cross-instrument combinations are the norm.
|
|
64
|
+
|
|
65
|
+
## Documentation
|
|
66
|
+
|
|
67
|
+
Full documentation and tutorials: <https://exoiris.readthedocs.io>
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
Install from PyPI:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install exoiris
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Latest development version:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
git clone https://github.com/hpparvi/ExoIris.git
|
|
81
|
+
cd ExoIris
|
|
82
|
+
pip install -e .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
ExoIris supports Python 3.9+. See the docs for dependency details and optional extras.
|
|
86
|
+
|
|
87
|
+
## Key Features
|
|
88
|
+
|
|
89
|
+
- **Direct modelling of spectroscopic transit time series**
|
|
90
|
+
Built on PyTransit’s `TSModel`, optimised for transmission spectroscopy; scales to hundreds–thousands of light curves simultaneously.
|
|
91
|
+
|
|
92
|
+
- **Flexible limb darkening**
|
|
93
|
+
Use standard analytical laws (quadratic, power-2, non-linear), numerical intensity profiles from stellar atmosphere models, or user-defined radially symmetric functions.
|
|
94
|
+
|
|
95
|
+
- **Robust noise treatment**
|
|
96
|
+
Choose white noise or **time-correlated** noise via a Gaussian Process likelihood, without changing the overall workflow.
|
|
97
|
+
|
|
98
|
+
- **Full control of spectral resolution**
|
|
99
|
+
The transmission spectrum is represented as a cubic spline with user-defined knots, allowing variable resolution across wavelength.
|
|
100
|
+
|
|
101
|
+
- **Reproducible, incremental workflows**
|
|
102
|
+
Save and reload models to refine a low-resolution run into a high-resolution analysis seamlessly.
|
|
103
|
+
|
|
104
|
+
- **Joint multi-dataset analyses**
|
|
105
|
+
Combine instruments and epochs in one fit, with support for transit timing variations and dataset-specific systematics and offsets.
|
|
106
|
+
|
|
107
|
+
## Performance
|
|
108
|
+
|
|
109
|
+
ExoIris is designed for speed and stability:
|
|
110
|
+
|
|
111
|
+
- A transmission spectroscopy analysis of a single JWST/NIRISS dataset at **R ≈ 100** typically runs in **3–5 minutes**
|
|
112
|
+
assuming white noise, or **5–15 minutes** with a GP noise model, on a standard desktop CPU.
|
|
113
|
+
- A high-resolution analysis of the JWST/NIRISS **WASP-39 b** dataset (~3800 spectroscopic light curves; see Feinstein
|
|
114
|
+
et al. 2023) can be optimised and sampled in about **1.5 hours** on an AMD Ryzen 7 5800X (8 cores, ~3-year-old desktop).
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
118
|
+
© 2025 Hannu Parviainen
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
exoiris/__init__.py,sha256=LU5jAE7_OVPLHFO0UAOGS0e0wuWV6rdSD0Qveet11K8,1147
|
|
2
|
+
exoiris/binning.py,sha256=-Y9hdK0jZj8DOS82keaprneid2lZ4rCx-keWlKi0LP8,6455
|
|
3
|
+
exoiris/ephemeris.py,sha256=dthBkJztT5yAP6VnnO7jGvxikboFUQBUGPUfBCFrA3w,1316
|
|
4
|
+
exoiris/exoiris.py,sha256=POqkyc9hM5YmARDRtVN6k0l6N63hk6g_ecOR8Y4Z_2o,53838
|
|
5
|
+
exoiris/ldtkld.py,sha256=7H1r1xail3vSKdsNKorMTqivnRKU9WrOVH-uE4Ky2jM,3495
|
|
6
|
+
exoiris/spotmodel.py,sha256=9-DxvVzGzxf6AjQfrzZreyJB4Htw0gsIAD3nWl0tQMc,7160
|
|
7
|
+
exoiris/tsdata.py,sha256=WqId5rfZR08pFZ83UZiyO39-QjX6WcB1GrUYolZsM-4,35323
|
|
8
|
+
exoiris/tslpf.py,sha256=yFyMjvx8P9t55wYGGfoEZ8u3Yw1H7T4Ot-dsnT2oQEw,31316
|
|
9
|
+
exoiris/tsmodel.py,sha256=6NaGY48fWHUT_7ti6Ao618PN-LgyoIhfQd8lZQqZ7hU,5160
|
|
10
|
+
exoiris/util.py,sha256=5PynwYYHRrzyXJHskBtp2J-pcM59zsA1_VtDxencQm4,4630
|
|
11
|
+
exoiris/wlpf.py,sha256=g6h1cLk2-nKD8u_FzwXNVVGFK4dry8fBr0A70LA5gJw,6281
|
|
12
|
+
exoiris-0.20.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
13
|
+
exoiris-0.20.0.dist-info/METADATA,sha256=LfJuP-1bFOckme0rDdzOcohvnUeuvspSNQ_m9_yNrbc,5056
|
|
14
|
+
exoiris-0.20.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
15
|
+
exoiris-0.20.0.dist-info/top_level.txt,sha256=EoNxT6c5mQDcM0f_LUQB-ETsYg03lNaV3o2L_Yc6-aE,8
|
|
16
|
+
exoiris-0.20.0.dist-info/RECORD,,
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: ExoIris
|
|
3
|
-
Version: 0.19.2
|
|
4
|
-
Summary: Easy and robust exoplanet transmission spectroscopy.
|
|
5
|
-
Author-email: Hannu Parviainen <hannu@iac.es>
|
|
6
|
-
License: GPLv3
|
|
7
|
-
Project-URL: homepage, https://github.com/hpparvi/ExoIris
|
|
8
|
-
Keywords: astronomy,astrophysics,exoplanets
|
|
9
|
-
Classifier: Topic :: Scientific/Engineering
|
|
10
|
-
Classifier: Intended Audience :: Science/Research
|
|
11
|
-
Classifier: Intended Audience :: Developers
|
|
12
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
13
|
-
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
14
|
-
Classifier: Operating System :: OS Independent
|
|
15
|
-
Classifier: Programming Language :: Python
|
|
16
|
-
Requires-Python: >=3.10
|
|
17
|
-
Description-Content-Type: text/markdown
|
|
18
|
-
License-File: LICENSE
|
|
19
|
-
Requires-Dist: pytransit>=2.6.15
|
|
20
|
-
Requires-Dist: ldtk>=1.8.5
|
|
21
|
-
Requires-Dist: numpy
|
|
22
|
-
Requires-Dist: scipy
|
|
23
|
-
Requires-Dist: numba
|
|
24
|
-
Requires-Dist: emcee
|
|
25
|
-
Requires-Dist: matplotlib
|
|
26
|
-
Requires-Dist: celerite2
|
|
27
|
-
Requires-Dist: pandas
|
|
28
|
-
Requires-Dist: xarray
|
|
29
|
-
Requires-Dist: seaborn
|
|
30
|
-
Requires-Dist: astropy
|
|
31
|
-
Requires-Dist: uncertainties
|
|
32
|
-
Dynamic: license-file
|
|
33
|
-
|
|
34
|
-
# ExoIris: Transmission Spectroscopy Made Easy
|
|
35
|
-
|
|
36
|
-
[](https://exoiris.readthedocs.io)
|
|
37
|
-

|
|
38
|
-
[](CODE_OF_CONDUCT.md)
|
|
39
|
-
[](http://www.gnu.org/licenses/gpl-3.0.html)
|
|
40
|
-
[](https://pypi.org/project/ExoIris/)
|
|
41
|
-
|
|
42
|
-
**ExoIris** is a user-friendly Python package designed to simplify and accelerate the analysis of transmission
|
|
43
|
-
spectroscopy data for exoplanets. The package can estimate a self-consistent medium-resolution transmission spectrum
|
|
44
|
-
with uncertainties from JWST NIRISS data in minutes, even when using a Gaussian Process-based noise model.
|
|
45
|
-
|
|
46
|
-

|
|
47
|
-
|
|
48
|
-
## Documentation
|
|
49
|
-
|
|
50
|
-
Read the docs at [exoiris.readthedocs.io](https://exoiris.readthedocs.io).
|
|
51
|
-
|
|
52
|
-
## Key Features
|
|
53
|
-
|
|
54
|
-
- **Fast modelling of spectroscopic transit time series**: ExoIris uses PyTransit's advanced `TSModel` transit
|
|
55
|
-
model that is specially tailored for fast and efficient modelling of spectroscopic transit (or eclipse) time series.
|
|
56
|
-
- **Flexible handling of limb darkening**: The stellar limb darkening can be modelled freely either by any of the standard
|
|
57
|
-
limb darkening laws (quadratic, power-2, non-linear, etc.), by numerical stellar intensity profiles obtained
|
|
58
|
-
directly from stellar atmosphere models, or by an arbitrary ser-defined radially symmetric function.
|
|
59
|
-
- **Handling of Correlated noise**: The noise model can be chosen between white or time-correlated noise, where the
|
|
60
|
-
time-correlated noise is modelled as a Gaussian process.
|
|
61
|
-
- **Model saving and loading**: Seamless model saving and loading allows one to create a high-resolution analysis starting
|
|
62
|
-
from a saved low-resolution analysis.
|
|
63
|
-
- **Full control of resolution**: ExoIris represents the transmission spectrum as a cubic spline, with complete
|
|
64
|
-
flexibility to set and modify the number and placement of spline knots, allowing variable resolution throughout the
|
|
65
|
-
analysis.
|
|
66
|
-
|
|
67
|
-
## Details
|
|
68
|
-
|
|
69
|
-
ExoIris uses PyTransit's `TSModel`, a transit model that is specially optimised for transmission spectroscopy and allows
|
|
70
|
-
for simultaneous modelling of hundreds to thousands of spectroscopic light curves 20-30 times faster than when using
|
|
71
|
-
standard transit models not explicitly designed for transmission spectroscopy.
|
|
72
|
-
|
|
73
|
-
A complete posterior solution for a low-resolution transmission spectrum with a data resolution of R=100
|
|
74
|
-
takes 3-5 minutes to estimate assuming white noise, or 5-15 minutes if using a Gaussian process-based likelihood
|
|
75
|
-
model powered by the celerite2 package. A high-resolution spectrum of the JWST NIRISS WASP-39 b observations
|
|
76
|
-
by [Feinstein et al. (2023)](https://ui.adsabs.harvard.edu/abs/2023Natur.614..670F/abstract) with ~3800
|
|
77
|
-
spectroscopic light curves (as shown above) takes about 1.5 hours to optimise and sample on a three-year-old
|
|
78
|
-
AMD Ryzen 7 5800X with eight cores.
|
|
79
|
-
|
|
80
|
-
---
|
|
81
|
-
© 2024 Hannu Parviainen
|
exoiris-0.19.2.dist-info/RECORD
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
exoiris/__init__.py,sha256=LU5jAE7_OVPLHFO0UAOGS0e0wuWV6rdSD0Qveet11K8,1147
|
|
2
|
-
exoiris/binning.py,sha256=-Y9hdK0jZj8DOS82keaprneid2lZ4rCx-keWlKi0LP8,6455
|
|
3
|
-
exoiris/ephemeris.py,sha256=dthBkJztT5yAP6VnnO7jGvxikboFUQBUGPUfBCFrA3w,1316
|
|
4
|
-
exoiris/exoiris.py,sha256=s-q5QoV2Vj4qDHfocXrdZZo0C99E3iTr3g8OjTTgaug,51312
|
|
5
|
-
exoiris/ldtkld.py,sha256=7H1r1xail3vSKdsNKorMTqivnRKU9WrOVH-uE4Ky2jM,3495
|
|
6
|
-
exoiris/tsdata.py,sha256=jEaoz9EvUtbZ3GS-W9ymp07NR952gfiBPlhs4Olll6I,35326
|
|
7
|
-
exoiris/tslpf.py,sha256=mpzYdubNXkeLAaQdUKKBuKJ6iDN_KEl4cOh4wcBB-g0,29734
|
|
8
|
-
exoiris/tsmodel.py,sha256=6NaGY48fWHUT_7ti6Ao618PN-LgyoIhfQd8lZQqZ7hU,5160
|
|
9
|
-
exoiris/util.py,sha256=5PynwYYHRrzyXJHskBtp2J-pcM59zsA1_VtDxencQm4,4630
|
|
10
|
-
exoiris/wlpf.py,sha256=g6h1cLk2-nKD8u_FzwXNVVGFK4dry8fBr0A70LA5gJw,6281
|
|
11
|
-
exoiris-0.19.2.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
12
|
-
exoiris-0.19.2.dist-info/METADATA,sha256=rmLHmfpXXera-ZGV_S3CHVi5oakrP317i-oeLrEaoYM,4214
|
|
13
|
-
exoiris-0.19.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
14
|
-
exoiris-0.19.2.dist-info/top_level.txt,sha256=EoNxT6c5mQDcM0f_LUQB-ETsYg03lNaV3o2L_Yc6-aE,8
|
|
15
|
-
exoiris-0.19.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|