Emission model basics¶
Here we give an overview of the basic functionality of an EmissionModel
. Elsewhere we cover what models are available, how to modify a model, making your own custom models, and combining_models from different components.
To use an EmissionModel
model we simply instantiate it with the required arguments. However, which arguments are required depends on the exact operation.
Operations¶
Extraction¶
For extraction operations you need:
A grid to extract from (
grid
).A key to extract (
extract
). For lines,line_ids
must be passed toget_lines
, this key is then the label given to theLineCollection
.Optionally, an escape fraction to apply which defaults to 0.0 (
fesc
orcovering_fraction
for AGN).
Combination¶
For combination operations you need:
A list of models which will be combined (i.e. added) to give the resultant emission (
combine
).
Generation¶
For generation operations you need:
A generator class (e.g. a dust emission model) from which to generate spectra (
generator
).
Attenuation¶
For attenuation operations you need:
The dust curve to apply (
dust_curve
).The model to apply the attenuation to (
apply_dust_to
).The optical depth to use with the dust curve (
tau_v
).
Masking¶
Masking can be applied alongside any of these operations. Any number of masks can be combined on the same operation. Each mask is defined by:
The attribute of the component to mask on (
mask_attr
).The threshold of the mask (
mask_thresh
).The operator to use when generating the mask, i.e.
"<"
,">"
,"<="
,">="
,"=="
, or"!="
(mask_op
).
Getting a model¶
For this demonstration we’ll load the TotalEmission
premade stellar emisison model. We define a few key parameters when initialising the EmissionModel
, such as the dust curve and the \(V\)-band optical depth.
[1]:
from unyt import Myr
from synthesizer.emission_models import TotalEmission
from synthesizer.emission_models.attenuation import PowerLaw
from synthesizer.grid import Grid
# Get the grid which we'll need for extraction
grid_dir = "../../../tests/test_grid"
grid_name = "test_grid"
grid = Grid(grid_name, grid_dir=grid_dir)
total = TotalEmission(grid=grid, dust_curve=PowerLaw(slope=-1), tau_v=0.67)
When using more complex premade models, with a deeper “tree”, more parameters will be required to populate their “child” models deeper in the tree. This tree terminology will become clear later – don’t worry about the specifics here if you are just starting with synthesizer
EmissionModels
.
In addition to the arguments specfic to each type of model, any model can be passed arguments to define a mask: - mask_attr
, the emitter attribute to define a mask with - mask_op
, the operator to use in the mask - mask_thresh
, the threshold for the mask
In the example below we apply a mask to the stellar ages, so that only emission from stars less than 10 Myr old are returned.
[2]:
masked_total = TotalEmission(
grid=grid,
label="young_total",
dust_curve=PowerLaw(slope=-1),
tau_v=0.67,
mask_attr="ages",
mask_op="<",
mask_thresh=10 * Myr,
)
In the above case we used a global mask on the
TotalEmission
model, so that every child model in the tree has also been masked. In most (but certainly not all) cases you’ll only want specific models masked. > This can either be done by constructing your own models or modifying existing ones.
Printing a summary of an EmissionModel
¶
If we want to see a summary of all the models contained within an instance of an EmissionModel
we simply print the model.
[3]:
print(masked_total)
|====================================== EmissionModel: young_total ======================================|
|--------------------------------------------------------------------------------------------------------|
| TRANSMITTED (stellar) |
|--------------------------------------------------------------------------------------------------------|
|Extraction model: |
| Grid: test_grid |
| Extract key: transmitted |
| Escape fraction: 0.0 |
| Save emission: True |
| Masks: |
| - ages < 10 Myr |
|--------------------------------------------------------------------------------------------------------|
| NEBULAR (stellar) |
|--------------------------------------------------------------------------------------------------------|
|Extraction model: |
| Grid: test_grid |
| Extract key: nebular |
| Escape fraction: 0.0 |
| Save emission: True |
| Masks: |
| - ages < 10 Myr |
|--------------------------------------------------------------------------------------------------------|
| ESCAPED (stellar) |
|--------------------------------------------------------------------------------------------------------|
|Extraction model: |
| Grid: test_grid |
| Extract key: transmitted |
| Escape fraction: 1.0 |
| Save emission: True |
| Masks: |
| - ages < 10 Myr |
|--------------------------------------------------------------------------------------------------------|
| REPROCESSED (stellar) |
|--------------------------------------------------------------------------------------------------------|
|Combination model: |
| Combine models: nebular, transmitted |
| Save emission: True |
| Masks: |
| - ages < 10 Myr |
|--------------------------------------------------------------------------------------------------------|
| ATTENUATED (stellar) |
|--------------------------------------------------------------------------------------------------------|
|Dust attenuation model: |
| Dust curve: <synthesizer.emission_models.attenuation.dust.PowerLaw object at 0x7fa744451270> |
| Apply dust to: reprocessed |
| Optical depth (tau_v): [0.67] |
| Save emission: True |
| Masks: |
| - ages < 10 Myr |
|--------------------------------------------------------------------------------------------------------|
| YOUNG_TOTAL (stellar) |
|--------------------------------------------------------------------------------------------------------|
|Combination model: |
| Combine models: attenuated, escaped |
| Save emission: True |
| Masks: |
| - ages < 10 Myr |
|========================================================================================================|
This returns a text block describing each model, including its label (in all caps), its emitter (in brackets after the label), and the operation the model performs, followed by the parameters defining the operation.
Plotting an EmissionModel
¶
For a more detailed view of how models relate to each other we can visualise the tree itself:
[4]:
total.plot_emission_tree()
masked_total.plot_emission_tree()
[4]:
(<Figure size 600x600 with 1 Axes>, <Axes: >)
In the tree we can see each individual spectra generated by the model, and how they relate:
Solid lines denote combinations of spectra.
Dashed lines denote an attenuation of the child spectra to produce the parent.
Dotted lines denote a relationship between the parent generator and it’s child spectra used to scale the generated spectra (not required for all generators).
Blue boxes have no mask applied.
Green boxes have a mask applied to them (which we only have for the masked model we made).
Square boxes are an extraction operation.
Boxes with rounded corners are generation, dust attenuation or combination operations.
You’ll notice the extraction operations are always leaves in the tree.
Extracting models¶
An emission model can be treated like a dictionary – if we want to get a model from somewhere in the tree, we simply index with the model label.
[5]:
sub_model = total["reprocessed"]
sub_model.plot_emission_tree()
[5]:
(<Figure size 600x600 with 1 Axes>, <Axes: >)
Generating spectra and lines¶
We’ll cover this in greater detail in the spectra docs and the lines docs, but to generate an emission from an EmissionModel
you need to:
Set up your model as shown in the other
EmissionModel
docs.Set up an “emitter” (e.g. a component or galaxy containing components) as shown in the [component docs](../components/components.rst.
Call the emitter’s
get_spectra
method passing in your model.
This will return the spectra/lines at the root of your emission model and store all generated spectra in the emitter.
Generating emissions for each particle¶
To generate spectra for each particle in a component/galaxy we follow the exact same steps as above, but we need to set per_particle=True
on our model. This can be done at model instantiation…
[6]:
# Create a model for per particle emission
total = TotalEmission(
grid=grid,
label="total",
dust_curve=PowerLaw(slope=-1),
tau_v=0.67,
per_particle=True,
)
total.plot_emission_tree()
[6]:
(<Figure size 600x600 with 1 Axes>, <Axes: >)
Or by using the set_per_particle
method on the model. This will set the model it is called from and any child models to generate spectra for each particle in the emitter. Below we’ll demonstrate this by making every model in the total
model we made above to be integrated (per_particle=False
) and then set some of the children to be per particle.
[7]:
total.set_per_particle(False)
total["reprocessed"].set_per_particle(True)
total["escaped"].set_per_particle(True)
total.plot_emission_tree()
[7]:
(<Figure size 600x600 with 1 Axes>, <Axes: >)
Notice how now the "total"
and "attenuated"
models don’t mention per particle emission while all others (which are children of "reprocessed"
) have Per particle emission: True
in their summary.
When per_particle=True
the model will generate a spectrum for each particle in the component/galaxy, for each individual model in your EmissionModel
, and store these in the particle_spectra
attribute. Note that integrated spectra will automatically be generated too and will be stored in the spectra
attribute.