Adding a result module¶
A tracer result module is fundamentally a plugin that is run on each tracer at each snapshot, unless there are reasons not to run it. Adding such a plugin means creating a new memory object, new code files, and adding instructions for SPARTA how to use the plugin. These changes constitute a non-trivial modification of the code, so please read the introductory documentation and make sure you understand the code for other tracer results. To add a new result, you need to add the following changes, listed on a per-file basis:
In the section called “TRACER RESULTS”, you will need to add a switch that determines whether your result is written to the output files. This switch should be called
OUTPUT_RESULT_XXXwhere “XXX” stands for the name of your result (which needs to differ from all other results and, ideally, analyses).
You may add additional switches for particular fields. For example, if your result contains a field “YYY”, there should be a switch
Make sure to generously add comments that clearly explain what your result does and what options the user has.
This file contains the compile-time dependency system used by SPARTA, meaning that it determines which parts of the code are executed. These decisions depend on the outputs chosen by the user in a non-trivial way, since results and analyses can depend on other results and analyses, even if the latter are not written to file. If your results depends on other results or analyses, make sure to add the corresponding decisions.
Add your result to the
In the following section, the lengths of the “stencils” are determined, meaning the number of snapshots that are saved in time for tracers and other data. If your result demands a certain minimum number of snapshots, set the stencil accordingly. Note that increasing the size of stencils can have a very large effect on SPARTA’s memory consumption!
In the section titled “Array Indices”, add a three-letter code for your result, similar to
IFLfor infall or
SBKfor splashback. This is the index of your result in any result-ordered array.
Typically, your result will occupy memory in the form of a dynamical array (see below). Add a memory ID such as
If there are any configuration parameters associated with your result, add the defaults using #define.
Add the fields to the
writeConfig, add your compile-time switches to the output, e.g.
PRINT_SETTING(OUTPUT_RESULT_XXX). If your result has config parameters, also add those.
If your result has no config parameters, you can ignore this file.
setDefaultConfig, set the defaults you created.
readConfigFile, add loops to check for the names of your parameters and set them.
checkConfigUser, check the parameters for erroneous input (e.g., negative values etc).
printConfig, add your parameters to the output.
This unit defines most datatypes used in SPARTA, and your result will be one such datatype. You will need to add a new DynArray type, a forward declaration, and mofidy the
DynArraytype to also contain your new type.
Declare the actual definition of your struct
Add an initializer function
addResultXxx. All of these steps are easy to perform by copying the corresponding code parts for an existing result.
Add code files
These files contain the actual code for your tracer result plugin. The easiest way to create them is to copy files from a different result, replace the name everywhere, and delete the content of the routines.
Your code files will typically need to contain certain routines, including
outputConfigResultXxx(if there are any config parameters specific to your result),
runResultXxx(the routine that is run on each tracer), and
outputFieldsResultXxxwhich sets the output fields that are written to file.
ttpropsstruct initialization, you need to choose how your result acts on tracers in a number of situations (see details below).
rsprops, you need to set the correct values. This struct contains basically all the information SPARTA needs about your result. The three-letter short name should be the same (non-capitalized) name you chose for an index in
src/global.h. The DynArray type should of course be the type you created previously. The function pointers can be
NULL, in which case no function is executed. For example, if your result has no config parameters, you can set
NULL, your result will have no effect in that it will never be run on a tracer.
In the output fields function, note that you do not need to actually output anything; the output module takes care of that. You only need to tell the output module which fields should be written out and where in your struct it can find them. See existing code for examples. Make sure to respect the switches you created in
printTypeSizes, add the size of your result type to the output.
The compile-time parameters such as
DO_RESULT_XXX should be confined to the files and
code segments listed above. If they are used anywhere else in the code, that is a sign that
your code needs to be structured differently!
One particularly tricky aspect are the instructions listed in
global_types.c. These instructions
correspond to particular situations when a tracer is born, and your result can respond to these
situations with a set of statuses (see
For example, you can decide what happens if a tracer is born inside a new halo. In this case, the
INSTR_IN_NEW. If your result does not care whether the infall was tracked, you
probably want to set
RS_STATUS_SEEKING, i.e., your result is on. If your result cannot be
determined in this situation, you might instead set
Note that you need to set an instruction for each situation and each tracer type, since you may want to treat subhalo and particle tracers differenty.