PSCF v1.4.0
Parameter File I/O

Periodic Systems: CPU vs. GPU (Prev)         Unit Tests (Next)

The format of the parameter file (discussed here ) consists of a set of nested blocks, in which each block contains the data required to initialize an instance of a particular class. Every class that reads a block of the parameter file must be directly or indirectly derived from the Util::ParamComposite base class, and uses functions defined in that base class to define the format of the associated parameter file block.

The readParameters function

The read a parameter file block, a subclass of Util::ParamComposite normally must override the inherited virtual function ParamComposite::readParameters. The interface of this function is

virtual void readParameters(std::istream& in);

This class has an empty (do-nothing) default implementation. Any subclasses of ParamComposite may define a non-trivial implementation in order to define the required format of the body of the parameter file block associated with that class. This file format is defined by source cod that uses other functions inherited from ParamComposite that are used used to read individual parameters and nested subblocks in a specified order.

The readParameters function is usually called by another protected member function of ParamComposite named ParamComposite::readParam. Like the readParameters function, the readParam function takes a std::iostream as its only parameter. The difference is that the readParam function reads the lines containing the opening and closing braces of a parameter file block, while readParameters reads only the body of the block, between those two lines. ParamComposite defines a default implementation of readParam function that reads the opening line of a parameter file block, calls the virtual readParameters function to read the body of the block, and then reads the line containing a closing brace. The readParam method is also declared virtual, and so can also be overridden, but most subclasses of ParamComposite override the readParameters function and simply use the default implementation of the readParam function.

Most classes thus override the ParamComposite::readParameters function to define a parameter file format. In this case, the source code of this function is the most complete documentation of the format of the associated parameter file block.

Setting the class name label

A parameter file block associated with an instance of a subclass of ParamComposite class begins with a line containing a label for the class, which is generally the name of the class or class template, followed by an opening curly bracket. For example, the opening and closing lines of a block associated with a class named "Domain" looks something like this

Domain{
...
}

where ellipses represented the omitted body of this block. When the code that reads a required block of a parameter file reads the first line, it compares the label that precedes the opening curly bracket to an expected value, and halts execution if these strings do not exactly match.

The expected value for the class name label that appears in this opening line is set by a function named "setClassName" that is inherited from ParamComposite. This function has the interface

void setClassName(char const * className)

Here, the className parameter is a string literal that gives the required label. The setClassName function is usually called in the constructor of a subclass of ParamComposite, and passed a string argument that is normally the name of the relevant class or class template.

Reading parameters

The of the readParameters() function typically uses one of several protected function templates that are inherited from the Util::ParamComposite class. The simplest of these are the read and readOptional function templates, either of which can be used to read a single parameter of any type.

The read function template of class ParamComposite is a function template that takes the data type of a required parameter value as a template parameter. The interface for this member class template is given in part by

template <int T>
read(std::istream& in, const char* label, T& data)

where template parameter T denotes the relevant data type. The readOptional function is used to read and optional parameter but is otherwise identical, and has an interface

template <int T>
readOptional(std::istream& in, const char* label, T& data)

In both of these function template:

  • parameter "in" represents an input stream associated with a parameter file.
  • parameter "label" is a string literal that gives the expected value of the label string for a parameter or a parameter block.
  • parameter "data" is a reference to the variable that will hold the parameter value extracted from the parameter file.

For simplicity, the type of return parameter has been omitted from both of the above interface descriptions. This is because the return value is actually almost never retained or used, and the actual type of the return value is somewhat a specialized type, Util::ScalarParam<T>. Both of these function templates are thus normally used as if they were void functions.

The read template is used for required parameters, and throws an Exception if the part of the stream that it reads does not begin with a string that exactly matches the "label" parameter. The readOptional template is used for optional parametrs, and so will exit with throwing an Exception if it does not encounter a label string that matches the label parameter, since this indicates only that the relevant optional parameter was omitted.

Example: As a simple example, consider the following skeleton of the definition for a class named A:

using namepace Util;
class A : public ParamComposite
{
public:
A();
void readParameters(std::istream& in) override;
// other member functions
private:
int var1_;
double var2_;
}
Utility classes for scientific computation.

Class A has an int member variable var1_, and a double precision real member variable var2_. Suppose that values of both var1_ and var2_ need to be read from a parameter file block, and that the desired parameter block format for a block associated with class A is as shown below:

A{
  var1     int
  var2*    double
}

This parameter file format is shown in a standard form, in which the strings var1 and var2 represent literal parameter label strings, the typenames int and double indicate the required types of the corresponding parameter values, and the asterisk after the var2 label indicates that var2 is an optional double precision parameter.

Minimal implementations of the constructor and readParameters member functions required to parse this parameter block format are show below:

A::A()
{ setClassName("A"); }
void A::readParameters(std::istream& in)
{
var2_ = 0.0;
read(in, "var1", var1_);
readOptional(in, "var2", var2_);
}

The label string "A" that appears in the opening line of the block is passed an argument to the setClassName class in the constructor. The required label strings "var1", and "var2" for individual parameters are instead passed as parameters to the read and readOptional functions. The line "var2_ = 0.0" assigns a zero default value to parameter var2_, which will be used if a line containing this optional parameter does not appear in the parameter file.

Often, the implementation of a readParameters() method also contains code to validate input values, allocate any required memory, and take any other actions that are required to initialize an instance of the class but require knowledge of values of parameters that are read from the parameter file. No such additional initialization steps are needed for this simple example.

Reading array valued parameters

The ParaComposite class also provides several other protected member functions that can be used by subclass to read array- and matrix-valued parameters, for which values of multiple elements can be placed in any of several different types of container.

For example, the readDArray and readOptionalDArray function templates are designed to read required and optional array-valued parameters for which the elements are stored DArray containers. Like the read and readOptional functions, these are function templates for which type of each element is a template parameter. The interface for the ParamComposite::readDArray function template (without the type of the seldom-used return value) is:

template <typename T>
readDArray(std::istream &in, const char *label, DArray<Type>& array, int n)

The readDArrayOptional member function template has an identical interface. For both of these function templates, the "in" and "label" parameters have the same meaning as for individual parameters, while:

  • parameter "array" is a reference to a DArray whose elements will hold an array parameter values
  • n is the expected number of elements in the array

The parameter file format for an array-valued parameter starts with a line containing the label string following by an opening square bracket ([) followed by elements values on separate lines and ending with a closing square bracket (]), as discussed Parameter File - Format Descriptions previously .

The ParamComposite base class provides several other protected member functions that subclasses can use read arrays and matrices of parameters into other types of containers. These include functions designe to store values in a bare C arrays, a fixed size FArray containers, and a DMatrix matrix container. Please consult the developer documentation for the Util::ParamComposite class for more complete information.

Reading nested subblocks

The ParamComposite class also provides two protected inherited functions named readParamComposite and readOptionalParamComposite that may be used by subclasses to read nested subblocks. Slightly simplified versions of interfaces for these functions (omitting an optional parameter that is rarely used) are

void readParamComposite(std::istream in, ParamComposite &child)

and

void readParamCompositeOptional(std::istream in, ParamComposite &child)

Here, "parameter" in is an input parameter file stream, while "child" is a reference to an instance of a class that is another subclass of ParamComposite which must read a nested subblock. Both functions are designed to read a nested subblock associated with a member of another subclass that of ParamComposite. The function readParamComposite is used for required subblocks, while readParamCompositeOptional is used for optional subblocks.

Example : To see how this works, we consider slightly more complicated version of the class named A that is defined above. We suppose for this purpose that A has a third member variable that holds an instance of another class named B, as shown below: below:

using namepace Util;
class A : public ParamComposite
{
public:
// Default constructor
A();
// Read the body of the parameter file
void readParameters(std::istream& in);
// other member functions
private:
int var1_;
double var2_;
B varB_;
}

We also suppose that B is itself a subclass of ParamComposite, and that the parameter file format for class A includes a nested subblock that is associated with the variable varB_ of type B, giving the following parameter file format:

A{
  var1    [int]
  var2*   [double]
  B{ 
    ...  
  }
}

Here, ellipses (...) are used to indicate the omitted indented body of a nested parameter file subblock associated with variable varB_. In this example, var1 and the B block are required, while var2 is optional.

A minimal version of the readParameters function required to read this modified format is shown below

void A::readParameters(std::istream& in)
{
read(in, "var1", var1_);
readOptional(in, "var2", var2_);
readParamComposite(in, varB_);
}

The readParamCompositeOptional function would have been used to read the nest block associatd with varB_ if that block was optional rather than required.

Note that the readParamComposite or readParamCompositeOptional functions do not require a label string as an input parameter. This is because each subclass of ParamComposite must instead use the inherited "setClassName" function to define the class name label that should appear in the opening line of an associated parameter file block. In this example, all constructors of class B are thus assumed to contain the statement setClassName("B").


Periodic Systems: CPU vs. GPU (Prev)         Developer Information (Up)         Unit Tests (Next)