Skip to content

Commit

Permalink
Adding functionality to supply list of SSOIDs to CLI.
Browse files Browse the repository at this point in the history
  • Loading branch information
astronomerritt committed May 14, 2024
1 parent 3ecce45 commit 3752376
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 61 deletions.
79 changes: 49 additions & 30 deletions src/adler/adler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,74 +6,93 @@
from adler.science.PhaseCurve import PhaseCurve
from adler.utilities.AdlerCLIArguments import AdlerCLIArguments
from adler.utilities.adler_logging import setup_adler_logging
from adler.utilities.readin_utilities import read_in_SSObjectID_file

logger = logging.getLogger(__name__)


def runAdler(cli_args):

logger.info("Beginning Adler.")
logger.info("Ingesting all data for object {} from RSP...".format(cli_args.ssObjectId))

planetoid = AdlerPlanetoid.construct_from_RSP(
cli_args.ssObjectId, cli_args.filter_list, cli_args.date_range
)
if cli_args.ssObjectId_list:
ssObjectId_list = read_in_SSObjectID_file(cli_args.ssObjectId_list)
else:
ssObjectId_list = [cli_args.ssObjectId]

logger.info("Data successfully ingested.")
logger.info("Calculating phase curves...")
for i, ssObjectId in enumerate(ssObjectId_list):
logger.info("Processing object {}/{}.".format(i + 1, len(ssObjectId_list)))
logger.info("Ingesting all data for object {} from RSP...".format(cli_args.ssObjectId))

# now let's do some phase curves!
planetoid = AdlerPlanetoid.construct_from_RSP(ssObjectId, cli_args.filter_list, cli_args.date_range)

# get the r filter SSObject metadata
sso_r = planetoid.SSObject_in_filter("r")
logger.info("Data successfully ingested.")
logger.info("Calculating phase curves...")

# get the RSP r filter model
pc = PhaseCurve(
abs_mag=sso_r.H * u.mag,
phase_param=sso_r.G12,
model_name="HG12_Pen16",
)
print(pc)
print(pc.abs_mag, pc.phase_param)
# now let's do some phase curves!

# get the r filter SSObject metadata
sso_r = planetoid.SSObject_in_filter("r")

# get the r filter observations
obs_r = planetoid.observations_in_filter("r")
alpha = obs_r.phaseAngle * u.deg
red_mag = obs_r.reduced_mag * u.mag
mag_err = obs_r.magErr * u.mag
# get the RSP r filter model
pc = PhaseCurve(
abs_mag=sso_r.H * u.mag,
phase_param=sso_r.G12,
model_name="HG12_Pen16",
)
print(pc)
print(pc.abs_mag, pc.phase_param)

# do a simple fit to all data
pc_fit = pc.FitModel(alpha, red_mag, mag_err)
print(pc_fit)
# get the r filter observations
obs_r = planetoid.observations_in_filter("r")
alpha = obs_r.phaseAngle * u.deg
red_mag = obs_r.reduced_mag * u.mag
mag_err = obs_r.magErr * u.mag

# do a simple fit to all data
pc_fit = pc.FitModel(alpha, red_mag, mag_err)
print(pc_fit)


def main():
parser = argparse.ArgumentParser(description="Runs Adler for select planetoid(s) and given user input.")

parser.add_argument("-s", "--ssObjectId", help="SSObject ID of planetoid.", type=str, required=True)
parser.add_argument(
# the below group ensures that AT LEAST one of the below arguments is included, but NOT both
input_group = parser.add_mutually_exclusive_group(required=True)
input_group.add_argument("-s", "--ssObjectId", help="SSObject ID of planetoid.", type=str, default=None)
input_group.add_argument(
"-sl",
"--ssObjectId_list",
help="Filepath to text file listing multiple SSObjectIds.",
type=str,
default=None,
)

optional_group = parser.add_argument_group("Optional arguments")
optional_group.add_argument(
"-f",
"--filter_list",
help="Filters required.",
nargs="*",
type=str,
default=["u", "g", "r", "i", "z", "y"],
)
parser.add_argument(
optional_group.add_argument(
"-d",
"--date_range",
help="Minimum and maximum MJD(TAI) of required observations. Default is to pull all observations.",
nargs=2,
type=float,
default=[60000.0, 67300.0],
)
parser.add_argument(
optional_group.add_argument(
"-o",
"--outpath",
help="Output path location. Default is current working directory.",
type=str,
default="./",
)
parser.add_argument(
optional_group.add_argument(
"-n",
"--db_name",
help="Stem filename of output database. If this doesn't exist, it will be created. Default: adler_out.",
Expand Down
5 changes: 0 additions & 5 deletions src/adler/dataclasses/AdlerPlanetoid.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,6 @@ def populate_observations(
filter_name
)
)
print(
"WARNING: No observations found in {} filter for this object. Skipping this filter.".format(
filter_name
)
)
else:
observations_by_filter.append(
Observations.construct_from_data_table(ssObjectId, filter_name, data_table)
Expand Down
5 changes: 0 additions & 5 deletions src/adler/dataclasses/dataclass_utilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,6 @@ def check_value_populated(data_val, data_type, column_name, table_name):
logger.warning(
"{} unpopulated in {} table for this object. Storing NaN instead.".format(column_name, table_name)
)
print(
"WARNING: {} unpopulated in {} table for this object. Storing NaN instead.".format(
column_name, table_name
)
)
data_val = np.nan

return data_val
34 changes: 33 additions & 1 deletion src/adler/utilities/AdlerCLIArguments.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import os
import logging

logger = logging.getLogger(__name__)


class AdlerCLIArguments:
Expand All @@ -14,6 +17,7 @@ class AdlerCLIArguments:

def __init__(self, args):
self.ssObjectId = args.ssObjectId
self.ssObjectId_list = args.ssObjectId_list
self.filter_list = args.filter_list
self.date_range = args.date_range
self.outpath = args.outpath
Expand All @@ -23,14 +27,22 @@ def __init__(self, args):

def validate_arguments(self):
self._validate_filter_list()
self._validate_ssObjectId()
self._validate_date_range()
self._validate_outpath()

if self.ssObjectId:
self._validate_ssObjectId()

if self.ssObjectId_list:
self._validate_ssObjectId_list()

def _validate_filter_list(self):
expected_filters = ["u", "g", "r", "i", "z", "y"]

if not set(self.filter_list).issubset(expected_filters):
logging.error(
"Unexpected filters found in --filter_list command-line argument. --filter_list must be a list of LSST filters."
)
raise ValueError(
"Unexpected filters found in --filter_list command-line argument. --filter_list must be a list of LSST filters."
)
Expand All @@ -39,18 +51,25 @@ def _validate_ssObjectId(self):
try:
int(self.ssObjectId)
except ValueError:
logging.error("--ssObjectId command-line argument does not appear to be a valid ssObjectId.")
raise ValueError("--ssObjectId command-line argument does not appear to be a valid ssObjectId.")

def _validate_date_range(self):
for d in self.date_range:
try:
float(d)
except ValueError:
logging.error(
"One or both of the values for the --date_range command-line argument do not seem to be valid numbers."
)
raise ValueError(
"One or both of the values for the --date_range command-line argument do not seem to be valid numbers."
)

if any(d > 250000 for d in self.date_range):
logging.error(
"Dates for --date_range command-line argument seem rather large. Did you input JD instead of MJD?"
)
raise ValueError(
"Dates for --date_range command-line argument seem rather large. Did you input JD instead of MJD?"
)
Expand All @@ -60,4 +79,17 @@ def _validate_outpath(self):
self.outpath = os.path.abspath(self.outpath)

if not os.path.isdir(self.outpath):
logging.error("The output path for the command-line argument --outpath cannot be found.")
raise ValueError("The output path for the command-line argument --outpath cannot be found.")

def _validate_ssObjectId_list(self):

self.ssObjectId_list = os.path.abspath(self.ssObjectId_list)

if not os.path.exists(self.ssObjectId_list):
logging.error(
"The file supplied for the command-line argument --ssObjectId_list cannot be found."
)
raise ValueError(
"The file supplied for the command-line argument --ssObjectId_list cannot be found."
)
21 changes: 21 additions & 0 deletions src/adler/utilities/readin_utilities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import logging

logger = logging.getLogger(__name__)


def read_in_SSObjectID_file(readin_path):

with open(readin_path) as f:
ssoid_list = f.read().splitlines()

# bit of validation here: we expect these to cast nicely to ints
for ssoid in ssoid_list:
try:
int(ssoid)
except ValueError:
logger.error(
"ValueError: One or more of the SSObjectIDs in the supplied list does not seem to be valid."
)
raise ValueError("One or more of the SSObjectIDs in the supplied list does not seem to be valid.")

return ssoid_list
13 changes: 0 additions & 13 deletions tests/adler/dataclasses/test_AdlerPlanetoid.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,19 +137,6 @@ def test_no_observations():
)


def test_for_warnings(capsys):
test_planetoid = AdlerPlanetoid.construct_from_SQL(ssoid, test_db_path, filter_list=["u", "g"])
captured = capsys.readouterr()

expected = (
"WARNING: No observations found in u filter for this object. Skipping this filter.\n"
+ "WARNING: n unpopulated in MPCORB table for this object. Storing NaN instead.\n"
+ "WARNING: uncertaintyParameter unpopulated in MPCORB table for this object. Storing NaN instead.\n"
)

assert captured.out == expected


def test_failed_SQL_queries():
test_planetoid = AdlerPlanetoid.construct_from_SQL(
ssoid, test_db_path, filter_list=["u", "g", "r", "i", "z", "y"]
Expand Down
44 changes: 37 additions & 7 deletions tests/adler/utilities/test_AdlerCLIArguments.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import os
import pytest
from adler.utilities.AdlerCLIArguments import AdlerCLIArguments
from adler.utilities.tests_utilities import get_test_data_filepath


# AdlerCLIArguments object takes an object as input, so we define a quick one here
class args:
def __init__(self, ssObjectId, filter_list, date_range, outpath, db_name):
def __init__(self, ssObjectId, ssObjectId_list, filter_list, date_range, outpath, db_name):
self.ssObjectId = ssObjectId
self.ssObjectId_list = ssObjectId_list
self.filter_list = filter_list
self.date_range = date_range
self.outpath = outpath
Expand All @@ -17,6 +19,7 @@ def test_AdlerCLIArguments_population():
# test correct population
good_input_dict = {
"ssObjectId": "666",
"ssObjectId_list": None,
"filter_list": ["g", "r", "i"],
"date_range": [60000.0, 67300.0],
"outpath": "./",
Expand All @@ -29,10 +32,17 @@ def test_AdlerCLIArguments_population():

assert good_arguments_object.__dict__ == good_input_dict

# and double-check that ssObjectID_list works too

good_input_dict["ssObjectId_list"] = get_test_data_filepath("test_SSOIDs.txt")
good_arguments = args(**good_input_dict)
good_arguments_object = AdlerCLIArguments(good_arguments)
assert good_arguments_object.ssObjectId_list == get_test_data_filepath("test_SSOIDs.txt")


def test_AdlerCLIArguments_badSSOID():
# test that a bad ssObjectId triggers the right error
bad_ssoid_arguments = args("hello!", ["g", "r", "i"], [60000.0, 67300.0], "./", "output")
bad_ssoid_arguments = args("hello!", None, ["g", "r", "i"], [60000.0, 67300.0], "./", "output")

with pytest.raises(ValueError) as bad_ssoid_error:
bad_ssoid_object = AdlerCLIArguments(bad_ssoid_arguments)
Expand All @@ -45,7 +55,7 @@ def test_AdlerCLIArguments_badSSOID():

def test_AdlerCLIArguments_badfilters():
# test that non-LSST or unexpected filters trigger the right error
bad_filter_arguments = args("666", ["g", "r", "i", "m"], [60000.0, 67300.0], "./", "output")
bad_filter_arguments = args("666", None, ["g", "r", "i", "m"], [60000.0, 67300.0], "./", "output")

with pytest.raises(ValueError) as bad_filter_error:
bad_filter_object = AdlerCLIArguments(bad_filter_arguments)
Expand All @@ -55,7 +65,7 @@ def test_AdlerCLIArguments_badfilters():
== "Unexpected filters found in --filter_list command-line argument. --filter_list must be a list of LSST filters."
)

bad_filter_arguments_2 = args("666", ["pony"], [60000.0, 67300.0], "./", "output")
bad_filter_arguments_2 = args("666", None, ["pony"], [60000.0, 67300.0], "./", "output")

with pytest.raises(ValueError) as bad_filter_error_2:
bad_filter_object = AdlerCLIArguments(bad_filter_arguments_2)
Expand All @@ -68,7 +78,7 @@ def test_AdlerCLIArguments_badfilters():

def test_AdlerCLIArguments_baddates():
# test that overly-large dates trigger the right error
big_date_arguments = args("666", ["g", "r", "i"], [260000.0, 267300.0], "./", "output")
big_date_arguments = args("666", None, ["g", "r", "i"], [260000.0, 267300.0], "./", "output")

with pytest.raises(ValueError) as big_date_error:
big_date_object = AdlerCLIArguments(big_date_arguments)
Expand All @@ -79,7 +89,7 @@ def test_AdlerCLIArguments_baddates():
)

# test that unexpected date values trigger the right error
bad_date_arguments = args("666", ["g", "r", "i"], [60000.0, "cheese"], "./", "output")
bad_date_arguments = args("666", None, ["g", "r", "i"], [60000.0, "cheese"], "./", "output")

with pytest.raises(ValueError) as bad_date_error:
bad_date_object = AdlerCLIArguments(bad_date_arguments)
Expand All @@ -92,7 +102,7 @@ def test_AdlerCLIArguments_baddates():

def test_AdlerCLIArguments_badoutput():
bad_output_arguments = args(
"666", ["g", "r", "i"], [60000.0, 67300.0], "./definitely_fake_folder/", "output"
"666", None, ["g", "r", "i"], [60000.0, 67300.0], "./definitely_fake_folder/", "output"
)

with pytest.raises(ValueError) as bad_output_error:
Expand All @@ -102,3 +112,23 @@ def test_AdlerCLIArguments_badoutput():
bad_output_error.value.args[0]
== "The output path for the command-line argument --outpath cannot be found."
)


def test_AdlerCLIArguments_badlist():

bad_list_arguments = args(
None,
"./fake_input/here.txt",
["g", "r", "i"],
[60000.0, 67300.0],
"./definitely_fake_folder/",
"output",
)

with pytest.raises(ValueError) as bad_list_error:
bad_list_object = AdlerCLIArguments(bad_list_arguments)

assert (
bad_list_error.value.args[0]
== "The output path for the command-line argument --outpath cannot be found."
)
Loading

0 comments on commit 3752376

Please sign in to comment.