-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
tickets/PREOPS-4948: functions to support imitating a DES nightsum report using a Times Square notebook #75
Changes from 3 commits
7e33c32
e6c0ba9
a7f22d5
1161ece
f1d7f82
7749366
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,4 +11,5 @@ param | |
pytz | ||
uranography | ||
rubin-scheduler | ||
rubin-sim | ||
pip |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
from .metrics import get_metric_path # noqa F401 | ||
from .opsim import read_opsim # noqa F401 | ||
from .opsim import read_ddf_visits, read_opsim # noqa F401 | ||
from .scheduler_pickle import read_scheduler # noqa F401 | ||
from .scheduler_pickle import sample_pickle # noqa F401 | ||
from .stars import load_bright_stars # noqa F401 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,99 @@ | ||
import sqlite3 | ||
|
||
import numpy as np | ||
import pandas as pd | ||
import yaml | ||
from astropy.time import Time | ||
from lsst.resources import ResourcePath | ||
from rubin_scheduler.utils import ddf_locations | ||
from rubin_sim import maf | ||
|
||
DEFAULT_VISITS_COLUMNS = [ | ||
"observationId", | ||
"fieldRA", | ||
"fieldDec", | ||
"observationStartMJD", | ||
"flush_by_mjd", | ||
"visitExposureTime", | ||
"filter", | ||
"rotSkyPos", | ||
"rotSkyPos_desired", | ||
"numExposures", | ||
"airmass", | ||
"seeingFwhm500", | ||
"seeingFwhmEff", | ||
"seeingFwhmGeom", | ||
"skyBrightness", | ||
"night", | ||
"slewTime", | ||
"visitTime", | ||
"slewDistance", | ||
"fiveSigmaDepth", | ||
"altitude", | ||
"azimuth", | ||
"paraAngle", | ||
"cloud", | ||
"moonAlt", | ||
"sunAlt", | ||
"note", | ||
"target", | ||
"fieldId", | ||
"proposalId", | ||
"block_id", | ||
"observationStartLST", | ||
"rotTelPos", | ||
"rotTelPos_backup", | ||
"moonAz", | ||
"sunAz", | ||
"sunRA", | ||
"sunDec", | ||
"moonRA", | ||
"moonDec", | ||
"moonDistance", | ||
"solarElong", | ||
"moonPhase", | ||
"cummTelAz", | ||
"scripted_id", | ||
] | ||
|
||
def read_opsim(opsim_uri, start_time="2000-01-01", end_time="2100-01-01"): | ||
|
||
class StartDateStacker(maf.BaseStacker): | ||
"""Add the start date.""" | ||
|
||
cols_added = ["start_date"] | ||
|
||
def __init__(self, start_mjd_col="observationStartMJD"): | ||
self.units = "ns" | ||
self.cols_req = [start_mjd_col] | ||
self.start_mjd_col = start_mjd_col | ||
|
||
def _run(self, sim_data, cols_present=False): | ||
"""The start date as a datetime.""" | ||
if cols_present: | ||
# Column already present in data; assume it is correct and does not | ||
# need recalculating. | ||
return sim_data | ||
if len(sim_data) == 0: | ||
return sim_data | ||
|
||
sim_data["start_date"] = pd.to_datetime( | ||
sim_data[self.start_mjd_col] + 2400000.5, origin="julian", unit="D", utc=True | ||
) | ||
|
||
return sim_data | ||
|
||
|
||
DEFAULT_STACKERS = [maf.HourAngleStacker(), StartDateStacker()] | ||
|
||
|
||
def read_opsim( | ||
opsim_uri, | ||
start_time=None, | ||
end_time=None, | ||
constraint=None, | ||
dbcols=DEFAULT_VISITS_COLUMNS, | ||
stackers=DEFAULT_STACKERS, | ||
**kwargs, | ||
): | ||
"""Read visits from an opsim database. | ||
|
||
Parameters | ||
|
@@ -18,14 +104,36 @@ def read_opsim(opsim_uri, start_time="2000-01-01", end_time="2100-01-01"): | |
The start time for visits to be loaded | ||
end_time : `str`, `astropy.time.Time` | ||
The end time for visits ot be loaded | ||
constraint : `str`, None | ||
Query for which visits to load. | ||
dbcols : `list` [`str`] | ||
Columns required from the database. | ||
stackers : `list` [`rubin_sim.maf.stackers`], optional | ||
Stackers to be used to generate additional columns. | ||
|
||
Returns | ||
------- | ||
visits : `pandas.DataFrame` | ||
The visits and their parameters. | ||
""" | ||
start_mjd = Time(start_time).mjd | ||
end_mjd = Time(end_time).mjd | ||
|
||
# Add constraints corresponding to quested start and end times | ||
if (start_time is not None) or (end_time is not None): | ||
if constraint is None: | ||
constraint = "" | ||
|
||
if start_time is not None: | ||
if len(constraint) > 0: | ||
constraint += " AND " | ||
constraint += f"(observationStartMJD >= {Time(start_time).mjd})" | ||
|
||
if end_time is not None: | ||
if len(constraint) > 0: | ||
constraint += " AND " | ||
constraint += f"(observationStartMJD <= {Time(end_time).mjd})" | ||
|
||
if stackers is not None and len(stackers) > 0: | ||
kwargs["stackers"] = stackers | ||
|
||
original_resource_path = ResourcePath(opsim_uri) | ||
|
||
|
@@ -42,18 +150,53 @@ def read_opsim(opsim_uri, start_time="2000-01-01", end_time="2100-01-01"): | |
|
||
with obs_path.as_local() as local_obs_path: | ||
with sqlite3.connect(local_obs_path.ospath) as sim_connection: | ||
visits = pd.read_sql_query( | ||
f"SELECT * FROM observations WHERE observationStartMJD BETWEEN {start_mjd} AND {end_mjd}", | ||
sim_connection, | ||
index_col="observationId", | ||
) | ||
|
||
visits["start_date"] = pd.to_datetime( | ||
visits["observationStartMJD"] + 2400000.5, origin="julian", unit="D", utc=True | ||
) | ||
visits = pd.DataFrame(maf.get_sim_data(sim_connection, constraint, dbcols, **kwargs)) | ||
|
||
if "start_date" in visits: | ||
visits["start_date"] = pd.to_datetime(visits.start_date, unit="ns", utc=True) | ||
|
||
if "HA_hours" not in visits.columns: | ||
visits["HA_hours"] = (visits.observationStartLST - visits.fieldRA) * 24.0 / 360.0 | ||
visits["HA_hours"] = np.mod(visits["HA_hours"] + 12.0, 24) - 12 | ||
visits.set_index("observationId", inplace=True) | ||
|
||
return visits | ||
|
||
|
||
def read_ddf_visits( | ||
opsim_uri, | ||
start_time=None, | ||
end_time=None, | ||
dbcols=DEFAULT_VISITS_COLUMNS, | ||
stackers=DEFAULT_STACKERS, | ||
**kwargs, | ||
): | ||
"""Read DDF visits from an opsim database. | ||
|
||
Parameters | ||
---------- | ||
opsim_uri : `str` | ||
The uri from which to load visits | ||
start_time : `str`, `astropy.time.Time` | ||
The start time for visits to be loaded | ||
end_time : `str`, `astropy.time.Time` | ||
The end time for visits ot be loaded | ||
dbcols : `list` [`str`] | ||
Columns required from the database. | ||
stackers : `list` [`rubin_sim.maf.stackers`], optional | ||
Stackers to be used to generate additional columns. | ||
|
||
Returns | ||
------- | ||
visits : `pandas.DataFrame` | ||
The visits and their parameters. | ||
""" | ||
ddf_field_names = tuple(ddf_locations().keys()) | ||
constraint = f"target IN {tuple(field_name for field_name in ddf_field_names)}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "note" is the scheduler note on how a visit was acquired. For DDFs, this has been pretty consistently There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. But Target is also good to use. Bear in mind it may change, too. (Peter is considering adding a sequence number to the current content). |
||
visits = read_opsim( | ||
opsim_uri, | ||
start_time=start_time, | ||
end_time=end_time, | ||
constraint=constraint, | ||
dbcols=dbcols, | ||
stackers=stackers, | ||
**kwargs, | ||
) | ||
return visits |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drop fieldId and proposalId