diff --git a/src/functionObjects/field/Make/files b/src/functionObjects/field/Make/files index 649176d1f4..580d9a3340 100644 --- a/src/functionObjects/field/Make/files +++ b/src/functionObjects/field/Make/files @@ -118,4 +118,6 @@ stabilityBlendingFactor/stabilityBlendingFactor.C interfaceHeight/interfaceHeight.C +STDMD/STDMD.C + LIB = $(FOAM_LIBBIN)/libfieldFunctionObjects diff --git a/src/functionObjects/field/Make/options b/src/functionObjects/field/Make/options index c24acfb632..5d3d5f11d6 100644 --- a/src/functionObjects/field/Make/options +++ b/src/functionObjects/field/Make/options @@ -1,4 +1,5 @@ EXE_INC = \ + -I$(LIB_SRC)/OpenFOAM/lnInclude \ -I$(LIB_SRC)/finiteVolume/lnInclude \ -I$(LIB_SRC)/fileFormats/lnInclude \ -I$(LIB_SRC)/surfMesh/lnInclude \ @@ -22,6 +23,7 @@ EXE_INC = \ -I$(LIB_SRC)/phaseSystemModels/reactingEulerFoam/phaseSystems/lnInclude LIB_LIBS = \ + -lOpenFOAM \ -lfiniteVolume \ -lfileFormats \ -lsurfMesh \ diff --git a/src/functionObjects/field/STDMD/STDMD.C b/src/functionObjects/field/STDMD/STDMD.C new file mode 100644 index 0000000000..d550a4cefb --- /dev/null +++ b/src/functionObjects/field/STDMD/STDMD.C @@ -0,0 +1,1280 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +\*---------------------------------------------------------------------------*/ + +#include "STDMD.H" +#include "addToRunTimeSelectionTable.H" + +using namespace Foam::constant::mathematical; + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + defineTypeNameAndDebug(STDMD, 0); + addToRunTimeSelectionTable(functionObject, STDMD, dictionary); +} +} + + +const Foam::Enum +< + Foam::functionObjects::STDMD::modeSorterType +> +Foam::functionObjects::STDMD::modeSorterTypeNames +({ + { modeSorterType::KIEWAT , "kiewat" }, + { modeSorterType::KOU_ZHANG , "kouZhang" }, + { modeSorterType::FIRST_SNAPSHOT, "firstSnap" } +}); + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +Foam::scalar Foam::functionObjects::STDMD::parnorm +( + const RMatrix& colVector +) const +{ + #ifdef FULLDEBUG + // Check if the given RectangularMatrix is effectively a column vector + if (colVector.n() != 1) + { + FatalErrorInFunction + << " # Input matrix is not a column vector. #" + << abort(FatalError); + } + #endif + const bool noSqrt = true; + scalar result(colVector.columnNorm(0, noSqrt)); + reduce(result, sumOp()); + + // Heuristic addition to avoid very small or zero norm + return max(SMALL, Foam::sqrt(result)); +} + + +void Foam::functionObjects::STDMD::snapshot() +{ + bool processed = false; + processed = processed || getSnapshotType(); + processed = processed || getSnapshotType(); + processed = processed || getSnapshotType(); + processed = processed || getSnapshotType(); + processed = processed || getSnapshotType(); + + if (!processed) + { + FatalErrorInFunction + << " # Unknown type of input field during snapshot loading = " + << fieldName_ << " #" << nl + << " # Do you execute required functionObjects " + << "before executing STDMD, e.g. mapFields?" + << abort(FatalError); + } +} + + +void Foam::functionObjects::STDMD::init() +{ + bool processed = false; + processed = processed || getComps(); + processed = processed || getComps(); + processed = processed || getComps(); + processed = processed || getComps(); + processed = processed || getComps(); + + if (!processed) + { + FatalErrorInFunction + << " # Unknown type of input field during initialisation = " + << fieldName_ << " #" << nl + << " # Do you execute required functionObjects " + << "before executing STDMD, e.g. mapFields?" + << abort(FatalError); + } + + nSnap_ = nComps_*mesh_.nCells(); + + if (nSnap_ <= 0) + { + FatalErrorInFunction + << " # Zero-size input field = " << fieldName_ << " #" + << abort(FatalError); + } + + currIndex_ = 0; + zNorm_ = 0; + ezNorm_ = 0; + + z_ = RMatrix(2*nSnap_, 1, Zero); + ez_ = z_; + X1_ = RMatrix(nSnap_, 1, Zero); + Qz_ = z_; + Gz_ = SMatrix(1); + + RxInv_.clear(); + Ap_.clear(); + oEVecs_.clear(); + oEVals_.clear(); + oAmps_.clear(); + oFreqs_.clear(); + iFreqs_.clear(); + oMags_.clear(); + iMags_.clear(); + + initialised_ = true; +} + + +void Foam::functionObjects::STDMD::initBasis() +{ + std::copy(z_.cbegin(), z_.cbegin() + nSnap_, X1_.begin()); + + zNorm_ = parnorm(z_); + Qz_ = z_/zNorm_; + Gz_(0,0) = sqr(zNorm_); +} + + +void Foam::functionObjects::STDMD::GramSchmidt() +{ + ez_ = z_; + RMatrix dz(Qz_.n(), 1, Zero); + + for (label i = 0; i < nGramSchmidt_; ++i) + { + dz = Qz_ & ez_; + reduce(dz, sumOp()); + ez_ -= Qz_*dz; + } +} + + +void Foam::functionObjects::STDMD::expandBasis() +{ + Log<< tab << "# " << name() << ":" + << " Expanding orthonormal basis for field = " << fieldName_ << " #" + << endl; + + // Stack a column (ez_/ezNorm_) to Qz_ + Qz_.resize(Qz_.m(), Qz_.n() + 1); + Qz_.subColumn(Qz_.n() - 1) = ez_/ezNorm_; + + // Stack a row (Zero) and column (Zero) to Gz_ + Gz_.resize(Gz_.m() + 1); +} + + +void Foam::functionObjects::STDMD::updateGz() +{ + RMatrix zTilde(Qz_ & z_); + reduce(zTilde, sumOp()); + + const SMatrix zTildes(zTilde^zTilde); + + Gz_ += zTildes; +} + + +void Foam::functionObjects::STDMD::compressBasis() +{ + Log<< tab << "# " << name() << ":" + << " Compressing orthonormal basis for field = " << fieldName_ << " #" + << endl; + + RMatrix qz; + + if (Pstream::master()) + { + const bool symmetric = true; + const EigenMatrix EM(Gz_, symmetric); + const SquareMatrix& EVecs = EM.EVecs(); + DiagonalMatrix EVals(EM.EValsRe()); + + if (testEigen_) + { + testEigenvalues(Gz_, EVals); + testEigenvectors(Gz_, EVals, EVecs); + } + + // Sort eigenvalues in descending order, and track indices + const auto descend = [&](scalar a, scalar b){ return a > b; }; + const List