"""
This module defines the `SNLS` survey class, including the SNLS field coordinates, MegaCam footprint, and tools
to load the observing logs.
"""
import numpy as np
import pandas
import sncosmo
from .basesurvey import GridSurvey
FIELDID = {'D1': {'ra': 36.450190, 'dec': -4.45065},
'D2': {'ra': 150.11322, 'dec': +2.21571},
'D3': {'ra': 214.90738, 'dec': +52.6660},
'D4': {'ra': 333.89903, 'dec': -17.71961}}
[docs]
def get_snls_field_coordinates(fieldid_name="fieldid"):
""" Get the radec location of the 4 SNLS fields.
Parameters
----------
fieldid_name: str
name of the fieldid column.
Returns
-------
`pandas.DataFrame`
"""
data = pandas.DataFrame(FIELDID).T
data.index.name = fieldid_name
return data
[docs]
def get_weblogs(url="https://supernovae.in2p3.fr/snls5/snls_obslogs.csv"):
""" Load and parse data from the input url.
Parameters
----------
url: str
url to the data.
Returns
-------
`pandas.DataFrame`
"""
data_snls = pandas.read_csv(url)
# merge RA, Dec as one of the four fields
radec_groups = data_snls[["ra","dec"]].round(0).groupby(["ra","dec"]).groups
fields = pandas.Series(radec_groups, name="index").to_frame()
fields["fieldid"] = ["D1", "D2", "D3", "D4"]
# and merge them inside the web-log
data_snls = data_snls.merge(fields[["index", "fieldid"]].explode("index").set_index("index").sort_index(),
left_index=True, right_index=True)
# url logs provide RA,Dec in radian, skysurvey works in degree
data_snls[["ra", "dec"]] = data_snls[["ra", "dec"]] * 180 / np.pi
data_snls["band"] = data_snls["band"].str.lower() # forcing low-cap
return data_snls
[docs]
def register_snls_bandpasses(filters=['g', 'r', 'i', 'z', 'y'], prefix="megacampsf", at_radius=13.):
""" Register snls band passes to sncosmo assuming a single radius.
Parameters
----------
filters: list
names of the snls filters
prefix: str
prefix for the megacam filters format: {prefix}{filter}
at_radius: float
bandpass will be estimated at this entry radius.
Returns
-------
None
"""
try:
sncosmo.get_bandpass("megacampsf::g")
return
# not well done...
except: # noqa
pass
for filter_ in filters:
megacamband = sncosmo.get_bandpass(f'megacampsf::{filter_}', at_radius)
megacamband.name = f'{prefix}::{filter_}'
sncosmo.register(megacamband, force=True)
[docs]
class SNLS( GridSurvey ):
""" A class to model the `SNLS` survey.
Parameters
----------
data: `pandas.DataFrame`
observing data.
**kwargs:
goes to ``GridSurvey.__init__``
"""
def __init__(self, data=None, **kwargs):
""" Initialize the SNLS class."""
footprint = get_snls_footprint()
fields = self._parse_fields(get_snls_field_coordinates(), footprint)
register_snls_bandpasses() # loads bandpass
super().__init__(data=data, fields=fields, footprint=footprint,
**kwargs)
[docs]
@classmethod
def from_logs(cls, logpath=None, **kwargs):
""" Loads the data from the observing logs.
If None provided, this uses:
https://supernovae.in2p3.fr/snls5/snls_obslogs.csv
Parameters
----------
logpath: path
filepath to where the logs are stored (as csv).
If None, the official snls webpage is used:
https://supernovae.in2p3.fr/snls5/snls_obslogs.csv
**kwargs goes to ``GridSurvey.__init__``
Returns
-------
instance
"""
if logpath is None:
logpath = "https://supernovae.in2p3.fr/snls5/snls_obslogs.csv"
snls_log = get_weblogs(logpath)
else:
snls_log = pandas.read_cvs(logpath)
if "fieldid" not in snls_log:
raise ValueError("fieldid is not provided in the input log.")
return cls.from_pointings(data=snls_log)
[docs]
@classmethod
def from_pointings(cls, data, **kwargs):
""" Loads from observing log data.
Parameters
----------
data: `pandas.DataFrame`, dict
observing logs, must contains:
['zp', 'fieldid', 'gain', 'skynoise', 'mjd', 'band']
**kwargs goes to ``GridSurvey.__init__``
Returns
-------
instance
See also:
---------
:func:`from_logs()`: loads the data from input file (or web).
"""
if type(data) is dict:
data = pandas.DataFrame.from_dict(data)
return cls(data=data, **kwargs)