asteroid_spinprops 1.3.7__py3-none-any.whl → 1.3.9__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.
- asteroid_spinprops/ssolib/__init__.py +0 -0
- asteroid_spinprops/ssolib/modelfit.py +77 -29
- asteroid_spinprops/ssolib/pipetools.py +167 -0
- asteroid_spinprops/ssolib/ssptools.py +0 -0
- asteroid_spinprops/ssolib/testing/atlas_x_ztf_testing/test_pqfile_1.parquet +0 -0
- asteroid_spinprops/ssolib/testing/atlas_x_ztf_testing/test_pqfile_2.parquet +0 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2000 WL152 +1702 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2001 PC +94 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2001 SG276 +111 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2008 GX32 +93 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2009 BE185 +130 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2011 EY17 +101 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2134 T-1 +352 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Bellmore +2657 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Dermott +2971 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Duke +2026 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Izenberg +2440 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Lermontov +2760 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Poullain +1272 -0
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Sonneberga +2756 -0
- asteroid_spinprops/ssolib/testing/testing_ssoname_keys.pkl +0 -0
- asteroid_spinprops/ssolib/utils.py +37 -0
- {asteroid_spinprops-1.3.7.dist-info → asteroid_spinprops-1.3.9.dist-info}/METADATA +11 -7
- asteroid_spinprops-1.3.9.dist-info/RECORD +28 -0
- asteroid_spinprops-1.3.7.dist-info/RECORD +0 -10
- {asteroid_spinprops-1.3.7.dist-info → asteroid_spinprops-1.3.9.dist-info}/WHEEL +0 -0
|
File without changes
|
|
@@ -4,10 +4,7 @@ import pandas as pd
|
|
|
4
4
|
import asteroid_spinprops.ssolib.utils as utils
|
|
5
5
|
import asteroid_spinprops.ssolib.periodest as periodest
|
|
6
6
|
|
|
7
|
-
from fink_utils.sso.spins import
|
|
8
|
-
estimate_sso_params,
|
|
9
|
-
func_shg1g2,
|
|
10
|
-
)
|
|
7
|
+
from fink_utils.sso.spins import estimate_sso_params, func_shg1g2, parameter_remapping
|
|
11
8
|
from asteroid_spinprops.ssolib.periodest import (
|
|
12
9
|
get_multiterm_period_estimate,
|
|
13
10
|
)
|
|
@@ -25,6 +22,8 @@ def get_fit_params(
|
|
|
25
22
|
period_in=None,
|
|
26
23
|
period_quality_flag=False,
|
|
27
24
|
terminator=False,
|
|
25
|
+
remap=False,
|
|
26
|
+
remap_kwargs=None,
|
|
28
27
|
time_me=True,
|
|
29
28
|
):
|
|
30
29
|
"""
|
|
@@ -188,9 +187,23 @@ def get_fit_params(
|
|
|
188
187
|
rms = []
|
|
189
188
|
model = []
|
|
190
189
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
190
|
+
# Add heliocentric distance mean
|
|
191
|
+
sma = data["Dhelio"].values[0].mean() # in AU
|
|
192
|
+
|
|
193
|
+
W = utils.period_range(sma, period_sy * 24) / 24 # in days
|
|
194
|
+
N = utils.Nintervals(sma)
|
|
195
|
+
|
|
196
|
+
Pmin = period_sy - W
|
|
197
|
+
Pmax = period_sy + W
|
|
198
|
+
|
|
199
|
+
period_scan = np.linspace(Pmin, Pmax, N)
|
|
200
|
+
|
|
201
|
+
if not np.isclose(period_scan, period_sy).any():
|
|
202
|
+
period_scan = np.sort(np.append(period_scan, period_sy))
|
|
203
|
+
|
|
204
|
+
# period_scan = np.linspace(
|
|
205
|
+
# period_sy - 20 / (24 * 60 * 60), period_sy + 20 / (24 * 60 * 60), 20
|
|
206
|
+
# )
|
|
194
207
|
|
|
195
208
|
ra0, dec0 = shg1g2_params["alpha0"], shg1g2_params["delta0"]
|
|
196
209
|
|
|
@@ -264,7 +277,7 @@ def get_fit_params(
|
|
|
264
277
|
H_key = next(
|
|
265
278
|
(
|
|
266
279
|
f"H_{i}" for i in range(1, 7) if f"H_{i}" in shg1g2_params
|
|
267
|
-
), # FIXME: Harcoded N of bands, won't throw error if N>6, but to be
|
|
280
|
+
), # FIXME: Harcoded N of bands, won't throw error if N>6, but to be reconsidered
|
|
268
281
|
None,
|
|
269
282
|
)
|
|
270
283
|
|
|
@@ -300,13 +313,24 @@ def get_fit_params(
|
|
|
300
313
|
a_c,
|
|
301
314
|
0.1,
|
|
302
315
|
] # phi 0
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
316
|
+
if remap:
|
|
317
|
+
SOCCA = get_fit_params(
|
|
318
|
+
data,
|
|
319
|
+
"SOCCA",
|
|
320
|
+
shg1g2_constrained=False,
|
|
321
|
+
p0=p_in,
|
|
322
|
+
terminator=terminator,
|
|
323
|
+
remap=remap,
|
|
324
|
+
remap_kwargs=remap_kwargs,
|
|
325
|
+
)
|
|
326
|
+
else:
|
|
327
|
+
SOCCA = get_fit_params(
|
|
328
|
+
data,
|
|
329
|
+
"SOCCA",
|
|
330
|
+
shg1g2_constrained=False,
|
|
331
|
+
p0=p_in,
|
|
332
|
+
terminator=terminator,
|
|
333
|
+
)
|
|
310
334
|
try:
|
|
311
335
|
rms.append(SOCCA["rms"])
|
|
312
336
|
model.append(SOCCA)
|
|
@@ -421,20 +445,44 @@ def get_fit_params(
|
|
|
421
445
|
print("Initialize SOCCA first!")
|
|
422
446
|
if p0 is not None:
|
|
423
447
|
if terminator:
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
448
|
+
if remap:
|
|
449
|
+
p0in = np.concatenate((p0[3:], p0[:3]))
|
|
450
|
+
p0_latent = parameter_remapping(
|
|
451
|
+
p0in, physical_to_latent=True, **remap_kwargs
|
|
452
|
+
)
|
|
453
|
+
p0_latent = np.concatenate((p0_latent[-3:], p0_latent[:-3]))
|
|
454
|
+
Afit = estimate_sso_params(
|
|
455
|
+
data["cmred"].values[0],
|
|
456
|
+
data["csigmapsf"].values[0],
|
|
457
|
+
np.radians(data["Phase"].values[0]),
|
|
458
|
+
data["cfid"].values[0],
|
|
459
|
+
ra=np.radians(data["ra"].values[0]),
|
|
460
|
+
dec=np.radians(data["dec"].values[0]),
|
|
461
|
+
jd=data["cjd"].values[0],
|
|
462
|
+
model="SOCCA",
|
|
463
|
+
p0=p0_latent,
|
|
464
|
+
terminator=terminator,
|
|
465
|
+
ra_s=np.radians(data["ra_s"].values[0]),
|
|
466
|
+
dec_s=np.radians(data["dec_s"].values[0]),
|
|
467
|
+
bounds=None,
|
|
468
|
+
remap=remap,
|
|
469
|
+
remap_kwargs=remap_kwargs,
|
|
470
|
+
)
|
|
471
|
+
else:
|
|
472
|
+
Afit = estimate_sso_params(
|
|
473
|
+
data["cmred"].values[0],
|
|
474
|
+
data["csigmapsf"].values[0],
|
|
475
|
+
np.radians(data["Phase"].values[0]),
|
|
476
|
+
data["cfid"].values[0],
|
|
477
|
+
ra=np.radians(data["ra"].values[0]),
|
|
478
|
+
dec=np.radians(data["dec"].values[0]),
|
|
479
|
+
jd=data["cjd"].values[0],
|
|
480
|
+
model="SOCCA",
|
|
481
|
+
p0=p0,
|
|
482
|
+
terminator=terminator,
|
|
483
|
+
ra_s=np.radians(data["ra_s"].values[0]),
|
|
484
|
+
dec_s=np.radians(data["dec_s"].values[0]),
|
|
485
|
+
)
|
|
438
486
|
else:
|
|
439
487
|
Afit = estimate_sso_params(
|
|
440
488
|
data["cmred"].values[0],
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from tqdm import tqdm
|
|
3
|
+
import rocks
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from asteroid_spinprops.ssolib.dataprep import filter_sso_data
|
|
7
|
+
from asteroid_spinprops.ssolib.modelfit import get_fit_params, make_residuals_df
|
|
8
|
+
from asteroid_spinprops.ssolib.periodest import (
|
|
9
|
+
get_period_estimate,
|
|
10
|
+
perform_residual_resampling,
|
|
11
|
+
)
|
|
12
|
+
from asteroid_spinprops.ssolib.utils import read_clean_data
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def process_single_sso(name: str, path_args: list, filtering=True) -> tuple | None:
|
|
16
|
+
"""
|
|
17
|
+
Process a single Solar System Object to extract period estimation metrics.
|
|
18
|
+
|
|
19
|
+
Parameters
|
|
20
|
+
----------
|
|
21
|
+
name : str
|
|
22
|
+
Name of the SSO to be processed.
|
|
23
|
+
path_args : list
|
|
24
|
+
Arguments required to locate and load SSO data,
|
|
25
|
+
paths to parquet files and ephemeris cache.
|
|
26
|
+
|
|
27
|
+
Returns
|
|
28
|
+
-------
|
|
29
|
+
tuple or None
|
|
30
|
+
A tuple containing:
|
|
31
|
+
- signal (tuple): Periodogram signal information (power, frequency and the 5 highest peaks).
|
|
32
|
+
- window (tuple): Window function data (power, frequency and the 5 highest peaks).
|
|
33
|
+
- noise (float): Signal noise level.
|
|
34
|
+
- name (str): SSO name.
|
|
35
|
+
- Nbs (int): Bootstrap score.
|
|
36
|
+
- npts (int): Number of data points.
|
|
37
|
+
Returns None if processing fails.
|
|
38
|
+
"""
|
|
39
|
+
try:
|
|
40
|
+
if filtering is True:
|
|
41
|
+
data, _ = filter_sso_data(name, *path_args)
|
|
42
|
+
else:
|
|
43
|
+
data = read_clean_data(name, *path_args, return_rejects=False)
|
|
44
|
+
mparams = get_fit_params(data=data, flavor="SHG1G2")
|
|
45
|
+
resid_df = make_residuals_df(data, mparams)
|
|
46
|
+
signal, window, noise = get_period_estimate(resid_df)
|
|
47
|
+
_, Nbs = perform_residual_resampling(resid_df=resid_df)
|
|
48
|
+
npts = len(data["Phase"].values[0])
|
|
49
|
+
return signal, window, noise, name, Nbs, npts
|
|
50
|
+
except Exception:
|
|
51
|
+
return None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def load_light_curve_data(file_path: str) -> pd.DataFrame:
|
|
55
|
+
"""
|
|
56
|
+
Load a LCDB CSV file and return a dataframe containing objects periods.
|
|
57
|
+
|
|
58
|
+
Parameters
|
|
59
|
+
----------
|
|
60
|
+
file_path : str
|
|
61
|
+
Path to the CSV file containing light curve details.
|
|
62
|
+
|
|
63
|
+
Returns
|
|
64
|
+
-------
|
|
65
|
+
pd.DataFrame
|
|
66
|
+
A DataFrame containing cleaned and filtered light curve data,
|
|
67
|
+
with the 'Period' column converted to float and initial metadata rows skipped.
|
|
68
|
+
"""
|
|
69
|
+
lc = pd.read_csv(file_path, skiprows=range(16))
|
|
70
|
+
lc = lc[5:]
|
|
71
|
+
lc["Period"] = lc["Period"].astype(float)
|
|
72
|
+
return lc
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def fill_missing_periods_and_powers(periods, powers):
|
|
76
|
+
"""
|
|
77
|
+
Replace incomplete period or power arrays with NaN-filled placeholders.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
periods : list of array-like
|
|
82
|
+
List of period arrays estimated for each SSO.
|
|
83
|
+
powers : list of array-like
|
|
84
|
+
List of power arrays associated with each estimated period.
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
None
|
|
89
|
+
The input lists are modified in place.
|
|
90
|
+
"""
|
|
91
|
+
filler = np.full(5, np.nan)
|
|
92
|
+
for i in range(len(periods)):
|
|
93
|
+
if len(periods[i]) < 5:
|
|
94
|
+
periods[i] = filler
|
|
95
|
+
if len(powers[i]) < 5:
|
|
96
|
+
powers[i] = filler
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def collect_rocks_periods(names: list[str]) -> list[np.ndarray]:
|
|
100
|
+
"""
|
|
101
|
+
Retrieve known periods from the SsODNet service for a list of SSOs.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
names : list of str
|
|
106
|
+
List of SSO names to query.
|
|
107
|
+
|
|
108
|
+
Returns
|
|
109
|
+
-------
|
|
110
|
+
list of np.ndarray
|
|
111
|
+
Each element is an array of known periods for the corresponding SSO & method.
|
|
112
|
+
If no valid periods are found, returns two arrays with a single NaN.
|
|
113
|
+
"""
|
|
114
|
+
periods = []
|
|
115
|
+
methods = []
|
|
116
|
+
for sso in tqdm(names, desc="Querying rocks"):
|
|
117
|
+
r = rocks.Rock(sso, datacloud="spins")
|
|
118
|
+
try:
|
|
119
|
+
values = r.spins["period"].values.astype(np.float64)
|
|
120
|
+
method = r.spins["method"].values
|
|
121
|
+
|
|
122
|
+
if (values == [None] * len(values)).all():
|
|
123
|
+
periods.append(np.array([np.nan]))
|
|
124
|
+
methods.append(np.array([np.nan]))
|
|
125
|
+
else:
|
|
126
|
+
periods.append(values[~np.isnan(values)])
|
|
127
|
+
methods.append(method[~np.isnan(values)])
|
|
128
|
+
except Exception:
|
|
129
|
+
periods.append(np.array([np.nan]))
|
|
130
|
+
methods.append(np.array([np.nan]))
|
|
131
|
+
return periods, methods
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def match_true_period(Ps, Procks, Pmethods):
|
|
135
|
+
"""
|
|
136
|
+
Match the closest known period from SsODNet to each estimated period.
|
|
137
|
+
|
|
138
|
+
Parameters
|
|
139
|
+
----------
|
|
140
|
+
Ps : array-like
|
|
141
|
+
Array of estimated periods
|
|
142
|
+
Procks : list of np.ndarray
|
|
143
|
+
List of known periods from Rocks for each SSO.
|
|
144
|
+
|
|
145
|
+
Returns
|
|
146
|
+
-------
|
|
147
|
+
list
|
|
148
|
+
The closest known period from Rocks for each estimate & method.
|
|
149
|
+
Returns NaN if no valid match exists.
|
|
150
|
+
"""
|
|
151
|
+
matched = []
|
|
152
|
+
method = []
|
|
153
|
+
for p_est, p_true, m_true in zip(Ps, Procks, Pmethods):
|
|
154
|
+
if isinstance(p_true, float) or len(p_true) == 0 or np.isnan(p_true).all():
|
|
155
|
+
matched.append(np.nan)
|
|
156
|
+
method.append(np.nan)
|
|
157
|
+
else:
|
|
158
|
+
diffs = np.abs(p_est - p_true[:, None]) / p_true[:, None]
|
|
159
|
+
min_idx = np.argmin(diffs, axis=0)
|
|
160
|
+
matched.append(p_true[min_idx[0]])
|
|
161
|
+
method.append(m_true[min_idx[0]])
|
|
162
|
+
return matched, method
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def filter_sso_name(name, path_args):
|
|
166
|
+
clean_data, rejects = filter_sso_data(name, *path_args, lc_filtering=False)
|
|
167
|
+
return name, clean_data, rejects
|
|
File without changes
|