From 73a525b7f57fd701cc3a5d3e41f935a40ec90b74 Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Thu, 22 Mar 2018 23:57:46 +0100 Subject: [PATCH] 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. --- ...edPointDisplacementPointPatchVectorField.C | 2 +- src/lumpedPointMotion/lumpedPointMovement.C | 303 +++++++++++++----- src/lumpedPointMotion/lumpedPointMovement.H | 37 ++- .../lumpedPointMovement.dict | 100 ++++++ src/lumpedPointMotion/lumpedPointMovementI.H | 8 +- src/lumpedPointMotion/lumpedPointState.C | 46 ++- src/lumpedPointMotion/lumpedPointState.H | 7 +- .../steady/system/lumpedPointMovement | 23 ++ 8 files changed, 409 insertions(+), 117 deletions(-) create mode 100644 src/lumpedPointMotion/lumpedPointMovement.dict diff --git a/src/lumpedPointMotion/lumpedPointDisplacementPointPatchVectorField.C b/src/lumpedPointMotion/lumpedPointDisplacementPointPatchVectorField.C index 3368d6f59f..1ac55bd8b8 100644 --- a/src/lumpedPointMotion/lumpedPointDisplacementPointPatchVectorField.C +++ b/src/lumpedPointMotion/lumpedPointDisplacementPointPatchVectorField.C @@ -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(); diff --git a/src/lumpedPointMotion/lumpedPointMovement.C b/src/lumpedPointMotion/lumpedPointMovement.C index 4e74f34a2f..00c34c7209 100644 --- a/src/lumpedPointMotion/lumpedPointMovement.C +++ b/src/lumpedPointMotion/lumpedPointMovement.C @@ -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 -static void writeList(Ostream& os, const string& header, const UList& lst) +static void writeList(Ostream& os, const string& header, const UList& 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& forces + Ostream& os, + const UList& forces, + const UList& moments, + const outputFormatType fmt, + const Time* timeinfo ) const { - if (!Pstream::master()) + const bool writeMoments = (moments.size() == forces.size()); + + if (fmt == outputFormatType::PLAIN) { - return false; - } - - const fileName output(coupler().resolveFile(outputName_)); - OFstream os(output); // ASCII - - if (outputFormat_ == outputFormatType::PLAIN) - { - os <<"# output from OpenFOAM" << nl - <<"# N, points, forces" << nl - << this->size() << nl; - - const char* zeroVector = "0 0 0"; - - forAll(locations_, i) + os <<"########" << nl; + if (timeinfo) { - const vector pos = locations_[i] * axis_; + os <<"# "; + putTime(os, *timeinfo) << nl; + } + os <<"# size=" << this->size() << nl + <<"# columns (points) (forces)"; - os << pos.x() << ' ' - << pos.y() << ' ' - << pos.z() << ' '; + if (writeMoments) + { + os << " (moments)"; + } - if (i < forces.size()) + 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) { - os << forces[i].x() << ' ' - << forces[i].y() << ' ' - << forces[i].z(); + report = true; } else { - os << zeroVector; + scaleMoment = 1.0; + } + } + + if (report) + { + os <<"# scaling points=" << scaleLength + <<" forces=" << scaleForce; + + if (writeMoments) + { + os <<" moments=" << scaleMoment; } - os << nl; + os << nl; + } + + os <<"########" << nl; + + forAll(locations_, i) + { + const vector pos = scaleLength * (locations_[i] * axis_); + + putPlain(os, pos) << ' '; + + if (i < forces.size()) + { + const vector val(scaleForce * forces[i]); + putPlain(os, val); + } + else + { + putPlain(os, vector::zero); + } + + 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& forces, - const UList& moments + const UList& 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 fileName output(coupler().resolveFile(outputName_)); + OFstream os(output, IOstream::ASCII); - const char* zeroVector = "0 0 0"; - - forAll(locations_, i) - { - const vector pos = locations_[i] * axis_; - - 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; diff --git a/src/lumpedPointMotion/lumpedPointMovement.H b/src/lumpedPointMotion/lumpedPointMovement.H index dc0f1fb189..7587ec8378 100644 --- a/src/lumpedPointMotion/lumpedPointMovement.H +++ b/src/lumpedPointMotion/lumpedPointMovement.H @@ -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 formatNames; + //- Names for the scaling types + static const Enum 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 scaleInput_; + FixedList 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& forces + Ostream& os, + const UList& forces, + const UList& moments, + const outputFormatType fmt = outputFormatType::PLAIN, + const Time* timeinfo = nullptr ) const; //- Write points, forces, moments bool writeData ( const UList& forces, - const UList& moments + const UList& moments = List(), + const Time* timeinfo = nullptr ) const; - //- Read state from file, applying relaxation as requested bool readState(); diff --git a/src/lumpedPointMotion/lumpedPointMovement.dict b/src/lumpedPointMotion/lumpedPointMovement.dict new file mode 100644 index 0000000000..5223b7d253 --- /dev/null +++ b/src/lumpedPointMotion/lumpedPointMovement.dict @@ -0,0 +1,100 @@ +/*--------------------------------*- 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; + } +} + + +// ************************************************************************* // diff --git a/src/lumpedPointMotion/lumpedPointMovementI.H b/src/lumpedPointMotion/lumpedPointMovementI.H index 43bcdb3094..ef73c4ddea 100644 --- a/src/lumpedPointMotion/lumpedPointMovementI.H +++ b/src/lumpedPointMotion/lumpedPointMovementI.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2017-2018 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -133,6 +133,12 @@ inline const Foam::word& Foam::lumpedPointMovement::outputName() const } +inline const Foam::word& Foam::lumpedPointMovement::logName() const +{ + return logName_; +} + + inline Foam::lumpedPointState::inputFormatType Foam::lumpedPointMovement::inputFormat() const { diff --git a/src/lumpedPointMotion/lumpedPointState.C b/src/lumpedPointMotion/lumpedPointState.C index a84e963fb6..8bddc73d8e 100644 --- a/src/lumpedPointMotion/lumpedPointState.C +++ b/src/lumpedPointMotion/lumpedPointState.C @@ -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 @@ -94,8 +94,8 @@ void Foam::lumpedPointState::readDict(const dictionary& dict) Foam::lumpedPointState::lumpedPointState() : - points_(0), - angles_(0), + points_(), + angles_(), degrees_(false), rotationPtr_(nullptr) {} @@ -110,10 +110,7 @@ Foam::lumpedPointState::lumpedPointState(const lumpedPointState& rhs) {} -Foam::lumpedPointState::lumpedPointState -( - const pointField& pts -) +Foam::lumpedPointState::lumpedPointState(const pointField& pts) : points_(pts), angles_(points_.size(), Zero), @@ -122,10 +119,7 @@ Foam::lumpedPointState::lumpedPointState {} -Foam::lumpedPointState::lumpedPointState -( - tmp& pts -) +Foam::lumpedPointState::lumpedPointState(tmp& pts) : points_(pts), angles_(points_.size(), Zero), @@ -134,13 +128,10 @@ Foam::lumpedPointState::lumpedPointState {} -Foam::lumpedPointState::lumpedPointState -( - const dictionary& dict -) +Foam::lumpedPointState::lumpedPointState(const dictionary& dict) : - points_(0), - angles_(0), + points_(), + angles_(), degrees_(false), rotationPtr_(nullptr) { @@ -168,6 +159,15 @@ void Foam::lumpedPointState::operator=(const lumpedPointState& rhs) } +void Foam::lumpedPointState::scalePoints(const scalar scaleFactor) +{ + if (scaleFactor > 0) + { + points_ *= scaleFactor; + } +} + + void Foam::lumpedPointState::relax ( const scalar alpha, @@ -273,19 +273,17 @@ void Foam::lumpedPointState::writePlain(Ostream& os) const { const vector& pt = points_[i]; - os << pt.x() << ' ' - << pt.y() << ' ' - << pt.z() << ' '; + os << pt.x() << ' ' << pt.y() << ' ' << pt.z(); if (i < angles_.size()) { - os << angles_[i].x() << ' ' - << angles_[i].y() << ' ' - << angles_[i].z() << '\n'; + os << ' ' << angles_[i].x() + << ' ' << angles_[i].y() + << ' ' << angles_[i].z() << '\n'; } else { - os << "0 0 0\n"; + os << " 0 0 0\n"; } } } diff --git a/src/lumpedPointMotion/lumpedPointState.H b/src/lumpedPointMotion/lumpedPointState.H index 0d32fa8927..2d69c8c1b2 100644 --- a/src/lumpedPointMotion/lumpedPointState.H +++ b/src/lumpedPointMotion/lumpedPointState.H @@ -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 @@ -143,13 +143,16 @@ public: //- The local-to-global transformation for each point inline const tensorField& rotations() const; + //- Scale points by given factor. + // Zero and negative values are ignored. + void scalePoints(const scalar scaleFactor); + //- Relax the state // alpha = 1 : no relaxation // alpha < 1 : relaxation // alpha = 0 : do nothing void relax(const scalar alpha, const lumpedPointState& prev); - //- Read input as dictionary content bool readData(Istream& is); diff --git a/tutorials/incompressible/lumpedPointMotion/building/steady/system/lumpedPointMovement b/tutorials/incompressible/lumpedPointMotion/building/steady/system/lumpedPointMovement index f1b33cbbfd..5c65da66da 100644 --- a/tutorials/incompressible/lumpedPointMotion/building/steady/system/lumpedPointMovement +++ b/tutorials/incompressible/lumpedPointMotion/building/steady/system/lumpedPointMovement @@ -66,10 +66,33 @@ communication // 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 "/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; + } } // ************************************************************************* //