asteroid_spinprops 0.2.32__py3-none-any.whl → 1.0.1__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.
Files changed (30) hide show
  1. asteroid_spinprops/ssolib/dataprep.py +0 -346
  2. asteroid_spinprops/ssolib/modelfit.py +143 -252
  3. asteroid_spinprops/ssolib/periodest.py +126 -158
  4. asteroid_spinprops/ssolib/utils.py +164 -211
  5. asteroid_spinprops-1.0.1.dist-info/METADATA +186 -0
  6. asteroid_spinprops-1.0.1.dist-info/RECORD +10 -0
  7. asteroid_spinprops/ssolib/.ruff_cache/.gitignore +0 -2
  8. asteroid_spinprops/ssolib/.ruff_cache/0.13.2/1980339045096230685 +0 -0
  9. asteroid_spinprops/ssolib/.ruff_cache/CACHEDIR.TAG +0 -1
  10. asteroid_spinprops/ssolib/pipetools.py +0 -167
  11. asteroid_spinprops/ssolib/testing/atlas_x_ztf_testing/test_pqfile_1.parquet +0 -0
  12. asteroid_spinprops/ssolib/testing/atlas_x_ztf_testing/test_pqfile_2.parquet +0 -0
  13. asteroid_spinprops/ssolib/testing/ephemeris_testing/2000 WL152 +0 -1702
  14. asteroid_spinprops/ssolib/testing/ephemeris_testing/2001 PC +0 -94
  15. asteroid_spinprops/ssolib/testing/ephemeris_testing/2001 SG276 +0 -111
  16. asteroid_spinprops/ssolib/testing/ephemeris_testing/2008 GX32 +0 -93
  17. asteroid_spinprops/ssolib/testing/ephemeris_testing/2009 BE185 +0 -130
  18. asteroid_spinprops/ssolib/testing/ephemeris_testing/2011 EY17 +0 -101
  19. asteroid_spinprops/ssolib/testing/ephemeris_testing/2134 T-1 +0 -352
  20. asteroid_spinprops/ssolib/testing/ephemeris_testing/Bellmore +0 -2657
  21. asteroid_spinprops/ssolib/testing/ephemeris_testing/Dermott +0 -2971
  22. asteroid_spinprops/ssolib/testing/ephemeris_testing/Duke +0 -2026
  23. asteroid_spinprops/ssolib/testing/ephemeris_testing/Izenberg +0 -2440
  24. asteroid_spinprops/ssolib/testing/ephemeris_testing/Lermontov +0 -2760
  25. asteroid_spinprops/ssolib/testing/ephemeris_testing/Poullain +0 -1272
  26. asteroid_spinprops/ssolib/testing/ephemeris_testing/Sonneberga +0 -2756
  27. asteroid_spinprops/ssolib/testing/testing_ssoname_keys.pkl +0 -0
  28. asteroid_spinprops-0.2.32.dist-info/METADATA +0 -77
  29. asteroid_spinprops-0.2.32.dist-info/RECORD +0 -31
  30. {asteroid_spinprops-0.2.32.dist-info → asteroid_spinprops-1.0.1.dist-info}/WHEEL +0 -0
@@ -1,8 +1,5 @@
1
1
  import numpy as np
2
2
  import pandas as pd
3
- import matplotlib.pyplot as plt
4
- import sys
5
- import os
6
3
  from asteroid_spinprops.ssolib.modelfit import (
7
4
  get_fit_params,
8
5
  get_residuals,
@@ -251,346 +248,3 @@ def lightcurve_filtering(data, window=10, maglim=0.6):
251
248
  data = utils.sort_by_cjd(data)
252
249
 
253
250
  return data, rejects
254
-
255
-
256
- def plot_filtering(
257
- clean_data, rejects, lc_filtering=False, iter_filtering=True, xaxis="Phase"
258
- ):
259
- if xaxis == "Date":
260
- coll = "cjd"
261
- if xaxis == "Phase":
262
- coll = "Phase"
263
- errorbar_rejects, projection_rejects, iterative_rejects, lightcurve_rejects = (
264
- rejects[0],
265
- rejects[1],
266
- rejects[2],
267
- rejects[3],
268
- )
269
-
270
- fig, ax = plt.subplots(2, 2, figsize=(12, 6))
271
-
272
- filter_names = ["ZTF g", "ZTF r", "ATLAS orange", "ATLAS cyan"]
273
-
274
- for i, f in enumerate(np.unique(clean_data["cfid"].values[0])):
275
- if f in [1, 2]:
276
- row = 0
277
- if f in [3, 4]:
278
- row = 1
279
-
280
- if i % 2 != 0:
281
- col = 1
282
- else:
283
- col = 0
284
-
285
- filter_mask = np.array(clean_data["cfid"].values[0]) == f
286
- filter_mask_r1 = np.array(errorbar_rejects["cfid"].values[0]) == f
287
- filter_mask_r2 = np.array(projection_rejects["cfid"].values[0]) == f
288
-
289
- if iter_filtering is True:
290
- filter_mask_r3 = np.array(iterative_rejects["cfid"].values[0]) == f
291
- else:
292
- filter_mask_r3 = None
293
-
294
- if lc_filtering is True:
295
- filter_mask_r4 = np.array(lightcurve_rejects["cfid"].values[0]) == f
296
- else:
297
- filter_mask_r4 = None
298
-
299
- ax[row, col].errorbar(
300
- x=clean_data[coll].values[0][filter_mask],
301
- y=clean_data["cmred"].values[0][filter_mask],
302
- yerr=clean_data["csigmapsf"].values[0][filter_mask],
303
- fmt=".",
304
- capsize=2,
305
- ms=5,
306
- elinewidth=1,
307
- label="Valid points",
308
- )
309
-
310
- ax[row, col].errorbar(
311
- x=errorbar_rejects[coll].values[0][filter_mask_r1],
312
- y=errorbar_rejects["cmred"].values[0][filter_mask_r1],
313
- yerr=errorbar_rejects["csigmapsf"].values[0][filter_mask_r1],
314
- fmt="x",
315
- capsize=2,
316
- ms=15,
317
- elinewidth=1,
318
- c="tab:red",
319
- label=r"$\delta m > 3\sigma_{LCDB}$",
320
- )
321
-
322
- ax[row, col].errorbar(
323
- x=projection_rejects[coll].values[0][filter_mask_r2],
324
- y=projection_rejects["cmred"].values[0][filter_mask_r2],
325
- yerr=projection_rejects["csigmapsf"].values[0][filter_mask_r2],
326
- fmt="+",
327
- capsize=2,
328
- ms=15,
329
- elinewidth=1,
330
- c="tab:green",
331
- label=r"$\substack{m > \bar{m} + 3\sigma_m \\ m < \bar{m} - 3\sigma_m}$",
332
- )
333
- if iter_filtering is True:
334
- ax[row, col].errorbar(
335
- x=iterative_rejects[coll].values[0][filter_mask_r3],
336
- y=iterative_rejects["cmred"].values[0][filter_mask_r3],
337
- yerr=iterative_rejects["csigmapsf"].values[0][filter_mask_r3],
338
- fmt=">",
339
- capsize=2,
340
- ms=7,
341
- elinewidth=1,
342
- label=r"sHG$_1$G$_2$ filtering",
343
- )
344
- if lc_filtering is True:
345
- ax[row, col].errorbar(
346
- x=lightcurve_rejects[coll].values[0][filter_mask_r4],
347
- y=lightcurve_rejects["cmred"].values[0][filter_mask_r4],
348
- yerr=lightcurve_rejects["csigmapsf"].values[0][filter_mask_r4],
349
- fmt="P",
350
- capsize=2,
351
- ms=7,
352
- elinewidth=1,
353
- c="black",
354
- label="Lightcurve",
355
- )
356
-
357
- ax[row, col].invert_yaxis()
358
- ax[row, col].text(
359
- 0.05,
360
- 0.05,
361
- filter_names[i],
362
- transform=ax[row, col].transAxes,
363
- va="bottom",
364
- ha="left",
365
- bbox=dict(
366
- facecolor="white",
367
- edgecolor="black",
368
- boxstyle="round,pad=0.3",
369
- alpha=0.8,
370
- ),
371
- )
372
- if xaxis == "Phase":
373
- ax[1, 0].set_xlabel("Phase / deg")
374
- ax[1, 1].set_xlabel("Phase / deg")
375
- if xaxis == "Date":
376
- ax[1, 0].set_xlabel("JD")
377
- ax[1, 1].set_xlabel("JD")
378
- ax[0, 0].set_ylabel("Reduced magnitude")
379
- ax[1, 0].set_ylabel("Reduced magnitude")
380
-
381
- ax[0, 1].legend(loc="upper right")
382
-
383
-
384
- def filter_sso_data(
385
- sso_name,
386
- path_to_data,
387
- pqdict,
388
- compute_ephemerides=False,
389
- ephem_path=None,
390
- mlimit=0.7928,
391
- lc_maglim=0.6,
392
- lc_filtering=False,
393
- iter_filtering=True,
394
- ):
395
- """
396
- Filters data for a given SSO.
397
- Applies errorbar, projections, iterative sigma-clipping and lightcurve filtering.
398
-
399
- Parameters
400
- ----------
401
- sso_name : str
402
- The name of the solar system object to filter.
403
- path_to_data : str
404
- Path to the data files.
405
- pqdict : dict
406
- Dictionary linking parquet filename to SSO.
407
- ephem_path : str | None
408
- Path to the ephemeris data.
409
- mlimit : float, optional
410
- Magnitude limit for errorbar filtering (default is 0.7928).
411
- lc_filtering : bool, optional
412
- Whether to apply lightcurve filtering (default is True).
413
- iter_filtering : bool, optional
414
- Whether to apply iterative filtering (default is True).
415
-
416
- Returns
417
- -------
418
- clean_data : pd.DataFrame
419
- Cleaned data
420
- rejects : list
421
- List of rejected data points from each filtering step.
422
-
423
- Examples
424
- ---------
425
-
426
- >>> from asteroid_spinprops.ssolib.dataprep import prepare_sso_data, filter_sso_data
427
- >>> from asteroid_spinprops.ssolib.dataprep import __file__
428
- >>> import os
429
- >>> import pickle
430
-
431
- >>> wpath = os.path.dirname(__file__)
432
-
433
- >>> ephem_path = os.path.join(wpath, "testing/ephemeris_testing")
434
- >>> data_path = os.path.join(wpath, "testing/atlas_x_ztf_testing")
435
- >>> pq_keys = os.path.join(wpath, "testing/testing_ssoname_keys.pkl")
436
- >>> available_ssos = os.listdir(ephem_path)
437
-
438
- >>> with open(pq_keys, "rb") as f:
439
- ... pqload = pickle.load(f)
440
-
441
- >>> path_args = [data_path, pqload, ephem_path]
442
-
443
- >>> for name in available_ssos:
444
- ... origin_data = prepare_sso_data(name, *path_args)
445
- ... cdata, rejects = filter_sso_data(name, *path_args)
446
- ... clean_p_rejects = cdata["cmred"].values[0].size
447
- ... for n in range(4):
448
- ... clean_p_rejects += rejects[n]["cmred"].values[0].size
449
-
450
- >>> assert origin_data["cmred"].values[0].size == clean_p_rejects
451
- """
452
- if compute_ephemerides is False:
453
- clean_data = read_sso_data(
454
- sso_name=sso_name, path_to_data=path_to_data, pqdict=pqdict
455
- )
456
- else:
457
- clean_data = prepare_sso_data(
458
- sso_name=sso_name,
459
- path_to_data=path_to_data,
460
- pqdict=pqdict,
461
- ephem_path=ephem_path,
462
- )
463
-
464
- clean_data, errorbar_rejects = errorbar_filtering(data=clean_data, mlimit=mlimit)
465
- clean_data, projection_rejects = projection_filtering(data=clean_data)
466
- if iter_filtering is True:
467
- clean_data, iterative_rejects = iterative_filtering(clean_data)
468
- else:
469
- iterative_rejects = None
470
-
471
- if lc_filtering is True:
472
- clean_data, lightcurve_rejects = lightcurve_filtering(
473
- clean_data, maglim=lc_maglim
474
- )
475
- else:
476
- lightcurve_rejects = None
477
-
478
- return clean_data, [
479
- errorbar_rejects,
480
- projection_rejects,
481
- iterative_rejects,
482
- lightcurve_rejects,
483
- ]
484
-
485
-
486
- def prepare_sso_data(
487
- sso_name,
488
- path_to_data,
489
- pqdict,
490
- ephem_path,
491
- ):
492
- """
493
- Load and prepare observational and ephemeris data for a given solar system object (SSO).
494
-
495
- - Locates the appropriate pqfile containing the SSO & loads its photometric data
496
- - Retrieves or generates the corresponding ephemeris and appends SSO-Sun & SSO-Obs distances, phase angle, RA/Dec, elongation, reduced magnitude
497
- - The resulting DataFrame is sorted by Julian date
498
-
499
- Parameters
500
- -----------------------------
501
- sso_name : str
502
- The name of the solar system object to retrieve data for.
503
- path_to_data : str
504
- Path to the directory containing pqfiles in Parquet format.
505
- pqdict : dict
506
- Dictionary mapping pqfile names to lists of SSOs they contain.
507
- ephem_path : str | None
508
- Path to the directory containing cached ephemeris files.
509
-
510
- Returns
511
- -----------------------------
512
- data_extra : pd.DataFrame
513
- A DataFrame containing observational data and appended ephemeris-related quantities:
514
- - 'Dobs': observer-centric distance [au]
515
- - 'Dhelio': heliocentric distance [au]
516
- - 'Phase': phase angle [deg]
517
- - 'ra', 'dec': right ascension and declination [deg]
518
- - 'Elongation': solar elongation angle [deg]
519
- - 'cmred': reduced magnitude
520
- The data is sorted chronologically by Julian date.
521
- """
522
- file_name = utils.find_sso_in_pqdict(sso_name=sso_name, pqdict=pqdict)
523
- file_path = os.path.join(path_to_data, file_name)
524
-
525
- pdf = pd.read_parquet(file_path)
526
-
527
- cond_name = pdf["name"] == sso_name
528
- data_extra = pdf[cond_name].copy().reset_index(drop=True)
529
-
530
- ephemeris = utils.get_atlas_ephem(
531
- pdf=pdf, name=sso_name, path_to_cached_ephems=ephem_path
532
- )
533
-
534
- Dobs = ephemeris["Dobs"].values
535
-
536
- Dhelio = ephemeris["Dhelio"].values
537
- Phase = ephemeris["Phase"].values
538
- Elongation = ephemeris["Elong."].values
539
- dRA = ephemeris["dRAcosDEC"].values
540
- dDec = ephemeris["dDEC"].values
541
-
542
- # px, py, pz = ephemeris["px"], ephemeris["py"], ephemeris["pz"]
543
- ra, dec = ra, dec = utils.sexa_to_deg(
544
- ephemeris["RA"].values, ephemeris["DEC"].values
545
- )
546
-
547
- data_extra[
548
- ["Dobs", "Dhelio", "Phase", "ra", "dec", "Elongation", "dRA", "dDec"]
549
- ] = pd.DataFrame(
550
- [[Dobs, Dhelio, Phase, ra, dec, Elongation, dRA, dDec]],
551
- index=data_extra.index,
552
- )
553
-
554
- data_extra["cmred"] = [
555
- utils.calculate_reduced_magnitude(
556
- magnitude=data_extra["cmagpsf"].values[0],
557
- D_observer=data_extra["Dobs"].values[0],
558
- D_sun=data_extra["Dhelio"].values[0],
559
- )
560
- ]
561
- data_extra = utils.sort_by_cjd(data_extra)
562
- return data_extra
563
-
564
-
565
- def read_sso_data(
566
- sso_name,
567
- path_to_data,
568
- pqdict,
569
- ):
570
- file_name = utils.find_sso_in_pqdict(sso_name=sso_name, pqdict=pqdict)
571
- file_path = os.path.join(path_to_data, file_name)
572
-
573
- pdf = pd.read_parquet(file_path)
574
-
575
- cond_name = pdf["name"] == sso_name
576
- data_extra = pdf[cond_name].copy().reset_index(drop=True)
577
-
578
- data_extra["cmred"] = [
579
- utils.calculate_reduced_magnitude(
580
- magnitude=data_extra["cmagpsf"].values[0],
581
- D_observer=data_extra["Dobs"].values[0],
582
- D_sun=data_extra["Dhelio"].values[0],
583
- )
584
- ]
585
-
586
- data_extra = data_extra.rename(columns={"RA": "ra", "DEC": "dec"})
587
-
588
- data_extra = utils.sort_by_cjd(data_extra)
589
-
590
- return data_extra
591
-
592
-
593
- if __name__ == "__main__":
594
- import doctest
595
-
596
- sys.exit(doctest.testmod()[0])