/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2022 FOSS GP
-------------------------------------------------------------------------------
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 "objectiveFlowRatePartition.H"
#include "createZeroField.H"
#include "IOmanip.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace objectives
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(objectiveFlowRatePartition, 0);
addToRunTimeSelectionTable
(
objectiveIncompressible,
objectiveFlowRatePartition,
dictionary
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
objectiveFlowRatePartition::objectiveFlowRatePartition
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
)
:
objectiveIncompressible(mesh, dict, adjointSolverName, primalSolverName),
inletPatches_
(
mesh_.boundaryMesh().patchSet
(
dict.get("inletPatches")
).sortedToc()
),
outletPatches_
(
mesh_.boundaryMesh().patchSet
(
dict.get("outletPatches")
).sortedToc()
),
targetFlowRateFraction_(),
currentFlowRateFraction_(outletPatches_.size(), Zero),
inletFlowRate_(0),
flowRateDifference_(outletPatches_.size(), Zero)
{
// Read target fractions if present, otherwise treat them as equally
// distributed
if
(
!dict.readIfPresentCompat
(
"targetFractions", {{"targetPercentages", 2306}},
targetFlowRateFraction_
)
)
{
const label nOutPatches = outletPatches_.size();
targetFlowRateFraction_.setSize(nOutPatches, 1.0/scalar(nOutPatches));
}
// Sanity checks
if (targetFlowRateFraction_.size() != outletPatches_.size())
{
FatalErrorInFunction
<< "Inconsistent sizes for targetFractions and outletPatches"
<< exit(FatalError);
}
// Allocate boundary field pointers
bdJdvPtr_.reset(createZeroBoundaryPtr(mesh_));
bdJdvnPtr_.reset(createZeroBoundaryPtr(mesh_));
// Determine word width for output
for (const label patchI : outletPatches_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
unsigned int wordSize = word(patch.name() + "Ratio").size();
width_ = max(width_, wordSize);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
scalar objectiveFlowRatePartition::J()
{
J_ = 0;
const surfaceScalarField& phi = vars_.phiInst();
// Inlet patches
inletFlowRate_ = 0;
for (const label patchI : inletPatches_)
{
// Negative value
inletFlowRate_ += gSum(phi.boundaryField()[patchI]);
}
// Outlet patches
forAll(outletPatches_, pI)
{
const label patchI = outletPatches_[pI];
const scalar outletFlowRate = gSum(phi.boundaryField()[patchI]);
currentFlowRateFraction_[pI] = -outletFlowRate/inletFlowRate_;
flowRateDifference_[pI] =
targetFlowRateFraction_[pI] - currentFlowRateFraction_[pI];
J_ += 0.5*flowRateDifference_[pI]*flowRateDifference_[pI];
}
return J_;
}
void objectiveFlowRatePartition::update_boundarydJdv()
{
forAll(outletPatches_, pI)
{
const label patchI = outletPatches_[pI];
tmp nf = mesh_.boundary()[patchI].nf();
bdJdvPtr_()[patchI] = nf*flowRateDifference_[pI]/inletFlowRate_;
}
}
void objectiveFlowRatePartition::update_boundarydJdvn()
{
forAll(outletPatches_, pI)
{
const label patchI = outletPatches_[pI];
bdJdvnPtr_()[patchI] = flowRateDifference_[pI]/inletFlowRate_;
}
}
void objectiveFlowRatePartition::addHeaderInfo() const
{
objFunctionFilePtr_()
<< setw(width_) << "#inletFlowRate" << " "
<< setw(width_) << -inletFlowRate_ << endl;
forAll(outletPatches_, pI)
{
const label patchI = outletPatches_[pI];
const fvPatch& patch = mesh_.boundary()[patchI];
objFunctionFilePtr_()
<< setw(width_) << word("#" + patch.name() + "Tar") << " "
<< setw(width_) << targetFlowRateFraction_[pI] << endl;
}
}
void objectiveFlowRatePartition::addHeaderColumns() const
{
for (const label patchI : outletPatches_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
objFunctionFilePtr_()
<< setw(width_) << word(patch.name() + "Ratio") << " ";
}
}
void objectiveFlowRatePartition::addColumnValues() const
{
for (const scalar flowRate : currentFlowRateFraction_)
{
objFunctionFilePtr_()
<< setw(width_) << flowRate << " ";
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace objectives
} // End namespace Foam
// ************************************************************************* //