Commit 73a525b7 authored by Mark OLESEN's avatar Mark OLESEN
Browse files

ENH: additional input/output parameters for lumped point motion (closes #804)

- input or output scaling of values to manage dissimilar unit systems
  in the structures model

- logging of communicated force, moments and updated positions.
  This allows tracking of the information exchange throughout the
  duration of the simulation and may assist in post-simulation diagnosis.
parent 51d6008b
......@@ -250,7 +250,7 @@ void Foam::lumpedPointDisplacementPointPatchVectorField::updateCoeffs()
if (Pstream::master())
{
movement().writeData(forces, moments);
movement().writeData(forces, moments, &(db().time()));
// Signal external source to execute
movement().coupler().useSlave();
......
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
......@@ -48,29 +48,65 @@ Foam::lumpedPointMovement::formatNames
};
const Foam::Enum
<
Foam::lumpedPointMovement::scalingType
>
Foam::lumpedPointMovement::scalingNames
{
{ scalingType::LENGTH, "plain" },
{ scalingType::FORCE, "force" },
{ scalingType::MOMENT, "moment" }
};
const Foam::word
Foam::lumpedPointMovement::dictionaryName("lumpedPointMovement");
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
//! \cond fileScope
//- Space-separated vector value (ASCII)
static inline Ostream& putPlain(Ostream& os, const vector& val)
{
os << val.x() << ' ' << val.y() << ' ' << val.z();
return os;
}
//! \cond fileScope
//- Space-separated vector value (ASCII)
static inline Ostream& putTime(Ostream& os, const Time& t)
{
os <<"Time index=" << t.timeIndex()
<< " value=" << t.timeOutputValue();
return os;
}
//! \cond fileScope
//- Write list content with size, bracket, content, bracket one-per-line.
// This makes for consistent for parsing, regardless of the list length.
template <class T>
static void writeList(Ostream& os, const string& header, const UList<T>& lst)
static void writeList(Ostream& os, const string& header, const UList<T>& list)
{
const label len = list.size();
// Header string
os << header.c_str() << nl;
// Write size and start delimiter
os << lst.size() << nl
<< token::BEGIN_LIST << nl;
os << len << nl << token::BEGIN_LIST << nl;
// Write contents
forAll(lst, i)
for (label i=0; i < len; ++i)
{
os << lst[i] << nl;
os << list[i] << nl;
}
// Write end delimiter
......@@ -165,8 +201,11 @@ Foam::lumpedPointMovement::lumpedPointMovement()
coupler_(),
inputName_("positions.in"),
outputName_("forces.out"),
logName_("movement.log"),
inputFormat_(lumpedPointState::inputFormatType::DICTIONARY),
outputFormat_(outputFormatType::DICTIONARY),
scaleInput_(-1.0),
scaleOutput_(-1.0),
state0_(),
state_(),
thresholdPtr_(0),
......@@ -198,6 +237,11 @@ Foam::lumpedPointMovement::lumpedPointMovement
autoCentre_(true),
forcesDict_(),
coupler_(),
inputName_("positions.in"),
outputName_("forces.out"),
logName_("movement.log"),
scaleInput_(-1.0),
scaleOutput_(-1.0),
state0_(),
state_(),
thresholdPtr_(0),
......@@ -262,6 +306,7 @@ void Foam::lumpedPointMovement::readDict(const dictionary& dict)
commDict.lookup("inputName") >> inputName_;
commDict.lookup("outputName") >> outputName_;
commDict.readIfPresent("logName", logName_);
inputFormat_ = lumpedPointState::formatNames.lookup
(
......@@ -274,6 +319,47 @@ void Foam::lumpedPointMovement::readDict(const dictionary& dict)
"outputFormat",
commDict
);
scaleInput_ = -1;
scaleOutput_ = -1;
const dictionary* scaleDict = nullptr;
if ((scaleDict = commDict.subDictPtr("scaleInput")))
{
for (int i=0; i < scaleInput_.size(); ++i)
{
const word& key = scalingNames[scalingType(i)];
if
(
scaleDict->readIfPresent(key, scaleInput_[i])
&& scaleInput_[i] > 0
)
{
Info<<"Using input " << key << " multiplier: "
<< scaleInput_[i] << nl;
}
}
}
if ((scaleDict = commDict.subDictPtr("scaleOutput")))
{
for (int i=0; i < scaleOutput_.size(); ++i)
{
const word& key = scalingNames[scalingType(i)];
if
(
scaleDict->readIfPresent(key, scaleOutput_[i])
&& scaleOutput_[i] > 0
)
{
Info<<"Using output " << key << " multiplier: "
<< scaleOutput_[i] << nl;
}
}
}
}
......@@ -638,6 +724,8 @@ bool Foam::lumpedPointMovement::readState()
coupler().resolveFile(inputName_)
);
state_.scalePoints(scaleInput_[scalingType::LENGTH]);
state_.relax(relax_, prev);
return status;
......@@ -646,45 +734,114 @@ bool Foam::lumpedPointMovement::readState()
bool Foam::lumpedPointMovement::writeData
(
const UList<vector>& forces
Ostream& os,
const UList<vector>& forces,
const UList<vector>& moments,
const outputFormatType fmt,
const Time* timeinfo
) const
{
if (!Pstream::master())
const bool writeMoments = (moments.size() == forces.size());
if (fmt == outputFormatType::PLAIN)
{
return false;
}
os <<"########" << nl;
if (timeinfo)
{
os <<"# ";
putTime(os, *timeinfo) << nl;
}
os <<"# size=" << this->size() << nl
<<"# columns (points) (forces)";
const fileName output(coupler().resolveFile(outputName_));
OFstream os(output); // ASCII
if (writeMoments)
{
os << " (moments)";
}
if (outputFormat_ == outputFormatType::PLAIN)
{
os <<"# output from OpenFOAM" << nl
<<"# N, points, forces" << nl
<< this->size() << nl;
os << nl;
bool report = false;
scalar scaleLength = scaleOutput_[scalingType::LENGTH];
scalar scaleForce = scaleOutput_[scalingType::FORCE];
scalar scaleMoment = scaleOutput_[scalingType::MOMENT];
if (scaleLength > 0)
{
report = true;
}
else
{
scaleLength = 1.0;
}
if (scaleForce > 0)
{
report = true;
}
else
{
scaleForce = 1.0;
}
if (writeMoments)
{
if (scaleMoment > 0)
{
report = true;
}
else
{
scaleMoment = 1.0;
}
}
if (report)
{
os <<"# scaling points=" << scaleLength
<<" forces=" << scaleForce;
if (writeMoments)
{
os <<" moments=" << scaleMoment;
}
os << nl;
}
const char* zeroVector = "0 0 0";
os <<"########" << nl;
forAll(locations_, i)
{
const vector pos = locations_[i] * axis_;
const vector pos = scaleLength * (locations_[i] * axis_);
os << pos.x() << ' '
<< pos.y() << ' '
<< pos.z() << ' ';
putPlain(os, pos) << ' ';
if (i < forces.size())
{
os << forces[i].x() << ' '
<< forces[i].y() << ' '
<< forces[i].z();
const vector val(scaleForce * forces[i]);
putPlain(os, val);
}
else
{
os << zeroVector;
putPlain(os, vector::zero);
}
os << nl;
if (writeMoments)
{
os << ' ';
if (i < moments.size())
{
const vector val(scaleMoment * moments[i]);
putPlain(os, val);
}
else
{
putPlain(os, vector::zero);
}
}
os << nl;
}
}
else
......@@ -693,10 +850,21 @@ bool Foam::lumpedPointMovement::writeData
// - exclude the usual OpenFOAM 'FoamFile' header
// - ensure lists have consistent format
os <<"// output from OpenFOAM" << nl << nl;
os <<"////////" << nl;
if (timeinfo)
{
os <<"// ";
putTime(os, *timeinfo) << nl;
}
os << nl;
writeList(os, "points", (locations_*axis_)());
writeList(os, "forces", forces);
if (writeMoments)
{
writeList(os, "moments", moments);
}
}
return true;
......@@ -706,7 +874,8 @@ bool Foam::lumpedPointMovement::writeData
bool Foam::lumpedPointMovement::writeData
(
const UList<vector>& forces,
const UList<vector>& moments
const UList<vector>& moments,
const Time* timeinfo
) const
{
if (!Pstream::master())
......@@ -714,60 +883,28 @@ bool Foam::lumpedPointMovement::writeData
return false;
}
const fileName output(coupler().resolveFile(outputName_));
OFstream os(output); // ASCII
if (outputFormat_ == outputFormatType::PLAIN)
// Regular output
{
os <<"# output from OpenFOAM" << nl
<<"# N, points, forces, moments" << nl
<< this->size() << nl;
const char* zeroVector = "0 0 0";
forAll(locations_, i)
{
const vector pos = locations_[i] * axis_;
const fileName output(coupler().resolveFile(outputName_));
OFstream os(output, IOstream::ASCII);
os << pos.x() << ' '
<< pos.y() << ' '
<< pos.z() << ' ';
if (i < forces.size())
{
os << forces[i].x() << ' '
<< forces[i].y() << ' '
<< forces[i].z() << ' ';
}
else
{
os << zeroVector << ' ';
}
if (i < moments.size())
{
os << moments[i].x() << ' '
<< moments[i].y() << ' '
<< moments[i].z();
}
else
{
os << zeroVector;
}
os << nl;
}
writeData(os, forces, moments, outputFormat_, timeinfo);
}
else
// Log output
{
// Make it easier for external programs to parse
// - exclude the usual OpenFOAM 'FoamFile' header
// - ensure lists have consistent format
const fileName output(coupler().resolveFile(logName_));
os <<"// output from OpenFOAM" << nl << nl;
OFstream os
(
output,
IOstream::ASCII,
IOstream::currentVersion,
IOstream::UNCOMPRESSED,
true // append mode
);
writeList(os, "points", (locations_*axis_)());
writeList(os, "forces", forces);
writeList(os, "moments", moments);
writeData(os, forces, moments, outputFormatType::PLAIN, timeinfo);
}
return true;
......
......@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2016-2017 OpenCFD Ltd.
\\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
License
......@@ -60,8 +60,10 @@ SourceFiles
namespace Foam
{
// Forward declarations
class polyMesh;
class Time;
/*---------------------------------------------------------------------------*\
Class lumpedPointMovement Declaration
......@@ -78,11 +80,22 @@ public:
DICTIONARY
};
//- Output format types
enum scalingType
{
LENGTH = 0,
FORCE,
MOMENT
};
// Static data
//- Names for the output format types
static const Enum<outputFormatType> formatNames;
//- Names for the scaling types
static const Enum<scalingType> scalingNames;
private:
......@@ -125,9 +138,15 @@ private:
//- File io
word inputName_;
word outputName_;
word logName_;
lumpedPointState::inputFormatType inputFormat_;
outputFormatType outputFormat_;
//- Optional scale factors for input/output files
FixedList<scalar, 1> scaleInput_;
FixedList<scalar, 3> scaleOutput_;
// Demand-driven private data
......@@ -246,6 +265,9 @@ public:
//- The output (forces) file name
inline const word& outputName() const;
//- The log file name
inline const word& logName() const;
//- The input (state) file format
inline lumpedPointState::inputFormatType inputFormat() const;
......@@ -324,21 +346,24 @@ public:
//- Write axis, locations, division as a dictionary
void writeDict(Ostream& os) const;
//- Write points, forces
//- Write points, forces, moments. Only call from the master process
bool writeData
(
const UList<vector>& forces
Ostream& os,
const UList<vector>& forces,
const UList<vector>& moments,
const outputFormatType fmt = outputFormatType::PLAIN,
const Time* timeinfo = nullptr
) const;
//- Write points, forces, moments
bool writeData
(
const UList<vector>& forces,
const UList<vector>& moments
const UList<vector>& moments = List<vector>(),
const Time* timeinfo = nullptr
) const;
//- Read state from file, applying relaxation as requested
bool readState();
......
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: plus |
| \\ / A nd | Web: www.OpenFOAM.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object lumpedPointMovement;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Reference axis for the locations
axis (0 0 1);
// Locations of the lumped points
locations 11(0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5);
// Division for pressure forces (0-1)
division 0.5;
//- If present, the offset of patch points compared to the locations
// Otherwise determined from the bounding box
// centre (0 0 0);
//- The interpolation scheme
interpolationScheme linear;
//- Relaxation/scaling factor when updating positions
relax 1.0;
forces
{
//- The pressure name (default: p)
p p;
//- Reference pressure [Pa] (default: 0)
pRef 0;
//- Reference density for incompressible calculations (default: 1)
rhoRef 1;
}
communication
{
commsDir "comms";
log on;
waitInterval 1;
timeOut 100;
initByExternal false;
// Input file of positions/rotation, written by external application
inputName positions.in;
// Output file of forces, written by OpenFOAM
outputName forces.out;
// Log of points/forces/moments during the simulation
logName movement.log;
inputFormat dictionary;
outputFormat dictionary;
debugTable "$FOAM_CASE/output.txt";
// Scaling applied to values read from 'inputName'
scaleInput
{
//- Length multiplier (to metres). Eg 0.001 for [mm] -> [m]
length 1;
}
// Scaling applied to values written to 'outputName'
scaleOutput
{
//- Length multiplier (from metres). Eg 1000 for [m] -> [mm]
length 1;
//- Force units multiplier (from Pa)
force 1;
//- Moment units multiplier (from N.m)
moment 1;
}
}
// ************************************************************************* //