codeStream: Typed substitutions
Dictionary entries constructed with #calc and #codeStream can now
conveniently access and use typed variables. This means calculations
involving vectors and tensors and list and field types are now possible.
To access a variable and construct it as a given type within a #calc
or #codeStream entry, put the type immediately after the $ symbol inside
angled brackets <>. So, $<vector>var or $<vector>{var} substitutes a
variable named var as a vector.
Examples:
- Reflect a point in a plane defined by a normal
p (1 2 3);
n (1 1 0);
pStar #calc "$<vector>p - (2*sqr($<vector>n)/magSqr($<vector>n)&$<vector>p)";
- Rotate a list of points around an axis by a given angle
points ((3 0 0) (2 1 1) (1 2 2) (0 3 3));
rotation
{
axis (0 1 1);
angle 45;
}
#codeStream
{
codeInclude
#{
#include "pointField.H"
#include "transform.H"
#};
code
#{
const pointField points($<List<point>>points);
const vector axis = $<vector>!rotation/axis;
const scalar angle = degToRad($!rotation/angle);
os << "pointsRotated" << nl << (Ra(axis, angle) & points)() << ";";
#};
};
- Compute the centre and trianglation of a polygon
polygon ((0 0 0) (1 0 0) (2 1 0) (0 2 0) (-1 1 0));
#codeStream
{
codeInclude
#{
#include "polygonTriangulate.H"
#};
code
#{
const List<point> polygon($<List<point>>polygon);
writeEntry(os, "polygonCentre", face::centre(polygon));
polygonTriangulate triEngine;
triEngine.triangulate(polygon);
os << "polygonTris" << ' ' << triEngine.triPoints() << ";";
#};
};
- Generate a single block blockMeshDict for use with snappyHexMesh with no redundant information
min (-2.5 -1.2 -3.0); // Minimum coordinates of the block
max (2.5 1.2 3.0); // Maximum coordinates of the block
nCellsByL 33.3333; // Number of cells per unit length
// Calculate the number of cells in each block direction
nCells #calc "Vector<label>($nCellsByL*($<vector>max - $<vector>min) + vector::one/2)";
// Generate the vertices using a boundBox
vertices #codeStream
{
codeInclude
#{
#include "boundBox.H"
#};
code
#{
os << boundBox($<vector>min, $<vector>max).points();
#};
};
blocks
(
hex (0 1 2 3 4 5 6 7) $nCells simpleGrading (1 1 1)
);
defaultPatch
{
type patch;
}
boundary
();
This commit is contained in:
@ -27,8 +27,10 @@ Description
|
|||||||
\*---------------------------------------------------------------------------*/
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
#include "dictionary.H"
|
#include "dictionary.H"
|
||||||
|
#include "fieldTypes.H"
|
||||||
#include "Ostream.H"
|
#include "Ostream.H"
|
||||||
#include "Pstream.H"
|
#include "Pstream.H"
|
||||||
|
#include "read.H"
|
||||||
#include "unitConversion.H"
|
#include "unitConversion.H"
|
||||||
|
|
||||||
//{{{ begin codeInclude
|
//{{{ begin codeInclude
|
||||||
|
|||||||
@ -513,9 +513,11 @@ public:
|
|||||||
bool patternMatch=true
|
bool patternMatch=true
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
//- Find and return an entry data stream pointer if present
|
//- Find and return an entry data stream pointer if present,
|
||||||
// otherwise return nullptr. Allows scoping using '/' with
|
// otherwise return nullptr.
|
||||||
// special handling for '!' and '..'.
|
// If recursive, search parent dictionaries.
|
||||||
|
// If patternMatch, use regular expressions.
|
||||||
|
// Allows scoping using '/' with special handling for '!' and '..'.
|
||||||
const entry* lookupScopedEntryPtr
|
const entry* lookupScopedEntryPtr
|
||||||
(
|
(
|
||||||
const word&,
|
const word&,
|
||||||
@ -523,6 +525,19 @@ public:
|
|||||||
bool patternMatch
|
bool patternMatch
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
|
//- Find and return a T,
|
||||||
|
// if not found throw a fatal error.
|
||||||
|
// If recursive, search parent dictionaries.
|
||||||
|
// If patternMatch, use regular expressions.
|
||||||
|
// Allows scoping using '/' with special handling for '!' and '..'.
|
||||||
|
template<class T>
|
||||||
|
T lookupScoped
|
||||||
|
(
|
||||||
|
const word&,
|
||||||
|
bool recursive=false,
|
||||||
|
bool patternMatch=true
|
||||||
|
) const;
|
||||||
|
|
||||||
//- Check if entry is a sub-dictionary
|
//- Check if entry is a sub-dictionary
|
||||||
bool isDict(const word&) const;
|
bool isDict(const word&) const;
|
||||||
|
|
||||||
|
|||||||
@ -223,6 +223,31 @@ bool Foam::dictionary::readIfPresent
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
T Foam::dictionary::lookupScoped
|
||||||
|
(
|
||||||
|
const word& keyword,
|
||||||
|
bool recursive,
|
||||||
|
bool patternMatch
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const entry* entryPtr =
|
||||||
|
lookupScopedEntryPtr(keyword, recursive, patternMatch);
|
||||||
|
|
||||||
|
if (entryPtr == nullptr)
|
||||||
|
{
|
||||||
|
FatalIOErrorInFunction
|
||||||
|
(
|
||||||
|
*this
|
||||||
|
) << "keyword " << keyword << " is undefined in dictionary "
|
||||||
|
<< name()
|
||||||
|
<< exit(FatalIOError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pTraits<T>(entryPtr->stream());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void Foam::dictionary::add(const keyType& k, const T& t, bool overwrite)
|
void Foam::dictionary::add(const keyType& k, const T& t, bool overwrite)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -295,4 +295,26 @@ void Foam::string::strip(const string& str)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::string::size_type Foam::string::findClosing
|
||||||
|
(
|
||||||
|
const char c,
|
||||||
|
string::size_type i0 = 0
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
size_t level = 1;
|
||||||
|
|
||||||
|
string::size_type i = i0 + 1;
|
||||||
|
|
||||||
|
while (level > 0 && i < size())
|
||||||
|
{
|
||||||
|
if (operator[](i) == operator[](i0)) ++level;
|
||||||
|
if (operator[](i) == c) --level;
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return level == 0 ? i - 1 : string::npos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// ************************************************************************* //
|
// ************************************************************************* //
|
||||||
|
|||||||
@ -244,6 +244,24 @@ public:
|
|||||||
//- Strip characters from the start and end of the string
|
//- Strip characters from the start and end of the string
|
||||||
void strip(const string&);
|
void strip(const string&);
|
||||||
|
|
||||||
|
//- Find the closing character. Brackets counting algorithm. The
|
||||||
|
// opening bracket character is taken to be the one at the starting
|
||||||
|
// position. The closing character is provided by argument.
|
||||||
|
//
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// [char #1] [char #15]
|
||||||
|
// | |
|
||||||
|
// V V
|
||||||
|
// string("0(2(4,6)8,a(c)e)g").findClosing(')',1) == 15
|
||||||
|
//
|
||||||
|
// [char #3] [char #7]
|
||||||
|
// | |
|
||||||
|
// V V
|
||||||
|
// string("0(2(4,6)8,a(c)e)g").findClosing(')',3) == 7
|
||||||
|
//
|
||||||
|
size_type findClosing(const char, const size_type) const;
|
||||||
|
|
||||||
|
|
||||||
// Member Operators
|
// Member Operators
|
||||||
|
|
||||||
|
|||||||
@ -410,6 +410,7 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString
|
|||||||
(
|
(
|
||||||
string& s,
|
string& s,
|
||||||
const dictionary& dict,
|
const dictionary& dict,
|
||||||
|
const word& dictVar,
|
||||||
const char sigil
|
const char sigil
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -427,16 +428,28 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString
|
|||||||
{
|
{
|
||||||
// Find end of first occurrence
|
// Find end of first occurrence
|
||||||
string::size_type endVar = begVar;
|
string::size_type endVar = begVar;
|
||||||
string::size_type delim = 0;
|
string::size_type begDelim = 0, endDelim = 0;
|
||||||
|
|
||||||
if (s[begVar+1] == '{')
|
// Get the type, if any
|
||||||
|
word varType;
|
||||||
|
if (s[begVar+1] == '<')
|
||||||
{
|
{
|
||||||
endVar = s.find('}', begVar);
|
begDelim += s.findClosing('>', begVar+1) - begVar;
|
||||||
delim = 1;
|
varType = s.substr(begVar+2, begDelim-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse any braces and find the end of the variable
|
||||||
|
if (s[begVar+begDelim+1] == '{')
|
||||||
|
{
|
||||||
|
endVar = s.find('}', begVar+begDelim);
|
||||||
|
begDelim += 1;
|
||||||
|
endDelim += 1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string::iterator iter = s.begin() + begVar + 1;
|
endVar = begVar + begDelim;
|
||||||
|
|
||||||
|
string::iterator iter = s.begin() + begVar + begDelim + 1;
|
||||||
|
|
||||||
// Accept all dictionary and environment variable characters
|
// Accept all dictionary and environment variable characters
|
||||||
while
|
while
|
||||||
@ -474,8 +487,8 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString
|
|||||||
(
|
(
|
||||||
s.substr
|
s.substr
|
||||||
(
|
(
|
||||||
begVar + 1 + delim,
|
begVar + begDelim + 1,
|
||||||
endVar - begVar - 2*delim
|
(endVar - endDelim) - (begVar + begDelim)
|
||||||
),
|
),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
@ -491,25 +504,54 @@ Foam::string& Foam::stringOps::inplaceExpandCodeString
|
|||||||
// Substitute if found
|
// Substitute if found
|
||||||
if (ePtr)
|
if (ePtr)
|
||||||
{
|
{
|
||||||
// Write to string buffer. Force floating point numbers to
|
|
||||||
// be printed with at least some decimal digits.
|
|
||||||
OStringStream buf;
|
OStringStream buf;
|
||||||
buf << scientific;
|
|
||||||
buf.precision(IOstream::defaultPrecision());
|
|
||||||
|
|
||||||
if (ePtr->isDict())
|
if (!dictVar.empty() && !varType.empty())
|
||||||
{
|
{
|
||||||
ePtr->dict().write(buf, false);
|
// If the dictionary is accessible and the type is
|
||||||
|
// known, then lookup the variable in the code, rather
|
||||||
|
// than substituting its value. That way we don't need
|
||||||
|
// to recompile this string if the value changes.
|
||||||
|
buf << dictVar
|
||||||
|
<< ".lookupScoped<" << varType << ">"
|
||||||
|
<< "(\"" << varName << "\", true, false)";
|
||||||
}
|
}
|
||||||
else if (isA<primitiveEntry>(*ePtr))
|
|
||||||
|
if (dictVar.empty() && !varType.empty())
|
||||||
{
|
{
|
||||||
dynamicCast<const primitiveEntry>(*ePtr)
|
// If the dictionary is not accessible but the type is
|
||||||
.write(buf, true);
|
// known, then read the substituted value from a string
|
||||||
|
buf << "read<" << varType << ">(\"";
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (dictVar.empty() || varType.empty())
|
||||||
{
|
{
|
||||||
// Can't do any other types. Fail.
|
// If the dictionary is not accessible and/or the type
|
||||||
dynamicCast<const primitiveEntry>(*ePtr);
|
// is not known, then we need to substitute the
|
||||||
|
// variable's value
|
||||||
|
|
||||||
|
// Make sure floating point values print with at least
|
||||||
|
// some decimal points
|
||||||
|
buf << scientific;
|
||||||
|
buf.precision(IOstream::defaultPrecision());
|
||||||
|
|
||||||
|
// Write the dictionary or primitive entry. Fail if
|
||||||
|
// anything else.
|
||||||
|
if (ePtr->isDict())
|
||||||
|
{
|
||||||
|
ePtr->dict().write(buf, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
dynamicCast<const primitiveEntry>(*ePtr)
|
||||||
|
.write(buf, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dictVar.empty() && !varType.empty())
|
||||||
|
{
|
||||||
|
// Close the string and read function as necessary
|
||||||
|
buf << "\")";
|
||||||
}
|
}
|
||||||
|
|
||||||
s.std::string::replace
|
s.std::string::replace
|
||||||
|
|||||||
@ -110,6 +110,7 @@ namespace stringOps
|
|||||||
(
|
(
|
||||||
string&,
|
string&,
|
||||||
const dictionary& dict,
|
const dictionary& dict,
|
||||||
|
const word& dictVar = "dict",
|
||||||
const char sigil = '$'
|
const char sigil = '$'
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user