Note:
This page was generated from a Jupyter notebook which can be found at
docs/tutorial_notebooks/2_quickstart.ipynb
in your DYNAMITE directory.
—-
2. Quickstart: Running a single Schwarzschild model¶
By the end of the notebook, you will have run a Schwarzschild model. This will involve: 1. understanding the configuration file 2. executing commands to create and run a Schwarzschild model 3. plotting some output for this model
To get started, let’s import DYNAMITE and print the version and installation path:
[1]:
import dynamite as dyn
print('DYNAMITE')
print(' version', dyn.__version__)
#print(' installed at ', dyn.__path__) # Uncomment to print the complete DYNAMITE installation path
DYNAMITE
version 4.2.0
Input files¶
You should be in the directory docs/tutorial_notebooks
. To prepare the input data files, you should first run the CALIFA section of the previous tutorial “Data Preparation for Gauss Hermite kinematics” (1_data_prep_for_gauss_hermite.ipynb
).
If this is the first time you run this tutorial, this directory should have the following structure:
tutorial_notebooks
|- ...
|- NGC6278_input
|- dynamite_input
|- aperture.dat
|- bins.dat
|- gauss_hermite_kins.ecvs
|- kinmaps.pdf
|- mge.ecsv
|- pafit.pdf
|- NGC6278.V1200.rscube_INDOUSv2_SN20_stellar_kin.fits
|- NGC6278_config.yaml
|- NGC6278_config_single.yaml
|- *.ipynb
|- ...
The input data files needed to run DYNAMITE are:
mge.ecvs
- the Multi Gaussian Expansion (MGE) describing the stellar surface density of the galaxygauss_hermite_kins.ecsv
- the kinematics extracted for this galaxyaperture.dat
andbins.dat
- information about the spatial apertures/bins used for kinematic extraction
The MGE and kinematics files must be in the form of Astropy ECSV files. This is a convenient and flexible file format, so we use it whenever possible for storing our input and output data.
We have provided example input data file for a specific galaxy (NGC 6278), and in the directory NGC6278_input
you can also see some diagnostic plots. A very basic set of instructions to generate your own input data is as follows:
fit a MGE to a photometric image, e.g. using mge
create a Voronoi binning of your IFU datacube, e.g. using e.g. vorbin
extract kinematics from the binned datacube, e.g. using e.g. PPXF
make the
aperture.dat
andbins.dat
files; an example script to do this isdynamite/data_prep/generate_kin_input.py
, which is used by the previous tutorial “Data Preparation for Gauss Hermite kinematics” (1_data_prep_for_gauss_hermite.ipynb
)
Configuration file¶
The configuration file controls all the settings that you may wish to vary when running your Schwarschild models. For example, in the configuration file you can specify:
the components of the gravitational potential
the parameters describing the potential, the parameter ranges, etc.
what type of kinematic data you are providing, e.g.
discrete vs continuous,
Gauss-Hermite vs Histograms
the location of the input and output files
the number of models you want to run
This list of options is incomplete - for a more detailed description of the configuration file, see the documentation.
The configuration file for this tutorial is
NGC6278_config_single.yaml
Open this file in a text editor, alongside this notebook, to see how it is organised. The file is in yaml
format. The basic structure of a yaml file are pairs of keys and values
key : value
which can be organised into hierarchical levels separated by tabs
main_key:
sub_key1 : value1
sub_key2 : value2
Comments begin with a #
. Values can be any type of variable (integers, floats, strings, booleans, etc.).
To read the congfiguration file we can use the following command, which creates a configuration object (called c
here):
[2]:
fname = 'NGC6278_config_single.yaml'
c = dyn.config_reader.Configuration(fname, reset_logging=True)
[INFO] 21:39:30 - dynamite.config_reader.Configuration - Config file NGC6278_config_single.yaml read.
[INFO] 21:39:30 - dynamite.config_reader.Configuration - io_settings...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - Output directory tree: NGC6278_output/.
[INFO] 21:39:30 - dynamite.config_reader.Configuration - system_attributes...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - model_components...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - system_parameters...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - orblib_settings...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - weight_solver_settings...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - Will attempt to recover partially run models.
[INFO] 21:39:30 - dynamite.config_reader.Configuration - parameter_space_settings...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - multiprocessing_settings...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - ... using 4 CPUs for orbit integration.
[INFO] 21:39:30 - dynamite.config_reader.Configuration - ... using 4 CPUs for weight solving.
[INFO] 21:39:30 - dynamite.config_reader.Configuration - legacy_settings...
[INFO] 21:39:30 - dynamite.config_reader.Configuration - System assembled
[INFO] 21:39:30 - dynamite.config_reader.Configuration - Configuration validated
[INFO] 21:39:30 - dynamite.config_reader.Configuration - Instantiated parameter space
[INFO] 21:39:30 - dynamite.model.AllModels - No previous models (file NGC6278_output/all_models.ecsv) have been found: Made an empty table in AllModels.table
[INFO] 21:39:30 - dynamite.config_reader.Configuration - Instantiated AllModels object
[INFO] 21:39:30 - dynamite.model.AllModels - No all_models table update required.
When making this object, some output is printed, telling you whether any previous models have been found. If you are running this tutorial for the first time, no models will be found and an empty table will be created at AllModels.table
. This table holds information about all the models which have been run so far.
Remark: if you run this tutorial again and wish to start from empty output, you can either manually delete the output directory tree (NGC6278_output
) or add the parameter reset_existing_output=True
to the configuration object constructor: c = dyn.config_reader.Configuration(fname, reset_logging=True, reset_existing_output=True)
.
The configuration object c
is structured in a similar way to the configuration file itself. For example, the configuration file is split into two sections. The top section defines aspects the physical system we wish to model - e.g. the globular cluster, galaxy or galaxy cluster - while the second section contains all other settings we need for running a model - e.g. settings about the orbit integration and input/output options. The two sections are stored in the system
and settings
attributes of the configuration object, respectively.
[3]:
print(type(c.system))
print(type(c.settings))
<class 'dynamite.physical_system.System'>
<class 'dynamite.config_reader.Settings'>
The physical system is comprised of components, which are stored in a list c.system.cmp_list
.
[4]:
print(f'cmp_list is a {type(c.system.cmp_list)}')
print(f'cmp_list has length {len(c.system.cmp_list)}')
cmp_list is a <class 'list'>
cmp_list has length 3
Let’s print some information about the components:
[5]:
for i in range(len(c.system.cmp_list)):
print(f'Information about component {i}:')
# Extract component i from the component list
component = c.system.cmp_list[i]
# Print the name of the component
print(f' name = {component.name}')
# Print a list of the names of the parameters of this component
parameters = component.parameters
parameter_names = [par0.name for par0 in parameters]
string = ' has parameters : '
for name in parameter_names:
string += f'{name} , '
print(string)
# Print the type of this component
print(f' type = {type(component)}')
# Does it contribute to the potential?
print(f' contributes to the potential? - {component.contributes_to_potential}')
Information about component 0:
name = bh
has parameters : m-bh , a-bh ,
type = <class 'dynamite.physical_system.Plummer'>
contributes to the potential? - True
Information about component 1:
name = dh
has parameters : c-dh , f-dh ,
type = <class 'dynamite.physical_system.NFW'>
contributes to the potential? - True
Information about component 2:
name = stars
has parameters : q-stars , p-stars , u-stars ,
type = <class 'dynamite.physical_system.TriaxialVisibleComponent'>
contributes to the potential? - True
Each component has a name, some parameters, and a type. Currently, DYNAMITE only supports this exact combination of component types:
one
Plummer
component representing the black holeone component representing the dark halo (DYNAMITE supports
NFW
and a number of additional dark halos, see API documentation)one
TriaxialVisibleComponent
representing the stellar body of the galaxy
In the future, we plan to support other components, and more flexible combinations of components.
For the stars - i.e. component 2 above - we must provide some input data files. The location of these files is specified in the configuration file, at
settings -> io_settings -> input_directory
and takes the value:
[6]:
c.settings.io_settings['input_directory']
[6]:
'NGC6278_input/dynamite_input/'
The names of the necessary input files are also specified in the configuration file, at the following locations:
system_components -> stars -> mge_pot
system_components -> stars -> mge_lum
system_components -> stars -> kinematics -> <kinematics name> --> datafile
system_components -> stars -> kinematics -> <kinematics name> --> aperturefile
system_components -> stars -> kinematics -> <kinematics name> --> binfile
which take as values the relevant filenames. You are free to give these files whatever name you like, as long as it is specified in the configuration file.
Let’s have a look at the MGE:
[7]:
c.system.cmp_list[2].mge_pot, c.system.cmp_list[2].mge_lum
[7]:
(MGE({'name': None, 'datafile': 'mge.ecsv', 'input_directory': 'NGC6278_input/dynamite_input/', 'data': <Table length=6>
I sigma q PA_twist
float64 float64 float64 float64
-------- -------- ------- --------
26819.14 0.49416 0.89541 0.0
2456.39 2.04299 0.79093 0.0
456.8 2.44313 0.9999 0.0
645.49 6.5305 0.55097 0.0
14.73 17.41488 0.9999 0.0
123.85 21.84711 0.55097 0.0, 'logger': <Logger dynamite.mges.MGE (DEBUG)>}),
MGE({'name': None, 'datafile': 'mge.ecsv', 'input_directory': 'NGC6278_input/dynamite_input/', 'data': <Table length=6>
I sigma q PA_twist
float64 float64 float64 float64
-------- -------- ------- --------
26819.14 0.49416 0.89541 0.0
2456.39 2.04299 0.79093 0.0
456.8 2.44313 0.9999 0.0
645.49 6.5305 0.55097 0.0
14.73 17.41488 0.9999 0.0
123.85 21.84711 0.55097 0.0, 'logger': <Logger dynamite.mges.MGE (DEBUG)>}))
The kinematic data are stored here:
[8]:
type(c.system.cmp_list[2].kinematic_data)
[8]:
list
Note that this object has type list
. This is because a single component can have multiple different sets of kinematic data. In this example, the first (and only) entry in the list is
[9]:
type(c.system.cmp_list[2].kinematic_data[0])
[9]:
dynamite.kinematics.GaussHermite
We see that this kinematics object has type GaussHermite
. This was also specified in the configuration file, under
system_components -> stars -> kinematics --> kinset1 --> type
In addition to GaussHermite
, DYNAMITE also supports BayesLOSVD
kinematics (see documentation).
The kinemtic data itself can be accessed as follows:
[10]:
c.system.cmp_list[2].kinematic_data[0].data
[10]:
vbin_id | v | dv | sigma | dsigma | h3 | dh3 | h4 | dh4 |
---|---|---|---|---|---|---|---|---|
int64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 |
1 | -44.7518 | 2.0988 | 211.7829 | 1.9654 | 0.0 | 0.005 | 0.0 | 0.005 |
2 | -69.2798 | 2.3608 | 188.883 | 2.1766 | 0.0 | 0.005 | 0.0 | 0.005 |
3 | -70.8007 | 3.9338 | 177.095 | 3.7142 | 0.0 | 0.005 | 0.0 | 0.005 |
4 | -47.9191 | 3.4617 | 184.1865 | 3.0684 | 0.0 | 0.005 | 0.0 | 0.005 |
5 | -30.5932 | 2.386 | 208.2472 | 2.2207 | 0.0 | 0.005 | 0.0 | 0.005 |
6 | -76.5504 | 5.5494 | 162.3144 | 4.572 | 0.0 | 0.005 | 0.0 | 0.005 |
7 | -49.8285 | 4.4211 | 174.0705 | 3.6461 | 0.0 | 0.005 | 0.0 | 0.005 |
8 | -35.7514 | 3.5335 | 180.28 | 3.3672 | 0.0 | 0.005 | 0.0 | 0.005 |
9 | -75.4144 | 3.5041 | 139.9438 | 3.9235 | 0.0 | 0.005 | 0.0 | 0.005 |
10 | -43.617 | 4.1029 | 175.4291 | 3.7975 | 0.0 | 0.005 | 0.0 | 0.005 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
142 | 136.8294 | 4.5934 | 107.5522 | 4.9049 | 0.0 | 0.005 | 0.0 | 0.005 |
143 | 130.3479 | 8.6243 | 119.4998 | 4.3771 | 0.0 | 0.005 | 0.0 | 0.005 |
144 | 142.0869 | 13.3664 | 95.5229 | 6.7464 | 0.0 | 0.005 | 0.0 | 0.005 |
145 | 111.6049 | 4.8763 | 120.454 | 4.4527 | 0.0 | 0.005 | 0.0 | 0.005 |
146 | 120.9348 | 3.9434 | 107.9628 | 4.4038 | 0.0 | 0.005 | 0.0 | 0.005 |
147 | 123.2916 | 5.2241 | 110.2003 | 5.0809 | 0.0 | 0.005 | 0.0 | 0.005 |
148 | 146.468 | 5.5686 | 102.5112 | 4.2288 | 0.0 | 0.005 | 0.0 | 0.005 |
149 | 185.5138 | 6.2494 | 78.0394 | 4.6495 | 0.0 | 0.005 | 0.0 | 0.005 |
150 | 153.1489 | 4.2502 | 89.5659 | 4.0578 | 0.0 | 0.005 | 0.0 | 0.005 |
151 | 114.6925 | 5.827 | 100.1592 | 6.2472 | 0.0 | 0.005 | 0.0 | 0.005 |
152 | 197.743 | 3.9056 | 65.0177 | 5.4738 | 0.0 | 0.005 | 0.0 | 0.005 |
Creating a Schwarzschild model¶
The next step will be to create a model, i.e. a dyn.model.Model
object for a particular parset
. This is a particular set of values for each of the parameters of the model. In the configuration file, every parameter has a been given a value
. We can extract and inspect a parameter set specified by these values as follows:
[11]:
parset = c.parspace.get_parset()
print(parset)
m-bh a-bh c-dh f-dh q-stars p-stars u-stars ml
----------------- ----- ---- ---- ------- ------- ------- ---
158489.3192461114 0.001 8.0 10.0 0.54 0.99 0.9999 5.0
Note that parameters which have been specified as logarithmic, i.e. those configured as
parameters -> XXX -> logarithmic : True
are exponentiated in this table, while their value is logarithmic in the configuration file.
More details can be found in the documentation and in the tutorial “Parameter Space” (5_parameter_space.ipynb
).
DYNAMITE uses the ModelIterator
object to run models. In this case, only one model will be run because the configuration file fixes all parameters to their respective values (fixed: True
). In the following tutorial “Model Iterations and Plots” (3_model_iterations_and_plots.ipynb
) we will see how to run a suite of models. To better understand what the model iterator does, let’s read the internal documentation (i.e. the docstring) for the class:
class ModelIterator(object):
"""Iterator for models
Creating this ``ModelIterator`` object will (i) generate parameters sets,
(ii) run models for those parameters, (iii) check stopping criteria, and
iterate this procedure till a stopping criterion is met. This is implemented
by creating a ``ModelInnerIterator`` object whose ``run_iteration`` method
is called a number of times.
Parameters
----------
config : a ``dyn.config_reader.Configuration`` object
model_kwargs : dict
other kewyord argument required for this model
do_dummy_run : Bool
whether this is a dummy run - if so, dummy_chi2_funciton is executed
instead of the model (for testing!)
dummy_chi2_function : function
a function of model parameters to be executed instead of the real model
plots : bool
whether or not to make plots
"""
def __init__(self,
config=None,
model_kwargs={},
do_dummy_run=None,
dummy_chi2_function=None,
plots=True):
All we need to do is pass the configuration object c
when we instantiate the ModelIterator
. The following step will take a few minutes (we will not need the ModelIterator
object itself, so we discard the return value):
[12]:
_ = dyn.model_iterator.ModelIterator(config=c)
[INFO] 21:39:30 - dynamite.model_iterator.ModelIterator - SpecificModels: iterations 0 and 1
[INFO] 21:39:30 - dynamite.parameter_space.SpecificModels - Found ONE individual model.
[INFO] 21:39:30 - dynamite.parameter_space.SpecificModels - SpecificModels added 1 new model(s) out of 1
[INFO] 21:39:30 - dynamite.parameter_space.SpecificModels - Found ONE individual model.
[INFO] 21:39:30 - dynamite.parameter_space.SpecificModels - SpecificModels added 0 new model(s) out of 1
[INFO] 21:39:30 - dynamite.model_iterator.ModelInnerIterator - ... running model 1 out of 1
[INFO] 21:39:30 - dynamite.orblib.LegacyOrbitLibrary - Calculating initial conditions
[INFO] 21:40:15 - dynamite.orblib.LegacyOrbitLibrary - ...done - cmd_orb_start exit code 0. Logfile: NGC6278_output/models/orblib_000_000/datfil/orbstart.log.
[INFO] 21:40:15 - dynamite.orblib.LegacyOrbitLibrary - Integrating orbit library tube and box orbits
[INFO] 21:40:24 - dynamite.orblib.LegacyOrbitLibrary - ...done - cmd_tube_box_orbs exit code 0. Logfiles: NGC6278_output/models/orblib_000_000/datfil/orblib.log, NGC6278_output/models/orblib_000_000/datfil/orblibbox.log, NGC6278_output/models/orblib_000_000/datfil/triaxmass.log, NGC6278_output/models/orblib_000_000/datfil/triaxmassbin.log.
[INFO] 21:40:24 - dynamite.weight_solvers.NNLS - Using WeightSolver: NNLS/scipy
[INFO] 21:40:27 - dynamite.weight_solvers.NNLS - NNLS problem solved
[INFO] 21:40:27 - dynamite.analysis.Analysis - Getting model projected masses and losvds.
[INFO] 21:40:31 - dynamite.config_reader.Configuration - Config file copied to NGC6278_output/models/orblib_000_000/ml05.00/NGC6278_config_single.yaml.
[INFO] 21:40:31 - dynamite.model_iterator.ModelInnerIterator - Model 1: NGC6278_output/models/orblib_000_000/ml05.00/model_done_staging.ecsv written.
[INFO] 21:40:31 - dynamite.model_iterator.ModelInnerIterator - Iteration done, 1 model(s) calculated.
[INFO] 21:40:31 - dynamite.model_iterator.ModelInnerIterator - 1 staging file(s) deleted.
[INFO] 21:40:31 - dynamite.plotter.Plotter - kinchi2 vs. model id plot created (1 models).
[INFO] 21:40:31 - dynamite.plotter.Plotter - Plot NGC6278_output/plots/kinchi2_progress_plot.png saved in NGC6278_output/plots/
[INFO] 21:40:31 - dynamite.plotter.Plotter - Making chi2 plot scaled according to kinchi2
[INFO] 21:40:31 - dynamite.plotter.Plotter - Plot NGC6278_output/plots/kinchi2_plot.png saved in NGC6278_output/plots/
[INFO] 21:40:31 - dynamite.plotter.Plotter - Plotting kinematic maps for 1 kin_sets.
[INFO] 21:40:31 - dynamite.plotter.Plotter - Plotting kinematic maps for kin_set no 0: califa
[INFO] 21:40:31 - dynamite.analysis.Analysis - Getting model projected masses and losvds.
[INFO] 21:40:31 - dynamite.weight_solvers.NNLS - Using WeightSolver: NNLS/scipy
[INFO] 21:40:34 - dynamite.weight_solvers.NNLS - NNLS solution read from existing output
[INFO] 21:40:41 - dynamite.plotter.Plotter - Kinematic map written to NGC6278_output/plots/kinematic_map_califa.png.
[INFO] 21:40:41 - dynamite.model_iterator.ModelIterator - SpecificModels: iteration 2
[INFO] 21:40:41 - dynamite.parameter_space.SpecificModels - Found ONE individual model.
[INFO] 21:40:41 - dynamite.parameter_space.SpecificModels - SpecificModels added 0 new model(s) out of 1
[INFO] 21:40:41 - dynamite.model_iterator.ModelIterator - Stopping at iteration 3
A lot happened here: when run for the first time, the particular parset
is new, so DYNAMITE creates a new entry in AllModels.table and assigns a model directory that will hold the results. The next step is to calculate the orbit library and then DYNAMITE finds out which orbits are useful for reproducing the observations. This is an Non-Negative Least Squares (NNLS) optimization problem resulting in a certain chi-squared value. Let’s first have a look at the all models table:
[13]:
c.all_models.table
[13]:
m-bh | a-bh | c-dh | f-dh | q-stars | p-stars | u-stars | ml | chi2 | kinchi2 | kinmapchi2 | time_modified | orblib_done | weights_done | all_done | which_iter | directory |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | str256 | bool | bool | bool | int64 | str256 |
158489.3192461114 | 0.001 | 8.0 | 10.0 | 0.54 | 0.99 | 0.9999 | 5.0 | 31349.21565175545 | 14861.370236613006 | 19795.503455835726 | 2024-02-22T20:40:31.000 | True | True | True | 0 | orblib_000_000/ml05.00/ |
This table is stored in the all_models_file
in the output_directory
as defined in the configuration file:
[14]:
c.settings.io_settings['output_directory'], c.settings.io_settings['all_models_file']
[14]:
('NGC6278_output/', 'all_models.ecsv')
In the output directory we find the AllModels.table
and a models/
subfolder (in our case, NGC6278_output/all_models.ecsv
and NGC6278_output/models/
, respectively), which hold the model parameters, status, and results in the so-called model directories as stated in the AllModels.table
.
Let’s look into how to access information about specific models in the AllModels.table
(see the Model API documentation for more information). We start with instantiating a dyn.model.Model
object from the table (here we use the only model in the table, which has index 0):
[15]:
model = c.all_models.get_model_from_row(0)
[16]:
model.parset # Verify the model's parameter set
[16]:
m-bh | a-bh | c-dh | f-dh | q-stars | p-stars | u-stars | ml |
---|---|---|---|---|---|---|---|
float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 |
158489.3192461114 | 0.001 | 8.0 | 10.0 | 0.54 | 0.99 | 0.9999 | 5.0 |
The model’s directory name is constructed by considering the standard name for new models and their ml
value. Here, we are at the first iteration 000
of the ModelIterator
and at the first model 000
inside this iteration:
[17]:
model.directory
[17]:
'NGC6278_output/models/orblib_000_000/ml05.00/'
Congratulations! You have run your first Schwarzschild model using DYNAMITE!
The chi-squared of this model is:
[18]:
orblib = model.get_orblib()
model.get_weights(orblib) # Read weights if already calculated. If not, calculate weights.
model.chi2
[INFO] 21:40:41 - dynamite.weight_solvers.NNLS - Using WeightSolver: NNLS/scipy
[INFO] 21:40:44 - dynamite.weight_solvers.NNLS - NNLS solution read from existing output
[18]:
31349.21565175545
Is that good? At this point, we don’t know! To find out, we will have to run more models and compare their chi-squared values. For information on how to do this, see the following tutorial “Model Iterations and Plots” (3_model_iterations_and_plots.ipynb
).
Plot the Models¶
Now let’s look at some output for the model that we have just run. You might have noticed that the ModelIterator
also created a directory for plots:
[19]:
c.settings.io_settings['plot_directory']
[19]:
'NGC6278_output/plots/'
This directory contains some diagnostic plots. In a run with multiple models, these plots will be updated as the calculations progress and reflect the latest state in model parameters, the chi-squared values, and the best-fit kinematic maps.
Here, we want to plot kinematic maps for our specific model. After instantiating a dyn.Plotter
object, we call the appropriate plotting method on our model. Please refer to the Plotting API documentation for more information.
[20]:
plotter = dyn.plotter.Plotter(config=c)
figure = plotter.plot_kinematic_maps(model)
[INFO] 21:40:44 - dynamite.plotter.Plotter - Plotting kinematic maps for kin_set no 0: califa
[INFO] 21:40:44 - dynamite.analysis.Analysis - Getting model projected masses and losvds.
[INFO] 21:40:44 - dynamite.weight_solvers.NNLS - Using WeightSolver: NNLS/scipy
[INFO] 21:40:47 - dynamite.weight_solvers.NNLS - NNLS solution read from existing output
[INFO] 21:40:53 - dynamite.plotter.Plotter - Kinematic map written to NGC6278_output/plots/kinematic_map_califa.png.
The top row shows the data, the middle row shows the model, and the bottom row shows the residuals. The columns, from left to right, are the stellar surface density, the mean velocity \(V\), the velocity dispersion \(\sigma\), and the \(h_3\) and \(h_4\) moments. In the figure, we can see that:
the model and data surface densities are very similar
the sense of rotation of the \(V\) map is reproduced well, even though the amplitude is lower than observed
the \(\sigma\), \(h_3\) and \(h_4\) maps are less well reproduced
While the fit is certainly not perfect, it is reassuring to see that some features are already reproduced well. To improve the fit, we will have to explore the parameter space more fully. See the following tutorial “Model Iterations and Plots” (3_model_iterations_and_plots.ipynb
) for more details.
Exercise¶
Manually adjust a model parameter, run this new model adding it to the all models table, inspect the new table, and plot the new model’s kinematic maps:
Adjust a model parameter, e.g. change the black hole mass from 5.0 to 5.2 (in the configuration file:
system_components -> bh -> parameters -> m -> value
).Read the new configuration file and look at the existing all models table.
[21]:
c = dyn.config_reader.Configuration(fname, reset_logging=True, reset_existing_output=False)
c.all_models.table
[INFO] 21:40:56 - dynamite.config_reader.Configuration - Config file NGC6278_config_single.yaml read.
[INFO] 21:40:56 - dynamite.config_reader.Configuration - io_settings...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - Output directory tree: NGC6278_output/.
[INFO] 21:40:56 - dynamite.config_reader.Configuration - system_attributes...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - model_components...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - system_parameters...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - orblib_settings...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - weight_solver_settings...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - Will attempt to recover partially run models.
[INFO] 21:40:56 - dynamite.config_reader.Configuration - parameter_space_settings...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - multiprocessing_settings...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - ... using 4 CPUs for orbit integration.
[INFO] 21:40:56 - dynamite.config_reader.Configuration - ... using 4 CPUs for weight solving.
[INFO] 21:40:56 - dynamite.config_reader.Configuration - legacy_settings...
[INFO] 21:40:56 - dynamite.config_reader.Configuration - System assembled
[INFO] 21:40:56 - dynamite.config_reader.Configuration - Configuration validated
[INFO] 21:40:56 - dynamite.config_reader.Configuration - Instantiated parameter space
[INFO] 21:40:56 - dynamite.model.AllModels - Previous models have been found: Reading NGC6278_output/all_models.ecsv into AllModels.table
[INFO] 21:40:56 - dynamite.config_reader.Configuration - Instantiated AllModels object
[INFO] 21:40:56 - dynamite.model.AllModels - No all_models table update required.
[21]:
m-bh | a-bh | c-dh | f-dh | q-stars | p-stars | u-stars | ml | chi2 | kinchi2 | kinmapchi2 | time_modified | orblib_done | weights_done | all_done | which_iter | directory |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | str256 | bool | bool | bool | int64 | str256 |
158489.3192461114 | 0.001 | 8.0 | 10.0 | 0.54 | 0.99 | 0.9999 | 5.0 | 31349.21565175545 | 14861.370236613006 | 19795.503455835726 | 2024-02-22T20:40:31.000 | True | True | True | 0 | orblib_000_000/ml05.00/ |
Inspect the new parameter values given in the configuration file.
[22]:
c.parspace.get_parset()
[22]:
m-bh | a-bh | c-dh | f-dh | q-stars | p-stars | u-stars | ml |
---|---|---|---|---|---|---|---|
float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 |
158489.3192461114 | 0.001 | 8.0 | 10.0 | 0.54 | 0.99 | 0.9999 | 5.0 |
Run the new model defined by this new parameter set and inspect the new all models table. Did the chi-squared improve?
[23]:
_ = dyn.model_iterator.ModelIterator(config=c)
c.all_models.table
[INFO] 21:40:56 - dynamite.model_iterator.ModelIterator - SpecificModels: iteration 1
[INFO] 21:40:56 - dynamite.parameter_space.SpecificModels - Found ONE individual model.
[INFO] 21:40:56 - dynamite.parameter_space.SpecificModels - SpecificModels added 0 new model(s) out of 1
[INFO] 21:40:56 - dynamite.model_iterator.ModelIterator - Stopping at iteration 2
[23]:
m-bh | a-bh | c-dh | f-dh | q-stars | p-stars | u-stars | ml | chi2 | kinchi2 | kinmapchi2 | time_modified | orblib_done | weights_done | all_done | which_iter | directory |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | float64 | str256 | bool | bool | bool | int64 | str256 |
158489.3192461114 | 0.001 | 8.0 | 10.0 | 0.54 | 0.99 | 0.9999 | 5.0 | 31349.21565175545 | 14861.370236613006 | 19795.503455835726 | 2024-02-22T20:40:31.000 | True | True | True | 0 | orblib_000_000/ml05.00/ |
Plot the new model’s kinematic maps (the new model is in the last row of the table).
[24]:
model = c.all_models.get_model_from_row(-1)
plotter = dyn.plotter.Plotter(config=c)
figure = plotter.plot_kinematic_maps(model)
[INFO] 21:40:56 - dynamite.plotter.Plotter - Plotting kinematic maps for kin_set no 0: califa
[INFO] 21:40:56 - dynamite.analysis.Analysis - Getting model projected masses and losvds.
[INFO] 21:40:56 - dynamite.weight_solvers.NNLS - Using WeightSolver: NNLS/scipy
[INFO] 21:40:59 - dynamite.weight_solvers.NNLS - NNLS solution read from existing output
[INFO] 21:41:06 - dynamite.plotter.Plotter - Kinematic map written to NGC6278_output/plots/kinematic_map_califa.png.
Experiment some more with adding new models to the all models table…