1- # Copyright 2023-2024 AstroLab Software
1+ # Copyright 2023-2025 AstroLab Software
22# Author: Julien Peloton
33#
44# Licensed under the Apache License, Version 2.0 (the "License");
2929from fink_utils .sso .spins import estimate_sso_params
3030from fink_utils .sso .spins import extract_obliquity
3131from fink_utils .sso .utils import rockify , extract_array_from_series
32+ from fink_utils .sso .utils import compute_light_travel_correction
3233
3334from fink_science import __file__
3435from fink_science .tester import spark_unit_tests
3940from astropy .coordinates import SkyCoord
4041import astropy .units as u
4142
43+ from asteroid_spinprops .ssolib import modelfit
44+
4245import logging
4346
4447
169172 "version" : {"type" : "str" , "description" : "Version of the SSOFT YYYY.MM" },
170173}
171174
172- COLUMNS_SSHG1G2 = {
175+ COLUMNS_SOCCA = {
173176 "G1_1" : {
174177 "type" : "double" ,
175178 "description" : "G1 phase parameter for the ZTF filter band g" ,
408411}
409412
410413
411- def estimate_period ():
412- """TBD
413-
414- Should be done only for SSHG1G2
415-
416- sb_method: str
417- Specify the single-band lomb scargle implementation to use.
418- See https://docs.astropy.org/en/stable/api/astropy.timeseries.LombScargleMultiband.html#astropy.timeseries.LombScargleMultiband.autopower
419- If nifty-ls is installed, one can also specify fastnifty. Although
420- in this case it does not work yet for Nterms_* higher than 1.
421- """
422- pass
423-
424-
425- def extract_ssoft_parameters_sshg1g2 ():
426- """TBD
427-
428- Notes
429- -----
430- For the SSHG1G2 model, the strategy is the following:
431- 1. Compute parameters as if it was SHG2G1 model (incl. period estimation)
432- 2. Using previously computed parameters, compute parameters from SSHG1G2
433- """
434- pass
435-
436-
437414@pandas_udf (MapType (StringType (), FloatType ()), PandasUDFType .SCALAR )
438415@profile
439416def extract_ssoft_parameters (
@@ -457,7 +434,7 @@ def extract_ssoft_parameters(
457434 Notes
458435 -----
459436 Only works for HG, HG1G2, and SHG1G2. Rotation period
460- is not estimated here. For SSHG1G2 , see <TBD>
437+ is not estimated here. For SOCCA , see <TBD>
461438
462439 Parameters
463440 ----------
@@ -483,7 +460,7 @@ def extract_ssoft_parameters(
483460 Use only the former on the Spark Cluster (local installation of ephemcc),
484461 otherwise use `rest` to call the ssodnet web service.
485462 model: str
486- Model name. Available: HG, HG1G2, SHG1G2
463+ Model name. Available: HG, HG1G2, SHG1G2, SOCCA
487464
488465
489466 Returns
@@ -502,7 +479,7 @@ def extract_ssoft_parameters(
502479 [30 , 1 , 1 , 1 , 2 * np .pi , np .pi / 2 ],
503480 ),
504481 },
505- "SSHG1G2 " : {
482+ "SOCCA " : {
506483 "p0" : [15.0 , 0.15 , 0.15 , np .pi , 0.0 , 5.0 , 1.05 , 1.05 , 0.0 ],
507484 "bounds" : (
508485 [- 3 , 0 , 0 , 0 , - np .pi / 2 , 2.2 / 24.0 , 1 , 1 , - np .pi / 2 ],
@@ -525,35 +502,81 @@ def extract_ssoft_parameters(
525502 extract_array_from_series (dobs , index , float )
526503 * extract_array_from_series (dhelio , index , float )
527504 )
528- pdf = pd .DataFrame ({
529- "i:ssnamenr" : [ssname ] * len (raobs .to_numpy ()[index ]),
530- "i:magpsf" : extract_array_from_series (magpsf , index , float ),
531- "i:sigmapsf" : extract_array_from_series (sigmapsf , index , float ),
532- "i:jd" : extract_array_from_series (jd , index , float ),
533- "i:fid" : extract_array_from_series (fid , index , int ),
534- "i:ra" : extract_array_from_series (raobs , index , float ),
535- "i:dec" : extract_array_from_series (decobs , index , float ),
536- "i:raephem" : extract_array_from_series (raephem , index , float ),
537- "i:decephem" : extract_array_from_series (decephem , index , float ),
538- "i:magpsf_red" : magpsf_red ,
539- "Phase" : extract_array_from_series (phase , index , float ),
540- "Dobs" : extract_array_from_series (dobs , index , float ),
541- })
542- pdf = pdf .sort_values ("i:jd" )
543-
544- outdic = estimate_sso_params (
545- pdf ["i:magpsf_red" ].to_numpy (),
546- pdf ["i:sigmapsf" ].to_numpy (),
547- np .deg2rad (pdf ["Phase" ].to_numpy ()),
548- pdf ["i:fid" ].to_numpy (),
549- np .deg2rad (pdf ["i:ra" ].to_numpy ()),
550- np .deg2rad (pdf ["i:dec" ].to_numpy ()),
551- jd = pdf ["i:jd" ].to_numpy (),
552- p0 = MODELS [model_name ]["p0" ],
553- bounds = MODELS [model_name ]["bounds" ],
554- model = model_name ,
555- normalise_to_V = False ,
556- )
505+ if model_name == "SOCCA" :
506+ jd_lt = compute_light_travel_correction (
507+ extract_array_from_series (jd , index , float ),
508+ extract_array_from_series (dobs , index , float ),
509+ )
510+ pdf = pd .DataFrame ({
511+ "cmred" : magpsf_red ,
512+ "csigmapsf" : extract_array_from_series (sigmapsf , index , float ),
513+ "Phase" : extract_array_from_series (phase , index , float ),
514+ "cfid" : extract_array_from_series (fid , index , int ),
515+ "ra" : extract_array_from_series (raobs , index , float ),
516+ "dec" : extract_array_from_series (decobs , index , float ),
517+ "cjd" : jd_lt ,
518+ "i:raephem" : extract_array_from_series (raephem , index , float ),
519+ "i:decephem" : extract_array_from_series (decephem , index , float ),
520+ })
521+ pdf = pdf .sort_values ("cjd" )
522+
523+ # Wrap columns inplace
524+ pdf_transposed = pd .DataFrame ({
525+ colname : [pdf [colname ].to_numpy ()] for colname in pdf .columns
526+ })
527+
528+ # parameter estimation
529+ outdic = modelfit .get_fit_params (
530+ pdf_transposed ,
531+ flavor = model_name ,
532+ shg1g2_constrained = True ,
533+ period_blind = True ,
534+ pole_blind = True ,
535+ alt_spin = False ,
536+ period_in = None ,
537+ terminator = False ,
538+ )
539+
540+ # replace names inplace for the remaning computation
541+ pdf = pdf .rename (
542+ columns = {
543+ "ra" : "i:ra" ,
544+ "dec" : "i:dec" ,
545+ "cfid" : "i:fid" ,
546+ "cjd" : "i:jd" , # FIXME: this is lighttime corrected
547+ }
548+ )
549+ else :
550+ pdf = pd .DataFrame ({
551+ "i:ssnamenr" : [ssname ] * len (raobs .to_numpy ()[index ]),
552+ "i:magpsf" : extract_array_from_series (magpsf , index , float ),
553+ "i:sigmapsf" : extract_array_from_series (sigmapsf , index , float ),
554+ "i:jd" : extract_array_from_series (jd , index , float ),
555+ "i:fid" : extract_array_from_series (fid , index , int ),
556+ "i:ra" : extract_array_from_series (raobs , index , float ),
557+ "i:dec" : extract_array_from_series (decobs , index , float ),
558+ "i:raephem" : extract_array_from_series (raephem , index , float ),
559+ "i:decephem" : extract_array_from_series (decephem , index , float ),
560+ "i:magpsf_red" : magpsf_red ,
561+ "Phase" : extract_array_from_series (phase , index , float ),
562+ "Dobs" : extract_array_from_series (dobs , index , float ),
563+ })
564+
565+ pdf = pdf .sort_values ("i:jd" )
566+
567+ outdic = estimate_sso_params (
568+ pdf ["i:magpsf_red" ].to_numpy (),
569+ pdf ["i:sigmapsf" ].to_numpy (),
570+ np .deg2rad (pdf ["Phase" ].to_numpy ()),
571+ pdf ["i:fid" ].to_numpy (),
572+ np .deg2rad (pdf ["i:ra" ].to_numpy ()),
573+ np .deg2rad (pdf ["i:dec" ].to_numpy ()),
574+ jd = pdf ["i:jd" ].to_numpy (),
575+ p0 = MODELS [model_name ]["p0" ],
576+ bounds = MODELS [model_name ]["bounds" ],
577+ model = model_name ,
578+ normalise_to_V = False ,
579+ )
557580
558581 # Add astrometry
559582 fink_coord = SkyCoord (
@@ -674,6 +697,19 @@ def build_the_ssoft(
674697 >>> col_ssoft_shg1g2 = sorted(ssoft_shg1g2.columns)
675698 >>> expected_cols = sorted({**COLUMNS, **COLUMNS_SHG1G2}.keys())
676699 >>> assert col_ssoft_shg1g2 == expected_cols, (col_ssoft_shg1g2, expected_cols)
700+
701+ >>> ssoft_socca = build_the_ssoft(
702+ ... aggregated_filename=aggregated_filename,
703+ ... nparts=1,
704+ ... nmin=50,
705+ ... frac=None,
706+ ... model='SOCCA',
707+ ... version=None,
708+ ... ephem_method="rest",
709+ ... sb_method="fastnifty")
710+ <BLANKLINE>
711+ >>> assert len(ssoft_socca) == 2, ssoft_socca
712+ >>> assert "period" in ssoft_socca.columns, ssoft_socca.columns
677713 """
678714 spark = SparkSession .builder .getOrCreate ()
679715 spark .sparkContext .setLogLevel ("WARN" )
0 commit comments