Difference between revisions of "Contrib multiSolver/programming"

From OpenFOAMWiki
Line 1: Line 1:
== Programming with multiSolver ==
+
== Solver mechanics ==
  
 
=== solverDomains ===
 
=== solverDomains ===
A [[TestMarupio/glossary#solverDomain|solverDomain]] is an individual solver loop.  It is assigned a name, and the list of names is static.  All [[TestMarupio/glossary#solverDomain|solverDomains]] must appear in the <tt>case/system/multiControlDict</tt> file.
+
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:
 +
 
 +
* <tt>all</tt>;
 +
* <tt>default</tt>; or
 +
* <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.
  
 
=== 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 increment the [[TestMarupio/glossary#superLoop|superLoop]] number if necessary.
+
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.
 +
 
 +
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 at <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 [[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]].
  
=== Support classes ===
+
=== 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:
 +
 
 +
* use <tt>setFinished()</tt> to tell '''multiSolver''' the end condition is met;
 +
* once the end condition is met, the function <tt>setSolverDomain</tt> 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 <tt>multiRun()</tt> returns true if another <tt>setSolverDomain</tt> still ''must'' be encountered; false means the run has finished, ''and'' <tt>setSolverDomain</tt> 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:
 +
<cpp>if (multiRun.run())
 +
{
 +
    // solverDomain loop
 +
}</cpp>
 +
 
 +
<!--=== Solver signal end condition ===
 +
There is a new end condition called <tt>solverSignal</tt>.  This allows users to tell the '''multiSolver''' that the solver ''must'' determine the end condition.  A superSolver not designed to handle this will enter a near-infinite loop.
 +
-->
 +
== Solver interface functions ==
 +
Functions designed for use within a solver.
 +
 
 +
=== setSolverDomain ===
 +
This function ''mutates'' the case directory into what the next solverDomain expects.  It:
 +
 
 +
* rereads any modified multiDicts;
 +
* archives the existing data to <tt>case/multiSolver/solverDomain/superLoop/time</tt>;
 +
* copies the current field data to the <tt>case/time/</tt> directory, swapping the boundary conditions if necessary;
 +
* creates and writes the new <tt>controlDict</tt>;
 +
* swaps all multiDicts to the next solverDomain; and
 +
* checks for the end condition.
 +
 
 +
=== 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 <tt>setSolverDomain()</tt>, then the full superSolver run is finished.)
 +
 
 +
=== 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 <tt>setSolverDomain()</tt> functions.
 +
 
 +
=== run and end ===
 +
The <tt>run()</tt> and <tt>end()</tt> functions are analogous to those of the same name in the <tt>Time</tt> class.  The first is <tt>true</tt> when the run should continue; the latter is <tt>true</tt> when the run should end.
 +
 
 +
== Post processing functions ==
 +
There are several functions designed for post-processing.  Many of them depend on the use of the <tt>[[#timeCluster|timeCluster]]</tt> and <tt>[[#timeClusterList|timeClusterList]]</tt> classes.
 +
 
 +
=== setSolverDomainPostProcessing ===
 +
This mutates the <tt>case</tt> directory to that expected by the specified solverDomain.  This is necessary for post-processors that read the controlDict.
 +
 
 +
=== timeFunctions ===
 +
There are several searching / cataloging functions available for post-processing.  Their function is described in the <tt>multiSolver.H</tt> header file.  These include:
 +
 
 +
* <tt>findSuperLoops</tt> - list all the superLoop directories in a given path;
 +
* <tt>findClosestGlobalTime</tt> - find the closest globalTime to a given value in a timeClusterList;
 +
* <tt>findClosestLocalTime</tt> - 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;
 +
* <tt>findInstancePath</tt> - return the path to a given timeCluster and index;
 +
* <tt>findMaxSuperLoopValue</tt> - maximum superLoop by value;
 +
* <tt>findMaxSuperLoopIndices</tt> - return a labelList of the timeClusters with the maximum superLoop value;
 +
* <tt>nonOverlapping</tt> - if the timeClusters overlap in time, return false.  timeClusters that share starting points, or share ending points are non-overlapping;
 +
* <tt>readSuperLoopTimes</tt> - catalog the <tt>time</tt> directories in <tt>case/multiSolver/givenSolverDomain/givenSuperLoop</tt>;
 +
* <tt>readSolverDomainTimes</tt> - catalog the <tt>time</tt> directories in <tt>case/multiSolver/givenSolverDomain/allSuperLoops</tt>;
 +
* <tt>readAllTimes</tt> - catalog the <tt>time</tt> directories in <tt>case/multiSolver/allSolverDomains/allSuperLoops</tt>;
 +
* <tt>loadTimeClusterList</tt> - copy / move <tt>time</tt> directories in a timeclusterList to <tt>case/time</tt>;
 +
* <tt>archiveTimeDirectories</tt> - copy / move <tt>time</tt> directories from <tt>sourcePath</tt> to <tt>destinatinoPath</tt>; and
 +
* <tt>purgeTimeDirectories</tt> - delete all <tt>time</tt> directories in a given path.
 +
 
 +
== Support classes ==
 
There are a few additional classes that were written to support '''multiSolver'''.  These include:
 
There are a few additional classes that were written to support '''multiSolver'''.  These include:
  
Line 18: Line 86:
 
* <tt>dummyControlDict</tt> class.
 
* <tt>dummyControlDict</tt> class.
  
'''tuple2List'''<BR>
+
=== 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 <tt>scalar</tt> or <tt>label</tt>.
 
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 <tt>scalar</tt> or <tt>label</tt>.
  
'''timeCluster'''<BR>
+
=== timeCluster ===
<tt>timeCluster</tt> is to '''multiSolver''' what <tt>instant</tt> is to '''runTime'''.  Basically an object that can catalogue all the time data within a '''multiSolver'''-enabled application.
+
<tt>timeCluster</tt> is to '''multiSolver''' what <tt>instant</tt> is to '''runTime'''.  This object holds all the information necessary to catalog the data within a single <tt>solverDomain/superLoop</tt> directory.  It holds:
 +
 
 +
* the solverDomain name;
 +
* the superLoop number;
 +
* the globalTimeOffset; and
 +
* an instantList, cataloging all the time directories within the directory.
 +
 
 +
Sometimes, a <tt>timeCluster</tt> is used to identify a single time directory within a solverDomain/superLoop.  This is useful for functions such as: <tt>findClosestGlobalTime</tt>, which needs to identify a single time directory.  To assist in this operation, <tt>operator()</tt> has been defined.  It creates just such a <tt>timeCluster</tt>, given the index of the <tt>instant</tt>.
 +
 
 +
(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.)
 +
 
 +
=== timeClusterList ===
 +
Again, similar to <tt>instantList</tt>, for '''multiSolver'''. A <tt>timeClusterList</tt> can catalog all the data in the case directory.  Unlike <tt>instantList</tt>, this class has some functions of its own:
  
'''timeClusterList'''<BR>
+
* <tt>append</tt> - add another <tt>timeCluster</tt> or <tt>timeClusterList</tt> to its collective;
Again, similar to <tt>instantList</tt>, for '''multiSolver'''.
+
* <tt>globalSort</tt> - sort its constituent <tt>timeCluster</tt>s by their minimum globalTime;
 +
* <tt>purgeEmpties</tt> - remove any <tt>timeCluster</tt>s that have an empty <tt>instantList</tt>.  Returns false if none remain.  Many functions depend on a non-empty <tt>instantList</tt>.
 +
* <tt>selectiveSubList</tt> - returns a <tt>timeClusterList</tt> that is composed of a subList of the original <tt>timeClusterList</tt>.  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 <tt>timeClusterList</tt>.
  
'''dummyControlDict'''<BR>
+
'''Note:''' Use <tt>purgeEmpties</tt> to ensure there are no empty timeClusters.  Many of the [[#timeFunctions|timeFunctions]] will throw a fatal error if passed an empty timeClusterList.
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>.  Ultimately it was necessary for global ''runTimeModification''.
+
  
== Implementation of multiSolver ==
+
=== 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>.
  
=== storeFields ===
+
<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> keywordsIf 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'''.
Some solverDomains may not need to use all the fields required by other solverDomainsRather than carry the unused fields in memory and write them out at every output point, storeFields can be declared.  storeFields works by copying the fields into the ''first'' time directory of that solverDomain for every superLoop.  When the next solverDomain is initialized, the stored field is retrieved and pasted into the starting time directory for that superLoop.
+
  
storeFields is a wordList defined in multiSolverDict, under each solverDomain.  One problem arises if the initial solverDomain has store fields - '''multiSolver''' would have no idea where to look for the storeFields.  Therefore, the initial solverDomain must have all storeFields defined in its 0/0 directory.
+
Ultimately, the <tt>dummyControlDict</tt> was necessary for global ''runTimeModification''.

Revision as of 01:47, 5 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:

  • use setFinished() to tell multiSolver the end condition is met;
  • 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
}

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.