From 6887f0fa2978f16c680f0faabf472e5eeea8b9b6 Mon Sep 17 00:00:00 2001 From: WGolay Date: Tue, 8 Oct 2024 12:26:11 -0400 Subject: [PATCH] Boundary conditions docs updates --- pyscope/telrun/airmass_condition.py | 136 ++++++++++----------------- pyscope/telrun/boundary_condition.py | 11 ++- pyscope/telrun/coord_condition.py | 77 ++++++++------- 3 files changed, 98 insertions(+), 126 deletions(-) diff --git a/pyscope/telrun/airmass_condition.py b/pyscope/telrun/airmass_condition.py index 77067361..c0b7e53f 100644 --- a/pyscope/telrun/airmass_condition.py +++ b/pyscope/telrun/airmass_condition.py @@ -6,16 +6,16 @@ class AirmassCondition(BoundaryCondition): - def __init__(self, airmass_limit=3, formula="secant", weight=1): + def __init__(self, airmass_limit=3, formula="Schoenberg1929", weight=1, **kwargs): """ A condition that penalizes targets for higher airmass values up to a limit. This condition is used to restrict the airmass value of a target to a maximum value. The airmass - can be calculated using several different formulae. The default is a simple secant formula, + can be calculated using several different formulae. The most simple is a secant formula, given by :math:`X = \\frac{1}{\\cos(z)}` where :math:`z` is the angle between the target and the zenith. This is the analytic solution for a plane-parallel atmosphere. - Other options include Schoenberg 1929[1]_, which is a geometric model for a non-refracting spherical atmosphere: + The default option is Schoenberg 1929[1]_, a geometric model for a non-refracting spherical atmosphere: .. math:: X = \\frac{R_{\\oplus}}{y_{\\rm atm}}\\sqrt{\\cos^2(z) + 2\\frac{y_{\\rm atm}}{R_{\\oplus}} + \\left(\\frac{y_{\\rm atm}}{R_{\\oplus}}\\right)^2} - \\frac{R_{\\oplus}}{y_{\\rm atm}}\\cos(z) @@ -43,7 +43,7 @@ def __init__(self, airmass_limit=3, formula="secant", weight=1): .. image:: https://upload.wikimedia.org/wikipedia/commons/d/d3/Viewing_angle_and_air_masses.svg - The airmass is penalized linearly from `1` with the best linear quality score and decreases to `0` at the `airmass_limit`. + The airmass is penalized linearly from `1` with the best linear quality score and decreases to `0` at the `airmass_limit` and beyond. Parameters ---------- @@ -56,6 +56,9 @@ def __init__(self, airmass_limit=3, formula="secant", weight=1): weight : float, default : 1 The weight of the condition in the final score. The default is 1. + **kwargs : dict, default : {} + Additional keyword arguments to pass to the `~pyscope.telrun.BoundaryCondition` constructor for storage in the `~pyscope.telrun.BoundaryCondition.kwargs` attribute. + References ---------- .. [1] `Schoenberg, E. 1929. Theoretische Photometrie, Über die Extinktion des Lichtes in der Erdatmosphäre. In Handbuch der Astrophysik. Band II, erste Hälfte. Berlin: Springer. `_ @@ -74,75 +77,82 @@ def __init__(self, airmass_limit=3, formula="secant", weight=1): """ logger.debug("AirmassCondition(airmass_limit=%s, formula=%s, weight=%s)") - super().__init__( - func=self.calculate, - lqs_func=self.score, - weight=weight, - airmass_limit=airmass_limit, - formula=formula, - ) - self.airmass_limit = airmass_limit - self.formula = formula + super().__init__(func=self._func, lqs_func=self._lqs_func, **kwargs) @classmethod - def from_string(self, string): - logger.debug("AirmassCondition.from_string(string=%s)" % string) - pass + def from_string(self, string, airmass_limit=None, formula=None, weight=None): + """ + Create a `~pyscope.telrun.AirmassCondition` or a `list` of `~pyscope.telrun.AirmassCondition` objects from a `str` representation of a `~pyscope.telrun.AirmassCondition`. + Any optional parameters are used to override the parameters extracted from the `str` representation. + + Parameters + ---------- + string : `str`, required + + airmass_limit : `float`, default : None + + formula : `str`, default : None + + weight : `float`, default : None + + """ + logger.debug( + "AirmassCondition.from_string(string=%s, airmass_limit=%s, formula=%s, weight=%s)" + % (string, airmass_limit, formula, weight) + ) def __str__(self): + """ + Return a `str` representation of the `~pyscope.telrun.AirmassCondition`. + + Returns + ------- + `str` + A `str` representation of the `~pyscope.telrun.AirmassCondition`. + + """ logger.debug("AirmassCondition().__str__()") - pass - def calculate(self, target, time, location, **kwargs): + @staticmethod + def _func(target, time, location, formula="Schoenberg1929", **kwargs): """ - Compute the airmass value for the target at the given time and location. + Calculate the airmass value for the target. Parameters ---------- target : `~astropy.coordinates.SkyCoord`, required - The target to evaluate the condition for. - - time : `~astropy.time.Time`, required - The time to evaluate the condition at. - - location : `~astropy.coordinates.EarthLocation`, required - The location to evaluate the condition at. - - formula : `str`, default : "secant", {"secant", "Schoenberg1929", "Young+Irvine1967", "Hardie1962", "Rozenberg1966", "KastenYoung1989", "Young1994", "Pickering2002"} - The formula to use to calculate the airmass value. + The target to calculate the airmass value for. Returns ------- `float` - The airmass value for the target at the given time and location. + The airmass value for the target. """ - logger.debug( - "AirmassCondition().calculate(target=%s, time=%s, location=%s, kwargs=%s)" - % (target, time, location, kwargs) - ) - pass + logger.debug("AirmassCondition._func(target=%s)" % target) - def score(self, value, **kwargs): + @staticmethod + def _lqs_func(self, value, airmass_limit=3, **kwargs): """ - Compute the score for the airmass condition. + Calculate the linear quality score for the airmass value. Parameters ---------- value : `float`, required - The airmass value to score. + The airmass value for the target. - airmass_limit : `float`, optional + airmass_limit : `float`, default : 3 The maximum airmass value that is allowed. Returns ------- `float` - The linear quality score value (between `0` and `1`) for the airmass condition. + The linear quality score for the airmass value. """ - logger.debug("AirmassCondition().score(value=%s, kwargs=%s)" % (value, kwargs)) - pass + logger.debug( + "AirmassCondition._lqs_func(value=%s, max_val=%s)" % (value, max_val) + ) @property def airmass_limit(self): @@ -158,23 +168,6 @@ def airmass_limit(self): logger.debug("AirmassCondition().airmass_limit == %s" % self._airmass_limit) return self._airmass_limit - @airmass_limit.setter - def airmass_limit(self, value): - """ - The maximum airmass value that is allowed. - - Parameters - ---------- - value : `float`, required - The maximum airmass value that is allowed - - """ - logger.debug("AirmassCondition().airmass_limit = %s" % value) - if value is not None: - if value <= 1: - raise ValueError("Airmass limit must be greater than 1") - self._airmass_limit = value - @property def formula(self): """ @@ -188,28 +181,3 @@ def formula(self): """ logger.debug("AirmassCondition().formula == %s" % self._formula) return self._formula - - @formula.setter - def formula(self, value): - """ - The formula to use to calculate the airmass value. - - Parameters - ---------- - value : `str`, required, {"secant", "Schoenberg1929", "Young+Irvine1967", "Hardie1962", "Rozenberg1966", "KastenYoung1989", "Young1994", "Pickering2002"} - The formula to use to calculate the airmass value. - - """ - logger.debug("AirmassCondition().formula = %s" % value) - if value not in [ - "secant", - "Schoenberg1929", - "Young+Irvine1967", - "Hardie1962", - "Rozenberg1966", - "KastenYoung1989", - "Young1994", - "Pickering2002", - ]: - raise ValueError("Invalid formula for airmass condition") - self._formula = value diff --git a/pyscope/telrun/boundary_condition.py b/pyscope/telrun/boundary_condition.py index 6c945f0e..5f3efb42 100644 --- a/pyscope/telrun/boundary_condition.py +++ b/pyscope/telrun/boundary_condition.py @@ -177,12 +177,19 @@ def __call__(self, target, time, location, **kwargs): return value - def calculate(target, time, location, **kwargs): + def calculate(self, target, time, location, **kwargs): + if kwargs is None: + kwargs = self._kwargs return self._func(target, time, location, **kwargs) - def score(value, **kwargs): + def score(self, value, **kwargs): + if kwargs is None: + kwargs = self._kwargs return self._lqs_func(value, **kwargs) + def plot(self, target, time, location, **kwargs): + pass + @property def weight(self): """ diff --git a/pyscope/telrun/coord_condition.py b/pyscope/telrun/coord_condition.py index 7f419aca..7668c675 100644 --- a/pyscope/telrun/coord_condition.py +++ b/pyscope/telrun/coord_condition.py @@ -13,13 +13,14 @@ def __init__( min_val=None, max_val=None, score_type="boolean", + ref_coord=None, **kwargs, ): """ A restriction on the coordinates of the target viewed from a specific location and at a specific time. - A manager to hande restrictions of a source's location when it is observered. The + A manager to handle restrictions of a source's location when it is observered. The coordinates can be specified in right ascension and declination, galactic latitude and longitude, or altitude and azimuth. @@ -30,7 +31,7 @@ def __init__( and azimuth, "radec" for right ascension and declination, and "galactic" for galactic latitude and longitude. The default is "altaz". - coord_idx : int, default : 0, {0, 1} + coord_idx : `int`, default : 0, {0, 1} The index of the coordinate to use. The default is 0 for the first coordinate. This parameter is ignored if `min_val` and `max_val` both contain two values for the minimum and maximum values of each coordinate. @@ -47,12 +48,13 @@ def __init__( that returns 1 if the condition is met and 0 if it is not, commonly used for determining if the source is above or below the horizon. The default is "boolean". - **kwargs : Additional keyword arguments to pass to the scoring function. + ref_coord : `~astropy.coordinates.SkyCoord`, default : `None` + If `coord_type` is "radec" or "galactic", a user can specify a center value + and `min_val` and `max_val` will be interpreted as a minimum and maximum angular + separation of the target from the reference coordinate. - ref_coord : `~astropy.coordinates.SkyCoord`, default : `None` - If `coord_type` is "radec" or "galactic", a user can specify a center value - and `min_val` and `max_val` will be interpreted as a minimum and maximum angular - separation of the target from the reference coordinate. + **kwargs : `dict`, default : {} + Additional keyword arguments to pass to the `~pyscope.telrun.BoundaryCondition` constructor. """ logger.debug( @@ -63,11 +65,13 @@ def __init__( min_val=%s, max_val=%s, score_type=%s, + ref_coord=%s, kwargs=%s )""" - % (coord_type, coord_idx, min_val, max_val, score_type, kwargs) + % (coord_type, coord_idx, min_val, max_val, score_type, ref_coord, kwargs) ) + @classmethod def from_string( self, string, @@ -76,6 +80,7 @@ def from_string( min_val=None, max_val=None, score_type=None, + ref_coord=None, **kwargs, ): """ @@ -96,6 +101,8 @@ def from_string( score_type : `str`, default : None + ref_coord : `~astropy.coordinates.SkyCoord`, default : None + **kwargs : `dict`, default : {} """ @@ -116,44 +123,34 @@ def __str__(self): """ logger.debug("CoordinateCondition().__str__()") - def __repr__(self): - """ - Return a `str` representation of the `~pyscope.telrun.CoordinateCondition`. - - Returns - ------- - `str` - A `str` representation of the `~pyscope.telrun.CoordinateCondition`. - - """ - logger.debug("CoordinateCondition().__repr__()") - return str(self) + @staticmethod + def _func(): + pass - def __call__(self, target, time=None, location=None): - """ - Evaluate the condition for the target at the specified time and location. + @staticmethod + def _lqs_func(): + pass - Parameters - ---------- - target : `~astropy.coordinates.SkyCoord`, required - The target to evaluate the condition for. + @property + def coord_type(self): + pass - time : `~astropy.time.Time`, default : None - The time to evaluate the condition at. Some conditions do not depend on time, - but others that do will require this parameter. + @property + def coord_idx(self): + pass - location : `~astropy.coordinates.EarthLocation`, default : None - The location to evaluate the condition at. Some conditions do not depend on - location, but others that do will require this parameter. + @property + def min_val(self): + pass - Returns - ------- - `float` - A `float` value between `0` and `1` that represents the linear quality score of the condition. + @property + def max_val(self): + pass - """ + @property + def score_type(self): pass - def plot(self, target, time, location, ax=None): - """ """ + @property + def ref_coord(self): pass