def fset(name, unit): name = f"_{name}" try: unit = u.Unit(unit) decorator = u.quantity_input(value=unit) except TypeError: if unit is Time: decorator = time_input elif unit is SkyCoord: decorator = coord_input else: raise TypeError(f"Expected a Quantity, Time, or SkyCoord, but got {unit}") @decorator def f(self, value): setattr(self, name, value) return f
class SpectralSampling(_Range): """ The average spectral sampling of a dataset. Parameters ---------- spectralmin : `u.Quantity` The minimum value of the average spectral sampling to search between. spectralmax : `u.Quantity` The maximum value of the average spectral sampling to search between. """ u.quantity_input(equivalencies=u.spectral()) def __init__(self, spectralmin: u.nm, spectralmax: u.nm): super().__init__(spectralmin, spectralmax) def collides(self, other): return isinstance(other, self.__class__)
class Transitioner(object): """ A class that defines how to compute transition times from one block to another. """ u.quantity_input(slew_rate=u.deg/u.second) def __init__(self, slew_rate=None, instrument_reconfig_times=None): """ Parameters ---------- slew_rate : `~astropy.units.Quantity` with angle/time units The slew rate of the telescope instrument_reconfig_times : dict of dicts or None If not None, gives a mapping from property names to another dictionary. The second dictionary maps 2-tuples of states to the time it takes to transition between those states (as an `~astropy.units.Quantity`), can also take a 'default' key mapped to a default transition time. """ self.slew_rate = slew_rate self.instrument_reconfig_times = instrument_reconfig_times def __call__(self, oldblock, newblock, start_time, observer): """ Determines the amount of time needed to transition from one observing block to another. This uses the parameters defined in ``self.instrument_reconfig_times``. Parameters ---------- oldblock : `~astroplan.scheduling.ObservingBlock` or None The initial configuration/target newblock : `~astroplan.scheduling.ObservingBlock` or None The new configuration/target to transition to start_time : `~astropy.time.Time` The time the transition should start observer : `astroplan.Observer` The observer at the time Returns ------- transition : `~astroplan.scheduling.TransitionBlock` or None A transition to get from ``oldblock`` to ``newblock`` or `None` if no transition is necessary """ components = {} if (self.slew_rate is not None and (oldblock is not None) and (newblock is not None)): # use the constraints cache for now, but should move that machinery # to observer from .constraints import _get_altaz from .target import get_skycoord if oldblock.target != newblock.target: targets = get_skycoord([oldblock.target, newblock.target]) aaz = _get_altaz(start_time, observer, targets)['altaz'] sep = aaz[0].separation(aaz[1]) if sep/self.slew_rate > 1 * u.second: components['slew_time'] = sep / self.slew_rate if self.instrument_reconfig_times is not None: components.update(self.compute_instrument_transitions(oldblock, newblock)) if components: return TransitionBlock(components, start_time) else: return None def compute_instrument_transitions(self, oldblock, newblock): components = {} for conf_name, old_conf in oldblock.configuration.items(): if conf_name in newblock.configuration: conf_times = self.instrument_reconfig_times.get(conf_name, None) if conf_times is not None: new_conf = newblock.configuration[conf_name] ctime = conf_times.get((old_conf, new_conf), None) def_time = conf_times.get('default', None) if ctime is not None: s = '{0}:{1} to {2}'.format(conf_name, old_conf, new_conf) components[s] = ctime elif def_time is not None and not old_conf == new_conf: s = '{0}:{1} to {2}'.format(conf_name, old_conf, new_conf) components[s] = def_time return components
class Transitioner(object): """ A class that defines how to compute transition times from one block to another. Parameters ---------- slew_rate : `~astropy.units.Quantity` with angle/time units The slew rate of the telescope instrument_reconfig_times : dict of dicts or None If not None, gives a mapping from property names to another dictionary. The second dictionary maps 2-tuples of states to the time it takes to transition between those states (as an `~astropy.units.Quantity`). """ u.quantity_input(slew_rate=u.deg / u.second) def __init__(self, slew_rate=None, instrument_reconfig_times=None): self.slew_rate = slew_rate self.instrument_reconfig_times = instrument_reconfig_times def __call__(self, oldblock, newblock, start_time, observer): """ Determines the amount of time needed to transition from one observing block to another. This uses the parameters defined in ``self.instrument_reconfig_times``. Parameters ---------- oldblock : `ObservingBlock` or None The initial configuration/target newblock : `ObservingBlock` or None The new configuration/target to transition to start_time : `~astropy.time.Time` The time the transition should start observer : `astroplan.Observer` The observer at the time Returns ------- transition : `TransitionBlock` or None A transition to get from `oldblock` to `newblock` or None if no transition is necessary """ components = {} if self.slew_rate is not None: # use the constraints cache for now, but should move that machinery to # observer from .constraints import _get_altaz from astropy.time import Time aaz = _get_altaz(Time([start_time]), observer, [oldblock.target, newblock.target])['altaz'] # TODO: make this [0] unnecessary by fixing _get_altaz to behave well in scalar-time case sep = aaz[0].separation(aaz[1])[0] components['slew_time'] = sep / self.slew_rate if self.instrument_reconfig_times is not None: components.update( self.compute_instrument_transitions(oldblock, newblock)) if components: return TransitionBlock(components, start_time) else: return None def compute_instrument_transitions(self, oldblock, newblock): components = {} for conf_name, old_conf in oldblock.configuration.items(): if conf_name in newblock: conf_times = self.instrument_reconfig_times.get( conf_name, None) if conf_times is not None: new_conf = newblock[conf_name] ctime = conf_times.get((old_conf, new_conf), None) if ctime is not None: s = '{0}:{1} to {2}'.format( conf_name, old_conf, new_conf) components[s] = ctime return components
if compound_str.lower() in lower_case_symbols_list: return lower_case_symbols_list.index(compound_str.lower()) lcase_name_list = list([s.lower() for s in roentgen.compounds["name"]]) if compound_str.lower() in lcase_name_list: return lcase_name_list.index(compound_str.lower()) else: return None def get_density(material_str): """Given a material name return the default density""" if is_an_element(material_str): ind = get_atomic_number(material_str) - 1 density = roentgen.elements[ind]["density"] else: # not using loc because table indexing is not yet stable # self.density = roentgen.compounds.loc[material_str]['density'] index = list(roentgen.compounds["symbol"]).index(material_str) density = roentgen.compounds[index]["density"] return density u.quantity_input(pressure=u.pascal) def density_ideal_gas(pressure, temperature): # noqa """Given pressure and temperature of a dry gas, return the density using the ideal gas law""" R = 287.058 * u.J / u.kg / u.Kelvin return pressure / (R * temperature.to('K', equivalencies=u.temperature()))