Tracking Module Description

Tracking

During the runtime of simulations, the user needs to keep track of the simultation state without being obliged to write out the complete domain to disk. This is achieved by tracking objects, at which the state is evaluated at certain defined intervals and then written to disk.

Tracking format

We support three formats for tracking.

  • "ascii"

Transient data: simple gnuplot-style A simple ascii file which creates a small header and then writes at each defined time step a column wise representation of all variables and points. This is not efficient and should only be used for simple point-tracking objects. Each process writes its own file.

output = {
  format = 'ascii',
},
folder = './tracking/'
  • "asciiSpatial"

Spatial Data: This format stores solution data along with coordinates in single data file for every timestep. Therefore, there would be multiple files depending on the total number of time-steps. It is ideal for tracking line and plane.

output = {
  format = 'asciiSpatial',
},
folder = './tracking/'
  • "Harvester Format"

Writes all participating elements to a treelm mesh and creates for each required time step a restart file. The output is done in vtk and pvd files that can be visualised with Paraview.

This is a scalable tracking object which works regardless of number of processes.

output = {
  format = 'vtk', 
},
folder = './output/'

Tracking variable types

  • "variables"

All variables defined in the tem_varSys_module can be tracked. See tem_variable_module for how to define variables.

  • derived variables: all variables defined in the global variable system can be tracked

  • spacetime: as analytical result, can be defined in lua file

  • tem_reduction_spatial_module reductions, e.g. difference, sum or average of defined variables

Tracking shapes

We show the tracking with simple shapes here. Get an overview over all existing shapes in tem_shape_module and examples are given here

  • zero-dimensional: point
  • one-dimensional: line
  • two-dimensional: plane
  • three-dimensional: cubes

So far point, line, plane are implemented in tem_shape_module.

Usage

The user specifies the desired parameters in the configuration file (in the scheme table) as

-- if you want to have a analytical solution as reference, you can add 
--  a spacetime variable first
-- define single new (spacetime) variable
variable = { 
  {
    name='spacetime', 
    ncomponents=1, 
    kind = 'st_fun',
    st_fun = luaFun1 
  },
  {
    name='spacetime2', 
    ncomponents=1, 
    kind = 'st_fun',
    st_fun = luaFun2 
  },
  { 
    name='dens_diff', 
    ncomponents=1, 
    kind = 'operation',
    operation = {
      kind = 'difference'
      input_varname = {
        'density','spacetime'
      }
    }
  },
  { 
    name='wss_diff', 
    ncomponents=1, 
    kind = 'operation',
    operation = {
      kind = 'difference'
      input_varname = {
        'wss','spacetime2'
      }
    }
  }
}

-- Tracking
tracking = {
  { 
    label = 'probe_error',
    variable = {
      'velocity','dens_diff','wss_diff'
    },
    folder = './tracking/',
    output = {
      format = 'ascii'
    },
    time = {
      interval = 1, 
      min = 1000, 
      max = 4000 
    },
    reduction = {
      'l2norm',
      'l2norm',
      'l2norm'
    },  
    shape = { 
      kind = 'canoND',
      object = { 
        origin ={0.,0.,0.},
        vec = {1.,0.,0.}, 
        segments={100,100,100}
      }
    }
  }
} 

Reduction

The tem_reduction_spatial_module takes a set of input quantities and reduces them according to the chosen operation. You can choose between the following operations: - average: Average of all occurring values - sum: Sum of all occurring values - max: Maximum of all occurring values - min: Minimum of all occurring values - l2norm: L2 norm of all values, i.e. L_2(x) = sqrt( sum( x_i^2 )) - linfnorm: L_inf norm of all values, i.e. L_inf(x) = max( | x_i | )

reduction = {
              'norm' -- 'average' or 'sum'
            }

tracking = {
  variable = {'pressure', 'velMag', 'density'},
  reduction = { 'average', 'max', l2norm' }
}

Using different shapes

Here, a point at the location {0.,0.,0.} is defined as a pressure probe. The interval is set to 1, meaning at each time step, the pressure has to be written. The probing starts at simulation time 1000 and lasts until 4000. The tracking write both pressure and velocityX in a single file. Use ref_value to normalize the output.

# Name:       GaussPulse_TestSimulation     Date 2011-060-27  Time 11:43 CEST
# Probe type: Point at {0.0 0.0 0.0} 
# Quantities: pressure, velocityX
# tMin:       1000,     tMax:    4000,     Interval: 1
# ref_value: 1.0, 0.01
#   iTime     rTime      Pressure           velocityX
1000          1000.0     1.0241818          0.00158287
1001          1001.0     1.0251427          0.00152617
...                                      
4000          4000.0     1.7162511          0.01273673

The shape is defined as a canonical object. The different shapes are basically derivatives of a simple cube. A cube with no length in any direction is a point, a cube with length along only one axis is a line whereas a cube with length along two axes is simply treated as plane by the underlying code. One example each for Point, Line and Plane is shown below.

Point Tracking

Example: tracking a point in ASCII format

tracking = { label = 'Velocity', 
variable = {'velocity'},   -- options: density, velocity

--   Tracking over a point
shape={kind = 'canoND', origin = {0.5,0.5,0.5} },

time = {min = 0, interval = 1},     -- if no max given: active for all times
output = {format = 'ascii'},
folder = 'tracking/'}
}

Once, the above section is executed within the musubi.lua file, an output in the asciiTransient format is generated in the output folder specified (tracking in this particular example). Now, we open the result file inside tracking folder, the structure of which looks like below:

# Rank of the process:       0
#               time     velocity_01     velocity_02     velocity_03
1.0000  0.000000000000  0.000000000000  0.000000000000
2.0000  0.000000000000  0.000000000000  0.000000000000
3.0000  0.000000000000  0.000000000000  0.000000000000
4.0000  0.000000000000  0.000000000000  0.000000000000
...
...
1997.0000 -0.006065558329  0.000443400622 -0.000003481789
1998.0000 -0.006063901533  0.000443795703 -0.000003286949
1999.0000 -0.006061596302  0.000443327890 -0.000003534752
2000.0000 -0.006059665212  0.000443720604 -0.000003339771

Here, it can be noticed that 3 velocity components for all time steps at the point (0.5, 0.5, 0.5) are stored. The interval was chosen as 1, so they are tracked for each time step. If the interval was chosen as say 10, then the tracking would have been done after 10 units of simulated time.

Line Tracking

We need to set the origin and the direction vector, as e.g. {origin={0.,0.,0.}, vec={1.0,1.0,1.0}}. The line is represented as a list of points in the tracking facility. The number of subdivisions and its distribution of the points on the line needs to be set, as e.g. segments=500, distribution='equal'. Make sure to specify enough segments to take into account all the required elements on the line. Elements are added only once, so it might be beneficial to specify much more segments than actually needed to consider elements on the highest levels as well.

Example: Tracking a line in ASCII Spatial format

tracking = { 
  label = 'line_probe',
  variable = {'state'}, -- state (=pdfs), pressure, density etc
  shape = { kind = 'canoND', 
            object={
              origin = {0.5,0.5,0.5}, 
              vec = { {0.0,0.2,0.0}},
              segments = {300},
              distribution='equal'} 
          },
  output = {format='asciispatial'}, 
  folder='tracking/',
  time = {interval = 5, min = 0, max = 800 } }
}

After, the above tracking is executed within musubi.lua file multiple res files are obtained inside the tracking folder each specific to particular time step. If you open any one of the 'res' files, there will be six data columns: three coordinate and three velocity components. An example is shown below:

# Rank of the process:       0
#         coordX          coordY          coordZ     velocity_01     velocity_02     velocity_03
0.51562500      0.51562500      0.51562500 -0.000998448727 -0.000118182367  0.000007560959
0.51562500      0.54687500      0.51562500 -0.000922746216  0.000011023243 -0.000000130462
0.51562500      0.57812500      0.51562500 -0.001083956104  0.000038534363 -0.000003774649
...
0.51562500      0.64062500      0.51562500 -0.001343981219 -0.000131107478 -0.000004381864
0.51562500      0.67187500      0.51562500 -0.001261956611  0.000081027056  0.000000215364
0.51562500      0.70312500      0.51562500 -0.001733303068  0.000060154818  0.000005793207

Out of three coordinate components, only 'coordY' is varying and 'coordX', 'coordZ' remain constant. This is according to our tracking input with origin = {0.5, 0.5, 0.5}, vec = {0.0, 0.2, 0.0}. You can now make a line plot with any one of velocity components with respect to 'coordY' in gnuplot.

Plane Tracking

We need to set the origin and the direction vectors, as e.g. object = {origin={0.,0.,0.}, vec={{1.0,1.0,1.0},{0.0,-1.0,1.0}}}. The plane is, just as the line, represented as a list of points in the tracking facility. The number of subdivisions in each direction and its distribution of the points on the plane needs to be set, as e.g. segments1=500, segments2=300, distribution='equal'. Make sure to specify enough segments to take into account all the required elements on the line. Elements are added only once, so it might be beneficial to specify much more segments than actually needed to consider elements on the highest levels as well.

Example: tracking a plane in harvester format

tracking = { 
  label = 'plane_probe',
  variable = {'state'}, -- state (=pdfs), pressure, density etc
  shape = { kind = 'canoND', 
            object={
              origin = {-75.,-15.,0.}, 
              vec = { {150.,0,0.}, {0.,30,0.}},
              segments = {300, 300},
              distribution='equal'} 
          },
  output = {format='vtk'}, 
  folder='tracking/',
  time = {interval = 5, min = 0, max = 800 } }
}

It will result in vtk files at the given time steps and one pvd file that is an animation file over all vtk files.

Global mesh tracking

Example: tracking the whole mesh

tracking = { 
  ...
  shape = { kind = 'all' },
  -- or:
  shape = { kind = 'global' },
  -- or:
  shape = { kind = 'globalmesh' },
  ...
}

Boundary elements tracking

Example: tracking the boundary elements

tracking = { 
  ...
  shape = { kind = 'property', property = {'boundary'} },
  ...
}
-- or:

tracking = { 
  ...
  shape = { kind = 'boundary', boundary = {'bnd_name1','bnd_name2'} },
  ...
}

Example: tracking solid elements

tracking = { 
  ...
  shape = { kind = 'property', property = {'solidified'} },
  ...
}

Design and Implementation

The user-specified tracking shapes have to be translated to a set of elements, on which the defined quantities are calculated and written to disk in a suitable format.

All elements are converted to a set of points. For each point, the correspoinding treeID is added to the element list of the tracker as track%elems( iLevel )%elem(1:nElems). Each element will only be added once. All these elements are then treated in the main loop within the tracker routine.

peons/harvest_series.py

Each solver comes with a harvesting tool that allows the postprocessing of restart data after the simulation has been run. If this harvesting is to be done on a set of files, this may become a little tedious. To ease the post-processing there is a small Python script available in peons/harvest_series.py, which takes care of the execution of the post-processing script for multiple restart files. It can be used as easily as running

peons/harvest_series.py restart_*.lua

The main argument this script expects is a list of files to work on. There specification may make use of shell globbing patterns as in the example above.

Aside from the files to process there are various other options that can be specified, like the name of the harvesting executable, the name of the Lua executable and the template to use to construct the input file for the harvesting tool. These options may always be provided as command-line arguments, but can also be stored in a configuration file. By default harvest_series will look for a file named series.config to read its configuration, but you can tell it where to look for it via the -c option.

In the configuration file you provide the options to use in the form of:

option: value

Thus, for example you could provide the name of the harvesting tool as follows:

harvester: build/atl_harvesting

See the Python ConfigParser module documentation for more details on the syntax of the configuration file. You may provide a list of files to process in the config file. In this case the files should be separated by commas, you may still use globbing patterns in the file name specification.

Have a look at the available options with the -h option:

peons/harvest_series.py -h