asteroid_spinprops 1.0.1__tar.gz → 1.1.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: asteroid_spinprops
3
- Version: 1.0.1
3
+ Version: 1.1.1
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
@@ -7,7 +7,7 @@ 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 get_period_estimate, get_multiterm_period_estimate, perform_residual_resampling
11
11
 
12
12
 
13
13
  def get_fit_params(
@@ -30,20 +30,20 @@ def get_fit_params(
30
30
 
31
31
  Parameters
32
32
  ----------
33
- data : pandas.DataFrame
33
+ data : pandas.DataFrame single-row
34
34
  Input dataset containing photometry and geometry with columns:
35
35
  - 'cmred': reduced magnitudes
36
36
  - 'csigmapsf': uncertainties
37
37
  - 'Phase': solar phase angles (deg)
38
38
  - 'cfid': filter IDs
39
39
  - 'ra', 'dec': coordinates (deg)
40
- - 'cjd': observation times
40
+ - 'cjd': observation times (light-time corrected)
41
41
  Optional (for terminator fits):
42
42
  - 'ra_s', 'dec_s': sub-solar point coordinates (deg)
43
43
  flavor : str
44
- Model type to fit. Must be 'SHG1G2' or 'SSHG1G2'.
44
+ Model type to fit. Must be 'SHG1G2' or 'SOCCA'.
45
45
  shg1g2_constrained : bool, optional
46
- Whether to constrain the SSHG1G2 fit using a prior SHG1G2 solution. Default True.
46
+ Whether to constrain the SOCCA fit using a prior SHG1G2 solution. Default True.
47
47
  blind_scan : bool, optional
48
48
  If True, perform a small grid search over initial pole positions and periods. Default True.
49
49
  p0 : list, optional
@@ -51,7 +51,7 @@ def get_fit_params(
51
51
  survey_filter : str or None, optional
52
52
  If 'ZTF' or 'ATLAS', only data from that survey are used. Default None uses all data.
53
53
  alt_spin : bool, optional
54
- For SSHG1G2 constrained fits, use the antipodal spin solution. Default False.
54
+ For SOCCA constrained fits, use the antipodal spin solution. Default False.
55
55
  period_in : float, optional
56
56
  Input synodic period (days) to override automatic estimation. Default None.
57
57
  terminator : bool, optional
@@ -63,7 +63,7 @@ def get_fit_params(
63
63
  If `flavor='SHG1G2'`:
64
64
  dict
65
65
  Best-fit SHG1G2 parameters.
66
- If `flavor='SSHG1G2'`:
66
+ If `flavor='SOCCA'`:
67
67
  dict
68
68
  Best-fit SOCCA parameters.
69
69
 
@@ -77,7 +77,7 @@ def get_fit_params(
77
77
  Raises
78
78
  ------
79
79
  ValueError
80
- If `flavor` is not 'SHG1G2' or 'SSHG1G2'.
80
+ If `flavor` is not 'SHG1G2' or 'SOCCA'.
81
81
  """
82
82
 
83
83
  if survey_filter is None:
@@ -115,7 +115,7 @@ def get_fit_params(
115
115
  )
116
116
 
117
117
  return Afit
118
- if flavor == "SSHG1G2":
118
+ if flavor == "SOCCA":
119
119
  if shg1g2_constrained is True:
120
120
  shg1g2_params = get_fit_params(
121
121
  data=data, flavor="SHG1G2", survey_filter=survey_filter
@@ -124,8 +124,24 @@ def get_fit_params(
124
124
  data, model_parameters=shg1g2_params
125
125
  )
126
126
  if period_in is None:
127
- sg, _, _ = get_period_estimate(residuals_dataframe=residuals_dataframe)
128
- period_sy = 2 / sg[2][0]
127
+ # Period search boundaries (in days)
128
+ pmin, pmax = 5e-2, 1e4
129
+ try:
130
+ p_in, k_val, p_rms, signal_peaks, window_peaks = (
131
+ get_multiterm_period_estimate(
132
+ residuals_dataframe, p_min=pmin, p_max=pmax, k_free=True
133
+ )
134
+ )
135
+ except KeyError:
136
+ # If more than 10 terms are required switch to fast rotator:
137
+ pmin, pmax = 5e-3, 5e-2
138
+
139
+ p_in, k_val, p_rms, signal_peaks, window_peaks = (
140
+ get_multiterm_period_estimate(
141
+ residuals_dataframe, p_min=pmin, p_max=pmax, k_free=True
142
+ )
143
+ )
144
+ period_sy = p_in
129
145
  else:
130
146
  period_sy = period_in
131
147
 
@@ -162,22 +178,22 @@ def get_fit_params(
162
178
  0.1,
163
179
  ] # phi 0
164
180
 
165
- sshg1g2 = get_fit_params(
181
+ SOCCA = get_fit_params(
166
182
  data,
167
- "SSHG1G2",
183
+ "SOCCA",
168
184
  shg1g2_constrained=False,
169
185
  p0=p_in,
170
186
  terminator=terminator,
171
187
  )
172
188
  try:
173
- rms.append(sshg1g2["rms"])
174
- model.append(sshg1g2)
189
+ rms.append(SOCCA["rms"])
190
+ model.append(SOCCA)
175
191
  except Exception:
176
192
  continue
177
193
  rms = np.array(rms)
178
- sshg1g2_opt = model[rms.argmin()]
194
+ SOCCA_opt = model[rms.argmin()]
179
195
 
180
- return sshg1g2_opt
196
+ return SOCCA_opt
181
197
  else:
182
198
  period_si_t, alt_period_si_t, _ = utils.estimate_sidereal_period(
183
199
  data=data, model_parameters=shg1g2_params, synodic_period=period_sy
@@ -245,14 +261,14 @@ def get_fit_params(
245
261
  ra=np.radians(data["ra"].values[0][filter_mask]),
246
262
  dec=np.radians(data["dec"].values[0][filter_mask]),
247
263
  jd=data["cjd"].values[0][filter_mask],
248
- model="SSHG1G2",
264
+ model="SSHG1G2", # We should call this SOCCA
249
265
  p0=p0,
250
266
  )
251
267
  return Afit
252
268
 
253
269
  if shg1g2_constrained is False:
254
270
  if p0 is None:
255
- print("Initialize SSHG1G2 first!")
271
+ print("Initialize SOCCA first!")
256
272
  if p0 is not None:
257
273
  if terminator:
258
274
  Afit = estimate_sso_params(
@@ -283,8 +299,8 @@ def get_fit_params(
283
299
  terminator=terminator,
284
300
  )
285
301
  return Afit
286
- if flavor not in ["SHG1G2", "SSHG1G2"]:
287
- print("Model must either be SHG1G2 or SSHG1G2, not {}".format(flavor))
302
+ if flavor not in ["SHG1G2", "SOCCA"]:
303
+ print("Model must either be SHG1G2 or SOCCA, not {}".format(flavor))
288
304
 
289
305
 
290
306
  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
  [project]
2
2
  name = "asteroid_spinprops"
3
- version = "1.0.1"
3
+ version = "1.1.1"
4
4
  description = "Collection of tools used for fitting sHG1G2 and SOCCA photometric models to sparse asteroid photometry"
5
5
  authors = [
6
6
  {name = "Odysseas",email = "odysseas.xenos@proton.me"}