Difference between revisions of "Contrib multiSolver/programming"

From OpenFOAMWiki
Line 2: Line 2:
  
 
=== solverDomains ===
 
=== solverDomains ===
A [[TestMarupio/glossary#solverDomain|solverDomain]] is an individual solver loop.  It is assigned a name, and the list of names is static.  A [[TestMarupio/glossary#solverDomainName|solverDomainName]] cannot be:
+
A [[Contrib_multiSolver/glossary#solverDomain|solverDomain]] is an individual solver loop.  It is assigned a name, and the list of names is static.  A [[Contrib_multiSolver/glossary#solverDomainName|solverDomainName]] cannot be:
  
 
* <tt>all</tt>;
 
* <tt>all</tt>;
Line 8: Line 8:
 
* <tt>root</tt>.
 
* <tt>root</tt>.
  
All [[TestMarupio/glossary#solverDomain|solverDomains]] must appear in the <tt>case/system/multiControlDict</tt> file, although declaring additional names is not a problem.
+
All [[Contrib_multiSolver/glossary#solverDomain|solverDomains]] must appear in the <tt>case/system/multiControlDict</tt> file, although declaring additional names is not a problem.
  
 
=== Order of execution ===
 
=== Order of execution ===
In the [[TestMarupio#simpleExample|simple example]] on the main page, all the [[TestMarupio/glossary#solverDomain|solverDomains]] execute in sequence, once per [[TestMarupio/glossary#superLoop|superLoop]].  This is not necessary: you can enclose them in conditionals; they can execute in any order; they can miss entire [[TestMarupio/glossary#superLoop|superLoops]]; however, they cannot execute more than once per [[TestMarupio/glossary#superLoop|superLoop]].  Use: <tt>multiRun++</tt> between solvers to force the [[TestMarupio/glossary#superLoop|superLoop]] number to increment if necessary.
+
In the [[Contrib_multiSolver#simpleExample|simple example]] on the main page, all the [[Contrib_multiSolver/glossary#solverDomain|solverDomains]] execute in sequence, once per [[Contrib_multiSolver/glossary#superLoop|superLoop]].  This is not necessary: you can enclose them in conditionals; they can execute in any order; they can miss entire [[Contrib_multiSolver/glossary#superLoop|superLoops]]; however, they cannot execute more than once per [[Contrib_multiSolver/glossary#superLoop|superLoop]].  Use: <tt>multiRun++</tt> between solvers to force the [[Contrib_multiSolver/glossary#superLoop|superLoop]] number to increment if necessary.
  
 
Using a <tt>multiRun++</tt> statement may lead to user-confusion with the <tt>endSuperLoop</tt> condition for <tt>finalStopAt</tt>.
 
Using a <tt>multiRun++</tt> statement may lead to user-confusion with the <tt>endSuperLoop</tt> condition for <tt>finalStopAt</tt>.
  
 
=== runTime must go out of scope ===
 
=== runTime must go out of scope ===
Looking at the include files specified in the [[TestMarupio#simpleExample|simple example]] on the main page, you will notice that the entire solver loop is enclosed in its own set of braces { }, starting before <tt>#include "createTime.H"</tt>.  This is necessary because '''runTime''', the mesh, and all fields must go out of scope before '''multiSolver''' initializes another [[TestMarupio/glossary#solverDomain|solverDomain]].
+
Looking at the include files specified in the [[Contrib_multiSolver#simpleExample|simple example]] on the main page, you will notice that the entire solver loop is enclosed in its own set of braces { }, starting before <tt>#include "createTime.H"</tt>.  This is necessary because '''runTime''', the mesh, and all fields must go out of scope before '''multiSolver''' initializes another [[Contrib_multiSolver/glossary#solverDomain|solverDomain]].
  
 
=== End condition ===
 
=== End condition ===
'''multiSolver''' will detect the end condition automatically during the <tt>setSolver</tt> function.  It will archive the last <tt>case/time</tt> directory, and exit the superLoop.  This is achieved using the <tt>#include</tt> framework described in the [[TestMarupio#simpleExample|simple example]] on the main page.  If you are deviating from this framework, the requirements for correctly ending the '''multiSolver''' are:
+
'''multiSolver''' will detect the end condition automatically during the <tt>setSolver</tt> function.  It will archive the last <tt>case/time</tt> directory, and exit the superLoop.  This is achieved using the <tt>#include</tt> framework described in the [[Contrib_multiSolver#simpleExample|simple example]] on the main page.  If you are deviating from this framework, the requirements for correctly ending the '''multiSolver''' are:
  
 
* <tt>setSolver</tt> will automatically detect an end condition;
 
* <tt>setSolver</tt> will automatically detect an end condition;
Line 147: Line 147:
  
 
=== dummyControlDict ===
 
=== dummyControlDict ===
In order to allow ''runTimeModification'' of '''multiSolver''''s [[TestMarupio/glossary#multiDict|multiDicts]], '''multiSolver''' required an [[snip objectRegistry|objectRegistry]] that doesn't dissappear between [[TestMarupio/glossary#solverDomain|solverDomains]], when '''runTime''' goes out of scope.  Therefore it needed its own [[objectRegistry]].  Hence, <tt>multiDictRegistry_</tt> is a <tt>Time</tt> object.  <tt>Time</tt> was never intended to be a member variable, therefore its constructors do not allow initialization without a <tt>controlDict</tt>.  The object <tt>dummyControlDict</tt> was introduced as a self-initializing, minimal <tt>controlDict</tt>.
+
In order to allow ''runTimeModification'' of '''multiSolver''''s [[Contrib_multiSolver/glossary#multiDict|multiDicts]], '''multiSolver''' required an [[snip objectRegistry|objectRegistry]] that doesn't dissappear between [[Contrib_multiSolver/glossary#solverDomain|solverDomains]], when '''runTime''' goes out of scope.  Therefore it needed its own [[objectRegistry]].  Hence, <tt>multiDictRegistry_</tt> is a <tt>Time</tt> object.  <tt>Time</tt> was never intended to be a member variable, therefore its constructors do not allow initialization without a <tt>controlDict</tt>.  The object <tt>dummyControlDict</tt> was introduced as a self-initializing, minimal <tt>controlDict</tt>.
  
 
<tt>dummycontrolDict</tt> also has constructors that take a <tt>multiControlDict</tt>; or its name.  These constructors look for the <tt>timeFormat</tt> and <tt>timePrecision</tt> keywords.  If found, it includes these in its settings.  These settings are static variables owned by <tt>Time</tt>; and to simplify implementation, it was made universal - i.e. they can only be set once (at initialization) in '''multiSolver'''.
 
<tt>dummycontrolDict</tt> also has constructors that take a <tt>multiControlDict</tt>; or its name.  These constructors look for the <tt>timeFormat</tt> and <tt>timePrecision</tt> keywords.  If found, it includes these in its settings.  These settings are static variables owned by <tt>Time</tt>; and to simplify implementation, it was made universal - i.e. they can only be set once (at initialization) in '''multiSolver'''.
  
 
Ultimately, the <tt>dummyControlDict</tt> was necessary for global ''runTimeModification''.
 
Ultimately, the <tt>dummyControlDict</tt> was necessary for global ''runTimeModification''.

Revision as of 11:56, 23 July 2010

1 Solver mechanics

1.1 solverDomains

A solverDomain is an individual solver loop. It is assigned a name, and the list of names is static. A solverDomainName cannot be:

  • all;
  • default; or
  • root.

All solverDomains must appear in the case/system/multiControlDict file, although declaring additional names is not a problem.

1.2 Order of execution

In the simple example on the main page, all the solverDomains execute in sequence, once per superLoop. This is not necessary: you can enclose them in conditionals; they can execute in any order; they can miss entire superLoops; however, they cannot execute more than once per superLoop. Use: multiRun++ between solvers to force the superLoop number to increment if necessary.

Using a multiRun++ statement may lead to user-confusion with the endSuperLoop condition for finalStopAt.

1.3 runTime must go out of scope

Looking at the include files specified in the simple example on the main page, you will notice that the entire solver loop is enclosed in its own set of braces { }, starting before #include "createTime.H". This is necessary because runTime, the mesh, and all fields must go out of scope before multiSolver initializes another solverDomain.

1.4 End condition

multiSolver will detect the end condition automatically during the setSolver function. It will archive the last case/time directory, and exit the superLoop. This is achieved using the #include framework described in the simple example on the main page. If you are deviating from this framework, the requirements for correctly ending the multiSolver are:

  • setSolver will automatically detect an end condition;
  • to force an end condition, use setFinished();
  • once the end condition is met, the function setSolverDomain must be encountered at least once more (although it may be encountered any number of times) to perform the final data clean-up;
  • the function multiRun() returns true if another setSolverDomain still must be encountered; false means the run has finished, and setSolverDomain has completed the final clean-up;
  • the inidivual solverDomain loops cannot be encountered after the final clean-up has taken place. Enclose them each in:
if (multiRun.run())
{
    // solverDomain loop
}

1.5 #undef directives

Sometimes there will be conflicts with #define directives across solverDomains. For instance, if you have more than one solver using #include "createPhi.H", only the first solver will recognize it. This is caused by the fact that the createPhi.H file has this structure:

#ifndef createPhi_H
#define createPhi_H
 
// createPhi code
 
#endif 
 

These preprocessor directives ensure the code for createPhi is read only once, regardless of how many times it is included. This prevents the compiler from complaining that something is being redefined. The problem is, when we switch solver domains, phi goes out of scope, and it is not recreated. To overcome this, use an #undef directive between solver domains: #undef createPhi.H

This, and a few other #undef directives are already included by default in the setSolverDomain.H file. You may encounter others that need to be undefined. Please let me know if you do, and I will add it to the setSolverDomain.H file. In the mean time, to add an #undef directive:

  • using #include "setSolverDomain.H":
    Info << "*** Switching to icoFoam ***\n" << endl;
#   undef [conflicting definition]
    solverDomain = "icoFoam";
#   include "setSolverDomain.H" 
 
  • without using #include "setSolverDomain.H":
} // previous solver domain goes out of scope
multiRun.setSolverDomain(solverDomain);
 
#undef [conflicting definition]
 
if (multiRun.run())
{ // next solver domain comes into scope 
 

where [conflicting definition] is the definition that needs to be removed.

2 Solver interface functions

Functions designed for use within a solver.

2.1 setSolverDomain

This function mutates the case directory into what the next solverDomain expects. It:

  • rereads any modified multiDicts;
  • archives the existing data to case/multiSolver/solverDomain/superLoop/time;
  • copies the current field data to the case/time/ directory, swapping the boundary conditions if necessary;
  • creates and writes the new controlDict;
  • swaps all multiDicts to the next solverDomain; and
  • checks for the end condition.

2.2 setFinished

This function tells multiSolver that once the current solverDomain is finihsed, the full superSolver run is finished. (Technical, it tells multiSolver to save the last data and clean-up at the next setSolverDomain(), then the full superSolver run is finished.)

2.3 operator++

This function increments the superLoop number. It must be used if the same solverDomain is visited more than once in the same superLoop (otherwise it will overwrite its previous data). It can be used once between any pair of setSolverDomain() functions.

2.4 run and end

The run() and end() functions are analogous to those of the same name in the Time class. The first is true when the run should continue; the latter is true when the run should end.

3 Post processing functions

There are several functions designed for post-processing. Many of them depend on the use of the timeCluster and timeClusterList classes.

3.1 setSolverDomainPostProcessing

This mutates the case directory to that expected by the specified solverDomain. This is necessary for post-processors that read the controlDict.

3.2 timeFunctions

There are several searching / cataloging functions available for post-processing. Their function is described in the multiSolver.H header file. These include:

  • findSuperLoops - list all the superLoop directories in a given path;
  • findClosestGlobalTime - find the closest globalTime to a given value in a timeClusterList;
  • findClosestLocalTime - find the closest localTime to a given value in a timeClusterList. If timeClusters are overlapping, this function only uses the those from the latest superLoop;
  • findInstancePath - return the path to a given timeCluster and index;
  • findMaxSuperLoopValue - maximum superLoop by value;
  • findMaxSuperLoopIndices - return a labelList of the timeClusters with the maximum superLoop value;
  • nonOverlapping - if the timeClusters overlap in time, return false. timeClusters that share starting points, or share ending points are non-overlapping;
  • readSuperLoopTimes - catalog the time directories in case/multiSolver/givenSolverDomain/givenSuperLoop;
  • readSolverDomainTimes - catalog the time directories in case/multiSolver/givenSolverDomain/allSuperLoops;
  • readAllTimes - catalog the time directories in case/multiSolver/allSolverDomains/allSuperLoops;
  • loadTimeClusterList - copy / move time directories in a timeclusterList to case/time;
  • archiveTimeDirectories - copy / move time directories from sourcePath to destinatinoPath; and
  • purgeTimeDirectories - delete all time directories in a given path.

4 Support classes

There are a few additional classes that were written to support multiSolver. These include:

  • tuple2List class;
  • timeCluster class;
  • timeClusterList class; and
  • dummyControlDict class.

4.1 tuple2List

This is a sortable list of paired values was created. It is sortable by first or second value, and currently can be any combination of scalar or label.

4.2 timeCluster

timeCluster is to multiSolver what instant is to runTime. This object holds all the information necessary to catalog the data within a single solverDomain/superLoop directory. It holds:

  • the solverDomain name;
  • the superLoop number;
  • the globalTimeOffset; and
  • an instantList, cataloging all the time directories within the directory.

Sometimes, a timeCluster is used to identify a single time directory within a solverDomain/superLoop. This is useful for functions such as: findClosestGlobalTime, which needs to identify a single time directory. To assist in this operation, operator() has been defined. It creates just such a timeCluster, given the index of the instant.

(This is a bit messy, it might have been smarter to create a different class to distinguish between single time directories, and time directory lists.)

4.3 timeClusterList

Again, similar to instantList, for multiSolver. A timeClusterList can catalog all the data in the case directory. Unlike instantList, this class has some functions of its own:

  • append - add another timeCluster or timeClusterList to its collective;
  • globalSort - sort its constituent timeClusters by their minimum globalTime;
  • purgeEmpties - remove any timeClusters that have an empty instantList. Returns false if none remain. Many functions depend on a non-empty instantList.
  • selectiveSubList - returns a timeClusterList that is composed of a subList of the original timeClusterList. The sublist is seleted by index using a labelList. The sublist is not a true sublist like in other classes; rather it is simply another timeClusterList.

Note: Use purgeEmpties to ensure there are no empty timeClusters. Many of the timeFunctions will throw a fatal error if passed an empty timeClusterList.

4.4 dummyControlDict

In order to allow runTimeModification of multiSolver's multiDicts, multiSolver required an objectRegistry that doesn't dissappear between solverDomains, when runTime goes out of scope. Therefore it needed its own objectRegistry. Hence, multiDictRegistry_ is a Time object. Time was never intended to be a member variable, therefore its constructors do not allow initialization without a controlDict. The object dummyControlDict was introduced as a self-initializing, minimal controlDict.

dummycontrolDict also has constructors that take a multiControlDict; or its name. These constructors look for the timeFormat and timePrecision keywords. If found, it includes these in its settings. These settings are static variables owned by Time; and to simplify implementation, it was made universal - i.e. they can only be set once (at initialization) in multiSolver.

Ultimately, the dummyControlDict was necessary for global runTimeModification.