ESBO-ETC/esbo_etc/classes/optical_component/Filter.py

269 lines
12 KiB
Python
Raw Normal View History

2020-04-15 16:35:35 +02:00
from .AHotOpticalComponent import AHotOpticalComponent
from ..SpectralQty import SpectralQty
2020-04-16 09:35:24 +02:00
from ..IRadiant import IRadiant
2020-05-29 09:36:02 +02:00
from ...lib.logger import logger
2020-05-08 15:06:13 +02:00
from ..Entry import Entry
2020-04-15 16:35:35 +02:00
from astropy import units as u
2020-09-12 11:51:49 +02:00
from typing import Union
2020-04-24 11:46:35 +02:00
import numpy as np
2020-04-15 16:35:35 +02:00
class Filter(AHotOpticalComponent):
"""
A class to model a filter component and its thermal emission. The model can be created from a file, the name of
a band or a custom spectral range.
"""
2020-04-22 11:02:32 +02:00
# Bands from Handbook of Space Astronomy and Astrophysics p. 139
2020-04-22 11:01:33 +02:00
_band = dict(U=dict(cwl=365 * u.nm, bw=68 * u.nm), B=dict(cwl=440 * u.nm, bw=98 * u.nm),
V=dict(cwl=550 * u.nm, bw=89 * u.nm), R=dict(cwl=700 * u.nm, bw=220 * u.nm),
I=dict(cwl=900 * u.nm, bw=240 * u.nm), J=dict(cwl=1250 * u.nm, bw=300 * u.nm),
H=dict(cwl=1650 * u.nm, bw=400 * u.nm), K=dict(cwl=2200 * u.nm, bw=600 * u.nm),
L=dict(cwl=3600 * u.nm, bw=1200 * u.nm), M=dict(cwl=4800 * u.nm, bw=800 * u.nm),
N=dict(cwl=10200 * u.nm, bw=2500 * u.nm))
2020-04-15 16:35:35 +02:00
2020-09-12 11:51:49 +02:00
def __init__(self, **kwargs):
2020-04-15 16:35:35 +02:00
"""
Instantiate a new filter model
Parameters
----------
2020-04-16 09:35:24 +02:00
parent : IRadiant
2020-04-15 16:35:35 +02:00
The parent element of the optical component from which the electromagnetic radiation is received.
2020-09-12 11:51:49 +02:00
transmittance : str
Path to the file containing the spectral transmittance-coefficients of the filter element.
The format of the file will be guessed by `astropy.io.ascii.read()`.
band : str
The spectral band of the filter. Can be one of [U, B, V, R, I, J, H, K].
start : length-quantity
Start wavelength of the pass-band
end : length-quantity
End wavelength of the pass-band
2020-05-08 15:06:13 +02:00
emissivity : Union[str, float]
2020-04-15 16:35:35 +02:00
The spectral emissivity coefficient for the optical surface.
temp: Quantity in Kelvin / Celsius
Temperature of the optical component
obstruction : float
The additional obstruction factor of the optical component. 0 means the component is not obstructed, 1
denotes a completely obstructed component with therefore no incoming flux. It is important to note, that
the obstruction factor reflects the obstruction of the optical component additionally to the obstruction
factors of the prior elements in the beam.
obstructor_temp : Quantity in Kelvin / Celsius
Temperature of the obstructing component.
obstructor_emissivity : float
Emissivity of the obstructing component.
"""
2020-09-12 11:51:49 +02:00
args = dict()
if "band" in kwargs:
args = self._fromBand(**kwargs)
elif "transmittance" in kwargs:
args = self._fromFile(**kwargs)
elif "start" in kwargs and "end" in kwargs:
args = self._fromRange(**kwargs)
else:
logger.error("Wrong parameters for filter.")
self._transmittance = args.pop("transmittance")
super().__init__(**args)
2020-04-15 16:35:35 +02:00
# @u.quantity_input(temp=[u.Kelvin, u.Celsius], obstructor_temp=[u.Kelvin, u.Celsius])
2020-09-12 11:51:49 +02:00
def _fromBand(self, parent: IRadiant, band: str, emissivity: Union[str, float] = 1, temp: u.Quantity = 0 * u.K,
obstruction: float = 0, obstructor_temp: u.Quantity = 0 * u.K,
obstructor_emissivity: float = 1) -> dict:
2020-04-15 16:35:35 +02:00
"""
Instantiate a new filter model from a spectral band. The filter will be modelled as bandpass filter of
infinite order and therefore similar to a hat-function.
Parameters
----------
2020-04-16 09:35:24 +02:00
parent : IRadiant
2020-04-15 16:35:35 +02:00
The parent element of the optical component from which the electromagnetic radiation is received.
band : str
The spectral band of the filter. Can be one of [U, B, V, R, I, J, H, K].
2020-05-08 15:06:13 +02:00
emissivity : Union[str, float]
2020-04-15 16:35:35 +02:00
The spectral emissivity coefficient for the optical surface.
temp: Quantity in Kelvin / Celsius
Temperature of the optical component
obstruction : float
The additional obstruction factor of the optical component. 0 means the component is not obstructed, 1
denotes a completely obstructed component with therefore no incoming flux. It is important to note, that
the obstruction factor reflects the obstruction of the optical component additionally to the obstruction
factors of the prior elements in the beam.
obstructor_temp : Quantity in Kelvin / Celsius
Temperature of the obstructing component.
obstructor_emissivity : float
Emissivity of the obstructing component.
Returns
-------
2020-09-12 11:51:49 +02:00
args : dict
The arguments for the class instantiation.
2020-04-15 16:35:35 +02:00
"""
2020-09-12 11:51:49 +02:00
if band not in self._band.keys():
logger.error("Band has to be one of '[" + ", ".join(list(self._band.keys())) + "]'")
return self._fromRange(parent, self._band[band]["cwl"] - self._band[band]["bw"] / 2,
self._band[band]["cwl"] + self._band[band]["bw"] / 2, emissivity, temp, obstruction,
obstructor_temp, obstructor_emissivity)
2020-04-15 16:35:35 +02:00
# @u.quantity_input(temp=[u.Kelvin, u.Celsius], obstructor_temp=[u.Kelvin, u.Celsius])
2020-09-12 11:51:49 +02:00
def _fromFile(self, parent: IRadiant, transmittance: str, emissivity: Union[str, float] = 1,
temp: u.Quantity = 0 * u.K, obstruction: float = 0, obstructor_temp: u.Quantity = 0 * u.K,
obstructor_emissivity: float = 1) -> dict:
2020-04-15 16:35:35 +02:00
"""
Instantiate a new filter model from a file containing the spectral transmittance coefficients.
Parameters
----------
2020-04-16 09:35:24 +02:00
parent : IRadiant
2020-04-15 16:35:35 +02:00
The parent element of the optical component from which the electromagnetic radiation is received.
transmittance : str
Path to the file containing the spectral transmittance-coefficients of the filter element.
The format of the file will be guessed by `astropy.io.ascii.read()`.
2020-05-08 15:06:13 +02:00
emissivity : Union[str, float]
2020-04-15 16:35:35 +02:00
The spectral emissivity coefficient for the optical surface.
temp: Quantity in Kelvin / Celsius
Temperature of the optical component
obstruction : float
The additional obstruction factor of the optical component. 0 means the component is not obstructed, 1
denotes a completely obstructed component with therefore no incoming flux. It is important to note, that
the obstruction factor reflects the obstruction of the optical component additionally to the obstruction
factors of the prior elements in the beam.
obstructor_temp : Quantity in Kelvin / Celsius
Temperature of the obstructing component.
obstructor_emissivity : float
Emissivity of the obstructing component.
Returns
-------
2020-09-12 11:51:49 +02:00
args : dict
The arguments for the class instantiation.
2020-04-15 16:35:35 +02:00
"""
2020-09-12 11:51:49 +02:00
return {"parent": parent, "transmittance": SpectralQty.fromFile(transmittance, u.nm, u.dimensionless_unscaled),
"emissivity": emissivity, "temp": temp, "obstruction": obstruction, "obstructor_temp": obstructor_temp,
"obstructor_emissivity": obstructor_emissivity}
2020-04-15 16:35:35 +02:00
# @u.quantity_input(start="length", end="length", temp=[u.Kelvin, u.Celsius], obstructor_temp=[u.Kelvin, u.Celsius])
2020-09-12 11:51:49 +02:00
def _fromRange(self, parent: IRadiant, start: u.Quantity, end: u.Quantity, emissivity: Union[str, float] = 1,
temp: u.Quantity = 0 * u.K, obstruction: float = 0, obstructor_temp: u.Quantity = 0 * u.K,
obstructor_emissivity: float = 1) -> dict:
2020-04-15 16:35:35 +02:00
"""
Instantiate a new filter model from a spectral range. The filter will be modelled as bandpass filter of
infinite order and therefore similar to a hat-function.
Parameters
----------
2020-04-16 09:35:24 +02:00
parent : IRadiant
2020-04-15 16:35:35 +02:00
The parent element of the optical component from which the electromagnetic radiation is received.
start : length-quantity
Start wavelength of the pass-band
end : length-quantity
End wavelength of the pass-band
2020-05-08 15:06:13 +02:00
emissivity : Union[str, float]
2020-04-15 16:35:35 +02:00
The spectral emissivity coefficient for the optical surface.
temp: Quantity in Kelvin / Celsius
Temperature of the optical component
obstruction : float
The additional obstruction factor of the optical component. 0 means the component is not obstructed, 1
denotes a completely obstructed component with therefore no incoming flux. It is important to note, that
the obstruction factor reflects the obstruction of the optical component additionally to the obstruction
factors of the prior elements in the beam.
obstructor_temp : Quantity in Kelvin / Celsius
Temperature of the obstructing component.
obstructor_emissivity : float
Emissivity of the obstructing component.
Returns
-------
2020-09-12 11:51:49 +02:00
args : dict
The arguments for the class instantiation.
2020-04-15 16:35:35 +02:00
"""
2020-09-12 11:51:49 +02:00
return {"parent": parent, "transmittance": self.__filter_factory(start, end),
"emissivity": emissivity, "temp": temp, "obstruction": obstruction, "obstructor_temp": obstructor_temp,
"obstructor_emissivity": obstructor_emissivity}
2020-04-15 16:35:35 +02:00
2020-04-16 13:04:21 +02:00
def _propagate(self, sqty: SpectralQty) -> SpectralQty:
2020-04-15 16:35:35 +02:00
"""
Propagate incoming radiation through the optical component
Parameters
----------
sqty : SpectralQty
The incoming radiation
Returns
-------
sqty : SpectralQty
Manipulated incoming radiation
"""
return sqty * self._transmittance
@staticmethod
2020-04-16 13:04:21 +02:00
@u.quantity_input(start="length", end="length")
def __filter_factory(start: u.Quantity, end: u.Quantity):
2020-04-15 16:35:35 +02:00
"""
Create a infinite order bandpass filter
Parameters
----------
start : length-quantity
Start wavelength of the pass-band
end : length-quantity
End wavelength of the pass-band
Returns
-------
2020-04-16 13:04:21 +02:00
lambda : Callable[[u.Quantity], u.Quantity]
2020-04-15 16:35:35 +02:00
The filter function
"""
2020-09-12 11:51:49 +02:00
return lambda wl: np.logical_and(np.greater_equal(wl, start), np.greater_equal(end, wl)).astype(
int) * u.dimensionless_unscaled
2020-05-08 15:06:13 +02:00
@staticmethod
def check_config(conf: Entry) -> Union[None, str]:
"""
Check the configuration for this class
Parameters
----------
conf : Entry
The configuration entry to be checked.
Returns
-------
mes : Union[None, str]
The error message of the check. This will be None if the check was successful.
"""
if hasattr(conf, "band"):
mes = conf.check_selection("band", ["U", "B", "V", "R", "I", "J", "H", "K", "L", "M", "N"])
elif hasattr(conf, "transmittance"):
mes = conf.check_file("transmittance")
elif hasattr(conf, "start") and hasattr(conf, "end"):
mes = conf.check_quantity("start", u.m)
if mes is not None:
return mes
mes = conf.check_quantity("end", u.m)
else:
mes = "Expected one of 'band' / 'transmittance' / 'start' & 'end'."
if mes is not None:
return mes
if hasattr(conf, "emissivity"):
mes = conf.check_file("emissivity")
if mes is not None:
mes = conf.check_float("emissivity")
if mes is not None:
return mes
if hasattr(conf, "temp"):
mes = conf.check_quantity("temp", u.K)
if mes is not None:
return mes
if hasattr(conf, "obstruction"):
mes = conf.check_float("obstruction")
if mes is not None:
return mes
if hasattr(conf, "obstructor_temp"):
mes = conf.check_quantity("obstructor_temp", u.K)
if mes is not None:
return mes
if hasattr(conf, "obstructor_emissivity"):
mes = conf.check_float("obstructor_emissivity")
if mes is not None:
return mes