The broad purpose of the FieldConvert utility is to read in data from a file, perform
some operation on this data, and write the data resulting from this operation to
an output file. To illustrate how it does this, let us consider a case in which the
user wishes to calculate the wall shear stress on the boundary labelled "0",
given a session file session.xml and field file field.fld, and write it to field
file field_wss.fld at 10 equispaced points using the output-points
option
1
The first task is to determine how to proceed based on the user input on the command line. In
this case, each command line input apart from -n 10
corresponds to a module. The
program stores these inputs as a boost::program_options::variables_map object,
in which each input is the key and its corresponding argument (if it has one) is
the value. The key is a std::string, and the value is optional, and can be any
type.
The names of process modules are specified using the flag--module
or -m
, and these are stored
in the map using the key "module" and the value being whatever follows the flag, in this case
the "wss:bnd=0". The file names, corresponding to input and output modules, are so-called
hidden options, meaning they don’t require a flag. These are stored in the map
using the key "input-file", with the value being a std::vector consisting of the
filenames, in this case "session.xml", "field.fld", and "field_wss.fld". The
output-points
option is stored in the map using the key output-points and the value being
10.
Assuming the user did not specify the command line options help
, modules-list
, or
modules-opt
, the program proceeds with its main functionality and a FieldSharedPtr is
constructed. The values in the map corresponding with the module and input-file keys are
stored as a std::vector of std::strings called the module commands, with the values
corresponding to input modules at the start, process modules in the middle, and output
modules at the end. Note that the program assumes that all these files apart from the
last are input files, unless specified by the prefix out
on the command line:, e.g.
out:file.fld
.
The module commands are iterated over, and for each entry, the the module string is identified
and stored with the module type in a ModuleKey. For input modules, the module string is
identified using InputModule::GuessFormat(), or failing that, by taking the name of
the file extension, as is done for output modules. For process modules, the module
string is simply the name of the entry (up to the colon separator if there is one).
The ModuleKey is used to create a ModuleSharedPtr using the factory by calling
Module::GetModuleFactory().CreateInstance, passing the ModuleKey and the
FieldSharedPtr as arguments. This ModuleSharedPtr is appended to a std::vector of
ModuleSharedPtrs. For input modules, InputModule::AddFile is called with the module
string and the input file name passed as arguments. The configuration options are then parsed
and registered using Module::RegisterConfig(), with arguments being the option name and
its value (if it is boolean, the argument is just the option name). For input and output
modules, the option infile or outfile is passed, along with the input or output file name. To
complete the loop, the Module::SetDefaults function is called. The process of
constructing a module, registering the configuration options (as well as calling AddFile for
InputModules), and setting the default configuration options for those that were not set
is summarised as setting up the module. The processes involved in the set up of
input, process, and output modules are shown in figure 16. In this case, instances
of the InputXml, InputFld, ProcessWSS, and OutputFld classes are constructed.
The configuration option name for InputXml and InputFld is the string infile
and the values are the filenames session.xml and field.fld respectively. The
option for ProcessWSS is bnd with value 0, and the option name for OutputFld
is the string outfile with the value being the filename field_wss.fld. Then, a
ModuleSharedPtr is created for the ProcessEquispacedOutput module if it is needed.
2 The
CheckModules function (defined FieldConvert.cpp is called with the std::vector of
ModuleSharedPtrs as argument in order to check the modules that have been set up are
compatible. Finally, the RunModule function (defined in FieldConvert.cpp
) is called with
each ModuleSharedPtr as argument in order of priority, which essentially calls the
Process function as for each module, operating on the various member variables of
Field, with the map used to store the command line arguments passed to each.
When using the nparts
command line argument, the calling of RunModule is done
in a loop over the number of partitions. On each iteration, Field::ClearField
is called, and a new Comm object is generated called partComm using the current
partition number, with the original saved as defComm. Field’s m_comm is switched to
partComm when running InputXml or any output module, and kept as defComm
otherwise.
A diagram of the process is shown in figure 16. It shows the order in which the modules are set up and run, and what member variables of Field each updates. The key for the diagrams in this section is shown in figure 16.