Skip to content
Snippets Groups Projects
Commit b4f050ad authored by mark's avatar mark Committed by Mark OLESEN
Browse files

ENH: more flexible selection/naming for ddt2 FO (issue #224)

- bugfix (empty patches), and added detection of steady-state
  scheme.

Caveat: when called via execFlowFunctionObjects will always produce a
  zero field, since the oldTime field is not available for this mode.
parent a5fbb36d
Branches
Tags
No related merge requests found
...@@ -29,6 +29,7 @@ License ...@@ -29,6 +29,7 @@ License
#include "dictionary.H" #include "dictionary.H"
#include "FieldFunctions.H" #include "FieldFunctions.H"
#include "fvcDdt.H" #include "fvcDdt.H"
#include "steadyStateDdtScheme.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
...@@ -39,76 +40,198 @@ namespace Foam ...@@ -39,76 +40,198 @@ namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
bool Foam::ddt2::checkFormatName(const word& str)
template<class FieldType>
bool Foam::ddt2::calculate
(
const fvMesh& mesh,
bool& done
)
{ {
if (done) if (str.find("@@") == string::npos)
{ {
return true; // already done - skip WarningInFunction
} << "Bad result naming "
<< "(no '@@' token found), deactivating."
<< nl << endl;
done = mesh.foundObject<FieldType>(fieldName_); return false;
if (!done) }
else if (str == "@@")
{ {
WarningInFunction
<< "Bad result naming "
<< "(only a '@@' token found), deactivating."
<< nl
<< endl;
return false; return false;
} }
else
{
return true;
}
}
const FieldType& input =
mesh.lookupObject<FieldType>(fieldName_);
if (!mesh.foundObject<volScalarField>(resultName_)) void Foam::ddt2::uniqWords(wordReList& lst)
{
boolList retain(lst.size());
wordHashSet uniq;
forAll(lst, i)
{ {
const dimensionSet dims const wordRe& select = lst[i];
retain[i] =
( (
mag_ select.isPattern()
? mag(input.dimensions()/dimTime) || uniq.insert(static_cast<const word&>(select))
: magSqr(input.dimensions()/dimTime)
); );
}
inplaceSubset(retain, lst);
}
bool Foam::ddt2::accept(const word& fieldName) const
{
// check input vs possible result names
// to avoid circular calculations
return !blacklist_.match(fieldName);
}
template<class FieldType>
int Foam::ddt2::apply
(
const fvMesh& mesh,
const word& inputName,
int& state
)
{
// state: return 0 (not-processed), -1 (skip), +1 ok
// already done, or not available
if (state || !mesh.foundObject<FieldType>(inputName))
{
return state;
}
const FieldType& input = mesh.lookupObject<FieldType>(inputName);
word outputName(resultName_);
outputName.replace("@@", inputName);
results_.set(outputName);
if (!mesh.foundObject<volScalarField>(outputName))
{
mesh.objectRegistry::store mesh.objectRegistry::store
( (
new volScalarField new volScalarField
( (
IOobject IOobject
( (
resultName_, outputName,
mesh.time().timeName(), mesh.time().timeName(),
mesh, mesh,
IOobject::NO_READ, IOobject::NO_READ,
IOobject::NO_WRITE // OR IOobject::AUTO_WRITE IOobject::NO_WRITE
), ),
mesh, mesh,
dimensionedScalar dimensionedScalar
( (
"zero", "0",
dims, (
mag_
? mag(input.dimensions()/dimTime)
: magSqr(input.dimensions()/dimTime)
),
Zero Zero
), )
emptyPolyPatch::typeName
) )
); );
} }
volScalarField& field = const_cast<volScalarField&> volScalarField& output = const_cast<volScalarField&>
( (
mesh.lookupObject<volScalarField>(resultName_) mesh.lookupObject<volScalarField>(outputName)
); );
if (mag_) if (mag_)
{ {
field = mag(fvc::ddt(input)); output = mag(fvc::ddt(input));
} }
else else
{ {
field = magSqr(fvc::ddt(input)); output = magSqr(fvc::ddt(input));
}
if (log_)
{
// could add additional statistics here
Info<< type() << " " << name_
<< " field " << output
<< " average: " << gAverage(output) << endl;
}
state = +1;
return state;
}
int Foam::ddt2::process(const fvMesh& mesh, const word& fieldName)
{
if (!accept(fieldName))
{
return -1;
}
int state = 0;
apply<volScalarField>(mesh, fieldName, state);
apply<volVectorField>(mesh, fieldName, state);
return state;
}
void Foam::ddt2::process(const fvMesh& mesh)
{
results_.clear();
wordHashSet candidates = subsetStrings(selectFields_, mesh.names());
DynamicList<word> missing(selectFields_.size());
DynamicList<word> ignored(selectFields_.size());
// check exact matches first
forAll(selectFields_, i)
{
const wordRe& select = selectFields_[i];
if (!select.isPattern())
{
const word& fieldName = static_cast<const word&>(select);
if (!candidates.erase(fieldName))
{
missing.append(fieldName);
}
else if (process(mesh, fieldName) < 1)
{
ignored.append(fieldName);
}
}
} }
return done; forAllConstIter(wordHashSet, candidates, iter)
{
process(mesh, iter.key());
}
if (missing.size())
{
WarningInFunction
<< "Missing field " << missing << endl;
}
if (ignored.size())
{
WarningInFunction
<< "Unprocessed field " << ignored << endl;
}
} }
...@@ -125,13 +248,28 @@ Foam::ddt2::ddt2 ...@@ -125,13 +248,28 @@ Foam::ddt2::ddt2
name_(name), name_(name),
obr_(obr), obr_(obr),
active_(true), active_(true),
fieldName_("undefined-fieldName"), selectFields_(),
resultName_(word::null), resultName_(word::null),
blacklist_(),
results_(),
log_(true), log_(true),
mag_(dict.lookupOrDefault<Switch>("mag", false)) mag_(dict.lookupOrDefault<Switch>("mag", false))
{ {
// Check if the available mesh is an fvMesh, otherwise deactivate // Check if the available mesh is an fvMesh and transient,
if (!isA<fvMesh>(obr_)) // otherwise deactivate
if (isA<fvMesh>(obr_))
{
const fvMesh& mesh = refCast<const fvMesh>(obr_);
if (word(mesh.ddtScheme("default")) == "steadyState")
{
active_ = false;
WarningInFunction
<< "Steady-state, deactivating." << nl
<< endl;
}
}
else
{ {
active_ = false; active_ = false;
WarningInFunction WarningInFunction
...@@ -157,76 +295,62 @@ void Foam::ddt2::read(const dictionary& dict) ...@@ -157,76 +295,62 @@ void Foam::ddt2::read(const dictionary& dict)
{ {
log_.readIfPresent("log", dict); log_.readIfPresent("log", dict);
dict.lookup("fieldName") >> fieldName_; dict.lookup("fields") >> selectFields_;
dict.readIfPresent("resultName", resultName_); uniqWords(selectFields_);
resultName_ = dict.lookupOrDefault<word>
(
"result",
( mag_ ? "mag(ddt(@@))" : "magSqr(ddt(@@))" )
);
if (resultName_.empty()) active_ = checkFormatName(resultName_);
if (active_)
{ {
resultName_ = blacklist_.set
( (
word(mag_ ? "mag" : "magSqr") string::quotemeta<regExp>
+ "(ddt(" + fieldName_ + "))" (
resultName_
).replace("@@", "(.+)")
); );
} }
else
{
blacklist_.clear();
}
} }
} }
void Foam::ddt2::execute() void Foam::ddt2::execute()
{ {
results_.clear();
if (active_) if (active_)
{ {
const fvMesh& mesh = refCast<const fvMesh>(obr_); process(refCast<const fvMesh>(obr_));
bool done = false;
calculate<volScalarField>(mesh, done);
calculate<volVectorField>(mesh, done);
if (!done)
{
WarningInFunction
<< "Unprocessed field " << fieldName_ << endl;
}
} }
} }
void Foam::ddt2::end()
{
// Do nothing
}
void Foam::ddt2::timeSet()
{
// Do nothing
}
void Foam::ddt2::write() void Foam::ddt2::write()
{ {
if (active_) if (active_)
{ {
if (obr_.foundObject<regIOobject>(resultName_)) // consistent output order
const wordList outputList = results_.sortedToc();
forAll(outputList, i)
{ {
const regIOobject& io = const word& fieldName = outputList[i];
obr_.lookupObject<regIOobject>(resultName_);
if (log_) if (obr_.foundObject<regIOobject>(fieldName))
{ {
const volScalarField& field = dynamicCast<const volScalarField&> const regIOobject& io =
( obr_.lookupObject<regIOobject>(fieldName);
io
);
// could add additional statistics here io.write();
Info<< type() << " " << name_
<< " output: writing field " << field.name()
<< " average: " << gAverage(field) << endl;
} }
// could also add option to suppress writing?
io.write();
} }
} }
} }
......
...@@ -40,8 +40,8 @@ Description ...@@ -40,8 +40,8 @@ Description
{ {
type ddt2; type ddt2;
functionObjectLibs ("libutilityFunctionObjects.so"); functionObjectLibs ("libutilityFunctionObjects.so");
fieldName p; fields (p);
resultName dpdt2; result d@@dt2;
... ...
} }
\endverbatim \endverbatim
...@@ -50,8 +50,8 @@ Description ...@@ -50,8 +50,8 @@ Description
\table \table
Property | Description | Required | Default value Property | Description | Required | Default value
type | type name: ddt2 | yes | type | type name: ddt2 | yes |
fieldName | Name of field to process | yes | fields | Name of fields to process | yes |
resultName | Name of magnitude field | no | magSqr(ddt(fieldName)) result | Name of results | no | magSqr(ddt(@@))
log | Log to standard output | no | yes log | Log to standard output | no | yes
mag | Use 'mag' instead of 'magSqr' | no | false mag | Use 'mag' instead of 'magSqr' | no | false
\endtable \endtable
...@@ -59,6 +59,13 @@ Description ...@@ -59,6 +59,13 @@ Description
Note that the optional 'mag' entry cannot be changed during the simulation Note that the optional 'mag' entry cannot be changed during the simulation
since it alters the dimensions of the output field. since it alters the dimensions of the output field.
A list of fields can contain exact names or regular expressions.
The token '\@\@' in the result name is replaced by the name of the source
field.
The function object will skip over fields that appear to have
already been processed (ie, their names are similar to the output names).
SourceFiles SourceFiles
ddt2.C ddt2.C
IOddt2.H IOddt2.H
...@@ -69,9 +76,10 @@ SourceFiles ...@@ -69,9 +76,10 @@ SourceFiles
#define ddt2_H #define ddt2_H
#include "volFieldsFwd.H" #include "volFieldsFwd.H"
#include "surfaceFieldsFwd.H"
#include "pointFieldFwd.H"
#include "OFstream.H" #include "OFstream.H"
#include "wordReList.H"
#include "regExp.H"
#include "HashSet.H"
#include "Switch.H" #include "Switch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
...@@ -85,7 +93,6 @@ class dictionary; ...@@ -85,7 +93,6 @@ class dictionary;
class fvMesh; class fvMesh;
class polyMesh; class polyMesh;
class mapPolyMesh; class mapPolyMesh;
class dimensionSet;
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class ddt2 Declaration Class ddt2 Declaration
...@@ -104,12 +111,18 @@ class ddt2 ...@@ -104,12 +111,18 @@ class ddt2
//- On/off switch //- On/off switch
bool active_; bool active_;
//- Name of field to process //- Name of fields to process
word fieldName_; wordReList selectFields_;
//- Name of result field //- Formatting for the result fields.
word resultName_; word resultName_;
//- Avoid processing the same field twice.
mutable regExp blacklist_;
//- Hashed names of result fields.
wordHashSet results_;
//- Switch to send output to Info as well as to file //- Switch to send output to Info as well as to file
Switch log_; Switch log_;
...@@ -121,21 +134,25 @@ class ddt2 ...@@ -121,21 +134,25 @@ class ddt2
// Private Member Functions // Private Member Functions
//- Create result field upon demand //- Check that the word contains the appropriate substitution token(s).
volScalarField& getOrCreateResultField static bool checkFormatName(const word&);
(
const fvMesh&,
const dimensionSet& inputDims
);
//- Eliminate duplicate 'word' entries
static void uniqWords(wordReList&);
//- Create result field upon demand
template<class FieldType>
bool calculate(const FieldType& input);
//- Create result field upon demand //- Accept unless field name appears to have already been processed
bool accept(const word& fieldName) const;
//- Apply for the volume field type
template<class FieldType> template<class FieldType>
bool calculate(const fvMesh&, bool& done); int apply(const fvMesh& mesh, const word& inputName, int& state);
//- Process by trying to apply for various volume field types.
int process(const fvMesh& mesh, const word& inputName);
//- Calculate the ddt2 fields
void process(const fvMesh& mesh);
//- Disallow default bitwise copy construct //- Disallow default bitwise copy construct
...@@ -179,16 +196,18 @@ public: ...@@ -179,16 +196,18 @@ public:
//- Read the ddt2 specification //- Read the ddt2 specification
virtual void read(const dictionary&); virtual void read(const dictionary&);
//- Execute, currently does nothing //- Calculate the ddt2 fields
virtual void execute(); virtual void execute();
//- Execute at the final time-loop, currently does nothing //- Execute at the final time-loop, currently does nothing
virtual void end(); virtual void end()
{}
//- Called when time was set at the end of the Time::operator++ //- Called when time was set at the end of the Time::operator++
virtual void timeSet(); virtual void timeSet()
{}
//- Calculate the ddt2 and write //- Write the ddt fields
virtual void write(); virtual void write();
//- Update for changes of mesh //- Update for changes of mesh
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment