asteroid_spinprops 0.2.32__py3-none-any.whl → 1.0.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.
- 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.0.dist-info/METADATA +101 -0
- asteroid_spinprops-1.0.0.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.0.dist-info}/WHEEL +0 -0
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import asteroid_spinprops.ssolib.ssptools as ssptools
|
|
4
|
-
import os
|
|
5
|
-
|
|
6
|
-
import pickle
|
|
7
|
-
import requests
|
|
8
|
-
import io
|
|
9
2
|
import astropy.constants as const
|
|
10
3
|
|
|
11
4
|
|
|
12
5
|
def is_sorted(a):
|
|
6
|
+
"""
|
|
7
|
+
Check whether a 1D array is sorted in non-decreasing order.
|
|
8
|
+
|
|
9
|
+
Parameters
|
|
10
|
+
----------
|
|
11
|
+
a : array_like
|
|
12
|
+
Input array to test.
|
|
13
|
+
|
|
14
|
+
Returns
|
|
15
|
+
-------
|
|
16
|
+
bool
|
|
17
|
+
True if `a` is sorted in non-decreasing order, False otherwise.
|
|
18
|
+
"""
|
|
13
19
|
return np.all(a[:-1] <= a[1:])
|
|
14
20
|
|
|
15
21
|
|
|
@@ -32,42 +38,6 @@ def sigma_condition_func(data):
|
|
|
32
38
|
return (data > mean_val - 3 * std_val) & (data < mean_val + 3 * std_val)
|
|
33
39
|
|
|
34
40
|
|
|
35
|
-
def get_atlas_ephem(pdf, name, path_to_cached_ephems=None):
|
|
36
|
-
# TODO: include midtime obs timeshift
|
|
37
|
-
"""
|
|
38
|
-
Get the ephemerides for a SSO from the ATLAS catalogue
|
|
39
|
-
|
|
40
|
-
Parameters
|
|
41
|
-
-----------------------------
|
|
42
|
-
name: str
|
|
43
|
-
Name of the object
|
|
44
|
-
jd: float or list
|
|
45
|
-
Julian Date(s) of the ephemerides requested
|
|
46
|
-
pdf: pd.DataFrame
|
|
47
|
-
Dataframe containing the name and the JDs of the observations of the object
|
|
48
|
-
path_to_cached_ephems: str
|
|
49
|
-
Path to already computed ephemerids
|
|
50
|
-
|
|
51
|
-
Returns
|
|
52
|
-
-----------------------------
|
|
53
|
-
ephem: pd.DataFrame
|
|
54
|
-
Ephemerides for the provided JDs
|
|
55
|
-
"""
|
|
56
|
-
|
|
57
|
-
namecond = pdf["name"] == name
|
|
58
|
-
jd = pdf[namecond]["cjd"].tolist()[0].tolist()
|
|
59
|
-
if path_to_cached_ephems is not None:
|
|
60
|
-
ephem_file = os.path.join(path_to_cached_ephems, name)
|
|
61
|
-
if os.path.exists(ephem_file):
|
|
62
|
-
eph = pd.read_csv(ephem_file)
|
|
63
|
-
else:
|
|
64
|
-
eph = ssptools.ephemcc(name, jd, tcoor=5, observer="500")
|
|
65
|
-
eph.to_csv(path_to_cached_ephems + "/" + name)
|
|
66
|
-
else:
|
|
67
|
-
eph = ssptools.ephemcc(name, jd, tcoor=5, observer="500")
|
|
68
|
-
return eph
|
|
69
|
-
|
|
70
|
-
|
|
71
41
|
def find_nearest(array, value):
|
|
72
42
|
"""
|
|
73
43
|
Find the nearest value of an array to a given value.
|
|
@@ -104,31 +74,6 @@ def flatten_list(xss):
|
|
|
104
74
|
return np.array(flat_list)
|
|
105
75
|
|
|
106
76
|
|
|
107
|
-
def c2rd(x, y, z):
|
|
108
|
-
"""
|
|
109
|
-
Geocentric cartesian to RA/DEC
|
|
110
|
-
|
|
111
|
-
Parameters
|
|
112
|
-
-----------------------------
|
|
113
|
-
x, y, z : float/np.array
|
|
114
|
-
x, y, z coordinates
|
|
115
|
-
|
|
116
|
-
Returns
|
|
117
|
-
-----------------------------
|
|
118
|
-
ra, dec : float/np.array
|
|
119
|
-
RA & DEC in degrees from x, y, z
|
|
120
|
-
"""
|
|
121
|
-
|
|
122
|
-
ra_rad = np.arctan2(y, x)
|
|
123
|
-
ra = np.degrees(ra_rad) % 360
|
|
124
|
-
|
|
125
|
-
r = np.sqrt(x**2 + y**2 + z**2)
|
|
126
|
-
dec_rad = np.arcsin(z / r)
|
|
127
|
-
dec = np.degrees(dec_rad)
|
|
128
|
-
|
|
129
|
-
return ra, dec
|
|
130
|
-
|
|
131
|
-
|
|
132
77
|
def calculate_reduced_magnitude(magnitude, D_observer, D_sun):
|
|
133
78
|
"""
|
|
134
79
|
Calculate reduced magnitude
|
|
@@ -149,30 +94,6 @@ def calculate_reduced_magnitude(magnitude, D_observer, D_sun):
|
|
|
149
94
|
return magnitude - 5 * np.log10(D_observer * D_sun)
|
|
150
95
|
|
|
151
96
|
|
|
152
|
-
def find_sso_in_pqdict(sso_name, pqdict):
|
|
153
|
-
"""
|
|
154
|
-
Search for a specific SSO name within a dictionary containing names of parquet files as keys
|
|
155
|
-
and lists of sso names as values.
|
|
156
|
-
|
|
157
|
-
Parameters
|
|
158
|
-
-----------------------------
|
|
159
|
-
sso_name : str
|
|
160
|
-
The name of the solar system object to search for.
|
|
161
|
-
pqdict : dict
|
|
162
|
-
A dictionary where keys are filenames,
|
|
163
|
-
and values are lists of SSO names contained in each pqfile.
|
|
164
|
-
|
|
165
|
-
Returns
|
|
166
|
-
-----------------------------
|
|
167
|
-
pqfile : str or None
|
|
168
|
-
The name of the pqfile that contains the specified SSO
|
|
169
|
-
"""
|
|
170
|
-
|
|
171
|
-
for pqfile in list(pqdict.keys()):
|
|
172
|
-
if sso_name in pqdict[pqfile]:
|
|
173
|
-
return pqfile
|
|
174
|
-
|
|
175
|
-
|
|
176
97
|
def sort_by_cjd(data):
|
|
177
98
|
"""
|
|
178
99
|
Function to sort data containing a `cjd` column by this column.
|
|
@@ -196,72 +117,6 @@ def sort_by_cjd(data):
|
|
|
196
117
|
return data
|
|
197
118
|
|
|
198
119
|
|
|
199
|
-
# sns.set_context('talk')
|
|
200
|
-
def sexa_to_deg(ra_list, dec_list):
|
|
201
|
-
"""
|
|
202
|
-
Convert 2 lists of RA and DEC angles from sexagesimal format to degrees.
|
|
203
|
-
|
|
204
|
-
Parameters
|
|
205
|
-
----------
|
|
206
|
-
ra_list : list
|
|
207
|
-
List of RA angles.
|
|
208
|
-
dec_list : list
|
|
209
|
-
List of Dec angles
|
|
210
|
-
|
|
211
|
-
Returns
|
|
212
|
-
-------
|
|
213
|
-
ra_degrees: np.array
|
|
214
|
-
np.array of RA angles in degrees
|
|
215
|
-
dec_degrees
|
|
216
|
-
np.array of DEC angles in degrees
|
|
217
|
-
"""
|
|
218
|
-
ra_array = np.asarray(ra_list, dtype=str)
|
|
219
|
-
dec_array = np.asarray(dec_list, dtype=str)
|
|
220
|
-
|
|
221
|
-
ra_signs = np.where(np.char.startswith(ra_array, "-"), -1, 1)
|
|
222
|
-
dec_signs = np.where(np.char.startswith(dec_array, "-"), -1, 1)
|
|
223
|
-
|
|
224
|
-
ra_array = np.char.lstrip(ra_array, "+-")
|
|
225
|
-
dec_array = np.char.lstrip(dec_array, "+-")
|
|
226
|
-
|
|
227
|
-
ra_h, ra_m, ra_s = np.array([s.split(":") for s in ra_array], dtype=float).T
|
|
228
|
-
dec_d, dec_m, dec_s = np.array([s.split(":") for s in dec_array], dtype=float).T
|
|
229
|
-
|
|
230
|
-
ra_degrees = ra_signs * (ra_h * 15 + ra_m * 15 / 60 + ra_s * 15 / 3600)
|
|
231
|
-
dec_degrees = dec_signs * (dec_d + dec_m / 60 + dec_s / 3600)
|
|
232
|
-
|
|
233
|
-
return ra_degrees, dec_degrees
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
def get_obejct_from_fink(name):
|
|
237
|
-
"""
|
|
238
|
-
Queries FINK portal for SSO
|
|
239
|
-
|
|
240
|
-
Parameters
|
|
241
|
-
-----------
|
|
242
|
-
name: str
|
|
243
|
-
Name of the object
|
|
244
|
-
|
|
245
|
-
Returns
|
|
246
|
-
--------
|
|
247
|
-
dframe: pd.DataFrame
|
|
248
|
-
Contains all necessary values for sHG1G2 fit (and previous models)
|
|
249
|
-
"""
|
|
250
|
-
r = requests.post(
|
|
251
|
-
"https://api.fink-portal.org/api/v1/sso",
|
|
252
|
-
json={
|
|
253
|
-
"n_or_d": name,
|
|
254
|
-
"withEphem": False,
|
|
255
|
-
"withResiduals": True,
|
|
256
|
-
"output-format": "json",
|
|
257
|
-
},
|
|
258
|
-
)
|
|
259
|
-
dframe = pd.read_json(
|
|
260
|
-
io.BytesIO(r.content),
|
|
261
|
-
)
|
|
262
|
-
return dframe
|
|
263
|
-
|
|
264
|
-
|
|
265
120
|
def get_apparition_indices(dates, threshold=100):
|
|
266
121
|
"""
|
|
267
122
|
Identify indices where there is a significant time gap (>threshold days).
|
|
@@ -281,30 +136,23 @@ def get_apparition_indices(dates, threshold=100):
|
|
|
281
136
|
return np.concatenate(([0], np.where(np.diff(dates) > threshold)[0], [len(dates)]))
|
|
282
137
|
|
|
283
138
|
|
|
284
|
-
def
|
|
285
|
-
|
|
286
|
-
for
|
|
287
|
-
if pq_file.__contains__(".parquet"):
|
|
288
|
-
file_path = os.path.join(path, pq_file)
|
|
289
|
-
sso_names = pd.read_parquet(file_path)["name"]
|
|
290
|
-
sso_in_pq[pq_file] = [n for n in sso_names]
|
|
291
|
-
if save is True:
|
|
292
|
-
with open("ssoname_keys.pkl", "wb") as f:
|
|
293
|
-
pickle.dump(sso_in_pq, f)
|
|
294
|
-
return sso_in_pq
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
def calc_radec_for_epoch(data, epoch):
|
|
298
|
-
eph = ssptools.ephemcc(
|
|
299
|
-
data["name"].values[0], epoch.tolist(), tcoor=1, observer="500"
|
|
300
|
-
)
|
|
301
|
-
ra, dec = sexa_to_deg(eph["RA"].values, eph["DEC"].values)
|
|
302
|
-
ra, dec = np.radians(ra), np.radians(dec)
|
|
303
|
-
return ra, dec
|
|
139
|
+
def flip_spin(ra0, dec0):
|
|
140
|
+
"""
|
|
141
|
+
Compute the antipodal (spin-flip) direction for a given RA/Dec.
|
|
304
142
|
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
ra0 : float or array_like
|
|
146
|
+
Right ascension in degrees.
|
|
147
|
+
dec0 : float or array_like
|
|
148
|
+
Declination in degrees.
|
|
305
149
|
|
|
306
|
-
|
|
307
|
-
|
|
150
|
+
Returns
|
|
151
|
+
-------
|
|
152
|
+
tuple of float or array_like
|
|
153
|
+
`(ra_alt, dec_alt)` giving the antipodal right ascension and
|
|
154
|
+
declination in degrees.
|
|
155
|
+
"""
|
|
308
156
|
ra0 = np.radians(ra0)
|
|
309
157
|
dec0 = np.radians(dec0)
|
|
310
158
|
ra_alt = (ra0 + np.pi) % (2 * np.pi)
|
|
@@ -313,7 +161,26 @@ def flip_spin(ra0, dec0):
|
|
|
313
161
|
|
|
314
162
|
|
|
315
163
|
def calc_atan_parameter(ra, dec, ra0, dec0):
|
|
316
|
-
|
|
164
|
+
"""
|
|
165
|
+
Compute the angular parameter used in great-circle or pole-separation geometry.
|
|
166
|
+
|
|
167
|
+
Parameters
|
|
168
|
+
----------
|
|
169
|
+
ra : float or array_like
|
|
170
|
+
Right ascension of the target point, in degrees.
|
|
171
|
+
dec : float or array_like
|
|
172
|
+
Declination of the target point, in degrees.
|
|
173
|
+
ra0 : float or array_like
|
|
174
|
+
Reference right ascension, in degrees.
|
|
175
|
+
dec0 : float or array_like
|
|
176
|
+
Reference declination, in degrees.
|
|
177
|
+
|
|
178
|
+
Returns
|
|
179
|
+
-------
|
|
180
|
+
float or array_like
|
|
181
|
+
The atan2-based angle (in radians) describing the orientation of
|
|
182
|
+
the target point relative to the reference direction.
|
|
183
|
+
"""
|
|
317
184
|
ra, dec, ra0, dec0 = (
|
|
318
185
|
np.radians(ra),
|
|
319
186
|
np.radians(dec),
|
|
@@ -326,7 +193,8 @@ def calc_atan_parameter(ra, dec, ra0, dec0):
|
|
|
326
193
|
|
|
327
194
|
|
|
328
195
|
def compute_ltc(jd, d_obs, filt=None):
|
|
329
|
-
"""
|
|
196
|
+
"""
|
|
197
|
+
Compute the time with light travel corrected
|
|
330
198
|
|
|
331
199
|
Parameters
|
|
332
200
|
----------
|
|
@@ -347,6 +215,23 @@ def compute_ltc(jd, d_obs, filt=None):
|
|
|
347
215
|
|
|
348
216
|
|
|
349
217
|
def angle_after_one_synodic_period(angle, synodic_period, rate):
|
|
218
|
+
"""
|
|
219
|
+
Propagate an angle forward by one synodic period given a drift rate.
|
|
220
|
+
|
|
221
|
+
Parameters
|
|
222
|
+
----------
|
|
223
|
+
angle : float or array_like
|
|
224
|
+
Initial angle in degrees.
|
|
225
|
+
synodic_period : float
|
|
226
|
+
Synodic period in days.
|
|
227
|
+
rate : float or array_like
|
|
228
|
+
Angular drift rate in arcseconds per minute.
|
|
229
|
+
|
|
230
|
+
Returns
|
|
231
|
+
-------
|
|
232
|
+
float or array_like
|
|
233
|
+
Angle after one synodic period, in degrees.
|
|
234
|
+
"""
|
|
350
235
|
angle_t1 = (
|
|
351
236
|
angle + synodic_period * (60 * 24) / 3600 * rate
|
|
352
237
|
) # dRA in arcsec/min, period in days, ra_t0|1 in degrees
|
|
@@ -354,6 +239,45 @@ def angle_after_one_synodic_period(angle, synodic_period, rate):
|
|
|
354
239
|
|
|
355
240
|
|
|
356
241
|
def estimate_sidereal_period(data, model_parameters, synodic_period):
|
|
242
|
+
"""
|
|
243
|
+
Estimate the sidereal period of an object from its astrometric drift
|
|
244
|
+
over one synodic period, using both the nominal and spin-flipped
|
|
245
|
+
pole solutions.
|
|
246
|
+
|
|
247
|
+
Parameters
|
|
248
|
+
----------
|
|
249
|
+
data : pandas.DataFrame
|
|
250
|
+
Table containing at least the columns:
|
|
251
|
+
- 'cjd' : float
|
|
252
|
+
Corrected Julian dates.
|
|
253
|
+
- 'ra' : float
|
|
254
|
+
Right ascension in degrees.
|
|
255
|
+
- 'dec' : float
|
|
256
|
+
Declination in degrees.
|
|
257
|
+
- 'dRA' : float
|
|
258
|
+
RA drift rate in arcseconds per minute.
|
|
259
|
+
- 'dDec' : float
|
|
260
|
+
Dec drift rate in arcseconds per minute.
|
|
261
|
+
model_parameters : dict
|
|
262
|
+
Dictionary containing pole coordinates:
|
|
263
|
+
- 'alpha0' : float
|
|
264
|
+
Reference right ascension (degrees).
|
|
265
|
+
- 'delta0' : float
|
|
266
|
+
Reference declination (degrees).
|
|
267
|
+
synodic_period : float
|
|
268
|
+
Synodic period in days.
|
|
269
|
+
|
|
270
|
+
Returns
|
|
271
|
+
-------
|
|
272
|
+
tuple
|
|
273
|
+
(sidereal_period, sidereal_period_alt, epoch1) where:
|
|
274
|
+
- sidereal_period : float
|
|
275
|
+
Sidereal period corresponding to the nominal pole.
|
|
276
|
+
- sidereal_period_alt : float
|
|
277
|
+
Sidereal period corresponding to the antipodal pole.
|
|
278
|
+
- epoch1 : float
|
|
279
|
+
Epoch of the first observation (CJD).
|
|
280
|
+
"""
|
|
357
281
|
ra0 = model_parameters["alpha0"]
|
|
358
282
|
dec0 = model_parameters["delta0"]
|
|
359
283
|
|
|
@@ -387,40 +311,56 @@ def estimate_sidereal_period(data, model_parameters, synodic_period):
|
|
|
387
311
|
return sidereal_period, sidereal_period_alt, epoch1
|
|
388
312
|
|
|
389
313
|
|
|
390
|
-
def
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
clean_data_path,
|
|
394
|
-
rejected_data_path=None,
|
|
395
|
-
return_rejects=True,
|
|
396
|
-
):
|
|
397
|
-
file_name = find_sso_in_pqdict(sso_name=sso_name, pqdict=pq_dictionary)
|
|
398
|
-
file_path = os.path.join(clean_data_path, file_name)
|
|
399
|
-
|
|
400
|
-
pdf = pd.read_parquet(file_path)
|
|
401
|
-
|
|
402
|
-
cond_name = pdf["name"] == sso_name
|
|
403
|
-
clean_data = pdf[cond_name].copy().reset_index(drop=True)
|
|
404
|
-
# TODO: is this a good idea? probably not...
|
|
405
|
-
if return_rejects is True:
|
|
406
|
-
rejects = pd.read_pickle(os.path.join(rejected_data_path, sso_name + ".pkl"))
|
|
407
|
-
|
|
408
|
-
return clean_data, rejects
|
|
409
|
-
else:
|
|
410
|
-
return clean_data
|
|
314
|
+
def oblateness(a_b, a_c):
|
|
315
|
+
"""
|
|
316
|
+
Compute a simple oblateness proxy from axis ratios.
|
|
411
317
|
|
|
318
|
+
Parameters
|
|
319
|
+
----------
|
|
320
|
+
a_b : float or array_like
|
|
321
|
+
Intermediate-to-long axis ratio (b/a).
|
|
322
|
+
a_c : float or array_like
|
|
323
|
+
Short-to-long axis ratio (c/a).
|
|
412
324
|
|
|
413
|
-
|
|
325
|
+
Returns
|
|
326
|
+
-------
|
|
327
|
+
float or array_like
|
|
328
|
+
Oblateness measure defined as 0.5 * (a_b / a_c + 1 / a_b).
|
|
329
|
+
"""
|
|
414
330
|
return 1 / 2 * a_b / a_c + 1 / 2 * 1 / a_b
|
|
415
331
|
|
|
416
332
|
|
|
417
333
|
def wrap_longitude(long):
|
|
418
|
-
"""
|
|
334
|
+
"""
|
|
335
|
+
Wrap a longitude angle into the range [0, 360).
|
|
336
|
+
|
|
337
|
+
Parameters
|
|
338
|
+
----------
|
|
339
|
+
long : float or array_like
|
|
340
|
+
Input longitude in degrees.
|
|
341
|
+
|
|
342
|
+
Returns
|
|
343
|
+
-------
|
|
344
|
+
float or array_like
|
|
345
|
+
Longitude wrapped to the interval [0, 360).
|
|
346
|
+
"""
|
|
419
347
|
return long % 360
|
|
420
348
|
|
|
421
349
|
|
|
422
350
|
def wrap_latitude(lat):
|
|
423
|
-
"""
|
|
351
|
+
"""
|
|
352
|
+
Wrap a latitude angle into the range [-90, 90] by folding across the poles.
|
|
353
|
+
|
|
354
|
+
Parameters
|
|
355
|
+
----------
|
|
356
|
+
lat : float or array_like
|
|
357
|
+
Input latitude in degrees.
|
|
358
|
+
|
|
359
|
+
Returns
|
|
360
|
+
-------
|
|
361
|
+
float or array_like
|
|
362
|
+
Latitude wrapped to the interval [-90, 90].
|
|
363
|
+
"""
|
|
424
364
|
m = (lat + 90) % 360 # shift so -90 maps to 0
|
|
425
365
|
if m > 180:
|
|
426
366
|
m = 360 - m
|
|
@@ -429,12 +369,25 @@ def wrap_latitude(lat):
|
|
|
429
369
|
|
|
430
370
|
def generate_initial_points(ra, dec, dec_shift=45):
|
|
431
371
|
"""
|
|
432
|
-
Generate
|
|
372
|
+
Generate a set of 12 initial (RA, Dec) sampling points by combining
|
|
373
|
+
spin-flipped poles, RA sweeps, and latitude shifts.
|
|
374
|
+
|
|
375
|
+
Parameters
|
|
376
|
+
----------
|
|
377
|
+
ra : float
|
|
378
|
+
Base right ascension in degrees.
|
|
379
|
+
dec : float
|
|
380
|
+
Base declination in degrees.
|
|
381
|
+
dec_shift : float, optional
|
|
382
|
+
Latitude shift (degrees) applied when generating the secondary
|
|
383
|
+
sets of points. Defaults to 45 degrees.
|
|
433
384
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
385
|
+
Returns
|
|
386
|
+
-------
|
|
387
|
+
tuple of list
|
|
388
|
+
(ra_list, dec_list), where each list contains 18 elements
|
|
389
|
+
representing the generated right ascensions and declinations
|
|
390
|
+
in degrees.
|
|
438
391
|
"""
|
|
439
392
|
if np.abs(2 * dec - dec_shift) < 10:
|
|
440
393
|
dec_shift += 20
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: asteroid_spinprops
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Collection of tools used for fitting sHG1G2 and SOCCA photometric models to sparse asteroid photometry
|
|
5
|
+
License: MIT
|
|
6
|
+
Author: Odysseas
|
|
7
|
+
Author-email: odysseas.xenos@proton.me
|
|
8
|
+
Requires-Python: >=3.11
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Dist: astropy (==7.0.0)
|
|
16
|
+
Requires-Dist: fink-utils (==0.43.0)
|
|
17
|
+
Requires-Dist: nifty-ls (==1.1.0)
|
|
18
|
+
Requires-Dist: pandas (==2.3.3)
|
|
19
|
+
Requires-Dist: scipy (==1.16.2)
|
|
20
|
+
Requires-Dist: tqdm (==4.67.1)
|
|
21
|
+
Project-URL: Homepage, https://gitlab.com/odysseas_xenos/asteroid-spinprops
|
|
22
|
+
Project-URL: Repository, https://gitlab.com/odysseas_xenos/asteroid-spinprops
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# asteroid-spinprops
|
|
26
|
+
|
|
27
|
+
## Overview
|
|
28
|
+
**asteroid-spinprops** is a Python package providing tools to fit SHG1G2 and SOCCA photometric models to sparse asteroid photometry.
|
|
29
|
+
It supports multiband modeling, residual analysis and shape, period and pole orientation estimation for small solar system objects.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
Install the package via pip:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install asteroid_spinprops
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
```python
|
|
42
|
+
import numpy as np
|
|
43
|
+
import pandas as pd
|
|
44
|
+
from asteroid_spinprops.ssolib import dataprep, periodest, modelfit
|
|
45
|
+
|
|
46
|
+
# Suppose `pdf` is your initial asteroid DataFrame
|
|
47
|
+
# Ensure all columns are converted to the required single row format.
|
|
48
|
+
pdf_s = pd.DataFrame({col: [np.array(pdf[col])] for col in pdf.columns})
|
|
49
|
+
|
|
50
|
+
# Convert filter IDs to numeric
|
|
51
|
+
unique_vals, inv = np.unique(pdf_s["cfid"].values[0], return_inverse=True)
|
|
52
|
+
numeric_filter = inv + 1
|
|
53
|
+
pdf_s["cfid"].values[0] = numeric_filter
|
|
54
|
+
|
|
55
|
+
# --- Data cleaning and filtering ---
|
|
56
|
+
clean_data, errorbar_rejects = dataprep.errorbar_filtering(data=pdf_s, mlimit=0.7928)
|
|
57
|
+
clean_data, projection_rejects = dataprep.projection_filtering(data=clean_data)
|
|
58
|
+
clean_data, iterative_rejects = dataprep.iterative_filtering(data=clean_data)
|
|
59
|
+
|
|
60
|
+
# --- Fit SHG1G2 model ---
|
|
61
|
+
shg1g2_params = modelfit.get_fit_params(
|
|
62
|
+
data=clean_data,
|
|
63
|
+
flavor="SHG1G2",
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# Compute residuals for period analysis
|
|
67
|
+
residuals_dataframe = modelfit.make_residuals_df(
|
|
68
|
+
clean_data, model_parameters=shg1g2_params
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# --- Estimate rotation period ---
|
|
72
|
+
p_in, k_val, p_rms, signal_peak, window_peak = periodest.get_multiband_period_estimate(
|
|
73
|
+
residuals_dataframe,
|
|
74
|
+
k_free=True,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Assess period robustness via bootstrap resampling
|
|
78
|
+
_, Nbs = periodest.perform_residual_resampling(
|
|
79
|
+
resid_df=residuals_dataframe,
|
|
80
|
+
p_min=0.03,
|
|
81
|
+
p_max=2,
|
|
82
|
+
k=int(k_val)
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# --- Fit SSHG1G2 (spin + multiband) model ---
|
|
86
|
+
SOCCA_params = modelfit.get_fit_params(
|
|
87
|
+
data=clean_data,
|
|
88
|
+
flavor="SSHG1G2",
|
|
89
|
+
shg1g2_constrained=True,
|
|
90
|
+
blind_scan=True,
|
|
91
|
+
period_in=p_in,
|
|
92
|
+
)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Models
|
|
96
|
+
Photometric models from Carry et al.(2024) {2024A&A...687A..38C}
|
|
97
|
+
and https://github.com/astrolabsoftware
|
|
98
|
+
|
|
99
|
+
## Project status
|
|
100
|
+
Under development
|
|
101
|
+
|
|
@@ -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=Kg5Qn0yU4wbfat9ZCvT9pYqSIo9toUm5kwhCiSvhalw,15898
|
|
5
|
+
asteroid_spinprops/ssolib/periodest.py,sha256=XCBqsgPFcLFk-vreVmpYPjghJDyUyHSEeCULayqPRHg,13216
|
|
6
|
+
asteroid_spinprops/ssolib/ssptools.py,sha256=DlSgYtXenztRAtEV9d4itzp5OZMjkbXkW2yZ_Qumu4U,4490
|
|
7
|
+
asteroid_spinprops/ssolib/utils.py,sha256=BUeIP0DZ45tg5qAQML8LBM8Gbj1vn2d3PGzvgQvfq_I,11094
|
|
8
|
+
asteroid_spinprops-1.0.0.dist-info/METADATA,sha256=LZvpOARV-nWnAkOnr5S097mzTbWufl7_qPS8zYxE6gw,3111
|
|
9
|
+
asteroid_spinprops-1.0.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
10
|
+
asteroid_spinprops-1.0.0.dist-info/RECORD,,
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Signature: 8a477f597d28d172789f06886806bc55
|