ENH: overhaul of the adjoint optimisation library

Parts of the adjoint optimisation library were re-designed to generalise
the way sensitivity derivatives (SDs) are computed and to allow easier
extension to primal problems other than the ones governed by
incompressible flows. In specific:
- the adjoint solver now holds virtual functions returning the part of
  SDs that depends only on the primal and the adjoint fields.
- a new class named designVariables was introduced which, apart from
  defining the design variables of the optimisation problem and
  providing hooks for updating them in an optimisation loop, provides
  the part of the SDs that affects directly the flow residuals (e.g.
  geometric variations in shape optimisation, derivatives of source
  terms in topology optimisation, etc). The final assembly of the SDs
  happens here, with the updated sensitivity class acting as an
  intermediate.

With the new structure, when the primal problem changes (for instance,
passive scalars are included), the same design variables and sensitivity
classes can be re-used for all physics, with additional contributions to
the SDs being limited (and contained) to the new adjoint solver to be
implemented. The old code structure would require new SD classes for
each additional primal problem.

As a side-effect, setting up a case has arguably become a bit easier and
more intuitive.

Additional changes include:
---------------------------

- Changes in the formulation and computation of shape sensitivity derivatives
  using the E-SI approach. The latter is now derived directly from the
  FI approach, with proper discretization for the terms and boundary
  conditions that emerge from applying the Gauss divergence theorem used
  to transition from FI to E-SI. When E-SI and FI are based on the same
  Laplace grid displacement model, they are now numerically equivalent
  (the previous formulation proved the theoretical equivalence of the
  two approaches but numerical results could differ, depending on the
  case).
- Sensitivity maps at faces are now computed based (and are deriving
  from) sensitivity maps at points, with a constistent point-to-face
  interpolation (requires the differentiation of volPointInterpolation).
- The objective class now allocates only the member pointers that
  correspond to the non-zero derivatives of the objective w.r.t. the
  flow and geometric quantities, leading to a reduced memory footprint.
  Additionally, contributions from volume-based objectives to the
  adjoint equations have been re-worked, removing the need for
  objectiveManager to be virtual.
- In constrained optimisation, an adjoint solver needs to be present for
  each constraint function. For geometric constraints though, no adjoint
  equations need to solved. This is now accounted for through the null
  adjoint solver and the geometric objectives which do not allocate
  adjoint fields for this kind of constraints, reducing memory
  requirements and file clutter.
- Refactoring of the updateMethod to collaborate with the new
  designVariables. Additionally, all updateMethods can now read and
  write restart data in binary, facilitating exact continuation.
  Furthermore, code shared by various quasi-Newton methods (BFGS, DBFGS,
  LBFGS, SR1) has been organised in the namesake class. Over and above,
  an SQP variant capable of tackling inequality constraints has been
  added (ISQP, with I indicating that the QP problem in the presence of
  inequality constraints is solved through an interior point method).
  Inequality constraints can be one-sided (constraint < upper-value)
  or double-sided (lower-value < constraint < upper-value).
- Bounds can now be defined for the design variables.
  For volumetricBSplines in specific, these can be computed as the
  mid-points of the control points and their neighbouring ones. This
  usually leads to better-defined optimisation problems and reduces the
  chances of an invalid mesh during optimisation.
- Convergence criteria can now be defined for the optimisation loop
  which will stop if the relative objective function reduction over
  the last objective value is lower than a given threshold and
  constraints are satisfied within a give tolerance. If no criteria are
  defined, the optimisation will run for the max. given number of cycles
  provided in controlDict.
- Added a new grid displacement method based on the p-Laplacian
  equation, which seems to outperform other PDE-based approaches.

TUT: updated the shape optimisation tutorials and added a new one
showcasing the use of double-sided constraints, ISQP, applying
no-overlapping constraints to volumetric B-Splines control points
and defining convergence criteria for the optimisation loop.
This commit is contained in:
Vaggelis Papoutsis
2023-07-18 17:07:55 +03:00
committed by Andrew Heather
parent ae8b654a86
commit b6a30fae61
266 changed files with 16883 additions and 11733 deletions

View File

@ -64,14 +64,14 @@ int main(int argc, char *argv[])
{
// Solve all primal equations
om.solvePrimalEquations();
}
// Update primal-based quantities of the adjoint solvers
om.updatePrimalBasedQuantities();
// Clear sensitivities
om.clearSensitivities();
// Solve all adjoint equations
om.solveAdjointEquations();
}
}
Info<< "End\n" << endl;

View File

@ -60,7 +60,8 @@ int main(int argc, char *argv[])
forAll(adjointSolvers, asI)
{
adjointSolvers[asI].getObjectiveManager().updateAndWrite();
adjointSolvers[asI].computeObjectiveSensitivities();
adjointSolvers[asI].
computeObjectiveSensitivities(om.getDesignVariables());
}
}

View File

@ -1,3 +0,0 @@
writeActiveDesignVariables.C
EXE = $(FOAM_APPBIN)/writeActiveDesignVariables

View File

@ -1,14 +0,0 @@
EXE_INC = \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/finiteVolume/cfdTools \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/optimisation/adjointOptimisation/adjoint/lnInclude
EXE_LIBS = \
-lfiniteVolume \
-lmeshTools \
-lfvOptions \
-ldynamicMesh \
-lfvMotionSolvers \
-ladjointOptimisation

View File

@ -1,108 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2019-2022 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 <http://www.gnu.org/licenses/>.
Application
writeActiveDesignVariables
Description
Writes the active design variables based on the selected parameterisation
scheme, as read from the meshMovement part of optimisationDict.
Keeps a back-up of the original optimisationDict in
system/optimisationDict.org, as comments in the dict will be lost.
\*---------------------------------------------------------------------------*/
#include "fvCFD.H"
#include "optMeshMovement.H"
#include "updateMethod.H"
#include "OFstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "setRootCase.H"
#include "createTime.H"
#include "createMesh.H"
IOdictionary optDict
(
IOobject
(
"optimisationDict",
mesh.time().caseSystem(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
);
// Back-up old optimisationDict, to maintain potential comments in it
if (Pstream::master())
{
Foam::cp(optDict.objectPath(), optDict.objectPath() + ".org");
}
// Construct mesh movement object and grab active design variables
// Will exit with error if not implemented for this type
const dictionary& movementDict =
optDict.subDict("optimisation").subDict("meshMovement");
// Empty patch list will do
labelList patchIDs(0);
autoPtr<optMeshMovement> movementPtr
(optMeshMovement::New(mesh, movementDict, patchIDs));
const labelList activeDesignVariables =
movementPtr().getActiveDesignVariables();
// Construct update method to grab the type
dictionary& updateMethodDict =
optDict.subDict("optimisation").subDict("updateMethod");
autoPtr<updateMethod> updMethod(updateMethod::New(mesh, updateMethodDict));
// Add to appropriate dictionary (creates it if it does not exist)
dictionary& coeffsDict = updateMethodDict.subDictOrAdd(updMethod().type());
coeffsDict.add<labelList>
(
"activeDesignVariables",
activeDesignVariables,
true
);
// Write modified dictionary
optDict.regIOobject::writeObject
(
IOstreamOption(IOstreamOption::ASCII),
true
);
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -214,6 +214,7 @@ void ATCModel::computeLimiter
scheme.interpolate(limiter)
);
limiter = fvc::average(faceLimiter);
limiter.correctBoundaryConditions();
}
}

View File

@ -52,26 +52,26 @@ faceCells::faceCells
:
zeroATCcells(mesh, dict)
{
DynamicList<label> cellIDs;
for (const fvPatch& patch : mesh_.boundary())
{
for (const word& patchType : zeroATCPatches_)
{
if (patch.type() == patchType)
{
const labelList& faceCells_ = patch.faceCells();
zeroATCcells_.append(faceCells_);
cellIDs.push_back(patch.faceCells());
}
}
}
for (const label zoneID: zeroATCZones_)
for (const label zoneID : zeroATCZones_)
{
if (zoneID !=-1)
if (zoneID != -1)
{
const labelList& zoneCells = mesh_.cellZones()[zoneID];
zeroATCcells_.append(zoneCells);
cellIDs.push_back(mesh_.cellZones()[zoneID]);
}
}
zeroATCZones_.transfer(cellIDs);
Info<< "Setting limiter on "
<< returnReduce(zeroATCcells_.size(), sumOp<label>())

View File

@ -27,6 +27,7 @@ solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C
solvers/adjointSolvers/adjointSolver/adjointSolver.C
solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C
solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C
solvers/adjointSolvers/null/adjointNull.C
/* ADJOINT SOLVER MANAGER */
solvers/adjointSolverManager/adjointSolverManager.C
@ -49,16 +50,16 @@ objectives/incompressible/objectiveForce/objectiveForce.C
objectives/incompressible/objectiveMoment/objectiveMoment.C
objectives/incompressible/objectivePtLosses/objectivePtLosses.C
objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.C
objectives/incompressible/objectivePartialVolume/objectivePartialVolume.C
objectives/incompressible/objectiveNutSqr/objectiveNutSqr.C
objectives/incompressible/objectiveFlowRate/objectiveFlowRate.C
objectives/incompressible/objectiveFlowRatePartition/objectiveFlowRatePartition.C
objectives/incompressible/objectiveUniformityPatch/objectiveUniformityPatch.C
objectives/incompressible/objectiveUniformityCellZone/objectiveUniformityCellZone.C
objectives/geometric/objectiveGeometric/objectiveGeometric.C
objectives/geometric/objectivePartialVolume/objectivePartialVolume.C
/* OBJECTIVE MANAGER*/
objectiveManager/objectiveManager/objectiveManager.C
objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C
objectiveManager/objectiveManager.C
/* BOUNDARY ADJOINT CONTRIBUTIONS */
boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C
@ -120,6 +121,7 @@ parameterization/Bezier/Bezier.C
dynamicMesh/motionSolver/volumetricBSplinesMotionSolver/volumetricBSplinesMotionSolver.C
dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.C
dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.C
dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolver.C
/* DISPLACEMENT METHOD */
displacementMethod/displacementMethod/displacementMethod.C
@ -128,28 +130,24 @@ displacementMethod/displacementMethoddisplacementLaplacian/displacementMethoddis
displacementMethod/displacementMethodvelocityLaplacian/displacementMethodvelocityLaplacian.C
displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.C
displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.C
displacementMethod/displacementMethodpLaplacianMotionSolver/displacementMethodpLaplacianMotionSolver.C
/* INTERPOLATION SCHEMES */
interpolation/pointVolInterpolation/pointVolInterpolation.C
interpolation/volPointInterpolation/volPointInterpolationAdjoint.C
/* ADJOINT SENSITIVITY */
optimisation/adjointSensitivity/sensitivity/sensitivity.C
optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBase.C
incoSens=optimisation/adjointSensitivity/incompressible
$(incoSens)/adjointSensitivity/adjointSensitivityIncompressible.C
$(incoSens)/shapeSensitivities/shapeSensitivitiesIncompressible.C
$(incoSens)/adjointEikonalSolver/adjointEikonalSolverIncompressible.C
$(incoSens)/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C
$(incoSens)/sensitivitySurface/sensitivitySurfaceIncompressible.C
$(incoSens)/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C
$(incoSens)/sensitivityMultiple/sensitivityMultipleIncompressible.C
$(incoSens)/SIBase/SIBaseIncompressible.C
$(incoSens)/FIBase/FIBaseIncompressible.C
$(incoSens)/sensitivityVolBSplines/sensitivityVolBSplinesIncompressible.C
$(incoSens)/sensitivityVolBSplinesFI/sensitivityVolBSplinesFIIncompressible.C
$(incoSens)/sensitivityBezier/sensitivityBezierIncompressible.C
$(incoSens)/sensitivityBezierFI/sensitivityBezierFIIncompressible.C
optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivity.C
optimisation/adjointSensitivity/adjointSensitivity/adjointEikonalSolver/adjointEikonalSolver.C
optimisation/adjointSensitivity/adjointSensitivity/shape/adjointMeshMovementSolver/adjointMeshMovementSolver.C
optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBase.C
optimisation/adjointSensitivity/adjointSensitivity/shape/FI/sensitivityShapeFI.C
optimisation/adjointSensitivity/adjointSensitivity/shape/ESI/sensitivityShapeESI.C
optimisation/adjointSensitivity/adjointSensitivity/shape/surfacePoints/sensitivitySurfacePoints.C
optimisation/adjointSensitivity/adjointSensitivity/shape/surface/sensitivitySurface.C
optimisation/adjointSensitivity/adjointSensitivity/topO/sensitivityTopO.C
optimisation/adjointSensitivity/adjointSensitivity/multiple/sensitivityMultiple.C
/* LINE SEARCH */
optimisation/lineSearch/lineSearch/lineSearch.C
@ -159,32 +157,32 @@ optimisation/lineSearch/stepUpdate/bisection/bisection.C
optimisation/lineSearch/stepUpdate/quadratic/quadratic.C
/* UPDATE METHOD */
updateMethod=optimisation/updateMethod/
updateMethod=optimisation/updateMethod
$(updateMethod)/updateMethod/updateMethod.C
$(updateMethod)/constrainedOptimisationMethod/constrainedOptimisationMethod.C
$(updateMethod)/steepestDescent/steepestDescent.C
$(updateMethod)/quasiNewton/quasiNewton.C
$(updateMethod)/BFGS/BFGS.C
$(updateMethod)/DBFGS/DBFGS.C
$(updateMethod)/LBFGS/LBFGS.C
$(updateMethod)/SR1/SR1.C
$(updateMethod)/conjugateGradient/conjugateGradient.C
$(updateMethod)/constraintProjection/constraintProjection.C
$(updateMethod)/SQPBase/SQPBase.C
$(updateMethod)/SQP/SQP.C
$(updateMethod)/ISQP/ISQP.C
/* OPT MESH MOVEMENT */
optMeshMovement=optimisation/optMeshMovement
$(optMeshMovement)/optMeshMovement/optMeshMovement.C
$(optMeshMovement)/optMeshMovementVolumetricBSplines/optMeshMovementVolumetricBSplines.C
$(optMeshMovement)/optMeshMovementVolumetricBSplinesExternalMotionSolver/optMeshMovementVolumetricBSplinesExternalMotionSolver.C
$(optMeshMovement)/optMeshMovementBezier/optMeshMovementBezier.C
$(optMeshMovement)/optMeshMovementNULL/optMeshMovementNULL.C
/* OPTIMIZATION TYPE */
incoOptType=optimisation/optimisationType/incompressible
$(incoOptType)/optimisationType/optimisationTypeIncompressible.C
$(incoOptType)/shapeOptimisation/shapeOptimisationIncompressible.C
/* DESIGN VARIABLES */
optimisation/designVariables/designVariables/designVariables.C
shapeVars=optimisation/designVariables/shape
$(shapeVars)/shapeDesignVariables/shapeDesignVariables.C
$(shapeVars)/volumetricBSplines/morphingBoxConstraints/morphingBoxConstaint/morphingBoxConstraint.C
$(shapeVars)/volumetricBSplines/morphingBoxConstraints/none/noConstraint.C
$(shapeVars)/volumetricBSplines/volumetricBSplinesDesignVariables.C
$(shapeVars)/Bezier/BezierDesignVariables.C
/* OPTIMIZATION MANAGER */
optimisation/optimisationManager/optimisationManager/designVariablesUpdate/designVariablesUpdate.C
optimisation/optimisationManager/optimisationManager/optimisationManager.C
optimisation/optimisationManager/singleRun/singleRun.C
optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.C

View File

@ -9,8 +9,10 @@ EXE_INC = \
-I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
-I$(LIB_SRC)/transportModels \
-I$(LIB_SRC)/transportModels/incompressible/singlePhaseTransportModel \
-I$(LIB_SRC)/transportModels/geometricVoF/lnInclude \
-I$(LIB_SRC)/fvMotionSolver/lnInclude \
-I$(LIB_SRC)/dynamicMesh/lnInclude \
-I$(LIB_SRC)/fileFormats/lnInclude \
-I$(LIB_SRC)/fvOptions/lnInclude
LIB_LIBS = \
@ -24,4 +26,5 @@ LIB_LIBS = \
-lincompressibleTransportModels \
-lfvMotionSolvers \
-ldynamicMesh \
-lgeometricVoF \
-lfvOptions

View File

@ -314,12 +314,7 @@ tmp
>
adjointBoundaryCondition<Type>::dxdbMult() const
{
return
tmp<Field<typename Foam::outerProduct<Foam::vector, Type>::type>>::New
(
patch_.size(),
Zero
);
return nullptr;
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -114,9 +114,10 @@ void Foam::adjointWallVelocityFvPatchVectorField::manipulateMatrix
typedef Foam::nutUSpaldingWallFunctionFvPatchScalarField
SAwallFunctionPatchField;
tmp<fvPatchScalarField> nutPatch(boundaryContrPtr_->turbulentDiffusivity());
if
(
isA<SAwallFunctionPatchField>(boundaryContrPtr_->turbulentDiffusivity())
isA<SAwallFunctionPatchField>(nutPatch())
&& patch().size() != 0
)
{
@ -199,8 +200,8 @@ void Foam::adjointWallVelocityFvPatchVectorField::updateCoeffs()
typedef Foam::nutUSpaldingWallFunctionFvPatchScalarField
SAwallFunctionPatchField;
const fvPatchScalarField& nutb = boundaryContrPtr_->turbulentDiffusivity();
if (isA<SAwallFunctionPatchField>(nutb))
tmp<fvPatchScalarField> nutb(boundaryContrPtr_->turbulentDiffusivity());
if (isA<SAwallFunctionPatchField>(nutb()))
{
Uap_t1 = (Uac & tf1)*tf1;
// leaving out second term for now

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -28,6 +28,7 @@ License
\*---------------------------------------------------------------------------*/
#include "boundaryAdjointContribution.H"
#include "fvPatchFieldsFwd.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -139,6 +140,13 @@ tmp<scalarField> boundaryAdjointContribution::TMVariable2()
}
tmp<fvPatchScalarField>
boundaryAdjointContribution::turbulentDiffusivity() const
{
NotImplemented;
return tmp<fvPatchScalarField>(nullptr);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -79,6 +79,18 @@ protected:
const fvPatch& patch_;
// Protected Member Functions
template<class returnType, class sourceType, class castType>
tmp<Field<returnType>> sumContributions
(
PtrList<sourceType>& sourceList,
const fvPatchField<returnType>&(castType::*boundaryFunction)
(const label),
bool (castType::*hasFunction)() const
);
public:
//- Runtime type information
@ -156,7 +168,7 @@ public:
virtual const fvPatchVectorField& Ub() const = 0;
virtual const fvPatchScalarField& pb() const = 0;
virtual const fvsPatchScalarField& phib() const = 0;
virtual const fvPatchScalarField& turbulentDiffusivity() const = 0;
virtual tmp<fvPatchScalarField> turbulentDiffusivity() const;
virtual const fvPatchVectorField& Uab() const = 0;
virtual const fvPatchScalarField& pab() const = 0;
virtual const fvsPatchScalarField& phiab() const = 0;
@ -173,6 +185,12 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "boundaryAdjointContributionTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -31,10 +31,11 @@ License
template<class returnType, class sourceType, class castType>
Foam::tmp<Foam::Field<returnType>>
Foam::boundaryAdjointContributionIncompressible::sumContributions
Foam::boundaryAdjointContribution::sumContributions
(
PtrList<sourceType>& sourceList,
const fvPatchField<returnType>&(castType::*boundaryFunction)(const label)
const fvPatchField<returnType>& (castType::*boundaryFunction)(const label),
bool (castType::*hasFunction)() const
)
{
// Objective function contribution
@ -45,10 +46,13 @@ Foam::boundaryAdjointContributionIncompressible::sumContributions
for (sourceType& funcI : sourceList)
{
castType& cfuncI = refCast<castType>(funcI);
if ((cfuncI.*hasFunction)())
{
const fvPatchField<returnType>& dJdvar =
(cfuncI.*boundaryFunction)(patch_.index());
dJtotdvar += cfuncI.weight()*dJdvar;
}
}
return tdJtotdvar;
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -93,7 +93,8 @@ tmp<vectorField> boundaryAdjointContributionIncompressible::velocitySource()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdv
&objectiveIncompressible::boundarydJdv,
&objectiveIncompressible::hasBoundarydJdv
);
vectorField& source = tsource.ref();
@ -113,7 +114,8 @@ tmp<scalarField> boundaryAdjointContributionIncompressible::pressureSource()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdvn
&objectiveIncompressible::boundarydJdvn,
&objectiveIncompressible::hasBoundarydJdvn
);
scalarField& source = tsource.ref();
@ -138,7 +140,8 @@ boundaryAdjointContributionIncompressible::tangentVelocitySource()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdvt
&objectiveIncompressible::boundarydJdvt,
&objectiveIncompressible::hasBoundarydJdvt
);
vectorField& source = tsource.ref();
@ -165,7 +168,8 @@ boundaryAdjointContributionIncompressible::normalVelocitySource()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdp
&objectiveIncompressible::boundarydJdp,
&objectiveIncompressible::hasBoundarydJdp
);
}
@ -177,7 +181,8 @@ tmp<scalarField> boundaryAdjointContributionIncompressible::energySource()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdT
&objectiveIncompressible::boundarydJdT,
&objectiveIncompressible::hasBoundarydJdT
);
}
@ -190,7 +195,8 @@ boundaryAdjointContributionIncompressible::adjointTMVariable1Source()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdTMvar1
&objectiveIncompressible::boundarydJdTMvar1,
&objectiveIncompressible::hasBoundarydJdTMVar1
);
}
@ -203,7 +209,8 @@ boundaryAdjointContributionIncompressible::adjointTMVariable2Source()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdTMvar2
&objectiveIncompressible::boundarydJdTMvar2,
&objectiveIncompressible::hasBoundarydJdTMVar2
);
}
@ -216,7 +223,8 @@ boundaryAdjointContributionIncompressible::dJdnut()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdnut
&objectiveIncompressible::boundarydJdnut,
&objectiveIncompressible::hasBoundarydJdnut
);
}
@ -228,7 +236,8 @@ boundaryAdjointContributionIncompressible::dJdGradU()
sumContributions
(
objectiveManager_.getObjectiveFunctions(),
&objectiveIncompressible::boundarydJdGradU
&objectiveIncompressible::boundarydJdGradU,
&objectiveIncompressible::hasBoundarydJdGradU
);
}
@ -331,14 +340,10 @@ boundaryAdjointContributionIncompressible::phib() const
}
const fvPatchScalarField&
tmp<fvPatchScalarField>
boundaryAdjointContributionIncompressible::turbulentDiffusivity() const
{
return
primalVars_.RASModelVariables()().nutRef().boundaryField()
[
patch_.index()
];
return primalVars_.RASModelVariables()().nutPatchField(patch_.index());
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -96,17 +96,6 @@ protected:
const incompressibleAdjointSolver& adjointSolver_;
// Protected Member Functions
template<class returnType, class sourceType, class castType>
tmp<Field<returnType>> sumContributions
(
PtrList<sourceType>& sourceList,
const fvPatchField<returnType>&(castType::*boundaryFunction)
(const label)
);
public:
//- Runtime type information
@ -155,7 +144,7 @@ public:
const fvPatchVectorField& Ub() const;
const fvPatchScalarField& pb() const;
const fvsPatchScalarField& phib() const;
const fvPatchScalarField& turbulentDiffusivity() const;
tmp<fvPatchScalarField> turbulentDiffusivity() const;
const fvPatchVectorField& Uab() const;
const fvPatchScalarField& pab() const;
const fvsPatchScalarField& phiab() const;
@ -175,12 +164,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
# include "boundaryAdjointContributionIncompressibleTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -97,6 +97,12 @@ Foam::autoPtr<Foam::displacementMethod> Foam::displacementMethod::New
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
bool Foam::displacementMethod::preferPointField() const
{
return true;
}
void Foam::displacementMethod::boundControlField(vectorField& controlField)
{
// Does nothing in base

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -66,12 +66,15 @@ protected:
fvMesh& mesh_;
//- IDs of the patches to be moved
const labelList& patchIDs_;
labelList patchIDs_;
autoPtr<motionSolver> motionPtr_;
scalar maxDisplacement_;
//- Whether the motion solver prefers a point of a vol field as input
bool preferPointField_;
private:
@ -130,6 +133,9 @@ public:
// Member Functions
//- Whether the motion solver prefers a point of a vol field as input
virtual bool preferPointField() const;
//- Set motion filed related to model based on given motion
virtual void setMotionField(const pointVectorField& pointMovement) = 0;
@ -155,6 +161,12 @@ public:
//- Get max displacement
scalar getMaxDisplacement() const;
//- Set parametertised patch IDs
inline void setPatchIDs(const labelList& patchIDs)
{
patchIDs_ = patchIDs;
}
//- Update mesh
void update();
};

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -98,6 +98,12 @@ displacementMethodelasticityMotionSolver
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool displacementMethodelasticityMotionSolver::preferPointField() const
{
return false;
}
void displacementMethodelasticityMotionSolver::setMotionField
(
const pointVectorField& pointMovement
@ -105,17 +111,17 @@ void displacementMethodelasticityMotionSolver::setMotionField
{
if (resetFields_)
{
pointMotionU_.primitiveFieldRef() = vector::zero;
cellMotionU_.primitiveFieldRef() = vector::zero;
pointMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.correctBoundaryConditions();
}
maxDisplacement_ = SMALL;
// Update the boundary conditions of the pointField in order to make
// sure that the boundary will move according to the initial BCs
// without the interference of the volPointInterpolation in the elasticityMotionSolver
for (label patchI : patchIDs_)
// Update the boundary conditions of the pointField in order to make sure
// that the boundary will move according to the initial BCs without the
// interference of the volPointInterpolation in the elasticityMotionSolver
for (const label patchI : patchIDs_)
{
// Set boundary field. Needed for the motionSolver class
pointMotionU_.boundaryFieldRef()[patchI] ==
@ -145,7 +151,8 @@ void displacementMethodelasticityMotionSolver::setMotionField
);
}
// update the volField boundary conditions, used for the elasticity PDEs solution
// Update the volField boundary conditions,
// used for the elasticity PDEs solution
const pointField& points = mesh_.points();
for (label patchI : patchIDs_)
{
@ -164,15 +171,12 @@ void displacementMethodelasticityMotionSolver::setMotionField
const volVectorField& cellMovement
)
{
auto cellMotionUbf = cellMotionU_.boundaryFieldRef();
auto& cellMotionUbf = cellMotionU_.boundaryFieldRef();
// Set boundary mesh movement and calculate
// max current boundary displacement
forAll(patchIDs_, pI)
for (const label patchI : patchIDs_)
{
label patchI = patchIDs_[pI];
// Set boundary field. Needed for the motionSolver class
cellMotionUbf[patchI] == cellMovement.boundaryField()[patchI];
// Find max value
@ -180,10 +184,7 @@ void displacementMethodelasticityMotionSolver::setMotionField
max
(
maxDisplacement_,
gMax
(
mag(cellMotionUbf[patchI])
)
gMax(mag(cellMotionUbf[patchI]))
);
}
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -105,6 +105,9 @@ public:
// Member Functions
//- Whether the motion solver prefers a point of a vol field as input
virtual bool preferPointField() const;
//- Set motion filed related to model based on given motion
void setMotionField(const pointVectorField& pointMovement);

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -57,24 +57,6 @@ displacementMethodlaplacianMotionSolver::displacementMethodlaplacianMotionSolver
displacementMethod(mesh, patchIDs),
pointMotionU_(refCast<laplacianMotionSolver>(motionPtr_()).pointMotionU()),
cellMotionU_(refCast<laplacianMotionSolver>(motionPtr_()).cellMotionU()),
/*
// getting a reference from the database is dangerous since multiple
// fields with the same name might be registered
pointMotionU_
(
const_cast<pointVectorField&>
(
mesh_.lookupObject<pointVectorField>("pointMotionU")
)
),
cellMotionU_
(
const_cast<volVectorField&>
(
mesh_.lookupObject<volVectorField>("cellMotionU")
)
),
*/
resetFields_
(
IOdictionary::readContents
@ -97,6 +79,12 @@ displacementMethodlaplacianMotionSolver::displacementMethodlaplacianMotionSolver
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool displacementMethodlaplacianMotionSolver::preferPointField() const
{
return false;
}
void displacementMethodlaplacianMotionSolver::setMotionField
(
const pointVectorField& pointMovement
@ -104,14 +92,16 @@ void displacementMethodlaplacianMotionSolver::setMotionField
{
if (resetFields_)
{
pointMotionU_.primitiveFieldRef() = vector::zero;
cellMotionU_.primitiveFieldRef() = vector::zero;
pointMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.correctBoundaryConditions();
}
maxDisplacement_ = SMALL;
// Set boundary mesh movement and calculate
// max current boundary displacement
for (label patchI : patchIDs_)
for (const label patchI : patchIDs_)
{
// Set boundary field. Needed for the motionSolver class
pointMotionU_.boundaryFieldRef()[patchI] ==
@ -140,6 +130,8 @@ void displacementMethodlaplacianMotionSolver::setMotionField
)
);
}
// Transfer movement to cellMotionU
refCast<laplacianMotionSolver>(motionPtr_()).setBoundaryConditions();
}
@ -148,28 +140,28 @@ void displacementMethodlaplacianMotionSolver::setMotionField
const volVectorField& cellMovement
)
{
NotImplemented;
/*
if (resetFields_)
{
pointMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.correctBoundaryConditions();
}
auto& cellMotionUbf = cellMotionU_.boundaryFieldRef();
// Set boundary mesh movement and calculate max current boundary
// displacement
forAll(patchIDs_, pI)
for (const label patchI : patchIDs_)
{
label patchI = patchIDs_[pI];
cellMotionU_.boundaryField()[patchI] ==
cellMovement.boundaryField()[patchI];
cellMotionUbf[patchI] == cellMovement.boundaryField()[patchI];
// Find max value
maxDisplacement_ =
max
(
maxDisplacement_,
gMax
(
mag(cellMovement.boundaryField()[patchI])
)
gMax(mag(cellMotionUbf[patchI]))
);
}
*/
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -102,6 +102,9 @@ public:
// Member Functions
//- Whether the motion solver prefers a point of a vol field as input
virtual bool preferPointField() const;
//- Set motion filed related to model based on given motion
void setMotionField(const pointVectorField& pointMovement);

View File

@ -0,0 +1,191 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021 PCOpt/NTUA
Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "displacementMethodpLaplacianMotionSolver.H"
#include "pLaplacianMotionSolver.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(displacementMethodpLaplacianMotionSolver, 1);
addToRunTimeSelectionTable
(
displacementMethod,
displacementMethodpLaplacianMotionSolver,
dictionary
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
displacementMethodpLaplacianMotionSolver::
displacementMethodpLaplacianMotionSolver
(
fvMesh& mesh,
const labelList& patchIDs
)
:
displacementMethod(mesh, patchIDs),
pointMotionU_(refCast<pLaplacianMotionSolver>(motionPtr_()).pointMotionU()),
cellMotionU_(refCast<pLaplacianMotionSolver>(motionPtr_()).cellMotionU()),
resetFields_
(
IOdictionary
(
IOobject
(
"dynamicMeshDict",
mesh.time().constant(),
mesh,
IOobject::MUST_READ_IF_MODIFIED,
IOobject::AUTO_WRITE,
false
)
).subDict("pLaplacianMotionSolverCoeffs").getOrDefault<bool>
(
"resetFields",
true
)
)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool displacementMethodpLaplacianMotionSolver::preferPointField() const
{
return false;
}
void displacementMethodpLaplacianMotionSolver::setMotionField
(
const pointVectorField& pointMovement
)
{
if (resetFields_)
{
pointMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.correctBoundaryConditions();
}
maxDisplacement_ = SMALL;
// Set boundary mesh movement and calculate
// max current boundary displacement
for (label patchI : patchIDs_)
{
// Set boundary field. Needed for the motionSolver class
pointMotionU_.boundaryFieldRef()[patchI] ==
pointMovement.boundaryField()[patchI].patchInternalField()();
// Set boundary field values as seen from the internalField!
// Needed for determining the max displacement
pointMotionU_.boundaryFieldRef()[patchI].setInInternalField
(
pointMotionU_.primitiveFieldRef(),
pointMovement.boundaryField()[patchI].patchInternalField()()
);
// Find max value
maxDisplacement_ =
max
(
maxDisplacement_,
gMax
(
mag
(
pointMotionU_.boundaryField()[patchI].
patchInternalField()
)
)
);
}
// Transfer movement to cellMotionU
refCast<pLaplacianMotionSolver>(motionPtr_()).setBoundaryConditions();
}
void displacementMethodpLaplacianMotionSolver::setMotionField
(
const volVectorField& cellMovement
)
{
if (resetFields_)
{
pointMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.primitiveFieldRef() = Zero;
cellMotionU_.correctBoundaryConditions();
}
auto& cellMotionUbf = cellMotionU_.boundaryFieldRef();
// Set boundary mesh movement and calculate max current boundary
// displacement
for (const label patchI : patchIDs_)
{
cellMotionUbf[patchI] == cellMovement.boundaryField()[patchI];
// Find max value
maxDisplacement_ =
max
(
maxDisplacement_,
gMax(mag(cellMotionUbf[patchI]))
);
}
}
void displacementMethodpLaplacianMotionSolver::setControlField
(
const vectorField& controlField
)
{
NotImplemented;
}
void displacementMethodpLaplacianMotionSolver::setControlField
(
const scalarField& controlField
)
{
NotImplemented;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -5,9 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2021 PCOpt/NTUA
Copyright (C) 2021 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,23 +24,22 @@ License
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::optMeshMovementVolumetricBSplines
Foam::displacementMethodpLaplacianMotionSolver
Description
Converts NURBS volume control points update to actual mesh movement.
Internal points are also moved based on the movement of the control points
Wrapper class for the pLaplacian motion solver
SourceFiles
optMeshMovementVolumetricBSplines.C
displacementMethodpLaplacianMotionSolver.C
\*---------------------------------------------------------------------------*/
#ifndef optMeshMovementVolumetricBSplines_H
#define optMeshMovementVolumetricBSplines_H
#ifndef displacementMethodpLaplacianMotionSolver_H
#define displacementMethodpLaplacianMotionSolver_H
#include "optMeshMovement.H"
#include "volBSplinesBase.H"
#include "displacementMethod.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -49,27 +47,22 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class optMeshMovementVolumetricBSplines Declaration
Class displacementMethodpLaplacianMotionSolver Declaration
\*---------------------------------------------------------------------------*/
class optMeshMovementVolumetricBSplines
class displacementMethodpLaplacianMotionSolver
:
public optMeshMovement
public displacementMethod
{
protected:
// Protected data
//- Reference to underlaying volumetric B-Splines morpher
volBSplinesBase& volBSplinesBase_;
pointVectorField& pointMotionU_;
//- Backup of initial control points. Useful for line-search
List<vectorField> cpsInit_;
volVectorField& cellMotionU_;
// Protected Member Functions
vectorField controlPointMovement(const scalarField& correction);
bool resetFields_;
private:
@ -77,53 +70,56 @@ private:
// Private Member Functions
//- No copy construct
optMeshMovementVolumetricBSplines
displacementMethodpLaplacianMotionSolver
(
const optMeshMovementVolumetricBSplines&
const displacementMethodpLaplacianMotionSolver&
) = delete;
//- No copy assignment
void operator=(const optMeshMovementVolumetricBSplines&) = delete;
void operator=
(
const displacementMethodpLaplacianMotionSolver&
) = delete;
public:
//- Runtime type information
TypeName("volumetricBSplines");
TypeName("pLaplacianMotionSolver");
// Constructors
//- Construct from components
optMeshMovementVolumetricBSplines
displacementMethodpLaplacianMotionSolver
(
fvMesh& mesh,
const dictionary& dict,
const labelList& patchIDs
);
//- Destructor
virtual ~optMeshMovementVolumetricBSplines() = default;
virtual ~displacementMethodpLaplacianMotionSolver() = default;
// Member Functions
//- Calculates surface mesh movement
void moveMesh();
//- Whether the motion solver prefers a point of a vol field as input
virtual bool preferPointField() const;
//- Store design variables and mesh, to act as the starting point of
//- line search
virtual void storeDesignVariables();
//- Set motion filed related to model based on given motion
void setMotionField(const pointVectorField& pointMovement);
//- Reset to starting point of line search
virtual void resetDesignVariables();
//- Set motion filed related to model based on given motion
void setMotionField(const volVectorField& cellMovement);
//- Compute eta value based on max displacement
virtual scalar computeEta(const scalarField& correction);
//- Set control field as a vectorField. For methods working with
//- parameters (RBF etc)
void setControlField(const vectorField& controlField);
//- Return active design variables
virtual labelList getActiveDesignVariables() const;
//- Set control field as a vectorField. For methods working with
//- parameters (RBF etc)
void setControlField(const scalarField& controlField);
};

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -29,6 +29,7 @@ License
#include "elasticityMotionSolver.H"
#include "motionInterpolation.H"
#include "motionDiffusivity.H"
#include "wallDist.H"
#include "fixedValuePointPatchFields.H"
#include "fvMatrices.H"
@ -36,6 +37,7 @@ License
#include "fvmDiv.H"
#include "fvmDiv.H"
#include "fvmLaplacian.H"
#include "surfaceInterpolate.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -57,6 +59,19 @@ namespace Foam
void Foam::elasticityMotionSolver::setBoundaryConditions()
{
// Adjust boundary conditions based on the steps to be executed
forAll(cellMotionU_.boundaryField(), patchI)
{
fvPatchVectorField& bc =
cellMotionU_.boundaryFieldRef()[patchI];
if (isA<fixedValueFvPatchVectorField>(bc))
{
auto& fixedValueBCs =
refCast<fixedValueFvPatchVectorField>(bc);
fixedValueBCs == fixedValueBCs/scalar(nSteps_);
}
}
/*
// Adjust boundary conditions based on the steps to be executed
forAll(pointMotionU_.boundaryField(), patchI)
{
@ -88,6 +103,7 @@ void Foam::elasticityMotionSolver::setBoundaryConditions()
}
}
}
*/
}
@ -141,21 +157,10 @@ Foam::elasticityMotionSolver::elasticityMotionSolver
? motionInterpolation::New(fvMesh_, coeffDict().lookup("interpolation"))
: motionInterpolation::New(fvMesh_)
),
E_
diffusivityPtr_
(
IOobject
(
"mu",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
motionDiffusivity::New(fvMesh_, coeffDict().lookup("diffusivity"))
),
fvMesh_,
dimensionedScalar(dimless, Zero),
fvPatchFieldBase::zeroGradientType()
),
exponent_(this->coeffDict().get<scalar>("exponent")),
nSteps_(this->coeffDict().get<label>("steps")),
nIters_(this->coeffDict().get<label>("iters")),
tolerance_(this->coeffDict().get<scalar>("tolerance"))
@ -175,7 +180,7 @@ Foam::tmp<Foam::pointField> Foam::elasticityMotionSolver::curPoints() const
void Foam::elasticityMotionSolver::solve()
{
// Re-init to zero
cellMotionU_.primitiveFieldRef() = vector::zero;
cellMotionU_.primitiveFieldRef() = Zero;
// Adjust boundary conditions based on the number of steps to be executed
// and interpolate to faces
@ -187,19 +192,18 @@ void Foam::elasticityMotionSolver::solve()
Info<< "Step " << istep << endl;
// Update diffusivity
const scalarField& vols = mesh().cellVolumes();
E_.primitiveFieldRef() = 1./pow(vols, exponent_);
E_.correctBoundaryConditions();
diffusivityPtr_->correct();
const surfaceScalarField E(diffusivityPtr_->operator()());
const surfaceVectorField& Sf = fvMesh_.Sf();
for (label iter = 0; iter < nIters_; ++iter)
{
Info<< "Iteration " << iter << endl;
cellMotionU_.storePrevIter();
fvVectorMatrix dEqn
(
fvm::laplacian(2*E_, cellMotionU_)
+ fvc::div(2*E_*T(fvc::grad(cellMotionU_)))
- fvc::div(E_*fvc::div(cellMotionU_)*tensor::I)
fvm::laplacian(2*E, cellMotionU_)
+ fvc::div(2*E*(fvc::interpolate(fvc::grad(cellMotionU_)) & Sf))
- fvc::div(E*fvc::interpolate(fvc::div(cellMotionU_))*Sf)
);
scalar residual = mag(dEqn.solve().initialResidual());
@ -218,12 +222,34 @@ void Foam::elasticityMotionSolver::solve()
}
}
interpolationPtr_->interpolate
(
cellMotionU_,
pointMotionU_
);
tmp<vectorField> newPoints
(
fvMesh_.points() + pointMotionU_.primitiveField()
);
/*
// Interpolate from cells to points
interpolationPtr_->interpolate(cellMotionU_, pointMotionU_);
syncTools::syncPointList
(
fvMesh_,
pointMotionU_.primitiveFieldRef(),
maxEqOp<vector>(),
vector::zero
);
vectorField newPoints
(
mesh().points() + pointMotionU_.primitiveFieldRef()
);
*/
// Move points and check mesh
fvMesh_.movePoints(newPoints);
@ -259,7 +285,14 @@ void Foam::elasticityMotionSolver::movePoints(const pointField&)
void Foam::elasticityMotionSolver::updateMesh(const mapPolyMesh&)
{
// Do nothing
// Update diffusivity. Note two stage to make sure old one is de-registered
// before creating/registering new one.
diffusivityPtr_.reset(nullptr);
diffusivityPtr_ = motionDiffusivity::New
(
fvMesh_,
coeffDict().lookup("diffusivity")
);
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -60,6 +60,7 @@ namespace Foam
// Forward class declarations
class motionInterpolation;
class motionDiffusivity;
class mapPolyMesh;
/*---------------------------------------------------------------------------*\
@ -84,11 +85,8 @@ protected:
//- Interpolation used to transfer cell displacement to the points
autoPtr<motionInterpolation> interpolationPtr_;
//- Inverse cell volume diffusivity
volScalarField E_;
//- Exponent to stiffen highly morphed cells
scalar exponent_;
//- Diffusivity used to control the motion
autoPtr<motionDiffusivity> diffusivityPtr_;
//- Intermediate steps to solve the PDEs
label nSteps_;

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -29,8 +29,10 @@ License
#include "laplacianMotionSolver.H"
#include "motionInterpolation.H"
#include "addToRunTimeSelectionTable.H"
#include "motionDiffusivity.H"
#include "fvmLaplacian.H"
#include "syncTools.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -47,29 +49,6 @@ namespace Foam
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::laplacianMotionSolver::setBoundaryConditions()
{
pointMotionU_.boundaryFieldRef().updateCoeffs();
auto& cellMotionUbf = cellMotionU_.boundaryFieldRef();
forAll(cellMotionU_.boundaryField(), pI)
{
fvPatchVectorField& bField = cellMotionUbf[pI];
if (isA<fixedValueFvPatchVectorField>(bField))
{
const pointField& points = fvMesh_.points();
const polyPatch& patch = fvMesh_.boundaryMesh()[pI];
forAll(bField, fI)
{
bField[fI] = patch[fI].average(points, pointMotionU_);
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::laplacianMotionSolver::laplacianMotionSolver
@ -114,6 +93,10 @@ Foam::laplacianMotionSolver::laplacianMotionSolver
? motionInterpolation::New(fvMesh_, coeffDict().lookup("interpolation"))
: motionInterpolation::New(fvMesh_)
),
diffusivityPtr_
(
motionDiffusivity::New(fvMesh_, coeffDict().lookup("diffusivity"))
),
nIters_(this->coeffDict().get<label>("iters")),
tolerance_(this->coeffDict().get<scalar>("tolerance"))
{}
@ -129,9 +112,17 @@ Foam::tmp<Foam::pointField> Foam::laplacianMotionSolver::curPoints() const
pointMotionU_
);
syncTools::syncPointList
(
fvMesh_,
pointMotionU_.primitiveFieldRef(),
maxEqOp<vector>(),
vector::zero
);
tmp<vectorField> tcurPoints
(
fvMesh_.points() + pointMotionU_.internalField()
fvMesh_.points() + pointMotionU_.primitiveField()
);
twoDCorrectPoints(tcurPoints.ref());
@ -142,7 +133,7 @@ Foam::tmp<Foam::pointField> Foam::laplacianMotionSolver::curPoints() const
void Foam::laplacianMotionSolver::solve()
{
setBoundaryConditions();
diffusivityPtr_->correct();
// Iteratively solve the Laplace equation, to account for non-orthogonality
for (label iter = 0; iter < nIters_; ++iter)
@ -150,7 +141,13 @@ void Foam::laplacianMotionSolver::solve()
Info<< "Iteration " << iter << endl;
fvVectorMatrix dEqn
(
fvm::laplacian(cellMotionU_)
fvm::laplacian
(
dimensionedScalar("viscosity", dimViscosity, 1.0)
* diffusivityPtr_->operator()(),
cellMotionU_,
"laplacian(diffusivity,cellMotionU)"
)
);
scalar residual = mag(dEqn.solve().initialResidual());
@ -169,6 +166,27 @@ void Foam::laplacianMotionSolver::solve()
}
void Foam::laplacianMotionSolver::setBoundaryConditions()
{
pointMotionU_.boundaryFieldRef().updateCoeffs();
auto& cellMotionUbf = cellMotionU_.boundaryFieldRef();
forAll(cellMotionU_.boundaryField(), pI)
{
fvPatchVectorField& bField = cellMotionUbf[pI];
if (isA<fixedValueFvPatchVectorField>(bField))
{
const pointField& points = fvMesh_.points();
const polyPatch& patch = fvMesh_.boundaryMesh()[pI];
forAll(bField, fI)
{
bField[fI] = patch[fI].average(points, pointMotionU_);
}
}
}
}
void Foam::laplacianMotionSolver::movePoints(const pointField&)
{
// Do nothing
@ -177,7 +195,14 @@ void Foam::laplacianMotionSolver::movePoints(const pointField&)
void Foam::laplacianMotionSolver::updateMesh(const mapPolyMesh&)
{
// Do nothing
// Update diffusivity. Note two stage to make sure old one is de-registered
// before creating/registering new one.
diffusivityPtr_.reset(nullptr);
diffusivityPtr_ = motionDiffusivity::New
(
fvMesh_,
coeffDict().lookup("diffusivity")
);
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -59,6 +59,7 @@ namespace Foam
// Forward class declarations
class motionInterpolation;
class motionDiffusivity;
class mapPolyMesh;
/*---------------------------------------------------------------------------*\
@ -80,6 +81,9 @@ protected:
//- Interpolation used to transfer cell displacement to the points
autoPtr<motionInterpolation> interpolationPtr_;
//- Diffusivity used to control the motion
autoPtr<motionDiffusivity> diffusivityPtr_;
//- Number of laplacian iterations per solution step
label nIters_;
@ -87,16 +91,6 @@ protected:
scalar tolerance_;
// Protected Member Functions
//- Set boundary conditions of cellMotionU based on pointMotionU.
// Avoiding the use of the cellMotionFvPatchField bc
// due to the use of the registry in order to grab pointMotionU, which
// may give problems if multiple objects of this class are constructed
// at the same time
void setBoundaryConditions();
private:
@ -144,6 +138,13 @@ public:
//- Solve for motion
virtual void solve();
//- Set boundary conditions of cellMotionU based on pointMotionU.
// Avoiding the use of the cellMotionFvPatchField bc
// due to the use of the registry in order to grab pointMotionU, which
// may give problems if multiple objects of this class are constructed
// at the same time
void setBoundaryConditions();
//- Update local data for geometry changes
virtual void movePoints(const pointField&);

View File

@ -0,0 +1,219 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2023 PCOpt/NTUA
Copyright (C) 2021-2023 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "pLaplacianMotionSolver.H"
#include "motionInterpolation.H"
#include "addToRunTimeSelectionTable.H"
#include "syncTools.H"
#include "fvmLaplacian.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(pLaplacianMotionSolver, 1);
addToRunTimeSelectionTable
(
motionSolver,
pLaplacianMotionSolver,
dictionary
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::pLaplacianMotionSolver::pLaplacianMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict
)
:
motionSolver(mesh, dict, typeName),
fvMotionSolver(mesh),
useFixedValuePointMotionUBCs_
(coeffDict().getOrDefault<bool>("useFixedValuePointMotionUBCs", false)),
pointMotionU_
(
IOobject
(
"pointMotionU",
mesh.time().timeName(),
mesh,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
pointMesh::New(mesh),
dimensionedVector(dimless, Zero),
word
(
useFixedValuePointMotionUBCs_
? fixedValuePointPatchVectorField::typeName
: calculatedPointPatchField<vector>::typeName
)
),
cellMotionU_
(
IOobject
(
"cellMotionU",
mesh.time().timeName(),
mesh,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
fvMesh_,
dimensionedVector(pointMotionU_.dimensions(), Zero),
pointMotionU_.boundaryField().types()
),
interpolationPtr_
(
coeffDict().found("interpolation")
? motionInterpolation::New(fvMesh_, coeffDict().lookup("interpolation"))
: motionInterpolation::New(fvMesh_)
),
nIters_(this->coeffDict().get<label>("iters")),
tolerance_(this->coeffDict().get<scalar>("tolerance")),
toleranceIntermediate_
(
this->coeffDict().
getOrDefault<scalar>("toleranceIntermediate", 100*tolerance_)
),
exponent_(this->coeffDict().get<label>("exponent"))
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::pLaplacianMotionSolver::setBoundaryConditions()
{
pointMotionU_.boundaryFieldRef().updateCoeffs();
auto& cellMotionUbf = cellMotionU_.boundaryFieldRef();
forAll(cellMotionU_.boundaryField(), pI)
{
fvPatchVectorField& bField = cellMotionUbf[pI];
if (isA<fixedValueFvPatchVectorField>(bField))
{
const pointField& points = fvMesh_.points();
const polyPatch& patch = fvMesh_.boundaryMesh()[pI];
forAll(bField, fI)
{
bField[fI] = patch[fI].average(points, pointMotionU_);
}
}
}
}
Foam::tmp<Foam::pointField> Foam::pLaplacianMotionSolver::curPoints() const
{
interpolationPtr_->interpolate
(
cellMotionU_,
pointMotionU_
);
syncTools::syncPointList
(
fvMesh_,
pointMotionU_.primitiveFieldRef(),
maxEqOp<vector>(),
vector::zero
);
tmp<vectorField> tcurPoints
(
fvMesh_.points() + pointMotionU_.internalField()
);
twoDCorrectPoints(tcurPoints.ref());
return tcurPoints;
}
void Foam::pLaplacianMotionSolver::solve()
{
// setBoundaryConditions();
for (label exp = 2; exp < exponent_ + 1; ++exp)
{
scalar tolerance
(exp == exponent_ ? tolerance_ : toleranceIntermediate_);
Info<< "Solving for exponent " << exp << endl;
for (label iter = 0; iter < nIters_; ++iter)
{
Info<< "Iteration " << iter << endl;
cellMotionU_.storePrevIter();
volScalarField gamma(pow(mag(fvc::grad(cellMotionU_)), exp - 2));
gamma.correctBoundaryConditions();
fvVectorMatrix dEqn
(
fvm::laplacian(gamma, cellMotionU_)
);
scalar residual = mag(dEqn.solve().initialResidual());
cellMotionU_.relax();
// Print execution time
fvMesh_.time().printExecutionTime(Info);
// Check convergence
if (residual < tolerance)
{
Info<< "\n***Reached mesh movement convergence limit at"
<< " iteration " << iter << "***\n\n";
if (debug)
{
gamma.write();
}
break;
}
}
}
}
void Foam::pLaplacianMotionSolver::movePoints(const pointField&)
{
// Do nothing
}
void Foam::pLaplacianMotionSolver::updateMesh(const mapPolyMesh&)
{
// Do nothing
}
// ************************************************************************* //

View File

@ -0,0 +1,178 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2023 PCOpt/NTUA
Copyright (C) 2021-2023 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 <http://www.gnu.org/licenses/>.
Class
Foam::pLaplacianMotionSolver
Description
Similar to velocityLaplacian but with a variable diffusivity, based
on the gradient of the displacement.
The boundary displacement is set as a boundary condition
on pointMotionU; the latter is generated automatically if not found.
SourceFiles
pLaplacianMotionSolver.C
\*---------------------------------------------------------------------------*/
#ifndef pLaplacianMotionSolver_H
#define pLaplacianMotionSolver_H
#include "velocityMotionSolver.H"
#include "fvMotionSolver.H"
#include "volPointInterpolation.H"
#include "polyMesh.H"
#include "pointMesh.H"
#include "pointPatchField.H"
#include "pointPatchFieldsFwd.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward class declarations
class motionInterpolation;
class mapPolyMesh;
/*---------------------------------------------------------------------------*\
Class pLaplacianMotionSolver Declaration
\*---------------------------------------------------------------------------*/
class pLaplacianMotionSolver
:
public motionSolver,
public fvMotionSolver
{
protected:
// Protected data
// Use a fixedValue boundary condition for the moving patches? When
// using this motionSolver in an optimisation context, we usually go
// from point movement to face movement, solve the grid dispalcement
// PDE and then interpolate the movement back to the points. If the
// boundary conditions of pointMotionU are fixedValue, the initial
// values will be retained, otherwise they will be overwritten by the
// face-to-point interpolation. The latter is usually beneficial for
// the resulting mesh quality but does not give us the exact geometry.
bool useFixedValuePointMotionUBCs_;
mutable pointVectorField pointMotionU_;
volVectorField cellMotionU_;
//- Interpolation used to transfer cell displacement to the points
autoPtr<motionInterpolation> interpolationPtr_;
//- Number of pLaplacian iterations per solution step
label nIters_;
//- Residual threshold
scalar tolerance_;
//- Residual threshold for intermediate exponents
scalar toleranceIntermediate_;
//- Exponent defining the order or the p-Laplacian
label exponent_;
private:
// Private Member Functions
//- No copy construct
pLaplacianMotionSolver(const pLaplacianMotionSolver&) = delete;
//- No copy assignment
void operator=(const pLaplacianMotionSolver&) = delete;
public:
//- Runtime type information
TypeName("pLaplacianMotionSolver");
// Constructors
//- Construct from mesh and dictionary
pLaplacianMotionSolver
(
const polyMesh& mesh,
const IOdictionary& dict
);
//- Destructor
virtual ~pLaplacianMotionSolver() = default;
// Member Functions
//- Set boundary conditions of cellMotionU based on pointMotionU.
// Avoiding the use of the cellMotionFvPatchField bc
// due to the use of the registry in order to grab pointMotionU, which
// may give problems if multiple objects of this class are constructed
// at the same time
void setBoundaryConditions();
//- Get const and non-const references to pointMotionU
inline pointVectorField& pointMotionU();
inline const pointVectorField& pointMotionU() const;
//- Get const and non-const references to cellMotionU
inline volVectorField& cellMotionU();
inline const volVectorField& cellMotionU() const;
//- Return point location obtained from the current motion field
virtual tmp<pointField> curPoints() const;
//- Solve for motion
virtual void solve();
//- Update local data for geometry changes
virtual void movePoints(const pointField&);
//- Update the mesh corresponding to given map
virtual void updateMesh(const mapPolyMesh&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "pLaplacianMotionSolverI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,9 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2021-2023 PCOpt/NTUA
Copyright (C) 2021-2023 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,47 +26,34 @@ License
\*---------------------------------------------------------------------------*/
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline bool sensitivitySurface::getIncludeObjective() const
inline Foam::pointVectorField& Foam::pLaplacianMotionSolver::pointMotionU()
{
return includeObjective_;
return pointMotionU_;
}
inline bool sensitivitySurface::getIncludeSurfaceArea() const
inline const Foam::pointVectorField&
Foam::pLaplacianMotionSolver::pointMotionU() const
{
return includeSurfaceArea_;
return pointMotionU_;
}
inline void sensitivitySurface::setIncludeObjective
(
const bool includeObjective
)
inline Foam::volVectorField& Foam::pLaplacianMotionSolver::cellMotionU()
{
includeObjective_ = includeObjective;
return cellMotionU_;
}
inline void sensitivitySurface::setIncludeSurfaceArea
(
const bool includeSurfaceArea
)
inline const Foam::volVectorField&
Foam::pLaplacianMotionSolver::cellMotionU() const
{
includeSurfaceArea_ = includeSurfaceArea;
return cellMotionU_;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,345 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "volPointInterpolationAdjoint.H"
#include "volFields.H"
#include "pointFields.H"
#include "emptyFvPatch.H"
#include "coupledPointPatchField.H"
#include "pointConstraints.H"
#include "symmetryPolyPatch.H"
#include "symmetryPlanePolyPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
template<class Type>
void Foam::volPointInterpolationAdjoint::pushUntransformedData
(
List<Type>& pointData
) const
{
// Transfer onto coupled patch
const globalMeshData& gmd = mesh().globalData();
const indirectPrimitivePatch& cpp = gmd.coupledPatch();
const labelList& meshPoints = cpp.meshPoints();
const mapDistribute& slavesMap = gmd.globalCoPointSlavesMap();
const labelListList& slaves = gmd.globalCoPointSlaves();
List<Type> elems(slavesMap.constructSize());
forAll(meshPoints, i)
{
elems[i] = pointData[meshPoints[i]];
}
// Combine master data with slave data
forAll(slaves, i)
{
const labelList& slavePoints = slaves[i];
// Copy master data to slave slots
forAll(slavePoints, j)
{
elems[slavePoints[j]] = elems[i];
}
}
// Push slave-slot data back to slaves
slavesMap.reverseDistribute(elems.size(), elems, false);
// Extract back onto mesh
forAll(meshPoints, i)
{
pointData[meshPoints[i]] = elems[i];
}
}
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::volPointInterpolationAdjoint::flatBoundaryField
(
const GeometricField<Type, fvPatchField, volMesh>& vf
) const
{
const fvMesh& mesh = vf.mesh();
const fvBoundaryMesh& bm = mesh.boundary();
tmp<Field<Type>> tboundaryVals
(
new Field<Type>(mesh.nBoundaryFaces())
);
Field<Type>& boundaryVals = tboundaryVals.ref();
forAll(vf.boundaryField(), patchi)
{
label bFacei = bm[patchi].patch().start() - mesh.nInternalFaces();
if
(
!isA<emptyFvPatch>(bm[patchi])
&& !vf.boundaryField()[patchi].coupled()
)
{
SubList<Type>
(
boundaryVals,
vf.boundaryField()[patchi].size(),
bFacei
) = vf.boundaryField()[patchi];
}
else
{
const polyPatch& pp = bm[patchi].patch();
forAll(pp, i)
{
boundaryVals[bFacei++] = Zero;
}
}
}
return tboundaryVals;
}
template<class Type>
void Foam::volPointInterpolationAdjoint::addSeparated
(
GeometricField<Type, pointPatchField, pointMesh>& pf
) const
{
if (debug)
{
Pout<< "volPointInterpolation::addSeparated" << endl;
}
auto& pfi = pf.ref();
auto& pfbf = pf.boundaryFieldRef();
const label startOfRequests = UPstream::nRequests();
forAll(pfbf, patchi)
{
if (pfbf[patchi].coupled())
{
refCast<coupledPointPatchField<Type>>
(pfbf[patchi]).initSwapAddSeparated
(
Pstream::commsTypes::nonBlocking,
pfi
);
}
}
// Wait for outstanding requests
UPstream::waitRequests(startOfRequests);
forAll(pfbf, patchi)
{
if (pfbf[patchi].coupled())
{
refCast<coupledPointPatchField<Type>>
(pfbf[patchi]).swapAddSeparated
(
Pstream::commsTypes::nonBlocking,
pfi
);
}
}
}
template<class Type>
void Foam::volPointInterpolationAdjoint::interpolateSensitivitiesField
(
const GeometricField<Type, pointPatchField, pointMesh>& pf,
typename GeometricField<Type, fvPatchField, volMesh>::Boundary& vf,
const labelHashSet& patchIDs
) const
{
const Field<Type>& pfi = pf.primitiveField();
// Get face data in flat list
const fvMesh& Mesh = mesh();
const fvBoundaryMesh& bm = Mesh.boundary();
tmp<Field<Type>> tboundaryVals
(
new Field<Type>(Mesh.nBoundaryFaces(), Zero)
);
Field<Type>& boundaryVals = tboundaryVals.ref();
// Do points on 'normal' patches from the surrounding patch faces
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const primitivePatch& boundary = boundaryPtr_();
const labelList& mp = boundary.meshPoints();
forAll(mp, i)
{
label pointi = mp[i];
if (isPatchPoint_[pointi])
{
const labelList& pFaces = boundary.pointFaces()[i];
const scalarList& pWeights = boundaryPointWeights_[i];
const Type& val = pfi[pointi];
// Face-to-point weights should, in general, have half the weight
// of what they actually do in volPointInterpolation since, in
// a complete case, a face laying on the opposite side of the
// symmetry plane would also contribute to a point laying on
// the symmetry plane.
// For face-to-point interpolation this is not a problem, but for
// the adjoint point-to-face interpolation, the correct value of
// the weight should be taken into consideration
scalar mod(isSymmetryPoint_[pointi] ? 0.5 : 1);
forAll(pFaces, j)
{
if (boundaryIsPatchFace_[pFaces[j]])
{
boundaryVals[pFaces[j]] += mod*pWeights[j]*val;
}
}
}
}
// Transfer values to face-based sensitivity field
for (const label patchi : patchIDs)
{
label bFacei = bm[patchi].patch().start() - Mesh.nInternalFaces();
if (!isA<emptyFvPatch>(bm[patchi]) && !vf[patchi].coupled())
{
vf[patchi] =
SubList<Type>
(
boundaryVals,
vf[patchi].size(),
bFacei
);
}
}
}
template<class Type>
void Foam::volPointInterpolationAdjoint::interpolateBoundaryField
(
const GeometricField<Type, fvPatchField, volMesh>& vf,
GeometricField<Type, pointPatchField, pointMesh>& pf
) const
{
const primitivePatch& boundary = boundaryPtr_();
Field<Type>& pfi = pf.primitiveFieldRef();
// Get face data in flat list
tmp<Field<Type>> tboundaryVals(flatBoundaryField(vf));
const Field<Type>& boundaryVals = tboundaryVals();
// Do points on 'normal' patches from the surrounding patch faces
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const labelList& mp = boundary.meshPoints();
forAll(mp, i)
{
label pointi = mp[i];
if (isPatchPoint_[pointi])
{
const labelList& pFaces = boundary.pointFaces()[i];
const scalarList& pWeights = boundaryPointWeights_[i];
Type& val = pfi[pointi];
val = Zero;
forAll(pFaces, j)
{
if (boundaryIsPatchFace_[pFaces[j]])
{
scalar mod(1);
if (isSymmetryPoint_[pointi])
{
const label globalFaceI =
mesh().nInternalFaces() + pFaces[j];
const label facePatchID =
mesh().boundaryMesh().whichPatch(globalFaceI);
const polyPatch& pp = mesh().boundaryMesh()[facePatchID];
if
(
isA<symmetryPolyPatch>(pp)
|| isA<symmetryPlanePolyPatch>(pp)
)
{
mod = 0;
}
//else
//{
// mod = 2;
//}
}
val += mod*pWeights[j]*boundaryVals[pFaces[j]];
}
}
}
}
// Sum collocated contributions
pointConstraints::syncUntransformedData(mesh(), pfi, plusEqOp<Type>());
// And add separated contributions
addSeparated(pf);
// Optionally normalise
/*
if (normalisationPtr_)
{
const scalarField& normalisation = normalisationPtr_();
forAll(mp, i)
{
pfi[mp[i]] *= normalisation[i];
}
}
*/
// Push master data to slaves. It is possible (not sure how often) for
// a coupled point to have its master on a different patch so
// to make sure just push master data to slaves.
pushUntransformedData(pfi);
// Apply displacement constraints
const pointConstraints& pcs = pointConstraints::New(pf.mesh());
pcs.constrain(pf, false);
}
// ************************************************************************* //

View File

@ -0,0 +1,391 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "volPointInterpolationAdjoint.H"
#include "fvMesh.H"
#include "volFields.H"
#include "pointFields.H"
#include "pointConstraints.H"
#include "surfaceFields.H"
#include "processorPointPatch.H"
#include "symmetryPolyPatch.H"
#include "symmetryPlanePolyPatch.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(volPointInterpolationAdjoint, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::volPointInterpolationAdjoint::calcBoundaryAddressing()
{
if (debug)
{
Pout<< "volPointInterpolationAdjoint::calcBoundaryAddressing() : "
<< "constructing boundary addressing"
<< endl;
}
boundaryPtr_.reset
(
new primitivePatch
(
SubList<face>
(
mesh().faces(),
mesh().nBoundaryFaces(),
mesh().nInternalFaces()
),
mesh().points()
)
);
const primitivePatch& boundary = boundaryPtr_();
boundaryIsPatchFace_.setSize(boundary.size());
boundaryIsPatchFace_ = false;
// Store per mesh point whether it is on any 'real' patch. Currently
// boolList just so we can use syncUntransformedData (does not take
// bitSet. Tbd)
boolList isPatchPoint(mesh().nPoints(), false);
boolList isSymmetryPoint(mesh().nPoints(), false);
const polyBoundaryMesh& pbm = mesh().boundaryMesh();
// Get precalculated volField only so we can use coupled() tests for
// cyclicAMI
const surfaceScalarField& magSf = mesh().magSf();
forAll(pbm, patchi)
{
const polyPatch& pp = pbm[patchi];
if
(
!isA<emptyPolyPatch>(pp)
&& !magSf.boundaryField()[patchi].coupled()
&& !isA<symmetryPolyPatch>(pp)
&& !isA<symmetryPlanePolyPatch>(pp)
)
{
label bFacei = pp.start()-mesh().nInternalFaces();
forAll(pp, i)
{
boundaryIsPatchFace_[bFacei] = true;
const face& f = boundary[bFacei++];
forAll(f, fp)
{
isPatchPoint[f[fp]] = true;
}
}
}
else if (isA<symmetryPolyPatch>(pp) || isA<symmetryPlanePolyPatch>(pp))
{
const labelList& meshPoints = pp.meshPoints();
for (const label pointI : meshPoints)
{
isSymmetryPoint[pointI] = true;
}
}
}
// Make sure point status is synchronised so even processor that holds
// no face of a certain patch still can have boundary points marked.
pointConstraints::syncUntransformedData
(
mesh(),
isPatchPoint,
orEqOp<bool>()
);
// Convert to bitSet
isPatchPoint_.setSize(mesh().nPoints());
isPatchPoint_.assign(isPatchPoint);
isSymmetryPoint_.setSize(mesh().nPoints());
isSymmetryPoint_.assign(isSymmetryPoint);
if (debug)
{
label nPatchFace = 0;
forAll(boundaryIsPatchFace_, i)
{
if (boundaryIsPatchFace_[i])
{
nPatchFace++;
}
}
label nPatchPoint = 0;
forAll(isPatchPoint_, i)
{
if (isPatchPoint_[i])
{
nPatchPoint++;
}
}
Pout<< "boundary:" << nl
<< " faces :" << boundary.size() << nl
<< " of which on proper patch:" << nPatchFace << nl
<< " points:" << boundary.nPoints() << nl
<< " of which on proper patch:" << nPatchPoint << endl;
}
}
void Foam::volPointInterpolationAdjoint::makeBoundaryWeights
(
scalarField& sumWeights
)
{
if (debug)
{
Pout<< "volPointInterpolationAdjoint::makeBoundaryWeights() : "
<< "constructing weighting factors for boundary points." << endl;
}
const pointField& points = mesh().points();
const pointField& faceCentres = mesh().faceCentres();
const primitivePatch& boundary = boundaryPtr_();
boundaryPointWeights_.clear();
boundaryPointWeights_.setSize(boundary.meshPoints().size());
forAll(boundary.meshPoints(), i)
{
label pointi = boundary.meshPoints()[i];
if (isPatchPoint_[pointi])
{
const labelList& pFaces = boundary.pointFaces()[i];
scalarList& pw = boundaryPointWeights_[i];
pw.setSize(pFaces.size());
sumWeights[pointi] = 0.0;
forAll(pFaces, i)
{
if (boundaryIsPatchFace_[pFaces[i]])
{
label facei = mesh().nInternalFaces() + pFaces[i];
pw[i] = 1.0/mag(points[pointi] - faceCentres[facei]);
sumWeights[pointi] += pw[i];
}
else
{
pw[i] = 0.0;
}
}
}
}
}
void Foam::volPointInterpolationAdjoint::makeWeights()
{
if (debug)
{
Pout<< "volPointInterpolationAdjoint::makeWeights() : "
<< "constructing weighting factors"
<< endl;
}
const pointMesh& pMesh = pointMesh::New(mesh());
// Update addressing over all boundary faces
calcBoundaryAddressing();
// Running sum of weights
tmp<pointScalarField> tsumWeights
(
new pointScalarField
(
IOobject
(
"volPointSumWeights",
mesh().polyMesh::instance(),
mesh()
),
pMesh,
dimensionedScalar(dimless, Zero)
)
);
pointScalarField& sumWeights = tsumWeights.ref();
// Create boundary weights; sumWeights
makeBoundaryWeights(sumWeights);
const primitivePatch& boundary = boundaryPtr_();
const labelList& mp = boundary.meshPoints();
// Sum collocated contributions
pointConstraints::syncUntransformedData
(
mesh(),
sumWeights,
plusEqOp<scalar>()
);
// Push master data to slaves. It is possible (not sure how often) for
// a coupled point to have its master on a different patch so
// to make sure just push master data to slaves. Reuse the syncPointData
// structure.
pushUntransformedData(sumWeights);
// Normalise boundary weights
forAll(mp, i)
{
const label pointi = mp[i];
scalarList& pw = boundaryPointWeights_[i];
// Note:pw only sized for isPatchPoint
forAll(pw, i)
{
pw[i] /= sumWeights[pointi];
}
}
if (debug)
{
Pout<< "volPointInterpolationAdjoint::makeWeights() : "
<< "finished constructing weighting factors"
<< endl;
}
}
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
Foam::volPointInterpolationAdjoint::volPointInterpolationAdjoint(const fvMesh& vm)
:
MeshObject<fvMesh, Foam::UpdateableMeshObject, volPointInterpolationAdjoint>
(
vm
)
{
makeWeights();
}
// * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * * //
Foam::volPointInterpolationAdjoint::~volPointInterpolationAdjoint()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::volPointInterpolationAdjoint::updateMesh(const mapPolyMesh&)
{
makeWeights();
}
bool Foam::volPointInterpolationAdjoint::movePoints()
{
makeWeights();
return true;
}
void Foam::volPointInterpolationAdjoint::interpolateSensitivitiesField
(
const vectorField& pf,
vectorField& vf,
const labelHashSet& patchIDs
) const
{
// Get face data in flat list
const fvMesh& Mesh = mesh();
vectorField boundaryVals(Mesh.nBoundaryFaces(), Zero);
// Do points on 'normal' patches from the surrounding patch faces
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const primitivePatch& boundary = boundaryPtr_();
const labelList& mp = boundary.meshPoints();
forAll(mp, i)
{
label pointi = mp[i];
if (isPatchPoint_[pointi])
{
const labelList& pFaces = boundary.pointFaces()[i];
const scalarList& pWeights = boundaryPointWeights_[i];
const vector& val = pf[pointi];
// In symmetry planes, face-to-point weights should, in general,
// have half the weight of what they actually do in
// volPointInterpolation since, in a complete case, a face laying
// on the opposite side of the symmetry plane would also contribute
// to a point laying on the symmetry plane.
// For face-to-point interpolation this is not a problem, but for
// the adjoint point-to-face interpolation, the correct value of
// the weight should be taken into consideration
scalar mod(isSymmetryPoint_[pointi] ? 0.5 : 1);
forAll(pFaces, j)
{
if (boundaryIsPatchFace_[pFaces[j]])
{
boundaryVals[pFaces[j]] += mod*pWeights[j]*val;
}
}
}
}
// Transfer values to face-based sensitivity field
label nPassedFaces(0);
for (const label patchi : patchIDs)
{
const fvPatch& patch = Mesh.boundary()[patchi];
label bFacei = patch.start() - Mesh.nInternalFaces();
SubList<vector> patchFaceSens(vf, patch.size(), nPassedFaces);
patchFaceSens = SubList<vector>(boundaryVals, patch.size(), bFacei);
nPassedFaces += patch.size();
}
}
// ************************************************************************* //

View File

@ -0,0 +1,193 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-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 <http://www.gnu.org/licenses/>.
Class
Foam::volPointInterpolationAdjoint
Description
Interpolate from cell centres to points (vertices) using inverse distance
weighting
SourceFiles
volPointInterpolationAdjoint.C
volPointInterpolate.C
\*---------------------------------------------------------------------------*/
#ifndef volPointInterpolationAdjoint_H
#define volPointInterpolationAdjoint_H
#include "MeshObject.H"
#include "scalarList.H"
#include "volFields.H"
#include "pointFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class fvMesh;
class pointMesh;
/*---------------------------------------------------------------------------*\
Class volPointInterpolationAdjoint Declaration
\*---------------------------------------------------------------------------*/
class volPointInterpolationAdjoint
:
public MeshObject<fvMesh, UpdateableMeshObject, volPointInterpolationAdjoint>
{
protected:
// Protected data
//- Boundary addressing
autoPtr<primitivePatch> boundaryPtr_;
//- Per boundary face whether is on non-coupled, non-empty patch
bitSet boundaryIsPatchFace_;
//- Per mesh(!) point whether is on non-coupled, non-empty patch (on
// any processor)
bitSet isPatchPoint_;
//- Per mesh(!) point whether is on symmetry plane
// any processor)
bitSet isSymmetryPoint_;
//- Per boundary point the weights per pointFaces.
scalarListList boundaryPointWeights_;
// Protected Member Functions
//- Construct addressing over all boundary faces
void calcBoundaryAddressing();
//- Make weights for points on uncoupled patches
void makeBoundaryWeights(scalarField& sumWeights);
//- Construct all point weighting factors
void makeWeights();
//- Helper: push master point data to collocated points
template<class Type>
void pushUntransformedData(List<Type>&) const;
//- Get boundary field in same order as boundary faces. Field is
// zero on all coupled and empty patches
template<class Type>
tmp<Field<Type>> flatBoundaryField
(
const GeometricField<Type, fvPatchField, volMesh>& vf
) const;
//- Add separated contributions
template<class Type>
void addSeparated
(
GeometricField<Type, pointPatchField, pointMesh>&
) const;
//- No copy construct
volPointInterpolationAdjoint(const volPointInterpolationAdjoint&) = delete;
//- No copy assignment
void operator=(const volPointInterpolationAdjoint&) = delete;
public:
// Declare name of the class and its debug switch
ClassName("volPointInterpolationAdjoint");
// Constructors
//- Constructor given fvMesh and pointMesh.
explicit volPointInterpolationAdjoint(const fvMesh&);
//- Destructor
~volPointInterpolationAdjoint();
// Member functions
// Edit
//- Update mesh topology using the morph engine
void updateMesh(const mapPolyMesh&);
//- Correct weighting factors for moving mesh.
bool movePoints();
// Interpolation Functions
//- Interpolate sensitivties from points to faces
// conditions
template<class Type>
void interpolateSensitivitiesField
(
const GeometricField<Type, pointPatchField, pointMesh>& pf,
typename GeometricField<Type, fvPatchField, volMesh>::Boundary& vf,
const labelHashSet& patchIDs
) const;
template<class Type>
void interpolateBoundaryField
(
const GeometricField<Type, fvPatchField, volMesh>& vf,
GeometricField<Type, pointPatchField, pointMesh>& pf
) const;
//- Interpolate sensitivties from points to faces
void interpolateSensitivitiesField
(
const vectorField& pf,
vectorField& vf,
const labelHashSet& patchIDs
) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "volPointInterpolateAdjoint.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -38,7 +38,6 @@ namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(objectiveManager, 0);
defineRunTimeSelectionTable(objectiveManager, dictionary);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -67,7 +66,7 @@ objectiveManager::objectiveManager
adjointSolverName_(adjointSolverName),
primalSolverName_(primalSolverName),
objectives_(0),
weigthedObjectiveFile_(nullptr)
weightedObjectiveFile_(nullptr)
{
// Construct objectives
//~~~~~~~~~~~~~~~~~~~~~
@ -107,7 +106,7 @@ objectiveManager::objectiveManager
if (objectives_.size() > 1)
{
const Time& time = mesh_.time();
weigthedObjectiveFile_.reset
weightedObjectiveFile_.reset
(
new OFstream
(
@ -117,59 +116,26 @@ objectiveManager::objectiveManager
);
unsigned int width = IOstream::defaultPrecision() + 5;
weigthedObjectiveFile_()
weightedObjectiveFile_()
<< setw(4) << "#" << " "
<< setw(width) << "weightedObjective" << " ";
for (objective& objI : objectives_)
{
weigthedObjectiveFile_()
weightedObjectiveFile_()
<< setw(width) << objI.objectiveName() << " ";
}
weigthedObjectiveFile_()
weightedObjectiveFile_()
<< endl;
}
}
}
// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
autoPtr<objectiveManager> objectiveManager::New
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
)
{
// Determine type of objectiveManager from objectiveType
const word objectiveType(dict.get<word>("type"));
const word managerType("objectiveManager" & objectiveType);
auto* ctorPtr = dictionaryConstructorTable(managerType);
if (!ctorPtr)
{
FatalIOErrorInLookup
(
dict,
"objectiveManagerType",
managerType,
*dictionaryConstructorTablePtr_
) << exit(FatalIOError);
}
return autoPtr<objectiveManager>
(
ctorPtr(mesh, dict, adjointSolverName, primalSolverName)
);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool objectiveManager::readDict(const dictionary& dict)
{
dict_ = dict;
for (objective& obj : objectives_)
{
obj.readDict
@ -233,15 +199,20 @@ void objectiveManager::incrementIntegrationTimes(const scalar timeSpan)
}
scalar objectiveManager::print()
scalar objectiveManager::print(bool negate)
{
scalar objValue(Zero);
Info<< "Adjoint solver " << adjointSolverName_ << endl;
for (objective& obj : objectives_)
{
scalar cost = obj.JCycle();
scalar weight = obj.weight();
objValue += weight*cost;
// This function is used to obtain the value used to figure out if
// line search is converged or not. If the objective is not updated
// in each iteration of the primal solver, the old objective value
// might be returned. Force the update of the objective the next
// time objective::J() is called.
obj.setComputed(false);
const scalar cost = obj.JCycle(negate);
objValue += cost;
Info<< obj.objectiveName() << " : " << cost << endl;
}
@ -252,35 +223,53 @@ scalar objectiveManager::print()
}
void objectiveManager::setWrite(const bool shouldWrite)
{
for (objective& obj : objectives_)
{
obj.setWrite(shouldWrite);
}
}
bool objectiveManager::writeObjectives()
{
for (const objective& obj : objectives_)
{
// Write objective function to file
if (obj.shouldWrite())
{
obj.write();
obj.writeMeanValue();
}
}
return true;
}
bool objectiveManager::writeObjectives
(
const scalar weightedObjective,
const bool valid
)
{
for (const objective& obj : objectives_)
{
// Write objective function to file
obj.write();
obj.writeMeanValue();
}
if (weigthedObjectiveFile_)
if (weightedObjectiveFile_.valid())
{
unsigned int width = IOstream::defaultPrecision() + 5;
weigthedObjectiveFile_()
weightedObjectiveFile_()
<< setw(4) << mesh_.time().timeName() << " "
<< setw(width) << weightedObjective << " ";
for (objective& objI : objectives_)
{
weigthedObjectiveFile_()
weightedObjectiveFile_()
<< setw(width) << objI.JCycle() << " ";
}
weigthedObjectiveFile_() << endl;
weightedObjectiveFile_() << endl;
}
return true;
return writeObjectives();
}
@ -332,6 +321,24 @@ void objectiveManager::checkIntegrationTimes() const
}
void objectiveManager::addSource(fvVectorMatrix& matrix)
{
for (objective& obj : objectives_)
{
obj.addSource(matrix);
}
}
void objectiveManager::addSource(fvScalarMatrix& matrix)
{
for (objective& obj : objectives_)
{
obj.addSource(matrix);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -29,7 +29,7 @@ Class
Foam::objectiveManager
Description
class for managing incompressible objective functions.
Class for managing objective functions.
SourceFiles
objectiveManager.C
@ -61,11 +61,11 @@ protected:
// Protected data
const fvMesh& mesh_;
const dictionary& dict_;
dictionary dict_;
const word adjointSolverName_;
const word primalSolverName_;
PtrList<objective> objectives_;
autoPtr<OFstream> weigthedObjectiveFile_;
autoPtr<OFstream> weightedObjectiveFile_;
private:
@ -83,22 +83,6 @@ public:
TypeName("objectiveManager");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
objectiveManager,
dictionary,
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
),
(mesh, dict, adjointSolverName, primalSolverName)
);
// Constructors
//- Construct from components
@ -110,17 +94,6 @@ public:
const word& primalSolverName
);
// Selectors
//- Return a reference to the selected turbulence model
static autoPtr<objectiveManager> New
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
);
//- Destructor
virtual ~objectiveManager() = default;
@ -143,7 +116,12 @@ public:
void incrementIntegrationTimes(const scalar timeSpan);
//- Print to screen
scalar print();
scalar print(bool negate = false);
//- Should the objectives be written to file upon calling write()?
void setWrite(const bool shouldWrite);
//- Write objective function history
virtual bool writeObjectives();
//- Write objective function history
virtual bool writeObjectives
@ -175,16 +153,10 @@ public:
void checkIntegrationTimes() const;
//- Add contribution to adjoint momentum PDEs
virtual void addUaEqnSource(fvVectorMatrix& UaEqn) = 0;
virtual void addSource(fvVectorMatrix& matrix);
//- Add contribution to adjoint momentum PDEs
virtual void addPaEqnSource(fvScalarMatrix& paEqn) = 0;
//- Add contribution to first adjoint turbulence model PDE
virtual void addTMEqn1Source(fvScalarMatrix& adjTMEqn1) = 0;
//- Add contribution to second adjoint turbulence model PDE
virtual void addTMEqn2Source(fvScalarMatrix& adjTMEqn2) = 0;
//- Add contribution to a scalar adjoint PDEs
virtual void addSource(fvScalarMatrix& matrix);
// IO

View File

@ -1,132 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "objectiveManagerIncompressible.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(objectiveManagerIncompressible, 0);
addToRunTimeSelectionTable
(
objectiveManager,
objectiveManagerIncompressible,
dictionary
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
objectiveManagerIncompressible::objectiveManagerIncompressible
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
)
:
objectiveManager(mesh, dict, adjointSolverName, primalSolverName)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void objectiveManagerIncompressible::addUaEqnSource(fvVectorMatrix& UaEqn)
{
// Add contributions from objective functions
for (objective& obj : objectives_)
{
auto& icoObj = refCast<objectiveIncompressible>(obj);
if (icoObj.hasdJdv())
{
scalar weight = icoObj.weight();
UaEqn += weight*icoObj.dJdv();
}
}
}
void objectiveManagerIncompressible::addPaEqnSource(fvScalarMatrix& paEqn)
{
// Add contributions from objective functions
for (objective& obj : objectives_)
{
auto& icoObj = refCast<objectiveIncompressible>(obj);
if (icoObj.hasdJdp())
{
scalar weight = icoObj.weight();
paEqn += weight*icoObj.dJdp();
}
}
}
void objectiveManagerIncompressible::addTMEqn1Source(fvScalarMatrix& adjTMEqn1)
{
// Add contributions from objective functions
for (objective& obj : objectives_)
{
auto& icoObj = refCast<objectiveIncompressible>(obj);
if (icoObj.hasdJdTMVar1())
{
scalar weight = icoObj.weight();
adjTMEqn1 += weight*icoObj.dJdTMvar1();
}
}
}
void objectiveManagerIncompressible::addTMEqn2Source(fvScalarMatrix& adjTMEqn2)
{
// Add contributions from objective functions
for (objective& obj : objectives_)
{
auto& icoObj = refCast<objectiveIncompressible>(obj);
if (icoObj.hasdJdTMVar2())
{
scalar weight = icoObj.weight();
adjTMEqn2 += weight*icoObj.dJdTMvar2();
}
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,119 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 PCOpt/NTUA
Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "objectiveGeometric.H"
#include "createZeroField.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(objectiveGeometric, 0);
defineRunTimeSelectionTable(objectiveGeometric, dictionary);
addToRunTimeSelectionTable
(
objective,
objectiveGeometric,
objective
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
objectiveGeometric::objectiveGeometric
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
)
:
objective(mesh, dict, adjointSolverName, primalSolverName)
{
weight_ = dict.get<scalar>("weight");
}
// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
autoPtr<objectiveGeometric> objectiveGeometric::New
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
)
{
const word modelType(dict.get<word>("type"));
Info<< "Creating objective function : " << dict.dictName()
<< " of type " << modelType << endl;
auto* ctorPtr = dictionaryConstructorTable(modelType);
if (!ctorPtr)
{
FatalIOErrorInLookup
(
dict,
"objectiveGeometric",
modelType,
*dictionaryConstructorTablePtr_
) << exit(FatalIOError);
}
return autoPtr<objectiveGeometric>
(
ctorPtr(mesh, dict, adjointSolverName, primalSolverName)
);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void objectiveGeometric::update()
{
// Update geometric fields
objective::update();
// Divide everything with normalization factor
doNormalization();
// Set objective as not computed, for the next optimisation cycle
computed_ = false;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -5,9 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2023 PCOpt/NTUA
Copyright (C) 2023 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,22 +26,21 @@ License
Class
Foam::objectiveManagerIncompressible
Foam::objectiveGeometric
Description
class for managing incompressible objective functions.
Abstract base class for objective functions that contain only geometric
quantities
SourceFiles
objectiveManagerIncompressible.C
objectiveGeometric.C
\*---------------------------------------------------------------------------*/
#ifndef objectiveManagerIncompressible_H
#define objectiveManagerIncompressible_H
#ifndef objectiveGeometric_H
#define objectiveGeometric_H
#include "objectiveManager.H"
#include "objectiveIncompressible.H"
#include "runTimeSelectionTables.H"
#include "objective.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -50,35 +48,64 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class objectiveManagerIncompressible Declaration
Class objectiveGeometric Declaration
\*---------------------------------------------------------------------------*/
class objectiveManagerIncompressible
class objectiveGeometric
:
public objectiveManager
public objective
{
private:
// Private Member Functions
//- No copy construct
objectiveManagerIncompressible
(
const objectiveManagerIncompressible&
) = delete;
objectiveGeometric(const objectiveGeometric&) = delete;
//- No copy assignment
void operator=(const objectiveManagerIncompressible&) = delete;
void operator=(const objectiveGeometric&) = delete;
public:
TypeName("objectiveManagerIncompressible");
//- Runtime type information
TypeName("geometric");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
objectiveGeometric,
dictionary,
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
),
(mesh, dict, adjointSolverName, primalSolverName)
);
// Constructors
//- Construct from components
objectiveManagerIncompressible
objectiveGeometric
(
const fvMesh& mesh,
const dictionary& dict,
const word& adjointSolverName,
const word& primalSolverName
);
// Selectors
//- Return a reference to the selected turbulence model
static autoPtr<objectiveGeometric> New
(
const fvMesh& mesh,
const dictionary& dict,
@ -88,22 +115,16 @@ public:
//- Destructor
virtual ~objectiveManagerIncompressible() = default;
virtual ~objectiveGeometric() = default;
// Member Functions
//- Add contribution to adjoint momentum PDEs
virtual void addUaEqnSource(fvVectorMatrix& UaEqn);
//- Return the objective function value
virtual scalar J() = 0;
//- Add contribution to adjoint momentum PDEs
virtual void addPaEqnSource(fvScalarMatrix& paEqn);
//- Add contribution to adjoint turbulence model PDE
virtual void addTMEqn1Source(fvScalarMatrix& adjTMEqn1);
//- Add contribution to adjoint turbulence model PDE
virtual void addTMEqn2Source(fvScalarMatrix& adjTMEqn2);
//- Update objective function derivatives
virtual void update();
};

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -45,7 +45,7 @@ namespace objectives
defineTypeNameAndDebug(objectivePartialVolume, 1);
addToRunTimeSelectionTable
(
objectiveIncompressible,
objectiveGeometric,
objectivePartialVolume,
dictionary
);
@ -61,7 +61,7 @@ objectivePartialVolume::objectivePartialVolume
const word& primalSolverName
)
:
objectiveIncompressible(mesh, dict, adjointSolverName, primalSolverName),
objectiveGeometric(mesh, dict, adjointSolverName, primalSolverName),
initVol_(Zero),
objectivePatches_
(
@ -72,7 +72,11 @@ objectivePartialVolume::objectivePartialVolume
)
{
// Read target volume if present. Else use the current one as a target
if (!dict.readIfPresent("initialVolume", initVol_))
if
(
!objective::readIfPresent("initialVolume", initVol_)
&& !dict.readIfPresent("initialVolume", initVol_)
)
{
const scalar oneThird(1.0/3.0);
for (const label patchi : objectivePatches_)
@ -129,10 +133,18 @@ void objectivePartialVolume::update_dSdbMultiplier()
}
bool objectivePartialVolume::writeData(Ostream& os) const
{
os.writeEntry("initialVolume", initVol_);
return objective::writeData(os);
}
void objectivePartialVolume::addHeaderInfo() const
{
objFunctionFilePtr_()
<< setw(width_) << "#VInit" << " "
<< setw(4) << "#" << " "
<< setw(width_) << "VInit" << " "
<< setw(width_) << initVol_ << endl;
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -39,7 +39,7 @@ SourceFiles
#ifndef objectivePartialVolume_H
#define objectivePartialVolume_H
#include "objectiveIncompressible.H"
#include "objectiveGeometric.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -55,7 +55,7 @@ namespace objectives
class objectivePartialVolume
:
public objectiveIncompressible
public objectiveGeometric
{
// Private data
@ -98,6 +98,9 @@ public:
//- sensitivity term
void update_dSdbMultiplier();
//- Write initial volume for continuation
virtual bool writeData(Ostream& os) const;
// Helper write functions
//- Write headers for additional columns
@ -107,7 +110,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace objectivePartialVolume
} // End namespace objectives
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019, 2022 PCOpt/NTUA
Copyright (C) 2013-2019, 2022 FOSS GP
Copyright (C) 2007-2023, 2022 PCOpt/NTUA
Copyright (C) 2013-2023, 2022 FOSS GP
Copyright (C) 2019-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -216,7 +216,7 @@ void objectiveForce::update_dxdbMultiplier()
tgradp.clear();
// Term coming from stresses
tmp<volScalarField> tnuEff = lamTransp.nu() + turbVars->nutRef();
tmp<volScalarField> tnuEff = lamTransp.nu() + turbVars->nut();
tmp<volSymmTensorField> tstress = tnuEff*twoSymm(tgradU);
const volSymmTensorField& stress = tstress.cref();
autoPtr<volVectorField> ptemp
@ -260,14 +260,14 @@ void objectiveForce::update_boundarydJdGradU()
const autoPtr<incompressible::RASModelVariables>& turbVars =
vars_.RASModelVariables();
const singlePhaseTransportModel& lamTransp = vars_.laminarTransport();
volScalarField nuEff(lamTransp.nu() + turbVars->nutRef());
volScalarField nuEff(lamTransp.nu() + turbVars->nut());
for (const label patchI : forcePatches_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
const vectorField& Sf = patch.Sf();
bdJdGradUPtr_()[patchI] =
- nuEff.boundaryField()[patchI]
*dev(forceDirection_*Sf + Sf*forceDirection_);
*dev(forceDirection_*Sf + Sf*forceDirection_)/denom();
}
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -89,7 +89,6 @@ objectiveIncompressible::objectiveIncompressible
bdJdnutPtr_(nullptr),
bdJdGradUPtr_(nullptr)
{
weight_ = dict.get<scalar>("weight");
computeMeanFields_ = vars_.computeMeanFields();
}
@ -200,312 +199,10 @@ void objectiveIncompressible::doNormalization()
}
const volVectorField& objectiveIncompressible::dJdv()
{
if (!dJdvPtr_)
{
// If pointer is not set, set it to a zero field
dJdvPtr_.reset
(
createZeroFieldPtr<vector>
(
mesh_,
("dJdv_"+type()),
dimLength/sqr(dimTime)
)
);
}
return *dJdvPtr_;
}
const volScalarField& objectiveIncompressible::dJdp()
{
if (!dJdpPtr_)
{
// If pointer is not set, set it to a zero field
dJdpPtr_.reset
(
createZeroFieldPtr<scalar>
(
mesh_,
("dJdp_"+type()),
dimensionSet(0, 3, -2, 0, 0, 0, 0)
)
);
}
return *dJdpPtr_;
}
const volScalarField& objectiveIncompressible::dJdT()
{
if (!dJdTPtr_)
{
// If pointer is not set, set it to a zero field
dJdTPtr_.reset
(
createZeroFieldPtr<scalar>
(
mesh_,
("dJdT_"+type()),
dimensionSet(0, 3, -2, 0, 0, 0, 0)
)
);
}
return *dJdTPtr_;
}
const volScalarField& objectiveIncompressible::dJdTMvar1()
{
if (!dJdTMvar1Ptr_)
{
// If pointer is not set, set it to a zero field
dJdTMvar1Ptr_.reset
(
createZeroFieldPtr<scalar>
(
mesh_,
("dJdTMvar1_"+type()),
dimensionSet(0, 0, -2, 0, 0, 0, 0)
)
);
}
return *dJdTMvar1Ptr_;
}
const volScalarField& objectiveIncompressible::dJdTMvar2()
{
if (!dJdTMvar2Ptr_)
{
// If pointer is not set, set it to a zero field
dJdTMvar2Ptr_.reset
(
createZeroFieldPtr<scalar>
(
mesh_,
("dJdTMvar2_"+type()),
dimensionSet(0, 3, -2, 0, 0, 0, 0)
)
);
}
return *dJdTMvar2Ptr_;
}
const fvPatchVectorField& objectiveIncompressible::boundarydJdv
(
const label patchI
)
{
if (!bdJdvPtr_)
{
bdJdvPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdJdvPtr_()[patchI];
}
const fvPatchScalarField& objectiveIncompressible::boundarydJdvn
(
const label patchI
)
{
if (!bdJdvnPtr_)
{
bdJdvnPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdvnPtr_()[patchI];
}
const fvPatchVectorField& objectiveIncompressible::boundarydJdvt
(
const label patchI
)
{
if (!bdJdvtPtr_)
{
bdJdvtPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdJdvtPtr_()[patchI];
}
const fvPatchVectorField& objectiveIncompressible::boundarydJdp
(
const label patchI
)
{
if (!bdJdpPtr_)
{
bdJdpPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdJdpPtr_()[patchI];
}
const fvPatchScalarField& objectiveIncompressible::boundarydJdT
(
const label patchI
)
{
if (!bdJdTPtr_)
{
bdJdTPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdTPtr_()[patchI];
}
const fvPatchScalarField& objectiveIncompressible::boundarydJdTMvar1
(
const label patchI
)
{
if (!bdJdTMvar1Ptr_)
{
bdJdTMvar1Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdTMvar1Ptr_()[patchI];
}
const fvPatchScalarField& objectiveIncompressible::boundarydJdTMvar2
(
const label patchI
)
{
if (!bdJdTMvar2Ptr_)
{
bdJdTMvar2Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdTMvar2Ptr_()[patchI];
}
const fvPatchScalarField& objectiveIncompressible::boundarydJdnut
(
const label patchI
)
{
if (!bdJdnutPtr_)
{
bdJdnutPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdnutPtr_()[patchI];
}
const fvPatchTensorField& objectiveIncompressible::boundarydJdGradU
(
const label patchI
)
{
if (!bdJdGradUPtr_)
{
bdJdGradUPtr_.reset(createZeroBoundaryPtr<tensor>(mesh_));
}
return bdJdGradUPtr_()[patchI];
}
const boundaryVectorField& objectiveIncompressible::boundarydJdv()
{
if (!bdJdvPtr_)
{
bdJdvPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdJdvPtr_();
}
const boundaryScalarField& objectiveIncompressible::boundarydJdvn()
{
if (!bdJdvnPtr_)
{
bdJdvnPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdvnPtr_();
}
const boundaryVectorField& objectiveIncompressible::boundarydJdvt()
{
if (!bdJdvtPtr_)
{
bdJdvtPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdJdvtPtr_();
}
const boundaryVectorField& objectiveIncompressible::boundarydJdp()
{
if (!bdJdpPtr_)
{
bdJdpPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdJdpPtr_();
}
const boundaryScalarField& objectiveIncompressible::boundarydJdT()
{
if (!bdJdTPtr_)
{
bdJdTPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdTPtr_();
}
const boundaryScalarField& objectiveIncompressible::boundarydJdTMvar1()
{
if (!bdJdTMvar1Ptr_)
{
bdJdTMvar1Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdTMvar1Ptr_();
}
const boundaryScalarField& objectiveIncompressible::boundarydJdTMvar2()
{
if (!bdJdTMvar2Ptr_)
{
bdJdTMvar2Ptr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdTMvar2Ptr_();
}
const boundaryScalarField& objectiveIncompressible::boundarydJdnut()
{
if (!bdJdnutPtr_)
{
bdJdnutPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
}
return bdJdnutPtr_();
}
const boundaryTensorField& objectiveIncompressible::boundarydJdGradU()
{
if (!bdJdGradUPtr_)
{
bdJdGradUPtr_.reset(createZeroBoundaryPtr<tensor>(mesh_));
}
return *bdJdGradUPtr_;
}
void objectiveIncompressible::update()
{
// Objective function value
J();
// Update geometric fields
objective::update();
// Update mean values here since they might be used in the
// subsequent functions
@ -517,9 +214,6 @@ void objectiveIncompressible::update()
update_dJdT();
update_dJdTMvar1();
update_dJdTMvar2();
update_dJdb();
update_divDxDbMultiplier();
update_gradDxDbMultiplier();
// boundaryFields
update_boundarydJdv();
@ -531,15 +225,12 @@ void objectiveIncompressible::update()
update_boundarydJdTMvar2();
update_boundarydJdnut();
update_boundarydJdGradU();
update_boundarydJdb();
update_dSdbMultiplier();
update_dndbMultiplier();
update_dxdbMultiplier();
update_dxdbDirectMultiplier();
update_boundaryEdgeContribution();
// Divide everything with normalization factor
doNormalization();
// Set objective as not computed, for the next optimisation cycle
computed_ = false;
}
@ -722,6 +413,15 @@ void objectiveIncompressible::update_dJdTMvar
}
void objectiveIncompressible::addSource(fvVectorMatrix& matrix)
{
if (fieldNames_.found(matrix.psi().name()) && hasdJdv())
{
matrix += weight()*dJdv();
}
}
bool objectiveIncompressible::write(const bool valid) const
{
return objective::write(valid);

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -176,76 +176,76 @@ public:
virtual void doNormalization();
//- Contribution to field adjoint momentum eqs
const volVectorField& dJdv();
inline const volVectorField& dJdv();
//- Contribution to field adjoint continuity eq
const volScalarField& dJdp();
inline const volScalarField& dJdp();
//- Contribution to field adjoint energy eq
const volScalarField& dJdT();
inline const volScalarField& dJdT();
//- Contribution to field adjoint turbulence model variable 1
const volScalarField& dJdTMvar1();
inline const volScalarField& dJdTMvar1();
//- Contribution to field adjoint turbulence model variable 2
const volScalarField& dJdTMvar2();
inline const volScalarField& dJdTMvar2();
//- Objective partial deriv wrt velocity for a specific patch
const fvPatchVectorField& boundarydJdv(const label);
//- Objective partial deriv wrt normal velocity for a specific patch
const fvPatchScalarField& boundarydJdvn(const label);
inline const fvPatchScalarField& boundarydJdvn(const label);
//- Objective partial deriv wrt tangent velocity for a specific patch
const fvPatchVectorField& boundarydJdvt(const label);
inline const fvPatchVectorField& boundarydJdvt(const label);
//- Objective partial deriv wrt pressure (times normal) for a specific
//- patch
const fvPatchVectorField& boundarydJdp(const label);
inline const fvPatchVectorField& boundarydJdp(const label);
//- Objective partial deriv wrt temperature for a specific patch
const fvPatchScalarField& boundarydJdT(const label);
inline const fvPatchScalarField& boundarydJdT(const label);
//- Objective partial deriv wrt turbulence model var 1 for a specific
//- patch
const fvPatchScalarField& boundarydJdTMvar1(const label);
inline const fvPatchScalarField& boundarydJdTMvar1(const label);
//- Objective partial deriv wrt turbulence model var 2 for a specific
//- patch
const fvPatchScalarField& boundarydJdTMvar2(const label);
inline const fvPatchScalarField& boundarydJdTMvar2(const label);
//- Objective partial deriv wrt nut for a specific patch
const fvPatchScalarField& boundarydJdnut(const label);
inline const fvPatchScalarField& boundarydJdnut(const label);
//- Objective partial deriv wrt stress tensor
const fvPatchTensorField& boundarydJdGradU(const label);
inline const fvPatchTensorField& boundarydJdGradU(const label);
//- Objective partial deriv wrt velocity for all patches
const boundaryVectorField& boundarydJdv();
inline const boundaryVectorField& boundarydJdv();
//- Objective partial deriv wrt normal velocity for all patches
const boundaryScalarField& boundarydJdvn();
inline const boundaryScalarField& boundarydJdvn();
//- Objective partial deriv wrt tangent velocity for all patches
const boundaryVectorField& boundarydJdvt();
inline const boundaryVectorField& boundarydJdvt();
//- Objective partial deriv wrt pressure (times normal) for all patches
const boundaryVectorField& boundarydJdp();
inline const boundaryVectorField& boundarydJdp();
//- Objective partial deriv wrt temperature for all patches
const boundaryScalarField& boundarydJdT();
inline const boundaryScalarField& boundarydJdT();
//- Objective partial deriv wrt turbulence model var 1 for all patches
const boundaryScalarField& boundarydJdTMvar1();
inline const boundaryScalarField& boundarydJdTMvar1();
//- Objective partial deriv wrt turbulence model var 2 for all patches
const boundaryScalarField& boundarydJdTMvar2();
inline const boundaryScalarField& boundarydJdTMvar2();
//- Objective partial deriv wrt nut for all patches
const boundaryScalarField& boundarydJdnut();
inline const boundaryScalarField& boundarydJdnut();
//- Objective partial deriv wrt gradU
const boundaryTensorField& boundarydJdGradU();
inline const boundaryTensorField& boundarydJdGradU();
//- Update objective function derivatives
virtual void update();
@ -295,6 +295,9 @@ public:
virtual void update_dJdb()
{}
virtual void update_dJdbField()
{}
virtual void update_divDxDbMultiplier()
{}
@ -328,20 +331,16 @@ public:
virtual void update_boundarydJdGradU()
{}
virtual void update_boundarydJdb()
//- Vector sources can be given only to the adjoint momentum equations.
//- Implemented in base objectiveIncompressible
virtual void addSource(fvVectorMatrix& matrix);
//- Scalar sources are more ambigious (adjoint pressure, turbulence
//- model, energy, etc equations), so the equivalent functions should
//- be overridden on an objective-basis
virtual void addSource(fvScalarMatrix& matrix)
{}
virtual void update_dSdbMultiplier()
{}
virtual void update_dndbMultiplier()
{}
virtual void update_dxdbMultiplier()
{}
virtual void update_dxdbDirectMultiplier()
{}
//- Some objectives need to store some auxiliary values.
//- If averaging is enabled, update these mean values here.

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -30,6 +30,189 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline const Foam::volVectorField& Foam::objectiveIncompressible::dJdv()
{
return *dJdvPtr_;
}
inline const Foam::volScalarField& Foam::objectiveIncompressible::dJdp()
{
return *dJdpPtr_;
}
inline const Foam::volScalarField& Foam::objectiveIncompressible::dJdT()
{
return *dJdTPtr_;
}
inline const Foam::volScalarField& Foam::objectiveIncompressible::dJdTMvar1()
{
return *dJdTMvar1Ptr_;
}
inline const Foam::volScalarField& Foam::objectiveIncompressible::dJdTMvar2()
{
return *dJdTMvar2Ptr_;
}
inline const Foam::fvPatchVectorField&
Foam::objectiveIncompressible::boundarydJdv
(
const label patchI
)
{
return bdJdvPtr_()[patchI];
}
inline const Foam::fvPatchScalarField&
Foam::objectiveIncompressible::boundarydJdvn
(
const label patchI
)
{
return bdJdvnPtr_()[patchI];
}
inline const Foam::fvPatchVectorField&
Foam::objectiveIncompressible::boundarydJdvt
(
const label patchI
)
{
return bdJdvtPtr_()[patchI];
}
inline const Foam::fvPatchVectorField&
Foam::objectiveIncompressible::boundarydJdp
(
const label patchI
)
{
return bdJdpPtr_()[patchI];
}
inline const Foam::fvPatchScalarField&
Foam::objectiveIncompressible::boundarydJdT
(
const label patchI
)
{
return bdJdTPtr_()[patchI];
}
inline const Foam::fvPatchScalarField&
Foam::objectiveIncompressible::boundarydJdTMvar1
(
const label patchI
)
{
return bdJdTMvar1Ptr_()[patchI];
}
inline const Foam::fvPatchScalarField&
Foam::objectiveIncompressible::boundarydJdTMvar2
(
const label patchI
)
{
return bdJdTMvar2Ptr_()[patchI];
}
inline const Foam::fvPatchScalarField&
Foam::objectiveIncompressible::boundarydJdnut
(
const label patchI
)
{
return bdJdnutPtr_()[patchI];
}
inline const Foam::fvPatchTensorField&
Foam::objectiveIncompressible::boundarydJdGradU
(
const label patchI
)
{
return bdJdGradUPtr_()[patchI];
}
inline const Foam::boundaryVectorField&
Foam::objectiveIncompressible::boundarydJdv()
{
return bdJdvPtr_();
}
inline const Foam::boundaryScalarField&
Foam::objectiveIncompressible::boundarydJdvn()
{
return bdJdvnPtr_();
}
inline const Foam::boundaryVectorField&
Foam::objectiveIncompressible::boundarydJdvt()
{
return bdJdvtPtr_();
}
inline const Foam::boundaryVectorField&
Foam::objectiveIncompressible::boundarydJdp()
{
return bdJdpPtr_();
}
inline const Foam::boundaryScalarField&
Foam::objectiveIncompressible::boundarydJdT()
{
return bdJdTPtr_();
}
inline const Foam::boundaryScalarField&
Foam::objectiveIncompressible::boundarydJdTMvar1()
{
return bdJdTMvar1Ptr_();
}
inline const Foam::boundaryScalarField&
Foam::objectiveIncompressible::boundarydJdTMvar2()
{
return bdJdTMvar2Ptr_();
}
inline const Foam::boundaryScalarField&
Foam::objectiveIncompressible::boundarydJdnut()
{
return bdJdnutPtr_();
}
inline const Foam::boundaryTensorField&
Foam::objectiveIncompressible::boundarydJdGradU()
{
return *bdJdGradUPtr_;
}
inline bool Foam::objectiveIncompressible::hasdJdv() const
{
return bool(dJdvPtr_);

View File

@ -242,7 +242,7 @@ void objectiveMoment::update_dxdbMultiplier()
tgradp.clear();
// Term coming from stresses
tmp<volScalarField> tnuEff = lamTransp.nu() + turbVars->nutRef();
tmp<volScalarField> tnuEff = lamTransp.nu() + turbVars->nut();
tmp<volSymmTensorField> tstress = tnuEff*twoSymm(tgradU);
const volSymmTensorField& stress = tstress.cref();
autoPtr<volVectorField> ptemp

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,6 +27,7 @@ License
\*---------------------------------------------------------------------------*/
#include "objectiveNutSqr.H"
#include "incompressiblePrimalSolver.H"
#include "incompressibleAdjointSolver.H"
#include "createZeroField.H"
#include "addToRunTimeSelectionTable.H"
@ -50,6 +51,27 @@ addToRunTimeSelectionTable
);
void objectiveNutSqr::populateFieldNames()
{
if (adjointTurbulenceNames_.empty())
{
const incompressibleAdjointSolver& adjSolver =
mesh_.lookupObject<incompressibleAdjointSolver>(adjointSolverName_);
const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS =
adjSolver.getAdjointVars().adjointTurbulence();
const wordList& baseNames =
adjointRAS().getAdjointTMVariablesBaseNames();
forAll(baseNames, nI)
{
fieldNames_.push_back
(adjSolver.extendedVariableName(baseNames[nI]));
adjointTurbulenceNames_.
push_back(adjSolver.extendedVariableName(baseNames[nI]));
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
objectiveNutSqr::objectiveNutSqr
@ -61,7 +83,8 @@ objectiveNutSqr::objectiveNutSqr
)
:
objectiveIncompressible(mesh, dict, adjointSolverName, primalSolverName),
zones_(mesh_.cellZones().indices(dict.get<wordRes>("zones")))
zones_(mesh_.cellZones().indices(dict.get<wordRes>("zones"))),
adjointTurbulenceNames_()
{
// Check if cellZones provided include at least one cell
checkCellZonesSize(zones_);
@ -70,13 +93,19 @@ objectiveNutSqr::objectiveNutSqr
// Allocate term to be added to volume-based sensitivity derivatives
divDxDbMultPtr_.reset
(
createZeroFieldPtr<scalar>
new volScalarField
(
IOobject
(
"divDxDbMult" + objectiveName_,
mesh_.time().timeName(),
mesh_,
("divDxdbMult"+type()) ,
// Dimensions are set in a way that the gradient of this term
// matches the source of the adjoint grid displacement PDE
sqr(dimLength)/pow3(dimTime)
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(sqr(dimLength)/pow3(dimTime), Zero),
fvPatchFieldBase::zeroGradientType()
)
);
}
@ -125,6 +154,9 @@ void objectiveNutSqr::update_dJdv()
tmp<volVectorField> dnutdU = adjointRAS->nutJacobianU(dnutdUMult);
if (dnutdU)
{
// If nut depends on U, allocate dJdv and add Ua to the fieldNames.
// It should be safe to do this here since objectives are updated
// before the first adjoint solution
if (!dJdvPtr_)
{
dJdvPtr_.reset
@ -137,6 +169,10 @@ void objectiveNutSqr::update_dJdv()
)
);
}
if (!fieldNames_.size())
{
fieldNames_.push_back(adjSolver.extendedVariableName("Ua"));
}
for (const label zI : zones_)
{
const cellZone& zoneI = mesh_.cellZones()[zI];
@ -204,6 +240,22 @@ void objectiveNutSqr::update_divDxDbMultiplier()
}
void objectiveNutSqr::addSource(fvScalarMatrix& matrix)
{
populateFieldNames();
const label fieldI = fieldNames_.find(matrix.psi().name());
if (fieldI == 0)
{
matrix += weight()*dJdTMvar1();
}
if (fieldI == 1)
{
matrix += weight()*dJdTMvar2();
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace objectives

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2022 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -76,6 +76,20 @@ class objectiveNutSqr
//- Where to define the objective
labelList zones_;
//- List with the names of the adjoint turbulence model fields
// This is kept separately from fieldNames since the latter may
// or may not include Ua, depending on whether nut is a function
// of U. This makes deciding on whether to add or not sources
// to a given fvScalarMatrix tricky, hence the utilisation of
// adjointTurbulenceNames_
wordList adjointTurbulenceNames_;
// Private Member Functions
//- Populate fieldNames
void populateFieldNames();
public:
@ -116,6 +130,9 @@ public:
//- Update field to be added to be added to volume-based
//- sensitivity derivatives, emerging from delta ( dV ) / delta b
void update_divDxDbMultiplier();
//- Add source terms to the adjoint turbulence model equations
virtual void addSource(fvScalarMatrix& matrix);
};

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2022 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -51,6 +51,25 @@ addToRunTimeSelectionTable
);
void objectivePowerDissipation::populateFieldNames()
{
if (fieldNames_.size() == 1)
{
const incompressibleAdjointSolver& adjSolver =
mesh_.lookupObject<incompressibleAdjointSolver>(adjointSolverName_);
const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS =
adjSolver.getAdjointVars().adjointTurbulence();
const wordList& baseNames =
adjointRAS().getAdjointTMVariablesBaseNames();
forAll(baseNames, nI)
{
fieldNames_.push_back
(adjSolver.extendedVariableName(baseNames[nI]));
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
objectivePowerDissipation::objectivePowerDissipation
@ -65,14 +84,12 @@ objectivePowerDissipation::objectivePowerDissipation
zones_(mesh_.cellZones().indices(dict.get<wordRes>("zones")))
{
// Append Ua name to fieldNames
/*
fieldNames_.setSize
(
1,
mesh_.lookupObject<solver>(adjointSolverName_).
extendedVariableName("Ua")
);
*/
// Check if cellZones provided include at least one cell
checkCellZonesSize(zones_);
@ -93,13 +110,19 @@ objectivePowerDissipation::objectivePowerDissipation
// Allocate terms to be added to volume-based sensitivity derivatives
divDxDbMultPtr_.reset
(
createZeroFieldPtr<scalar>
new volScalarField
(
IOobject
(
"divDxDbMult" + objectiveName_,
mesh_.time().timeName(),
mesh_,
("divDxdbMult" + type()),
// Dimensions are set in a way that the gradient of this term
// matches the source of the adjoint grid displacement PDE
sqr(dimLength)/pow3(dimTime)
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(sqr(dimLength)/pow3(dimTime), Zero),
fvPatchFieldBase::zeroGradientType()
)
);
gradDxDbMultPtr_.reset
@ -250,7 +273,21 @@ void objectivePowerDissipation::update_gradDxDbMultiplier()
}
}
gradDxDbMult.correctBoundaryConditions();
// Missing contribution from gradU in nut
}
void objectivePowerDissipation::addSource(fvScalarMatrix& matrix)
{
populateFieldNames();
const label fieldI = fieldNames_.find(matrix.psi().name());
if (fieldI == 1)
{
matrix += weight()*dJdTMvar1Ptr_();
}
if (fieldI == 2)
{
matrix += weight()*dJdTMvar2Ptr_();
}
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2022 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -66,6 +66,12 @@ class objectivePowerDissipation
labelList zones_;
// Private Member Functions
//- Populate fieldNames
void populateFieldNames();
public:
//- Runtime type information
@ -107,6 +113,9 @@ public:
//- Update grad(dx/db multiplier). Volume-based sensitivity term
virtual void update_gradDxDbMultiplier();
//- Add source terms to the adjoint turbulence model equations
virtual void addSource(fvScalarMatrix& matrix);
};

View File

@ -107,7 +107,7 @@ void objectivePtLosses::initialize()
const scalar mass = gSum(phiPatch);
if (mag(mass) > SMALL)
{
objectiveReportPatches.append(patchI);
objectiveReportPatches.push_back(patchI);
}
}
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2022 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -67,14 +67,12 @@ objectiveUniformityCellZone::objectiveUniformityCellZone
volZone_(zones_.size(), Zero)
{
// Append Ua name to fieldNames
/*
fieldNames_.setSize
(
1,
mesh_.lookupObject<solver>(adjointSolverName_).
extendedVariableName("Ua")
);
*/
// Check if cellZones provided include at least one cell
checkCellZonesSize(zones_);
@ -92,13 +90,19 @@ objectiveUniformityCellZone::objectiveUniformityCellZone
// Allocate term to be added to volume-based sensitivity derivatives
divDxDbMultPtr_.reset
(
createZeroFieldPtr<scalar>
new volScalarField
(
IOobject
(
"divDxDbMult" + objectiveName_,
mesh_.time().timeName(),
mesh_,
("divDxdbMult" + type()) ,
// Dimensions are set in a way that the gradient of this term
// matches the source of the adjoint grid displacement PDE
sqr(dimLength)/pow3(dimTime)
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(sqr(dimLength)/pow3(dimTime), Zero),
fvPatchFieldBase::zeroGradientType()
)
);
}

View File

@ -106,7 +106,7 @@ void objectiveUniformityPatch::initialize()
const scalar mass = gSum(phiPatch);
if (mass > SMALL)
{
objectiveReportPatches.append(patchI);
objectiveReportPatches.push_back(patchI);
}
}
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -50,6 +50,10 @@ void objective::makeFolder()
const Time& time = mesh_.time();
objFunctionFolder_ =
time.globalPath()/"optimisation"/type()/time.timeName();
if (mesh_.name() != polyMesh::defaultRegion)
{
objFunctionFolder_ /= mesh_.name();
}
mkDir(objFunctionFolder_);
}
@ -131,10 +135,12 @@ objective::objective
computeMeanFields_(false), // is reset in derived classes
nullified_(false),
normalize_(dict.getOrDefault<bool>("normalize", false)),
shouldWrite_(true),
J_(Zero),
JMean_(this->getOrDefault<scalar>("JMean", Zero)),
weight_(Zero),
weight_(dict.get<scalar>("weight")),
computed_(false),
normFactor_(nullptr),
target_
(
@ -142,14 +148,22 @@ objective::objective
autoPtr<scalar>::New(dict.get<scalar>("target")) :
nullptr
),
targetLeft_
(
dict.found("targetLeft") ?
autoPtr<scalar>::New(dict.get<scalar>("targetLeft")) :
nullptr
),
integrationStartTimePtr_(nullptr),
integrationEndTimePtr_(nullptr),
fieldNames_(),
// Initialize pointers to nullptr.
// Not all of them are required for each objective function.
// Each child should allocate whatever is needed.
dJdbPtr_(nullptr),
dJdbFieldPtr_(nullptr),
bdJdbPtr_(nullptr),
bdSdbMultPtr_(nullptr),
bdndbMultPtr_(nullptr),
@ -196,6 +210,9 @@ objective::objective
normFactor_.reset(new scalar(normFactor));
}
}
// Set the weight factor in case of continuation
this->readIfPresent("weight", weight_);
}
@ -245,7 +262,7 @@ bool objective::readDict(const dictionary& dict)
}
scalar objective::JCycle() const
scalar objective::JCycle(bool negate) const
{
scalar J(J_);
if
@ -259,15 +276,23 @@ scalar objective::JCycle() const
// Subtract target, in case the objective is used as a constraint
if (target_.valid())
{
if (negate)
{
J = - J + targetLeft_();
}
else
{
J -= target_();
}
}
// Normalize here, in order to get the correct value for line search
if (normalize_ && normFactor_)
{
J /= normFactor_();
}
J *= weight_;
return J;
}
@ -277,7 +302,12 @@ void objective::updateNormalizationFactor()
{
if (normalize_ && !normFactor_)
{
normFactor_.reset(new scalar(JCycle()));
scalar J(JCycle()/weight_);
normFactor_.reset(new scalar(J));
DebugInfo
<< "objective " << name() << ":: updating norm factor "
<< "to " << normFactor_()
<< " for time = " << mesh_.time().timeName() << endl;
}
}
@ -343,6 +373,10 @@ void objective::doNormalization()
{
dJdbPtr_().primitiveFieldRef() *= oneOverNorm;
}
if (hasdJdbField())
{
dJdbFieldPtr_() *= oneOverNorm;
}
if (hasBoundarydJdb())
{
bdJdbPtr_() *= oneOverNorm;
@ -393,7 +427,8 @@ bool objective::isWithinIntegrationTime() const
else
{
FatalErrorInFunction
<< "Unallocated integration start or end time"
<< "Unallocated integration start or end time for objective '"
<< objectiveName_ << "'"
<< exit(FatalError);
}
return false;
@ -416,193 +451,24 @@ void objective::incrementIntegrationTimes(const scalar timeSpan)
}
const volScalarField& objective::dJdb()
void objective::update()
{
if (!dJdbPtr_)
{
// If pointer is not set, set it to a zero field
dJdbPtr_.reset
(
createZeroFieldPtr<scalar>
(
mesh_,
("dJdb_" + objectiveName_),
dimensionSet(0, 5, -2, 0, 0, 0, 0)
)
);
}
// Objective function value
J();
return *dJdbPtr_;
}
// volFields
update_dJdb();
update_dJdbField();
update_divDxDbMultiplier();
update_gradDxDbMultiplier();
const fvPatchVectorField& objective::boundarydJdb(const label patchI)
{
if (!bdJdbPtr_)
{
bdJdbPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdJdbPtr_()[patchI];
}
const fvPatchVectorField& objective::dSdbMultiplier(const label patchI)
{
if (!bdSdbMultPtr_)
{
bdSdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdSdbMultPtr_()[patchI];
}
const fvPatchVectorField& objective::dndbMultiplier(const label patchI)
{
if (!bdndbMultPtr_)
{
bdndbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdndbMultPtr_()[patchI];
}
const fvPatchVectorField& objective::dxdbMultiplier(const label patchI)
{
if (!bdxdbMultPtr_)
{
bdxdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdxdbMultPtr_()[patchI];
}
const fvPatchVectorField& objective::dxdbDirectMultiplier(const label patchI)
{
if (!bdxdbDirectMultPtr_)
{
bdxdbDirectMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return bdxdbDirectMultPtr_()[patchI];
}
const vectorField& objective::boundaryEdgeMultiplier
(
const label patchI,
const label edgeI
)
{
if (!bdxdbDirectMultPtr_)
{
FatalErrorInFunction
<< "Unallocated boundaryEdgeMultiplier field"
<< exit(FatalError);
}
return bEdgeContribution_()[patchI][edgeI];
}
const boundaryVectorField& objective::boundarydJdb()
{
if (!bdJdbPtr_)
{
bdJdbPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return *bdJdbPtr_;
}
const boundaryVectorField& objective::dSdbMultiplier()
{
if (!bdSdbMultPtr_)
{
bdSdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return *bdSdbMultPtr_;
}
const boundaryVectorField& objective::dndbMultiplier()
{
if (!bdndbMultPtr_)
{
bdndbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return *bdndbMultPtr_;
}
const boundaryVectorField& objective::dxdbMultiplier()
{
if (!bdxdbMultPtr_)
{
bdxdbMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return *bdxdbMultPtr_;
}
const boundaryVectorField& objective::dxdbDirectMultiplier()
{
if (!bdxdbDirectMultPtr_)
{
bdxdbDirectMultPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
return *bdxdbDirectMultPtr_;
}
const vectorField3& objective::boundaryEdgeMultiplier()
{
if (!bdxdbDirectMultPtr_)
{
FatalErrorInFunction
<< "Unallocated boundaryEdgeMultiplier field"
<< endl << endl
<< exit(FatalError);
}
return *bEdgeContribution_;
}
const volScalarField& objective::divDxDbMultiplier()
{
if (!divDxDbMultPtr_)
{
// If pointer is not set, set it to a zero field
divDxDbMultPtr_.reset
(
createZeroFieldPtr<scalar>
(
mesh_,
("divDxDbMult"+objectiveName_),
// Variable dimensions!!
// Dummy dimensionless. Only the internalField will be used
dimless
)
);
}
return *divDxDbMultPtr_;
}
const volTensorField& objective::gradDxDbMultiplier()
{
if (!gradDxDbMultPtr_)
{
// If pointer is not set, set it to a zero field
gradDxDbMultPtr_.reset
(
createZeroFieldPtr<tensor>
(
mesh_,
("gradDxDbMult"+objectiveName_),
// Variable dimensions!!
dimensionSet(pow2(dimLength)/pow3(dimTime))
)
);
}
return *gradDxDbMultPtr_;
// boundaryFields
update_boundarydJdb();
update_dSdbMultiplier();
update_dndbMultiplier();
update_dxdbMultiplier();
update_dxdbDirectMultiplier();
update_boundaryEdgeContribution();
}
@ -614,6 +480,10 @@ void objective::nullify()
{
dJdbPtr_() == dimensionedScalar(dJdbPtr_().dimensions(), Zero);
}
if (hasdJdbField())
{
dJdbFieldPtr_() = Zero;
}
if (hasBoundarydJdb())
{
bdJdbPtr_() == vector::zero;
@ -676,6 +546,11 @@ bool objective::write(const bool valid) const
file<< setw(width_) << "#target" << " "
<< setw(width_) << target_() << endl;
}
if (targetLeft_.valid())
{
file<< setw(width_) << "#targetLeft" << " "
<< setw(width_) << targetLeft_() << endl;
}
if (normalize_)
{
file<< setw(width_) << "#normFactor " << " "
@ -685,6 +560,10 @@ bool objective::write(const bool valid) const
file<< setw(4) << "#" << " ";
file<< setw(width_) << "J" << " ";
file<< setw(width_) << "JCycle" << " ";
if (targetLeft_)
{
file<< setw(width_) << "JCycleLeft" << " ";
}
addHeaderColumns();
file<< endl;
}
@ -693,6 +572,10 @@ bool objective::write(const bool valid) const
file<< setw(4) << mesh_.time().value() << " ";
file<< setw(width_) << J_ << " ";
file<< setw(width_) << JCycle() << " ";
if (targetLeft_)
{
file<< setw(width_) << JCycle(true) << " ";
}
addColumnValues();
file<< endl;
}
@ -708,12 +591,14 @@ void objective::writeInstantaneousValue() const
// File is opened only upon invocation of the write function
// in order to avoid various instantiations of the same objective
// opening the same file
unsigned int width = IOstream::defaultPrecision() + 6;
if (!instantValueFilePtr_)
{
setInstantValueFilePtr();
}
instantValueFilePtr_() << mesh_.time().value() << tab << J_ << endl;
instantValueFilePtr_()
<< setw(width) << mesh_.time().value() << tab << J_ << endl;
}
}
@ -764,6 +649,7 @@ bool objective::writeData(Ostream& os) const
{
os.writeEntry("normFactor", normFactor_());
}
os.writeEntry("weight", weight_);
return os.good();
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -73,6 +73,7 @@ protected:
bool computeMeanFields_;
bool nullified_;
bool normalize_;
bool shouldWrite_;
//- Objective function value and weight
scalar J_;
@ -83,23 +84,47 @@ protected:
//- Objective weight
scalar weight_;
//- Whether the objective is computed or not
// Some objective (e.g. geometric ones) might not change from one
// iteration of the primal solver to the next and might be expensive
// to evaluate. This can be used to compute them only once per
// optimisation cycle
bool computed_;
//- Normalization factor
autoPtr<scalar> normFactor_;
//- Target value, in case the objective is used as a constraint
// Should be used in caution and with updateMethods than get affected
// by the target value, without requiring a sqr (e.g. SQP, MMA)
// Should be used with caution and with updateMethods
// than get affected by the target value, without
// requiring a sqr (e.g. SQP, MMA)
autoPtr<scalar> target_;
//- Target on the left hand-side of a double inequality,
//- for double sided constraints
autoPtr<scalar> targetLeft_;
//- Objective integration start and end times (for unsteady flows)
autoPtr<scalar> integrationStartTimePtr_;
autoPtr<scalar> integrationEndTimePtr_;
//- List of adjoint fields for which this objective will contribute
//- sources to their equations.
// Only for volume-based objectives for the moment
wordList fieldNames_;
//- Contribution to field sensitivity derivatives
// Topology optimisation or other variants with
// as many design variables as the mesh cells
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr<volScalarField> dJdbPtr_;
//- Contribution to sensitivity derivatives with a
//- random number of design variables
//- (neither surface, nor volume based)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr<scalarField> dJdbFieldPtr_;
// Contribution to surface sensitivity derivatives
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -155,9 +180,6 @@ protected:
// Protected Member Functions
//- Return objective dictionary
const dictionary& dict() const;
//- Set the output file ptr
void setObjectiveFilePtr() const;
@ -241,9 +263,10 @@ public:
//- Return the instantaneous objective function value
virtual scalar J() = 0;
//- Return the mean objective function value, if it exists,
//- otherwise the mean one
scalar JCycle() const;
//- Return the objective function of the optimisation cycle.
// This corresponds to the mean value, if it exists, or the
// instantaneous value otherwise
scalar JCycle(bool negate = false) const;
//- Accumulate contribution for the mean objective value
// For steady-state runs
@ -256,6 +279,12 @@ public:
//- Return the objective function weight
scalar weight() const;
//- Return the normalization factor
const autoPtr<scalar>& normFactor() const;
//- Return the objective target value
const autoPtr<scalar>& target() const;
//- Is the objective normalized
bool normalize() const;
@ -269,53 +298,56 @@ public:
void incrementIntegrationTimes(const scalar timeSpan);
//- Contribution to field sensitivities
const volScalarField& dJdb();
inline const volScalarField& dJdb();
//- Contribution to sensitivities with a random number of designVars
inline const scalarField& dJdbField();
//- Contribution to surface sensitivities for a specific patch
const fvPatchVectorField& boundarydJdb(const label);
inline const fvPatchVectorField& boundarydJdb(const label);
//- Multiplier of delta(n dS)/delta b
const fvPatchVectorField& dSdbMultiplier(const label);
inline const fvPatchVectorField& dSdbMultiplier(const label);
//- Multiplier of delta(n dS)/delta b
const fvPatchVectorField& dndbMultiplier(const label);
inline const fvPatchVectorField& dndbMultiplier(const label);
//- Multiplier of delta(x)/delta b
const fvPatchVectorField& dxdbMultiplier(const label);
inline const fvPatchVectorField& dxdbMultiplier(const label);
//- Multiplier of delta(x)/delta b
const fvPatchVectorField& dxdbDirectMultiplier(const label);
inline const fvPatchVectorField& dxdbDirectMultiplier(const label);
//- Multiplier located at patch boundary edges
const vectorField& boundaryEdgeMultiplier
inline const vectorField& boundaryEdgeMultiplier
(
const label patchI,
const label edgeI
);
//- Contribution to surface sensitivities for all patches
const boundaryVectorField& boundarydJdb();
inline const boundaryVectorField& boundarydJdb();
//- Multiplier of delta(n dS)/delta b for all patches
const boundaryVectorField& dSdbMultiplier();
inline const boundaryVectorField& dSdbMultiplier();
//- Multiplier of delta(n dS)/delta b for all patches
const boundaryVectorField& dndbMultiplier();
inline const boundaryVectorField& dndbMultiplier();
//- Multiplier of delta(x)/delta b for all patches
const boundaryVectorField& dxdbMultiplier();
inline const boundaryVectorField& dxdbMultiplier();
//- Multiplier of delta(x)/delta b for all patches
const boundaryVectorField& dxdbDirectMultiplier();
inline const boundaryVectorField& dxdbDirectMultiplier();
//- Multiplier located at patch boundary edges
const vectorField3& boundaryEdgeMultiplier();
inline const vectorField3& boundaryEdgeMultiplier();
//- Multiplier of grad( delta(x)/delta b) for volume-based sensitivities
const volScalarField& divDxDbMultiplier();
inline const volScalarField& divDxDbMultiplier();
//- Multiplier of grad( delta(x)/delta b) for volume-based sensitivities
const volTensorField& gradDxDbMultiplier();
inline const volTensorField& gradDxDbMultiplier();
//- Update objective function derivatives
virtual void update() = 0;
@ -327,6 +359,13 @@ public:
//- which the factor is not known a priori
virtual void updateNormalizationFactor();
virtual void update_dJdb()
{}
virtual void update_dJdbField()
{}
//- Update objective function derivative term
virtual void update_boundarydJdb()
{}
@ -360,6 +399,15 @@ public:
virtual void update_gradDxDbMultiplier()
{}
//- Manipulate fvVectorMatrix through the objective
virtual void addSource(fvVectorMatrix& matrix)
{}
//- Manipulate fvVectorMatrix through the objective
virtual void addSource(fvScalarMatrix& matrix)
{}
//- Write objective function history
virtual bool write(const bool valid = true) const;
@ -392,8 +440,15 @@ public:
//- Return the objective name
inline const word& objectiveName() const;
//- Should the objective be written to file upon calling write()?
inline bool shouldWrite() const;
//- Should the objective be written to file upon calling write()?
inline void setWrite(const bool shouldWrite);
// Inline functions for checking whether pointers are set or not
inline bool hasdJdb() const;
inline bool hasdJdbField() const;
inline bool hasBoundarydJdb() const;
inline bool hasdSdbMult() const;
inline bool hasdndbMult() const;
@ -406,6 +461,11 @@ public:
// Inline functions for checking whether integration times are set
inline bool hasIntegrationStartTime() const;
inline bool hasIntegrationEndTime() const;
// Set the computed status of the objective
inline void setComputed(const bool isComputed);
//- Return objective dictionary
const dictionary& dict() const;
};

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -36,12 +36,148 @@ inline const Foam::word& Foam::objective::objectiveName() const
}
inline bool Foam::objective::shouldWrite() const
{
return shouldWrite_;
}
inline void Foam::objective::setWrite(const bool shouldWrite)
{
shouldWrite_ = shouldWrite;
}
inline const Foam::volScalarField& Foam::objective::dJdb()
{
return *dJdbPtr_;
}
inline const Foam::scalarField& Foam::objective::dJdbField()
{
return *dJdbFieldPtr_;
}
inline const Foam::fvPatchVectorField&
Foam::objective::boundarydJdb(const label patchI)
{
return bdJdbPtr_()[patchI];
}
inline const Foam::fvPatchVectorField&
Foam::objective::dSdbMultiplier(const label patchI)
{
return bdSdbMultPtr_()[patchI];
}
inline const Foam::fvPatchVectorField&
Foam::objective::dndbMultiplier(const label patchI)
{
return bdndbMultPtr_()[patchI];
}
inline const Foam::fvPatchVectorField&
Foam::objective::dxdbMultiplier(const label patchI)
{
return bdxdbMultPtr_()[patchI];
}
inline const Foam::fvPatchVectorField&
Foam::objective::dxdbDirectMultiplier(const label patchI)
{
return bdxdbDirectMultPtr_()[patchI];
}
inline const Foam::vectorField& Foam::objective::boundaryEdgeMultiplier
(
const label patchI,
const label edgeI
)
{
if (!bdxdbDirectMultPtr_)
{
FatalErrorInFunction
<< "Unallocated boundaryEdgeMultiplier field"
<< exit(FatalError);
}
return bEdgeContribution_()[patchI][edgeI];
}
inline const Foam::boundaryVectorField& Foam::objective::boundarydJdb()
{
return *bdJdbPtr_;
}
inline const Foam::boundaryVectorField& Foam::objective::dSdbMultiplier()
{
return *bdSdbMultPtr_;
}
inline const Foam::boundaryVectorField& Foam::objective::dndbMultiplier()
{
return *bdndbMultPtr_;
}
inline const Foam::boundaryVectorField& Foam::objective::dxdbMultiplier()
{
return *bdxdbMultPtr_;
}
inline const Foam::boundaryVectorField& Foam::objective::dxdbDirectMultiplier()
{
return *bdxdbDirectMultPtr_;
}
inline const Foam::vectorField3& Foam::objective::boundaryEdgeMultiplier()
{
if (!bdxdbDirectMultPtr_)
{
FatalErrorInFunction
<< "Unallocated boundaryEdgeMultiplier field"
<< endl << endl
<< exit(FatalError);
}
return *bEdgeContribution_;
}
inline const Foam::volScalarField& Foam::objective::divDxDbMultiplier()
{
return *divDxDbMultPtr_;
}
inline const Foam::volTensorField& Foam::objective::gradDxDbMultiplier()
{
return *gradDxDbMultPtr_;
}
inline bool Foam::objective::hasdJdb() const
{
return bool(dJdbPtr_);
}
inline bool Foam::objective::hasdJdbField() const
{
return bool(dJdbFieldPtr_);
}
inline bool Foam::objective::hasBoundarydJdb() const
{
return bool(bdJdbPtr_);
@ -101,4 +237,11 @@ inline bool Foam::objective::hasIntegrationEndTime() const
return bool(integrationEndTimePtr_);
}
inline void Foam::objective::setComputed(const bool isComputed)
{
computed_ = isComputed;
}
// ************************************************************************* //

View File

@ -27,18 +27,23 @@ License
\*---------------------------------------------------------------------------*/
#include "adjointEikonalSolverIncompressible.H"
#include "adjointEikonalSolver.H"
#include "adjointSolver.H"
#include "fvc.H"
#include "fvm.H"
#include "surfaceInterpolation.H"
#include "volFieldsFwd.H"
#include "wallFvPatch.H"
#include "patchDistMethod.H"
#include "fvOptions.H"
#include "zeroGradientFvPatchField.H"
#include "sensitivityTopO.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(adjointEikonalSolver, 0);
@ -55,7 +60,7 @@ wordList adjointEikonalSolver::patchTypes() const
for (const label patchi : wallPatchIDs_)
{
daTypes[patchi] = fvPatchFieldBase::zeroGradientType();
daTypes[patchi] = zeroGradientFvPatchScalarField::typeName;
}
return daTypes;
@ -66,7 +71,6 @@ void adjointEikonalSolver::read()
{
nEikonalIters_ = dict_.getOrDefault<label>("iters", 1000);
tolerance_ = dict_.getOrDefault<scalar>("tolerance", 1e-6);
epsilon_ = dict_.getOrDefault<scalar>("epsilon", 0.1);
const scalar defaultEps =
mesh_.schemesDict().subDict("wallDist").
subOrEmptyDict("advectionDiffusionCoeffs").
@ -78,7 +82,7 @@ void adjointEikonalSolver::read()
tmp<surfaceScalarField> adjointEikonalSolver::computeYPhi()
{
// Primal distance field
const volScalarField& d = RASModelVars_().d();
const volScalarField& d = adjointSolver_.yWall();
volVectorField ny
(
@ -118,15 +122,13 @@ adjointEikonalSolver::adjointEikonalSolver
(
const fvMesh& mesh,
const dictionary& dict,
const autoPtr<incompressible::RASModelVariables>& RASModelVars,
incompressibleAdjointVars& adjointVars,
adjointSolver& adjointSolver,
const labelHashSet& sensitivityPatchIDs
)
:
mesh_(mesh),
dict_(dict.subOrEmptyDict("adjointEikonalSolver")),
RASModelVars_(RASModelVars),
adjointTurbulence_(adjointVars.adjointTurbulence()),
adjointSolver_(adjointSolver),
sensitivityPatchIDs_(sensitivityPatchIDs),
nEikonalIters_(-1),
tolerance_(-1),
@ -138,17 +140,19 @@ adjointEikonalSolver::adjointEikonalSolver
(
word
(
adjointVars.useSolverNameForFields() ?
"da" + adjointTurbulence_().adjointSolverName() :
adjointSolver.useSolverNameForFields() ?
"da" + adjointSolver.solverName() :
"da"
),
mesh_.time().timeName(),
mesh_,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
// adjointVars.writeFields() ?
// IOobject::AUTO_WRITE : IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(sqr(dimLength)/pow3(dimTime), Zero),
dimensionedScalar(adjointSolver.daDimensions() , Zero),
patchTypes()
),
source_
@ -162,7 +166,7 @@ adjointEikonalSolver::adjointEikonalSolver
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(dimLength/pow3(dimTime), Zero)
dimensionedScalar(adjointSolver.daDimensions()/dimLength, Zero)
),
distanceSensPtr_(createZeroBoundaryPtr<vector>(mesh_))
{
@ -175,6 +179,7 @@ adjointEikonalSolver::adjointEikonalSolver
bool adjointEikonalSolver::readDict(const dictionary& dict)
{
dict_ = dict.subOrEmptyDict("adjointEikonalSolver");
read();
return true;
}
@ -183,7 +188,7 @@ bool adjointEikonalSolver::readDict(const dictionary& dict)
void adjointEikonalSolver::accumulateIntegrand(const scalar dt)
{
// Accumulate integrand from the current time step
source_ += adjointTurbulence_->distanceSensitivities()*dt;
source_ += adjointSolver_.adjointEikonalSource()*dt;
}
@ -192,12 +197,29 @@ void adjointEikonalSolver::solve()
read();
// Primal distance field
const volScalarField& d = RASModelVars_().d();
const volScalarField& d = adjointSolver_.yWall();
// Convecting flux
tmp<surfaceScalarField> tyPhi = computeYPhi();
const surfaceScalarField& yPhi = tyPhi();
volScalarField scaleDims
(
IOobject
(
"scaleDims",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
mesh_,
dimensionedScalar("scaleDims", dimTime/dimLength, scalar(1))
);
fv::options& fvOptions(fv::options::New(this->mesh_));
// Iterate the adjoint to the eikonal equation
for (label iter = 0; iter < nEikonalIters_; ++iter)
{
@ -211,10 +233,15 @@ void adjointEikonalSolver::solve()
+ fvm::SuSp(-epsilon_*fvc::laplacian(d), da_)
- epsilon_*fvm::laplacian(d, da_)
+ source_
==
fvOptions(scaleDims, da_)
);
daEqn.relax();
fvOptions.constrain(daEqn);
scalar residual = daEqn.solve().initialResidual();
fvOptions.correct(da_);
Info<< "Max da " << gMax(mag(da_)()) << endl;
mesh_.time().printExecutionTime(Info);
@ -247,7 +274,7 @@ boundaryVectorField& adjointEikonalSolver::distanceSensitivities()
boundaryVectorField& distanceSens = distanceSensPtr_();
const volScalarField& d = RASModelVars_().d();
const volScalarField& d = adjointSolver_.yWall();
for (const label patchi : sensitivityPatchIDs_)
{
vectorField nf(mesh_.boundary()[patchi].nf());
@ -266,10 +293,12 @@ tmp<volTensorField> adjointEikonalSolver::getFISensitivityTerm() const
{
Info<< "Calculating distance sensitivities " << endl;
const volScalarField& d = RASModelVars_().d();
const volScalarField& d = adjointSolver_.yWall();
const volVectorField gradD(fvc::grad(d));
volVectorField gradDDa
auto gradDDa
(
tmp<volVectorField>::New
(
IOobject
(
@ -282,12 +311,13 @@ tmp<volTensorField> adjointEikonalSolver::getFISensitivityTerm() const
mesh_,
dimensionedVector(d.dimensions()*da_.dimensions()/dimLength, Zero),
patchDistMethod::patchTypes<vector>(mesh_, wallPatchIDs_)
)
);
gradDDa = fvc::grad(d*da_);
gradDDa.ref() = fvc::grad(d*da_);
tmp<volTensorField> tdistanceSens
auto tdistanceSens
(
new volTensorField
tmp<volTensorField>::New
(
IOobject
(
@ -298,20 +328,46 @@ tmp<volTensorField> adjointEikonalSolver::getFISensitivityTerm() const
IOobject::AUTO_WRITE
),
mesh_,
dimensionedTensor(da_.dimensions(), Zero)
dimensionedTensor(da_.dimensions(), Zero),
zeroGradientFvPatchField<tensor>::typeName
)
);
volTensorField& distanceSens = tdistanceSens.ref();
distanceSens =
- 2.*da_*gradD*gradD
- epsilon_*gradD*gradDDa
+ epsilon_*da_*d*fvc::grad(gradD);
- epsilon_*gradDDa*gradD
// grad(gradD) is symmetric theoretically but not numerically when
// computed with the Gauss divergence theorem. The following maintains
// exactly the same behaviour as the one before the re-factoring of
// sensitivities but avoid calling the tranpose operator.
+ epsilon_*da_*d*fvc::div(fvc::interpolate(gradD)*mesh_.Sf());
distanceSens.correctBoundaryConditions();
return tdistanceSens;
}
tmp<scalarField> adjointEikonalSolver::topologySensitivities
(
const word& designVarsName
) const
{
const volScalarField& d = adjointSolver_.yWall();
auto tres(tmp<scalarField>::New(d.primitiveField().size(), Zero));
scalarField dSens(d.primitiveField()*da_.primitiveField());
fv::options& fvOptions(fv::options::New(this->mesh_));
sensitivityTopO::postProcessSens
(
tres.ref(), dSens, fvOptions, d.name(), designVarsName
);
return tres;
}
const volScalarField& adjointEikonalSolver::da()
{
return da_;
@ -320,7 +376,7 @@ const volScalarField& adjointEikonalSolver::da()
tmp<volVectorField> adjointEikonalSolver::gradEikonal()
{
const volScalarField& d = RASModelVars_().d();
const volScalarField& d = adjointSolver_.yWall();
volVectorField gradD(fvc::grad(d));
return tmp<volVectorField>::New("gradEikonal", 2*gradD & fvc::grad(gradD));
}
@ -328,7 +384,6 @@ tmp<volVectorField> adjointEikonalSolver::gradEikonal()
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -27,7 +27,7 @@ License
Class
Foam::incompressible::adjointEikonalSolver
Foam::adjointEikonalSolver
Description
Solver of the adjoint to the eikonal PDE
@ -123,22 +123,23 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef adjointEikonalSolverIncompressible_H
#define adjointEikonalSolverIncompressible_H
#ifndef adjointEikonalSolver_H
#define adjointEikonalSolver_H
#include "IOdictionary.H"
#include "incompressibleAdjointVars.H"
#include "volFieldsFwd.H"
#include "fvMesh.H"
#include "calculatedFvPatchField.H"
#include "createZeroField.H"
#include "boundaryFieldsFwd.H"
#include "RASModelVariables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// Forward Declaration
class adjointSolver;
/*---------------------------------------------------------------------------*\
Class adjointEikonalSolver Declaration
@ -165,10 +166,7 @@ protected:
dictionary dict_;
const autoPtr<incompressible::RASModelVariables>& RASModelVars_;
autoPtr<Foam::incompressibleAdjoint::adjointRASModel>&
adjointTurbulence_;
adjointSolver& adjointSolver_;
const labelHashSet& sensitivityPatchIDs_;
@ -214,8 +212,7 @@ public:
(
const fvMesh& mesh,
const dictionary& dict,
const autoPtr<incompressible::RASModelVariables>& RASModelVars,
incompressibleAdjointVars& adjointVars,
adjointSolver& adjointSolver,
const labelHashSet& sensitivityPatchIDs
);
@ -244,6 +241,9 @@ public:
//- Return the volume-based sensitivity term depending on da
tmp<volTensorField> getFISensitivityTerm() const;
//- Return sensitivity contribution to topology optimisation
tmp<scalarField> topologySensitivities(const word& designVarsName) const;
//- Return the adjoint distance field
const volScalarField& da();
@ -257,7 +257,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2022 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -27,41 +27,57 @@ License
\*---------------------------------------------------------------------------*/
#include "adjointEikonalSolver.H"
#include "runTimeSelectionTables.H"
#include "adjointSensitivityIncompressible.H"
#include "boundaryAdjointContribution.H"
#include "incompressibleAdjointSolver.H"
#include "wallFvPatch.H"
#include "adjointSensitivity.H"
#include "adjointSolver.H"
#include "designVariables.H"
#include "fvOptions.H"
#include "reverseLinear.H"
#include "sensitivity.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(adjointSensitivity, 0);
defineRunTimeSelectionTable(adjointSensitivity, dictionary);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
adjointSensitivity::adjointSensitivity
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
class adjointSolver& adjointSolver
)
:
sensitivity(mesh, dict),
derivatives_(0),
adjointSolver_(adjointSolver),
primalVars_(adjointSolver.getPrimalVars()),
adjointVars_(adjointSolver.getAdjointVars()),
objectiveManager_(adjointSolver.getObjectiveManager())
derivatives_(0),
suffix_(word::null),
includeDistance_
(
this->dict().getOrDefault<bool>
(
"includeDistance",
adjointSolver_.includeDistance()
)
),
eikonalSolver_(nullptr),
gradDxDbMult_(nullptr),
divDxDbMult_(nullptr),
dxdbMult_(nullptr),
dSfdbMult_(nullptr),
dnfdbMult_(nullptr),
dxdbDirectMult_(nullptr),
pointDxDbDirectMult_(nullptr),
bcDxDbMult_(nullptr),
optionsDxDbMult_(nullptr)
{}
@ -71,14 +87,15 @@ autoPtr<adjointSensitivity> adjointSensitivity::New
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
class adjointSolver& adjointSolver
)
{
const word modelType(dict.get<word>("type"));
const word sensType =
dict.optionalSubDict(mesh.name()).get<word>("sensitivityType");
Info<< "adjointSensitivity type : " << modelType << endl;
Info<< "adjointSensitivity type : " << sensType << endl;
auto* ctorPtr = dictionaryConstructorTable(modelType);
auto* ctorPtr = dictionaryConstructorTable(sensType);
if (!ctorPtr)
{
@ -86,7 +103,7 @@ autoPtr<adjointSensitivity> adjointSensitivity::New
(
dict,
"adjointSensitivity",
modelType,
sensType,
*dictionaryConstructorTablePtr_
) << exit(FatalIOError);
}
@ -100,9 +117,47 @@ autoPtr<adjointSensitivity> adjointSensitivity::New
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
const scalarField& adjointSensitivity::calculateSensitivities()
bool adjointSensitivity::readDict(const dictionary& dict)
{
assembleSensitivities();
if (sensitivity::readDict(dict))
{
// The adjoint eikonal solver requires the parameterized patches
// as an argument, if they exist. Allocation will be managed by
// derived classes that have access to them
includeDistance_ = this->dict().getOrDefault<bool>
(
"includeDistance",
adjointSolver_.includeDistance()
);
return true;
}
return false;
}
bool adjointSensitivity::computeDxDbInternalField() const
{
return false;
}
void adjointSensitivity::assembleSensitivities
(
autoPtr<designVariables>& designVars
)
{
derivatives_ = designVars->assembleSensitivities(*this);
}
const scalarField& adjointSensitivity::calculateSensitivities
(
autoPtr<designVariables>& designVars
)
{
assembleSensitivities(designVars);
write(type());
return derivatives_;
}
@ -116,10 +171,18 @@ const scalarField& adjointSensitivity::getSensitivities() const
void adjointSensitivity::clearSensitivities()
{
derivatives_ = scalar(0);
derivatives_ = Zero;
if (fieldSensPtr_)
{
fieldSensPtr_().primitiveFieldRef() = scalar(0);
fieldSensPtr_().primitiveFieldRef() = Zero;
}
if (eikonalSolver_)
{
eikonalSolver_->reset();
}
if (adjointMeshMovementSolver_)
{
adjointMeshMovementSolver_->reset();
}
}
@ -130,51 +193,8 @@ void adjointSensitivity::write(const word& baseName)
}
tmp<volTensorField> adjointSensitivity::computeGradDxDbMultiplier()
{
return adjointSolver_.computeGradDxDbMultiplier();
}
tmp<volVectorField> adjointSensitivity::adjointMeshMovementSource()
{
tmp<volTensorField> tgradDxDbMult = computeGradDxDbMultiplier();
volTensorField& gradDxDbMult = tgradDxDbMult.ref();
tmp<volVectorField> tadjointMeshMovementSource
(
new volVectorField
(
IOobject
(
"adjointMeshMovementSource",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector(gradDxDbMult.dimensions()/dimLength, Zero)
)
);
volVectorField& source = tadjointMeshMovementSource.ref();
source -= fvc::div(gradDxDbMult.T());
// Terms from fvOptions
fv::options::New(this->mesh_).postProcessSens
(
source.primitiveFieldRef(), adjointVars_.solverName()
);
return (tadjointMeshMovementSource);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -0,0 +1,299 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
Class
Foam::adjointSensitivity
Description
Abstract base class for adjoint-based sensitivities
SourceFiles
adjointSensitivity.C
\*---------------------------------------------------------------------------*/
#ifndef adjointSensitivityIncompressible_H
#define adjointSensitivityIncompressible_H
#include "boundaryFieldsFwd.H"
#include "adjointEikonalSolver.H"
#include "adjointMeshMovementSolver.H"
#include "sensitivity.H"
#include "volFieldsFwd.H"
#include "wallFvPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration
class adjointSolver;
/*---------------------------------------------------------------------------*\
Class adjointSensitivity Declaration
\*---------------------------------------------------------------------------*/
class adjointSensitivity
:
public sensitivity
{
protected:
// Protected data
//- Reference to the underlaying adjoint solver
adjointSolver& adjointSolver_;
//- The sensitivity derivative values
scalarField derivatives_;
//- Append this word to files related to the sensitivities
word suffix_;
//- Include distance variation in sensitivity computations
bool includeDistance_;
//- Adjoint eikonal equation solver
autoPtr<adjointEikonalSolver> eikonalSolver_;
//- Adjoint grid displacement solver
autoPtr<adjointMeshMovementSolver> adjointMeshMovementSolver_;
// Fields to accumulated through the adjoint solver
// Shape optimisation
//- Multiplier of grad(dx/b)
autoPtr<volTensorField> gradDxDbMult_;
//- Multiplier of div(dx/db)
autoPtr<scalarField> divDxDbMult_;
//- Multiplier of face dx/db
// The term that multiplies the adjoint-related part of the
// sensitivities in the (E)SI approach
autoPtr<boundaryVectorField> dxdbMult_;
//- Multiplier of dSf/db
autoPtr<boundaryVectorField> dSfdbMult_;
//- Multiplier of dnf/db
autoPtr<boundaryVectorField> dnfdbMult_;
//- Multiplier of dCf/db, found in the objective function
autoPtr<boundaryVectorField> dxdbDirectMult_;
//- Multiplier of dx/db computed at points,
//- found in the objective function
autoPtr<pointBoundaryVectorField> pointDxDbDirectMult_;
//- Multiplier of dx/db, coming from boundary conditions that
//- depend on the geometry, like rotatingWallVelocity
autoPtr<boundaryVectorField> bcDxDbMult_;
//- dx/db multiplier coming from fvOptions
autoPtr<vectorField> optionsDxDbMult_;
private:
// Private Member Functions
//- No copy construct
adjointSensitivity(const adjointSensitivity&) = delete;
//- No copy assignment
void operator=(const adjointSensitivity&) = delete;
public:
//- Runtime type information
TypeName("adjointSensitivity");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
adjointSensitivity,
dictionary,
(
const fvMesh& mesh,
const dictionary& dict,
adjointSolver& adjointSolver
),
(
mesh,
dict,
adjointSolver
)
);
// Constructors
//- Construct from components
adjointSensitivity
(
const fvMesh& mesh,
const dictionary& dict,
adjointSolver& adjointSolver
);
// Selectors
//- Return a reference to the selected turbulence model
static autoPtr<adjointSensitivity> New
(
const fvMesh& mesh,
const dictionary& dict,
adjointSolver& adjointSolver
);
//- Destructor
virtual ~adjointSensitivity() = default;
// Member Functions
//- Read dictionary if changed
virtual bool readDict(const dictionary& dict);
//- Const access to adjoint solver
inline const adjointSolver& getAdjointSolver() const
{
return adjointSolver_;
}
//- Non-const access to adjoint solver
inline adjointSolver& getAdjointSolver()
{
return adjointSolver_;
}
//- Should the adjoint eikonal PDE should be solved
inline bool includeDistance() const
{
return includeDistance_;
}
//- Return the adjoint eikonal solver
inline autoPtr<adjointEikonalSolver>& getAdjointEikonalSolver()
{
return eikonalSolver_;
}
//- Return the adjoint eikonal solver
inline autoPtr<adjointMeshMovementSolver>&
getAdjointMeshMovementSolver()
{
return adjointMeshMovementSolver_;
}
//- Set suffix
inline void setSuffix(const word& suffix)
{
suffix_ = suffix;
}
//- Get suffix
inline const word& getSuffix() const
{
return suffix_;
}
//- Should the parameterization compute the internalField of dxdb
virtual bool computeDxDbInternalField() const;
//- Accumulate sensitivity integrands
// Corresponds to the flow and adjoint part of the sensitivities
virtual void accumulateIntegrand(const scalar dt) = 0;
//- Assemble sensitivities
// Adds the geometric part of the sensitivities
virtual void assembleSensitivities
(
autoPtr<designVariables>& designVars
);
//- Calculates and returns sensitivity fields.
// Used with optimisation libraries
virtual const scalarField& calculateSensitivities
(
autoPtr<designVariables>& designVars
);
//- Returns the sensitivity fields
// Assumes it has already been updated/computed
const scalarField& getSensitivities() const;
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Write sensitivity fields.
// If valid, copies boundaryFields to volFields and writes them.
// Virtual to be reimplemented by control points-based methods
// (Bezier, RBF) which do not need to write fields
virtual void write(const word& baseName = word::null);
// Access functions to multipliers
// Shape optimisation
inline const autoPtr<volTensorField>& gradDxDbMult() const;
inline autoPtr<volTensorField>& gradDxDbMult();
inline const autoPtr<scalarField>& divDxDbMult() const;
inline const autoPtr<boundaryVectorField>& dxdbMult() const;
inline const autoPtr<boundaryVectorField>& dSfdbMult() const;
inline const autoPtr<boundaryVectorField>& dnfdbMult() const;
inline const autoPtr<boundaryVectorField>&
dxdbDirectMult() const;
inline const autoPtr<pointBoundaryVectorField>&
pointDxDbDirectMult() const;
inline const autoPtr<boundaryVectorField>& bcDxDbMult() const;
inline const autoPtr<vectorField>& optionsDxDbMult() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "adjointSensitivityI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 PCOpt/NTUA
Copyright (C) 2023 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 <Foam::http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline const Foam::autoPtr<Foam::volTensorField>&
Foam::adjointSensitivity::gradDxDbMult() const
{
return gradDxDbMult_;
}
inline Foam::autoPtr<Foam::volTensorField>&
Foam::adjointSensitivity::gradDxDbMult()
{
return gradDxDbMult_;
}
inline const Foam::autoPtr<Foam::scalarField>&
Foam::adjointSensitivity::divDxDbMult() const
{
return divDxDbMult_;
}
inline const Foam::autoPtr<Foam::boundaryVectorField>&
Foam::adjointSensitivity::dxdbMult() const
{
return dxdbMult_;
}
inline const Foam::autoPtr<Foam::boundaryVectorField>&
Foam::adjointSensitivity::dSfdbMult() const
{
return dSfdbMult_;
}
inline const Foam::autoPtr<Foam::boundaryVectorField>&
Foam::adjointSensitivity::dnfdbMult() const
{
return dnfdbMult_;
}
inline const Foam::autoPtr<Foam::boundaryVectorField>&
Foam::adjointSensitivity::dxdbDirectMult() const
{
return dxdbDirectMult_;
}
inline const Foam::autoPtr<Foam::pointBoundaryVectorField>&
Foam::adjointSensitivity::pointDxDbDirectMult() const
{
return pointDxDbDirectMult_;
}
inline const Foam::autoPtr<Foam::boundaryVectorField>&
Foam::adjointSensitivity::bcDxDbMult() const
{
return bcDxDbMult_;
}
inline const Foam::autoPtr<Foam::vectorField>&
Foam::adjointSensitivity::optionsDxDbMult() const
{
return optionsDxDbMult_;
}
// ************************************************************************* //

View File

@ -27,7 +27,8 @@ License
\*---------------------------------------------------------------------------*/
#include "sensitivityMultipleIncompressible.H"
#include "adjointSensitivity.H"
#include "sensitivityMultiple.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -35,9 +36,6 @@ License
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivityMultiple, 0);
@ -54,11 +52,11 @@ sensitivityMultiple::sensitivityMultiple
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
adjointSolver& adjointSolver
)
:
adjointSensitivity(mesh, dict, adjointSolver),
sensTypes_(dict.subDict("sensTypes").toc()),
sensTypes_(this->dict().get<wordList>("sensitivityTypes")),
sens_(sensTypes_.size())
{
forAll(sensTypes_, sI)
@ -69,10 +67,11 @@ sensitivityMultiple::sensitivityMultiple
adjointSensitivity::New
(
mesh,
dict.subDict("sensTypes").subDict(sensTypes_[sI]),
this->dict().subDict(sensTypes_[sI]),
adjointSolver
)
);
sens_[sI].setSuffix(sensTypes_[sI]);
}
}
@ -81,14 +80,11 @@ sensitivityMultiple::sensitivityMultiple
bool sensitivityMultiple::readDict(const dictionary& dict)
{
if (sensitivity::readDict(dict))
if (adjointSensitivity::readDict(dict))
{
forAll(sens_, sI)
{
sens_[sI].readDict
(
dict.subDict("sensTypes").subDict(sensTypes_[sI])
);
sens_[sI].readDict(dict.subDict(sensTypes_[sI]));
}
return true;
@ -107,21 +103,27 @@ void sensitivityMultiple::accumulateIntegrand(const scalar dt)
}
void sensitivityMultiple::assembleSensitivities()
void sensitivityMultiple::assembleSensitivities
(
autoPtr<designVariables>& designVars
)
{
forAll(sens_, sI)
{
sens_[sI].assembleSensitivities();
sens_[sI].assembleSensitivities(designVars);
}
}
const scalarField& sensitivityMultiple::calculateSensitivities()
const scalarField& sensitivityMultiple::calculateSensitivities
(
autoPtr<designVariables>& designVars
)
{
forAll(sens_, sI)
{
Info<< "Computing sensitivities " << sensTypes_[sI] << endl;
derivatives_ = sens_[sI].calculateSensitivities();
sens_[sI].calculateSensitivities(designVars);
}
write(type());
@ -149,7 +151,6 @@ void sensitivityMultiple::write(const word& baseName)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -26,7 +26,7 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::sensitivityMultiple
Foam::sensitivityMultiple
Description
Calculation of adjoint based sensitivities of multiple types
@ -36,19 +36,16 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef sensitivityMultipleIncompressible_H
#define sensitivityMultipleIncompressible_H
#ifndef sensitivityMultiple_H
#define sensitivityMultiple_H
#include "adjointSensitivityIncompressible.H"
#include "adjointSensitivity.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class sensitivityMultiple Declaration
\*---------------------------------------------------------------------------*/
@ -90,7 +87,7 @@ public:
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
adjointSolver& adjointSolver
);
@ -107,10 +104,13 @@ public:
virtual void accumulateIntegrand(const scalar dt);
//- Assemble sensitivities
virtual void assembleSensitivities();
virtual void assembleSensitivities(autoPtr<designVariables>& designVars);
//- Calculates sensitivities at wall surface points
const scalarField& calculateSensitivities();
const scalarField& calculateSensitivities
(
autoPtr<designVariables>& designVars
);
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
@ -122,7 +122,6 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -0,0 +1,168 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-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
ESITNESS 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "boundaryFieldsFwd.H"
#include "sensitivityShapeESI.H"
#include "adjointSolver.H"
#include "ShapeSensitivitiesBase.H"
#include "fvOptions.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivityShapeESI, 0);
addToRunTimeSelectionTable
(
adjointSensitivity, sensitivityShapeESI, dictionary
);
void sensitivityShapeESI::computeDxDbMult()
{
if (eikonalSolver_)
{
eikonalSolver_->solve();
}
if (adjointMeshMovementSolver_)
{
adjointMeshMovementSolver_->solve();
boundaryVectorField& meshMovementSens =
adjointMeshMovementSolver_->meshMovementSensitivities();
PtrList<objective>& functions =
adjointSolver_.getObjectiveManager().getObjectiveFunctions();
for (const label patchI : geometryVariationIntegrationPatches())
{
const fvPatch& patch = mesh_.boundary()[patchI];
const scalarField& magSf = patch.magSf();
const vectorField& Sf = patch.Sf();
dxdbMult_()[patchI] = meshMovementSens[patchI]*magSf;
for (objective& func : functions)
{
if (func.hasDivDxDbMult())
{
Info<< func.objectiveName() << " " << patch.name() << endl;
dxdbDirectMult_()[patchI] +=
func.weight()
*func.divDxDbMultiplier().boundaryField()[patchI]
*Sf;
}
}
}
}
for (const label patchI : geometryVariationIntegrationPatches())
{
const vectorField& Sf = mesh_.boundary()[patchI].Sf();
dxdbMult_()[patchI] += Sf & gradDxDbMult_().boundaryField()[patchI];
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivityShapeESI::sensitivityShapeESI
(
const fvMesh& mesh,
const dictionary& dict,
adjointSolver& adjointSolver
)
:
ShapeSensitivitiesBase(mesh, dict, adjointSolver)
{
dxdbMult_.reset(createZeroBoundaryPtr<vector>(mesh_));
// The boundary values of divDxDbMultiplier are stored in dxdbDirectMult
// after applying the Gauss divergence theorem.
// Allocate dxdbDirectMult if necessary
if (hasMultiplier(&objective::hasDivDxDbMult))
{
dxdbDirectMult_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
if (dict.getOrDefault<bool>("includeMeshMovement", true))
{
adjointMeshMovementSolver_.reset
(
new adjointMeshMovementSolver(mesh, dict, *this)
);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::sensitivityShapeESI::readDict(const dictionary& dict)
{
if (ShapeSensitivitiesBase::readDict(dict))
{
bool includeMeshMovement =
dict.getOrDefault<bool>("includeMeshMovement", true);
if (includeMeshMovement)
{
if (adjointMeshMovementSolver_)
{
adjointMeshMovementSolver_->readDict(dict);
}
else
{
adjointMeshMovementSolver_.reset
(
new adjointMeshMovementSolver(mesh_, dict, *this)
);
}
}
return true;
}
return false;
}
void sensitivityShapeESI::assembleSensitivities
(
autoPtr<designVariables>& designVars
)
{
computeDxDbMult();
if (designVars)
{
adjointSensitivity::assembleSensitivities(designVars);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -19,29 +19,30 @@ License
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
ESITNESS 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 <http://www.gnu.org/licenses/>.
Class
Foam::optMeshMovementBezier
Foam::sensitivityShapeESI
Description
Converts NURBS control points update to actual mesh movement
Class for computing sensitivity derivatives using the Enhanced Surface
Integral (E-SI) formulation, when a parameterization scheme is inluded
through the design variables. Sensitivity maps are implemented in class
sensitivitySurfacePoints
SourceFiles
optMeshMovementBezier.C
sensitivityShapeESI.C
\*---------------------------------------------------------------------------*/
#ifndef optMeshMovementBezier_H
#define optMeshMovementBezier_H
#ifndef sensitivityShapeESI_H
#define sensitivityShapeESI_H
#include "optMeshMovement.H"
#include "Bezier.H"
#include "ShapeSensitivitiesBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -49,30 +50,19 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class optMeshMovementBezier Declaration
Class sensitivityShapeESI Declaration
\*---------------------------------------------------------------------------*/
class optMeshMovementBezier
class sensitivityShapeESI
:
public optMeshMovement
public ShapeSensitivitiesBase
{
protected:
// Protected data
//- Parameterization based on NURBS curves
Bezier Bezier_;
//- Boundary movement due to change of NURBS control points
pointVectorField dx_;
//- Cumulative change of control points
vectorField cumulativeChange_;
// Protected Member Functions
void computeBoundaryMovement(const scalarField& correction);
//- Compute dxdbMult from its various components
void computeDxDbMult();
private:
@ -80,43 +70,45 @@ private:
// Private Member Functions
//- No copy construct
optMeshMovementBezier(const optMeshMovementBezier&) = delete;
sensitivityShapeESI(const sensitivityShapeESI&) = delete;
//- No copy assignment
void operator=(const optMeshMovementBezier&) = delete;
void operator=(const sensitivityShapeESI&) = delete;
public:
//- Runtime type information
TypeName("Bezier");
TypeName("shapeESI");
// Constructors
//- Construct from components
optMeshMovementBezier
sensitivityShapeESI
(
fvMesh& mesh,
const fvMesh& mesh,
const dictionary& dict,
const labelList& patchIDs
adjointSolver& adjointSolver
);
//- Destructor
virtual ~optMeshMovementBezier() = default;
virtual ~sensitivityShapeESI() = default;
// Member Functions
//- Calculates surface mesh movement
void moveMesh();
//- Read dict if changed
virtual bool readDict(const dictionary& dict);
//- Compute eta value based on max displacement
virtual scalar computeEta(const scalarField& correction);
//- Return active design variables
virtual labelList getActiveDesignVariables() const;
//- Assemble sensitivities
// Solve the adjoint eikonal PDE and the adjoint grid displacement PDE,
// if needed, and assemble the sensitivities
virtual void assembleSensitivities
(
autoPtr<designVariables>& designVars
);
};

View File

@ -0,0 +1,88 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "adjointSensitivity.H"
#include "sensitivityShapeFI.H"
#include "adjointSolver.H"
#include "fvOptions.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivityShapeFI, 0);
addToRunTimeSelectionTable
(
adjointSensitivity, sensitivityShapeFI, dictionary
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivityShapeFI::sensitivityShapeFI
(
const fvMesh& mesh,
const dictionary& dict,
adjointSolver& adjointSolver
)
:
ShapeSensitivitiesBase(mesh, dict, adjointSolver)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool sensitivityShapeFI::computeDxDbInternalField() const
{
return true;
}
void sensitivityShapeFI::assembleSensitivities
(
autoPtr<designVariables>& designVars
)
{
if (eikonalSolver_)
{
eikonalSolver_->solve();
}
adjointSensitivity::assembleSensitivities(designVars);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -26,73 +26,79 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::optMeshMovementNULL
Foam::sensitivityShapeFI
Description
A dummy optMeshMovement object
Class for computing Field Integral (FI)-based sensitivity derivatives
SourceFiles
optMeshMovementNULL.C
sensitivityShapeFI.C
\*---------------------------------------------------------------------------*/
#ifndef optMeshMovementNULL_H
#define optMeshMovementNULL_H
#ifndef sensitivityShapeFI_H
#define sensitivityShapeFI_H
#include "optMeshMovement.H"
#include "ShapeSensitivitiesBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class optMeshMovementNULL Declaration
Class sensitivityShapeFI Declaration
\*---------------------------------------------------------------------------*/
class optMeshMovementNULL
class sensitivityShapeFI
:
public optMeshMovement
public ShapeSensitivitiesBase
{
private:
// Private Member Functions
//- No copy construct
optMeshMovementNULL(const optMeshMovementNULL&) = delete;
sensitivityShapeFI(const sensitivityShapeFI&) = delete;
//- No copy assignment
void operator=(const optMeshMovementNULL&) = delete;
void operator=(const sensitivityShapeFI&) = delete;
public:
//- Runtime type information
TypeName("none");
TypeName("shapeFI");
// Constructors
//- Construct from components
optMeshMovementNULL
sensitivityShapeFI
(
fvMesh& mesh,
const fvMesh& mesh,
const dictionary& dict,
const labelList& patchIDs
adjointSolver& adjointSolver
);
//- Destructor
virtual ~optMeshMovementNULL() = default;
virtual ~sensitivityShapeFI() = default;
// Member Functions
//- Calculates surface mesh movement
void moveMesh();
//- Should the parameterization compute the internalField of dxdb
virtual bool computeDxDbInternalField() const;
//- Compute eta value based on max displacement
virtual scalar computeEta(const scalarField& correction);
//- Assemble sensitivities
// Solve the adjoint eikonal PDE, if needed, and calls the assembles
// the sensitivities
virtual void assembleSensitivities
(
autoPtr<designVariables>& designVars
);
};

View File

@ -5,9 +5,9 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2022 PCOpt/NTUA
Copyright (C) 2013-2022 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,133 +27,145 @@ License
\*---------------------------------------------------------------------------*/
#include "adjointMeshMovementSolverIncompressible.H"
#include "incompressibleAdjointSolver.H"
#include "fixedValueFvPatchFields.H"
#include "subCycleTime.H"
#include "adjointMeshMovementSolver.H"
#include "adjointEikonalSolver.H"
#include "adjointSolver.H"
#include "fvc.H"
#include "fvm.H"
#include "ShapeSensitivitiesBase.H"
#include "reverseLinear.H"
#include "volFieldsFwd.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(adjointMeshMovementSolver, 0);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
// * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
void adjointMeshMovementSolver::read()
{
nLaplaceIters_ = dict_.getOrDefault<label>("iters", 1000);
tolerance_ = dict_.getOrDefault<scalar>("tolerance", 1e-6);
iters_ = dict_.getOrDefault<label>("iters", 1000);
tolerance_ = dict_.getOrDefault<scalar>("tolerance", 1.e-06);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
void adjointMeshMovementSolver::setSource()
{
volTensorField& gradDxDbMult = adjointSensitivity_.gradDxDbMult()();
// Add part related to the adjoint eikaonal equation, if necessary
const autoPtr<adjointEikonalSolver>& eikonalSolver =
adjointSensitivity_.getAdjointEikonalSolver();
if (eikonalSolver)
{
gradDxDbMult += eikonalSolver->getFISensitivityTerm();
}
source_ -=
fvc::div
(
mesh_.Sf()
& reverseLinear<tensor>(mesh_).interpolate(gradDxDbMult)
);
// Terms from objectives defined in (part of the) internal field
PtrList<objective>& functions =
adjointSensitivity_.getAdjointSolver().getObjectiveManager().
getObjectiveFunctions();
for (objective& func : functions)
{
if (func.hasDivDxDbMult())
{
source_ -= func.weight()*fvc::grad(func.divDxDbMultiplier());
}
}
// Terms from fvOptions
source_.primitiveFieldRef() += adjointSensitivity_.optionsDxDbMult()();
}
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
adjointMeshMovementSolver::adjointMeshMovementSolver
(
const fvMesh& mesh,
const dictionary& dict,
Foam::incompressible::adjointSensitivity& adjointSensitivity,
const labelHashSet& sensitivityPatchIDs,
const autoPtr<adjointEikonalSolver>& adjointEikonalSolverPtr
ShapeSensitivitiesBase& adjointSensitivity
)
:
mesh_(mesh),
dict_(dict.subOrEmptyDict("adjointMeshMovementSolver")),
meshMovementSensPtr_(createZeroBoundaryPtr<vector>(mesh)),
adjointSensitivity_(adjointSensitivity),
sensitivityPatchIDs_(sensitivityPatchIDs),
nLaplaceIters_(-1),
tolerance_(-1),
ma_
(
IOobject
variablesSet::autoCreateMeshMovementField
(
word
(
adjointSensitivity.adjointVars().useSolverNameForFields()
? "ma" + adjointSensitivity.adjointSolver().solverName()
: "ma"
),
mesh.time().timeName(),
mesh,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
mesh,
dimensionedVector(pow3(dimLength/dimTime), Zero),
fixedValueFvPatchVectorField::typeName
mesh_,
adjointSensitivity.getAdjointSolver().useSolverNameForFields()
? ("ma" + adjointSensitivity.getAdjointSolver().solverName())
: "ma",
adjointSensitivity.getAdjointSolver().maDimensions()
)
),
source_
(
IOobject
(
"sourceAdjointMeshMovement",
"sourceadjointMeshMovement",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector(dimLength/pow3(dimTime), Zero)
dimensionedVector
(
adjointSensitivity.getAdjointSolver().maDimensions()/sqr(dimLength),
Zero
)
),
meshMovementSensPtr_(createZeroBoundaryPtr<vector>(mesh_)),
adjointEikonalSolverPtr_(adjointEikonalSolverPtr)
iters_(0),
tolerance_(Zero)
{
read();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool adjointMeshMovementSolver::readDict(const dictionary& dict)
bool adjointMeshMovementSolver::readDict
(
const dictionary& dict
)
{
dict_ = dict.subOrEmptyDict("adjointMeshMovementSolver");
read();
return true;
}
void adjointMeshMovementSolver::accumulateIntegrand(const scalar dt)
{
// Accumulate integrand from the current time step
source_ += adjointSensitivity_.adjointMeshMovementSource()*dt;
// Part of the source depending on the adjoint distance can be added only
// after solving the adjoint eikonal equation. Added in solve()
}
void adjointMeshMovementSolver::solve()
{
read();
// Add source from the adjoint eikonal equation
if (adjointEikonalSolverPtr_)
{
source_ -=
fvc::div(adjointEikonalSolverPtr_().getFISensitivityTerm()().T());
}
setSource();
// Iterate the adjoint to the mesh movement equation
for (label iter = 0; iter < nLaplaceIters_; iter++)
for (label iter = 0; iter < iters_; iter++)
{
Info<< "Adjoint Mesh Movement Iteration: " << iter << endl;
Info<< "adjoint Mesh Movement Iteration: " << iter << endl;
fvVectorMatrix maEqn
(
fvm::laplacian(ma_)
+ source_
fvm::laplacian(ma_) + source_
);
maEqn.boundaryManipulate(ma_.boundaryFieldRef());
//scalar residual = max(maEqn.solve().initialResidual());
scalar residual =
mag(Foam::solve(maEqn, mesh_.solverDict("ma")).initialResidual());
@ -176,19 +188,22 @@ void adjointMeshMovementSolver::solve()
void adjointMeshMovementSolver::reset()
{
source_ == dimensionedVector(source_.dimensions(), Zero);
meshMovementSensPtr_() = vector::zero;
meshMovementSensPtr_() = Zero;
}
boundaryVectorField& adjointMeshMovementSolver::meshMovementSensitivities()
{
Info<< "Calculating mesh movement sensitivities " << endl;
boundaryVectorField& meshMovementSens = meshMovementSensPtr_();
for (const label patchi : sensitivityPatchIDs_)
for
(
const label patchi
: adjointSensitivity_.geometryVariationIntegrationPatches()
)
{
// No surface area included. Will be done by the actual sensitivity tool
// No surface area included.
// Will be added during the assembly of the sensitivities
meshMovementSens[patchi] = -ma_.boundaryField()[patchi].snGrad();
}
@ -196,15 +211,8 @@ boundaryVectorField& adjointMeshMovementSolver::meshMovementSensitivities()
}
const volVectorField& adjointMeshMovementSolver::ma()
{
return ma_;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -25,20 +25,23 @@ License
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::adjointMeshMovementSolver
Foam::adjointMeshMovementSolver
Description
Solver of the adjoint to the Laplace grid displacement equation
Class solving the adjoint grid dispalcement PDEs.
Assumes the primal grid displacement PDE is a Laplace one with uniform
diffusivity.
Reference:
\verbatim
For the derivation of the adjoint grid displacement PDEs, see
Kavvadias, I., Papoutsis-Kiachagias, E., & Giannakoglou, K. (2015).
On the proper treatment of grid sensitivities in continuous adjoint
methods for shape optimization.
Journal of Computational Physics, 301, 118.
http://doi.org/10.1016/j.jcp.2015.08.012
\endverbatim
SourceFiles
@ -46,48 +49,63 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef adjointMeshMovementSolverIncompressible_H
#define adjointMeshMovementSolverIncompressible_H
#ifndef adjointMeshMovementSolver_H
#define adjointMeshMovementSolver_H
#include "adjointSensitivityIncompressible.H"
#include "adjointEikonalSolverIncompressible.H"
#include "createZeroField.H"
#include "boundaryFieldsFwd.H"
#include "createZeroField.H"
#include "variablesSet.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// Forward declarations
class ShapeSensitivitiesBase;
/*---------------------------------------------------------------------------*\
Class adjointMeshMovementSolver Declaration
Class adjointMeshMovementSolver Decleration
\*---------------------------------------------------------------------------*/
class adjointMeshMovementSolver
{
protected:
// Protected data
// Protected Data Members
//- Reference to mesh
const fvMesh& mesh_;
//- Dictionary containing solution controls
dictionary dict_;
Foam::incompressible::adjointSensitivity& adjointSensitivity_;
const labelHashSet& sensitivityPatchIDs_;
label nLaplaceIters_;
scalar tolerance_;
//- Part of sensitivity derivatives coming from the adjoint grid
//- displacement PDE
autoPtr<boundaryVectorField> meshMovementSensPtr_;
// Underlaying adjoint sensitivities
ShapeSensitivitiesBase& adjointSensitivity_;
//- Adjoint grid displacement field
volVectorField ma_;
//- Source term of the adjoint grid displacement PDEs
volVectorField source_;
//- Wall face sens w.r.t.(x, y.z) //wall face sens w.r.t. (x,y.z)
autoPtr<boundaryVectorField> meshMovementSensPtr_;
const autoPtr<adjointEikonalSolver>& adjointEikonalSolverPtr_;
//- Solution controls
label iters_;
scalar tolerance_;
// Protected Member Functions
//- Read options each time a new solution is found
void read();
//- Set the source term of the PDE
void setSource();
private:
@ -97,7 +115,7 @@ private:
adjointMeshMovementSolver(const adjointMeshMovementSolver&) = delete;
//- No copy assignment
void operator=(const adjointMeshMovementSolver&) = delete;
void operator=( const adjointMeshMovementSolver) = delete;
public:
@ -113,12 +131,11 @@ public:
(
const fvMesh& mesh,
const dictionary& dict,
Foam::incompressible::adjointSensitivity& adjointSensitivity,
const labelHashSet& sensitivityPatchIDs,
const autoPtr<adjointEikonalSolver>& adjointEikonalSolverPtr
ShapeSensitivitiesBase& adjointSensitivity
);
//- Destructor
// Destructor
virtual ~adjointMeshMovementSolver() = default;
@ -127,30 +144,31 @@ public:
//- Read dict if changed
virtual bool readDict(const dictionary& dict);
//- Accumulate source term
void accumulateIntegrand(const scalar dt);
//- Calculate the adjoint distance field
void solve();
virtual void solve();
//- Reset source term
//- Reset the source term
void reset();
//- Return the sensitivity term depending on da
//- Return the sensitivity term depending on ma
boundaryVectorField& meshMovementSensitivities();
//- Return the adjoint distance field
const volVectorField& ma();
inline const volVectorField& ma() const
{
return ma_;
}
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -27,20 +27,58 @@ License
\*---------------------------------------------------------------------------*/
#include "shapeSensitivitiesBase.H"
#include "HashSet.H"
#include "ShapeSensitivitiesBase.H"
#include "adjointSensitivity.H"
#include "adjointSolver.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(shapeSensitivitiesBase, 0);
defineTypeNameAndDebug(ShapeSensitivitiesBase, 0);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::shapeSensitivitiesBase::writeFaceBasedSens() const
void Foam::ShapeSensitivitiesBase::allocateEikonalSolver()
{
// Allocate distance solver if needed
if (includeDistance_ && !eikonalSolver_)
{
eikonalSolver_.reset
(
new adjointEikonalSolver
(
mesh_,
this->dict(),
adjointSolver_,
geometryVariationIntegrationPatches()
)
);
}
}
bool Foam::ShapeSensitivitiesBase::hasMultiplier
(
bool (objective::*hasFunction)() const
)
{
bool hasMult(false);
const PtrList<objective>& objectives =
adjointSolver_.getObjectiveManager().getObjectiveFunctions();
for (const objective& func : objectives)
{
hasMult = hasMult || (func.*hasFunction)();
}
return hasMult;
}
void Foam::ShapeSensitivitiesBase::writeFaceBasedSens() const
{
// Wall face sensitivity projected to normal
if (wallFaceSensNormalPtr_)
@ -48,7 +86,7 @@ void Foam::shapeSensitivitiesBase::writeFaceBasedSens() const
constructAndWriteSensitivityField<scalar>
(
wallFaceSensNormalPtr_,
"faceSensNormal" + surfaceFieldSuffix_
"faceSensNormal" + suffix_
);
}
@ -60,7 +98,7 @@ void Foam::shapeSensitivitiesBase::writeFaceBasedSens() const
constructAndWriteSensitivityField<vector>
(
wallFaceSensVecPtr_,
"faceSensVec" + surfaceFieldSuffix_
"faceSensVec" + suffix_
);
}
@ -70,14 +108,14 @@ void Foam::shapeSensitivitiesBase::writeFaceBasedSens() const
constructAndWriteSensitivityField<vector>
(
wallFaceSensNormalVecPtr_,
"faceSensNormalVec" + surfaceFieldSuffix_
"faceSensNormalVec" + suffix_
);
}
}
}
void Foam::shapeSensitivitiesBase::writePointBasedSens() const
void Foam::ShapeSensitivitiesBase::writePointBasedSens() const
{
// Wall point sensitivity projected to normal
if (wallPointSensNormalPtr_)
@ -85,7 +123,7 @@ void Foam::shapeSensitivitiesBase::writePointBasedSens() const
constructAndWriteSensitivtyPointField<scalar>
(
wallPointSensNormalPtr_,
"pointSensNormal" + surfaceFieldSuffix_
"pointSensNormal" + suffix_
);
}
@ -100,7 +138,7 @@ void Foam::shapeSensitivitiesBase::writePointBasedSens() const
constructAndWriteSensitivtyPointField<vector>
(
wallPointSensVecPtr_,
"pointSensVec" + surfaceFieldSuffix_
"pointSensVec" + suffix_
);
}
@ -110,69 +148,14 @@ void Foam::shapeSensitivitiesBase::writePointBasedSens() const
constructAndWriteSensitivtyPointField<vector>
(
wallPointSensNormalVecPtr_,
"pointSensNormalVec" + surfaceFieldSuffix_
"pointSensNormalVec" + suffix_
);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::shapeSensitivitiesBase::shapeSensitivitiesBase
(
const fvMesh& mesh,
const dictionary& dict
)
:
meshShape_(mesh),
surfaceFieldSuffix_(),
writeAllSurfaceFiles_
(
dict.getOrDefault<bool>
(
"writeAllSurfaceFiles",
false
)
),
sensitivityPatchIDs_
(
mesh.boundaryMesh().patchSet
(
dict.get<wordRes>("patches", keyType::REGEX_RECURSIVE)
)
),
wallFaceSensVecPtr_(nullptr),
wallFaceSensNormalPtr_(nullptr),
wallFaceSensNormalVecPtr_(nullptr),
wallPointSensVecPtr_(nullptr),
wallPointSensNormalPtr_(nullptr),
wallPointSensNormalVecPtr_(nullptr)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
const Foam::labelHashSet&
Foam::shapeSensitivitiesBase::sensitivityPatchIDs() const
{
return sensitivityPatchIDs_;
}
void Foam::shapeSensitivitiesBase::setSensitivityPatchIDs
(
const labelHashSet& sensPatchIDs
)
{
sensitivityPatchIDs_ = sensPatchIDs;
}
void Foam::shapeSensitivitiesBase::clearSensitivities()
void Foam::ShapeSensitivitiesBase::clearSurfaceFields()
{
// Face-based boundary sens
if (wallFaceSensVecPtr_)
@ -213,21 +196,212 @@ void Foam::shapeSensitivitiesBase::clearSensitivities()
}
void Foam::shapeSensitivitiesBase::write()
void Foam::ShapeSensitivitiesBase::allocateMultipliers()
{
gradDxDbMult_.reset
(
new volTensorField
(
IOobject
(
"gradDxDbMult",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero)
)
);
if (hasMultiplier(&objective::hasDivDxDbMult))
{
divDxDbMult_.reset(new scalarField(mesh_.nCells(), Zero));
}
if (hasMultiplier(&objective::hasdSdbMult))
{
dSfdbMult_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
if (hasMultiplier(&objective::hasdndbMult))
{
dnfdbMult_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
if (hasMultiplier(&objective::hasdxdbDirectMult))
{
dxdbDirectMult_.reset(createZeroBoundaryPtr<vector>(mesh_));
}
bcDxDbMult_.reset(createZeroBoundaryPtr<vector>(mesh_));
optionsDxDbMult_.reset(new vectorField(mesh_.nCells(), Zero));
}
void Foam::ShapeSensitivitiesBase::clearMultipliers()
{
gradDxDbMult_() = dimensionedTensor(gradDxDbMult_().dimensions(), Zero);
if (divDxDbMult_)
{
divDxDbMult_() = Zero;
}
if (eikonalSolver_)
{
eikonalSolver_->reset();
}
if (dxdbMult_)
{
dxdbMult_() = Zero;
}
if (dSfdbMult_)
{
dSfdbMult_() = Zero;
}
if (dnfdbMult_)
{
dnfdbMult_() = Zero;
}
if (dxdbDirectMult_)
{
dxdbDirectMult_() = Zero;
}
if (pointDxDbDirectMult_)
{
for (vectorField& field : pointDxDbDirectMult_())
{
field = Zero;
}
}
bcDxDbMult_() = Zero;
optionsDxDbMult_() = Zero;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::ShapeSensitivitiesBase::ShapeSensitivitiesBase
(
const fvMesh& mesh,
const dictionary& dict,
class adjointSolver& adjointSolver
)
:
adjointSensitivity(mesh, dict, adjointSolver),
sensitivityPatchIDs_
(
mesh.boundaryMesh().patchSet
(
dict.optionalSubDict(mesh.name()).
get<wordRes>("patches", keyType::REGEX_RECURSIVE)
)
),
writeAllSurfaceFiles_
(
dict.getOrDefault<bool>("writeAllSurfaceFiles", false)
),
wallFaceSensVecPtr_(nullptr),
wallFaceSensNormalPtr_(nullptr),
wallFaceSensNormalVecPtr_(nullptr),
wallPointSensVecPtr_(nullptr),
wallPointSensNormalPtr_(nullptr),
wallPointSensNormalVecPtr_(nullptr)
{
allocateEikonalSolver();
allocateMultipliers();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::ShapeSensitivitiesBase::readDict(const dictionary& dict)
{
if (adjointSensitivity::readDict(dict))
{
sensitivityPatchIDs_ =
mesh_.boundaryMesh().patchSet
(
dict_.optionalSubDict(mesh_.name()).
get<wordRes>("patches", keyType::REGEX_RECURSIVE)
);
writeAllSurfaceFiles_ =
dict_.getOrDefault<bool>("writeAllSurfaceFiles", false);
if (includeDistance_)
{
if (eikonalSolver_)
{
eikonalSolver_().readDict(dict);
}
else
{
allocateEikonalSolver();
}
}
return true;
}
return false;
}
const Foam::labelHashSet&
Foam::ShapeSensitivitiesBase::geometryVariationIntegrationPatches() const
{
return sensitivityPatchIDs_;
}
void Foam::ShapeSensitivitiesBase::accumulateIntegrand(const scalar dt)
{
// Accumulate multiplier of grad(dxdb)
adjointSolver_.accumulateGradDxDbMultiplier(gradDxDbMult_(), dt);
// Accumulate multiplier of div(dxdb)
adjointSolver_.accumulateDivDxDbMultiplier(divDxDbMult_, dt);
// Terms from fvOptions - missing contributions from turbulence models
adjointSolver_.accumulateOptionsDxDbMultiplier(optionsDxDbMult_(), dt);
// Accumulate source for the adjoint to the eikonal equation
if (eikonalSolver_)
{
eikonalSolver_->accumulateIntegrand(dt);
}
// Accumulate direct sensitivities
adjointSolver_.accumulateGeometryVariationsMultipliers
(
dSfdbMult_,
dnfdbMult_,
dxdbDirectMult_,
pointDxDbDirectMult_,
geometryVariationIntegrationPatches(),
dt
);
// Accumulate sensitivities due to boundary conditions
adjointSolver_.accumulateBCSensitivityIntegrand
(bcDxDbMult_, geometryVariationIntegrationPatches(), dt);
}
void Foam::ShapeSensitivitiesBase::clearSensitivities()
{
adjointSensitivity::clearSensitivities();
clearSurfaceFields();
clearMultipliers();
}
void Foam::ShapeSensitivitiesBase::write(const word& baseName)
{
adjointSensitivity::write(baseName);
writeFaceBasedSens();
writePointBasedSens();
}
void Foam::shapeSensitivitiesBase::setSuffix(const word& suffix)
{
surfaceFieldSuffix_ = suffix;
}
Foam::tmp<Foam::volVectorField>
Foam::shapeSensitivitiesBase::getWallFaceSensVec()
Foam::ShapeSensitivitiesBase::getWallFaceSensVec()
{
if (wallFaceSensVecPtr_)
{
@ -235,7 +409,7 @@ Foam::shapeSensitivitiesBase::getWallFaceSensVec()
constructVolSensitivtyField<vector>
(
wallFaceSensVecPtr_,
"faceSensVec" + surfaceFieldSuffix_
"faceSensVec" + suffix_
);
}
else
@ -248,8 +422,8 @@ Foam::shapeSensitivitiesBase::getWallFaceSensVec()
(
createZeroFieldPtr<vector>
(
meshShape_,
"faceSensVec" + surfaceFieldSuffix_,
mesh_,
"faceSensVec" + suffix_,
dimless
).ptr()
);
@ -258,7 +432,7 @@ Foam::shapeSensitivitiesBase::getWallFaceSensVec()
Foam::tmp<Foam::volScalarField>
Foam::shapeSensitivitiesBase::getWallFaceSensNormal()
Foam::ShapeSensitivitiesBase::getWallFaceSensNormal()
{
if (wallFaceSensNormalPtr_)
{
@ -266,7 +440,7 @@ Foam::shapeSensitivitiesBase::getWallFaceSensNormal()
constructVolSensitivtyField<scalar>
(
wallFaceSensNormalPtr_,
"faceSensNormal" + surfaceFieldSuffix_
"faceSensNormal" + suffix_
);
}
else
@ -279,8 +453,8 @@ Foam::shapeSensitivitiesBase::getWallFaceSensNormal()
(
createZeroFieldPtr<scalar>
(
meshShape_,
"faceSensNormal" + surfaceFieldSuffix_, dimless
mesh_,
"faceSensNormal" + suffix_, dimless
).ptr()
);
}
@ -288,7 +462,7 @@ Foam::shapeSensitivitiesBase::getWallFaceSensNormal()
Foam::tmp<Foam::volVectorField>
Foam::shapeSensitivitiesBase::getWallFaceSensNormalVec()
Foam::ShapeSensitivitiesBase::getWallFaceSensNormalVec()
{
if (wallFaceSensNormalVecPtr_)
{
@ -296,7 +470,7 @@ Foam::shapeSensitivitiesBase::getWallFaceSensNormalVec()
constructVolSensitivtyField<vector>
(
wallFaceSensNormalVecPtr_,
"faceSensNormalVec" + surfaceFieldSuffix_
"faceSensNormalVec" + suffix_
);
}
else
@ -310,8 +484,8 @@ Foam::shapeSensitivitiesBase::getWallFaceSensNormalVec()
(
createZeroFieldPtr<vector>
(
meshShape_,
"faceSensNormalVec" + surfaceFieldSuffix_,
mesh_,
"faceSensNormalVec" + suffix_,
dimless
).ptr()
);
@ -320,51 +494,51 @@ Foam::shapeSensitivitiesBase::getWallFaceSensNormalVec()
Foam::tmp<Foam::pointVectorField>
Foam::shapeSensitivitiesBase::getWallPointSensVec()
Foam::ShapeSensitivitiesBase::getWallPointSensVec()
{
tmp<volVectorField> tWallFaceSensVec = getWallFaceSensVec();
volPointInterpolation volPointInter(meshShape_);
volPointInterpolation volPointInter(mesh_);
return (volPointInter.interpolate(tWallFaceSensVec));
}
Foam::tmp<Foam::pointScalarField>
Foam::shapeSensitivitiesBase::getWallPointSensNormal()
Foam::ShapeSensitivitiesBase::getWallPointSensNormal()
{
tmp<volScalarField> tWallFaceSensNormal = getWallFaceSensNormal();
volPointInterpolation volPointInter(meshShape_);
volPointInterpolation volPointInter(mesh_);
return (volPointInter.interpolate(tWallFaceSensNormal));
}
Foam::tmp<Foam::pointVectorField>
Foam::shapeSensitivitiesBase::getWallPointSensNormalVec()
Foam::ShapeSensitivitiesBase::getWallPointSensNormalVec()
{
tmp<volVectorField> tWallFaceSensNormalVec = getWallFaceSensNormalVec();
volPointInterpolation volPointInter(meshShape_);
volPointInterpolation volPointInter(mesh_);
return (volPointInter.interpolate(tWallFaceSensNormalVec));
}
const Foam::boundaryVectorField&
Foam::shapeSensitivitiesBase::getWallFaceSensVecBoundary() const
Foam::ShapeSensitivitiesBase::getWallFaceSensVecBoundary() const
{
return wallFaceSensVecPtr_();
}
const Foam::boundaryScalarField&
Foam::shapeSensitivitiesBase::getWallFaceSensNormalBoundary() const
Foam::ShapeSensitivitiesBase::getWallFaceSensNormalBoundary() const
{
return wallFaceSensNormalPtr_();
}
const Foam::boundaryVectorField&
Foam::shapeSensitivitiesBase::getWallFaceSensNormalVecBoundary() const
Foam::ShapeSensitivitiesBase::getWallFaceSensNormalVecBoundary() const
{
return wallFaceSensNormalVecPtr_();
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -26,24 +26,40 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::shapeSensitivitiesBase
Foam::ShapeSensitivitiesBase
Description
Base class supporting shape sensitivity derivatives
Base class supporting Shape sensitivity derivatives.
Reference:
\verbatim
For the FI formulation see
Kavvadias, I., Papoutsis-Kiachagias, E., & Giannakoglou, K. (2015).
On the proper treatment of grid sensitivities in continuous adjoint
methods for shape optimization.
Journal of Computational Physics, 301, 118.
http://doi.org/10.1016/j.jcp.2015.08.012
The ESI formulation is derived in a slightly different way than the
one described in this paper, to provide a common mathematical
formulation for both low- and high-Re meshes and to produce numerically
identical results as the FI formulation. In brief, the boundary-bound
part of the sensitivities is the patchInternalField of the tensor
multiplying grad(dxdb) in the FI formulation.
\endverbatim
SourceFiles
shapeSensitivitiesBase.C
ShapeSensitivitiesBase.C
\*---------------------------------------------------------------------------*/
#ifndef shapeSensitivitiesBase_H
#define shapeSensitivitiesBase_H
#ifndef ShapeSensitivitiesBase_H
#define ShapeSensitivitiesBase_H
#include "volFields.H"
#include "surfaceFields.H"
#include "dictionary.H"
#include "adjointSensitivity.H"
#include "objective.H"
#include "volPointInterpolation.H"
#include "pointMesh.H"
#include "pointPatchField.H"
#include "pointPatchFieldsFwd.H"
@ -58,27 +74,29 @@ namespace Foam
{
/*---------------------------------------------------------------------------*\
Class shapeSensitivitiesBase Declaration
Class ShapeSensitivitiesBase Declaration
\*---------------------------------------------------------------------------*/
class shapeSensitivitiesBase
class ShapeSensitivitiesBase
:
public adjointSensitivity
{
protected:
// Protected data
const fvMesh& meshShape_;
word surfaceFieldSuffix_;
bool writeAllSurfaceFiles_;
// Patches on which to compute shape sensitivities
//- Patches on which to compute shape sensitivities
labelHashSet sensitivityPatchIDs_;
//- Whether to write all surface sensitivity fields
bool writeAllSurfaceFiles_;
// autoPtrs for fields holding sensitivities.
// Not all of them are required for each case
// Boundary sensitivities at faces. Shape opt & flow control
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//- Wall face sens w.r.t. (x,y.z)
autoPtr<boundaryVectorField> wallFaceSensVecPtr_;
@ -101,6 +119,16 @@ protected:
//- Normal sens as vectors
autoPtr<pointBoundaryVectorField> wallPointSensNormalVecPtr_;
// Protected Member Functions
//- Allocate the adjoint eikonal solver
void allocateEikonalSolver();
//- Check if any of the available objective has a certain multiplier,
//- provided through a function object
bool hasMultiplier(bool (objective::*hasFunction)() const);
//- Constructs volField based on boundaryField and writes it
template<class Type>
void constructAndWriteSensitivityField
@ -138,55 +166,78 @@ protected:
//- Write point-based sensitivities, if present
void writePointBasedSens() const;
//- Clear surface/point fields
void clearSurfaceFields();
//- Allocate multiplier fields
void allocateMultipliers();
//- Clear multipliers
void clearMultipliers();
private:
// Private Member Functions
//- No copy construct
shapeSensitivitiesBase(const shapeSensitivitiesBase&) = delete;
ShapeSensitivitiesBase(const ShapeSensitivitiesBase&) = delete;
//- No copy assignment
void operator=(const shapeSensitivitiesBase&) = delete;
void operator=(const ShapeSensitivitiesBase&) = delete;
public:
//- Runtime type information
TypeName("shapeSensitivitiesBase");
TypeName("ShapeSensitivitiesBase");
// Constructors
//- Construct from components
shapeSensitivitiesBase
ShapeSensitivitiesBase
(
const fvMesh& mesh,
const dictionary& dict
const dictionary& dict,
adjointSolver& adjointSolver
);
//- Destructor
virtual ~shapeSensitivitiesBase() = default;
virtual ~ShapeSensitivitiesBase() = default;
// Member Functions
//- Read dict if changed
virtual bool readDict(const dictionary& dict);
//- Get patch IDs on which sensitivities are computed
const labelHashSet& sensitivityPatchIDs() const;
inline const labelHashSet& sensitivityPatchIDs() const
{
return sensitivityPatchIDs_;
}
//- Overwrite sensitivityPatchIDs
void setSensitivityPatchIDs(const labelHashSet& sensPatchIDs);
inline void setSensitivityPatchIDs(const labelHashSet& sensPatchIDs)
{
sensitivityPatchIDs_ = sensPatchIDs;
}
//- Return set of patches on which to compute direct sensitivities
virtual const labelHashSet& geometryVariationIntegrationPatches() const;
//- Accumulate sensitivity integrands
// Common function for the FI and E-SI approaches
virtual void accumulateIntegrand(const scalar dt);
//- Zero sensitivity fields and their constituents
void clearSensitivities();
//- Write sensitivity fields.
// If valid, copies boundaryFields to volFields and writes them.
void write();
//- Set suffix
void setSuffix(const word& suffix);
virtual void write(const word& baseName = word::null);
//- Get wall face sensitivity vectors field
tmp<volVectorField> getWallFaceSensVec();
@ -229,7 +280,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#ifdef NoRepository
#include "shapeSensitivitiesBaseTemplates.C"
#include "ShapeSensitivitiesBaseTemplates.C"
#endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -27,7 +27,7 @@ License
\*---------------------------------------------------------------------------*/
#include "shapeSensitivitiesBase.H"
#include "ShapeSensitivitiesBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -37,7 +37,7 @@ namespace Foam
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template<class Type>
void shapeSensitivitiesBase::constructAndWriteSensitivityField
void ShapeSensitivitiesBase::constructAndWriteSensitivityField
(
const autoPtr
<
@ -51,12 +51,12 @@ void shapeSensitivitiesBase::constructAndWriteSensitivityField
IOobject
(
name,
meshShape_.time().timeName(),
meshShape_,
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
meshShape_,
mesh_,
dimensioned<Type>(dimless, Zero)
);
@ -70,7 +70,7 @@ void shapeSensitivitiesBase::constructAndWriteSensitivityField
template<class Type>
void shapeSensitivitiesBase::constructAndWriteSensitivtyPointField
void ShapeSensitivitiesBase::constructAndWriteSensitivtyPointField
(
const autoPtr<List<Field<Type>>>& sensFieldPtr,
const word& name
@ -81,12 +81,12 @@ void shapeSensitivitiesBase::constructAndWriteSensitivtyPointField
IOobject
(
name,
meshShape_.time().timeName(),
meshShape_,
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
pointMesh::New(meshShape_),
pointMesh::New(mesh_),
dimensioned<Type>(dimless, Zero)
//fixedValuePointPatchField<Type>::typeName
);
@ -109,7 +109,7 @@ void shapeSensitivitiesBase::constructAndWriteSensitivtyPointField
template<class Type>
tmp<GeometricField<Type, fvPatchField, volMesh>>
shapeSensitivitiesBase::constructVolSensitivtyField
ShapeSensitivitiesBase::constructVolSensitivtyField
(
const autoPtr
<
@ -125,12 +125,12 @@ shapeSensitivitiesBase::constructVolSensitivtyField
IOobject
(
name,
meshShape_.time().timeName(),
meshShape_,
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
meshShape_,
mesh_,
pTraits<Type>::zero
)
);

View File

@ -0,0 +1,384 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020, 2022 PCOpt/NTUA
Copyright (C) 2013-2020, 2022 FOSS GP
Copyright (C) 2019-2022 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivitySurface.H"
#include "volPointInterpolationAdjoint.H"
#include "faMatrices.H"
#include "famSup.H"
#include "famLaplacian.H"
#include "volSurfaceMapping.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivitySurface, 0);
addToRunTimeSelectionTable
(
adjointSensitivity,
sensitivitySurface,
dictionary
);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
label sensitivitySurface::computeFaceDerivativesSize
(
const bool computeVectorFieldSize
)
{
label size(0);
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
const label patchSize = patch.size();
size += label(computeVectorFieldSize ? 3*patchSize : patchSize);
}
return size;
}
void sensitivitySurface::smoothSensitivities()
{
// Read in parameters
const label iters(dict().getOrDefault<label>("iters", 500));
const scalar tolerance(dict().getOrDefault<scalar>("tolerance", 1.e-06));
autoPtr<faMesh> aMeshPtr(nullptr);
IOobject faceLabels
(
"faceLabels",
mesh_.time().findInstance
(
mesh_.dbDir()/faMesh::meshSubDir,
"faceLabels",
IOobject::READ_IF_PRESENT
),
faMesh::meshSubDir,
mesh_,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE
);
// If the faMesh already exists, read it
if (faceLabels.typeHeaderOk<labelIOList>(false))
{
Info<< "Reading the already constructed faMesh" << endl;
aMeshPtr.reset(new faMesh(mesh_));
}
else
{
// Dictionary used to construct the faMesh
dictionary faMeshDefinition;
IOobject faMeshDefinitionDict
(
"faMeshDefinition",
mesh_.time().caseSystem(),
mesh_,
IOobject::MUST_READ,
IOobject::NO_WRITE
);
// If the faMeshDefinitionDict exists, use it to construct the mesh
if (faMeshDefinitionDict.typeHeaderOk<IOdictionary>(false))
{
Info<< "Reading faMeshDefinition from system " << endl;
faMeshDefinition = IOdictionary(faMeshDefinitionDict);
}
// Otherwise, faMesh is generated from all patches on which we compute
// sensitivities
else
{
Info<< "Constructing faMeshDefinition from sensitivity patches"
<< endl;
wordList polyMeshPatches(sensitivityPatchIDs_.size());
label i(0);
for (const label patchID : sensitivityPatchIDs_)
{
polyMeshPatches[i++] = mesh_.boundary()[patchID].name();
}
faMeshDefinition.add<wordList>("polyMeshPatches", polyMeshPatches);
(void)faMeshDefinition.subDictOrAdd("boundary");
Info<< faMeshDefinition << endl;
}
// Construct faMesh
aMeshPtr.reset(new faMesh(mesh_, faMeshDefinition));
}
faMesh& aMesh = aMeshPtr.ref();
// Physical radius of the smoothing, provided either directly or computed
// based on the average 'length' of boundary faces
const scalar Rphysical
(dict().getOrDefault<scalar>("radius", computeRadius(aMesh)));
DebugInfo
<< "Physical radius of the sensitivity smoothing "
<< Rphysical << nl << endl;
// Radius used as the diffusivity in the Helmholtz filter, computed as a
// function of the physical radius
const dimensionedScalar RpdeSqr
(
"RpdeSqr", dimArea, sqr(Rphysical/(2.*::sqrt(3.)))
);
dimensionedScalar one("1", dimless, 1.);
// Mapping engine
volSurfaceMapping vsm(aMesh);
// Source term in faMatrix needs to be an areaField
areaVectorField sens
(
IOobject
(
"sens",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
aMesh,
dimensionedVector(dimless, Zero),
faPatchFieldBase::zeroGradientType()
);
// Copy sensitivities to area field
sens.primitiveFieldRef() =
vsm.mapToSurface<vector>(wallFaceSensVecPtr_());
// Initialisation of the smoothed sensitivities field based on the original
// sensitivities
areaVectorField smoothedSens("smoothedSens", sens);
for (label iter = 0; iter < iters; ++iter)
{
Info<< "Sensitivity smoothing iteration " << iter << endl;
faVectorMatrix smoothEqn
(
fam::Sp(one, smoothedSens)
- fam::laplacian(RpdeSqr, smoothedSens)
==
sens
);
smoothEqn.relax();
const scalar residual(mag(smoothEqn.solve().initialResidual()));
DebugInfo
<< "Max smoothSens " << gMax(mag(smoothedSens)()) << endl;
// Print execution time
mesh_.time().printExecutionTime(Info);
// Check convergence
if (residual < tolerance)
{
Info<< "\n***Reached smoothing equation convergence limit, "
"iteration " << iter << "***\n\n";
break;
}
}
// Transfer smooth sensitivity field to wallFaceSensVecPtr_ for defining
// derivatives_
vsm.mapToVolume(smoothedSens, wallFaceSensVecPtr_());
// Write normal, regularised sensitivities to file
volScalarField volSmoothedSens
(
IOobject
(
"smoothedSurfaceSens" + suffix_,
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(dimless, Zero)
);
areaVectorField nf(aMesh.faceAreaNormals());
nf.normalise();
areaScalarField smoothedSensNormal(smoothedSens & nf);
vsm.mapToVolume(smoothedSensNormal, volSmoothedSens.boundaryFieldRef());
volSmoothedSens.write();
}
scalar sensitivitySurface::computeRadius(const faMesh& aMesh)
{
scalar averageArea(gAverage(aMesh.S().field()));
const Vector<label>& geometricD = mesh_.geometricD();
const boundBox& bounds = mesh_.bounds();
forAll(geometricD, iDir)
{
if (geometricD[iDir] == -1)
{
averageArea /= bounds.span()[iDir];
}
}
scalar mult = dict().getOrDefault<scalar>("meanRadiusMultiplier", 10);
return mult*pow(averageArea, scalar(1)/scalar(mesh_.nGeometricD() - 1));
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivitySurface::sensitivitySurface
(
const fvMesh& mesh,
const dictionary& dict,
adjointSolver& adjointSolver
)
:
sensitivitySurfacePoints(mesh, dict, adjointSolver),
smoothSensitivities_(dict.getOrDefault("smoothSensitivities", false)),
returnVectorField_
(dict.getOrDefault<bool>("returnVectorField", true))
//finalResultIncludesArea_
// (dict.getOrDefault<bool>("finalResultIncludesArea", false))
{
// Allocate boundary field pointers
wallFaceSensVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
wallFaceSensNormalPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
wallFaceSensNormalVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
derivatives_.setSize(computeFaceDerivativesSize(returnVectorField_), Zero);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void sensitivitySurface::read()
{
sensitivitySurfacePoints::read();
smoothSensitivities_ = dict().getOrDefault("smoothSensitivities", false);
returnVectorField_ =
dict().getOrDefault<bool>("returnVectorField", true);
//finalResultIncludesArea_ =
// dict().getOrDefault<bool>("finalResultIncludesArea", false);
}
void sensitivitySurface::assembleSensitivities
(
autoPtr<designVariables>& designVars
)
{
// Compute point-based sensitivities
sensitivitySurfacePoints::assembleSensitivities(designVars);
// Transfer point sensitivities to point field
vectorField pointSens(mesh_.nPoints(), Zero);
for (const label patchI : sensitivityPatchIDs_)
{
const polyPatch& pp = mesh_.boundaryMesh()[patchI];
const labelList& meshPoints = pp.meshPoints();
forAll(meshPoints, ppi)
{
pointSens[meshPoints[ppi]] = wallPointSensVecPtr_()[patchI][ppi];
}
}
// vectorField face-sensitivities
vectorField faceVecSens(computeFaceDerivativesSize(false), Zero);
// Map sensitivities from points to faces
volPointInterpolationAdjoint interpolation(mesh_);
interpolation.interpolateSensitivitiesField
(pointSens, faceVecSens, sensitivityPatchIDs_);
// Transfer non-regularised sensitivities to wallFaceSens* fields and write
label nPassedFaces(0);
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> nf = patch.nf();
wallFaceSensVecPtr_()[patchI] =
SubField<vector>(faceVecSens, patch.size(), nPassedFaces)
/patch.magSf();
wallFaceSensNormalPtr_()[patchI] = wallFaceSensVecPtr_()[patchI] & nf();
wallFaceSensNormalVecPtr_()[patchI] =
wallFaceSensNormalPtr_()[patchI]*nf;
nPassedFaces += patch.size();
}
write();
// Regularise sensitivities if necessary
if (smoothSensitivities_)
{
smoothSensitivities();
}
// Make sure we have the correct sensitivities size
derivatives_.setSize(computeFaceDerivativesSize(returnVectorField_), Zero);
nPassedFaces = 0;
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
const vectorField nf(patch.nf());
if (returnVectorField_)
{
const Vector<label>& sd = mesh_.solutionD();
forAll(patch, fI)
{
const label gfI = nPassedFaces + fI;
const vector& fSens = wallFaceSensVecPtr_()[patchI][fI];
derivatives_[3*gfI ] = scalar(sd[0] == -1 ? 0 : fSens.x());
derivatives_[3*gfI + 1] = scalar(sd[1] == -1 ? 0 : fSens.y());
derivatives_[3*gfI + 2] = scalar(sd[2] == -1 ? 0 : fSens.z());
}
}
else
{
forAll(patch, fI)
{
derivatives_[nPassedFaces + fI]
= wallFaceSensVecPtr_()[patchI][fI] & nf[fI];
}
}
nPassedFaces += patch.size();
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -26,7 +26,7 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::sensitivitySurface
Foam::sensitivitySurface
Description
Calculation of adjoint based sensitivities at wall faces
@ -60,11 +60,7 @@ SourceFiles
#ifndef sensitivitySurfaceIncompressible_H
#define sensitivitySurfaceIncompressible_H
#include "adjointSensitivityIncompressible.H"
#include "shapeSensitivitiesBase.H"
#include "adjointEikonalSolverIncompressible.H"
#include "adjointMeshMovementSolverIncompressible.H"
#include "deltaBoundary.H"
#include "sensitivitySurfacePoints.H"
#include "faMesh.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -72,75 +68,31 @@ SourceFiles
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class sensitivitySurface Declaration
\*---------------------------------------------------------------------------*/
class sensitivitySurface
:
public adjointSensitivity,
public shapeSensitivitiesBase
public sensitivitySurfacePoints
{
protected:
// Protected data
//- Include surface area in sens computation
bool includeSurfaceArea_;
//- Include the adjoint pressure term in sens computation
bool includePressureTerm_;
//- Include the term containing the grad of the stress at the boundary
bool includeGradStressTerm_;
//- Include the transpose part of the adjoint stresses
bool includeTransposeStresses_;
//- Use snGrad in the transpose part of the adjoint stresses
bool useSnGradInTranposeStresses_;
//- Include the term from the deviatoric part of the stresses
bool includeDivTerm_;
//- Include distance variation in sens computation
bool includeDistance_;
//- Include mesh movement variation in sens computation
bool includeMeshMovement_;
//- Include terms directly emerging from the objective function
bool includeObjective_;
//- Write geometric info for use by external programs
bool writeGeometricInfo_;
//- Smooth sensitivity derivatives based on the computation of the
//- 'Sobolev gradient'
//- Smooth sensitivity derivatives based on a surface Laplace solver
bool smoothSensitivities_;
autoPtr<adjointEikonalSolver> eikonalSolver_;
//- Return the complete vector of sensitivities
bool returnVectorField_;
autoPtr<adjointMeshMovementSolver> meshMovementSolver_;
// Export face normal and face centre for use by external users
autoPtr<volVectorField> nfOnPatchPtr_;
autoPtr<volVectorField> SfOnPatchPtr_;
autoPtr<volVectorField> CfOnPatchPtr_;
//bool finalResultIncludesArea_;
// Protected Member Functions
//- Add sensitivities from dSd/db and dnf/db computed at points and
//- mapped to faces
void addGeometricSens();
//- Set suffix name for sensitivity fields
void setSuffixName();
//- Compute the size of the return field
label computeFaceDerivativesSize(const bool computeVectorFieldSize);
//- Smooth sensitivity derivatives based on the computation of the
//- 'Sobolev gradient'
@ -175,7 +127,7 @@ public:
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
adjointSolver& adjointSolver
);
@ -188,55 +140,20 @@ public:
//- Read controls and update solver pointers if necessary
void read();
//- Read dict if changed
virtual bool readDict(const dictionary& dict);
//- Compute the number of faces on sensitivityPatchIDs_
void computeDerivativesSize();
//- Accumulate sensitivity integrands
virtual void accumulateIntegrand(const scalar dt);
//- Assemble sensitivities
virtual void assembleSensitivities();
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Get adjoint eikonal solver
autoPtr<adjointEikonalSolver>& getAdjointEikonalSolver();
//- Write sensitivity maps
virtual void write(const word& baseName = word::null);
// Inline getters and setters
//- Get access to the includeObjective bool
inline bool getIncludeObjective() const;
//- Get access to the includeSurfaceArea bool
inline bool getIncludeSurfaceArea() const;
//- Set includeObjective bool
inline void setIncludeObjective(const bool includeObjective);
//- Set includeSurfaceArea bool
inline void setIncludeSurfaceArea(const bool includeSurfaceArea);
virtual void assembleSensitivities
(
autoPtr<designVariables>& designVars
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "sensitivitySurfaceIncompressibleI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,560 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020, 2022 PCOpt/NTUA
Copyright (C) 2013-2020, 2022 FOSS GP
Copyright (C) 2019-2022 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivitySurfacePoints.H"
#include "deltaBoundary.H"
#include "designVariables.H"
#include "syncTools.H"
#include "symmetryFvPatch.H"
#include "symmetryPlaneFvPatch.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivitySurfacePoints, 1);
addToRunTimeSelectionTable
(
adjointSensitivity,
sensitivitySurfacePoints,
dictionary
);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
labelHashSet sensitivitySurfacePoints::populateExtendedIDs() const
{
// Populate extendedPatchIDs
label pI(0);
labelList extendedPatchIDs(mesh_.boundary().size(), -1);
forAll(mesh_.boundary(), patchI)
{
const fvPatch& pp = mesh_.boundary()[patchI];
bool isSymmetry
(isA<symmetryFvPatch>(pp) || isA<symmetryPlaneFvPatch>(pp));
if (!isA<coupledFvPatch>(pp) && !isA<emptyFvPatch>(pp) && !isSymmetry)
{
extendedPatchIDs[pI++] = patchI;
}
}
extendedPatchIDs.setSize(pI);
return labelHashSet(extendedPatchIDs);
}
void sensitivitySurfacePoints::setSuffixName()
{
word suffix(adjointMeshMovementSolver_ ? "ESI" : "SI");
suffix = suffix + word(dict().getOrDefault<word>("suffix", word::null));
setSuffix(adjointSolver_.solverName() + suffix);
}
void sensitivitySurfacePoints::finalisePointSensitivities()
{
// List with mesh faces. Global addressing
const faceList& faces = mesh_.faces();
// Geometry differentiation engine
deltaBoundary dBoundary(mesh_);
for (const label patchI : extendedPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
vectorField nf(patch.nf());
// Point sens result for patch
vectorField& pointPatchSens = wallPointSensVecPtr_()[patchI];
// Face sens for patch
vectorField facePatchSens = dxdbMult_()[patchI];
if (dxdbDirectMult_)
{
facePatchSens += dxdbDirectMult_()[patchI];
}
if (bcDxDbMult_)
{
facePatchSens += bcDxDbMult_()[patchI];
}
// Correspondance of local point addressing to global point addressing
const labelList& meshPoints = patch.patch().meshPoints();
// Each local patch point belongs to these local patch faces
// (local numbering)
const labelListList& patchPointFaces = patch.patch().pointFaces();
// Index of first face in patch
const label patchStartIndex = patch.start();
// Loop over patch points.
// Collect contributions from each boundary face this point belongs to
forAll(meshPoints, ppI)
{
const labelList& pointFaces = patchPointFaces[ppI];
forAll(pointFaces, pfI)
{
label localFaceIndex = pointFaces[pfI];
label globalFaceIndex = patchStartIndex + localFaceIndex;
const face& faceI = faces[globalFaceIndex];
// Point coordinates. All indices in global numbering
pointField p(faceI.points(mesh_.points()));
tensorField p_d(faceI.size(), Zero);
forAll(faceI, facePointI)
{
if (faceI[facePointI] == meshPoints[ppI])
{
p_d[facePointI] = tensor::I;
}
}
tensorField deltaNormals =
dBoundary.makeFaceCentresAndAreas_d(p, p_d);
if (isSymmetryPoint_[meshPoints[ppI]])
{
const vector& n = symmPointNormal_[meshPoints[ppI]];
deltaNormals =
//0.5*(deltaNormals + transform(I - 2.0*sqr(n), deltaNormals));
(deltaNormals + transform(I - 2.0*sqr(n), deltaNormals));
}
// Element [0] is the variation in the face center
// (dxFace/dxPoint)
const tensor& deltaCf = deltaNormals[0];
pointPatchSens[ppI] += facePatchSens[localFaceIndex] & deltaCf;
// Term multiplying d(Sf)/d(point displacement) and
// d(nf)/d(point displacement)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Element [1] is the variation in the (dimensional) normal
if (dSfdbMult_)
{
const tensor& deltaSf = deltaNormals[1];
pointPatchSens[ppI] +=
dSfdbMult_()[patchI][localFaceIndex] & deltaSf;
}
// Element [2] is the variation in the unit normal
if (dnfdbMult_)
{
const tensor& deltaNf = deltaNormals[2];
pointPatchSens[ppI] +=
dnfdbMult_()[patchI][localFaceIndex] & deltaNf;
}
}
}
}
}
void sensitivitySurfacePoints::constructGlobalPointNormalsAndAreas
(
vectorField& pointNormals,
scalarField& pointMagSf
)
{
for (const label patchI : extendedPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
const scalarField& magSf = patch.magSf();
vectorField nf(patch.nf());
// Correspondance of local point addressing to global point addressing
const labelList& meshPoints = patch.patch().meshPoints();
// Each local patch point belongs to these local patch faces
// (local numbering)
const labelListList& patchPointFaces = patch.patch().pointFaces();
// Loop over patch points
forAll(meshPoints, ppI)
{
const labelList& pointFaces = patchPointFaces[ppI];
forAll(pointFaces, pfI)
{
const label localFaceIndex = pointFaces[pfI];
// Accumulate information for point normals
pointNormals[meshPoints[ppI]] += nf[localFaceIndex];
pointMagSf[meshPoints[ppI]] += magSf[localFaceIndex];
}
}
}
syncTools::syncPointList
(
mesh_,
pointNormals,
plusEqOp<vector>(),
vector::zero
);
syncTools::syncPointList
(
mesh_,
pointMagSf,
plusEqOp<scalar>(),
scalar(0)
);
if (writeGeometricInfo_)
{
pointScalarField MagSf
(
IOobject
(
"pointMagSf",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
pointMesh::New(mesh_),
dimensionedScalar(dimless, Zero)
);
pointVectorField Nf
(
IOobject
(
"pointNf",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
pointMesh::New(mesh_),
dimensionedVector(dimless, Zero)
);
MagSf.primitiveFieldRef() = pointMagSf;
Nf.primitiveFieldRef() = pointNormals;
Nf.primitiveFieldRef().normalise();
MagSf.write();
Nf.write();
}
}
void sensitivitySurfacePoints::computePointDerivativesSize()
{
// Allocate appropriate space for sensitivities
label nTotalPoints(0);
for (const label patchI : sensitivityPatchIDs_)
{
nTotalPoints += mesh_.boundaryMesh()[patchI].nPoints();
}
// Derivatives for all (x,y,z) components of the displacement
derivatives_ = scalarField(3*nTotalPoints, Zero);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivitySurfacePoints::sensitivitySurfacePoints
(
const fvMesh& mesh,
const dictionary& dict,
adjointSolver& adjointSolver
)
:
sensitivityShapeESI(mesh, dict, adjointSolver),
writeGeometricInfo_(false),
includeSurfaceArea_(false),
isSymmetryPoint_(mesh.nPoints(), false),
symmPointNormal_(mesh.nPoints(), Zero),
extendedPatchIDs_(populateExtendedIDs())
{
if (debug)
{
Info<< "Extended sensitivity patches " << nl;
for (const label patchI : extendedPatchIDs_)
{
Info<< mesh_.boundary()[patchI].name() << endl;
}
}
read();
setSuffixName();
// Allocate boundary field pointer
wallPointSensVecPtr_.reset(createZeroBoundaryPointFieldPtr<vector>(mesh_));
wallPointSensNormalPtr_.reset
(
createZeroBoundaryPointFieldPtr<scalar>(mesh_)
);
wallPointSensNormalVecPtr_.reset
(
createZeroBoundaryPointFieldPtr<vector>(mesh_)
);
computePointDerivativesSize();
// Populate symmetry patches
forAll(mesh_.boundary(), patchI)
{
const fvPatch& pp = mesh_.boundary()[patchI];
bool isSymmetry
(isA<symmetryFvPatch>(pp) || isA<symmetryPlaneFvPatch>(pp));
if (isSymmetry)
{
const labelList& meshPoints = pp.patch().meshPoints();
const vectorField& pointNormals = pp.patch().pointNormals();
forAll(meshPoints, pI)
{
const label pointi = meshPoints[pI];
isSymmetryPoint_[pointi] = true;
symmPointNormal_[pointi] = pointNormals[pI];
}
}
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void sensitivitySurfacePoints::read()
{
writeGeometricInfo_ =
dict().getOrDefault<bool>("writeGeometricInfo", false);
// Point sensitivities do not include the surface area by default
includeSurfaceArea_ =
dict().getOrDefault<bool>("includeSurfaceArea", false);
}
bool sensitivitySurfacePoints::readDict(const dictionary& dict)
{
if (sensitivityShapeESI::readDict(dict))
{
read();
return true;
}
return false;
}
const Foam::labelHashSet&
Foam::sensitivitySurfacePoints::geometryVariationIntegrationPatches() const
{
return extendedPatchIDs_;
}
void sensitivitySurfacePoints::assembleSensitivities
(
autoPtr<designVariables>& designVars
)
{
// Make sure we have the proper size for the sensitivities
computePointDerivativesSize();
// Assemble the multipliers of dxdbFace, as in the ESI approach
computeDxDbMult();
// Geometric (or "direct") sensitivities are better computed directly on
// the points. Compute them and add the ones that depend on dxFace/dxPoint
finalisePointSensitivities();
// polyPatch::pointNormals will give the wrong result for points
// belonging to multiple patches or patch-processorPatch intersections.
// Keeping a mesh-wide field to allow easy reduction using syncTools.
// A bit expensive? Better way?
vectorField pointNormals(mesh_.nPoints(), Zero);
scalarField pointMagSf(mesh_.nPoints(), Zero);
constructGlobalPointNormalsAndAreas(pointNormals, pointMagSf);
// Do parallel communications to avoid wrong values at processor boundaries
// Global field for accumulation
vectorField pointSensGlobal(mesh_.nPoints(), Zero);
for (const label patchI : extendedPatchIDs_)
{
const labelList& meshPoints = mesh_.boundaryMesh()[patchI].meshPoints();
forAll(meshPoints, ppI)
{
const label globaPointI = meshPoints[ppI];
pointSensGlobal[globaPointI] += wallPointSensVecPtr_()[patchI][ppI];
}
}
/*
// Remove components normal to symmetry planes
forAll(mesh_.boundary(), patchI)
{
const fvPatch& patch = mesh_.boundary()[patchI];
if (isA<symmetryFvPatch>(patch) || isA<symmetryPlaneFvPatch>(patch))
{
// Deliberately using local point normals instead of the global ones,
// to get the direction normal to the symmetry plane itself
const vectorField& pn = patch.patch().pointNormals();
const labelList& meshPoints = patch.patch().meshPoints();
forAll(meshPoints, pI)
{
const label gpI = meshPoints[pI];
pointSensGlobal[gpI] -= wallPointSensVecPtr_()[patchI][pI];
pointSensGlobal[gpI] -=
(pointSensGlobal[gpI] & pn[pI])*pn[pI];
pointSensGlobal[gpI] *= 2;
}
}
}
*/
// Accumulate dJ/dx_i
syncTools::syncPointList
(
mesh_,
pointSensGlobal,
plusEqOp<vector>(),
vector::zero
);
// Transfer back to local fields
for (const label patchI : extendedPatchIDs_)
{
const labelList& meshPoints =
mesh_.boundaryMesh()[patchI].meshPoints();
wallPointSensVecPtr_()[patchI].map(pointSensGlobal, meshPoints);
}
// Compute normal sens and append to return field
label nPassedDVs(0);
const Vector<label>& sd = mesh_.solutionD();
for (const label patchI : sensitivityPatchIDs_)
{
const polyPatch& patch = mesh_.boundaryMesh()[patchI];
//if (patch.size()>0)
{
const labelList& meshPoints = patch.meshPoints();
// Avoid storing unit point normals in the global list since we
// might divide multiple times with the number of faces belonging
// to the point. Instead do the division locally, per patch use
vectorField patchPointNormals(pointNormals, meshPoints);
patchPointNormals.normalise();
if (!includeSurfaceArea_)
{
wallPointSensVecPtr_()[patchI] /=
scalarField(pointMagSf, meshPoints);
}
wallPointSensNormalPtr_()[patchI] =
wallPointSensVecPtr_()[patchI] & patchPointNormals;
wallPointSensNormalVecPtr_()[patchI] =
wallPointSensNormalPtr_()[patchI] *patchPointNormals;
forAll(patch.localPoints(), pi)
{
const label gpi = nPassedDVs + pi;
const vector& pSens = wallPointSensVecPtr_()[patchI][pi];
derivatives_[3*gpi ] = scalar(sd[0] == -1 ? 0 : pSens.x());
derivatives_[3*gpi + 1] = scalar(sd[1] == -1 ? 0 : pSens.y());
derivatives_[3*gpi + 2] = scalar(sd[2] == -1 ? 0 : pSens.z());
}
nPassedDVs += patch.nPoints();
}
}
// Write derivative fields
write();
// Get processed sensitivities from designVariables, if present
if (designVars)
{
adjointSensitivity::assembleSensitivities(designVars);
}
}
void sensitivitySurfacePoints::write(const word& baseName)
{
adjointSensitivity::write();
ShapeSensitivitiesBase::write();
if (writeGeometricInfo_)
{
volVectorField nfOnPatch
(
IOobject
(
"nfOnPatch",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh_,
Zero
);
volVectorField SfOnPatch
(
IOobject
(
"SfOnPatch",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh_,
Zero
);
volVectorField CfOnPatch
(
IOobject
(
"CfOnPatch",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh_,
Zero
);
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
nfOnPatch.boundaryFieldRef()[patchI] = patch.nf();
SfOnPatch.boundaryFieldRef()[patchI] = patch.Sf();
CfOnPatch.boundaryFieldRef()[patchI] = patch.Cf();
}
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -26,99 +26,62 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::sensitivitySurfacePoints
Foam::sensitivitySurfacePoints
Description
Calculation of adjoint based sensitivities at wall points
Calculation of adjoint-based sensitivities at wall points using the
E-SI formulation
SourceFiles
sensitivitySurfacePoints.C
\*---------------------------------------------------------------------------*/
#ifndef sensitivitySurfacePointsIncompressible_H
#define sensitivitySurfacePointsIncompressible_H
#ifndef sensitivitySurfacePoints_H
#define sensitivitySurfacePoints_H
#include "adjointSensitivityIncompressible.H"
#include "shapeSensitivitiesBase.H"
#include "adjointEikonalSolverIncompressible.H"
#include "adjointMeshMovementSolverIncompressible.H"
#include "deltaBoundary.H"
#include "sensitivityShapeESI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class sensitivitySurfacePoints Declaration
\*---------------------------------------------------------------------------*/
class sensitivitySurfacePoints
:
public adjointSensitivity,
public shapeSensitivitiesBase
public sensitivityShapeESI
{
protected:
// Protected data
//- Write geometric info for use by external programs
bool writeGeometricInfo_;
//- Include surface area in sens computation
bool includeSurfaceArea_;
//- Include the adjoint pressure term in sens computation
bool includePressureTerm_;
//- Is point belonging to a symmetry{Plane}
boolList isSymmetryPoint_;
//- Include the term containing the grad of the stress at the boundary
bool includeGradStressTerm_;
//- Local point normal per symmetry point
vectorField symmPointNormal_;;
//- Include the transpose part of the adjoint stresses
bool includeTransposeStresses_;
//- Use snGrad in the transpose part of the adjoint stresses
bool useSnGradInTranposeStresses_;
//- Include the term from the deviatoric part of the stresses
bool includeDivTerm_;
//- Include distance variation in sens computation
bool includeDistance_;
//- Include mesh movement variation in sens computation
bool includeMeshMovement_;
//- Include terms directly emerging from the objective function
bool includeObjective_;
autoPtr<adjointEikonalSolver> eikonalSolver_;
autoPtr<adjointMeshMovementSolver> meshMovementSolver_;
//- The face-based part of the sensitivities
// i.e. terms that multiply dxFace/dxPoint.
// Sensitivities DO include locale surface area, to get
// the correct weighting from the contributions of various faces.
// Normalized at the end.
autoPtr<boundaryVectorField> wallFaceSens_;
//- Multipliers of d(Sf)/db and d(nf)/db
autoPtr<boundaryVectorField> dSfdbMult_;
autoPtr<boundaryVectorField> dnfdbMult_;
//- Extended patchIDs
// Sensitivities from patches adjacent to the sensitivityPatchIDs_
// should also be taken into consideration in order to compute the
// correct values at points in their interfaces
labelHashSet extendedPatchIDs_;
// Protected Member Functions
//- Read controls and update solver pointers if necessary
void read();
//- Add terms related to post-processing PDEs
//- (i.e. adjoint Eikonal, adjoint mesh movement)
//- and add local face area
void finaliseFaceMultiplier();
//- Set suffix name for sensitivity fields
labelHashSet populateExtendedIDs() const;
//- Converts face sensitivities to point sensitivities and adds the
//- ones directly computed in points (i.e. dSf/db and dnf/db).
@ -134,6 +97,9 @@ protected:
//- Set suffix name for sensitivity fields
void setSuffixName();
//- Allocate the proper size for the point-based sensitivities
void computePointDerivativesSize();
private:
@ -159,7 +125,7 @@ public:
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
adjointSolver& adjointSolver
);
@ -169,25 +135,29 @@ public:
// Member Functions
//- Read controls and update solver pointers if necessary
void read();
//- Read dict if changed
virtual bool readDict(const dictionary& dict);
//- Accumulate sensitivity integrands
virtual void accumulateIntegrand(const scalar dt);
//- Return set of patches on which to compute direct sensitivities
virtual const labelHashSet& geometryVariationIntegrationPatches() const;
//- Assemble sensitivities
virtual void assembleSensitivities();
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
virtual void assembleSensitivities
(
autoPtr<designVariables>& designVars
);
//- Write sensitivity fields.
// If valid, copies boundaryFields to pointFields and writes them.
virtual void write(const word& baseName = word::null);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -1,183 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2019-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "FIBaseIncompressible.H"
#include "addToRunTimeSelectionTable.H"
#include "fvOptions.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(FIBase, 0);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void FIBase::read()
{
includeDistance_ =
dict_.getOrDefault<bool>
(
"includeDistance",
adjointVars_.adjointTurbulence().ref().includeDistance()
);
// Allocate distance solver if needed
if (includeDistance_ && !eikonalSolver_)
{
eikonalSolver_.reset
(
new adjointEikonalSolver
(
mesh_,
dict_,
primalVars_.RASModelVariables(),
adjointVars_,
sensitivityPatchIDs_
)
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
FIBase::FIBase
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
shapeSensitivities(mesh, dict, adjointSolver),
gradDxDbMult_
(
IOobject
(
"gradDxDbMult",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero)
),
divDxDbMult_(mesh_.nCells(), Zero),
optionsDxDbMult_(mesh_.nCells(), Zero),
includeDistance_(false),
eikonalSolver_(nullptr)
{
read();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool FIBase::readDict(const dictionary& dict)
{
if (sensitivity::readDict(dict))
{
if (eikonalSolver_)
{
eikonalSolver_().readDict(dict);
}
return true;
}
return false;
}
void FIBase::accumulateIntegrand(const scalar dt)
{
// Accumulate multiplier of grad(dxdb)
gradDxDbMult_ += computeGradDxDbMultiplier()().T()*dt;
// Accumulate multiplier of div(dxdb)
PtrList<objective>& functions(objectiveManager_.getObjectiveFunctions());
for (objective& func : functions)
{
if (func.hasDivDxDbMult())
{
divDxDbMult_ +=
func.weight()*func.divDxDbMultiplier().primitiveField()*dt;
}
}
// Terms from fvOptions
fv::options::New(this->mesh_).postProcessSens
(
optionsDxDbMult_, adjointVars_.solverName()
);
// Accumulate source for the adjoint to the eikonal equation
if (includeDistance_)
{
eikonalSolver_->accumulateIntegrand(dt);
}
// Accumulate direct sensitivities
accumulateDirectSensitivityIntegrand(dt);
// Accumulate sensitivities due to boundary conditions
accumulateBCSensitivityIntegrand(dt);
}
void FIBase::clearSensitivities()
{
gradDxDbMult_ = dimensionedTensor(gradDxDbMult_.dimensions(), Zero);
divDxDbMult_ = Zero;
optionsDxDbMult_ = vector::zero;
if (includeDistance_)
{
eikonalSolver_->reset();
}
shapeSensitivities::clearSensitivities();
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,165 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "SIBaseIncompressible.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(SIBase, 0);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void SIBase::read()
{
surfaceSensitivity_.read();
includeObjective_ =
dict().getOrDefault<bool>("includeObjectiveContribution", true);
writeSensitivityMap_ =
dict().getOrDefault<bool>("writeSensitivityMap", false);
// If includeObjective is set to true both here and in the surface
// sensitivities, set the one in the latter to false to avoid double
// contributions
bool surfSensIncludeObjective(surfaceSensitivity_.getIncludeObjective());
if (includeObjective_ && surfSensIncludeObjective)
{
WarningInFunction
<< "includeObjectiveContribution set to true in both "
<< "surfaceSensitivities and the parameterization options" << nl
<< "This will lead to double contributions " << nl
<< "Disabling the former"
<< endl;
surfaceSensitivity_.setIncludeObjective(false);
}
// Make sure surface area is included in the sensitivity map
surfaceSensitivity_.setIncludeSurfaceArea(true);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
SIBase::SIBase
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
shapeSensitivities(mesh, dict, adjointSolver),
surfaceSensitivity_
(
mesh,
// Ideally, subOrEmptyDict would be used.
// Since we need a recursive search in shapeSensitivities though
// and the dict returned by subOrEmptyDict (if found)
// does not know its parent, optionalSubDict is used
dict.optionalSubDict("surfaceSensitivities"),
adjointSolver
),
includeObjective_(true),
writeSensitivityMap_(true)
{
read();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool SIBase::readDict(const dictionary& dict)
{
if (sensitivity::readDict(dict))
{
surfaceSensitivity_.readDict
(
dict.optionalSubDict("surfaceSensitivities")
);
return true;
}
return false;
}
void SIBase::accumulateIntegrand(const scalar dt)
{
// Accumulate multiplier of dxFace/db
surfaceSensitivity_.accumulateIntegrand(dt);
// Accumulate direct sensitivities
if (includeObjective_)
{
accumulateDirectSensitivityIntegrand(dt);
}
// Accumulate sensitivities due to boundary conditions
accumulateBCSensitivityIntegrand(dt);
}
void SIBase::clearSensitivities()
{
surfaceSensitivity_.clearSensitivities();
shapeSensitivities::clearSensitivities();
}
const sensitivitySurface& SIBase::getSurfaceSensitivities() const
{
return surfaceSensitivity_;
}
void SIBase::write(const word& baseName)
{
shapeSensitivities::write(baseName);
if (writeSensitivityMap_)
{
surfaceSensitivity_.write(baseName);
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,219 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / 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
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::adjointSensitivity
Description
Abstract base class for adjoint-based sensitivities in incompressible flows
Reference:
\verbatim
For the FI and ESI formulations
Kavvadias, I., Papoutsis-Kiachagias, E., & Giannakoglou, K. (2015).
On the proper treatment of grid sensitivities in continuous adjoint
methods for shape optimization.
Journal of Computational Physics, 301, 118.
http://doi.org/10.1016/j.jcp.2015.08.012
For the SI formulation
Papoutsis-Kiachagias, E. M., & Giannakoglou, K. C. (2014).
Continuous Adjoint Methods for Turbulent Flows, Applied to Shape
and Topology Optimization: Industrial Applications.
Archives of Computational Methods in Engineering, 23(2), 255299.
http://doi.org/10.1007/s11831-014-9141-9
\endverbatim
SourceFiles
adjointSensitivity.C
\*---------------------------------------------------------------------------*/
#ifndef adjointSensitivityIncompressible_H
#define adjointSensitivityIncompressible_H
#include "sensitivity.H"
#include "incompressibleVars.H"
#include "incompressibleAdjointVars.H"
#include "wallFvPatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration
class incompressibleAdjointSolver;
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class adjointSensitivity Declaration
\*---------------------------------------------------------------------------*/
class adjointSensitivity
:
public sensitivity
{
protected:
// Protected data
scalarField derivatives_;
incompressibleAdjointSolver& adjointSolver_;
const incompressibleVars& primalVars_;
incompressibleAdjointVars& adjointVars_;
objectiveManager& objectiveManager_;
private:
// Private Member Functions
//- No copy construct
adjointSensitivity(const adjointSensitivity&) = delete;
//- No copy assignment
void operator=(const adjointSensitivity&) = delete;
public:
//- Runtime type information
TypeName("adjointSensitivity");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
adjointSensitivity,
dictionary,
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
),
(
mesh,
dict,
adjointSolver
)
);
// Constructors
//- Construct from components
adjointSensitivity
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
);
// Selectors
//- Return a reference to the selected turbulence model
static autoPtr<adjointSensitivity> New
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
);
//- Destructor
virtual ~adjointSensitivity() = default;
// Member Functions
//- Get primal variables
inline const incompressibleVars& primalVars() const
{
return primalVars_;
}
//- Get adjoint variables
inline const incompressibleAdjointVars& adjointVars() const
{
return adjointVars_;
}
//- Get adjoint solver
inline const incompressibleAdjointSolver& adjointSolver() const
{
return adjointSolver_;
}
//- Accumulate sensitivity integrands
// Corresponds to the flow and adjoint part of the sensitivities
virtual void accumulateIntegrand(const scalar dt) = 0;
//- Assemble sensitivities
// Adds the geometric part of the sensitivities
virtual void assembleSensitivities() = 0;
//- Calculates and returns sensitivity fields.
// Used with optimisation libraries
virtual const scalarField& calculateSensitivities();
//- Returns the sensitivity fields
// Assumes it has already been updated/computed
const scalarField& getSensitivities() const;
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Write sensitivity fields.
// If valid, copies boundaryFields to volFields and writes them.
// Virtual to be reimplemented by control points-based methods
// (Bezier, RBF) which do not need to write fields
virtual void write(const word& baseName = word::null);
//- Compute the volTensorField multiplying grad(dxdb) for
//- the volume-based approach to compute shape sensitivity derivatives
tmp<volTensorField> computeGradDxDbMultiplier();
//- Compute source term for adjoint mesh movement equation
tmp<volVectorField> adjointMeshMovementSource();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,247 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivityBezierIncompressible.H"
#include "addToRunTimeSelectionTable.H"
#include "IOmanip.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivityBezier, 0);
addToRunTimeSelectionTable
(
adjointSensitivity,
sensitivityBezier,
dictionary
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivityBezier::sensitivityBezier
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
SIBase(mesh, dict, adjointSolver),
//Bezier_(mesh, dict), // AJH Read locally?
Bezier_(mesh, mesh.lookupObject<IOdictionary>("optimisationDict")),
sens_(Bezier_.nBezier(), Zero),
flowSens_(Bezier_.nBezier(), Zero),
dSdbSens_(Bezier_.nBezier(), Zero),
dndbSens_(Bezier_.nBezier(), Zero),
dxdbDirectSens_(Bezier_.nBezier(), Zero),
bcSens_(Bezier_.nBezier(), Zero),
derivativesFolder_("optimisation"/type() + "Derivatives")
{
derivatives_ = scalarField(3*Bezier_.nBezier(), Zero);
// Create folder to store sensitivities
mkDir(derivativesFolder_);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void sensitivityBezier::assembleSensitivities()
{
// Assemble the sensitivity map
// Solves for the post-processing equations and adds their contribution to
// the sensitivity map
surfaceSensitivity_.assembleSensitivities();
forAll(sens_, iCP)
{
// Face-based summation. More robust since the result is independent of
// the number of processors (does not hold for a point-based summation)
for (const label patchI : sensitivityPatchIDs_)
{
// Interpolate parameterization info to faces
tmp<tensorField> tdxidXj = Bezier_.dxdbFace(patchI, iCP);
const tensorField& dxidXj = tdxidXj();
// Patch sensitivity map
const vectorField& patchSensMap =
surfaceSensitivity_.getWallFaceSensVecBoundary()[patchI];
flowSens_[iCP] += gSum(patchSensMap & dxidXj);
if (includeObjective_)
{
// Contribution from objective function
// term from delta( n dS ) / delta b and
// term from delta( n ) / delta b
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tmp<tensorField> tdSdb
(
Bezier_.dndbBasedSensitivities(patchI, iCP)
);
const tensorField& dSdb = tdSdb();
dSdbSens_[iCP] += gSum(dSfdbMult_()[patchI] & dSdb);
tmp<tensorField> tdndb
(
Bezier_.dndbBasedSensitivities(patchI, iCP, false)
);
const tensorField& dndb = tdndb();
dndbSens_[iCP] += gSum((dnfdbMult_()[patchI] & dndb));
// Contribution from objective function
// term from delta( x ) / delta b
// Only for objectives directly including
// x, like moments
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dxdbDirectSens_[iCP] +=
gSum((dxdbDirectMult_()[patchI] & dxidXj));
}
// Sensitivities from boundary conditions
bcSens_[iCP] += gSum(bcDxDbMult_()[patchI] & dxidXj);
}
}
sens_ = flowSens_ + dSdbSens_ + dndbSens_ + dxdbDirectSens_ + bcSens_;
// Transform sensitivities to scalarField in order to cooperate with
// updateMethod
label nBezier = Bezier_.nBezier();
forAll(sens_, cpI)
{
derivatives_[cpI] = sens_[cpI].x();
derivatives_[cpI + nBezier] = sens_[cpI].y();
derivatives_[cpI + 2*nBezier] = sens_[cpI].z();
const boolList& confineXmovement = Bezier_.confineXmovement();
const boolList& confineYmovement = Bezier_.confineYmovement();
const boolList& confineZmovement = Bezier_.confineZmovement();
if (confineXmovement[cpI])
{
derivatives_[cpI] *= scalar(0);
flowSens_[cpI].x() = Zero;
dSdbSens_[cpI].x() = Zero;
dndbSens_[cpI].x() = Zero;
dxdbDirectSens_[cpI].x() = Zero;
bcSens_[cpI].x() = Zero;
}
if (confineYmovement[cpI])
{
derivatives_[cpI + nBezier] *= scalar(0);
flowSens_[cpI].y() = Zero;
dSdbSens_[cpI].y() = Zero;
dndbSens_[cpI].y() = Zero;
dxdbDirectSens_[cpI].y() = Zero;
bcSens_[cpI].y() = Zero;
}
if (confineZmovement[cpI])
{
derivatives_[cpI + 2*nBezier] *= scalar(0);
flowSens_[cpI].z() = Zero;
dSdbSens_[cpI].z() = Zero;
dndbSens_[cpI].z() = Zero;
dxdbDirectSens_[cpI].z() = Zero;
bcSens_[cpI].z() = Zero;
}
}
}
void sensitivityBezier::clearSensitivities()
{
sens_ = Zero;
flowSens_ = Zero;
dSdbSens_ = Zero;
dndbSens_ = Zero;
dxdbDirectSens_ = Zero;
bcSens_ = Zero;
SIBase::clearSensitivities();
}
void sensitivityBezier::write(const word& baseName)
{
Info<< "Writing control point sensitivities to file" << endl;
// Write sensitivity map
SIBase::write(baseName);
// Write control point sensitivities
if (Pstream::master())
{
OFstream derivFile
(
derivativesFolder_/
baseName + adjointVars_.solverName() + mesh_.time().timeName()
);
unsigned int widthDV = max(int(name(sens_.size()).size()), int(3));
unsigned int width = IOstream::defaultPrecision() + 7;
derivFile
<< setw(widthDV) << "#dv" << " "
<< setw(width) << "total" << " "
<< setw(width) << "flow" << " "
<< setw(width) << "dSdb" << " "
<< setw(width) << "dndb" << " "
<< setw(width) << "dxdbDirect" << " "
<< setw(width) << "dvdb" << endl;
label nDV = derivatives_.size();
label nBezier = Bezier_.nBezier();
const boolListList& confineMovement = Bezier_.confineMovement();
label lastActive(-1);
for (label iDV = 0; iDV < nDV; iDV++)
{
label iCP = iDV%nBezier;
label idir = iDV/nBezier;
if (!confineMovement[idir][iCP])
{
if (iDV!=lastActive + 1) derivFile << "\n";
lastActive = iDV;
derivFile
<< setw(widthDV) << iDV << " "
<< setw(width) << derivatives_[iDV] << " "
<< setw(width) << flowSens_[iCP].component(idir) << " "
<< setw(width) << dSdbSens_[iCP].component(idir) << " "
<< setw(width) << dndbSens_[iCP].component(idir) << " "
<< setw(width) << dxdbDirectSens_[iCP].component(idir) << " "
<< setw(width) << bcSens_[iCP].component(idir)
<< endl;
}
}
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,136 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::sensitivityBezier
Description
Calculation of adjoint based sensitivities for Bezier control points
SourceFiles
sensitivityBezier.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_sensitivityBezierIncompressible_H
#define Foam_sensitivityBezierIncompressible_H
#include "primitiveFieldsFwd.H"
#include "volFieldsFwd.H"
#include "pointFieldsFwd.H"
#include "surfaceFieldsFwd.H"
#include "volPointInterpolation.H"
#include "SIBaseIncompressible.H"
#include "primitivePatchInterpolation.H"
#include "deltaBoundary.H"
#include "Bezier.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class sensitivityBezier Declaration
\*---------------------------------------------------------------------------*/
class sensitivityBezier
:
public SIBase
{
protected:
// Protected data
Bezier Bezier_;
vectorField sens_;
vectorField flowSens_;
vectorField dSdbSens_;
vectorField dndbSens_;
vectorField dxdbDirectSens_;
vectorField bcSens_;
fileName derivativesFolder_;
private:
// Private Member Functions
//- No copy construct
sensitivityBezier(const sensitivityBezier&) = delete;
//- No copy assignment
void operator=(const sensitivityBezier&) = delete;
public:
//- Runtime type information
TypeName("Bezier");
// Constructors
//- Construct from components
sensitivityBezier
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
);
//- Destructor
virtual ~sensitivityBezier() = default;
// Member Functions
//- Assemble sensitivities
virtual void assembleSensitivities();
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Write sensitivities to file
virtual void write(const word& baseName = word::null);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif

View File

@ -1,368 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivityBezierFIIncompressible.H"
#include "addToRunTimeSelectionTable.H"
#include "IOmanip.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivityBezierFI, 0);
addToRunTimeSelectionTable
(
adjointSensitivity, sensitivityBezierFI, dictionary
);
// * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * * //
void sensitivityBezierFI::read()
{
// Laplace solution controls
const dictionary dxdbDict = dict_.subOrEmptyDict("dxdbSolver");
meshMovementIters_ = dxdbDict.getOrDefault<label>("iters", 1000);
meshMovementResidualLimit_ =
dxdbDict.getOrDefault<scalar>("tolerance", 1.e-07);
// Read variables related to the adjoint eikonal solver
FIBase::read();
}
tmp<volVectorField> sensitivityBezierFI::solveMeshMovementEqn
(
const label iCP,
const label idir
)
{
read();
tmp<volVectorField> tm(new volVectorField("m", dxdb_));
volVectorField& m = tm.ref();
// SOLVE FOR DXDB
//~~~~~~~~~~~~~~~~
// set boundary conditions
for (const label patchI : sensitivityPatchIDs_)
{
// interpolate parameterization info to faces
tmp<vectorField> tdxidXjFace = Bezier_.dxdbFace(patchI, iCP, idir);
const vectorField& dxidXjFace = tdxidXjFace();
m.boundaryFieldRef()[patchI] == dxidXjFace;
}
// iterate the adjoint to the eikonal equation
for (label iter = 0; iter < meshMovementIters_; iter++)
{
Info<< "Mesh Movement Propagation(direction, CP), ("
<< idir << ", " << iCP << "), Iteration : "<< iter << endl;
fvVectorMatrix mEqn
(
fvm::laplacian(m)
);
// Scalar residual = max(mEqn.solve().initialResidual());
scalar residual = mag(mEqn.solve().initialResidual());
Info<< "Max dxdb " << gMax(mag(m)()) << endl;
mesh_.time().printExecutionTime(Info);
// Check convergence
if (residual < meshMovementResidualLimit_)
{
Info<< "\n***Reached dxdb convergence limit, iteration " << iter
<< "***\n\n";
break;
}
}
return tm;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivityBezierFI::sensitivityBezierFI
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
FIBase(mesh, dict, adjointSolver),
//Bezier_(mesh, dict), // AJH Read locally?
Bezier_(mesh, mesh.lookupObject<IOdictionary>("optimisationDict")),
flowSens_(3*Bezier_.nBezier(), Zero),
dSdbSens_(3*Bezier_.nBezier(), Zero),
dndbSens_(3*Bezier_.nBezier(), Zero),
dxdbDirectSens_(3*Bezier_.nBezier(), Zero),
dVdbSens_(3*Bezier_.nBezier(), Zero),
distanceSens_(3*Bezier_.nBezier(), Zero),
optionsSens_(3*Bezier_.nBezier(), Zero),
bcSens_(3*Bezier_.nBezier(), Zero),
derivativesFolder_("optimisation"/type() + "Derivatives"),
meshMovementIters_(-1),
meshMovementResidualLimit_(1.e-7),
dxdb_
(
variablesSet::autoCreateMeshMovementField
(
mesh,
"mTilda",
dimensionSet(dimLength)
)
)
{
read();
derivatives_ = scalarField(3*Bezier_.nBezier(), Zero),
// Create folder to store sensitivities
mkDir(derivativesFolder_);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void sensitivityBezierFI::assembleSensitivities()
{
// Adjoint to the eikonal equation
autoPtr<volTensorField> distanceSensPtr(nullptr);
if (includeDistance_)
{
// Solver equation
eikonalSolver_->solve();
// Allocate memory and compute grad(dxdb) multiplier
distanceSensPtr.reset
(
createZeroFieldPtr<tensor>
(
mesh_,
"distanceSensPtr",
dimensionSet(0, 2, -3, 0, 0, 0, 0)
)
);
distanceSensPtr() = eikonalSolver_->getFISensitivityTerm()().T();
}
const label nBezier = Bezier_.nBezier();
const label nDVs = 3*nBezier;
for (label iDV = 0; iDV < nDVs; iDV++)
{
label iCP = iDV%nBezier;
label idir = iDV/nBezier;
if
(
(idir == 0 && Bezier_.confineXmovement()[iCP])
|| (idir == 1 && Bezier_.confineYmovement()[iCP])
|| (idir == 2 && Bezier_.confineZmovement()[iCP])
)
{
continue;
}
else
{
// Flow term
// ~~~~~~~~~~~
// compute dxdb and its grad
tmp<volVectorField> tm = solveMeshMovementEqn(iCP, idir);
const volVectorField& m = tm();
volTensorField gradDxDb(fvc::grad(m, "grad(dxdb)"));
flowSens_[iDV] =
gSum
(
(gradDxDb.primitiveField() && gradDxDbMult_.primitiveField())
* mesh_.V()
);
for (const label patchI : sensitivityPatchIDs_)
{
// Contribution from objective function
// term from delta(n dS)/delta b and
// term from delta(n)/delta b
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tmp<vectorField> tdSdb =
Bezier_.dndbBasedSensitivities(patchI, iCP, idir);
const vectorField& dSdb = tdSdb();
tmp<vectorField> tdndb =
Bezier_.dndbBasedSensitivities(patchI, iCP, idir, false);
const vectorField& dndb = tdndb();
dSdbSens_[iDV] += gSum(dSfdbMult_()[patchI] & dSdb);
dndbSens_[iDV] += gSum(dnfdbMult_()[patchI] & dndb);
// Contribution from objective function
// term from delta( x ) / delta b
// Only for objectives directly including
// x, like moments
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
tmp<vectorField> tdxdbFace =
Bezier_.dxdbFace(patchI, iCP, idir);
const vectorField& dxdbFace = tdxdbFace();
dxdbDirectSens_[iDV] +=
gSum(dxdbDirectMult_()[patchI] & dxdbFace);
// Contribution from boundary conditions
bcSens_[iDV] += gSum(bcDxDbMult_()[patchI] & dxdbFace);
}
// Contribution from delta (V) / delta b
// For objectives defined as volume integrals only
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dVdbSens_[iDV] =
gSum
(
divDxDbMult_
* fvc::div(m)().primitiveField()
* mesh_.V()
);
// Distance dependent term
//~~~~~~~~~~~~~~~~~~~~~~~~~
if (includeDistance_)
{
distanceSens_[iDV] =
gSum
(
(
distanceSensPtr().primitiveField()
&& gradDxDb.primitiveField()
)
*mesh_.V()
);
}
// Terms from fvOptions
optionsSens_[iDV] +=
gSum((optionsDxDbMult_ & m.primitiveField())*mesh_.V());
}
// Sum contributions
derivatives_ =
flowSens_
+ dSdbSens_
+ dndbSens_
+ dxdbDirectSens_
+ dVdbSens_
+ distanceSens_
+ optionsSens_
+ bcSens_;
}
}
void sensitivityBezierFI::clearSensitivities()
{
flowSens_ = Zero;
dSdbSens_ = Zero;
dndbSens_ = Zero;
dxdbDirectSens_ = Zero;
dVdbSens_ = Zero;
distanceSens_ = Zero;
optionsSens_ = Zero;
bcSens_ = Zero;
FIBase::clearSensitivities();
}
void sensitivityBezierFI::write(const word& baseName)
{
Info<< "Writing control point sensitivities to file" << endl;
if (Pstream::master())
{
OFstream derivFile
(
derivativesFolder_/
baseName + adjointVars_.solverName() + mesh_.time().timeName()
);
unsigned int widthDV = max(int(name(flowSens_.size()).size()), int(3));
unsigned int width = IOstream::defaultPrecision() + 7;
derivFile
<< setw(widthDV) << "#dv" << " "
<< setw(width) << "total" << " "
<< setw(width) << "flow" << " "
<< setw(width) << "dSdb" << " "
<< setw(width) << "dndb" << " "
<< setw(width) << "dxdbDirect" << " "
<< setw(width) << "dVdb" << " "
<< setw(width) << "distance" << " "
<< setw(width) << "options" << " "
<< setw(width) << "dvdb" << endl;
const label nDVs = derivatives_.size();
const label nBezier = Bezier_.nBezier();
const boolListList& confineMovement = Bezier_.confineMovement();
label lastActive(-1);
for (label iDV = 0; iDV < nDVs; iDV++)
{
const label iCP(iDV%nBezier);
const label idir(iDV/nBezier);
if (!confineMovement[idir][iCP])
{
if (iDV!=lastActive + 1)
{
derivFile << "\n";
}
lastActive = iDV;
derivFile
<< setw(widthDV) << iDV << " "
<< setw(width) << derivatives_[iDV] << " "
<< setw(width) << flowSens_[iDV] << " "
<< setw(width) << dSdbSens_[iDV] << " "
<< setw(width) << dndbSens_[iDV] << " "
<< setw(width) << dxdbDirectSens_[iDV] << " "
<< setw(width) << dVdbSens_[iDV] << " "
<< setw(width) << distanceSens_[iDV] << " "
<< setw(width) << optionsSens_[iDV] << " "
<< setw(width) << bcSens_[iDV] << endl;
}
}
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,168 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::sensitivityBezierFI
Description
Calculation of adjoint based sensitivities for Bezier control points
using the FI appoach
SourceFiles
sensitivityBezierFI.C
\*---------------------------------------------------------------------------*/
#ifndef sensitivityBezierFIIncompressible_H
#define sensitivityBezierFIIncompressible_H
#include "primitiveFieldsFwd.H"
#include "volFieldsFwd.H"
#include "pointFieldsFwd.H"
#include "surfaceFieldsFwd.H"
#include "volPointInterpolation.H"
#include "FIBaseIncompressible.H"
#include "primitivePatchInterpolation.H"
#include "deltaBoundary.H"
#include "Bezier.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class sensitivityBezierFI Declaration
\*---------------------------------------------------------------------------*/
class sensitivityBezierFI
:
public FIBase
{
protected:
// Protected data
Bezier Bezier_;
//- Flow related term
scalarField flowSens_;
//- Term depending on delta(n dS)/delta b
scalarField dSdbSens_;
//- Term depending on delta(n)/delta b
scalarField dndbSens_;
//- Term depending on delta(x)/delta b for objectives that directly
//- depend on x
scalarField dxdbDirectSens_;
//- Term depending on delta(V)/delta b
scalarField dVdbSens_;
//- Term depending on distance differentiation
scalarField distanceSens_;
//- Term depending on fvOptions
scalarField optionsSens_;
//- Term depending on the differenation of boundary conditions
scalarField bcSens_;
fileName derivativesFolder_;
label meshMovementIters_;
scalar meshMovementResidualLimit_;
volVectorField dxdb_;
void read();
tmp<volVectorField> solveMeshMovementEqn
(
const label iCP,
const label idir
);
private:
// Private Member Functions
//- No copy construct
sensitivityBezierFI(const sensitivityBezierFI&) = delete;
//- No copy assignment
void operator=(const sensitivityBezierFI&) = delete;
public:
//- Runtime type information
TypeName("BezierFI");
// Constructors
//- Construct from components
sensitivityBezierFI
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
);
//- Destructor
virtual ~sensitivityBezierFI() = default;
// Member Functions
//- Assemble sensitivities
virtual void assembleSensitivities();
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Write sensitivities to file
virtual void write(const word& baseName = word::null);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,946 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2019-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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivitySurfaceIncompressible.H"
#include "incompressibleAdjointSolver.H"
#include "primitivePatchInterpolation.H"
#include "syncTools.H"
#include "addToRunTimeSelectionTable.H"
#include "faMatrices.H"
#include "famSup.H"
#include "famLaplacian.H"
#include "volSurfaceMapping.H"
#include "fixedValueFaPatchFields.H"
#include "zeroGradientFaPatchFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivitySurface, 1);
addToRunTimeSelectionTable
(
adjointSensitivity,
sensitivitySurface,
dictionary
);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void sensitivitySurface::addGeometricSens()
{
if (includeObjective_)
{
// Grab objective refs
PtrList<objective>& functions
(objectiveManager_.getObjectiveFunctions());
// Compute sens for all points in parameterized patches.
// Interfacing points will be accumulated later
autoPtr<pointBoundaryVectorField> pointSensdSdb
(
createZeroBoundaryPointFieldPtr<vector>(mesh_)
);
autoPtr<pointBoundaryVectorField> pointSensdndb
(
createZeroBoundaryPointFieldPtr<vector>(mesh_)
);
// Geometric (or "direct") sensitivities are better computed directly
// on the points
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
const vectorField nf(patch.nf());
// point sens result for patch
vectorField& patchdSdb = pointSensdSdb()[patchI];
vectorField& patchdndb = pointSensdndb()[patchI];
vectorField dSdbMultiplierTot(patch.size(), Zero);
vectorField dndbMultiplierTot(patch.size(), Zero);
for (auto& fun : functions)
{
dSdbMultiplierTot += fun.weight()*fun.dSdbMultiplier(patchI);
dndbMultiplierTot += fun.weight()*fun.dndbMultiplier(patchI);
}
// Correspondence of local point addressing to global point
// addressing
const labelList& meshPoints = patch.patch().meshPoints();
// List with mesh faces. Global addressing
const faceList& faces = mesh_.faces();
// Each local patch point belongs to these local patch faces
// (local numbering)
const labelListList& patchPointFaces = patch.patch().pointFaces();
// index of first face in patch
const label patchStartIndex = patch.start();
// geometry differentiation engine
deltaBoundary dBoundary(mesh_);
// Loop over patch points.
// Collect contributions from each boundary face this point
// belongs to
forAll(meshPoints, ppI)
{
const labelList& pointFaces = patchPointFaces[ppI];
for (label localFaceIndex : pointFaces)
{
label globalFaceIndex = patchStartIndex + localFaceIndex;
const face& faceI = faces[globalFaceIndex];
// Point coordinates. All indices in global numbering
const pointField p(faceI.points(mesh_.points()));
tensorField p_d(faceI.size(), Zero);
forAll(faceI, facePointI)
{
if (faceI[facePointI] == meshPoints[ppI])
{
p_d[facePointI] = tensor::I;
}
}
const tensorField deltaNormals
(
dBoundary.makeFaceCentresAndAreas_d(p, p_d)
);
// Element [1] is the variation in the (dimensional) normal
const tensor& deltaSf = deltaNormals[1];
patchdSdb[ppI] +=
dSdbMultiplierTot[localFaceIndex] & deltaSf;
// Element [2] is the variation in the unit normal
const tensor& deltaNf = deltaNormals[2];
patchdndb[ppI] +=
dndbMultiplierTot[localFaceIndex] & deltaNf;
}
}
}
// Do parallel communications to avoid wrong values at processor
// boundaries
vectorField dSdbGlobal(mesh_.nPoints(), Zero);
vectorField dndbGlobal(mesh_.nPoints(), Zero);
for (const label patchI : sensitivityPatchIDs_)
{
const labelList& meshPoints =
mesh_.boundaryMesh()[patchI].meshPoints();
forAll(meshPoints, ppI)
{
const label globaPointI = meshPoints[ppI];
dSdbGlobal[globaPointI] += pointSensdSdb()[patchI][ppI];
dndbGlobal[globaPointI] += pointSensdndb()[patchI][ppI];
}
}
// Accumulate over processors
syncTools::syncPointList
(
mesh_, dSdbGlobal, plusEqOp<vector>(), vector::zero
);
syncTools::syncPointList
(
mesh_, dndbGlobal, plusEqOp<vector>(), vector::zero
);
// Transfer back to local fields and map to faces
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
const labelList& meshPoints = patch.patch().meshPoints();
const scalarField& magSf = patch.magSf();
pointSensdSdb()[patchI].map(dSdbGlobal, meshPoints);
pointSensdndb()[patchI].map(dndbGlobal, meshPoints);
// Map dSf/dx and dnf/dx term from points to faces. Ideally, all
// sensitivities should be computed at points rather than faces.
PrimitivePatchInterpolation<polyPatch> patchInter(patch.patch());
vectorField dSdbFace
(
patchInter.pointToFaceInterpolate(pointSensdSdb()[patchI])
);
// dSdb already contains the face area. Divide with it to make it
// compatible with the rest of the terms
dSdbFace /= magSf;
tmp<vectorField> tdndbFace =
patchInter.pointToFaceInterpolate(pointSensdndb()[patchI]);
const vectorField& dndbFace = tdndbFace();
// Add to sensitivity fields
wallFaceSensVecPtr_()[patchI] += dSdbFace + dndbFace;
}
}
}
void sensitivitySurface::setSuffixName()
{
word suffix(dict().getOrDefault<word>("suffix", word::null));
// Determine suffix for fields holding the sens
if (includeMeshMovement_)
{
shapeSensitivitiesBase::setSuffix
(
adjointVars_.solverName() + "ESI" + suffix
);
}
else
{
shapeSensitivitiesBase::setSuffix
(
adjointVars_.solverName() + "SI" + suffix
);
}
}
void sensitivitySurface::smoothSensitivities()
{
// Read in parameters
const label iters(dict().getOrDefault<label>("iters", 500));
const scalar tolerance(dict().getOrDefault<scalar>("tolerance", 1.e-06));
autoPtr<faMesh> aMeshPtr(nullptr);
IOobject faceLabels
(
"faceLabels",
mesh_.time().findInstance
(
mesh_.dbDir()/faMesh::meshSubDir,
"faceLabels",
IOobject::READ_IF_PRESENT
),
faMesh::meshSubDir,
mesh_,
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE
);
// If the faMesh already exists, read it
if (faceLabels.typeHeaderOk<labelIOList>(false))
{
Info<< "Reading the already constructed faMesh" << endl;
aMeshPtr.reset(new faMesh(mesh_));
}
else
{
// Dictionary used to construct the faMesh
dictionary faMeshDefinition;
IOobject faMeshDefinitionDict
(
"faMeshDefinition",
mesh_.time().caseSystem(),
mesh_,
IOobject::MUST_READ,
IOobject::NO_WRITE
);
// If the faMeshDefinitionDict exists, use it to construct the mesh
if (faMeshDefinitionDict.typeHeaderOk<IOdictionary>(false))
{
Info<< "Reading faMeshDefinition from system " << endl;
faMeshDefinition = IOdictionary(faMeshDefinitionDict);
}
// Otherwise, faMesh is generated from all patches on which we compute
// sensitivities
else
{
Info<< "Constructing faMeshDefinition from sensitivity patches"
<< endl;
wordList polyMeshPatches(sensitivityPatchIDs_.size());
label i(0);
for (const label patchID : sensitivityPatchIDs_)
{
polyMeshPatches[i++] = mesh_.boundary()[patchID].name();
}
faMeshDefinition.add<wordList>("polyMeshPatches", polyMeshPatches);
(void)faMeshDefinition.subDictOrAdd("boundary");
}
// Construct faMesh
aMeshPtr.reset(new faMesh(mesh_, faMeshDefinition));
}
faMesh& aMesh = aMeshPtr.ref();
// Physical radius of the smoothing, provided either directly or computed
// based on the average 'length' of boundary faces
const scalar Rphysical
(dict().getOrDefault<scalar>("radius", computeRadius(aMesh)));
DebugInfo
<< "Physical radius of the sensitivity smoothing "
<< Rphysical << nl << endl;
// Radius used as the diffusivity in the Helmholtz filter, computed as a
// function of the physical radius
const dimensionedScalar RpdeSqr
(
"RpdeSqr", dimArea, sqr(Rphysical/(2.*::sqrt(3.)))
);
dimensionedScalar one("1", dimless, 1.);
// Mapping engine
const volSurfaceMapping vsm(aMesh);
// Source term in faMatrix needs to be an areaField
areaScalarField sens
(
IOobject
(
"sens",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
aMesh,
dimensionedScalar(dimless, Zero),
faPatchFieldBase::zeroGradientType()
);
// Copy sensitivities to area field
sens.primitiveFieldRef() =
vsm.mapToSurface<scalar>(wallFaceSensNormalPtr_());
// Initialisation of the smoothed sensitivities field based on the original
// sensitivities
areaScalarField smoothedSens("smoothedSens", sens);
for (label iter = 0; iter < iters; ++iter)
{
Info<< "Sensitivity smoothing iteration " << iter << endl;
faScalarMatrix smoothEqn
(
fam::Sp(one, smoothedSens)
- fam::laplacian(RpdeSqr, smoothedSens)
==
sens
);
smoothEqn.relax();
const scalar residual(mag(smoothEqn.solve().initialResidual()));
DebugInfo
<< "Max smoothSens " << gMax(mag(smoothedSens)()) << endl;
// Print execution time
mesh_.time().printExecutionTime(Info);
// Check convergence
if (residual < tolerance)
{
Info<< "\n***Reached smoothing equation convergence limit, "
"iteration " << iter << "***\n\n";
break;
}
}
// Field used to write the smoothed sensitivity field to file
volScalarField volSmoothedSens
(
IOobject
(
"smoothedSurfaceSens" + surfaceFieldSuffix_,
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(dimless, Zero)
);
// Transfer result back to volField and write
vsm.mapToVolume(smoothedSens, volSmoothedSens.boundaryFieldRef());
volSmoothedSens.write();
}
scalar sensitivitySurface::computeRadius(const faMesh& aMesh)
{
scalar averageArea(gAverage(aMesh.S().field()));
const Vector<label>& geometricD = mesh_.geometricD();
const boundBox& bounds = mesh_.bounds();
forAll(geometricD, iDir)
{
if (geometricD[iDir] == -1)
{
averageArea /= bounds.span()[iDir];
}
}
scalar mult = dict().getOrDefault<scalar>("meanRadiusMultiplier", 10);
return mult*pow(averageArea, scalar(1)/scalar(mesh_.nGeometricD() - 1));
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivitySurface::sensitivitySurface
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
adjointSensitivity(mesh, dict, adjointSolver),
shapeSensitivitiesBase(mesh, dict),
includeSurfaceArea_(false),
includePressureTerm_(false),
includeGradStressTerm_(false),
includeTransposeStresses_(false),
useSnGradInTranposeStresses_(false),
includeDivTerm_(false),
includeDistance_(false),
includeMeshMovement_(false),
includeObjective_(false),
writeGeometricInfo_(false),
smoothSensitivities_(false),
eikonalSolver_(nullptr),
meshMovementSolver_(nullptr),
nfOnPatchPtr_(nullptr),
SfOnPatchPtr_(nullptr),
CfOnPatchPtr_(nullptr)
{
read();
setSuffixName();
// Allocate boundary field pointer
wallFaceSensVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
wallFaceSensNormalPtr_.reset(createZeroBoundaryPtr<scalar>(mesh_));
wallFaceSensNormalVecPtr_.reset(createZeroBoundaryPtr<vector>(mesh_));
// Allocate fields to contain geometric info
if (writeGeometricInfo_)
{
nfOnPatchPtr_.reset
(
new volVectorField
(
IOobject
(
"nfOnPatch",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh,
vector::zero
)
);
SfOnPatchPtr_.reset
(
new volVectorField
(
IOobject
(
"SfOnPatch",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh,
vector::zero
)
);
CfOnPatchPtr_.reset
(
new volVectorField
(
IOobject
(
"CfOnPatch",
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh,
vector::zero
)
);
}
// Allocate appropriate space for the sensitivity field
computeDerivativesSize();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void sensitivitySurface::read()
{
includeSurfaceArea_ =
dict().getOrDefault<bool>("includeSurfaceArea", true);
includePressureTerm_ =
dict().getOrDefault<bool>("includePressure", true);
includeGradStressTerm_ =
dict().getOrDefault<bool>("includeGradStressTerm", true);
includeTransposeStresses_ =
dict().getOrDefault<bool>("includeTransposeStresses", true);
useSnGradInTranposeStresses_ =
dict().getOrDefault<bool>("useSnGradInTranposeStresses", false);
includeDivTerm_ = dict().getOrDefault<bool>("includeDivTerm", false);
includeDistance_ =
dict().getOrDefault<bool>
(
"includeDistance",
adjointVars_.adjointTurbulence().ref().includeDistance()
);
includeMeshMovement_ =
dict().getOrDefault<bool>("includeMeshMovement", true);
includeObjective_ =
dict().getOrDefault<bool>("includeObjectiveContribution", true);
writeGeometricInfo_ =
dict().getOrDefault<bool>("writeGeometricInfo", false);
smoothSensitivities_ =
dict().getOrDefault<bool>("smoothSensitivities", false);
// Allocate new solvers if necessary
if (includeDistance_ && !eikonalSolver_)
{
eikonalSolver_.reset
(
new adjointEikonalSolver
(
mesh_,
dict_,
primalVars_.RASModelVariables(),
adjointVars_,
sensitivityPatchIDs_
)
);
}
if (includeMeshMovement_ && !meshMovementSolver_)
{
meshMovementSolver_.reset
(
new adjointMeshMovementSolver
(
mesh_,
dict_,
*this,
sensitivityPatchIDs_,
eikonalSolver_
)
);
}
}
bool sensitivitySurface::readDict(const dictionary& dict)
{
if (sensitivity::readDict(dict))
{
if (eikonalSolver_)
{
eikonalSolver_().readDict(dict);
}
if (meshMovementSolver_)
{
meshMovementSolver_().readDict(dict);
}
return true;
}
return false;
}
void sensitivitySurface::computeDerivativesSize()
{
label nFaces(0);
for (const label patchI : sensitivityPatchIDs_)
{
nFaces += mesh_.boundary()[patchI].size();
}
derivatives_.setSize(nFaces);
}
void sensitivitySurface::accumulateIntegrand(const scalar dt)
{
// Grab references
const volScalarField& p = primalVars_.p();
const volVectorField& U = primalVars_.U();
const volScalarField& pa = adjointVars_.pa();
const volVectorField& Ua = adjointVars_.Ua();
autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence =
adjointVars_.adjointTurbulence();
// Accumulate source for additional post-processing PDEs, if necessary
if (includeDistance_)
{
eikonalSolver_->accumulateIntegrand(dt);
}
if (includeMeshMovement_)
{
meshMovementSolver_->accumulateIntegrand(dt);
}
// Terms from the adjoint turbulence model
const boundaryVectorField& adjointTMsensitivities =
adjointTurbulence->wallShapeSensitivities();
DebugInfo
<< " Calculating adjoint sensitivity. " << endl;
tmp<volScalarField> tnuEff = adjointTurbulence->nuEff();
const volScalarField& nuEff = tnuEff.ref();
// Sensitivities do not include locale surface area by default.
// The part of the sensitivities that multiplies dxFace/db follows
// Deal with the stress part first since it's the most awkward in terms
// of memory managment
if (includeGradStressTerm_)
{
// Terms corresponding to contributions from converting delta
// to thetas are added through the corresponding adjoint
// boundary conditions instead of grabbing contributions from
// the objective function. Useful to have a unified
// formulation for low- and high-re meshes
tmp<volVectorField> tgradp = fvc::grad(p);
const volVectorField& gradp = tgradp.ref();
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
wallFaceSensVecPtr_()[patchI] -=
(Uab & tnf)*gradp.boundaryField()[patchI]*dt;
}
tgradp.clear();
// We only need to modify the boundaryField of gradU locally.
// If grad(U) is cached then
// a. The .ref() call fails since the tmp is initialised from a
// const ref
// b. we would be changing grad(U) for all other places in the code
// that need it
// So, always allocate new memory and avoid registering the new field
tmp<volTensorField> tgradU =
volTensorField::New("gradULocal", fvc::grad(U));
volTensorField::Boundary& gradUbf = tgradU.ref().boundaryFieldRef();
// Explicitly correct the boundary gradient to get rid of the
// tangential component
forAll(mesh_.boundary(), patchI)
{
const fvPatch& patch = mesh_.boundary()[patchI];
if (isA<wallFvPatch>(patch))
{
tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
gradUbf[patchI] = tnf*U.boundaryField()[patchI].snGrad();
}
}
tmp<volSymmTensorField> tstress = nuEff*twoSymm(tgradU);
const volSymmTensorField& stress = tstress.cref();
autoPtr<volVectorField> ptemp
(Foam::createZeroFieldPtr<vector>(mesh_, "temp", sqr(dimVelocity)));
volVectorField& temp = ptemp.ref();
for (label idir = 0; idir < pTraits<vector>::nComponents; ++idir)
{
unzipRow(stress, idir, temp);
volTensorField gradStressDir(fvc::grad(temp));
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
wallFaceSensVecPtr_()[patchI] +=
(
Uab.component(idir)
*(gradStressDir.boundaryField()[patchI] & tnf)
)*dt;
}
}
}
// Transpose part of the adjoint stresses
// Dealt with separately to deallocate gradUa as soon as possible
if (includeTransposeStresses_)
{
tmp<volTensorField> tgradUa = fvc::grad(Ua);
const volTensorField::Boundary& gradUabf =
tgradUa.cref().boundaryField();
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const vectorField& nf = tnf();
vectorField gradUaNf
(
useSnGradInTranposeStresses_
? (Ua.boundaryField()[patchI].snGrad() & nf)*nf
: (gradUabf[patchI] & nf)
);
wallFaceSensVecPtr_()[patchI] -=
nuEff.boundaryField()[patchI]
*(gradUaNf & U.boundaryField()[patchI].snGrad())*nf;
}
}
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const vectorField& nf = tnf();
// Includes spurious tangential gradU part. Deprecated
/*
vectorField stressAndPressureTerm =
(
- (
Ua.boundaryField()[patchI].snGrad()
+ (gradUa.boundaryField()[patchI] & nf)
) * nuEff.boundaryField()[patchI]
+ pa.boundaryField()[patchI] *nf
) & gradU.boundaryField()[patchI].T();
*/
// Adjoint stress term
vectorField stressTerm
(
- (
Ua.boundaryField()[patchI].snGrad()
& U.boundaryField()[patchI].snGrad()
)
* nuEff.boundaryField()[patchI]
* nf
);
if (includeDivTerm_)
{
stressTerm +=
scalar(1./3.)*nuEff.boundaryField()[patchI]
* (
((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
& U.boundaryField()[patchI].snGrad()
)
* nf;
}
// Adjoint pressure terms
vectorField pressureTerm(patch.size(), Zero);
if (includePressureTerm_)
{
pressureTerm =
(
(nf*pa.boundaryField()[patchI])
& U.boundaryField()[patchI].snGrad()
)* nf;
}
PtrList<objective>& functions
(objectiveManager_.getObjectiveFunctions());
// Term from objectives including x directly (e.g. moments)
vectorField dxdbMultiplierTot(pressureTerm.size(), Zero);
if (includeObjective_)
{
forAll(functions, funcI)
{
dxdbMultiplierTot +=
functions[funcI].weight()
* (
functions[funcI].dxdbDirectMultiplier(patchI)
);
}
}
// Fill in sensitivity fields
wallFaceSensVecPtr_()[patchI] +=
(
stressTerm
+ pressureTerm
+ adjointTMsensitivities[patchI]
+ dxdbMultiplierTot
)*dt;
}
// Add terms from physics other than the typical incompressible flow eqns
adjointSolver_.additionalSensitivityMapTerms
(wallFaceSensVecPtr_(), sensitivityPatchIDs_, dt);
// Add the sensitivity part corresponding to changes of the normal vector
// Computed at points and mapped to faces
addGeometricSens();
}
void sensitivitySurface::assembleSensitivities()
{
// Update geometric fields for use by external users
if (writeGeometricInfo_)
{
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const vectorField& nf = tnf();
const vectorField& Sf = patch.Sf();
const vectorField& Cf = patch.Cf();
nfOnPatchPtr_().boundaryFieldRef()[patchI] = nf;
SfOnPatchPtr_().boundaryFieldRef()[patchI] = Sf;
CfOnPatchPtr_().boundaryFieldRef()[patchI] = Cf;
}
}
// Solve extra equations if necessary
// Solved using accumulated sources over time
autoPtr<boundaryVectorField> distanceSensPtr(nullptr);
if (includeDistance_)
{
eikonalSolver_->solve();
distanceSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
const boundaryVectorField& sens =
eikonalSolver_->distanceSensitivities();
for (const label patchI : sensitivityPatchIDs_)
{
distanceSensPtr()[patchI] = sens[patchI];
}
}
autoPtr<boundaryVectorField> meshMovementSensPtr(nullptr);
if (includeMeshMovement_)
{
meshMovementSolver_->solve();
meshMovementSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
const boundaryVectorField& sens =
meshMovementSolver_->meshMovementSensitivities();
for (const label patchI : sensitivityPatchIDs_)
{
meshMovementSensPtr()[patchI] = sens[patchI];
}
}
// Project to normal face vector
label nPassedFaces(0);
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf(patch.nf());
const vectorField& nf = tnf();
// Distance related terms
if (includeDistance_)
{
wallFaceSensVecPtr_()[patchI] += distanceSensPtr()[patchI];
}
// Mesh movement related terms
if (includeMeshMovement_)
{
wallFaceSensVecPtr_()[patchI] += meshMovementSensPtr()[patchI];
}
if (includeSurfaceArea_)
{
wallFaceSensVecPtr_()[patchI] *= patch.magSf();
}
wallFaceSensNormalPtr_()[patchI] = wallFaceSensVecPtr_()[patchI] & nf;
wallFaceSensNormalVecPtr_()[patchI] =
wallFaceSensNormalPtr_()[patchI] * nf;
forAll(patch, fI)
{
derivatives_[nPassedFaces + fI]
= wallFaceSensNormalPtr_()[patchI][fI];
}
nPassedFaces += patch.size();
}
// Smooth sensitivities if needed
if (smoothSensitivities_)
{
smoothSensitivities();
}
}
void sensitivitySurface::clearSensitivities()
{
// Reset terms in post-processing PDEs
if (includeDistance_)
{
eikonalSolver_->reset();
}
if (includeMeshMovement_)
{
meshMovementSolver_->reset();
}
// Reset sensitivity fields
adjointSensitivity::clearSensitivities();
shapeSensitivitiesBase::clearSensitivities();
}
autoPtr<adjointEikonalSolver>& sensitivitySurface::getAdjointEikonalSolver()
{
return eikonalSolver_;
}
void sensitivitySurface::write(const word& baseName)
{
setSuffixName();
adjointSensitivity::write();
shapeSensitivitiesBase::write();
if (writeGeometricInfo_)
{
nfOnPatchPtr_().write();
SfOnPatchPtr_().write();
CfOnPatchPtr_().write();
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
} // End namespace incompressible
// ************************************************************************* //

View File

@ -1,773 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020, 2022 PCOpt/NTUA
Copyright (C) 2013-2020, 2022 FOSS GP
Copyright (C) 2019-2022 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivitySurfacePointsIncompressible.H"
#include "incompressibleAdjointSolver.H"
#include "addToRunTimeSelectionTable.H"
#include "syncTools.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivitySurfacePoints, 0);
addToRunTimeSelectionTable
(
adjointSensitivity,
sensitivitySurfacePoints,
dictionary
);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void sensitivitySurfacePoints::read()
{
includeSurfaceArea_ =
dict().getOrDefault<bool>("includeSurfaceArea", false);
includePressureTerm_ =
dict().getOrDefault<bool>("includePressure", true);
includeGradStressTerm_ =
dict().getOrDefault<bool>("includeGradStressTerm", true);
includeTransposeStresses_ =
dict().getOrDefault<bool>("includeTransposeStresses", true);
useSnGradInTranposeStresses_ =
dict().getOrDefault<bool>("useSnGradInTranposeStresses", false);
includeDivTerm_ =
dict().getOrDefault<bool>("includeDivTerm", false);
includeDistance_ =
dict().getOrDefault<bool>
(
"includeDistance",
adjointVars_.adjointTurbulence().ref().includeDistance()
);
includeMeshMovement_ =
dict().getOrDefault<bool>("includeMeshMovement", true);
includeObjective_ =
dict().getOrDefault<bool>("includeObjectiveContribution", true);
// Allocate new solvers if necessary
if (includeDistance_ && !eikonalSolver_)
{
eikonalSolver_.reset
(
new adjointEikonalSolver
(
mesh_,
dict(),
primalVars_.RASModelVariables(),
adjointVars_,
sensitivityPatchIDs_
)
);
}
if (includeMeshMovement_ && !meshMovementSolver_)
{
meshMovementSolver_.reset
(
new adjointMeshMovementSolver
(
mesh_,
dict(),
*this,
sensitivityPatchIDs_,
eikonalSolver_
)
);
}
}
void sensitivitySurfacePoints::finaliseFaceMultiplier()
{
// Solve extra equations if necessary
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr<boundaryVectorField> distanceSensPtr(nullptr);
if (includeDistance_)
{
eikonalSolver_->solve();
distanceSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
const boundaryVectorField& sens =
eikonalSolver_->distanceSensitivities();
for (const label patchI : sensitivityPatchIDs_)
{
distanceSensPtr()[patchI] = sens[patchI];
}
}
autoPtr<boundaryVectorField> meshMovementSensPtr(nullptr);
if (includeMeshMovement_)
{
meshMovementSolver_->solve();
meshMovementSensPtr.reset(createZeroBoundaryPtr<vector>(mesh_));
const boundaryVectorField& sens =
meshMovementSolver_->meshMovementSensitivities();
for (const label patchI : sensitivityPatchIDs_)
{
meshMovementSensPtr()[patchI] = sens[patchI];
}
}
// Add to other terms multiplying dxFace/dxPoints
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const scalarField& magSf = patch.magSf();
// Distance related terms
if (includeDistance_)
{
wallFaceSens_()[patchI] += distanceSensPtr()[patchI];
}
// Mesh movement related terms
if (includeMeshMovement_)
{
wallFaceSens_()[patchI] += meshMovementSensPtr()[patchI];
}
// Add local face area
//~~~~~~~~~~~~~~~~~~~~
// Sensitivities DO include locale surface area, to get
// the correct weighting from the contributions of various faces.
// Normalized at the end.
// dSfdbMult already includes the local area. No need to re-multiply
wallFaceSens_()[patchI] *= magSf;
dnfdbMult_()[patchI] *= magSf;
}
}
void sensitivitySurfacePoints::finalisePointSensitivities()
{
// Geometric (or "direct") sensitivities are better computed directly on
// the points. Compute them and add the ones that depend on dxFace/dxPoint
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
vectorField nf(patch.nf());
// Point sens result for patch
vectorField& pointPatchSens = wallPointSensVecPtr_()[patchI];
// Face sens for patch
const vectorField& facePatchSens = wallFaceSens_()[patchI];
// Geometry variances
const vectorField& dSfdbMultPatch = dSfdbMult_()[patchI];
const vectorField& dnfdbMultPatch = dnfdbMult_()[patchI];
// Correspondance of local point addressing to global point addressing
const labelList& meshPoints = patch.patch().meshPoints();
// List with mesh faces. Global addressing
const faceList& faces = mesh_.faces();
// Each local patch point belongs to these local patch faces
// (local numbering)
const labelListList& patchPointFaces = patch.patch().pointFaces();
// Index of first face in patch
const label patchStartIndex = patch.start();
// Geometry differentiation engine
deltaBoundary dBoundary(mesh_);
// Loop over patch points.
// Collect contributions from each boundary face this point belongs to
forAll(meshPoints, ppI)
{
const labelList& pointFaces = patchPointFaces[ppI];
forAll(pointFaces, pfI)
{
label localFaceIndex = pointFaces[pfI];
label globalFaceIndex = patchStartIndex + localFaceIndex;
const face& faceI = faces[globalFaceIndex];
// Point coordinates. All indices in global numbering
pointField p(faceI.points(mesh_.points()));
tensorField p_d(faceI.size(), Zero);
forAll(faceI, facePointI)
{
if (faceI[facePointI] == meshPoints[ppI])
{
p_d[facePointI] = tensor::I;
}
}
tensorField deltaNormals =
dBoundary.makeFaceCentresAndAreas_d(p, p_d);
// Element [0] is the variation in the face center
// (dxFace/dxPoint)
const tensor& deltaCf = deltaNormals[0];
pointPatchSens[ppI] += facePatchSens[localFaceIndex] & deltaCf;
// Term multiplying d(Sf)/d(point displacement) and
// d(nf)/d(point displacement)
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (includeObjective_)
{
// Element [1] is the variation in the (dimensional) normal
const tensor& deltaSf = deltaNormals[1];
pointPatchSens[ppI] +=
dSfdbMultPatch[localFaceIndex] & deltaSf;
// Element [2] is the variation in the unit normal
const tensor& deltaNf = deltaNormals[2];
pointPatchSens[ppI] +=
dnfdbMultPatch[localFaceIndex] & deltaNf;
}
}
}
}
}
void sensitivitySurfacePoints::constructGlobalPointNormalsAndAreas
(
vectorField& pointNormals,
scalarField& pointMagSf
)
{
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
const scalarField& magSf = patch.magSf();
vectorField nf(patch.nf());
// Correspondance of local point addressing to global point addressing
const labelList& meshPoints = patch.patch().meshPoints();
// Each local patch point belongs to these local patch faces
// (local numbering)
const labelListList& patchPointFaces = patch.patch().pointFaces();
// Loop over patch points
forAll(meshPoints, ppI)
{
const labelList& pointFaces = patchPointFaces[ppI];
forAll(pointFaces, pfI)
{
const label localFaceIndex = pointFaces[pfI];
// Accumulate information for point normals
pointNormals[meshPoints[ppI]] += nf[localFaceIndex];
pointMagSf[meshPoints[ppI]] += magSf[localFaceIndex];
}
}
}
syncTools::syncPointList
(
mesh_,
pointNormals,
plusEqOp<vector>(),
vector::zero
);
syncTools::syncPointList
(
mesh_,
pointMagSf,
plusEqOp<scalar>(),
scalar(0)
);
}
void sensitivitySurfacePoints::setSuffixName()
{
word suffix(dict().getOrDefault<word>("suffix", word::null));
// Determine suffix for fields holding the sens
if (includeMeshMovement_)
{
shapeSensitivitiesBase::setSuffix
(
adjointVars_.solverName() + "ESI" + suffix
);
}
else
{
shapeSensitivitiesBase::setSuffix
(
adjointVars_.solverName() + "SI" + suffix
);
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivitySurfacePoints::sensitivitySurfacePoints
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
adjointSensitivity(mesh, dict, adjointSolver),
shapeSensitivitiesBase(mesh, dict),
includeSurfaceArea_(false),
includePressureTerm_(false),
includeGradStressTerm_(false),
includeTransposeStresses_(false),
useSnGradInTranposeStresses_(false),
includeDivTerm_(false),
includeDistance_(false),
includeMeshMovement_(false),
includeObjective_(false),
eikonalSolver_(nullptr),
meshMovementSolver_(nullptr),
wallFaceSens_(createZeroBoundaryPtr<vector>(mesh_)),
dSfdbMult_(createZeroBoundaryPtr<vector>(mesh_)),
dnfdbMult_(createZeroBoundaryPtr<vector>(mesh_))
{
read();
// Allocate boundary field pointer
wallPointSensVecPtr_.reset(createZeroBoundaryPointFieldPtr<vector>(mesh_));
wallPointSensNormalPtr_.reset
(
createZeroBoundaryPointFieldPtr<scalar>(mesh_)
);
wallPointSensNormalVecPtr_.reset
(
createZeroBoundaryPointFieldPtr<vector>(mesh_)
);
// Allocate appropriate space for sensitivities
label nTotalPoints(0);
for (const label patchI : sensitivityPatchIDs_)
{
nTotalPoints += mesh_.boundaryMesh()[patchI].nPoints();
}
reduce(nTotalPoints, sumOp<label>());
// Derivatives for all (x,y,z) components of the displacement are kept
derivatives_ = scalarField(3*nTotalPoints, Zero);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool sensitivitySurfacePoints::readDict(const dictionary& dict)
{
if (sensitivity::readDict(dict))
{
if (eikonalSolver_)
{
eikonalSolver_().readDict(dict);
}
if (meshMovementSolver_)
{
meshMovementSolver_().readDict(dict);
}
return true;
}
return false;
}
void sensitivitySurfacePoints::accumulateIntegrand(const scalar dt)
{
// Grab references
const volScalarField& p = primalVars_.p();
const volVectorField& U = primalVars_.U();
const volScalarField& pa = adjointVars_.pa();
const volVectorField& Ua = adjointVars_.Ua();
autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence =
adjointVars_.adjointTurbulence();
// Solve extra equations if necessary
if (includeDistance_)
{
eikonalSolver_->accumulateIntegrand(dt);
}
if (includeMeshMovement_)
{
meshMovementSolver_->accumulateIntegrand(dt);
}
// Terms from the adjoint turbulence model
const boundaryVectorField& adjointTMsensitivities =
adjointTurbulence->wallShapeSensitivities();
// Objective references
PtrList<objective>& functions(objectiveManager_.getObjectiveFunctions());
DebugInfo
<< " Calculating adjoint sensitivity. " << endl;
tmp<volScalarField> tnuEff = adjointTurbulence->nuEff();
const volScalarField& nuEff = tnuEff.ref();
// Deal with the stress part first since it's the most awkward in terms
// of memory managment
if (includeGradStressTerm_)
{
// Terms corresponding to contributions from converting delta
// to thetas are added through the corresponding adjoint
// boundary conditions instead of grabbing contributions from
// the objective function. Useful to have a unified
// formulation for low- and high-re meshes
tmp<volVectorField> tgradp = fvc::grad(p);
const volVectorField& gradp = tgradp.ref();
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
wallFaceSens_()[patchI] -=
(Uab & tnf)*gradp.boundaryField()[patchI]*dt;
}
tgradp.clear();
// We only need to modify the boundaryField of gradU locally.
// If grad(U) is cached then
// a. The .ref() call fails since the tmp is initialised from a
// const ref
// b. we would be changing grad(U) for all other places in the code
// that need it
// So, always allocate new memory and avoid registering the new field
tmp<volTensorField> tgradU =
volTensorField::New("gradULocal", fvc::grad(U));
volTensorField::Boundary& gradUbf = tgradU.ref().boundaryFieldRef();
// Explicitly correct the boundary gradient to get rid of the
// tangential component
forAll(mesh_.boundary(), patchI)
{
const fvPatch& patch = mesh_.boundary()[patchI];
if (isA<wallFvPatch>(patch))
{
tmp<vectorField> tnf = mesh_.boundary()[patchI].nf();
gradUbf[patchI] = tnf*U.boundaryField()[patchI].snGrad();
}
}
tmp<volSymmTensorField> tstress = nuEff*twoSymm(tgradU);
const volSymmTensorField& stress = tstress.cref();
autoPtr<volVectorField> ptemp
(Foam::createZeroFieldPtr<vector>(mesh_, "temp", sqr(dimVelocity)));
volVectorField& temp = ptemp.ref();
for (label idir = 0; idir < pTraits<vector>::nComponents; ++idir)
{
unzipRow(stress, idir, temp);
volTensorField gradStressDir(fvc::grad(temp));
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const fvPatchVectorField& Uab = Ua.boundaryField()[patchI];
wallFaceSens_()[patchI] +=
(
Uab.component(idir)
*(gradStressDir.boundaryField()[patchI] & tnf)
)*dt;
}
}
}
// Transpose part of the adjoint stresses
// Dealt with separately to deallocate gradUa as soon as possible
if (includeTransposeStresses_)
{
tmp<volTensorField> tgradUa = fvc::grad(Ua);
const volTensorField::Boundary& gradUabf =
tgradUa.cref().boundaryField();
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const vectorField& nf = tnf();
vectorField gradUaNf
(
useSnGradInTranposeStresses_
? (Ua.boundaryField()[patchI].snGrad() & nf)*nf
: (gradUabf[patchI] & nf)
);
wallFaceSens_()[patchI] -=
nuEff.boundaryField()[patchI]
*(gradUaNf & U.boundaryField()[patchI].snGrad())*tnf;
}
}
// The face-based part of the sensitivities, i.e. terms that multiply
// dxFace/dxPoint.
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = mesh_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const vectorField& nf = tnf();
// Adjoint stress term
// vectorField stressTerm
// (
// -(nf & DUa.boundaryField()[patchI])
// *nuEff.boundaryField()[patchI]
// & gradU.boundaryField()[patchI].T();
// )
vectorField stressTerm
(
- (
Ua.boundaryField()[patchI].snGrad()
& U.boundaryField()[patchI].snGrad()
)
* nuEff.boundaryField()[patchI]
* nf
);
if (includeDivTerm_)
{
stressTerm +=
scalar(1./3.)*nuEff.boundaryField()[patchI]
* (
((Ua.boundaryField()[patchI].snGrad() &nf)*nf)
& U.boundaryField()[patchI].snGrad()
)
*nf;
}
// Adjoint pressure terms
vectorField pressureTerm(patch.size(), Zero);
if (includePressureTerm_)
{
pressureTerm =
(
(nf*pa.boundaryField()[patchI])
& U.boundaryField()[patchI].snGrad()
)
*nf;
}
vectorField dxdbMultiplierTot(patch.size(), Zero);
if (includeObjective_)
{
// Term from objectives multiplying dxdb
forAll(functions, funcI)
{
const scalar wei = functions[funcI].weight();
// dt added in wallFaceSens_
dxdbMultiplierTot +=
wei*functions[funcI].dxdbDirectMultiplier(patchI);
// Fill in multipliers of d(Sf)/db and d(nf)/db
dSfdbMult_()[patchI] +=
wei*dt*functions[funcI].dSdbMultiplier(patchI);
dnfdbMult_()[patchI] +=
wei*dt*functions[funcI].dndbMultiplier(patchI);
}
}
// Fill in dxFace/dxPoint multiplier.
// Missing geometric contributions which are directly computed on the
// points
wallFaceSens_()[patchI] +=
(
stressTerm
+ pressureTerm
+ adjointTMsensitivities[patchI]
+ dxdbMultiplierTot
)*dt;
}
// Add terms from physics other than the typical incompressible flow eqns
adjointSolver_.additionalSensitivityMapTerms
(wallFaceSens_(), sensitivityPatchIDs_, dt);
}
void sensitivitySurfacePoints::assembleSensitivities()
{
// Add remaining parts to term multiplying dxFace/dxPoints
// Solves for post-processing PDEs
finaliseFaceMultiplier();
// Geometric (or "direct") sensitivities are better computed directly on
// the points. Compute them and add the ones that depend on dxFace/dxPoint
finalisePointSensitivities();
// polyPatch::pointNormals will give the wrong result for points
// belonging to multiple patches or patch-processorPatch intersections.
// Keeping a mesh-wide field to allow easy reduction using syncTools.
// A bit expensive? Better way?
vectorField pointNormals(mesh_.nPoints(), Zero);
scalarField pointMagSf(mesh_.nPoints(), Zero);
constructGlobalPointNormalsAndAreas(pointNormals, pointMagSf);
// Do parallel communications to avoid wrong values at processor boundaries
// Global field for accumulation
vectorField pointSensGlobal(mesh_.nPoints(), Zero);
for (const label patchI : sensitivityPatchIDs_)
{
const labelList& meshPoints = mesh_.boundaryMesh()[patchI].meshPoints();
forAll(meshPoints, ppI)
{
const label globaPointI = meshPoints[ppI];
pointSensGlobal[globaPointI] +=
wallPointSensVecPtr_()[patchI][ppI];
}
}
// Accumulate dJ/dx_i
syncTools::syncPointList
(
mesh_,
pointSensGlobal,
plusEqOp<vector>(),
vector::zero
);
// Transfer back to local fields
for (const label patchI : sensitivityPatchIDs_)
{
const labelList& meshPoints =
mesh_.boundaryMesh()[patchI].meshPoints();
wallPointSensVecPtr_()[patchI].map(pointSensGlobal, meshPoints);
}
// Compute normal sens and append to return field
label nPassedDVs(0);
for (const label patchI : sensitivityPatchIDs_)
{
const polyPatch& patch = mesh_.boundaryMesh()[patchI];
List<scalarField> procPatchSens(Pstream::nProcs());
//if (patch.size()>0)
{
const labelList& meshPoints = patch.meshPoints();
// Avoid storing unit point normals in the global list since we
// might divide multiple times with the number of faces belonging
// to the point. Instead do the division locally, per patch use
vectorField patchPointNormals(pointNormals, meshPoints);
patchPointNormals /= mag(patchPointNormals) + VSMALL;
if (!includeSurfaceArea_)
{
wallPointSensVecPtr_()[patchI] /=
scalarField(pointMagSf, meshPoints);
}
wallPointSensNormalPtr_()[patchI] =
wallPointSensVecPtr_()[patchI]
& patchPointNormals;
wallPointSensNormalVecPtr_()[patchI] =
wallPointSensNormalPtr_()[patchI]
*patchPointNormals;
// 1. Gather sens from all processors for this patch and communicate
// them back. Potentially large memory overhead but the rest of the
// code structure assumes that all procs know all sensitivity
// derivatives
//
// 2. Transfer vectorial sensitivities to scalarField.
// Needed since the normal point vector is wrongly computed at patch
// boundaries and cannot be used to reconstruct a vectorial movement
// from just its normal component
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
procPatchSens[Pstream::myProcNo()].setSize
(
3*wallPointSensNormalVecPtr_()[patchI].size()
);
scalarField& patchScalarSens = procPatchSens[Pstream::myProcNo()];
forAll(wallPointSensNormalVecPtr_()[patchI], ptI)
{
patchScalarSens[3*ptI] =
wallPointSensNormalVecPtr_()[patchI][ptI].x();
patchScalarSens[3*ptI + 1] =
wallPointSensNormalVecPtr_()[patchI][ptI].y();
patchScalarSens[3*ptI + 2] =
wallPointSensNormalVecPtr_()[patchI][ptI].z();
}
Pstream::allGatherList(procPatchSens);
forAll(procPatchSens, procI)
{
const scalarField& procSens = procPatchSens[procI];
forAll(procSens, dvI)
{
derivatives_[nPassedDVs + dvI] = procSens[dvI];
}
nPassedDVs += procSens.size();
}
}
}
}
void sensitivitySurfacePoints::clearSensitivities()
{
// Reset terms in post-processing PDEs
if (includeDistance_)
{
eikonalSolver_->reset();
}
if (includeMeshMovement_)
{
meshMovementSolver_->reset();
}
// Reset local fields to zero
wallFaceSens_() = vector::zero;
dSfdbMult_() = vector::zero;
dnfdbMult_() = vector::zero;
// Reset sensitivity fields
adjointSensitivity::clearSensitivities();
shapeSensitivitiesBase::clearSensitivities();
}
void sensitivitySurfacePoints::write(const word& baseName)
{
setSuffixName();
adjointSensitivity::write();
shapeSensitivitiesBase::write();
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
} // End namespace incompressible
// ************************************************************************* //

View File

@ -1,346 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivityVolBSplinesIncompressible.H"
#include "addToRunTimeSelectionTable.H"
#include "IOmanip.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivityVolBSplines, 0);
addToRunTimeSelectionTable
(
adjointSensitivity,
sensitivityVolBSplines,
dictionary
);
// * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * * //
void sensitivityVolBSplines::computeObjectiveContributions()
{
if (includeObjective_)
{
label passedCPs = 0;
PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
forAll(boxes, iNURB)
{
label nb = boxes[iNURB].getControlPoints().size();
for (label cpI = 0; cpI < nb; cpI++)
{
vector dSdbSensCP(Zero);
vector dndbSensCP(Zero);
for (const label patchI : sensitivityPatchIDs_)
{
tensorField dSdb
(
boxes[iNURB].dndbBasedSensitivities(patchI, cpI)
);
dSdbSensCP += gSum(dSfdbMult_()[patchI] & dSdb);
tensorField dndb
(
boxes[iNURB].dndbBasedSensitivities
(
patchI,
cpI,
false
)
);
dndbSensCP += gSum((dnfdbMult_()[patchI] & dndb));
}
dSdbSens_[passedCPs + cpI] = dSdbSensCP;
dndbSens_[passedCPs + cpI] = dndbSensCP;
}
passedCPs += nb;
}
volBSplinesBase_.boundControlPointMovement(dSdbSens_);
volBSplinesBase_.boundControlPointMovement(dndbSens_);
passedCPs = 0;
forAll(boxes, iNURB)
{
vectorField sensDxDbDirect =
boxes[iNURB].computeControlPointSensitivities
(
dxdbDirectMult_(),
sensitivityPatchIDs_.toc()
);
// Transfer to global list
forAll(sensDxDbDirect, cpI)
{
dxdbDirectSens_[passedCPs + cpI] = sensDxDbDirect[cpI];
}
passedCPs += sensDxDbDirect.size();
}
volBSplinesBase_.boundControlPointMovement(dxdbDirectSens_);
}
}
void sensitivityVolBSplines::computeBCContributions()
{
label passedCPs = 0;
PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
forAll(boxes, iNURB)
{
vectorField sensBcsDxDb =
boxes[iNURB].computeControlPointSensitivities
(
bcDxDbMult_(),
sensitivityPatchIDs_.toc()
);
// Transfer to global list
forAll(sensBcsDxDb, cpI)
{
bcSens_[passedCPs + cpI] = sensBcsDxDb[cpI];
}
passedCPs += sensBcsDxDb.size();
}
volBSplinesBase_.boundControlPointMovement(bcSens_);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivityVolBSplines::sensitivityVolBSplines
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
SIBase(mesh, dict, adjointSolver),
volBSplinesBase_
(
const_cast<volBSplinesBase&>(volBSplinesBase::New(mesh))
),
flowSens_(0),
dSdbSens_(0),
dndbSens_(0),
dxdbDirectSens_(0),
bcSens_(0),
derivativesFolder_("optimisation"/type() + "Derivatives")
{
// No boundary field pointers need to be allocated
const label nCPs(volBSplinesBase_.getTotalControlPointsNumber());
derivatives_ = scalarField(3*nCPs, Zero);
flowSens_ = vectorField(nCPs, Zero);
dSdbSens_ = vectorField(nCPs, Zero);
dndbSens_ = vectorField(nCPs, Zero);
dxdbDirectSens_ = vectorField(nCPs, Zero);
bcSens_ = vectorField(nCPs, Zero);
// Create folder to store sensitivities
mkDir(derivativesFolder_);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void sensitivityVolBSplines::assembleSensitivities()
{
// Assemble the sensitivity map
// Solves for the post-processing equations and adds their contribution to
// the sensitivity map
surfaceSensitivity_.assembleSensitivities();
// Finalise sensitivities including dxFace/db
const boundaryVectorField& faceSens =
surfaceSensitivity_.getWallFaceSensVecBoundary();
label passedCPs(0);
PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
forAll(boxes, iNURB)
{
vectorField sens =
boxes[iNURB].computeControlPointSensitivities
(
faceSens,
sensitivityPatchIDs_.toc()
);
// Transfer to global list
forAll(sens, cpI)
{
flowSens_[passedCPs + cpI] = sens[cpI];
}
passedCPs += sens.size();
}
volBSplinesBase_.boundControlPointMovement(flowSens_);
// Contribution from objective function
// Note:
// includeObjectiveContribution has to be set to false (false by default)
// in surfaceSensitivity, in order to avoid computing this term twice.
// Optionally avoided altogether if includeObjectiveContribution is set to
// false for sensitivityVolBSplines
computeObjectiveContributions();
computeBCContributions();
// Transform sensitivites to scalarField in order to cooperate with
// updateMethod
forAll(flowSens_, cpI)
{
derivatives_[3*cpI] =
flowSens_[cpI].x()
+ dSdbSens_[cpI].x()
+ dndbSens_[cpI].x()
+ dxdbDirectSens_[cpI].x()
+ bcSens_[cpI].x();
derivatives_[3*cpI + 1] =
flowSens_[cpI].y()
+ dSdbSens_[cpI].y()
+ dndbSens_[cpI].y()
+ dxdbDirectSens_[cpI].y()
+ bcSens_[cpI].y();
derivatives_[3*cpI + 2] =
flowSens_[cpI].z()
+ dSdbSens_[cpI].z()
+ dndbSens_[cpI].z()
+ dxdbDirectSens_[cpI].z()
+ bcSens_[cpI].z();
}
}
void sensitivityVolBSplines::clearSensitivities()
{
flowSens_ = vector::zero;
dSdbSens_ = vector::zero;
dndbSens_ = vector::zero;
dxdbDirectSens_ = vector::zero;
bcSens_ = vector::zero;
SIBase::clearSensitivities();
}
void sensitivityVolBSplines::write(const word& baseName)
{
Info<< "Writing control point sensitivities to file" << endl;
// Write sensitivity map
SIBase::write(baseName);
// Write control point sensitivities
if (Pstream::master())
{
OFstream derivFile
(
derivativesFolder_/
baseName + adjointVars_.solverName() + mesh_.time().timeName()
);
unsigned int widthDV =
max(int(Foam::name(derivatives_.size()).size()), int(3));
unsigned int width = IOstream::defaultPrecision() + 7;
derivFile
<< setw(widthDV) << "#cp" << " "
<< setw(width) << "total::x"<< " "
<< setw(width) << "total::y"<< " "
<< setw(width) << "total::z"<< " "
<< setw(width) << "flow::x" << " "
<< setw(width) << "flow::y" << " "
<< setw(width) << "flow::z" << " "
<< setw(width) << "dSdb::x" << " "
<< setw(width) << "dSdb::y" << " "
<< setw(width) << "dSdb::z" << " "
<< setw(width) << "dndb::x" << " "
<< setw(width) << "dndb::y" << " "
<< setw(width) << "dndb::z" << " "
<< setw(width) << "dxdbDirect::x" << " "
<< setw(width) << "dxdbDirect::y" << " "
<< setw(width) << "dxdbDirect::z" << " "
<< setw(width) << "dvdb::x" << " "
<< setw(width) << "dvdb::y" << " "
<< setw(width) << "dvdb::z" << endl;
label passedCPs(0);
label lastActive(-1);
PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
forAll(boxes, iNURB)
{
label nb = boxes[iNURB].getControlPoints().size();
const boolList& activeCPs = boxes[iNURB].getActiveCPs();
for (label iCP = 0; iCP < nb; iCP++)
{
if (activeCPs[iCP])
{
label globalCP = passedCPs + iCP;
if (globalCP!=lastActive + 1)
{
derivFile << "\n";
}
lastActive = globalCP;
derivFile
<< setw(widthDV) << globalCP << " "
<< setw(width) << derivatives_[3*globalCP] << " "
<< setw(width) << derivatives_[3*globalCP + 1] << " "
<< setw(width) << derivatives_[3*globalCP + 2] << " "
<< setw(width) << flowSens_[globalCP].x() << " "
<< setw(width) << flowSens_[globalCP].y() << " "
<< setw(width) << flowSens_[globalCP].z() << " "
<< setw(width) << dSdbSens_[globalCP].x() << " "
<< setw(width) << dSdbSens_[globalCP].y() << " "
<< setw(width) << dSdbSens_[globalCP].z() << " "
<< setw(width) << dndbSens_[globalCP].x() << " "
<< setw(width) << dndbSens_[globalCP].y() << " "
<< setw(width) << dndbSens_[globalCP].z() << " "
<< setw(width) << dxdbDirectSens_[globalCP].x() << " "
<< setw(width) << dxdbDirectSens_[globalCP].y() << " "
<< setw(width) << dxdbDirectSens_[globalCP].z() << " "
<< setw(width) << bcSens_[globalCP].x() << " "
<< setw(width) << bcSens_[globalCP].y() << " "
<< setw(width) << bcSens_[globalCP].z()
<< endl;
}
}
passedCPs += nb;
}
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,148 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::sensitivityVolBSplines
Description
Calculation of adjoint based sensitivities at vol B-Splines control points
using the SI or e-SI approach (determined by surface sensitivities)
SourceFiles
sensitivityVolBSplines.C
\*---------------------------------------------------------------------------*/
#ifndef sensitivityVolBSplinesIncompressible_H
#define sensitivityVolBSplinesIncompressible_H
#include "SIBaseIncompressible.H"
#include "volBSplinesBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class sensitivityVolBSplines Declaration
\*---------------------------------------------------------------------------*/
class sensitivityVolBSplines
:
public SIBase
{
protected:
// Protected data
//- Reference to underlaying volumetric B-Splines morpher
volBSplinesBase& volBSplinesBase_;
//- Flow related term
vectorField flowSens_;
//- Term depending on delta(n dS)/delta b
vectorField dSdbSens_;
//- Term depending on delta (n)/delta b
vectorField dndbSens_;
//- Term depending on dxdb for objective functions directly depending
//- on x
vectorField dxdbDirectSens_;
//- Term dependng on the differentiation of boundary conditions
vectorField bcSens_;
fileName derivativesFolder_;
// Protected Member Functions
void computeObjectiveContributions();
void computeBCContributions();
private:
// Private Member Functions
//- No copy construct
sensitivityVolBSplines(const sensitivityVolBSplines&) = delete;
//- No copy assignment
void operator=(const sensitivityVolBSplines&) = delete;
public:
//- Runtime type information
TypeName("volumetricBSplines");
// Constructors
//- Construct from components
sensitivityVolBSplines
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
);
//- Destructor
virtual ~sensitivityVolBSplines() = default;
// Member Functions
//- Assemble sensitivities
virtual void assembleSensitivities();
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Write sensitivities to file
virtual void write(const word& baseName = word::null);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,409 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2021 PCOpt/NTUA
Copyright (C) 2013-2021 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "sensitivityVolBSplinesFIIncompressible.H"
#include "pointVolInterpolation.H"
#include "IOmanip.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(sensitivityVolBSplinesFI, 0);
addToRunTimeSelectionTable
(
adjointSensitivity,
sensitivityVolBSplinesFI,
dictionary
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
sensitivityVolBSplinesFI::sensitivityVolBSplinesFI
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
FIBase(mesh, dict, adjointSolver),
volBSplinesBase_
(
const_cast<volBSplinesBase&>(volBSplinesBase::New(mesh))
),
flowSens_(0),
dSdbSens_(0),
dndbSens_(0),
dxdbDirectSens_(0),
dVdbSens_(0),
distanceSens_(0),
optionsSens_(0),
bcSens_(0),
derivativesFolder_("optimisation"/type() + "Derivatives")
{
// No boundary field pointers need to be allocated
label nCPs = volBSplinesBase_.getTotalControlPointsNumber();
derivatives_ = scalarField(3*nCPs, Zero);
flowSens_ = vectorField(nCPs, Zero);
dSdbSens_ = vectorField(nCPs, Zero);
dndbSens_ = vectorField(nCPs, Zero);
dxdbDirectSens_ = vectorField(nCPs, Zero);
dVdbSens_ = vectorField(nCPs, Zero);
distanceSens_ = vectorField(nCPs, Zero);
optionsSens_ = vectorField(nCPs, Zero);
bcSens_ = vectorField(nCPs, Zero);
// Create folder to store sensitivities
mkDir(derivativesFolder_);
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void sensitivityVolBSplinesFI::assembleSensitivities()
{
/*
addProfiling
(
sensitivityVolBSplinesFI,
"sensitivityVolBSplinesFI::assembleSensitivities"
);
*/
read();
// Interpolation engine
pointVolInterpolation volPointInter(pointMesh::New(mesh_), mesh_);
// Adjoint to the eikonal equation
autoPtr<volTensorField> distanceSensPtr(nullptr);
if (includeDistance_)
{
// Solver equation
eikonalSolver_->solve();
// Allocate memory and compute grad(dxdb) multiplier
distanceSensPtr.reset
(
createZeroFieldPtr<tensor>
(
mesh_,
"distanceSensPtr",
dimensionSet(0, 2, -3, 0, 0, 0, 0)
)
);
distanceSensPtr() = eikonalSolver_->getFISensitivityTerm()().T();
}
// Integration
label passedCPs(0);
PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
forAll(boxes, iNURB)
{
const label nb(boxes[iNURB].getControlPoints().size());
vectorField boxSensitivities(nb, Zero);
vectorField dxdbSens = boxes[iNURB].computeControlPointSensitivities
(
dxdbDirectMult_(),
sensitivityPatchIDs_.toc()
);
vectorField bcSens = boxes[iNURB].computeControlPointSensitivities
(
bcDxDbMult_(),
sensitivityPatchIDs_.toc()
);
for (label cpI = 0; cpI < nb; cpI++)
{
label globalCP = passedCPs + cpI;
// Parameterization info
tmp<volTensorField> tvolDxDbI
(
volPointInter.interpolate(boxes[iNURB].getDxDb(cpI))
);
const volTensorField& volDxDbI = tvolDxDbI();
// Chain rule used to get dx/db at cells
// Gives practically the same results at a much higher CPU cost
/*
tmp<volTensorField> tvolDxDbI(boxes[iNURB].getDxCellsDb(cpI));
volTensorField& volDxDbI = tvolDxDbI.ref();
*/
const tensorField& gradDxDbMultInt = gradDxDbMult_.primitiveField();
for (label idir = 0; idir < pTraits<vector>::nComponents; ++idir)
{
// Gradient of parameterization info
auto ttemp =
tmp<volVectorField>::New
(
IOobject
(
"dxdb",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedVector(dimless, Zero)
);
volVectorField& temp = ttemp.ref();
unzipCol(volDxDbI, vector::components(idir), temp);
volTensorField gradDxDb(fvc::grad(temp));
// Volume integral terms
flowSens_[globalCP].component(idir) = gSum
(
(gradDxDbMultInt && gradDxDb.primitiveField())
*mesh_.V()
);
if (includeDistance_)
{
const tensorField& distSensInt =
distanceSensPtr().primitiveField();
distanceSens_[globalCP].component(idir) =
gSum
(
(distSensInt && gradDxDb.primitiveField())
*mesh_.V()
);
}
}
// Contribution from objective function term from
// delta( n dS ) / delta b and
// delta ( x ) / delta b
// for objectives directly depending on x
for (const label patchI : sensitivityPatchIDs_)
{
tensorField dSdb
(
boxes[iNURB].dndbBasedSensitivities(patchI, cpI)
);
dSdbSens_[globalCP] += gSum(dSfdbMult_()[patchI] & dSdb);
tensorField dndb
(
boxes[iNURB].dndbBasedSensitivities(patchI, cpI, false)
);
dndbSens_[globalCP] += gSum((dnfdbMult_()[patchI] & dndb));
}
// Contribution from delta (V) / delta b
// For objectives defined as volume integrals only
dVdbSens_[globalCP] +=
gSum
(
divDxDbMult_
*fvc::div(T(volDxDbI))().primitiveField()
*mesh_.V()
);
// Terms from fvOptions
optionsSens_[globalCP] +=
gSum((optionsDxDbMult_ & volDxDbI.primitiveField())*mesh_.V());
// dxdbSens storage
dxdbDirectSens_[globalCP] = dxdbSens[cpI];
// bcSens storage
bcSens_[globalCP] = bcSens[cpI];
boxSensitivities[cpI] =
flowSens_[globalCP]
+ dSdbSens_[globalCP]
+ dndbSens_[globalCP]
+ dVdbSens_[globalCP]
+ distanceSens_[globalCP]
+ dxdbDirectSens_[globalCP]
+ optionsSens_[globalCP]
+ bcSens_[globalCP];
}
// Zero sensitivities in non-active design variables
boxes[iNURB].boundControlPointMovement(boxSensitivities);
// Transfer sensitivities to global list
for (label cpI = 0; cpI < nb; cpI++)
{
label globalCP = passedCPs + cpI;
derivatives_[3*globalCP] = boxSensitivities[cpI].x();
derivatives_[3*globalCP + 1] = boxSensitivities[cpI].y();
derivatives_[3*globalCP + 2] = boxSensitivities[cpI].z();
}
// Increment number of passed sensitivities
passedCPs += nb;
}
// Zero non-active sensitivity components.
// For consistent output only, does not affect optimisation
volBSplinesBase_.boundControlPointMovement(flowSens_);
volBSplinesBase_.boundControlPointMovement(dSdbSens_);
volBSplinesBase_.boundControlPointMovement(dndbSens_);
volBSplinesBase_.boundControlPointMovement(dVdbSens_);
volBSplinesBase_.boundControlPointMovement(distanceSens_);
volBSplinesBase_.boundControlPointMovement(dxdbDirectSens_);
volBSplinesBase_.boundControlPointMovement(optionsSens_);
volBSplinesBase_.boundControlPointMovement(bcSens_);
//profiling::writeNow();
}
void sensitivityVolBSplinesFI::clearSensitivities()
{
flowSens_ = vector::zero;
dSdbSens_ = vector::zero;
dndbSens_ = vector::zero;
dxdbDirectSens_ = vector::zero;
dVdbSens_ = vector::zero;
distanceSens_ = vector::zero;
optionsSens_ = vector::zero;
bcSens_ = vector::zero;
FIBase::clearSensitivities();
}
void sensitivityVolBSplinesFI::write(const word& baseName)
{
Info<< "Writing control point sensitivities to file" << endl;
if (Pstream::master())
{
OFstream derivFile
(
derivativesFolder_/
baseName + adjointVars_.solverName() + mesh_.time().timeName()
);
unsigned int widthDV
(
max(int(Foam::name(flowSens_.size()).size()), int(3))
);
unsigned int width = IOstream::defaultPrecision() + 7;
derivFile
<< setw(widthDV) << "#cp" << " "
<< setw(width) << "total::x" << " "
<< setw(width) << "total::y" << " "
<< setw(width) << "total::z" << " "
<< setw(width) << "flow::x" << " "
<< setw(width) << "flow::y" << " "
<< setw(width) << "flow::z" << " "
<< setw(width) << "dSdb::x" << " "
<< setw(width) << "dSdb::y" << " "
<< setw(width) << "dSdb::z" << " "
<< setw(width) << "dndb::x" << " "
<< setw(width) << "dndb::y" << " "
<< setw(width) << "dndb::z" << " "
<< setw(width) << "dxdbDirect::x" << " "
<< setw(width) << "dxdbDirect::y" << " "
<< setw(width) << "dxdbDirect::z" << " "
<< setw(width) << "dVdb::x" << " "
<< setw(width) << "dVdb::y" << " "
<< setw(width) << "dVdb::z" << " "
<< setw(width) << "distance::x" << " "
<< setw(width) << "distance::y" << " "
<< setw(width) << "distance::z" << " "
<< setw(width) << "options::x" << " "
<< setw(width) << "options::y" << " "
<< setw(width) << "options::z" << " "
<< setw(width) << "dvdb::x" << " "
<< setw(width) << "dvdb::y" << " "
<< setw(width) << "dvdb::z" << endl;
label passedCPs(0);
label lastActive(-1);
PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef();
forAll(boxes, iNURB)
{
label nb = boxes[iNURB].getControlPoints().size();
const boolList& activeCPs = boxes[iNURB].getActiveCPs();
for (label iCP = 0; iCP < nb; iCP++)
{
if (activeCPs[iCP])
{
label globalCP = passedCPs + iCP;
if (globalCP!=lastActive + 1) derivFile << "\n";
lastActive = globalCP;
derivFile
<< setw(widthDV) << globalCP << " "
<< setw(width) << derivatives_[3*globalCP] << " "
<< setw(width) << derivatives_[3*globalCP + 1] << " "
<< setw(width) << derivatives_[3*globalCP + 2] << " "
<< setw(width) << flowSens_[globalCP].x() << " "
<< setw(width) << flowSens_[globalCP].y() << " "
<< setw(width) << flowSens_[globalCP].z() << " "
<< setw(width) << dSdbSens_[globalCP].x() << " "
<< setw(width) << dSdbSens_[globalCP].y() << " "
<< setw(width) << dSdbSens_[globalCP].z() << " "
<< setw(width) << dndbSens_[globalCP].x() << " "
<< setw(width) << dndbSens_[globalCP].y() << " "
<< setw(width) << dndbSens_[globalCP].z() << " "
<< setw(width) << dxdbDirectSens_[globalCP].x() << " "
<< setw(width) << dxdbDirectSens_[globalCP].y() << " "
<< setw(width) << dxdbDirectSens_[globalCP].z() << " "
<< setw(width) << dVdbSens_[globalCP].x() << " "
<< setw(width) << dVdbSens_[globalCP].y() << " "
<< setw(width) << dVdbSens_[globalCP].z() << " "
<< setw(width) << distanceSens_[globalCP].x() << " "
<< setw(width) << distanceSens_[globalCP].y() << " "
<< setw(width) << distanceSens_[globalCP].z() << " "
<< setw(width) << optionsSens_[globalCP].x() << " "
<< setw(width) << optionsSens_[globalCP].y() << " "
<< setw(width) << optionsSens_[globalCP].z() << " "
<< setw(width) << bcSens_[globalCP].x() << " "
<< setw(width) << bcSens_[globalCP].y() << " "
<< setw(width) << bcSens_[globalCP].z() << endl;
}
}
passedCPs += nb;
}
}
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,151 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2020 PCOpt/NTUA
Copyright (C) 2013-2020 FOSS GP
Copyright (C) 2019 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 <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::sensitivityVolBSplinesFI
Description
Calculation of adjoint based sensitivities at vol B-Splines control points
using the FI approach.
SourceFiles
sensitivityVolBSplinesFI.C
\*---------------------------------------------------------------------------*/
#ifndef sensitivityVolBSplinesFIIncompressible_H
#define sensitivityVolBSplinesFIIncompressible_H
#include "FIBaseIncompressible.H"
#include "volBSplinesBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class sensitivityVolBSplinesFI Declaration
\*---------------------------------------------------------------------------*/
class sensitivityVolBSplinesFI
:
public FIBase
{
protected:
// Protected data
//- Reference to underlaying volumetric B-Splines morpher
volBSplinesBase& volBSplinesBase_;
//- Flow related term
vectorField flowSens_;
//- Term depending on delta(n dS)/delta b
vectorField dSdbSens_;
//- Term depending on delta(n)/delta b
vectorField dndbSens_;
//- Term depending on delta(x)/delta b for objectives that directly
//- depend on x
vectorField dxdbDirectSens_;
//- Term depending on delta(V)/delta b
vectorField dVdbSens_;
//- Term depending on distance differentiation
vectorField distanceSens_;
//- Term depending on fvOptions
vectorField optionsSens_;
//- Term depending on the differentiation of boundary conditions
vectorField bcSens_;
fileName derivativesFolder_;
private:
// Private Member Functions
//- No copy construct
sensitivityVolBSplinesFI(const sensitivityVolBSplinesFI&) = delete;
//- No copy assignment
void operator=(const sensitivityVolBSplinesFI&) = delete;
public:
//- Runtime type information
TypeName("volumetricBSplinesFI");
// Constructors
//- Construct from components
sensitivityVolBSplinesFI
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
);
//- Destructor
virtual ~sensitivityVolBSplinesFI() = default;
// Member Functions
//- Assemble sensitivities
virtual void assembleSensitivities();
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Write sensitivities to file
virtual void write(const word& baseName = word::null);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,176 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 PCOpt/NTUA
Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "shapeSensitivitiesIncompressible.H"
#include "adjointBoundaryConditions.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
defineTypeNameAndDebug(shapeSensitivities, 0);
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void shapeSensitivities::accumulateDirectSensitivityIntegrand(const scalar dt)
{
// Accumulate direct sensitivities
PtrList<objective>& functions = objectiveManager_.getObjectiveFunctions();
for (const label patchI : sensitivityPatchIDs_)
{
const scalarField magSfDt(mesh_.boundary()[patchI].magSf()*dt);
for (objective& func : functions)
{
const scalar wei(func.weight());
dSfdbMult_()[patchI] += wei*func.dSdbMultiplier(patchI)*dt;
dnfdbMult_()[patchI] += wei*func.dndbMultiplier(patchI)*magSfDt;
dxdbDirectMult_()[patchI] +=
wei*func.dxdbDirectMultiplier(patchI)*magSfDt;
}
}
}
void shapeSensitivities::accumulateBCSensitivityIntegrand(const scalar dt)
{
// Avoid updating the event number to keep consistency with cases caching
// gradUa
auto& UaBoundary = adjointVars_.Ua().boundaryFieldRef(false);
tmp<boundaryVectorField> DvDbMult(dvdbMult());
// Accumulate sensitivities due to boundary conditions
for (const label patchI : sensitivityPatchIDs_)
{
const scalarField magSfDt(mesh_.boundary()[patchI].magSf()*dt);
fvPatchVectorField& Uab = UaBoundary[patchI];
if (isA<adjointVectorBoundaryCondition>(Uab))
{
bcDxDbMult_()[patchI] +=
(
DvDbMult()[patchI]
& refCast<adjointVectorBoundaryCondition>(Uab).dxdbMult()
)*magSfDt;
}
}
}
tmp<boundaryVectorField> shapeSensitivities::dvdbMult() const
{
tmp<boundaryVectorField>
tres(createZeroBoundaryPtr<vector>(meshShape_).ptr());
boundaryVectorField& res = tres.ref();
// Grab references
const volScalarField& pa = adjointVars_.pa();
const volVectorField& Ua = adjointVars_.Ua();
const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence =
adjointVars_.adjointTurbulence();
// Fields needed to calculate adjoint sensitivities
const autoPtr<incompressible::RASModelVariables>&
turbVars = primalVars_.RASModelVariables();
const singlePhaseTransportModel& lamTransp = primalVars_.laminarTransport();
volScalarField nuEff(lamTransp.nu() + turbVars->nutRef());
tmp<volTensorField> tgradUa = fvc::grad(Ua);
const volTensorField::Boundary& gradUabf = tgradUa.cref().boundaryField();
for (const label patchI : sensitivityPatchIDs_)
{
const fvPatch& patch = meshShape_.boundary()[patchI];
tmp<vectorField> tnf = patch.nf();
const vectorField& nf = tnf();
res[patchI] =
(
nuEff.boundaryField()[patchI]
* (
Ua.boundaryField()[patchI].snGrad()
+ (gradUabf[patchI] & nf)
)
)
- (nf*pa.boundaryField()[patchI])
+ adjointTurbulence().adjointMomentumBCSource()[patchI];
}
return tres;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
shapeSensitivities::shapeSensitivities
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
)
:
adjointSensitivity(mesh, dict, adjointSolver),
shapeSensitivitiesBase(mesh, dict),
dSfdbMult_(createZeroBoundaryPtr<vector>(mesh_)),
dnfdbMult_(createZeroBoundaryPtr<vector>(mesh_)),
dxdbDirectMult_(createZeroBoundaryPtr<vector>(mesh_)),
bcDxDbMult_(createZeroBoundaryPtr<vector>(mesh_))
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void shapeSensitivities::clearSensitivities()
{
dSfdbMult_() = vector::zero;
dnfdbMult_() = vector::zero;
dxdbDirectMult_() = vector::zero;
bcDxDbMult_() = vector::zero;
adjointSensitivity::clearSensitivities();
shapeSensitivitiesBase::clearSensitivities();
}
void shapeSensitivities::write(const word& baseName)
{
adjointSensitivity::write(baseName);
shapeSensitivitiesBase::write();
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// ************************************************************************* //

View File

@ -1,141 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020 PCOpt/NTUA
Copyright (C) 2020 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 <http://www.gnu.org/licenses/>.
Class
Foam::incompressible::shapeSensitivitiesBase
Description
Base class supporting shape sensitivity derivatives for
incompressible flows
SourceFiles
shapeSensitivitiesBase.C
\*---------------------------------------------------------------------------*/
#ifndef shapeSensitivitiesIncompressible_H
#define shapeSensitivitiesIncompressible_H
#include "adjointSensitivityIncompressible.H"
#include "shapeSensitivitiesBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace incompressible
{
/*---------------------------------------------------------------------------*\
Class shapeSensitivities Declaration
\*---------------------------------------------------------------------------*/
class shapeSensitivities
:
public adjointSensitivity,
public shapeSensitivitiesBase
{
protected:
// Protected data
//- Fields related to direct sensitivities
autoPtr<boundaryVectorField> dSfdbMult_;
autoPtr<boundaryVectorField> dnfdbMult_;
autoPtr<boundaryVectorField> dxdbDirectMult_;
autoPtr<boundaryVectorField> bcDxDbMult_;
// Protected Member Fuctions
//- Accumulate direct sensitivities
virtual void accumulateDirectSensitivityIntegrand(const scalar dt);
//- Accumulate sensitivities enamating from the boundary conditions
virtual void accumulateBCSensitivityIntegrand(const scalar dt);
//- Compute multiplier of dv_i/db
tmp<boundaryVectorField> dvdbMult() const;
private:
// Private Member Functions
//- No copy construct
shapeSensitivities(const shapeSensitivities&) = delete;
//- No copy assignment
void operator=(const shapeSensitivities&) = delete;
public:
//- Runtime type information
TypeName("shapeSensitivities");
// Constructors
//- Construct from components
shapeSensitivities
(
const fvMesh& mesh,
const dictionary& dict,
incompressibleAdjointSolver& adjointSolver
);
//- Destructor
virtual ~shapeSensitivities() = default;
// Member Functions
//- Accumulate sensitivity integrands
virtual void accumulateIntegrand(const scalar dt) = 0;
//- Assemble sensitivities
virtual void assembleSensitivities() = 0;
//- Zero sensitivity fields and their constituents
virtual void clearSensitivities();
//- Write sensitivity fields.
virtual void write(const word& baseName = word::null);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace incompressible
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -48,18 +48,13 @@ Foam::sensitivity::sensitivity
:
mesh_(mesh),
dict_(dict),
writeFieldSens_(dict.getOrDefault<bool>("writeFieldSens", false)),
fieldSensPtr_(nullptr)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
const Foam::dictionary& Foam::sensitivity::dict() const
{
return dict_;
}
bool Foam::sensitivity::readDict(const dictionary& dict)
{
dict_ = dict;
@ -68,15 +63,9 @@ bool Foam::sensitivity::readDict(const dictionary& dict)
}
void Foam::sensitivity::computeDerivativesSize()
{
// Does nothing
}
void Foam::sensitivity::write(const word& baseName)
{
if (fieldSensPtr_)
if (fieldSensPtr_ && writeFieldSens_)
{
fieldSensPtr_->write();
}

View File

@ -5,8 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
@ -57,6 +57,9 @@ SourceFiles
namespace Foam
{
// Forward declaration
class designVariables;
/*---------------------------------------------------------------------------*\
Class sensitivity Declaration
\*---------------------------------------------------------------------------*/
@ -69,14 +72,13 @@ protected:
const fvMesh& mesh_;
dictionary dict_;
bool writeFieldSens_;
// Field sensitivities. Topology optimisation
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
autoPtr<volScalarField> fieldSensPtr_;
// Protected Member Functions
private:
// Private Member Functions
@ -108,27 +110,40 @@ public:
// Member Functions
//- Return reference to mesh
inline const fvMesh& mesh() const
{
return mesh_;
}
//- Return the construction dictionary
const dictionary& dict() const;
inline const dictionary& dict() const
{
return
dict_.optionalSubDict(mesh_.name()).
optionalSubDict("sensitivities");
}
//- Read dictionary if changed
virtual bool readDict(const dictionary& dict);
//- Compute design variables number. Does nothing in the base
// Used to get the correct design variables number when
// setSensitivityPatchIDs are not set in the constructor
virtual void computeDerivativesSize();
//- Calculates and returns sensitivity field
virtual const scalarField& calculateSensitivities
(
autoPtr<designVariables>& designVars
) = 0;
//- Calculates and returns sensitivity fields.
// Used with optimisation libraries
virtual const scalarField& calculateSensitivities() = 0;
//- Get the fieldSensPtr
inline const autoPtr<volScalarField>& fieldSensPtr() const
{
return fieldSensPtr_;
}
//- Write sensitivity fields.
// If valid, copies boundaryFields to volFields and writes them.
// Virtual to be reimplemented by control points-based methods
// (Bezier, RBF) which do not need to write fields
virtual void write(const word& baseName = word::null);
};

View File

@ -0,0 +1,281 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "designVariables.H"
#include "adjointSensitivity.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(designVariables, 0);
defineRunTimeSelectionTable(designVariables, designVariables);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::designVariables::readBounds
(
autoPtr<scalar> lowerBoundPtr,
autoPtr<scalar> upperBoundPtr
)
{
// Read lower bounds for the design variables, if present
if (dict_.found("lowerBounds"))
{
scalarField lowerBounds(dict_.get<scalarField>("lowerBounds"));
if (lowerBounds.size() != getVars().size())
{
FatalErrorInFunction
<< "Inconsistent dimensions for lowerBounds ("
<< lowerBounds.size()
<< ") and design variables ("
<< getVars().size() << ")"
<< exit(FatalError);
}
lowerBounds_.reset(new scalarField(lowerBounds));
}
else if (dict_.found("lowerBound"))
{
scalar lowerBound(dict_.get<scalar>("lowerBound"));
lowerBounds_.reset(new scalarField(getVars().size(), lowerBound));
}
else if (lowerBoundPtr.valid())
{
lowerBounds_.reset(new scalarField(getVars().size(), lowerBoundPtr()));
}
// Read upper bounds for the design variables, if present
if (dict_.found("upperBounds"))
{
scalarField upperBounds(dict_.get<scalarField>("upperBounds"));
if (upperBounds.size() != getVars().size())
{
FatalErrorInFunction
<< "Inconsistent dimensions for upperBounds ("
<< upperBounds.size()
<< ") and design variables ("
<< getVars().size() << ")"
<< exit(FatalError);
}
upperBounds_.reset(new scalarField(upperBounds));
}
else if (dict_.found("upperBound"))
{
scalar upperBound(dict_.get<scalar>("upperBound"));
upperBounds_.reset(new scalarField(getVars().size(), upperBound));
}
else if (upperBoundPtr.valid())
{
upperBounds_.reset(new scalarField(getVars().size(), upperBoundPtr()));
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::designVariables::designVariables
(
fvMesh& mesh,
const dictionary& dict
)
:
scalarField(0),
mesh_(mesh),
dict_(dict),
activeDesignVariables_(0),
oldDesignVariables_(nullptr),
maxInitChange_(nullptr),
lowerBounds_(nullptr),
upperBounds_(nullptr)
{
// Read max initial change of design variables if present
if (dict.found("maxInitChange"))
{
maxInitChange_.reset(new scalar(dict_.get<scalar>("maxInitChange")));
}
}
Foam::designVariables::designVariables
(
fvMesh& mesh,
const dictionary& dict,
const label size
)
:
scalarField(size, Zero),
mesh_(mesh),
dict_(dict),
activeDesignVariables_(0),
oldDesignVariables_(nullptr),
maxInitChange_(nullptr),
lowerBounds_(nullptr),
upperBounds_(nullptr)
{
// Read max initial change of design variables if present
if (dict.found("maxInitChange"))
{
maxInitChange_.reset(new scalar(dict_.get<scalar>("maxInitChange")));
}
}
// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::designVariables> Foam::designVariables::New
(
fvMesh& mesh,
const dictionary& dict
)
{
if (!dict.found("type"))
{
return autoPtr<designVariables>(nullptr);
}
const word modelType(dict.get<word>("type"));
Info<< "designVariables type : " << modelType << endl;
auto cstrIter = designVariablesConstructorTablePtr_->cfind(modelType);
if (!cstrIter.found())
{
FatalErrorInLookup
(
"designVariables",
modelType,
*designVariablesConstructorTablePtr_
) << exit(FatalError);
}
return autoPtr<designVariables>(cstrIter()(mesh, dict));
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
bool Foam::designVariables::readDict(const dictionary& dict)
{
dict_ = dict;
if (dict.found("maxInitChange"))
{
maxInitChange_.reset(new scalar(dict_.get<scalar>("maxInitChange")));
}
return true;
}
const Foam::scalarField& Foam::designVariables::getVars() const
{
return *this;
}
Foam::scalarField& Foam::designVariables::getVars()
{
return *this;
}
void Foam::designVariables::storeDesignVariables()
{
if (!oldDesignVariables_)
{
oldDesignVariables_.reset(new scalarField(getVars().size(), Zero));
}
oldDesignVariables_.ref() = getVars();
}
void Foam::designVariables::resetDesignVariables()
{
DebugInfo
<< "Reseting design variables" << endl;
getVars() = (oldDesignVariables_());
}
void Foam::designVariables::postProcessSens
(
scalarField& objectiveSens,
PtrList<scalarField>& constraintSens,
const wordList& adjointSolversNames,
bool isMaster
)
{
// Does nothing in base
}
void Foam::designVariables::evolveNumber()
{
// Does nothing in base
}
void Foam::designVariables::setInitialValues()
{
// Does nothing in base
}
void Foam::designVariables::addFvOptions
(
const PtrList<primalSolver>& primalSolver,
const PtrList<adjointSolverManager>& adjointSolverManagers
)
{
// Does nothing in base
}
Foam::tmp<Foam::scalarField> Foam::designVariables::constraintValues()
{
return tmp<scalarField>(nullptr);
}
Foam::PtrList<Foam::scalarField> Foam::designVariables::constraintDerivatives()
{
return PtrList<scalarField>();
}
void Foam::designVariables::writeDesignVars()
{
// Does nothing in base
}
// ************************************************************************* //

View File

@ -0,0 +1,282 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 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 <http://www.gnu.org/licenses/>.
Class
Foam::designVariables
Description
Abstract base class for defining design variables.
SourceFiles
designVariables.C
\*---------------------------------------------------------------------------*/
#ifndef designVariables_H
#define designVariables_H
#include "fvMesh.H"
#include "volFieldsFwd.H"
#include "volFields.H"
#include "dictionary.H"
#include "primalSolver.H"
#include "adjointSolverManager.H"
#include "adjointSensitivity.H"
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class adjointSensitivity;
/*---------------------------------------------------------------------------*\
Class designVariables Declaration
\*---------------------------------------------------------------------------*/
class designVariables
:
public scalarField
{
protected:
// Protected data
fvMesh& mesh_;
dictionary dict_;
//- Which of the design variables will be updated
labelList activeDesignVariables_;
//- Copy of old design variables. Usefull when performing line-search
autoPtr<scalarField> oldDesignVariables_;
//- Maximum design variables' change in the first optimisation cycle
// Used when eta is not used in updateMethod
autoPtr<scalar> maxInitChange_;
//- Lower bounds of the design variables
autoPtr<scalarField> lowerBounds_;
//- Upper bounds of the design variables
autoPtr<scalarField> upperBounds_;
// Protected Member Functions
//- Read bounds for design variables, if present
void readBounds
(
autoPtr<scalar> lowerBoundPtr = nullptr,
autoPtr<scalar> upperBoundPtr = nullptr
);
private:
// Private Member Functions
//- Disallow default bitwise copy construct
designVariables(const designVariables&) = delete;
//- Disallow default bitwise assignment
void operator=(const designVariables&) = delete;
public:
//- Runtime type information
TypeName("designVariables");
// Declare run-time constructor selection table
declareRunTimeNewSelectionTable
(
autoPtr,
designVariables,
designVariables,
(
fvMesh& mesh,
const dictionary& dict
),
(mesh, dict)
);
// Constructors
//- Construct from dictionary
designVariables
(
fvMesh& mesh,
const dictionary& dict
);
//- Construct from dictionary and size
designVariables
(
fvMesh& mesh,
const dictionary& dict,
const label size
);
// Selectors
//- Return a reference to the selected design variables
static autoPtr<designVariables> New
(
fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~designVariables() = default;
// Member Functions
//- Read dictionary if changed
virtual bool readDict(const dictionary& dict);
//- Get the design variables
// Defaults to *this.
// Virtual for potential overriding from derived classes
virtual const scalarField& getVars() const;
//- Get the design variables
// Defaults to *this.
// Virtual for potential overriding from derived classes
virtual scalarField& getVars();
//- Update design variables based on a given correction
// Translates the scalarField of corrections to a meaningful
// update of the design variables
virtual void update(scalarField& correction) = 0;
//- Store design variables, as the starting point for line search
virtual void storeDesignVariables();
//- Reset to the starting point of line search
virtual void resetDesignVariables();
//- Compute eta if not set in the first step
virtual scalar computeEta(scalarField& correction) = 0;
//- Whether to use global sum when computing matrix-vector products
//- in update methods
// Depends on whether the design variables are common for all
// processors (e.g. volumetric B-Splines control points) or distributed
// across them (e.g. topology optimisation)
virtual bool globalSum() const = 0;
//- Return list of active design variables
inline const labelList& activeDesignVariables() const;
//- Check whether the max. initial change of the design variables has
//- been set
inline bool isMaxInitChangeSet() const;
//- Set maxInitChange
inline void setMaxInitChange(const scalar maxInitChange);
//- Trigger the recomputation of eta by updateMethod
inline virtual bool resetEta() const;
//- Get min bounds for the design variables
inline const autoPtr<scalarField>& lowerBounds() const;
//- Get max bounds for the design variables
inline const autoPtr<scalarField>& upperBounds() const;
//- Get min bounds for the design variables
inline scalarField& lowerBoundsRef();
//- Get max bounds for the design variables
inline scalarField& upperBoundsRef();
//- Post process sensitivities if needed
virtual void postProcessSens
(
scalarField& objectiveSens,
PtrList<scalarField>& constraintSens,
const wordList& adjointSolversNames,
bool isMaster
);
//- Assemble sensitivity derivatives, by combining the part related
//- to the primal and adjoint solution with the part related to the
//- design variables
virtual tmp<scalarField> assembleSensitivities
(
adjointSensitivity& sens
) = 0;
//- For design variables with a dynamic character (i.e. changing
//- number), perform the evolution
virtual void evolveNumber();
//- Set initial values of the design variables
// For design variables sets that need to be initialised after the
// construction of the primal fields.
// Does nothing in base
virtual void setInitialValues();
//- Add fvOptions depending on the design variables
virtual void addFvOptions
(
const PtrList<primalSolver>& primalSolver,
const PtrList<adjointSolverManager>& adjointSolverManagers
);
//- Design variables might add constraints related to themselves
//- (e.g. linear combinations of the design variables)
//- Return the values and gradients of these constraints
virtual tmp<scalarField> constraintValues();
virtual PtrList<scalarField> constraintDerivatives();
//- Write useful quantities to files
virtual void writeDesignVars();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#include "designVariablesI.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -5,9 +5,8 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2019 PCOpt/NTUA
Copyright (C) 2013-2019 FOSS GP
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2021 PCOpt/NTUA
Copyright (C) 2021 FOSS GP
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -27,48 +26,56 @@ License
\*---------------------------------------------------------------------------*/
#include "optMeshMovementNULL.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(optMeshMovementNULL, 0);
addToRunTimeSelectionTable
(
optMeshMovement,
optMeshMovementNULL,
dictionary
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::optMeshMovementNULL::optMeshMovementNULL
(
fvMesh& mesh,
const dictionary& dict,
const labelList& patchIDs
)
:
optMeshMovement(mesh, dict, patchIDs)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::optMeshMovementNULL::moveMesh()
inline const Foam::labelList&
Foam::designVariables::activeDesignVariables() const
{
// Do nothing
return activeDesignVariables_;
}
Foam::scalar
Foam::optMeshMovementNULL::computeEta(const scalarField& correction)
bool Foam::designVariables::isMaxInitChangeSet() const
{
return scalar(0);
return maxInitChange_.valid();
}
void Foam::designVariables::setMaxInitChange(const scalar maxInitChange)
{
maxInitChange_.reset(new scalar(maxInitChange));
}
bool Foam::designVariables::resetEta() const
{
return false;
}
const Foam::autoPtr<Foam::scalarField>&
Foam::designVariables::lowerBounds() const
{
return lowerBounds_;
}
const Foam::autoPtr<Foam::scalarField>&
Foam::designVariables::upperBounds() const
{
return upperBounds_;
}
Foam::scalarField& Foam::designVariables::lowerBoundsRef()
{
return lowerBounds_.ref();
}
Foam::scalarField& Foam::designVariables::upperBoundsRef()
{
return upperBounds_.ref();
}

View File

@ -0,0 +1,289 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "BezierDesignVariables.H"
#include "IOmanip.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(BezierDesignVariables, 0);
addToRunTimeSelectionTable
(
shapeDesignVariables,
BezierDesignVariables,
dictionary
);
}
// * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * //
void Foam::BezierDesignVariables::readBounds
(
autoPtr<scalar> lowerBoundPtr,
autoPtr<scalar> upperBoundPtr
)
{
designVariables::readBounds(lowerBoundPtr, upperBoundPtr);
if (dict_.found("lowerCPBounds"))
{
vector lowerCPBounds(dict_.get<vector>("lowerCPBounds"));
lowerBounds_.reset(new scalarField(getVars().size(), Zero));
setBounds(lowerBounds_, lowerCPBounds);
}
if (dict_.found("upperCPBounds"))
{
vector upperCPBounds(dict_.get<vector>("upperCPBounds"));
upperBounds_.reset(new scalarField(getVars().size(), Zero));
setBounds(upperBounds_, upperCPBounds);
}
}
void Foam::BezierDesignVariables::setBounds
(
autoPtr<scalarField>& bounds,
const vector& cpBounds
)
{
bounds.reset(new scalarField(getVars().size(), Zero));
const label nCPs(bezier_.nBezier());
for (label iCP = 0; iCP < nCPs; ++iCP)
{
bounds()[iCP] = cpBounds.x();
bounds()[nCPs + iCP] = cpBounds.y();
bounds()[2*nCPs + iCP] = cpBounds.z();
}
}
Foam::tmp<Foam::vectorField>
Foam::BezierDesignVariables::computeBoundaryDisplacement
(
const scalarField& correction
)
{
// Reset boundary movement field
dx_.primitiveFieldRef() = Zero;
// Compute boundary movement using the derivatives of grid nodes
// wrt to the Bezier control points and the correction
const label nCPs(bezier_.nBezier());
auto tcpMovement(tmp<vectorField>::New(nCPs, Zero));
vectorField& cpMovement = tcpMovement.ref();
const boolListList& confineMovement = bezier_.confineMovement();
forAll(cpMovement, cpI)
{
if (!confineMovement[0][cpI])
{
cpMovement[cpI].x() = correction[cpI];
}
if (!confineMovement[1][cpI])
{
cpMovement[cpI].y() = correction[nCPs + cpI];
}
if (!confineMovement[2][cpI])
{
cpMovement[cpI].z() = correction[2*nCPs + cpI];
}
dx_ += (bezier_.dxidXj()[cpI] & cpMovement[cpI]);
}
return tcpMovement;
}
void Foam::BezierDesignVariables::decomposeVarID
(
label& cpI,
label& dir,
const label varID
) const
{
const label nBezier = bezier_.nBezier();
cpI = varID%nBezier;
dir = varID/nBezier;
}
// * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * //
Foam::BezierDesignVariables::BezierDesignVariables
(
fvMesh& mesh,
const dictionary& dict
)
:
shapeDesignVariables(mesh, dict),
bezier_
(
mesh,
IOdictionary
(
IOobject
(
"optimisationDict",
mesh_.time().globalPath()/"system",
mesh,
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
)
)
),
dx_
(
IOobject
(
"dx",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
pointMesh::New(mesh_),
dimensionedVector(dimless, Zero)
)
{
// Set the size of the design variables field
scalarField::setSize(3*bezier_.nBezier(), Zero);
// Set the active design variables
activeDesignVariables_ = bezier_.getActiveDesignVariables();
// Read bounds
readBounds();
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
void Foam::BezierDesignVariables::update(scalarField& correction)
{
// Translate the correction field to control point movements
computeBoundaryDisplacement(correction);
// Transfer movement to the displacementMethod
displMethodPtr_->setMotionField(dx_);
// Update the design variables
scalarField::operator+=(correction);
// Do the actual mesh movement
moveMesh();
}
Foam::scalar Foam::BezierDesignVariables::computeEta(scalarField& correction)
{
// Transfer the correction field to control point movement
computeBoundaryDisplacement(correction);
const scalar maxDisplacement(max(mag(dx_)).value());
Info<< "maxAllowedDisplacement/maxDisplacement at the boundary\t"
<< maxInitChange_() << "/" << maxDisplacement << endl;
const scalar eta = maxInitChange_()/maxDisplacement;
Info<< "Setting eta value to " << eta << endl;
correction *= eta;
return eta;
}
bool Foam::BezierDesignVariables::globalSum() const
{
return false;
}
Foam::tmp<Foam::vectorField> Foam::BezierDesignVariables::dxdbFace
(
const label patchI,
const label varID
) const
{
label cpI(-1), dir(-1);
decomposeVarID(cpI, dir, varID);
return bezier_.dxdbFace(patchI, cpI, dir);
}
Foam::tmp<Foam::vectorField> Foam::BezierDesignVariables::dndb
(
const label patchI,
const label varID
) const
{
label cpI(-1), dir(-1);
decomposeVarID(cpI, dir, varID);
return bezier_.dndbBasedSensitivities(patchI, cpI, dir, false);
}
Foam::tmp<Foam::vectorField> Foam::BezierDesignVariables::dSdb
(
const label patchI,
const label varID
) const
{
label cpI(-1), dir(-1);
decomposeVarID(cpI, dir, varID);
return bezier_.dndbBasedSensitivities(patchI, cpI, dir, true);
}
Foam::tmp<Foam::volVectorField>
Foam::BezierDesignVariables::dCdb(const label varID) const
{
label cpI(-1), dir(-1);
decomposeVarID(cpI, dir, varID);
label patchI(-1);
// There is no mechanism in place to identify the parametertised patch.
// Look over all patches and grab one with a non-zero dxdb
for (const label pI : parametertisedPatches_)
{
tmp<vectorField> dxdbFace = bezier_.dxdbFace(pI, cpI, dir);
if (gSum(mag(dxdbFace)) > SMALL)
{
patchI = pI;
}
}
return solveMeshMovementEqn(patchI, varID);
}
// ************************************************************************* //

View File

@ -0,0 +1,172 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 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 <http://www.gnu.org/licenses/>.
Class
Foam::BezierDesignVariables
Description
Bezier design variables for shape optimisation
SourceFiles
BezierDesignVariables.C
\*---------------------------------------------------------------------------*/
#ifndef BezierDesignVariables_H
#define BezierDesignVariables_H
#include "shapeDesignVariables.H"
#include "Bezier.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class BezierDesignVariables Decleration
\*---------------------------------------------------------------------------*/
class BezierDesignVariables
:
public shapeDesignVariables
{
protected:
// Protected Data Members
//- The Bezier control points and auxiliary functions
Bezier bezier_;
//- Boundary movement due to the change in Bezier control points
pointVectorField dx_;
// Protected Member Functions
//- Read bounds for design variables, if present
void readBounds
(
autoPtr<scalar> lowerBoundPtr = nullptr,
autoPtr<scalar> upperBoundPtr = nullptr
);
//- Set uniform bounds for all control points
void setBounds(autoPtr<scalarField>& bounds, const vector& cpBounds);
//- Transform the correction of design variables to control points'
//- movement
tmp<vectorField> computeBoundaryDisplacement
(
const scalarField& correction
);
//- Decompose varID to cpID and direction
void decomposeVarID(label& cpI, label& dir, const label varID) const;
private:
// Private Member Functions
//- No copy construct
BezierDesignVariables(const BezierDesignVariables&) = delete;
//- No copy assignment
void operator=(const BezierDesignVariables&) = delete;
public:
//- Runtime type information
TypeName("Bezier");
// Constructors
//- Construct from components
BezierDesignVariables
(
fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~BezierDesignVariables() = default;
// Member Functions
//- Update design variables based on a given correction
virtual void update(scalarField& correction);
//- Compute eta if not set in the first step
virtual scalar computeEta(scalarField& correction);
//- Whether to use global sum when computing matrix-vector products
// in update methods
virtual bool globalSum() const;
// Fields related to sensitivity computations
//- Get dxdb for given design variable and patch
virtual tmp<vectorField> dxdbFace
(
const label patchI,
const label varID
) const;
//- Get dndb for given design variable and patch
virtual tmp<vectorField> dndb
(
const label patchI,
const label varID
) const;
//- Get dSdb for given design variable and patch
virtual tmp<vectorField> dSdb
(
const label patchI,
const label varID
) const;
//- Get dCdb for given design variable.
// Used for FI-based sensitivities
virtual tmp<volVectorField> dCdb(const label varID) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,510 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 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 <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "shapeDesignVariables.H"
#include "cellQuality.H"
#include "createZeroField.H"
#include "addToRunTimeSelectionTable.H"
#include "volFieldsFwd.H"
#include "adjointEikonalSolver.H"
#include "IOmanip.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(shapeDesignVariables, 0);
defineRunTimeSelectionTable(shapeDesignVariables, dictionary);
addToRunTimeSelectionTable
(
designVariables,
shapeDesignVariables,
designVariables
);
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
Foam::label Foam::shapeDesignVariables::sensSize() const
{
return size();
}
const Foam::labelList& Foam::shapeDesignVariables::activeSensitivities() const
{
return activeDesignVariables_;
}
Foam::tmp<Foam::volVectorField>
Foam::shapeDesignVariables::solveMeshMovementEqn
(
const label patchI,
const label varID
) const
{
const dictionary dxdbDict = dict_.subOrEmptyDict("dxdbSolver");
const label iters = dxdbDict.getOrDefault<label>("iters", 1000);
const scalar tolerance =
dxdbDict.getOrDefault<scalar>("tolerance", 1.e-07);
tmp<volVectorField> tm
(
tmp<volVectorField>::New
(
variablesSet::autoCreateMeshMovementField
(
mesh_,
"m",
dimensionSet(dimLength)
)
)
);
volVectorField& m = tm.ref();
// Solve for dxdb
//~~~~~~~~~~~~~~~~
m.boundaryFieldRef()[patchI] == dxdbFace(patchI, varID);
// Iterate the direct differentiation of the grid displacement equation
for (label iter = 0; iter < iters; ++iter)
{
Info<< "Mesh Movement Propagation for varID" << varID
<< ", Iteration : "<< iter << endl;
fvVectorMatrix mEqn
(
fvm::laplacian(m)
);
scalar residual = mag(mEqn.solve().initialResidual());
DebugInfo
<< "Max dxdb " << gMax(mag(m)()) << endl;
mesh_.time().printExecutionTime(Info);
// Check convergence
if (residual < tolerance)
{
Info<< "\n***Reached dxdb convergence limit, iteration " << iter
<< "***\n\n";
break;
}
}
return tm;
}
void Foam::shapeDesignVariables::allocateSensFields()
{
if (dxdbVolSens_.empty())
{
dxdbVolSens_.setSize(sensSize(), Zero);
dxdbSurfSens_.setSize(sensSize(), Zero);
dSdbSens_.setSize(sensSize(), Zero);
dndbSens_.setSize(sensSize(), Zero);
dxdbDirectSens_.setSize(sensSize(), Zero);
dVdbSens_.setSize(sensSize(), Zero);
distanceSens_.setSize(sensSize(), Zero);
optionsSens_.setSize(sensSize(), Zero);
bcSens_.setSize(sensSize(), Zero);
}
}
void Foam::shapeDesignVariables::zeroSensFields()
{
dxdbVolSens_ = Zero;
dxdbSurfSens_ = Zero;
dSdbSens_ = Zero;
dndbSens_ = Zero;
dxdbDirectSens_ = Zero;
dVdbSens_ = Zero;
distanceSens_ = Zero;
optionsSens_ = Zero;
bcSens_ = Zero;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::shapeDesignVariables::shapeDesignVariables
(
fvMesh& mesh,
const dictionary& dict
)
:
designVariables(mesh, dict),
parametertisedPatches_
(
mesh_.boundaryMesh().patchSet(dict.get<wordRes>("patches"))
),
displMethodPtr_
(
displacementMethod::New(mesh_, parametertisedPatches_.toc())
),
pointsInit_(nullptr),
writeEachMesh_(dict.getOrDefault<bool>("writeEachMesh", true)),
dxdbVolSens_(),
dxdbSurfSens_(),
dSdbSens_(),
dndbSens_(),
dxdbDirectSens_(),
dVdbSens_(),
distanceSens_(),
optionsSens_(),
bcSens_(),
derivativesFolder_
(
word("optimisation")/word("derivatives")
/word(mesh.name() == polyMesh::defaultRegion ? word() : mesh.name())
)
{
if (!parametertisedPatches_.size())
{
FatalErrorInFunction
<< "None of the provided parameterised patches is valid"
<< endl
<< exit(FatalError);
}
mkDir(derivativesFolder_);
}
// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * //
Foam::autoPtr<Foam::shapeDesignVariables> Foam::shapeDesignVariables::New
(
fvMesh& mesh,
const dictionary& dict
)
{
const word modelType(dict.get<word>("shapeType"));
Info<< "shapeDesignVariables type : " << modelType << endl;
auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
if (!cstrIter.found())
{
FatalErrorInLookup
(
"shapeType",
modelType,
*dictionaryConstructorTablePtr_
) << exit(FatalError);
}
return autoPtr<shapeDesignVariables>(cstrIter()(mesh, dict));
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * //
bool Foam::shapeDesignVariables::readDict(const dictionary& dict)
{
if (designVariables::readDict(dict))
{
parametertisedPatches_ =
mesh_.boundaryMesh().patchSet(dict.get<wordRes>("patches"));
displMethodPtr_->setPatchIDs(parametertisedPatches_.toc());
writeEachMesh_ =
dict.getOrDefault<bool>("writeEachMesh", true);
return true;
}
return false;
}
void Foam::shapeDesignVariables::storeDesignVariables()
{
designVariables::storeDesignVariables();
if (!pointsInit_)
{
pointsInit_.reset(new pointField(mesh_.nPoints(), Zero));
}
pointsInit_() = mesh_.points();
}
void Foam::shapeDesignVariables::resetDesignVariables()
{
designVariables::resetDesignVariables();
mesh_.movePoints(pointsInit_());
}
void Foam::shapeDesignVariables::moveMesh()
{
// Move mesh
displMethodPtr_->update();
if (writeEachMesh_)
{
Info<< " Writing new mesh points for mesh region "
<< mesh_.name() << endl;
pointIOField points
(
IOobject
(
"points",
mesh_.pointsInstance(),
mesh_.meshSubDir,
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE,
false
),
mesh_.points()
);
points.write();
}
// Check mesh quality
mesh_.checkMesh(true);
}
Foam::tmp<Foam::scalarField> Foam::shapeDesignVariables::assembleSensitivities
(
adjointSensitivity& adjointSens
)
{
// Return field
tmp<scalarField> tsens(tmp<scalarField>::New(sensSize(), Zero));
scalarField& sens = tsens.ref();
// Reset sensitivity components to zero
allocateSensFields();
zeroSensFields();
// Grab multipliers from the adjoint sensitivities
const autoPtr<volTensorField>& gradDxDbMult = adjointSens.gradDxDbMult();
const autoPtr<scalarField>& divDxDbMult = adjointSens.divDxDbMult();
const autoPtr<boundaryVectorField>& dxdbMult = adjointSens.dxdbMult();
const autoPtr<boundaryVectorField>& dSdbMult = adjointSens.dSfdbMult();
const autoPtr<boundaryVectorField>& dndbMult = adjointSens.dnfdbMult();
const autoPtr<boundaryVectorField>& dxdbDirectMult =
adjointSens.dxdbDirectMult();
const autoPtr<boundaryVectorField>& bcDxDbmult = adjointSens.bcDxDbMult();
const autoPtr<vectorField>& optionsDxDbMult = adjointSens.optionsDxDbMult();
const volScalarField::Internal& V = mesh_.V();
autoPtr<adjointEikonalSolver>& eikonalSolver =
adjointSens.getAdjointEikonalSolver();
autoPtr<volTensorField> distanceSens(nullptr);
if (adjointSens.includeDistance())
{
distanceSens.reset
(
new volTensorField(eikonalSolver->getFISensitivityTerm())
);
}
// Loop over active design variables only
for (const label varI : activeSensitivities())
{
// FI approach, integrate terms including variations of the grid
// sensitivities
if (adjointSens.computeDxDbInternalField())
{
// Parameterization info
tmp<volVectorField> tvolDxDbI = dCdb(varI);
const volVectorField& volDxDbI = tvolDxDbI();
tmp<volTensorField> gradDxDb = fvc::grad(volDxDbI);
// Contributions from the adjoint-related part
dxdbVolSens_[varI] = gSum((gradDxDbMult() && gradDxDb())*V);
// Contributions from the distance related part
if (adjointSens.includeDistance())
{
distanceSens_[varI] = gSum((distanceSens() && gradDxDb)*V);
}
// Contributions from the multiplier of divDxDb
if (divDxDbMult)
{
dVdbSens_[varI] +=
gSum(divDxDbMult()*fvc::div(volDxDbI)().primitiveField()*V);
}
// Contributions from fvOptions
optionsSens_[varI] +=
gSum((optionsDxDbMult() & volDxDbI.primitiveField())*V);
}
// Contribution from boundary terms
// Most of them (with the expection of dxdbMult) exist in both the
// FI and E-SI approaches
for (const label patchI : parametertisedPatches_)
{
if (dSdbMult)
{
tmp<vectorField> pdSdb = dSdb(patchI, varI);
dSdbSens_[varI] += gSum(dSdbMult()[patchI] & pdSdb);
}
if (dndbMult)
{
tmp<vectorField> pdndb = dndb(patchI, varI);
dndbSens_[varI] += gSum((dndbMult()[patchI] & pdndb));
}
tmp<vectorField> pdxdb = dxdbFace(patchI, varI);
// Main contribution in the E-SI approach
if (dxdbMult)
{
dxdbSurfSens_[varI] += gSum(dxdbMult()[patchI] & pdxdb());
}
if (dxdbDirectMult)
{
dxdbDirectSens_[varI] +=
gSum((dxdbDirectMult()[patchI] & pdxdb()));
}
if (bcDxDbmult)
{
bcSens_[varI] += gSum((bcDxDbmult()[patchI] & pdxdb()));
}
}
}
sens =
dxdbVolSens_ + dxdbSurfSens_ + dSdbSens_ + dndbSens_ + dxdbDirectSens_
+ dVdbSens_ + distanceSens_ + optionsSens_ + bcSens_;
writeSensitivities(sens, adjointSens);
return tsens;
}
void Foam::shapeDesignVariables::writeSensitivities
(
const scalarField& sens,
const adjointSensitivity& adjointSens
)
{
OFstream derivFile
(
derivativesFolder_/
type() + adjointSens.getAdjointSolver().solverName()
+ adjointSens.getSuffix() + mesh_.time().timeName()
);
unsigned int widthDV = max(int(name(dxdbVolSens_.size()).size()), int(6));
unsigned int width = IOstream::defaultPrecision() + 7;
derivFile
<< setw(widthDV) << "#varID" << " "
<< setw(width) << "total"<< " "
<< setw(width) << "dxdbVol" << " "
<< setw(width) << "dxdbSurf" << " "
<< setw(width) << "dSdb" << " "
<< setw(width) << "dndb" << " "
<< setw(width) << "dxdbDirect" << " "
<< setw(width) << "dVdb" << " "
<< setw(width) << "distance" << " "
<< setw(width) << "options" << " "
<< setw(width) << "dvdb" << endl;
for (const label varI : activeSensitivities())
{
derivFile
<< setw(widthDV) << varI << " "
<< setw(width) << sens[varI] << " "
<< setw(width) << dxdbVolSens_[varI] << " "
<< setw(width) << dxdbSurfSens_[varI] << " "
<< setw(width) << dSdbSens_[varI] << " "
<< setw(width) << dndbSens_[varI] << " "
<< setw(width) << dxdbDirectSens_[varI] << " "
<< setw(width) << dVdbSens_[varI] << " "
<< setw(width) << distanceSens_[varI] << " "
<< setw(width) << optionsSens_[varI] << " "
<< setw(width) << bcSens_[varI] << " "
<< endl;
}
}
Foam::tmp<Foam::vectorField> Foam::shapeDesignVariables::dxdbVol
(
const label varID
) const
{
// Deliberately returning a zero-sized field
return tmp<vectorField>::New(0);
}
Foam::tmp<Foam::vectorField> Foam::shapeDesignVariables::dxdbFace
(
const label patchI,
const label varID
) const
{
NotImplemented;
return nullptr;
}
Foam::tmp<Foam::vectorField> Foam::shapeDesignVariables::dndb
(
const label patchI,
const label varID
) const
{
NotImplemented;
return nullptr;
}
Foam::tmp<Foam::vectorField> Foam::shapeDesignVariables::dSdb
(
const label patchI,
const label varID
) const
{
NotImplemented;
return nullptr;
}
Foam::tmp<Foam::volVectorField>
Foam::shapeDesignVariables::dCdb(const label varID) const
{
NotImplemented;
return nullptr;
}
// ************************************************************************* //

View File

@ -0,0 +1,296 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2007-2023 PCOpt/NTUA
Copyright (C) 2013-2023 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 <http://www.gnu.org/licenses/>.
Class
Foam::shapeDesignVariables
Description
Abstract base class for defining design variables for shape optimisation.
SourceFiles
shapeDesignVariables.C
\*---------------------------------------------------------------------------*/
#ifndef shapeDesignVariables_H
#define shapeDesignVariables_H
#include "designVariables.H"
#include "displacementMethod.H"
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class shapeDesignVariables Declaration
\*---------------------------------------------------------------------------*/
class shapeDesignVariables
:
public designVariables
{
protected:
// Protected data
//- Patches to be moved by the design variables
labelHashSet parametertisedPatches_;
//- Mesh movement mechanism
autoPtr<displacementMethod> displMethodPtr_;
//- Store old points. Useful for line search
autoPtr<pointField> pointsInit_;
//- Write the mesh points irrespective of whether this is a write time
bool writeEachMesh_;
// Auxiliary fields keeping track of the various sensitiity components
//- Flow related term.
// Term including grad(dxdb) in the volume integrals of the FI
// formulation
scalarField dxdbVolSens_;
//- Flow related term.
// Main term in the E-SI formulation. Is the surface intergral
// emerging after performing the Gauss-divergence theorem on the
// FI-based sensitivities
scalarField dxdbSurfSens_;
//- Term depending on delta(n dS)/delta b
scalarField dSdbSens_;
//- Term depending on delta(n)/delta b
scalarField dndbSens_;
//- Term depending on delta(x)/delta b for objectives that directly
//- depend on x
scalarField dxdbDirectSens_;
//- Term depending on delta(V)/delta b
scalarField dVdbSens_;
//- Term depending on distance differentiation
scalarField distanceSens_;
//- Term depending on fvOptions
scalarField optionsSens_;
//- Term depending on the differenation of boundary conditions
scalarField bcSens_;
//- Name of the sensitivity derivatives folder
fileName derivativesFolder_;
// Protected Member Functions
//- Size of the sensitivity derivatives.
// Might be different than this->size() in some cases
virtual label sensSize() const;
//- Active variables for which to compute sensitivities
// Might be different than this->activeDesignVariables_ in some cases
virtual const labelList& activeSensitivities() const;
//- Compute dxdb at the mesh cell centers by solving a Laplace PDE
virtual tmp<volVectorField> solveMeshMovementEqn
(
const label patchI,
const label varID
) const;
//- Allocate the fields assosiated with the computation of sensitivities
// Not allocated in the constructor since the size of the design
// variables is usually not known there
void allocateSensFields();
//- Zero the fields assosiated with the computation of sensitivities
void zeroSensFields();
private:
// Private Member Functions
//- Disallow default bitwise copy construct
shapeDesignVariables(const shapeDesignVariables&) = delete;
//- Disallow default bitwise assignment
void operator=(const shapeDesignVariables&) = delete;
public:
//- Runtime type information
TypeName("shape");
// Declare run-time constructor selection table
declareRunTimeSelectionTable
(
autoPtr,
shapeDesignVariables,
dictionary,
(
fvMesh& mesh,
const dictionary& dict
),
(mesh, dict)
);
// Constructors
//- Construct from components
shapeDesignVariables
(
fvMesh& mesh,
const dictionary& dict
);
// Selectors
//- Construct and return the selected shapeDesignVariables
static autoPtr<shapeDesignVariables> New
(
fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~shapeDesignVariables() = default;
// Member Functions
//- Read dictionary if changed
virtual bool readDict(const dictionary& dict);
//- Update design variables based on a given correction.
// Translates the scalarField of corrections to a meaningful
// update of the design variables
virtual void update(scalarField& correction) = 0;
//- Store design variables, as the starting point for line search
virtual void storeDesignVariables();
//- Reset to starting point of line search
virtual void resetDesignVariables();
//- Compute eta if not set in the first step
virtual scalar computeEta(scalarField& correction) = 0;
//- Whether to use global sum when computing matrix-vector products
//- in update methods
// Depends on whether the design variables are common for all
// processors (e.g. volumetric B-Splines control points) or distributed
// across them (e.g. topology optimisation)
virtual bool globalSum() const = 0;
// Functions related to mesh movement
//- Move mesh based on displacementMethod
virtual void moveMesh();
//- Patches affected by the parameterisation
inline const labelHashSet& getPatches() const
{
return parametertisedPatches_;
}
//- Return displacementMethod
inline autoPtr<displacementMethod>& returnDisplacementMethod()
{
return displMethodPtr_;
}
// Fields related to sensitivity computations
//- Add part of sensitivity derivatives related to geometry
//- variations
virtual tmp<scalarField> assembleSensitivities
(
adjointSensitivity& adjointSens
);
//- Write final sensitivity derivatives to files
virtual void writeSensitivities
(
const scalarField& sens,
const adjointSensitivity& adjointSens
);
//- Get dxdb for all mesh points
virtual tmp<vectorField> dxdbVol
(
const label varID
) const;
//- Get dxdb for a given design variable and patch
virtual tmp<vectorField> dxdbFace
(
const label patchI,
const label varID
) const;
//- Get dndb for a given design variable and patch
virtual tmp<vectorField> dndb
(
const label patchI,
const label varID
) const;
//- Get dSdb for a given design variable and patch
virtual tmp<vectorField> dSdb
(
const label patchI,
const label varID
) const;
//- Get dCdb for a given design variable.
// Used for FI-based sensitivities
virtual tmp<volVectorField> dCdb(const label varID) const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

Some files were not shown because too many files have changed in this diff Show More