diff --git a/src/adler/dataclasses/AdlerData.py b/src/adler/dataclasses/AdlerData.py index 38d6265..9d24d43 100644 --- a/src/adler/dataclasses/AdlerData.py +++ b/src/adler/dataclasses/AdlerData.py @@ -2,6 +2,17 @@ import numpy as np +FILTER_DEPENDENT_KEYS = ["phaseAngle_min", "phaseAngle_range", "nobs", "arc"] +MODEL_DEPENDENT_KEYS = [ + "H", + "H_err", + "phase_parameter_1", + "phase_parameter_1_err", + "phase_parameter_2", + "phase_parameter_2_err", +] + + @dataclass class AdlerData: """ @@ -9,217 +20,120 @@ class AdlerData: Attributes: ----------- - filter_list : list - List of filters under investigation. - - model_lists : list - List of lists of models per-filter. Length = len(filter_list) such that [[filter1_model1, filter1_model2], [filter2_model1]]. Used to index values - in the H_adler, phase_parameter_1, phase_parameter_1_err, phase_parameter_2 and phase_parameter_2_err list structures. - - phaseAngle_min_adler : array_like - Minimum phase angle of observations used in fitting model (degrees). Size = len(filter_list). - - phaseAngle_range_adler : array_like - Max minus min phase angle range of observations used in fitting model (degrees). Size = len(filter_list). + ssObjectId : str + ssObjectId of the object of interest. - nobs_adler : array_like - Number of observations used in fitting model. Size = len(filter_list). - - arc_adler : array_like - Observational arc used to fit model (days). Size = len(filter_list). - - H_adler : list - Absolute magnitude. List of lists arranged identically to model_lists, with per-filter and per-model values. - - H_err_adler : list - Error in absolute magnitude. List of lists arranged identically to model_lists, with per-filter and per-model values. - - phase_parameters : list - Phase parameters of the model in question. List of lists arranged as model_lists, with per-filter and per-model values: however, phase_parameters[filter_index][model_index] is itself a - list of either one or two values, depending on the number of phase parameters. + filter_list : list of str + List of filters under investigation. - phase_parameter_err : list - Error in the first phase parameter. List of lists arranged identically to phase_parameters. + filter_dependent_values : list of FilterDependentAdler objects, optional + List of FilterDependentAdler objects containing filter-dependent data in order of filter_list. Default empty list. """ + ssObjectId: str filter_list: list - model_lists: list = field(default_factory=list) - phaseAngle_min_adler: np.ndarray = field(default_factory=lambda: np.full(0, np.nan, dtype=float)) - phaseAngle_range_adler: np.ndarray = field(default_factory=lambda: np.full(0, np.nan, dtype=float)) - nobs_adler: np.ndarray = field(default_factory=lambda: np.zeros(0, dtype=int)) - arc_adler: np.ndarray = field(default_factory=lambda: np.full(0, np.nan, dtype=float)) - - # Note that these are lists and not arrays because appending to Numpy arrays (i.e. to add parameters for a different model) is not recommended. - # They can be cast to Numpy arrays later if needed. - H_adler: list = field(default_factory=list, init=False) - H_err_adler: list = field(default_factory=list, init=False) - phase_parameters: list = field(default_factory=list, init=False) - phase_parameters_err: list = field(default_factory=list, init=False) + filter_dependent_values: list = field(default_factory=list) def __post_init__(self): - """This runs post-initialisation and creates all of the class attributes where one dimension is "filters" to ensure the arrays - and lists have the correct size. This makes population a little easier. + """This runs post-initialisation and creates the class attribute where one dimension is "filters" to ensure the array + has the correct size. This makes population a little easier. """ - filter_length = len(self.filter_list) - - self.model_lists = [[] for a in range(0, filter_length)] - - self.phaseAngle_min_adler = np.full(filter_length, np.nan, dtype=float) - self.phaseAngle_range_adler = np.full(filter_length, np.nan, dtype=float) - self.nobs_adler = np.zeros(filter_length, dtype=int) - self.arc_adler = np.full(filter_length, np.nan, dtype=float) - - self.H_adler = [[] for a in range(0, filter_length)] - self.H_err_adler = [[] for a in range(0, filter_length)] - self.phase_parameters = [[] for a in range(0, filter_length)] - self.phase_parameters_err = [[] for a in range(0, filter_length)] - - def populate_phase_parameters( - self, - filter_name, - model_name=None, - phaseAngle_min=None, - phaseAngle_range=None, - nobs=None, - arc=None, - H=None, - H_err=None, - phase_parameters=[], - phase_parameters_err=[], - ): - """Convenience method to correctly populate phase curve arrays/lists. Only the supplied arguments to the method will - be updated, allowing for only some values to be populated if desired. + + # note that we don't do the same for model-dependent values as we don't know a priori how many models the user wishes + # to calculate, but we do know how many filters the AdlerPlanetoid object was generated with + self.filter_dependent_values = [FilterDependentAdler(filter_name) for filter_name in self.filter_list] + + def populate_phase_parameters(self, filter_name, **kwargs): + """Convenience method to correctly populate phase curve parameters for a given filter and (if desired) model. + Only the supplied arguments to the method will be updated, allowing for only some values to be populated if desired. Parameters ----------- filter_name : str The one-letter name of the filter in which the phase curve was calculated. - - model_name : str, optional - The name of the model used to calculate the phase curve. If not supplied, no model-dependent parameters will be updated. - - phaseAngle_min : float, optional - Minimum phase angle of observations used in fitting model (degrees) - - phaseAngle_range : float, optional - Max minus min phase angle range of observations used in fitting model (degrees). - - nobs : int, optional - Number of observations used in fitting model. - - arc : float, optional - Observational arc used to fit model (days). - - H : float, optional - Absolute magnitude in model. - - H_err : float, optional - Error on the absolute magnitude. - - phase_parameters : list, optional - Phase parameters of the model. - - phase_parameters_err : list, optional - Phase parameter errors. + **kwargs : FilterDependentAdler and PhaseModelDependentAdler attributes + The attribute names of the parameters you wish to update. See docs for FilterDependentAdler and PhaseModelDependentAdler + classes for definitions of each attribute. + Valid keyword arguments are: model_name, phaseAngle_min, phaseAngle_range, nobs, arc, H, H_err, phase_parameter_1, + phase_parameter_1_err, phase_parameter_2, phase_parameter_2_err. + Note that to update any of the model-dependent parameters (H, H_err, etc.), you WILL need to supply a model_name. """ - # Make sure the supplied filter is in the filter list. + # make sure the supplied filter is in the filter list try: filter_index = self.filter_list.index(filter_name) except ValueError: raise ValueError("Filter {} does not exist in AdlerData.filter_list.".format(filter_name)) - # If parameters and/or parameters_err are not lists, error out. - if not isinstance(phase_parameters, list) or not isinstance(phase_parameters_err, list): - raise TypeError("Both phase_parameters and phase_parameters_err arguments must be lists.") - - self.phaseAngle_min_adler[filter_index] = self.update_value( - self.phaseAngle_min_adler[filter_index], phaseAngle_min - ) - self.phaseAngle_range_adler[filter_index] = self.update_value( - self.phaseAngle_range_adler[filter_index], phaseAngle_range - ) - self.nobs_adler[filter_index] = self.update_value(self.nobs_adler[filter_index], nobs) - self.arc_adler[filter_index] = self.update_value(self.arc_adler[filter_index], arc) - - if model_name is None and ( - any(v is not None for v in [H, H_err]) - or len(phase_parameters) != 0 - or len(phase_parameters_err) != 0 - ): - raise Exception("No model name given. Cannot update model-specific phase_parameters.") - - elif model_name is None: - pass - - elif model_name not in self.model_lists[filter_index]: - self.model_lists[filter_index].append(model_name) - - self.H_adler[filter_index].append(H) - self.H_err_adler[filter_index].append(H_err) - self.phase_parameters[filter_index].append(phase_parameters) - self.phase_parameters_err[filter_index].append(phase_parameters_err) - - else: - model_index = self.model_lists[filter_index].index(model_name) - - self.H_adler[filter_index][model_index] = self.update_value( - self.H_adler[filter_index][model_index], H - ) - self.H_err_adler[filter_index][model_index] = self.update_value( - self.H_err_adler[filter_index][model_index], H_err + # if model-dependent parameters exist without a model name, return an error + if not kwargs.get("model_name") and any(name in kwargs for name in MODEL_DEPENDENT_KEYS): + raise NameError("No model name given. Cannot update model-specific phase parameters.") + + # update the value if it's in **kwargs + for filter_key in FILTER_DEPENDENT_KEYS: + if kwargs.get(filter_key): + setattr(self.filter_dependent_values[filter_index], filter_key, kwargs.get(filter_key)) + + # if no model_name is supplied, just end here + # else, if the model does not exist for this filter, create it + if not kwargs.get("model_name"): + return + elif kwargs.get("model_name") not in self.filter_dependent_values[filter_index].model_list: + self.filter_dependent_values[filter_index].model_list.append(kwargs.get("model_name")) + self.filter_dependent_values[filter_index].model_dependent_values.append( + PhaseModelDependentAdler(filter_name, kwargs.get("model_name")) ) - self.phase_parameters[filter_index][model_index] = self.update_value( - self.phase_parameters[filter_index][model_index], phase_parameters - ) - self.phase_parameters_err[filter_index][model_index] = self.update_value( - self.phase_parameters_err[filter_index][model_index], phase_parameters_err - ) - - def update_value(self, original_value, new_value): - """Returns one of two values depending on whether one of them is None. Used to update class attributes. - - Parameters - ----------- - original_value : any - Original value of the attribute. - - new_value : any or None - The value to replace it with, if this is not None. - - Returns - ----------- - any - Either original_value (if new_value is None) or new_value. + # then get the model index + model_index = self.filter_dependent_values[filter_index].model_list.index(kwargs.get("model_name")) - """ - if not new_value: - return original_value - else: - return new_value + # update the value if it's in **kwargs + for model_key in MODEL_DEPENDENT_KEYS: + if kwargs.get(model_key): + setattr( + self.filter_dependent_values[filter_index].model_dependent_values[model_index], + model_key, + kwargs.get(model_key), + ) def print_data(self): """Convenience method to clearly print the stored values.""" - print("Phase parameters (per filter):\n") for f, filter_name in enumerate(self.filter_list): print("Filter: {}".format(filter_name)) - print("Phase angle minimum: {}".format(self.phaseAngle_min_adler[f])) - print("Phase angle range: {}".format(self.phaseAngle_range_adler[f])) - print("Number of observations: {}".format(self.nobs_adler[f])) - print("Arc: {}".format(self.arc_adler[f])) + print("Phase angle minimum: {}".format(self.filter_dependent_values[f].phaseAngle_min)) + print("Phase angle range: {}".format(self.filter_dependent_values[f].phaseAngle_range)) + print("Number of observations: {}".format(self.filter_dependent_values[f].nobs)) + print("Arc: {}".format(self.filter_dependent_values[f].arc)) - for m, model_name in enumerate(self.model_lists[f]): + for m, model_name in enumerate(self.filter_dependent_values[f].model_list): print("Model: {}.".format(model_name)) - print("\tH: {}".format(self.H_adler[f][m])) - print("\tH error: {}".format(self.H_err_adler[f][m])) - print("\tPhase parameter(s): {}".format(self.phase_parameters[f][m])) - print("\tPhase parameter(s) error: {}".format(self.phase_parameters_err[f][m])) + print("\tH: {}".format(self.filter_dependent_values[f].model_dependent_values[m].H)) + print("\tH error: {}".format(self.filter_dependent_values[f].model_dependent_values[m].H_err)) + print( + "\tPhase parameter 1: {}".format( + self.filter_dependent_values[f].model_dependent_values[m].phase_parameter_1 + ) + ) + print( + "\tPhase parameter 1 error: {}".format( + self.filter_dependent_values[f].model_dependent_values[m].phase_parameter_1_err + ) + ) + print( + "\tPhase parameter 2: {}".format( + self.filter_dependent_values[f].model_dependent_values[m].phase_parameter_2 + ) + ) + print( + "\tPhase parameter 2 error: {}".format( + self.filter_dependent_values[f].model_dependent_values[m].phase_parameter_2_err + ) + ) print("\n") @@ -232,14 +146,14 @@ def get_phase_parameters_in_filter(self, filter_name, model_name=None): The filter of interest. model_name : str, optional - The model name of the model of interest. If this is not supplied, the code automatically returns the - parameters for the first model in the list. + The model name of the model of interest. If this is not supplied, the code will not return any model-dependent + parameters. Default None. Returns ----------- - parameters_dict : dict - Dictionary of the phase curve parameters for the specified filter and model. + output_obj : PhaseParameterOutput object + Object containing phase curve parameters for the specified filter and model. """ @@ -248,18 +162,18 @@ def get_phase_parameters_in_filter(self, filter_name, model_name=None): except ValueError: raise ValueError("Filter {} does not exist in AdlerData.filter_list.".format(filter_name)) - parameters_dict = { - "phaseAngle_min": self.phaseAngle_min_adler[filter_index], - "phaseAngle_range": self.phaseAngle_range_adler[filter_index], - "nobs": self.nobs_adler[filter_index], - "arc": self.arc_adler[filter_index], - } + output_obj = PhaseParameterOutput() + output_obj.filter_name = filter_name + output_obj.phaseAngle_min = self.filter_dependent_values[filter_index].phaseAngle_min + output_obj.phaseAngle_range = self.filter_dependent_values[filter_index].phaseAngle_range + output_obj.nobs = self.filter_dependent_values[filter_index].nobs + output_obj.arc = self.filter_dependent_values[filter_index].arc if not model_name: print("No model name specified. Returning non-model-dependent phase parameters.") else: try: - model_index = self.model_lists[filter_index].index(model_name) + model_index = self.filter_dependent_values[filter_index].model_list.index(model_name) except ValueError: raise ValueError( "Model {} does not exist for filter {} in AdlerData.model_lists.".format( @@ -267,9 +181,116 @@ def get_phase_parameters_in_filter(self, filter_name, model_name=None): ) ) - parameters_dict["H"] = self.H_adler[filter_index][model_index] - parameters_dict["H_err"] = self.H_err_adler[filter_index][model_index] - parameters_dict["phase_parameters"] = self.phase_parameters[filter_index][model_index] - parameters_dict["phase_parameters_err"] = self.phase_parameters_err[filter_index][model_index] + output_obj.model_name = model_name + output_obj.H = self.filter_dependent_values[filter_index].model_dependent_values[model_index].H + output_obj.H_err = ( + self.filter_dependent_values[filter_index].model_dependent_values[model_index].H_err + ) + output_obj.phase_parameter_1 = ( + self.filter_dependent_values[filter_index] + .model_dependent_values[model_index] + .phase_parameter_1 + ) + output_obj.phase_parameter_1_err = ( + self.filter_dependent_values[filter_index] + .model_dependent_values[model_index] + .phase_parameter_1_err + ) + output_obj.phase_parameter_2 = ( + self.filter_dependent_values[filter_index] + .model_dependent_values[model_index] + .phase_parameter_2 + ) + output_obj.phase_parameter_2_err = ( + self.filter_dependent_values[filter_index] + .model_dependent_values[model_index] + .phase_parameter_2_err + ) + + return output_obj + + +@dataclass +class FilterDependentAdler: + """Dataclass containing filter-dependent values generated by Adler. Note that NaN indicates a value that has not yet been populated. + + Attributes: + ----------- + filter_name : str + The filter for which these values are calculated. + + phaseAngle_min : float, optional + Minimum phase angle of observations used in fitting model (degrees). + + phaseAngle_range : float, optional + Max minus min phase angle range of observations used in fitting model (degrees). + + nobs : int, optional + Number of observations used in fitting model. + + arc: float, optional + Observational arc used to fit model (days). + + model_list: list of str, optional + List of the models for which phase curve parameters have been calculated. Default: empty list + + model_dependent_values: list of PhaseModelDependentAdler objects, optional + List of PhaseModelDependentAdler objects storing phase-model parameters for each model, given in order of model_list. Default: empty list. + + """ + + filter_name: str + phaseAngle_min: float = np.nan + phaseAngle_range: float = np.nan + nobs: int = 0 + arc: float = np.nan + model_list: list = field(default_factory=list) + model_dependent_values: list = field(default_factory=list) + + +@dataclass +class PhaseModelDependentAdler: + """Dataclass containing phase-model-dependent values generated by Adler. Note that NaN indicates a value that has not yet been populated. + + Attributes: + ----------- + filter_name : str + The filter for which these values are calculated. + + model_name : str + The phase model for which these values were calculated. Example: "HG", "HG1G2", "linear". + + H : float, optional + The absolute magnitude. Default NaN. + + H_err : float, optional + Error in absolute magnitude. Default NaN. + + phase_parameter_1 : float, optional + The first parameter of the phase model. May be the only parameter. For example, G in the HG model. Default NaN. + + phase_parameter_1_err : float, optional + The error on the first parameter of the phase model. Default NaN. + + phase_parameter_2 : float, optional + The second parameter of the phase model. May not exist for this model. Default NaN. + + phase_parameter_2_err : float, optional + The error on the second parameter of the phase model. Default NaN. + + """ + + filter_name: str + model_name: str + H: float = np.nan + H_err: float = np.nan + phase_parameter_1: float = np.nan + phase_parameter_1_err: float = np.nan + phase_parameter_2: float = np.nan + phase_parameter_2_err: float = np.nan + + +class PhaseParameterOutput: + """Empty convenience class so that the output of AdlerData.get_phase_parameters_in_filter is an object.""" - return parameters_dict + pass diff --git a/src/adler/dataclasses/AdlerPlanetoid.py b/src/adler/dataclasses/AdlerPlanetoid.py index 3002ac2..8b03781 100644 --- a/src/adler/dataclasses/AdlerPlanetoid.py +++ b/src/adler/dataclasses/AdlerPlanetoid.py @@ -91,7 +91,7 @@ def construct_from_SQL( cls, ssObjectId, filter_list, sql_filename=sql_filename, schema=schema ) - adler_data = AdlerData(filter_list) + adler_data = AdlerData(ssObjectId, filter_list) return cls(ssObjectId, filter_list, date_range, observations_by_filter, mpcorb, ssobject, adler_data) @@ -125,7 +125,7 @@ def construct_from_RSP( mpcorb = cls.populate_MPCORB(cls, ssObjectId, service=service) ssobject = cls.populate_SSObject(cls, ssObjectId, filter_list, service=service) - adler_data = AdlerData(filter_list) + adler_data = AdlerData(ssObjectId, filter_list) return cls(ssObjectId, filter_list, date_range, observations_by_filter, mpcorb, ssobject, adler_data) diff --git a/tests/adler/dataclasses/test_AdlerData.py b/tests/adler/dataclasses/test_AdlerData.py index 066a889..1363746 100644 --- a/tests/adler/dataclasses/test_AdlerData.py +++ b/tests/adler/dataclasses/test_AdlerData.py @@ -1,102 +1,204 @@ from numpy.testing import assert_array_equal import pytest +import numpy as np from adler.dataclasses.AdlerData import AdlerData # setting up the AdlerData object to be used for testing -test_object = AdlerData(["u", "g", "r"]) - -test_object.populate_phase_parameters("u", "model_1", 11.0, 12.0, 13, 14.0, 15.0, 16.0, [17.0], [18.0]) -test_object.populate_phase_parameters( - "u", - model_name="model_2", - H=25.0, - H_err=26.0, - phase_parameters=[27.0, 27.5], - phase_parameters_err=[28.0, 28.5], -) -test_object.populate_phase_parameters("g", "model_1", 31.0, 32.0, 33, 34.0, 35.0, 36.0, [37.0], [38.0]) -test_object.populate_phase_parameters( - "r", "model_2", 41.0, 42.0, 43, 44.0, 45.0, 46.0, [47.0, 47.5], [48.0, 48.5] -) +test_object = AdlerData(666, ["u", "g", "r"]) + +u_model_1 = { + "model_name": "model_1", + "phaseAngle_min": 11.0, + "phaseAngle_range": 12.0, + "nobs": 13, + "arc": 14.0, + "H": 15.0, + "H_err": 16.0, + "phase_parameter_1": 17.0, + "phase_parameter_1_err": 18.0, +} + +u_model_2 = { + "model_name": "model_2", + "H": 25.0, + "H_err": 26.0, + "phase_parameter_1": 27.0, + "phase_parameter_1_err": 28.0, + "phase_parameter_2": 29.0, + "phase_parameter_2_err": 30.0, +} + +g_model_1 = { + "model_name": "model_1", + "phaseAngle_min": 31.0, + "phaseAngle_range": 32.0, + "nobs": 33, + "arc": 34.0, + "H": 35.0, + "H_err": 36.0, + "phase_parameter_1": 37.0, + "phase_parameter_1_err": 38.0, +} + +r_model_2 = { + "model_name": "model_2", + "phaseAngle_min": 41.0, + "phaseAngle_range": 42.0, + "nobs": 43, + "arc": 44.0, + "H": 45.0, + "H_err": 46.0, + "phase_parameter_1": 47.0, + "phase_parameter_1_err": 48.0, + "phase_parameter_2": 49.0, + "phase_parameter_2_err": 50.0, +} + +test_object.populate_phase_parameters("u", **u_model_1) +test_object.populate_phase_parameters("u", **u_model_2) +test_object.populate_phase_parameters("g", **g_model_1) +test_object.populate_phase_parameters("r", **r_model_2) def test_populate_phase_parameters(): # test to make sure the object is correctly populated assert test_object.filter_list == ["u", "g", "r"] - assert test_object.model_lists == [["model_1", "model_2"], ["model_1"], ["model_2"]] - assert_array_equal(test_object.phaseAngle_min_adler, [11.0, 31.0, 41.0]) - assert_array_equal(test_object.phaseAngle_range_adler, [12.0, 32.0, 42.0]) - assert_array_equal(test_object.nobs_adler, [13, 33, 43]) - assert_array_equal(test_object.arc_adler, [14.0, 34.0, 44.0]) + assert test_object.filter_dependent_values[0].model_list == ["model_1", "model_2"] + assert test_object.filter_dependent_values[1].model_list == ["model_1"] + assert test_object.filter_dependent_values[2].model_list == ["model_2"] + + assert_array_equal([a.phaseAngle_min for a in test_object.filter_dependent_values], [11.0, 31.0, 41.0]) + assert_array_equal([a.phaseAngle_range for a in test_object.filter_dependent_values], [12.0, 32.0, 42.0]) + assert_array_equal([a.nobs for a in test_object.filter_dependent_values], [13, 33, 43]) + assert_array_equal([a.arc for a in test_object.filter_dependent_values], [14.0, 34.0, 44.0]) + + assert test_object.filter_dependent_values[0].model_dependent_values[0].__dict__ == { + "filter_name": "u", + "model_name": "model_1", + "H": 15.0, + "H_err": 16.0, + "phase_parameter_1": 17.0, + "phase_parameter_1_err": 18.0, + "phase_parameter_2": np.nan, + "phase_parameter_2_err": np.nan, + } + + assert test_object.filter_dependent_values[0].model_dependent_values[1].__dict__ == { + "filter_name": "u", + "model_name": "model_2", + "H": 25.0, + "H_err": 26.0, + "phase_parameter_1": 27.0, + "phase_parameter_1_err": 28.0, + "phase_parameter_2": 29.0, + "phase_parameter_2_err": 30.0, + } - assert test_object.H_adler == [[15.0, 25.0], [35.0], [45.0]] - assert test_object.H_err_adler == [[16.0, 26.0], [36.0], [46.0]] - assert test_object.phase_parameters == [[[17.0], [27.0, 27.5]], [[37.0]], [[47.0, 47.5]]] - assert test_object.phase_parameters_err == [[[18.0], [28.0, 28.5]], [[38.0]], [[48.0, 48.5]]] + assert test_object.filter_dependent_values[1].model_dependent_values[0].__dict__ == { + "filter_name": "g", + "model_name": "model_1", + "H": 35.0, + "H_err": 36.0, + "phase_parameter_1": 37.0, + "phase_parameter_1_err": 38.0, + "phase_parameter_2": np.nan, + "phase_parameter_2_err": np.nan, + } + + assert test_object.filter_dependent_values[2].model_dependent_values[0].__dict__ == { + "filter_name": "r", + "model_name": "model_2", + "H": 45.0, + "H_err": 46.0, + "phase_parameter_1": 47.0, + "phase_parameter_1_err": 48.0, + "phase_parameter_2": 49.0, + "phase_parameter_2_err": 50.0, + } # check to make sure model-dependent parameter is correctly updated (then return it to previous) - test_object.populate_phase_parameters("u", "model_1", H=99.0) - assert test_object.H_adler[0][0] == 99.0 - test_object.populate_phase_parameters("u", "model_1", H=15.0) + test_object.populate_phase_parameters("u", model_name="model_1", H=99.0) + assert test_object.filter_dependent_values[0].model_dependent_values[0].H == 99.0 + test_object.populate_phase_parameters("u", model_name="model_1", H=15.0) # check to make sure filter-dependent parameter is correctly updated (then return it to previous) - test_object.populate_phase_parameters("u", nobs=99) - assert test_object.nobs_adler[0] == 99 - test_object.populate_phase_parameters("u", nobs=13) # testing to make sure the correct error messages trigger - with pytest.raises(TypeError) as error_info_1: - test_object.populate_phase_parameters("u", "model_1", 11.0, 12.0, 13, 14.0, 15.0, 16.0, 17.0, 18.0) - - assert ( - error_info_1.value.args[0] - == "Both phase_parameters and phase_parameters_err arguments must be lists." - ) - - with pytest.raises(ValueError) as error_info_2: - test_object.populate_phase_parameters("y", "model_1", 11.0, 12.0, 13, 14.0, 15.0, 16.0, 17.0, 18.0) + with pytest.raises(ValueError) as error_info_1: + test_object.populate_phase_parameters("y") - assert error_info_2.value.args[0] == "Filter y does not exist in AdlerData.filter_list." + assert error_info_1.value.args[0] == "Filter y does not exist in AdlerData.filter_list." - with pytest.raises(Exception) as error_info_3: + with pytest.raises(NameError) as error_info_2: test_object.populate_phase_parameters("u", H=4.0) - assert error_info_3.value.args[0] == "No model name given. Cannot update model-specific phase_parameters." + assert error_info_2.value.args[0] == "No model name given. Cannot update model-specific phase parameters." def test_get_phase_parameters_in_filter(): - u_model2 = { + assert test_object.get_phase_parameters_in_filter("u", "model_1").__dict__ == { + "filter_name": "u", "phaseAngle_min": 11.0, "phaseAngle_range": 12.0, "nobs": 13, "arc": 14.0, - "H": 25.0, - "H_err": 26.0, - "phase_parameters": [27.0, 27.5], - "phase_parameters_err": [28.0, 28.5], + "model_name": "model_1", + "H": 15.0, + "H_err": 16.0, + "phase_parameter_1": 17.0, + "phase_parameter_1_err": 18.0, + "phase_parameter_2": np.nan, + "phase_parameter_2_err": np.nan, } - u_model1 = { + assert test_object.get_phase_parameters_in_filter("u", "model_2").__dict__ == { + "filter_name": "u", "phaseAngle_min": 11.0, "phaseAngle_range": 12.0, "nobs": 13, "arc": 14.0, - "H": 15.0, - "H_err": 16.0, - "phase_parameters": [17.0], - "phase_parameters_err": [18.0], + "model_name": "model_2", + "H": 25.0, + "H_err": 26.0, + "phase_parameter_1": 27.0, + "phase_parameter_1_err": 28.0, + "phase_parameter_2": 29.0, + "phase_parameter_2_err": 30.0, } - u_independent = {"phaseAngle_min": 11.0, "phaseAngle_range": 12.0, "nobs": 13, "arc": 14.0} + assert test_object.get_phase_parameters_in_filter("g", "model_1").__dict__ == { + "filter_name": "g", + "phaseAngle_min": 31.0, + "phaseAngle_range": 32.0, + "nobs": 33, + "arc": 34.0, + "model_name": "model_1", + "H": 35.0, + "H_err": 36.0, + "phase_parameter_1": 37.0, + "phase_parameter_1_err": 38.0, + "phase_parameter_2": np.nan, + "phase_parameter_2_err": np.nan, + } - # making sure the correct parameters are retreived - assert test_object.get_phase_parameters_in_filter("u", model_name="model_2") == u_model2 - assert test_object.get_phase_parameters_in_filter("u", model_name="model_1") == u_model1 - assert test_object.get_phase_parameters_in_filter("u") == u_independent + assert test_object.get_phase_parameters_in_filter("r", "model_2").__dict__ == { + "filter_name": "r", + "phaseAngle_min": 41.0, + "phaseAngle_range": 42.0, + "nobs": 43, + "arc": 44.0, + "model_name": "model_2", + "H": 45.0, + "H_err": 46.0, + "phase_parameter_1": 47.0, + "phase_parameter_1_err": 48.0, + "phase_parameter_2": 49.0, + "phase_parameter_2_err": 50.0, + } # checking the error messages with pytest.raises(ValueError) as error_info_1: @@ -117,6 +219,6 @@ def test_print_data(capsys): # get what was printed to the terminal captured = capsys.readouterr() - expected = "Phase parameters (per filter):\n\nFilter: u\nPhase angle minimum: 11.0\nPhase angle range: 12.0\nNumber of observations: 13\nArc: 14.0\nModel: model_1.\n\tH: 15.0\n\tH error: 16.0\n\tPhase parameter(s): [17.0]\n\tPhase parameter(s) error: [18.0]\nModel: model_2.\n\tH: 25.0\n\tH error: 26.0\n\tPhase parameter(s): [27.0, 27.5]\n\tPhase parameter(s) error: [28.0, 28.5]\n\n\nFilter: g\nPhase angle minimum: 31.0\nPhase angle range: 32.0\nNumber of observations: 33\nArc: 34.0\nModel: model_1.\n\tH: 35.0\n\tH error: 36.0\n\tPhase parameter(s): [37.0]\n\tPhase parameter(s) error: [38.0]\n\n\nFilter: r\nPhase angle minimum: 41.0\nPhase angle range: 42.0\nNumber of observations: 43\nArc: 44.0\nModel: model_2.\n\tH: 45.0\n\tH error: 46.0\n\tPhase parameter(s): [47.0, 47.5]\n\tPhase parameter(s) error: [48.0, 48.5]\n\n\n" + expected = "Filter: u\nPhase angle minimum: 11.0\nPhase angle range: 12.0\nNumber of observations: 13\nArc: 14.0\nModel: model_1.\n\tH: 15.0\n\tH error: 16.0\n\tPhase parameter 1: 17.0\n\tPhase parameter 1 error: 18.0\n\tPhase parameter 2: nan\n\tPhase parameter 2 error: nan\nModel: model_2.\n\tH: 25.0\n\tH error: 26.0\n\tPhase parameter 1: 27.0\n\tPhase parameter 1 error: 28.0\n\tPhase parameter 2: 29.0\n\tPhase parameter 2 error: 30.0\n\n\nFilter: g\nPhase angle minimum: 31.0\nPhase angle range: 32.0\nNumber of observations: 33\nArc: 34.0\nModel: model_1.\n\tH: 35.0\n\tH error: 36.0\n\tPhase parameter 1: 37.0\n\tPhase parameter 1 error: 38.0\n\tPhase parameter 2: nan\n\tPhase parameter 2 error: nan\n\n\nFilter: r\nPhase angle minimum: 41.0\nPhase angle range: 42.0\nNumber of observations: 43\nArc: 44.0\nModel: model_2.\n\tH: 45.0\n\tH error: 46.0\n\tPhase parameter 1: 47.0\n\tPhase parameter 1 error: 48.0\n\tPhase parameter 2: 49.0\n\tPhase parameter 2 error: 50.0\n\n\n" assert captured.out == expected