asteroid_spinprops 0.2.32__py3-none-any.whl → 1.0.1__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/dataprep.py +0 -346
- asteroid_spinprops/ssolib/modelfit.py +143 -252
- asteroid_spinprops/ssolib/periodest.py +126 -158
- asteroid_spinprops/ssolib/utils.py +164 -211
- asteroid_spinprops-1.0.1.dist-info/METADATA +186 -0
- asteroid_spinprops-1.0.1.dist-info/RECORD +10 -0
- asteroid_spinprops/ssolib/.ruff_cache/.gitignore +0 -2
- asteroid_spinprops/ssolib/.ruff_cache/0.13.2/1980339045096230685 +0 -0
- asteroid_spinprops/ssolib/.ruff_cache/CACHEDIR.TAG +0 -1
- asteroid_spinprops/ssolib/pipetools.py +0 -167
- 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 +0 -1702
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2001 PC +0 -94
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2001 SG276 +0 -111
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2008 GX32 +0 -93
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2009 BE185 +0 -130
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2011 EY17 +0 -101
- asteroid_spinprops/ssolib/testing/ephemeris_testing/2134 T-1 +0 -352
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Bellmore +0 -2657
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Dermott +0 -2971
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Duke +0 -2026
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Izenberg +0 -2440
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Lermontov +0 -2760
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Poullain +0 -1272
- asteroid_spinprops/ssolib/testing/ephemeris_testing/Sonneberga +0 -2756
- asteroid_spinprops/ssolib/testing/testing_ssoname_keys.pkl +0 -0
- asteroid_spinprops-0.2.32.dist-info/METADATA +0 -77
- asteroid_spinprops-0.2.32.dist-info/RECORD +0 -31
- {asteroid_spinprops-0.2.32.dist-info → asteroid_spinprops-1.0.1.dist-info}/WHEEL +0 -0
|
@@ -1,16 +1,10 @@
|
|
|
1
1
|
import numpy as np
|
|
2
2
|
import pandas as pd
|
|
3
|
-
import asteroid_spinprops.ssolib.ssptools as ssptools
|
|
4
|
-
|
|
5
|
-
import matplotlib.pyplot as plt
|
|
6
|
-
|
|
7
|
-
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
|
|
8
3
|
|
|
9
4
|
import asteroid_spinprops.ssolib.utils as utils
|
|
10
5
|
|
|
11
6
|
from fink_utils.sso.spins import (
|
|
12
7
|
estimate_sso_params,
|
|
13
|
-
func_sshg1g2,
|
|
14
8
|
func_hg1g2_with_spin,
|
|
15
9
|
)
|
|
16
10
|
from asteroid_spinprops.ssolib.periodest import get_period_estimate
|
|
@@ -26,8 +20,66 @@ def get_fit_params(
|
|
|
26
20
|
alt_spin=False,
|
|
27
21
|
period_in=None,
|
|
28
22
|
terminator=False,
|
|
29
|
-
pole_metadata=False,
|
|
30
23
|
):
|
|
24
|
+
"""
|
|
25
|
+
Fit a small solar system object's photometric data using SHG1G2 or SOCCA models.
|
|
26
|
+
|
|
27
|
+
This function can perform either a standard SHG1G2 fit or a spin- and
|
|
28
|
+
shape-constrained SOCCA fit, optionally including blind scans over
|
|
29
|
+
initial pole positions and periods. It supports filtering data by survey.
|
|
30
|
+
|
|
31
|
+
Parameters
|
|
32
|
+
----------
|
|
33
|
+
data : pandas.DataFrame
|
|
34
|
+
Input dataset containing photometry and geometry with columns:
|
|
35
|
+
- 'cmred': reduced magnitudes
|
|
36
|
+
- 'csigmapsf': uncertainties
|
|
37
|
+
- 'Phase': solar phase angles (deg)
|
|
38
|
+
- 'cfid': filter IDs
|
|
39
|
+
- 'ra', 'dec': coordinates (deg)
|
|
40
|
+
- 'cjd': observation times
|
|
41
|
+
Optional (for terminator fits):
|
|
42
|
+
- 'ra_s', 'dec_s': sub-solar point coordinates (deg)
|
|
43
|
+
flavor : str
|
|
44
|
+
Model type to fit. Must be 'SHG1G2' or 'SSHG1G2'.
|
|
45
|
+
shg1g2_constrained : bool, optional
|
|
46
|
+
Whether to constrain the SSHG1G2 fit using a prior SHG1G2 solution. Default True.
|
|
47
|
+
blind_scan : bool, optional
|
|
48
|
+
If True, perform a small grid search over initial pole positions and periods. Default True.
|
|
49
|
+
p0 : list, optional
|
|
50
|
+
Initial guess parameters for the fit. Required if `shg1g2_constrained=False`.
|
|
51
|
+
survey_filter : str or None, optional
|
|
52
|
+
If 'ZTF' or 'ATLAS', only data from that survey are used. Default None uses all data.
|
|
53
|
+
alt_spin : bool, optional
|
|
54
|
+
For SSHG1G2 constrained fits, use the antipodal spin solution. Default False.
|
|
55
|
+
period_in : float, optional
|
|
56
|
+
Input synodic period (days) to override automatic estimation. Default None.
|
|
57
|
+
terminator : bool, optional
|
|
58
|
+
If True, include self-shading in the fit. Default False.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
dict or tuple
|
|
63
|
+
If `flavor='SHG1G2'`:
|
|
64
|
+
dict
|
|
65
|
+
Best-fit SHG1G2 parameters.
|
|
66
|
+
If `flavor='SSHG1G2'`:
|
|
67
|
+
dict
|
|
68
|
+
Best-fit SOCCA parameters.
|
|
69
|
+
|
|
70
|
+
Notes
|
|
71
|
+
-----
|
|
72
|
+
- For SOCCA fits with `shg1g2_constrained=True`, the function first performs
|
|
73
|
+
a SHG1G2 fit to constrain H, G1, G2, and shape parameters.
|
|
74
|
+
- Blind scans systematically vary initial pole positions and period to find
|
|
75
|
+
the optimal fit when `blind_scan=True`.
|
|
76
|
+
|
|
77
|
+
Raises
|
|
78
|
+
------
|
|
79
|
+
ValueError
|
|
80
|
+
If `flavor` is not 'SHG1G2' or 'SSHG1G2'.
|
|
81
|
+
"""
|
|
82
|
+
|
|
31
83
|
if survey_filter is None:
|
|
32
84
|
filter_mask = np.array(data["cfid"].values[0]) >= 0
|
|
33
85
|
if survey_filter == "ZTF":
|
|
@@ -86,20 +138,10 @@ def get_fit_params(
|
|
|
86
138
|
)
|
|
87
139
|
|
|
88
140
|
ra0, dec0 = shg1g2_params["alpha0"], shg1g2_params["delta0"]
|
|
89
|
-
|
|
90
|
-
# shg1g2_params["alpha0"], shg1g2_params["delta0"]
|
|
91
|
-
# )
|
|
141
|
+
|
|
92
142
|
ra_init, dec_init = utils.generate_initial_points(
|
|
93
143
|
ra0, dec0, dec_shift=45
|
|
94
144
|
)
|
|
95
|
-
if pole_metadata:
|
|
96
|
-
pole_md = pd.DataFrame()
|
|
97
|
-
pole_md["ra0"] = [ra0]
|
|
98
|
-
pole_md["dec0"] = [dec0]
|
|
99
|
-
pole_md["ra_init"] = [ra_init]
|
|
100
|
-
pole_md["dec_init"] = [dec_init]
|
|
101
|
-
|
|
102
|
-
ra_fin, dec_fin = [], []
|
|
103
145
|
|
|
104
146
|
H_key = next(
|
|
105
147
|
(f"H_{i}" for i in range(1, 7) if f"H_{i}" in shg1g2_params),
|
|
@@ -130,24 +172,12 @@ def get_fit_params(
|
|
|
130
172
|
try:
|
|
131
173
|
rms.append(sshg1g2["rms"])
|
|
132
174
|
model.append(sshg1g2)
|
|
133
|
-
if pole_metadata:
|
|
134
|
-
ra_fin.append(sshg1g2["alpha0"])
|
|
135
|
-
dec_fin.append(sshg1g2["dec0"])
|
|
136
175
|
except Exception:
|
|
137
176
|
continue
|
|
138
177
|
rms = np.array(rms)
|
|
139
178
|
sshg1g2_opt = model[rms.argmin()]
|
|
140
179
|
|
|
141
|
-
|
|
142
|
-
ra_fin = np.array(ra_fin)
|
|
143
|
-
dec_fin = np.array(dec_fin)
|
|
144
|
-
|
|
145
|
-
pole_md["ra_fin"] = [ra_fin]
|
|
146
|
-
pole_md["dec_fin"] = [dec_fin]
|
|
147
|
-
|
|
148
|
-
return sshg1g2_opt, pole_md
|
|
149
|
-
else:
|
|
150
|
-
return sshg1g2_opt
|
|
180
|
+
return sshg1g2_opt
|
|
151
181
|
else:
|
|
152
182
|
period_si_t, alt_period_si_t, _ = utils.estimate_sidereal_period(
|
|
153
183
|
data=data, model_parameters=shg1g2_params, synodic_period=period_sy
|
|
@@ -257,228 +287,36 @@ def get_fit_params(
|
|
|
257
287
|
print("Model must either be SHG1G2 or SSHG1G2, not {}".format(flavor))
|
|
258
288
|
|
|
259
289
|
|
|
260
|
-
def plot_model(
|
|
261
|
-
data, flavor, model_params, x_axis="Date", resolution=400, filterout=False
|
|
262
|
-
):
|
|
263
|
-
fink_colors = ["#15284F", "#F5622E", "#0E6B77", "#4A4A4A"]
|
|
264
|
-
|
|
265
|
-
jd = np.linspace(
|
|
266
|
-
np.min(data["cjd"].values[0]), np.max(data["cjd"].values[0]), resolution
|
|
267
|
-
).tolist()
|
|
268
|
-
eph = ssptools.ephemcc(data["name"].values[0], jd, tcoor=1, observer="500")
|
|
269
|
-
ra = eph["RA"].values
|
|
270
|
-
dec = eph["DEC"].values
|
|
271
|
-
ra, dec = utils.sexa_to_deg(ra, dec)
|
|
272
|
-
|
|
273
|
-
params = model_params
|
|
274
|
-
|
|
275
|
-
if x_axis == "Date":
|
|
276
|
-
xvals_eph = "Date"
|
|
277
|
-
xvals = "cjd"
|
|
278
|
-
else:
|
|
279
|
-
xvals = xvals_eph = "Phase"
|
|
280
|
-
|
|
281
|
-
markers = ["<", ">", "^", "v"]
|
|
282
|
-
|
|
283
|
-
label_sh = r"$\text{sHG}_1\text{G}_2$"
|
|
284
|
-
label_ssh = r"$\text{ssHG}_1\text{G}_2$"
|
|
285
|
-
|
|
286
|
-
if flavor == "SHG1G2":
|
|
287
|
-
label_m = label_sh
|
|
288
|
-
if flavor == "SSHG1G2":
|
|
289
|
-
label_m = label_ssh
|
|
290
|
-
|
|
291
|
-
filter_names = ["ZTF g", "ZTF r", "ATLAS orange", "ATLAS cyan"]
|
|
292
|
-
|
|
293
|
-
if filterout is True:
|
|
294
|
-
rdata = data.copy()
|
|
295
|
-
ztfcond = (rdata["cfid"].values[0] == 1) | (rdata["cfid"].values[0] == 2)
|
|
296
|
-
for col in rdata.columns:
|
|
297
|
-
values = rdata.at[0, col]
|
|
298
|
-
if isinstance(values, np.ndarray) and len(values) == len(ztfcond):
|
|
299
|
-
rdata.at[0, col] = np.array(values)[ztfcond]
|
|
300
|
-
|
|
301
|
-
data = rdata
|
|
302
|
-
nfilts = len(np.unique(data["cfid"].values[0]))
|
|
303
|
-
|
|
304
|
-
fig, ax = plt.subplots(
|
|
305
|
-
int(nfilts + nfilts / 2),
|
|
306
|
-
1,
|
|
307
|
-
figsize=(12, 8 * nfilts / 2),
|
|
308
|
-
sharex=True,
|
|
309
|
-
gridspec_kw={
|
|
310
|
-
"top": 0.995,
|
|
311
|
-
"left": 0.075,
|
|
312
|
-
"right": 0.995,
|
|
313
|
-
"bottom": 0.085,
|
|
314
|
-
"hspace": 0.02,
|
|
315
|
-
"height_ratios": [2, 2, 1] if nfilts == 2 else [2, 2, 1, 2, 2, 1],
|
|
316
|
-
},
|
|
317
|
-
)
|
|
318
|
-
|
|
319
|
-
if x_axis == "Phase":
|
|
320
|
-
alpha = 0.5
|
|
321
|
-
else:
|
|
322
|
-
alpha = 1
|
|
323
|
-
|
|
324
|
-
for i, f in enumerate(np.unique(data["cfid"].values[0])):
|
|
325
|
-
filter_mask = data["cfid"].values[0] == f
|
|
326
|
-
|
|
327
|
-
if flavor == "SHG1G2":
|
|
328
|
-
model_params = [
|
|
329
|
-
params["H_{}".format(f)],
|
|
330
|
-
params["G1_{}".format(f)],
|
|
331
|
-
params["G2_{}".format(f)],
|
|
332
|
-
params["R"],
|
|
333
|
-
np.radians(params["alpha0"]),
|
|
334
|
-
np.radians(params["delta0"]),
|
|
335
|
-
]
|
|
336
|
-
|
|
337
|
-
model = func_hg1g2_with_spin(
|
|
338
|
-
[np.radians(eph["Phase"]), np.radians(ra), np.radians(dec)],
|
|
339
|
-
*model_params,
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
model_points = func_hg1g2_with_spin(
|
|
343
|
-
[
|
|
344
|
-
np.radians(data["Phase"].values[0][filter_mask]),
|
|
345
|
-
np.radians(data["ra"].values[0][filter_mask]),
|
|
346
|
-
np.radians(data["dec"].values[0][filter_mask]),
|
|
347
|
-
],
|
|
348
|
-
*model_params,
|
|
349
|
-
)
|
|
350
|
-
if flavor == "SSHG1G2":
|
|
351
|
-
jd_ltc = np.array(jd)
|
|
352
|
-
jd_data_ltc = data["cjd"].values[0][filter_mask]
|
|
353
|
-
|
|
354
|
-
model_params = [
|
|
355
|
-
params["H_{}".format(f)],
|
|
356
|
-
params["G1_{}".format(f)],
|
|
357
|
-
params["G2_{}".format(f)],
|
|
358
|
-
np.radians(params["alpha0"]),
|
|
359
|
-
np.radians(params["delta0"]),
|
|
360
|
-
params["period"],
|
|
361
|
-
params["a_b"],
|
|
362
|
-
params["a_c"],
|
|
363
|
-
np.radians(params["phi0"]),
|
|
364
|
-
]
|
|
365
|
-
|
|
366
|
-
model = func_sshg1g2(
|
|
367
|
-
[np.radians(eph["Phase"]), np.radians(ra), np.radians(dec), jd_ltc],
|
|
368
|
-
*model_params,
|
|
369
|
-
)
|
|
370
|
-
|
|
371
|
-
model_points = func_sshg1g2(
|
|
372
|
-
[
|
|
373
|
-
np.radians(data["Phase"].values[0][filter_mask]),
|
|
374
|
-
np.radians(data["ra"].values[0][filter_mask]),
|
|
375
|
-
np.radians(data["dec"].values[0][filter_mask]),
|
|
376
|
-
jd_data_ltc,
|
|
377
|
-
],
|
|
378
|
-
*model_params,
|
|
379
|
-
)
|
|
380
|
-
residuals = data["cmred"].values[0][filter_mask] - model_points
|
|
381
|
-
|
|
382
|
-
if i > 1:
|
|
383
|
-
ax[i + 1].plot(
|
|
384
|
-
eph[xvals_eph].values,
|
|
385
|
-
model,
|
|
386
|
-
c="black",
|
|
387
|
-
linestyle="--",
|
|
388
|
-
linewidth=1.1,
|
|
389
|
-
label=label_m,
|
|
390
|
-
alpha=alpha,
|
|
391
|
-
)
|
|
392
|
-
ax[i + 1].scatter(
|
|
393
|
-
data[xvals].values[0][filter_mask],
|
|
394
|
-
data["cmred"].values[0][filter_mask],
|
|
395
|
-
marker=markers[i],
|
|
396
|
-
c=fink_colors[i],
|
|
397
|
-
label=filter_names[i],
|
|
398
|
-
zorder=1000,
|
|
399
|
-
)
|
|
400
|
-
|
|
401
|
-
inset_hist = inset_axes(ax[i + 1], width="30%", height="30%")
|
|
402
|
-
inset_hist.hist(residuals, bins=40, color=fink_colors[i], density=True)
|
|
403
|
-
|
|
404
|
-
ax[5].scatter(
|
|
405
|
-
data[xvals].values[0][filter_mask],
|
|
406
|
-
residuals,
|
|
407
|
-
marker=markers[i],
|
|
408
|
-
c=fink_colors[i],
|
|
409
|
-
)
|
|
410
|
-
yabs_max = abs(max(ax[5].get_ylim(), key=abs))
|
|
411
|
-
ax[5].set_ylim(ymin=-yabs_max - 0.2, ymax=yabs_max + 0.2)
|
|
412
|
-
ax[5].axhline(y=0, c="black", linestyle="--", zorder=-1000, alpha=0.5)
|
|
413
|
-
ax[i + 1].legend(loc="lower left")
|
|
414
|
-
if xvals == "Phase":
|
|
415
|
-
ax[i + 1].invert_yaxis()
|
|
416
|
-
|
|
417
|
-
else:
|
|
418
|
-
ax[i].plot(
|
|
419
|
-
eph[xvals_eph].values,
|
|
420
|
-
model,
|
|
421
|
-
c="black",
|
|
422
|
-
linestyle="--",
|
|
423
|
-
linewidth=1.1,
|
|
424
|
-
label=label_m,
|
|
425
|
-
alpha=alpha,
|
|
426
|
-
)
|
|
427
|
-
ax[i].scatter(
|
|
428
|
-
data[xvals].values[0][filter_mask],
|
|
429
|
-
data["cmred"].values[0][filter_mask],
|
|
430
|
-
marker=markers[i],
|
|
431
|
-
c=fink_colors[i],
|
|
432
|
-
label=filter_names[i],
|
|
433
|
-
zorder=1000,
|
|
434
|
-
)
|
|
435
|
-
|
|
436
|
-
inset_hist = inset_axes(ax[i], width="30%", height="30%")
|
|
437
|
-
inset_hist.hist(residuals, bins=40, color=fink_colors[i], density=True)
|
|
438
|
-
|
|
439
|
-
ax[2].scatter(
|
|
440
|
-
data[xvals].values[0][filter_mask],
|
|
441
|
-
residuals,
|
|
442
|
-
marker=markers[i],
|
|
443
|
-
c=fink_colors[i],
|
|
444
|
-
)
|
|
445
|
-
yabs_max = abs(max(ax[2].get_ylim(), key=abs))
|
|
446
|
-
ax[2].set_ylim(ymin=-yabs_max - 0.1, ymax=yabs_max + 0.1)
|
|
447
|
-
ax[2].axhline(y=0, c="black", linestyle="--", zorder=-1000, alpha=0.5)
|
|
448
|
-
ax[i].legend(loc="lower left")
|
|
449
|
-
if x_axis == "Phase":
|
|
450
|
-
ax[i].invert_yaxis()
|
|
451
|
-
if i > 2:
|
|
452
|
-
if xvals == "cjd":
|
|
453
|
-
ax[5].set_xlabel("Time (days)")
|
|
454
|
-
else:
|
|
455
|
-
ax[5].set_xlabel("Phase (degree)")
|
|
456
|
-
|
|
457
|
-
ax[5].set_ylabel("Residuals")
|
|
458
|
-
|
|
459
|
-
if xvals == "cjd":
|
|
460
|
-
ax[2].set_xlabel("Time (days)")
|
|
461
|
-
else:
|
|
462
|
-
ax[2].set_xlabel("Phase (degree)")
|
|
463
|
-
|
|
464
|
-
else:
|
|
465
|
-
if xvals == "cjd":
|
|
466
|
-
ax[2].set_xlabel("Time (days)")
|
|
467
|
-
else:
|
|
468
|
-
ax[2].set_xlabel("Phase (degree)")
|
|
469
|
-
|
|
470
|
-
ax[2].set_ylabel("Residuals")
|
|
471
|
-
|
|
472
|
-
fig.text(0.01, 0.81, "Reduced magnitude", va="center", rotation="vertical")
|
|
473
|
-
fig.text(0.01, 0.35, "Reduced magnitude", va="center", rotation="vertical")
|
|
474
|
-
|
|
475
|
-
plt.tight_layout()
|
|
476
|
-
|
|
477
|
-
# if xvals == "Phase":
|
|
478
|
-
# plt.gca().set_xlim(left=0)
|
|
479
|
-
|
|
480
|
-
|
|
481
290
|
def get_model_points(data, params):
|
|
291
|
+
"""
|
|
292
|
+
Compute modeled magnitudes for a dataset using SHG1G2.
|
|
293
|
+
|
|
294
|
+
For each unique filter in the data, this function applies the SHG1G2 model
|
|
295
|
+
to the corresponding subset of observations.
|
|
296
|
+
|
|
297
|
+
Parameters
|
|
298
|
+
----------
|
|
299
|
+
data : pandas.DataFrame
|
|
300
|
+
Dataset containing at least the following columns:
|
|
301
|
+
- 'Phase' : solar phase angles (deg)
|
|
302
|
+
- 'ra' : right ascension (deg)
|
|
303
|
+
- 'dec' : declination (deg)
|
|
304
|
+
- 'cfid' : filter IDs (int)
|
|
305
|
+
params : dict
|
|
306
|
+
Model parameters containing keys:
|
|
307
|
+
- 'H_i', 'G1_i', 'G2_i' for each filter i
|
|
308
|
+
- 'R' : oblateness
|
|
309
|
+
- 'alpha0', 'delta0' : pole coordinates in degrees
|
|
310
|
+
|
|
311
|
+
Returns
|
|
312
|
+
-------
|
|
313
|
+
tuple of lists
|
|
314
|
+
- model_points_stack : list of numpy.ndarray
|
|
315
|
+
Modeled magnitudes for each filter.
|
|
316
|
+
- index_points_stack : list of numpy.ndarray
|
|
317
|
+
Indices of the original data points corresponding to each modeled subset.
|
|
318
|
+
"""
|
|
319
|
+
|
|
482
320
|
model_points_stack = []
|
|
483
321
|
index_points_stack = []
|
|
484
322
|
index = np.array([ind for ind in range(len(data["cfid"].values[0]))])
|
|
@@ -510,6 +348,29 @@ def get_model_points(data, params):
|
|
|
510
348
|
|
|
511
349
|
|
|
512
350
|
def get_residuals(data, params):
|
|
351
|
+
"""
|
|
352
|
+
Compute residuals between observed and modeled magnitudes for a dataset.
|
|
353
|
+
|
|
354
|
+
Parameters
|
|
355
|
+
----------
|
|
356
|
+
data : pandas.DataFrame
|
|
357
|
+
Dataset containing at least the following columns:
|
|
358
|
+
- 'cmred' : observed reduced magnitudes
|
|
359
|
+
- 'Phase' : solar phase angles (deg)
|
|
360
|
+
- 'ra' : right ascension (deg)
|
|
361
|
+
- 'dec' : declination (deg)
|
|
362
|
+
- 'cfid' : filter IDs (int)
|
|
363
|
+
params : dict
|
|
364
|
+
Model parameters including H, G1, G2 for each filter, pole coordinates,
|
|
365
|
+
and oblateness. Keys should match those expected by `get_model_points`.
|
|
366
|
+
|
|
367
|
+
Returns
|
|
368
|
+
-------
|
|
369
|
+
numpy.ndarray
|
|
370
|
+
Residuals (observed - modeled magnitudes) for all data points,
|
|
371
|
+
ordered according to the original dataset.
|
|
372
|
+
"""
|
|
373
|
+
|
|
513
374
|
pstack, istack = get_model_points(data, params)
|
|
514
375
|
fpstack, fistack = utils.flatten_list(pstack), utils.flatten_list(istack)
|
|
515
376
|
df_to_sort = pd.DataFrame({"mpoints": fpstack}, index=fistack)
|
|
@@ -519,6 +380,36 @@ def get_residuals(data, params):
|
|
|
519
380
|
|
|
520
381
|
|
|
521
382
|
def make_residuals_df(data, model_parameters):
|
|
383
|
+
"""
|
|
384
|
+
Create a DataFrame of residuals between observed and modeled magnitudes.
|
|
385
|
+
|
|
386
|
+
Parameters
|
|
387
|
+
----------
|
|
388
|
+
data : pandas.DataFrame
|
|
389
|
+
Dataset containing at least the following columns:
|
|
390
|
+
- 'cmred' : observed reduced magnitudes
|
|
391
|
+
- 'csigmapsf' : photometric uncertainties
|
|
392
|
+
- 'Phase' : solar phase angles (deg)
|
|
393
|
+
- 'ra' : right ascension (deg)
|
|
394
|
+
- 'dec' : declination (deg)
|
|
395
|
+
- 'cfid' : filter IDs (int)
|
|
396
|
+
- 'cjd' : observation times
|
|
397
|
+
model_parameters : dict
|
|
398
|
+
Model parameters including H, G1, G2 for each filter, pole coordinates,
|
|
399
|
+
and oblateness. Keys should match those expected by `get_model_points`.
|
|
400
|
+
|
|
401
|
+
Returns
|
|
402
|
+
-------
|
|
403
|
+
pandas.DataFrame
|
|
404
|
+
DataFrame indexed by observation index, with columns:
|
|
405
|
+
- 'mpoints' : modeled magnitudes
|
|
406
|
+
- 'mred' : observed reduced magnitudes
|
|
407
|
+
- 'sigma' : observational uncertainties
|
|
408
|
+
- 'filters' : filter IDs
|
|
409
|
+
- 'jd' : observation times
|
|
410
|
+
- 'residuals' : difference between observed and modeled magnitudes
|
|
411
|
+
(mred - mpoints)
|
|
412
|
+
"""
|
|
522
413
|
mpoints, indices = get_model_points(data=data, params=model_parameters)
|
|
523
414
|
flat_mpoints, flat_index = utils.flatten_list(mpoints), utils.flatten_list(indices)
|
|
524
415
|
|