Adding Outputs
Adding a derived variable
Derived variables are variables which are defined on the
Cartesian spatial grid but are not directly updated by the solver. They are
calculated when needed for output or for use in other physics packages. The
final form of a derived variable is an array on each processor with the same
size as the field arrays. Examples include number_density
, ekbar
and
poynting_flux
.
A derived variable is defined on the same grid as the main simulation variables and must be written to disk in such a way as to stitch the parts of the grid from each processor together. This is achieved using the routine:
CALL sdf_write_plain_variable(sdf_handle, id, name, units, dims, stagger, &
grid_id, variable, subtype_field, subarray_field)
The parameters have the following types and meanings:
- block_id - The id name of the variable. This character string is a unique identifier for the variable in the file enabling a program to retrieve it later. Once defined it should not change so that newer versions of EPOCH can still identify variables generated by older versions.
- name - The display name of the variable. This character string is the name that is used by external programs to display an identifying name for the variable. If it contains ‘/’ characters then these are used by VisIt to group the variables.
- units - The units of the variable. This character string is used when displaying the data units. For most variables in EPOCH these are SI units.
- dims - An nD integer array containing the GLOBAL length of the variable across all processors. In EPOCH a variable actually called “dims” exists for variables which are the same size as the default field variables.
- stagger - An integer constant containing the stagger of a variable from the cell centre of a cell. This property lets external programs know the position of a variable on the grid.
- grid_id - The id name of the grid to which the variable is attached. In EPOCH, the main grid is just called “grid”. Note that this property is case sensitive.
- variable - The actual variable to be written to disk.
- subtype_field - This is an MPI type representing the layout of the data across the processors. For a standard field variable, there is an automatically created type called “subtype_field” which should be used here.
- subarray_field - This is an MPI type representing the section of the “variable” parameter to be written. For a standard field variable, there is an automatically created type called “subarray_field” which should be used here.
It’s probably easiest to read the diagnostics.F90 file and see how the code implements the output of simple variables like ex or ey for an example of how this works. Once the appropriate sdf_write call has been added to the code, there is no further work to be done. The IDL, MatLab and VisIt routines will all read the existence of the variable from the metadata in the SDF file, and it will now be available to view in all SDF reading packages.
There is a working variable called array
which is large enough to
store a derived variable. It is
therefore recommended that to calculate derived variables a new subroutine
should be created which populates array
with the required variable
and then writes it to disk. An example would look like:
IF (IAND(dumpmask(c_dump_myvar), code)) THEN
CALL calc_my_variable(array)
CALL sdf_write_plain_variable(sdf_handle, 'my_var', 'Mine/variable', 'unit',
dims, c_stagger_cell_centre, 'grid', array, subtype_field, subarray_field)
ENDIF
where calc_my_variable
is a function which calculates the
variable which you wish to write. The form of this function depends on the type
of variable to be calculated and is given in the next section.
Adding a particle variable
The next simplest type of output to add is a new property for all particles. To add new particle variables to the output dump, two things are needed: a call to the SDF command to write the data and an iterator function to iterate through all the particles. NOTE: This section only deals with new outputs for existing particle variables. Creation of a new particle variable is more involved, and requires modifying MPI routines.
The iterators are stored in the file
iterators.F90
. An example iterator is:
! iterator for particle momenta
FUNCTION iterate_px(array, n_points, start)
REAL(num) :: iterate_px
REAL(num), DIMENSION(:), INTENT(OUT) :: array
INTEGER, INTENT(INOUT) :: n_points
LOGICAL, INTENT(IN) :: start
TYPE(particle), POINTER, SAVE :: cur
TYPE(particle_list), POINTER, SAVE :: current_list
INTEGER :: part_count
IF (start) THEN
CALL start_particle_list(current_species, current_list, cur)
ENDIF
part_count = 0
DO WHILE (ASSOCIATED(current_list) .AND. (part_count .LT. n_points))
DO WHILE (ASSOCIATED(cur) .AND. (part_count .LT. n_points))
part_count = part_count + 1
array(part_count) = cur%part_p(1)
cur=>cur%next
ENDDO
! If the current partlist is exhausted, switch to the next one
IF (.NOT. ASSOCIATED(cur)) CALL advance_particle_list(current_list, cur)
ENDDO
n_points = part_count
iterate_px = 0
END FUNCTION iterate_px
This is a fairly complicated routine which includes code for dealing with the possibility of particle species not being dumped, and other complicated book keeping. Luckily, there is only one line in the routine which needs to change to output a new variable. This being:
array(part_count) = cur%part_p(1)
To write a new iterator, you just have to copy the skeleton of an existing
iterator and change this line to copy your particle property into the “array”
array. The details of the particle structure’s contents is explained
here.
Once your new iterator has been written and added into
the iterators.F90
file, it’s time to add the SDF routine to actually
write the data. The routine is:
CALL write_particle_variable(c_dump_id, code, name, iterator)
The parameters this time are
- c_dump_id - The index into the dumpmask for this variable.
- code - The dump code for the current output dump.
- name - The display name to use for this variable.
- iterator - The name of the iterator function that you created in the previous step. Note that this is not a string but simply the name of the function.
Once again, looking at how this is implemented for one of the existing variables (e.g. px) is probably the most enlightening way to see how it works. As for the fluid variables, the new variable will appear in IDL, MatLab and VisIt.
At this point it is possible to write any property which is similar to the default field variables or the default particle properties. It becomes slightly more challenging if you want to write other types of variable into an output file.