asteroid_spinprops 1.2.5__py3-none-any.whl → 1.3.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.
@@ -11,6 +11,7 @@ from fink_utils.sso.spins import (
11
11
  from asteroid_spinprops.ssolib.periodest import (
12
12
  get_multiterm_period_estimate,
13
13
  )
14
+ import time
14
15
 
15
16
 
16
17
  def get_fit_params(
@@ -24,6 +25,7 @@ def get_fit_params(
24
25
  period_in=None,
25
26
  period_quality_flag=False,
26
27
  terminator=False,
28
+ time_me=True,
27
29
  ):
28
30
  """
29
31
  Fit a small solar system object's photometric data using SHG1G2 or SOCCA models.
@@ -52,7 +54,7 @@ def get_fit_params(
52
54
  If True, perform a small grid search over initial periods. Default True.
53
55
  pole_blind : bool, optional
54
56
  If True, perform a grid search over 12 initial poles all over a sphere. Default True.
55
- If False, produce the sHG1G2 rms error landscape and initialize SOCCA poles on its local minima
57
+ If False, produce the sHG1G2 rms error landscape and initialize SOCCA poles on its local minima
56
58
  p0 : list, optional
57
59
  Initial guess parameters for the fit. Required if `shg1g2_constrained=False`.
58
60
  alt_spin : bool, optional
@@ -63,6 +65,8 @@ def get_fit_params(
63
65
  Provide bootstrap score, alias/true (0/1) flags and period fit rms for the period estimates
64
66
  terminator : bool, optional
65
67
  If True, include self-shading in the fit. Default False.
68
+ time_me : bool, optional
69
+ If True, include timing (in seconds). Default True.
66
70
 
67
71
  Returns
68
72
  -------
@@ -86,7 +90,8 @@ def get_fit_params(
86
90
  ValueError
87
91
  If `flavor` is not 'SHG1G2' or 'SOCCA'.
88
92
  """
89
-
93
+ if time_me:
94
+ t1 = time.time()
90
95
  if flavor == "SHG1G2":
91
96
  if p0 is None:
92
97
  Afit = estimate_sso_params(
@@ -110,19 +115,24 @@ def get_fit_params(
110
115
  model="SHG1G2",
111
116
  p0=p0,
112
117
  )
113
-
118
+ if time_me:
119
+ t2 = time.time()
120
+ etime = t2 - t1
121
+ Afit["invtime"] = etime
114
122
  return Afit
115
123
  if flavor == "SOCCA":
116
124
  if shg1g2_constrained is True:
117
- shg1g2_params = get_fit_params(
118
- data=data, flavor="SHG1G2"
119
- )
125
+ shg1g2_params = get_fit_params(data=data, flavor="SHG1G2")
120
126
  try:
121
127
  residuals_dataframe = make_residuals_df(
122
128
  data, model_parameters=shg1g2_params
123
129
  )
124
130
  except Exception:
125
131
  SOCCA_opt = {"Failed at period search preliminary steps": 1}
132
+ if time_me:
133
+ t2 = time.time()
134
+ etime = t2 - t1
135
+ SOCCA_opt["invtime"] = etime
126
136
  return SOCCA_opt
127
137
  if period_in is None:
128
138
  # Period search boundaries (in days)
@@ -135,8 +145,11 @@ def get_fit_params(
135
145
  )
136
146
  if period_quality_flag:
137
147
  _, Nbs = periodest.perform_residual_resampling(
138
- resid_df=residuals_dataframe, p_min=pmin, p_max=pmax, k=int(k_val)
139
- )
148
+ resid_df=residuals_dataframe,
149
+ p_min=pmin,
150
+ p_max=pmax,
151
+ k=int(k_val),
152
+ )
140
153
  except KeyError:
141
154
  # If more than 10 terms are required switch to fast rotator:
142
155
  pmin, pmax = 5e-3, 5e-2
@@ -148,13 +161,24 @@ def get_fit_params(
148
161
  )
149
162
  if period_quality_flag:
150
163
  _, Nbs = periodest.perform_residual_resampling(
151
- resid_df=residuals_dataframe, p_min=pmin, p_max=pmax, k=int(k_val)
152
- )
164
+ resid_df=residuals_dataframe,
165
+ p_min=pmin,
166
+ p_max=pmax,
167
+ k=int(k_val),
168
+ )
153
169
  except Exception:
154
170
  SOCCA_opt = {"Failed at period search after": 1}
171
+ if time_me:
172
+ t2 = time.time()
173
+ etime = t2 - t1
174
+ SOCCA_opt["invtime"] = etime
155
175
  return SOCCA_opt
156
176
  except IndexError:
157
177
  SOCCA_opt = {"Failed at bootsrap sampling": 1}
178
+ if time_me:
179
+ t2 = time.time()
180
+ etime = t2 - t1
181
+ SOCCA_opt["invtime"] = etime
158
182
  return SOCCA_opt
159
183
  period_sy = p_in
160
184
  else:
@@ -182,23 +206,25 @@ def get_fit_params(
182
206
 
183
207
  for i, ra0 in enumerate(rarange):
184
208
  for j, dec0 in enumerate(decrange):
185
-
186
209
  all_residuals = []
187
210
 
188
211
  for ff in np.unique(data["cfid"].values[0]):
189
- cond_ff = data["cfid"].values[0] == ff
212
+ cond_ff = data["cfid"].values[0] == ff
190
213
 
191
- pha = [np.radians(data["Phase"].values[0][cond_ff]),
214
+ pha = [
215
+ np.radians(data["Phase"].values[0][cond_ff]),
192
216
  np.radians(data["ra"].values[0][cond_ff]),
193
- np.radians(data["dec"].values[0][cond_ff])]
217
+ np.radians(data["dec"].values[0][cond_ff]),
218
+ ]
194
219
 
195
- H = shg1g2_params[f"H_{ff}"]
220
+ H = shg1g2_params[f"H_{ff}"]
196
221
  G1 = shg1g2_params[f"G1_{ff}"]
197
222
  G2 = shg1g2_params[f"G2_{ff}"]
198
- R = shg1g2_params["R"]
223
+ R = shg1g2_params["R"]
199
224
 
200
- C = func_hg1g2_with_spin(pha, H, G1, G2, R,
201
- np.radians(ra0), np.radians(dec0))
225
+ C = func_hg1g2_with_spin(
226
+ pha, H, G1, G2, R, np.radians(ra0), np.radians(dec0)
227
+ )
202
228
 
203
229
  Obs = data["cmred"].values[0][cond_ff]
204
230
 
@@ -207,37 +233,59 @@ def get_fit_params(
207
233
  all_residuals = np.concatenate(all_residuals)
208
234
  rms_landscape[j, i] = np.sqrt(np.mean(all_residuals**2))
209
235
 
210
- interp_vals = utils.gaussian_interpolate(rms_landscape, factor=4, sigma=1.0)
236
+ interp_vals = utils.gaussian_interpolate(
237
+ rms_landscape, factor=4, sigma=1.0
238
+ )
211
239
  ny, nx = interp_vals.shape
212
240
  [rarange[0], rarange[-1], decrange[0], decrange[-1]]
213
- ra_vals = np.linspace(rarange.min(), rarange.max(), nx)
241
+ ra_vals = np.linspace(rarange.min(), rarange.max(), nx)
214
242
  dec_vals = np.linspace(decrange.min(), decrange.max(), ny)
215
243
  ys, xs = utils.detect_local_minima(interp_vals)
216
- ra_minima = ra_vals[xs]
244
+ ra_minima = ra_vals[xs]
217
245
  dec_minima = dec_vals[ys]
218
246
 
219
247
  ra_init = ra_minima
220
248
  dec_init = dec_minima
221
249
 
222
250
  H_key = next(
223
- (f"H_{i}" for i in range(1, 7) if f"H_{i}" in shg1g2_params),
251
+ (
252
+ f"H_{i}" for i in range(1, 7) if f"H_{i}" in shg1g2_params
253
+ ), # Harcoded number of filters? Grr...
224
254
  None,
225
255
  )
226
256
 
257
+ G1_key = next(
258
+ (f"G1_{i}" for i in range(1, 7) if f"G1_{i}" in shg1g2_params),
259
+ None,
260
+ )
261
+
262
+ G2_key = next(
263
+ (f"G2_{i}" for i in range(1, 7) if f"G2_{i}" in shg1g2_params),
264
+ None,
265
+ )
266
+ G1, G2 = shg1g2_params[G1_key], shg1g2_params[G2_key]
267
+
268
+ if not (1 - G1 - G2 > 0):
269
+ G1, G2 = 0.15, 0.15
270
+
271
+ a_b, a_c = shg1g2_params["a_b"], shg1g2_params["a_c"]
272
+ if not (1 <= a_b <= 5 and 1 <= a_c <= 5):
273
+ a_b = 1.05
274
+ a_c = 1.5
275
+
227
276
  for ra, dec in zip(ra_init, dec_init):
228
277
  for period_sc in period_scan:
229
278
  p_in = [
230
279
  shg1g2_params[H_key],
231
- 0.15,
232
- 0.15, # G1,2
280
+ G1,
281
+ G2,
233
282
  np.radians(ra),
234
283
  np.radians(dec),
235
284
  period_sc, # in days
236
- shg1g2_params["a_b"],
237
- shg1g2_params["a_c"],
285
+ a_b,
286
+ a_c,
238
287
  0.1,
239
288
  ] # phi 0
240
-
241
289
  SOCCA = get_fit_params(
242
290
  data,
243
291
  "SOCCA",
@@ -257,22 +305,28 @@ def get_fit_params(
257
305
  try:
258
306
  DeltaF1 = signal_peaks[1] - signal_peaks[2]
259
307
  f_obs = 2 / period_sy
260
- y_trumpet = utils.trumpet(
261
- DeltaF1, 1, f_obs
262
- )
308
+ y_trumpet = utils.trumpet(DeltaF1, 1, f_obs)
263
309
  alias_flag = (DeltaF1 - y_trumpet) * 100
264
310
  if alias_flag < 1:
265
- SOCCA_opt["Period_class"] = 1 # True
311
+ SOCCA_opt["Period_class"] = 1 # True
266
312
  else:
267
- SOCCA_opt["Period_class"] = 0 # Alias
313
+ SOCCA_opt["Period_class"] = 0 # Alias
268
314
  SOCCA_opt["Nbs"] = Nbs
269
315
  except Exception:
270
- SOCCA_opt["Period_class"] = -1 # Classification error
316
+ SOCCA_opt["Period_class"] = -1 # Classification error
271
317
  if period_in is None:
272
318
  SOCCA_opt["prms"] = p_rms
273
319
  SOCCA_opt["k_terms"] = k_val
274
320
  except Exception:
321
+ if time_me:
322
+ t2 = time.time()
323
+ etime = t2 - t1
324
+ SOCCA_opt["invtime"] = etime
275
325
  SOCCA_opt = {"Failed at SOCCA inversion": 1}
326
+ if time_me:
327
+ t2 = time.time()
328
+ etime = t2 - t1
329
+ SOCCA_opt["invtime"] = etime
276
330
  return SOCCA_opt
277
331
  else:
278
332
  period_si_t, alt_period_si_t, _ = utils.estimate_sidereal_period(
@@ -320,6 +374,12 @@ def get_fit_params(
320
374
  None,
321
375
  )
322
376
 
377
+ a_b, a_c = shg1g2_params["a_b"], shg1g2_params["a_c"]
378
+
379
+ if not (1 <= a_b <= 5 and 1 <= a_c <= 5):
380
+ a_b = 1.05
381
+ a_c = 1.5
382
+
323
383
  p0 = [
324
384
  H,
325
385
  G1,
@@ -327,8 +387,8 @@ def get_fit_params(
327
387
  ra0,
328
388
  de0,
329
389
  period,
330
- shg1g2_params["a_b"],
331
- shg1g2_params["a_c"],
390
+ a_b,
391
+ a_c,
332
392
  0.1,
333
393
  ]
334
394
 
@@ -220,7 +220,7 @@ def get_multiterm_period_estimate(
220
220
  for i in range(len(results) - 1):
221
221
  k, f_best, rss, dof, n_params = results[i]
222
222
  k_next, f_best_next, rss_next, dof_next, n_params_next = results[i + 1]
223
- F = ((rss**2/rss_next**2) - 1) * ((N - dof_next) / (dof_next - dof))
223
+ F = ((rss**2 / rss_next**2) - 1) * ((N - dof_next) / (dof_next - dof))
224
224
 
225
225
  # Here crit = Fstat value for which model_2 (more complex) is in fact better than model_1 (less complex)
226
226
  crit = ftest.ppf(
@@ -240,16 +240,9 @@ def get_multiterm_period_estimate(
240
240
  model_comparison = model_comparison[
241
241
  ~cond
242
242
  ] # don't go for the more complex model
243
- f_chosen = model_comparison[
244
- model_comparison.k == model_comparison.k.min()
245
- ].f_best.values[0] # Simplest model
246
- k_val = model_comparison[model_comparison.k == model_comparison.k.min()].k.values[
247
- 0
248
- ] # Simplest model
249
- p_rms = model_comparison[model_comparison.k == model_comparison.k.min()].rms.values[
250
- 0
251
- ] # Simplest model
252
-
243
+ f_chosen = model_comparison.loc[model_comparison.k.idxmin()]["f_best"]
244
+ k_val = model_comparison.loc[model_comparison.k.idxmin()]["k"]
245
+ p_rms = model_comparison.loc[model_comparison.k.idxmin()]["rms"]
253
246
  if not k_free:
254
247
  model = LombScargleMultiband(
255
248
  residuals_dataframe["jd"].values,
@@ -282,7 +275,7 @@ def get_multiterm_period_estimate(
282
275
  residuals_dataframe["sigma"].values,
283
276
  normalization="standard",
284
277
  fit_mean=True,
285
- nterms_base=k_val,
278
+ nterms_base=int(k_val),
286
279
  nterms_band=1,
287
280
  )
288
281
  frequency_final, power_final = model_final.autopower(
@@ -323,7 +316,7 @@ def get_multiterm_period_estimate(
323
316
  signal_peaks = frequency_final[pindex[hindex]]
324
317
  window_peaks = frequencyW[pindexW[hindexW]]
325
318
 
326
- return period_in, k_val, p_rms, signal_peaks, window_peaks
319
+ return period_in, int(k_val), p_rms, signal_peaks, window_peaks
327
320
 
328
321
 
329
322
  def perform_residual_resampling(resid_df, p_min, p_max, k=1):
@@ -419,6 +419,7 @@ def generate_initial_points(ra, dec, dec_shift=45):
419
419
  dec_list.append(shifted_dec)
420
420
  return ra_list, dec_list
421
421
 
422
+
422
423
  def gaussian_interpolate(data, factor=4, sigma=1.0):
423
424
  """
424
425
  Reproduce matplotlib's `interpolation="gaussian"` effect.
@@ -429,12 +430,13 @@ def gaussian_interpolate(data, factor=4, sigma=1.0):
429
430
 
430
431
  # Step 1: upsample (mimics interpolation grid)
431
432
  up = zoom(data, factor, order=1) # bilinear before smoothing
432
-
433
+
433
434
  # Step 2: apply gaussian smoothing
434
435
  smoothed = gaussian_filter(up, sigma=sigma)
435
-
436
+
436
437
  return smoothed
437
438
 
439
+
438
440
  def detect_local_minima(arr):
439
441
  import scipy.ndimage.filters as filters
440
442
  import scipy.ndimage.morphology as morphology
@@ -446,17 +448,19 @@ def detect_local_minima(arr):
446
448
  Returns a boolean mask of the troughs (i.e. 1 when
447
449
  the pixel's value is the neighborhood maximum, 0 otherwise)
448
450
  """
449
- neighborhood = morphology.generate_binary_structure(len(arr.shape),2)
450
-
451
+ neighborhood = morphology.generate_binary_structure(len(arr.shape), 2)
452
+
451
453
  footprint = np.ones((15, 15))
452
454
  local_min = filters.minimum_filter(arr, footprint=footprint) == arr
453
455
 
454
- background = (arr==0)
456
+ background = arr == 0
455
457
  eroded_background = morphology.binary_erosion(
456
- background, structure=neighborhood, border_value=1)
458
+ background, structure=neighborhood, border_value=1
459
+ )
457
460
 
458
461
  detected_minima = local_min ^ eroded_background
459
- return np.where(detected_minima)
462
+ return np.where(detected_minima)
463
+
460
464
 
461
465
  def trumpet(peak_diff_1, f_feat, f_obs):
462
466
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: asteroid_spinprops
3
- Version: 1.2.5
3
+ Version: 1.3.0
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
@@ -0,0 +1,10 @@
1
+ asteroid_spinprops/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ asteroid_spinprops/ssolib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ asteroid_spinprops/ssolib/dataprep.py,sha256=7PfkVNpLjPERkhr8dZQfN8haFCFmoeXB3fWuTSBLVuc,7848
4
+ asteroid_spinprops/ssolib/modelfit.py,sha256=u-qvKAmR-NLcJD7qQdeF3f0L2rg1-O0z0yXaVFRx5r0,22418
5
+ asteroid_spinprops/ssolib/periodest.py,sha256=OaJcDNBPiNDsDlzTfHInHUFt-7xZS4QbwaCrxKcnl2A,13180
6
+ asteroid_spinprops/ssolib/ssptools.py,sha256=DlSgYtXenztRAtEV9d4itzp5OZMjkbXkW2yZ_Qumu4U,4490
7
+ asteroid_spinprops/ssolib/utils.py,sha256=kbe69JxyCnbMebqkObuMS-0DFulnlgLNHxHNbP_U9J4,13334
8
+ asteroid_spinprops-1.3.0.dist-info/METADATA,sha256=z8jhQrXtXaz_ruV46ho-odYTDnR-GgtdxmVGsm8ZjUY,6143
9
+ asteroid_spinprops-1.3.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
10
+ asteroid_spinprops-1.3.0.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- asteroid_spinprops/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- asteroid_spinprops/ssolib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
- asteroid_spinprops/ssolib/dataprep.py,sha256=7PfkVNpLjPERkhr8dZQfN8haFCFmoeXB3fWuTSBLVuc,7848
4
- asteroid_spinprops/ssolib/modelfit.py,sha256=6BdkTsehPO-wOV8cbk61Rm4woMydUirtIQjYnj_ZfPU,20273
5
- asteroid_spinprops/ssolib/periodest.py,sha256=_uPfLKA5epPl0Cb3neAROAKZi2Pos93WT3C5e_GTKOA,13355
6
- asteroid_spinprops/ssolib/ssptools.py,sha256=DlSgYtXenztRAtEV9d4itzp5OZMjkbXkW2yZ_Qumu4U,4490
7
- asteroid_spinprops/ssolib/utils.py,sha256=Na0EAgCCeBrvY3-KwfU7PuaoDGLjw5jGP9oi19lY490,13344
8
- asteroid_spinprops-1.2.5.dist-info/METADATA,sha256=XjsSNdyXb_ze2JVj6zpUJh2voCj0zcQJe-KbBwe71L8,6143
9
- asteroid_spinprops-1.2.5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
10
- asteroid_spinprops-1.2.5.dist-info/RECORD,,