Difference between revisions of "Contrib equationReader/Programming"

From OpenFOAMWiki
(Created page with "For now, please refer to the '''equationReader''' demo application.")
 
Line 1: Line 1:
For now, please refer to the '''equationReader''' demo application.
+
Most of the programming features can be gleaned from the '''equationReader''' demo application.  Please also refer to that.
 +
 
 +
== Creating an equationReader object ==
 +
To add '''equationReader''' to an application:
 +
 
 +
* Put <tt>#include "IOEquationReader.H"</tt> at the top of your main source file;
 +
* Put <tt>#include "createEquationReader.H"</tt> somewhere after <tt>createTime</tt>;
 +
 
 +
== Adding data sources ==
 +
You need to add data sources - this is where '''equationReader''' looks for its variables.
 +
 
 +
=== Is the data permanent? ===
 +
Data must be permanently available.  For instance, <tt>mesh.C()</tt> is a valid data source because it returns a &reference.  But <tt>turbulence->R()</tt> is not valid because it returns an object (or <tt>tmp<object></tt>), and hence is ''derived'' from other permanent sources.
 +
 
 +
To use ''derived'' data sources, there are two options.
 +
 
 +
1. Create a permanent copy, and update it at every timestep.  This is demonstrated in <tt>equationReaderDemo</tt>.
 +
 
 +
2. Create an ''activeVariable''.
 +
 
 +
=== Active variables ===
 +
'''(Advanced developers)''' An ''activeVariable'' is one that does not permanently store its data, and provides values ''on-demand'' to '''equationReader'''.  The key to this is it must be able to calculate a single cell value on-demand, and not the entire field at once.  The interface is given in the <tt>equationReader/equationVariable/equationVariable.H</tt> file.
 +
 
 +
=== Functions to add data sources ===
 +
To add data sources:
 +
 
 +
* for <tt>scalars</tt>, <tt>dimensionedScalars</tt>, <tt>scalarFields</tt>, <tt>GeometricScalarFields</tt>, etc.:
 +
    eqns.scalarSources().addData(''scalarObject'');
 +
:or if it doesn't have its own name (i.e. <tt>scalars</tt> and <tt>scalarFields</tt>) or you want to assign it a different name:
 +
    eqns.scalarSources().addData(''scalarObject'', ''name'');
 +
* for <tt>vectors</tt>, <tt>dimensionedVectors</tt>, <tt>vectorFields</tt>, <tt>GeometricVectorFields</tt>, etc.:
 +
    eqns.vectorSources().addData(''vectorObject'');
 +
:or if it doesn't have its own name (i.e. <tt>scalars</tt> and <tt>scalarFields</tt>) or you want to assign it a different name:
 +
    eqns.vectorSources().addData(''vectorObject'', ''name'');
 +
* and so on for other Types (<tt>tensor</tt>, <tt>diagTensor</tt>, <tt>symmTensor</tt>, and <tt>sphericalTensor</tt>);
 +
* for <tt>dictionaries</tt> or <tt>activeVariables</tt>:
 +
    eqns.addDataSource(''dataObject'');
 +
 
 +
== Reading in the equations ==
 +
To read equations from a dictionary use:
 +
eqns.readEquation(''dictionaryName'', ''equationName'');
 +
 
 +
== Searching the equations ==
 +
These functions are useful:
 +
eqns.found(''equationName'');
 +
This is true if <tt>''equationName''</tt> exists.
 +
equationIndex = eqns.lookup(''equationName'');
 +
If you use the equation index instead of the name, the functions don't have to perform a <tt>lookup</tt> everytime you call it.
 +
 
 +
== Evaluating equations ==
 +
Once you are done adding data sources, and reading equations, you can start evaluating equations.
 +
 
 +
=== All data sources required ===
 +
When evaluating an equation, '''equationReader''' needs access to all the possible variables and other equations that equation might depend on. If that variable or equation isn't found, '''equationReader''' produces a '''FatalError'''.  '''''Therefore it is a mistake to try adding more data sources after the first evaluation.'''''
 +
 
 +
=== No mesh available ===
 +
'''equationReader''' doesn't care about the mesh... all it cares about are the sizes of the the fields.  '''''The size of the variable fields must match.'''''  Index checking is expensive, so it is only available in <tt>FULLDEBUG</tt> mode.  These rules apply:
 +
 
 +
* a single-element variable (e.g. a <tt>scalar</tt>, or a <tt>dimensionedVector</tt>) is assumed ''uniform throughout the entire domain'', and can be used in any equation;
 +
* a field variable (e.g. a <tt>scalarField</tt>, or a <tt>DimensionedVectorField</tt>) does not have a boundary field, therefore it is only available to equations of other fields or internal fields.  Attempting to use it in a <tt>GeometricField</tt> is a mistake; and
 +
* a <tt>GeometricField</tt> variable can be used with any equation.
 +
 
 +
There are two indices to indicate field / boundary field position:
 +
 
 +
* '''cellIndex''' - this is the position within a field (e.g. cell number in the internal field, or face number on a boundary patch);
 +
* '''geoIndex''':
 +
** 0 = the internal field;
 +
** 1+ = the boundary patches.  The geoIndex is therefore 1-indexed on the boundaryField: patchI = geoIndex - 1.
 +
 
 +
If you omit either of these in the evaluation equations, they are assumed equal to zero.
 +
 
 +
=== Evaluation functions ===
 +
* for single element types:
 +
    scalarA = eqns.evaluateScalar
 +
    (
 +
        ''eqnNameOrIndex'',
 +
        ''[cellIndex]'',
 +
        ''[geoIndex]''
 +
    );
 +
    vectorA.x() = eqns.evaluateScalar
 +
    (
 +
        ''xEqnNameOrIndex'',
 +
        ''[cellIndex]'',
 +
        ''[geoIndex]''
 +
    ); // and so on for all its components
 +
    tensorA.xx() = eqns.evaluateScalar
 +
    (
 +
        ''xxEqnNameOrIndex'',
 +
        ''[cellIndex]'',
 +
        ''[geoIndex]''
 +
    ); // and so on for all its components
 +
* for <tt>dimensionedScalars</tt>:
 +
    dimensionedScalarA = eqns.evaluateDimensioned
 +
    (
 +
        ''eqnNameOrIndex'',
 +
        ''[cellIndex]'',
 +
        ''[geoIndex]''
 +
    );
 +
* for other <tt>dimensionedTypes</tt> - there is no elegant dimensionChecking... use this hack:
 +
    vectorA.x() = eqns.evaluateScalar
 +
    (
 +
        ''xEqnNameOrIndex'',
 +
        ''[cellIndex]'',
 +
        ''[geoIndex]''
 +
    );
 +
    vectorA.y() = eqns.evaluateScalar
 +
    (
 +
        ''yEqnNameOrIndex'',
 +
        ''[cellIndex]'',
 +
        ''[geoIndex]''
 +
    );
 +
    vectorA.z() = eqns.evaluateScalar
 +
    (
 +
        ''zEqnNameOrIndex'',
 +
        ''[cellIndex]'',
 +
        ''[geoIndex]''
 +
    );
 +
    vectorA.dimensions() = eqns.evaluateDimensions(''xEqnNameOrIndex'');
 +
    vectorA.dimensions() = eqns.evaluateDimensions(''yEqnNameOrIndex'');
 +
    vectorA.dimensions() = eqns.evaluateDimensions(''zEqnNameOrIndex'');
 +
* for <tt>scalarFields</tt>:
 +
    eqns.evaluateScalarField(''resultScalarField'', ''eqnNameOrIndex'', ''[geoIndex]'');
 +
:or
 +
    eqns.evaluateTypeField
 +
    (
 +
        ''resultScalarField'',
 +
        ''dummyWord'',
 +
        ''eqnNameOrIndex'',
 +
        ''[geoIndex]''
 +
    );
 +
* for <tt>vectorFields</tt>:
 +
    eqns.evaluateTypeField
 +
    (
 +
        ''resultVectorField'',
 +
        "x", // this is the component name
 +
        ''xEqnNameOrIndex'',
 +
        ''[geoIndex]''
 +
    ); // and so on for the "y" and "z" components
 +
* and so on for other <tt>typeFields</tt>;
 +
* for <tt>DimensionedScalarFields</tt>:
 +
    eqns.evaluateDimensionedScalarField
 +
    (
 +
        ''resultDimensionedScalarField'',
 +
        ''eqnNameOrIndex'',
 +
        ''[geoIndex]''
 +
    );
 +
:do not use <tt>evaluateDimensionedTypeField</tt> - this will fail for scalars;
 +
*for <tt>DimensionedVectorFields</tt>:
 +
    eqns.evaluateDimensionedTypeField
 +
    (
 +
        ''resultDimensionedVectorField'',
 +
        ''xEqnNameOrIndex'',
 +
        "x",
 +
        ''[geoIndex]''
 +
    ); // and so on for the "y" and "z" components
 +
* and so on for other <tt>DimensionedTypeFields</tt>;
 +
* for <tt>GeometricScalarFields</tt>
 +
    eqns.evaluateGeometricScalarField
 +
    (
 +
        ''resultGeometricScalarField'',
 +
        ''eqnNameOrIndex''
 +
    );
 +
:do not use <tt>evaluateGeometricTypeField</tt> - this will fail for scalars;
 +
* for <tt>GeometricVectorFields</tt>
 +
    eqns.evaluateGeometricTypeField
 +
    (
 +
        ''resultGeometricTypeField'',
 +
        "x",
 +
        ''xEqnNameOrIndex''
 +
    ); // and so on for the "y" and "z" components
 +
* and so on for other <tt>GeometricTypeFields</tt>;

Revision as of 00:29, 15 September 2011

Most of the programming features can be gleaned from the equationReader demo application. Please also refer to that.

1 Creating an equationReader object

To add equationReader to an application:

  • Put #include "IOEquationReader.H" at the top of your main source file;
  • Put #include "createEquationReader.H" somewhere after createTime;

2 Adding data sources

You need to add data sources - this is where equationReader looks for its variables.

2.1 Is the data permanent?

Data must be permanently available. For instance, mesh.C() is a valid data source because it returns a &reference. But turbulence->R() is not valid because it returns an object (or tmp<object>), and hence is derived from other permanent sources.

To use derived data sources, there are two options.

1. Create a permanent copy, and update it at every timestep. This is demonstrated in equationReaderDemo.

2. Create an activeVariable.

2.2 Active variables

(Advanced developers) An activeVariable is one that does not permanently store its data, and provides values on-demand to equationReader. The key to this is it must be able to calculate a single cell value on-demand, and not the entire field at once. The interface is given in the equationReader/equationVariable/equationVariable.H file.

2.3 Functions to add data sources

To add data sources:

  • for scalars, dimensionedScalars, scalarFields, GeometricScalarFields, etc.:
   eqns.scalarSources().addData(scalarObject);
or if it doesn't have its own name (i.e. scalars and scalarFields) or you want to assign it a different name:
   eqns.scalarSources().addData(scalarObject, name);
  • for vectors, dimensionedVectors, vectorFields, GeometricVectorFields, etc.:
   eqns.vectorSources().addData(vectorObject);
or if it doesn't have its own name (i.e. scalars and scalarFields) or you want to assign it a different name:
   eqns.vectorSources().addData(vectorObject, name);
  • and so on for other Types (tensor, diagTensor, symmTensor, and sphericalTensor);
  • for dictionaries or activeVariables:
    eqns.addDataSource(dataObject);

3 Reading in the equations

To read equations from a dictionary use:

eqns.readEquation(dictionaryName, equationName);

4 Searching the equations

These functions are useful:

eqns.found(equationName);

This is true if equationName exists.

equationIndex = eqns.lookup(equationName);

If you use the equation index instead of the name, the functions don't have to perform a lookup everytime you call it.

5 Evaluating equations

Once you are done adding data sources, and reading equations, you can start evaluating equations.

5.1 All data sources required

When evaluating an equation, equationReader needs access to all the possible variables and other equations that equation might depend on. If that variable or equation isn't found, equationReader produces a FatalError. Therefore it is a mistake to try adding more data sources after the first evaluation.

5.2 No mesh available

equationReader doesn't care about the mesh... all it cares about are the sizes of the the fields. The size of the variable fields must match. Index checking is expensive, so it is only available in FULLDEBUG mode. These rules apply:

  • a single-element variable (e.g. a scalar, or a dimensionedVector) is assumed uniform throughout the entire domain, and can be used in any equation;
  • a field variable (e.g. a scalarField, or a DimensionedVectorField) does not have a boundary field, therefore it is only available to equations of other fields or internal fields. Attempting to use it in a GeometricField is a mistake; and
  • a GeometricField variable can be used with any equation.

There are two indices to indicate field / boundary field position:

  • cellIndex - this is the position within a field (e.g. cell number in the internal field, or face number on a boundary patch);
  • geoIndex:
    • 0 = the internal field;
    • 1+ = the boundary patches. The geoIndex is therefore 1-indexed on the boundaryField: patchI = geoIndex - 1.

If you omit either of these in the evaluation equations, they are assumed equal to zero.

5.3 Evaluation functions

  • for single element types:
   scalarA = eqns.evaluateScalar
   (
       eqnNameOrIndex,
       [cellIndex],
       [geoIndex]
   );
   vectorA.x() = eqns.evaluateScalar
   (
       xEqnNameOrIndex,
       [cellIndex],
       [geoIndex]
   ); // and so on for all its components
   tensorA.xx() = eqns.evaluateScalar
   (
       xxEqnNameOrIndex,
       [cellIndex],
       [geoIndex]
   ); // and so on for all its components
  • for dimensionedScalars:
   dimensionedScalarA = eqns.evaluateDimensioned
   (
       eqnNameOrIndex,
       [cellIndex],
       [geoIndex]
   );
  • for other dimensionedTypes - there is no elegant dimensionChecking... use this hack:
   vectorA.x() = eqns.evaluateScalar
   (
       xEqnNameOrIndex,
       [cellIndex],
       [geoIndex]
   );
   vectorA.y() = eqns.evaluateScalar
   (
       yEqnNameOrIndex,
       [cellIndex],
       [geoIndex]
   );
   vectorA.z() = eqns.evaluateScalar
   (
       zEqnNameOrIndex,
       [cellIndex],
       [geoIndex]
   );
   vectorA.dimensions() = eqns.evaluateDimensions(xEqnNameOrIndex);
   vectorA.dimensions() = eqns.evaluateDimensions(yEqnNameOrIndex);
   vectorA.dimensions() = eqns.evaluateDimensions(zEqnNameOrIndex);
  • for scalarFields:
   eqns.evaluateScalarField(resultScalarField, eqnNameOrIndex, [geoIndex]);
or
   eqns.evaluateTypeField
   (
       resultScalarField,
       dummyWord,
       eqnNameOrIndex,
       [geoIndex]
   );
  • for vectorFields:
   eqns.evaluateTypeField
   (
       resultVectorField,
       "x", // this is the component name
       xEqnNameOrIndex,
       [geoIndex]
   ); // and so on for the "y" and "z" components
  • and so on for other typeFields;
  • for DimensionedScalarFields:
   eqns.evaluateDimensionedScalarField
   (
       resultDimensionedScalarField,
       eqnNameOrIndex,
       [geoIndex]
   );
do not use evaluateDimensionedTypeField - this will fail for scalars;
  • for DimensionedVectorFields:
   eqns.evaluateDimensionedTypeField
   (
       resultDimensionedVectorField,
       xEqnNameOrIndex,
       "x",
       [geoIndex]
   ); // and so on for the "y" and "z" components
  • and so on for other DimensionedTypeFields;
  • for GeometricScalarFields
   eqns.evaluateGeometricScalarField
   (
       resultGeometricScalarField,
       eqnNameOrIndex
   );
do not use evaluateGeometricTypeField - this will fail for scalars;
  • for GeometricVectorFields
   eqns.evaluateGeometricTypeField
   (
       resultGeometricTypeField,
       "x",
       xEqnNameOrIndex
   ); // and so on for the "y" and "z" components
  • and so on for other GeometricTypeFields;