asteroid_spinprops 1.0.1__py3-none-any.whl → 1.1.2__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.
@@ -7,16 +7,18 @@ from fink_utils.sso.spins import (
7
7
  estimate_sso_params,
8
8
  func_hg1g2_with_spin,
9
9
  )
10
- from asteroid_spinprops.ssolib.periodest import get_period_estimate
10
+ from asteroid_spinprops.ssolib.periodest import (
11
+ get_multiterm_period_estimate,
12
+ )
11
13
 
12
14
 
13
15
  def get_fit_params(
14
16
  data,
15
17
  flavor,
16
18
  shg1g2_constrained=True,
17
- blind_scan=True,
19
+ period_blind=True,
20
+ pole_blind=True,
18
21
  p0=None,
19
- survey_filter=None,
20
22
  alt_spin=False,
21
23
  period_in=None,
22
24
  terminator=False,
@@ -30,28 +32,28 @@ def get_fit_params(
30
32
 
31
33
  Parameters
32
34
  ----------
33
- data : pandas.DataFrame
35
+ data : pandas.DataFrame single-row
34
36
  Input dataset containing photometry and geometry with columns:
35
37
  - 'cmred': reduced magnitudes
36
38
  - 'csigmapsf': uncertainties
37
39
  - 'Phase': solar phase angles (deg)
38
40
  - 'cfid': filter IDs
39
41
  - 'ra', 'dec': coordinates (deg)
40
- - 'cjd': observation times
42
+ - 'cjd': observation times (light-time corrected)
41
43
  Optional (for terminator fits):
42
44
  - 'ra_s', 'dec_s': sub-solar point coordinates (deg)
43
45
  flavor : str
44
- Model type to fit. Must be 'SHG1G2' or 'SSHG1G2'.
46
+ Model type to fit. Must be 'SHG1G2' or 'SOCCA'.
45
47
  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.
48
+ Whether to constrain the SOCCA fit using a prior SHG1G2 solution. Default True.
49
+ period_blind : bool, optional
50
+ If True, perform a small grid search over initial periods. Default True.
51
+ pole_blind : bool, optional
52
+ If True, perform a grid search over initial poles. Default True.
49
53
  p0 : list, optional
50
54
  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
55
  alt_spin : bool, optional
54
- For SSHG1G2 constrained fits, use the antipodal spin solution. Default False.
56
+ For SOCCA constrained fits, use the antipodal spin solution. Default False.
55
57
  period_in : float, optional
56
58
  Input synodic period (days) to override automatic estimation. Default None.
57
59
  terminator : bool, optional
@@ -63,7 +65,7 @@ def get_fit_params(
63
65
  If `flavor='SHG1G2'`:
64
66
  dict
65
67
  Best-fit SHG1G2 parameters.
66
- If `flavor='SSHG1G2'`:
68
+ If `flavor='SOCCA'`:
67
69
  dict
68
70
  Best-fit SOCCA parameters.
69
71
 
@@ -77,59 +79,72 @@ def get_fit_params(
77
79
  Raises
78
80
  ------
79
81
  ValueError
80
- If `flavor` is not 'SHG1G2' or 'SSHG1G2'.
82
+ If `flavor` is not 'SHG1G2' or 'SOCCA'.
81
83
  """
82
84
 
83
- if survey_filter is None:
84
- filter_mask = np.array(data["cfid"].values[0]) >= 0
85
- if survey_filter == "ZTF":
86
- filter_mask = (np.array(data["cfid"].values[0]) == 1) | (
87
- np.array(data["cfid"].values[0]) == 2
88
- )
89
- if survey_filter == "ATLAS":
90
- filter_mask = (np.array(data["cfid"].values[0]) == 3) | (
91
- np.array(data["cfid"].values[0]) == 4
92
- )
93
85
  if flavor == "SHG1G2":
94
86
  if p0 is None:
95
87
  Afit = estimate_sso_params(
96
- magpsf_red=data["cmred"].values[0][filter_mask],
97
- sigmapsf=data["csigmapsf"].values[0][filter_mask],
98
- phase=np.radians(data["Phase"].values[0][filter_mask]),
99
- filters=data["cfid"].values[0][filter_mask],
100
- ra=np.radians(data["ra"].values[0][filter_mask]),
101
- dec=np.radians(data["dec"].values[0][filter_mask]),
88
+ magpsf_red=data["cmred"].values[0],
89
+ sigmapsf=data["csigmapsf"].values[0],
90
+ phase=np.radians(data["Phase"].values[0]),
91
+ filters=data["cfid"].values[0],
92
+ ra=np.radians(data["ra"].values[0]),
93
+ dec=np.radians(data["dec"].values[0]),
102
94
  model="SHG1G2",
103
95
  )
104
96
 
105
97
  if p0 is not None:
106
98
  Afit = estimate_sso_params(
107
- magpsf_red=data["cmred"].values[0][filter_mask],
108
- sigmapsf=data["csigmapsf"].values[0][filter_mask],
109
- phase=np.radians(data["Phase"].values[0][filter_mask]),
110
- filters=data["cfid"].values[0][filter_mask],
111
- ra=np.radians(data["ra"].values[0][filter_mask]),
112
- dec=np.radians(data["dec"].values[0][filter_mask]),
99
+ magpsf_red=data["cmred"].values[0],
100
+ sigmapsf=data["csigmapsf"].values[0],
101
+ phase=np.radians(data["Phase"].values[0]),
102
+ filters=data["cfid"].values[0],
103
+ ra=np.radians(data["ra"].values[0]),
104
+ dec=np.radians(data["dec"].values[0]),
113
105
  model="SHG1G2",
114
106
  p0=p0,
115
107
  )
116
108
 
117
109
  return Afit
118
- if flavor == "SSHG1G2":
110
+ if flavor == "SOCCA":
119
111
  if shg1g2_constrained is True:
120
112
  shg1g2_params = get_fit_params(
121
- data=data, flavor="SHG1G2", survey_filter=survey_filter
122
- )
123
- residuals_dataframe = make_residuals_df(
124
- data, model_parameters=shg1g2_params
113
+ data=data, flavor="SHG1G2"
125
114
  )
115
+ try:
116
+ residuals_dataframe = make_residuals_df(
117
+ data, model_parameters=shg1g2_params
118
+ )
119
+ except Exception:
120
+ SOCCA_opt = {"Failed at period search preliminary steps": 3}
121
+ return SOCCA_opt
126
122
  if period_in is None:
127
- sg, _, _ = get_period_estimate(residuals_dataframe=residuals_dataframe)
128
- period_sy = 2 / sg[2][0]
123
+ # Period search boundaries (in days)
124
+ pmin, pmax = 5e-2, 1e4
125
+ try:
126
+ p_in, k_val, p_rms, signal_peaks, window_peaks = (
127
+ get_multiterm_period_estimate(
128
+ residuals_dataframe, p_min=pmin, p_max=pmax, k_free=True
129
+ )
130
+ )
131
+ except KeyError:
132
+ # If more than 10 terms are required switch to fast rotator:
133
+ pmin, pmax = 5e-3, 5e-2
134
+ try:
135
+ p_in, k_val, p_rms, signal_peaks, window_peaks = (
136
+ get_multiterm_period_estimate(
137
+ residuals_dataframe, p_min=pmin, p_max=pmax, k_free=True
138
+ )
139
+ )
140
+ except Exception:
141
+ SOCCA_opt = {"Failed at period search after": 4}
142
+ return SOCCA_opt
143
+ period_sy = p_in
129
144
  else:
130
145
  period_sy = period_in
131
146
 
132
- if blind_scan is True:
147
+ if period_blind is True:
133
148
  rms = []
134
149
  model = []
135
150
 
@@ -138,10 +153,16 @@ def get_fit_params(
138
153
  )
139
154
 
140
155
  ra0, dec0 = shg1g2_params["alpha0"], shg1g2_params["delta0"]
156
+
157
+ if pole_blind is True:
158
+ ra_init, dec_init = utils.generate_initial_points(
159
+ ra0, dec0, dec_shift=45
160
+ )
141
161
 
142
- ra_init, dec_init = utils.generate_initial_points(
143
- ra0, dec0, dec_shift=45
144
- )
162
+ else:
163
+ ra0_antipodal, dec0_antipodal = utils.flip_spin(ra0, dec0)
164
+ ra_init = [ra0, ra0_antipodal]
165
+ dec_init = [dec0, dec0_antipodal]
145
166
 
146
167
  H_key = next(
147
168
  (f"H_{i}" for i in range(1, 7) if f"H_{i}" in shg1g2_params),
@@ -162,22 +183,24 @@ def get_fit_params(
162
183
  0.1,
163
184
  ] # phi 0
164
185
 
165
- sshg1g2 = get_fit_params(
186
+ SOCCA = get_fit_params(
166
187
  data,
167
- "SSHG1G2",
188
+ "SOCCA",
168
189
  shg1g2_constrained=False,
169
190
  p0=p_in,
170
191
  terminator=terminator,
171
192
  )
172
193
  try:
173
- rms.append(sshg1g2["rms"])
174
- model.append(sshg1g2)
194
+ rms.append(SOCCA["rms"])
195
+ model.append(SOCCA)
175
196
  except Exception:
176
197
  continue
177
- rms = np.array(rms)
178
- sshg1g2_opt = model[rms.argmin()]
179
-
180
- return sshg1g2_opt
198
+ try:
199
+ rms = np.array(rms)
200
+ SOCCA_opt = model[rms.argmin()]
201
+ except Exception:
202
+ SOCCA_opt = {"Failed at SOCCA inversion": 5}
203
+ return SOCCA_opt
181
204
  else:
182
205
  period_si_t, alt_period_si_t, _ = utils.estimate_sidereal_period(
183
206
  data=data, model_parameters=shg1g2_params, synodic_period=period_sy
@@ -238,53 +261,53 @@ def get_fit_params(
238
261
 
239
262
  # Constrained Fit
240
263
  Afit = estimate_sso_params(
241
- data["cmred"].values[0][filter_mask],
242
- data["csigmapsf"].values[0][filter_mask],
243
- np.radians(data["Phase"].values[0][filter_mask]),
244
- data["cfid"].values[0][filter_mask],
245
- ra=np.radians(data["ra"].values[0][filter_mask]),
246
- dec=np.radians(data["dec"].values[0][filter_mask]),
247
- jd=data["cjd"].values[0][filter_mask],
248
- model="SSHG1G2",
264
+ data["cmred"].values[0],
265
+ data["csigmapsf"].values[0],
266
+ np.radians(data["Phase"].values[0]),
267
+ data["cfid"].values[0],
268
+ ra=np.radians(data["ra"].values[0]),
269
+ dec=np.radians(data["dec"].values[0]),
270
+ jd=data["cjd"].values[0],
271
+ model="SSHG1G2", # We should call this SOCCA
249
272
  p0=p0,
250
273
  )
251
274
  return Afit
252
275
 
253
276
  if shg1g2_constrained is False:
254
277
  if p0 is None:
255
- print("Initialize SSHG1G2 first!")
278
+ print("Initialize SOCCA first!")
256
279
  if p0 is not None:
257
280
  if terminator:
258
281
  Afit = estimate_sso_params(
259
- data["cmred"].values[0][filter_mask],
260
- data["csigmapsf"].values[0][filter_mask],
261
- np.radians(data["Phase"].values[0][filter_mask]),
262
- data["cfid"].values[0][filter_mask],
263
- ra=np.radians(data["ra"].values[0][filter_mask]),
264
- dec=np.radians(data["dec"].values[0][filter_mask]),
265
- jd=data["cjd"].values[0][filter_mask],
282
+ data["cmred"].values[0],
283
+ data["csigmapsf"].values[0],
284
+ np.radians(data["Phase"].values[0]),
285
+ data["cfid"].values[0],
286
+ ra=np.radians(data["ra"].values[0]),
287
+ dec=np.radians(data["dec"].values[0]),
288
+ jd=data["cjd"].values[0],
266
289
  model="SSHG1G2",
267
290
  p0=p0,
268
291
  terminator=terminator,
269
- ra_s=np.radians(data["ra_s"].values[0][filter_mask]),
270
- dec_s=np.radians(data["dec_s"].values[0][filter_mask]),
292
+ ra_s=np.radians(data["ra_s"].values[0]),
293
+ dec_s=np.radians(data["dec_s"].values[0]),
271
294
  )
272
295
  else:
273
296
  Afit = estimate_sso_params(
274
- data["cmred"].values[0][filter_mask],
275
- data["csigmapsf"].values[0][filter_mask],
276
- np.radians(data["Phase"].values[0][filter_mask]),
277
- data["cfid"].values[0][filter_mask],
278
- ra=np.radians(data["ra"].values[0][filter_mask]),
279
- dec=np.radians(data["dec"].values[0][filter_mask]),
280
- jd=data["cjd"].values[0][filter_mask],
297
+ data["cmred"].values[0],
298
+ data["csigmapsf"].values[0],
299
+ np.radians(data["Phase"].values[0]),
300
+ data["cfid"].values[0],
301
+ ra=np.radians(data["ra"].values[0]),
302
+ dec=np.radians(data["dec"].values[0]),
303
+ jd=data["cjd"].values[0],
281
304
  model="SSHG1G2",
282
305
  p0=p0,
283
306
  terminator=terminator,
284
307
  )
285
308
  return Afit
286
- if flavor not in ["SHG1G2", "SSHG1G2"]:
287
- print("Model must either be SHG1G2 or SSHG1G2, not {}".format(flavor))
309
+ if flavor not in ["SHG1G2", "SOCCA"]:
310
+ print("Model must either be SHG1G2 or SOCCA, not {}".format(flavor))
288
311
 
289
312
 
290
313
  def get_model_points(data, params):
@@ -122,7 +122,7 @@ def get_period_estimate(residuals_dataframe, p_min=0.03, p_max=2):
122
122
  )
123
123
 
124
124
 
125
- def get_multiband_period_estimate(
125
+ def get_multiterm_period_estimate(
126
126
  residuals_dataframe, p_min=0.03, p_max=2, k_free=True, k_val=None
127
127
  ):
128
128
  """
@@ -337,7 +337,7 @@ def perform_residual_resampling(resid_df, p_min, p_max, k=1):
337
337
  ----------
338
338
  resid_df : pandas.DataFrame
339
339
  DataFrame of residuals containing columns required for `get_period_estimate`
340
- or `get_multiband_period_estimate`.
340
+ or `get_multiterm_period_estimate`.
341
341
  p_min : float
342
342
  Minimum period to search (days).
343
343
  p_max : float
@@ -356,7 +356,7 @@ def perform_residual_resampling(resid_df, p_min, p_max, k=1):
356
356
  Notes
357
357
  -----
358
358
  - Performs 25 bootstrap resamples by default.
359
- - For k=1, uses `get_period_estimate`; for k>1, uses `get_multiband_period_estimate`.
359
+ - For k=1, uses `get_period_estimate`; for k>1, uses `get_multiterm_period_estimate`.
360
360
  """
361
361
 
362
362
  if k == 1:
@@ -373,13 +373,13 @@ def perform_residual_resampling(resid_df, p_min, p_max, k=1):
373
373
  cond = np.abs(Pog - Pbs) / Pog < 1e-2
374
374
  Nbs = np.sum(np.ones(25)[cond])
375
375
  if k > 1:
376
- Pog, _, _ = 24 / get_multiband_period_estimate(
376
+ Pog, _, _ = 24 / get_multiterm_period_estimate(
377
377
  resid_df, p_min=p_min, p_max=p_max, k_free=False, k_val=k
378
378
  )
379
379
  Pbs = np.zeros(25)
380
380
  for n in range(25):
381
381
  BS_df = resid_df.sample(n=len(resid_df), replace=True)
382
- Pbs[n], _, _ = 24 / get_multiband_period_estimate(
382
+ Pbs[n], _, _ = 24 / get_multiterm_period_estimate(
383
383
  BS_df, p_min=p_min, p_max=p_max, k_free=False, k_val=k
384
384
  )
385
385
  cond = np.abs(Pog - Pbs) / Pog < 1e-2
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: asteroid_spinprops
3
- Version: 1.0.1
3
+ Version: 1.1.2
4
4
  Summary: Collection of tools used for fitting sHG1G2 and SOCCA photometric models to sparse asteroid photometry
5
5
  License: MIT
6
6
  Author: Odysseas
@@ -1,10 +1,10 @@
1
1
  asteroid_spinprops/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  asteroid_spinprops/ssolib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
3
  asteroid_spinprops/ssolib/dataprep.py,sha256=7PfkVNpLjPERkhr8dZQfN8haFCFmoeXB3fWuTSBLVuc,7848
4
- asteroid_spinprops/ssolib/modelfit.py,sha256=Kg5Qn0yU4wbfat9ZCvT9pYqSIo9toUm5kwhCiSvhalw,15898
5
- asteroid_spinprops/ssolib/periodest.py,sha256=XCBqsgPFcLFk-vreVmpYPjghJDyUyHSEeCULayqPRHg,13216
4
+ asteroid_spinprops/ssolib/modelfit.py,sha256=CM2fc_OKPrajK3Dadiny4JEkY1KuwCXqoarTx8SnYpM,16473
5
+ asteroid_spinprops/ssolib/periodest.py,sha256=kDWEB0fPRd5paqxNjJmigsocrAd4rydYLwxNh5sMV2U,13216
6
6
  asteroid_spinprops/ssolib/ssptools.py,sha256=DlSgYtXenztRAtEV9d4itzp5OZMjkbXkW2yZ_Qumu4U,4490
7
7
  asteroid_spinprops/ssolib/utils.py,sha256=BUeIP0DZ45tg5qAQML8LBM8Gbj1vn2d3PGzvgQvfq_I,11094
8
- asteroid_spinprops-1.0.1.dist-info/METADATA,sha256=4aQ7NoSNXRB2HbMHw1AIjhNE3UZFLUL5CYV_QeQywnA,5635
9
- asteroid_spinprops-1.0.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
10
- asteroid_spinprops-1.0.1.dist-info/RECORD,,
8
+ asteroid_spinprops-1.1.2.dist-info/METADATA,sha256=Ea_ijdxK1WerLh0BSULWUQp3sn054ghbk35Chg_Ggz4,5635
9
+ asteroid_spinprops-1.1.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
10
+ asteroid_spinprops-1.1.2.dist-info/RECORD,,