Custom Tasks#
ExoSim allow the user to replace some of the default Task with custom versions of the same process.
Before writing a custom task, make you sure to read The Task structure.
To write a custom Task we need to create a class that first inherits from the default one,
and then we can overwrite the model method.
Let’s do an example. Suppose we want to write our own version of LoadResponsivity.
This task estimate the detector responsivity and shall be indicated in the channel description, as described in Estimate responsivity.
The default task simply reads the right column from the file:
<channel> channel_name
<qe>
<responsivity_task>LoadResponsivity</responsivity_task>
<datafile>__ConfigPath__/qe.ecsv</datafile>
</qe>
Using the model method:
def model(self, parameters, wavelength, time):
"""
Parameters
----------
parameters: dict
dictionary contained the sources parameters.
wavelength: :class:`~astropy.units.Quantity`
wavelength grid.
time: :class:`~astropy.units.Quantity`
time grid.
Returns
--------
:class:`~exosim.models.signal.Signal`
channel responsivity
"""
qe_data = parameters['qe']['data']
wl_ = qe_data['Wavelength']
qe_ = qe_data[parameters['value']]
qe = signal.Dimensionless(data=qe_, spectral=wl_)
qe.spectral_rebin(wavelength)
qe.temporal_rebin(time)
responsivity = signal.Signal(spectral=wavelength, time=time,
data=qe.data * wavelength.to(
u.m) / const.c / const.h * u.count)
return responsivity
The input of the model is the parameter dictionary that contains the description of the full channel. So, let’s imagine that instead of reading the data from a file, we want to estimate the quantum efficiency from a quadratic equation:
where \(\lambda_0\) is a reference wavelength. This equation for the quantum efficiency obviously has no physical justification. This example has been chosen specifically because it is not representative of any physical process, just to focus the attention on the code capabilities.
Then we need to include this model parameters in the channel description:
<channel> channel_name
<qe>
<A> 1 </A>
<B> 2 </B>
<C> 3 </C>
<wl_0 unit=`micron`> 3.0 </wl_0>
</qe>
and then we can write our own Task as
import exosim.tasks.load as load
class CustomResponsivity(load.LoadResponsivity):
"""
Custom responsivity class
"""
def model(self, parameters, wavelength, time):
"""
Parameters
----------
parameters: dict
dictionary contained the sources parameters.
wavelength: :class:`~astropy.units.Quantity`
wavelength grid.
time: :class:`~astropy.units.Quantity`
time grid.
Returns
--------
:class:`~exosim.models.signal.Signal`
channel responsivity
"""
A = parameters['qe']['A']
B = parameters['qe']['B']
C = parameters['qe']['C']
wl_0 = parameters['qe']['wl_0']
qe_ = A * (wavelength/wl_0)**2 + B * (wavelength/wl_0) + c
qe = signal.Dimensionless(data=qe_, spectral=wavelength)
qe.temporal_rebin(time)
responsivity = signal.Signal(spectral=wavelength, time=time,
data=qe.data * wavelength.to(
u.m) / const.c / const.h * u.count)
return responsivity
It’s important that the custom model returns an object of the same kind of the default one or an error will be raised.
Now we need to store this class in a dedicated file. Assume the file is your/path/customResponsivity.py, then you have to indicate it in the .xml description as
<channel> channel_name
<qe>
<responsivity_task> your/path/customResponsivity.py </responsivity_task>
<A> 1 </A>
<B> 2 </B>
<C> 3 </C>
<wl_0 unit=`micron`> 3.0 </wl_0>
</qe>
Now ExoSim will run your task instead of the default one.