/*--------------------------------*- C++ -*----------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     | Website:  https://openfoam.org
    \\  /    A nd           | Version:  14
     \\/     M anipulation  |
\*---------------------------------------------------------------------------*/
FoamFile
{
    format      ascii;
    class       dictionary;
    object      testCalc;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

#codeBlock

a   1.1;
b   3.2;
c   #calc "$a*$b";

// Special care is required for calc entries that include a division since
// "/" is also used as the scoping operator to identify keywords in
// sub-dictionaries. For example, "$a/b" expects a keyword "b" within a
// sub-dictionary named "a". A division can be correctly executed by using a
// space between a variables and "/", e.g.

c1  #calc "$a / $b";

// or bracketing the variable, e.g.

c2  #calc "($a)/$b + 1";

// Access to sub-entries using the "/" operator, e.g.
d
{
    b   4.8;
}
e   #calc "$a / $d/b";

// Access to higher-level sub-entries using the "../" operators, e.g.
f
{
    g #calc "$a / $d/b";
}

s   "field";
fieldName #calc "$<string>s + \"Name\"";

time    100;
fileName #calc "\"movingBox_\" + name($time) + \".obj\"";
fileName2 #calc #{ "movingBox_" + name($time) + ".obj" #};

// Additional include files for the #calc code compilation can be specified
// using the #codeInclude entry, e.g. if functions from transform.H are used
angle           -5 [deg];

#codeInclude    "transform.H"
liftDir         #calc "transform(Ry($<scalar>angle), vector(0, 0, 1))";
dragDir         #calc "transform(Ry($<scalar>angle), vector(1, 0, 0))";

// Calculate the magnitude of the velocity and turbulent kinetic energy
// where the velocity is looked-up from testCalc2
magU            #calc "mag($<vector>testCalc2!U)";
k               #calc "1.5*magSqr(0.05*$<vector>{${FOAM_CASE}/testCalc2!U})";

// With #stream multiple code statements can be used to generate the entry using
// 'os << ...;'.
// This is equivalent to #codeStream but with a more compact syntax
// but include files must be specified using separate #codeInclude statements
#codeInclude    "transform.H"
maxAngle        30 [deg];
nAngles         7;
Us              #stream
#{
    const vector U($<vector>testCalc2!U);
    const int nAngles = $nAngles;
    const scalar angleStep = ($<scalar>maxAngle)/(nAngles - 1);
    List<vector> Us(nAngles);
    for(int i=0; i<nAngles; i++)
    {
        const scalar angle = i*angleStep;
        Us[i] = transform(Ry(angle), U);
    }
    os << Us;
#};

// List of vectors example
listU           ((1.1 2.1 1.1) (2.1 3.2 4.1) (4.3 5.3 0));
magU1           #calc "mag($<List<vector>>listU[1])";

// Field of vectors and scalars example
#codeInclude    "Field.H"
magUs           #calc "mag($<Field<vector>>listU)";
magSqrU1        #calc "sqr($<Field<scalar>>magUs[1])";

#codeInclude    "HashTable.H"
namedU          (U0 (1.1 2.1 1.1) U1 (2.1 3.2 4.1) U2 (4.3 5.3 0));
magU2           #calc "mag($<HashTable<vector>>namedU[\"U2\"])";

// List of vectors stored as a typed compound example
listU2          List<vector> ((1.1 2.1 1.1) (2.1 3.2 4.1) (4.3 5.3 0));
magU21          #calc "mag($listU2[1])";

#endCodeBlock

// Complex conditionals are also possible using #if and #calculate
// but not within #codeBlock...#endCodeBlock
#if (#calc "$<scalar>angle < 0")
    negativeAngle $angle;
#else
    positiveAngle $angle;
#endif

// ************************************************************************* //
