asteroid_spinprops 1.1.2__py3-none-any.whl → 1.2.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.
@@ -2,6 +2,7 @@ import numpy as np
2
2
  import pandas as pd
3
3
 
4
4
  import asteroid_spinprops.ssolib.utils as utils
5
+ import asteroid_spinprops.ssolib.periodest as periodest
5
6
 
6
7
  from fink_utils.sso.spins import (
7
8
  estimate_sso_params,
@@ -21,6 +22,7 @@ def get_fit_params(
21
22
  p0=None,
22
23
  alt_spin=False,
23
24
  period_in=None,
25
+ period_quality_flag=False,
24
26
  terminator=False,
25
27
  ):
26
28
  """
@@ -128,6 +130,10 @@ def get_fit_params(
128
130
  residuals_dataframe, p_min=pmin, p_max=pmax, k_free=True
129
131
  )
130
132
  )
133
+ if period_quality_flag:
134
+ _, Nbs = periodest.perform_residual_resampling(
135
+ resid_df=residuals_dataframe, p_min=pmin, p_max=pmax, k=int(k_val)
136
+ )
131
137
  except KeyError:
132
138
  # If more than 10 terms are required switch to fast rotator:
133
139
  pmin, pmax = 5e-3, 5e-2
@@ -137,6 +143,10 @@ def get_fit_params(
137
143
  residuals_dataframe, p_min=pmin, p_max=pmax, k_free=True
138
144
  )
139
145
  )
146
+ if period_quality_flag:
147
+ _, Nbs = periodest.perform_residual_resampling(
148
+ resid_df=residuals_dataframe, p_min=pmin, p_max=pmax, k=int(k_val)
149
+ )
140
150
  except Exception:
141
151
  SOCCA_opt = {"Failed at period search after": 4}
142
152
  return SOCCA_opt
@@ -153,16 +163,55 @@ def get_fit_params(
153
163
  )
154
164
 
155
165
  ra0, dec0 = shg1g2_params["alpha0"], shg1g2_params["delta0"]
156
-
166
+
157
167
  if pole_blind is True:
158
168
  ra_init, dec_init = utils.generate_initial_points(
159
169
  ra0, dec0, dec_shift=45
160
170
  )
161
171
 
162
172
  else:
163
- ra0_antipodal, dec0_antipodal = utils.flip_spin(ra0, dec0)
164
- ra_init = [ra0, ra0_antipodal]
165
- dec_init = [dec0, dec0_antipodal]
173
+ rarange = np.arange(0, 360, 10)
174
+ decrange = np.arange(-90, 90, 5)
175
+ rms_landscape = np.ones(shape=(len(rarange), len(decrange)))
176
+
177
+ for i, ra0 in enumerate(rarange):
178
+ for j, dec0 in enumerate(decrange):
179
+
180
+ all_residuals = []
181
+
182
+ for ff in np.unique(data["cfid"].values[0]):
183
+ cond_ff = data["cfid"].values[0] == ff
184
+
185
+ pha = [np.radians(data["Phase"].values[0][cond_ff]),
186
+ np.radians(data["ra"].values[0][cond_ff]),
187
+ np.radians(data["dec"].values[0][cond_ff])]
188
+
189
+ H = shg1g2_params[f"H_{ff}"]
190
+ G1 = shg1g2_params[f"G1_{ff}"]
191
+ G2 = shg1g2_params[f"G2_{ff}"]
192
+ R = shg1g2_params["R"]
193
+
194
+ C = func_hg1g2_with_spin(pha, H, G1, G2, R,
195
+ np.radians(ra0), np.radians(dec0))
196
+
197
+ O = data["cmred"].values[0][cond_ff]
198
+
199
+ all_residuals.append(O - C)
200
+
201
+ all_residuals = np.concatenate(all_residuals)
202
+ rms_landscape[j, i] = np.sqrt(np.mean(all_residuals**2))
203
+
204
+ interp_vals = utils.gaussian_interpolate(rms_landscape, factor=4, sigma=1.0)
205
+ ny, nx = interp_vals.shape
206
+ [rarange[0], rarange[-1], decrange[0], decrange[-1]]
207
+ ra_vals = np.linspace(rarange.min(), rarange.max(), nx)
208
+ dec_vals = np.linspace(decrange.min(), decrange.max(), ny)
209
+ ys, xs = utils.detect_local_minima(interp_vals)
210
+ ra_minima = ra_vals[xs]
211
+ dec_minima = dec_vals[ys]
212
+
213
+ ra_init = ra_minima
214
+ dec_init = dec_minima
166
215
 
167
216
  H_key = next(
168
217
  (f"H_{i}" for i in range(1, 7) if f"H_{i}" in shg1g2_params),
@@ -198,6 +247,21 @@ def get_fit_params(
198
247
  try:
199
248
  rms = np.array(rms)
200
249
  SOCCA_opt = model[rms.argmin()]
250
+ if period_quality_flag:
251
+ try:
252
+ DeltaF1 = signal_peaks[1] - signal_peaks[2]
253
+ f_obs = 2 / period_sy
254
+ y_trumpet = utils.trumpet(
255
+ DeltaF1, 1, f_obs
256
+ )
257
+ alias_flag = (DeltaF1 - y_trumpet) * 100
258
+ if alias_flag < 1:
259
+ SOCCA_opt["Period_class"] = "true"
260
+ else:
261
+ SOCCA_opt["Period_class"] = "alias"
262
+ SOCCA_opt["Nbs"] = Nbs
263
+ except Exception:
264
+ SOCCA_opt["Period_class"] = "class_error"
201
265
  except Exception:
202
266
  SOCCA_opt = {"Failed at SOCCA inversion": 5}
203
267
  return SOCCA_opt
@@ -418,3 +418,57 @@ def generate_initial_points(ra, dec, dec_shift=45):
418
418
  ra_list.append(wrap_longitude(temp_ra + offset))
419
419
  dec_list.append(shifted_dec)
420
420
  return ra_list, dec_list
421
+
422
+ def gaussian_interpolate(data, factor=4, sigma=1.0):
423
+ """
424
+ Reproduce matplotlib's `interpolation="gaussian"` effect.
425
+ factor : upsampling factor
426
+ sigma : Gaussian smoothing strength
427
+ """
428
+ from scipy.ndimage import zoom, gaussian_filter
429
+
430
+ # Step 1: upsample (mimics interpolation grid)
431
+ up = zoom(data, factor, order=1) # bilinear before smoothing
432
+
433
+ # Step 2: apply gaussian smoothing
434
+ smoothed = gaussian_filter(up, sigma=sigma)
435
+
436
+ return smoothed
437
+
438
+ def detect_local_minima(arr):
439
+ import scipy.ndimage.filters as filters
440
+ import scipy.ndimage.morphology as morphology
441
+
442
+ # https://stackoverflow.com/questions/3684484/peak-detection-in-a-2d-array/3689710#3689710
443
+ # https://stackoverflow.com/questions/3986345/how-to-find-the-local-minima-of-a-smooth-multidimensional-array-in-numpy
444
+ """
445
+ Takes an array and detects the troughs using the local maximum filter.
446
+ Returns a boolean mask of the troughs (i.e. 1 when
447
+ the pixel's value is the neighborhood maximum, 0 otherwise)
448
+ """
449
+ neighborhood = morphology.generate_binary_structure(len(arr.shape),2)
450
+
451
+ footprint = np.ones((15, 15))
452
+ local_min = filters.minimum_filter(arr, footprint=footprint) == arr
453
+
454
+ background = (arr==0)
455
+ eroded_background = morphology.binary_erosion(
456
+ background, structure=neighborhood, border_value=1)
457
+
458
+ detected_minima = local_min ^ eroded_background
459
+ return np.where(detected_minima)
460
+
461
+ def trumpet(peak_diff_1, f_feat, f_obs):
462
+ if peak_diff_1 > 0 and f_obs > f_feat:
463
+ return 2 * f_feat
464
+
465
+ elif peak_diff_1 < 0 and f_obs < f_feat:
466
+ return -2 * f_obs
467
+
468
+ elif peak_diff_1 > 0 and f_obs < f_feat:
469
+ return 2 * f_obs
470
+
471
+ elif peak_diff_1 < 0 and f_obs > f_feat:
472
+ return -2 * f_feat
473
+
474
+ return 0.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: asteroid_spinprops
3
- Version: 1.1.2
3
+ Version: 1.2.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
@@ -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=CM2fc_OKPrajK3Dadiny4JEkY1KuwCXqoarTx8SnYpM,16473
4
+ asteroid_spinprops/ssolib/modelfit.py,sha256=-EA0Ha0fUh9CPqqh_f9kuoZWTVmSP-XMITUHJ3OsCy4,19698
5
5
  asteroid_spinprops/ssolib/periodest.py,sha256=kDWEB0fPRd5paqxNjJmigsocrAd4rydYLwxNh5sMV2U,13216
6
6
  asteroid_spinprops/ssolib/ssptools.py,sha256=DlSgYtXenztRAtEV9d4itzp5OZMjkbXkW2yZ_Qumu4U,4490
7
- asteroid_spinprops/ssolib/utils.py,sha256=BUeIP0DZ45tg5qAQML8LBM8Gbj1vn2d3PGzvgQvfq_I,11094
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,,
7
+ asteroid_spinprops/ssolib/utils.py,sha256=Cv1TYSaUsWLbeQyrdqou6YnrPv4VijDP6GB9HAXtzKA,12902
8
+ asteroid_spinprops-1.2.0.dist-info/METADATA,sha256=6j5gC6L3ptLRtFfAQIDUQfuY5y6LmLGOiao0VsMdi48,5635
9
+ asteroid_spinprops-1.2.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
10
+ asteroid_spinprops-1.2.0.dist-info/RECORD,,