def __init__(self, lon, lat=None, height=None, copy=True): if height is None and not isinstance(lon, self.__class__): height = 0 << u.m super().__init__(lon, lat, height, copy=copy) if not self.height.unit.is_equivalent(u.m): raise u.UnitTypeError(f"{self.__class__.__name__} requires " f"height with units of length.")
def _set_unit(self, unit): if unit is None or unit != self._unit: raise u.UnitTypeError( "{0} instances require units of '{1}'" .format(type(self).__name__, self._unit) + (", but no unit was given." if unit is None else ", so cannot set it to '{0}'.".format(unit))) super()._set_unit(unit)
def ingest_filter_set(path: str, instrument: str, instrument_response: bool = False, atmosphere: bool = False, source: str = None, wavelength_unit: units.Unit = None, percentage: bool = False, lambda_name='LAMBDA', quiet: bool = False): """ :param path: :param instrument: :param instrument_response: Filter curve includes instrument response :param atmosphere: Filter curve includes atmospheric transmission :param source: :param wavelength_unit: :param percentage: :param lambda_name: :param quiet: :return: """ if not wavelength_unit.is_equivalent(units.Angstrom): raise units.UnitTypeError( f"Wavelength units must be of type length, not {wavelength_unit}") type_str = "_filter" if instrument_response: type_str += "_instrument" if atmosphere: type_str += "_atmosphere" data = QTable.read(path, format='ascii') data.sort("col1") wavelengths = data["col1"] * wavelength_unit wavelengths = wavelengths.to("Angstrom") for f in data.colnames: if f != lambda_name: params = filter_params(f=f, instrument=instrument, quiet=quiet) transmissions = data[f] if params is None: params = new_filter_params(quiet=quiet) params['name'] = f if source is not None: params[f'source{type_str}'] = source if percentage: transmissions /= 100 params[f'wavelengths{type_str}'] = wavelengths params[f'transmissions{type_str}'] = transmissions save_params(file=param_dir + f'filters/{instrument}-{f}', dictionary=params, quiet=quiet) refresh_params_filters(quiet=quiet)
def __pow__(self, other): if isinstance(other, Measurement): if other.unit.physical_type != u'dimensionless': raise u.UnitTypeError('Can only raise something to a dimensionless quantity') new_value = self.value**other.value uncertainty = np.abs(new_value)*np.sqrt((other.value*self.uncertainty/self.value)**2 +\ (other.uncertainty*np.log(self.value))**2) return self._new_view(new_value, self.unit**other.value, uncertainty) elif isinstance(other, u.Quantity): if other.unit.physical_type != u'dimensionless': raise u.UnitTypeError('Can only raise something to a dimensionless quantity') new_value = self.value**other.value uncertainty = np.abs(new_value*other.value*self.uncertainty/self.value) return self._new_view(new_value, self.unit**other.value, uncertainty) else: return self._new_view(self.value**other, self.unit**other, np.abs(self.value**(other-1)*other*self.uncertainty))
def _check_optional_units(namespace, allowed_physical_types): for name, kinds in allowed_physical_types.items(): if name not in namespace: continue obj = namespace[name] if isinstance(kinds, (str, u.PhysicalType)): kinds = (kinds, ) if isinstance(obj, u.Quantity) and (obj.unit.physical_type not in kinds): raise u.UnitTypeError(f'Parameter {name} should have physical ' f'type(s) {kinds}, not ' f'{obj.unit.physical_type}.')
def __rpow__(self, other): if self.unit.physical_type != u'dimensionless': raise u.UnitTypeError('Can only raise something to a dimensionless quantity') if isinstance(other, Measurement): new_value = other.value**self.value uncertainty = np.abs(new_value)*np.sqrt((self.value*other.uncertainty/other.value)**2+ (self.uncertainty*np.log(other.value))**2) return self._new_view(new_value, other.unit**self.value, uncertainty) elif isinstance(other, u.Quantity): new_value = other.value**self.value uncertainty = np.abs(new_value*self.uncertainty*np.log(other.value)) return self._new_view(new_value, other.unit**self.value, uncertainty) else: new_value = other**self.value return self._new_view(new_value, u.dimensionless_unscaled, np.abs(new_value*self.uncertainty*np.log(other)))
def _check_unit_core( self, arg, arg_name: str, arg_checks: Dict[str, Any] ) -> Tuple[ Union[None, u.Quantity], Union[None, u.Unit], Union[None, List[Any]], Union[None, Exception], ]: """ Determines if `arg` passes unit checks `arg_checks` and if the units of `arg` is equivalent to any units specified in `arg_checks`. Parameters ---------- arg The argument to be checked arg_name: str The name of the argument to be checked arg_checks: Dict[str, Any] The requested checks for the argument Returns ------- (`arg`, `unit`, `equivalencies`, `error`) * `arg` is the original input argument `arg` or `None` if unit checks fail * `unit` is the identified astropy :mod:`~astropy.units` that `arg` can be converted to or `None` if none exist * `equivalencies` is the astropy :mod:`~astropy.units.equivalencies` used for the unit conversion or `None` * `error` is the `Exception` associated with the failed unit checks or `None` for successful unit checks """ # initialize str for error messages if arg_name == "checks_on_return": err_msg = "The return value " else: err_msg = f"The argument '{arg_name}' " err_msg += f"to function {self.f.__name__}()" # initialize ValueError message valueerror_msg = f"{err_msg} can not contain" # initialize TypeError message typeerror_msg = f"{err_msg} should be an astropy Quantity with " if len(arg_checks["units"]) == 1: typeerror_msg += f"the following unit: {arg_checks['units'][0]}" else: typeerror_msg += "one of the following units: " for unit in arg_checks["units"]: typeerror_msg += str(unit) if unit != arg_checks["units"][-1]: typeerror_msg += ", " if arg_checks["none_shall_pass"]: typeerror_msg += "or None " # pass Nones if allowed if arg is None: if arg_checks["none_shall_pass"]: return arg, None, None, None else: return None, None, None, ValueError(f"{valueerror_msg} Nones") # check units in_acceptable_units = [] equiv = arg_checks["equivalencies"] for unit in arg_checks["units"]: try: in_acceptable_units.append( arg.unit.is_equivalent(unit, equivalencies=equiv) ) except AttributeError: if hasattr(arg, "unit"): err_specifier = ( "a 'unit' attribute without an 'is_equivalent' method" ) else: err_specifier = "no 'unit' attribute" msg = ( f"{err_msg} has {err_specifier}. " f"Use an astropy Quantity instead." ) return None, None, None, TypeError(msg) # How many acceptable units? nacceptable = np.count_nonzero(in_acceptable_units) unit = None equiv = None err = None if nacceptable == 0: # NO equivalent units arg = None err = u.UnitTypeError(typeerror_msg) else: # is there an exact match? units_arr = np.array(arg_checks["units"]) units_equal_mask = np.equal(units_arr, arg.unit) units_mask = np.logical_and(units_equal_mask, in_acceptable_units) if np.count_nonzero(units_mask) == 1: # matched exactly to a desired unit unit = units_arr[units_mask][0] equiv = arg_checks["equivalencies"] elif nacceptable == 1: # there is a match to 1 equivalent unit unit = units_arr[in_acceptable_units][0] equiv = arg_checks["equivalencies"] if not arg_checks["pass_equivalent_units"]: err = u.UnitTypeError(typeerror_msg) elif arg_checks["pass_equivalent_units"]: # there is a match to more than one equivalent units pass else: # there is a match to more than 1 equivalent units arg = None err = u.UnitTypeError(typeerror_msg) return arg, unit, equiv, err
def ingest_filter_transmission(path: str, fil_name: str, instrument: str, instrument_response: bool = False, atmosphere: bool = False, lambda_eff: units.Quantity = None, fwhm: float = None, source: str = None, wavelength_unit: units.Unit = units.Angstrom, percentage: bool = False, quiet: bool = False): """ :param path: :param fil_name: :param instrument: :param instrument_response: Filter curve includes instrument response :param atmosphere: Filter curve includes atmospheric transmission :param lambda_eff: :param fwhm: :param source: :param wavelength_unit: :param percentage: :param quiet: :return: """ if not wavelength_unit.is_equivalent(units.Angstrom): raise units.UnitTypeError( f"Wavelength units must be of type length, not {wavelength_unit}") type_str = "_filter" if instrument_response: type_str += "_instrument" if atmosphere: type_str += "_atmosphere" params = filter_params(f=fil_name, instrument=instrument, quiet=quiet) if params is None: params = new_filter_params(quiet=quiet) params['name'] = fil_name params['instrument'] = instrument if lambda_eff is not None: lambda_eff = u.check_quantity(lambda_eff, unit=units.Angstrom, convert=True) params['lambda_eff'] = lambda_eff # TODO: If None, measure? if fwhm is not None: params['fwhm'] = fwhm # TODO: If None, measure? if source is not None: params[f'source{type_str}'] = source tbl = QTable.read(path, format="ascii") tbl["col1"].name = "wavelength" tbl["wavelength"] *= wavelength_unit tbl["wavelength"] = tbl["wavelength"].to("Angstrom") tbl["col2"].name = "transmission" if percentage: tbl["transmission"] /= 100 tbl.sort("wavelength") params[f'wavelengths{type_str}'] = tbl["wavelength"].value.tolist() params[f'transmissions{type_str}'] = tbl["transmission"].value.tolist() save_params(file=os.path.join(param_dir, 'filters', f'{instrument}-{fil_name}'), dictionary=params, quiet=quiet)
def __init__(self, dim): if not dim.unit.is_equivalent((u.radian, u.meter)): raise u.UnitTypeError( 'aperture must be defined with angles or lengths.') self.dim = dim