OpenFOAM® v3.0+: New Solution Control Functionality
Co-simulation
OpenFOAM includes a set of boundary conditions for communicating between OpenFOAM and external codes using file-based data transfer. In previous versions the control between OpenFOAM and the external code was performed inside the boundary conditions itself.
In this version, the control logic has been moved to a special function object, externalCoupled, which controls the coupling of all regions at every time step. The control between OpenFOAM and the external code employs a lock file whereby the existence of the lock file instructs the external code to wait, and either read or write the boundary values.
The default file format is currently hard-coded to be a text based format with one line per boundary face, but this can be overridden inside the boundary condition.
The special settings in this functionObject are the definition of the directory to use for the file exchange, and the fields to read/write per region, per patch. For the patch, either a single patch name can be used or a patch group. The patch group enables multiple patches to be collated into one coupling interface.
{
// Where to load it from (if not already in solver)
functionObjectLibs ("libjobControl.so");
type externalCoupled;
// Directory to use for communication
commsDir "$FOAM_CASE/comms";
// Does external process start first
initByExternal true;
// Additional output
log true;
regions
{
// Region name
region0
{
// Patch or patchGroup
coupleGroup
{
// Fields to output in commsDir
writeFields (T);
// Fields to read from commsDir
readFields (T);
}
}
}
}
- Examples
- multi-region case: $FOAM_TUTORIALS/heatTransfer/chtMultiRegionFoam/externalCoupledMultiRegionHeater
This example shows the setup for a multi-region case, with reading and writing fixedValue boundary conditions for data transfer.
- Source code
- $FOAM_SRC/postProcessing/functionObjects/jobControl/externalCoupled
Case Termination Controls
Simulation duration controls are defined using the main run-time controls in the case controlDict dictionary, or, for steady cases, the residualControl section in the fvSolution dictionary. However, for transient cases, it is often more appropriate to end the calculation when relevant statistics have converged to within a given tolerance.
The new runTimeControl function object offers several termination options, including:
- average: when the average of a function object value does not vary outside a given tolerance over a given time
- equationInitialResidualDivergence: when an equation initial residual exceeds a given value
- equationMaxIter: when an equation number of solve iterations exceeds a given value
- minMax: when a function object value exceeds the bounds defined by minimum or maximum values
- minTimeStep: when the time step falls below a given value
Conditions can be grouped by setting a groupID for each condition. In order for the condition to be marked as satisfied, all members of that group must be satisfied. A write step is performed each time any group is determined to be satisfied.
Case1: Terminate simulation based on drag coefficient convergence
The example case shows the application of the runTimeControl function object to
terminate the calculation when the change in the average drag coefficient falls
below a given threshold. Firstly, the force coefficients are calculated using a
forceCoeffs function object:
{
type forceCoeffs;
functionObjectLibs ( "libforces.so" );
outputControl timeStep;
timeInterval 1;
log yes;
patches (motorBikeGroup);
// Indicates incompressible
rhoName rhoInf;
// Redundant for incompressible
rhoIn 1.0;
liftDir (1 0 1);
dragDir (1 0 0);
// Axle midpoint on ground
CofR (0.72 0 0);
pitchAxis (0 1 0);
magUInf 20;
// Wheelbase length
lRef 1.42;
// Estimated
Aref 0.75;
}
The average drag coefficient is then calculated using a valueAverage function object:
{
type valueAverage;
functionObjectLibs ( "libfieldFunctionObjects.so" );
outputControl timeStep;
// Retrieve Cd from forceCoeffs1 object, and average using a
// window of 50
functionObjectName forceCoeffs1;
fields (Cd);
window 50;
}
{
type runTimeControl;
functionObjectLibs ("libjobControl.so");
conditions
{
// Terminate when average CDMean varies by less than tolerance
average1
{
type average;
functionObjectName valueAverage1;
fields (CdMean);
tolerance 1e-4;
window 50;
}
}
}
solver output ...
forceCoeffs forceCoeffs1 output:
Coefficients
Cm : 0.028232 (pressure: 0.028297 viscous: -6.49179e-05)
Cd : 0.424388 (pressure: 0.409931 viscous: 0.0144568)
Cl : 0.0668758 (pressure: 0.0669115 viscous: -3.57411e-05)
Cl(f) : 0.0616699
Cl(r) : 0.00520584
valueAverage: valueAverage1 averages:
CdMean: 0.421788
runTimeControl runTimeControl1 output:
average: average1 averages:
CdMeanMean: 0.421856, delta: 6.83194e-05
average: average1 condition satisfied
Stopping calculation
Writing fields - final step
End
Case2: Write on diverge
The failure mode of OpenFOAM cases can be immediate, whereby the calculation
can stop on the current iteration. In other cases, the failure mode can lead to a
slow death whereby the calculation proceeds, sometimes indefinitely. In order to
identify the latter case, a typical set-up may be:
{
type runTimeControl;
functionObjectLibs ("libjobControl.so");
nWriteStep 3;
conditions
{
condition1
{
...
}
condition2
{
...
}
}
}
The nWriteStep entry sets the number of write steps to perform prior to termination. For the example above, data will be written for a maximum of 3 times before the calculation stops.
- Source code
- runTimeControl $FOAM_SRC/postProcessing/functionObjects/jobControl/runTimeControl