diff --git a/applications/solvers/incompressible/adjointOptimisationFoam/adjointOptimisationFoam.C b/applications/solvers/incompressible/adjointOptimisationFoam/adjointOptimisationFoam.C index 7d29d4849783caabea3f670d343b0c722cd85d7d..ddf2c809abf5ac2cc9fddf04759989fb565727bf 100644 --- a/applications/solvers/incompressible/adjointOptimisationFoam/adjointOptimisationFoam.C +++ b/applications/solvers/incompressible/adjointOptimisationFoam/adjointOptimisationFoam.C @@ -64,13 +64,13 @@ 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(); + // Solve all adjoint equations + om.solveAdjointEquations(); + } } Info<< "End\n" << endl; diff --git a/applications/utilities/postProcessing/optimisation/computeSensitivities/computeSensitivities.C b/applications/utilities/postProcessing/optimisation/computeSensitivities/computeSensitivities.C index b7ced6e309fc22fd18a6bbdc37a03ceb403e9979..b1ec73c7553b4ef6ca802299d224a7d8d205dc22 100644 --- a/applications/utilities/postProcessing/optimisation/computeSensitivities/computeSensitivities.C +++ b/applications/utilities/postProcessing/optimisation/computeSensitivities/computeSensitivities.C @@ -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()); } } diff --git a/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/Make/files b/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/Make/files deleted file mode 100644 index c6e8c8fb9df222cf7edec704aa32792d9d3fd819..0000000000000000000000000000000000000000 --- a/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/Make/files +++ /dev/null @@ -1,3 +0,0 @@ -writeActiveDesignVariables.C - -EXE = $(FOAM_APPBIN)/writeActiveDesignVariables diff --git a/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/Make/options b/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/Make/options deleted file mode 100644 index f5b51c5ca77603cf7808511472bb86c85434649f..0000000000000000000000000000000000000000 --- a/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/Make/options +++ /dev/null @@ -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 diff --git a/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/writeActiveDesignVariables.C b/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/writeActiveDesignVariables.C deleted file mode 100644 index b87b0bb837a981aed18cc9cbab47ae873d0c59a0..0000000000000000000000000000000000000000 --- a/applications/utilities/preProcessing/optimisation/writeActiveDesignVariables/writeActiveDesignVariables.C +++ /dev/null @@ -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; -} - - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.C index d6791326aabf9e58ebb0a331734147b705a48482..9a3bb69b9fe7c858ae734a2a68eb3c5e88ec2dae 100644 --- a/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.C +++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/ATCModel/ATCModel.C @@ -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(); } } diff --git a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.C b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.C index 9f1d346ed74e35c18af542ac91dd862eee08daee..714af8c9219209d9294bd5b493d9a5a53008e44b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.C +++ b/src/optimisation/adjointOptimisation/adjoint/ATCModel/zeroATCcells/faceCells/faceCells.C @@ -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>()) diff --git a/src/optimisation/adjointOptimisation/adjoint/Make/files b/src/optimisation/adjointOptimisation/adjoint/Make/files index c389a14403696b1e5a0aeee6670221c64043b159..8a1b1662f60c97c00dcc8afb75898825df3add20 100644 --- a/src/optimisation/adjointOptimisation/adjoint/Make/files +++ b/src/optimisation/adjointOptimisation/adjoint/Make/files @@ -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 diff --git a/src/optimisation/adjointOptimisation/adjoint/Make/options b/src/optimisation/adjointOptimisation/adjoint/Make/options index f3041856b6bfa06999842fbb96bea046f58490db..0853278b17d98c7b242ad34de6f9f0294530ffd1 100644 --- a/src/optimisation/adjointOptimisation/adjoint/Make/options +++ b/src/optimisation/adjointOptimisation/adjoint/Make/options @@ -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 diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C index 9523408d2d2855d854e0efbc8ad660de76875787..d7f399de4fc397739b49851c9c9a2f6f6e6bb491 100644 --- a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C +++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointBoundaryCondition/adjointBoundaryCondition.C @@ -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; } diff --git a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C index 0172840bb03f01e65e680a2dda7bbfa24ee757a2..0b59ba177007f692142d09ad8d78b0a9183010fc 100644 --- a/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C +++ b/src/optimisation/adjointOptimisation/adjoint/adjointBoundaryConditions/adjointWallVelocity/adjointWallVelocityFvPatchVectorField.C @@ -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 diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C index 004ea4b0ae786374c0502f46531d8e4219755ca5..a8220f2639d9af36ca102ef8e6e9a0ab17bbe3d8 100644 --- a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C +++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.C @@ -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 diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.H b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.H index b9e52b829469056239160287ea1f0dcfa843f492..fc42c5fb81f7fc437e00b41680b2a7898712de0f 100644 --- a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.H +++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContribution.H @@ -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 // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressibleTemplates.C b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContributionTemplates.C similarity index 79% rename from src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressibleTemplates.C rename to src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContributionTemplates.C index 0fd968f7765a9cff9e32db14594514795c9a862c..dd6503e8a3230b1bea2bc6523f98cdbceaf70f37 100644 --- a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressibleTemplates.C +++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContribution/boundaryAdjointContributionTemplates.C @@ -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,9 +46,12 @@ Foam::boundaryAdjointContributionIncompressible::sumContributions for (sourceType& funcI : sourceList) { castType& cfuncI = refCast<castType>(funcI); - const fvPatchField<returnType>& dJdvar = - (cfuncI.*boundaryFunction)(patch_.index()); - dJtotdvar += cfuncI.weight()*dJdvar; + if ((cfuncI.*hasFunction)()) + { + const fvPatchField<returnType>& dJdvar = + (cfuncI.*boundaryFunction)(patch_.index()); + dJtotdvar += cfuncI.weight()*dJdvar; + } } return tdJtotdvar; diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C index 3d1d19f474cdfd6359a5b0925652b86c5a7d4198..86f780e6b1cd46efdda2cde457fdd9b91d5b520e 100644 --- a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C +++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.C @@ -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()); } diff --git a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.H index d77cec9b254412f34ca8f18ffe1b414088adfa67..b4a4569bcc8935a71b6627020dd86134d0b2c6a3 100644 --- a/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/boundaryAdjointContributions/boundaryAdjointContributionIncompressible/boundaryAdjointContributionIncompressible.H @@ -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 // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.C b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.C index d0da1a72118b629d2fb6567d1d66e78bf8a5caaa..32d5a41fd4566598235aba7df811bb7774115d59 100644 --- a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.C +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.C @@ -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 diff --git a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.H b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.H index 0521fe4edcc39c2566ce12ce8d1ff9d686299dbb..84f30d1c5d279f7fe8391f1db3f6e175860bd20d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.H +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethod/displacementMethod.H @@ -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,33 +133,42 @@ public: // Member Functions - //- Set motion filed related to model based on given motion - virtual void setMotionField(const pointVectorField& pointMovement) = 0; + //- 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; + + //- Set motion filed related to model based on given motion + virtual void setMotionField(const volVectorField& cellMovement) = 0; - //- Set motion filed related to model based on given motion - virtual void setMotionField(const volVectorField& cellMovement) = 0; + //- Set control field as a vectorField. For methods working with + //- parameters (RBF etc) + virtual void setControlField(const vectorField& controlField) = 0; - //- Set control field as a vectorField. For methods working with - //- parameters (RBF etc) - virtual void setControlField(const vectorField& controlField) = 0; + //- Set control field as a vectorField. For methods working with + //- parameters (RBF etc) + virtual void setControlField(const scalarField& controlField) = 0; - //- Set control field as a vectorField. For methods working with - //- parameters (RBF etc) - virtual void setControlField(const scalarField& controlField) = 0; + //- Bound control field in certain directions etc. For methods working + //- with parameters (RBF etc) + //- does nothing by default + virtual void boundControlField(vectorField& controlField); - //- Bound control field in certain directions etc. For methods working - //- with parameters (RBF etc) - //- does nothing by default - virtual void boundControlField(vectorField& controlField); + //- Get access to motionSolver + autoPtr<motionSolver>& getMotionSolver(); - //- Get access to motionSolver - autoPtr<motionSolver>& getMotionSolver(); + //- Get max displacement + scalar getMaxDisplacement() const; - //- Get max displacement - scalar getMaxDisplacement() const; + //- Set parametertised patch IDs + inline void setPatchIDs(const labelList& patchIDs) + { + patchIDs_ = patchIDs; + } - //- Update mesh - void update(); + //- Update mesh + void update(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.C b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.C index f26dc3b132bb9bcd1aa59ad442ea9d0c45d81264..8aa927342b69733473ee1cdba56db39de32448df 100644 --- a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.C @@ -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])) ); } } diff --git a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.H b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.H index 50b8ec4df825bfab82c9f6b1a51075b49497b4e4..6077cbc4d85db7cbc61fa771354445e9b446077e 100644 --- a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodelasticityMotionSolver/displacementMethodelasticityMotionSolver.H @@ -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); diff --git a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.C b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.C index 873aff3d7984bb481ea9a16506630a758a2f25aa..dfdcdb544479e277fd1cf5122773f6b9fd101301 100644 --- a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.C @@ -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])) ); } - */ } diff --git a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.H b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.H index 083ab095893b01209457aa1b5733ac12c6e13b07..e1d73c39c2397d4e3aba5af0f3cf383a5684556d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodlaplacianMotionSolver/displacementMethodlaplacianMotionSolver.H @@ -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); diff --git a/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodpLaplacianMotionSolver/displacementMethodpLaplacianMotionSolver.C b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodpLaplacianMotionSolver/displacementMethodpLaplacianMotionSolver.C new file mode 100644 index 0000000000000000000000000000000000000000..d73d0d270b327b9af3fab8296345e5978cdb5d90 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodpLaplacianMotionSolver/displacementMethodpLaplacianMotionSolver.C @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplines/optMeshMovementVolumetricBSplines.H b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodpLaplacianMotionSolver/displacementMethodpLaplacianMotionSolver.H similarity index 54% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplines/optMeshMovementVolumetricBSplines.H rename to src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodpLaplacianMotionSolver/displacementMethodpLaplacianMotionSolver.H index 5c39b97d7ffa03a6359f12edc1abdccc9c6107f3..dc599353593b2457ac2490aafbc9bfaa55cd62b1 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplines/optMeshMovementVolumetricBSplines.H +++ b/src/optimisation/adjointOptimisation/adjoint/displacementMethod/displacementMethodpLaplacianMotionSolver/displacementMethodpLaplacianMotionSolver.H @@ -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_; - - //- Backup of initial control points. Useful for line-search - List<vectorField> cpsInit_; - + pointVectorField& pointMotionU_; - // Protected Member Functions + volVectorField& cellMotionU_; - 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); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.C b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.C index 663f7e3ea9a510bd7823a48bca62ee5dcf5d812a..3778a5cce99a42d0236c23a170121958eb811e3c 100644 --- a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.C @@ -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 - ), - fvMesh_, - dimensionedScalar(dimless, Zero), - fvPatchFieldBase::zeroGradientType() + motionDiffusivity::New(fvMesh_, coeffDict().lookup("diffusivity")) ), - 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") + ); } diff --git a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.H b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.H index f6c2f0dc058a5c3530de9800d2234c4acce0dc08..2fd11babf307685dea484a15ea7386a37c585e6b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/elasticityMotionSolver/elasticityMotionSolver.H @@ -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_; diff --git a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.C b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.C index fa7039ff5928754bddb53673a8892d9050c6f9f3..d53daf1d13e30128c3254d973c79a3238e00820e 100644 --- a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.C @@ -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") + ); } diff --git a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.H b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.H index f2cf0471d11c5ce044e4de4e573a90b5d22457c2..66f397c57e659d0324a528143df353eaa7042c73 100644 --- a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/laplacianMotionSolver/laplacianMotionSolver.H @@ -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&); diff --git a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolver.C b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolver.C new file mode 100644 index 0000000000000000000000000000000000000000..6b03ef4a5de3a9601c0e90cf3a94cf3a4890fbfb --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolver.C @@ -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 +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolver.H b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolver.H new file mode 100644 index 0000000000000000000000000000000000000000..37baaa7041edb3d044a8de3ff4e4b3a885e6bbb2 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolver.H @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressibleI.H b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolverI.H similarity index 65% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressibleI.H rename to src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolverI.H index c6274f3b4420b1cb540546b1ba1e411a388a3c81..3aba688f93022bcc105d76a4eff758fc7f7d1606 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressibleI.H +++ b/src/optimisation/adjointOptimisation/adjoint/dynamicMesh/motionSolver/pLaplacianMotionSolver/pLaplacianMotionSolverI.H @@ -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 -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolateAdjoint.C b/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolateAdjoint.C new file mode 100644 index 0000000000000000000000000000000000000000..e174ef78889cb553931227efac3733400d566261 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolateAdjoint.C @@ -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); +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolationAdjoint.C b/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolationAdjoint.C new file mode 100644 index 0000000000000000000000000000000000000000..63e07ae5266317080b92e899a5ffba5afe4507e0 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolationAdjoint.C @@ -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(); + } +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolationAdjoint.H b/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolationAdjoint.H new file mode 100644 index 0000000000000000000000000000000000000000..78225457b8ba34b3a8a826df5bb05f2cc5954272 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/interpolation/volPointInterpolation/volPointInterpolationAdjoint.H @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.C b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager.C similarity index 82% rename from src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.C rename to src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager.C index f3d2819ba5a6e978e0fbad3352a13afce898b428..39b36884316b017a38265f9e9e2366b7bcfb4eec 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager.C @@ -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() } -bool objectiveManager::writeObjectives -( - const scalar weightedObjective, - const bool valid -) +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 - obj.write(); - obj.writeMeanValue(); + if (obj.shouldWrite()) + { + obj.write(); + obj.writeMeanValue(); + } } - if (weigthedObjectiveFile_) + return true; +} + + +bool objectiveManager::writeObjectives +( + const scalar weightedObjective, + const bool valid +) +{ + 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 diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.H b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager.H similarity index 75% rename from src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.H rename to src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager.H index 0aeacc6b484ba4a72b9e60bc82add78a68a85488..951e53c11633fbff494be6d21cb37d53bec876fe 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager/objectiveManager.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManager.H @@ -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; - - //- 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; + virtual void addSource(fvVectorMatrix& matrix); - //- 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 diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C deleted file mode 100644 index 44aaa1a0a73ae7d38f2d104cb21330bb24163e16..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectiveGeometric/objectiveGeometric.C b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectiveGeometric/objectiveGeometric.C new file mode 100644 index 0000000000000000000000000000000000000000..548329f9a95788c69912d2cd9200ba6694e5d608 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectiveGeometric/objectiveGeometric.C @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectiveGeometric/objectiveGeometric.H similarity index 58% rename from src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectiveGeometric/objectiveGeometric.H index ff13355b09f3ff369302ddbde1e10a6df4df59cd..29e14cd11e1bf8ba484a30c703e938cbffe645e5 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectiveManager/objectiveManagerIncompressible/objectiveManagerIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectiveGeometric/objectiveGeometric.H @@ -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,52 @@ 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, @@ -87,23 +102,29 @@ public: ); - //- Destructor - virtual ~objectiveManagerIncompressible() = default; + // Selectors + //- Return a reference to the selected turbulence model + static autoPtr<objectiveGeometric> New + ( + const fvMesh& mesh, + const dictionary& dict, + const word& adjointSolverName, + const word& primalSolverName + ); - // Member Functions - //- Add contribution to adjoint momentum PDEs - virtual void addUaEqnSource(fvVectorMatrix& UaEqn); + //- Destructor + virtual ~objectiveGeometric() = default; + - //- Add contribution to adjoint momentum PDEs - virtual void addPaEqnSource(fvScalarMatrix& paEqn); + // Member Functions - //- Add contribution to adjoint turbulence model PDE - virtual void addTMEqn1Source(fvScalarMatrix& adjTMEqn1); + //- Return the objective function value + virtual scalar J() = 0; - //- Add contribution to adjoint turbulence model PDE - virtual void addTMEqn2Source(fvScalarMatrix& adjTMEqn2); + //- Update objective function derivatives + virtual void update(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePartialVolume/objectivePartialVolume.C b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectivePartialVolume/objectivePartialVolume.C similarity index 88% rename from src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePartialVolume/objectivePartialVolume.C rename to src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectivePartialVolume/objectivePartialVolume.C index 5df2db8b9de6cc5a353259eb40e1a771311d8936..f131efa41808030980d17e5a31937f4dc858663d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePartialVolume/objectivePartialVolume.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectivePartialVolume/objectivePartialVolume.C @@ -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; } diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePartialVolume/objectivePartialVolume.H b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectivePartialVolume/objectivePartialVolume.H similarity index 91% rename from src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePartialVolume/objectivePartialVolume.H rename to src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectivePartialVolume/objectivePartialVolume.H index 4aef943fc8564bb560fed9112194039547da93cd..bc9527a5d7b9cd38427434b01e0b4e7aaf3b9bff 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePartialVolume/objectivePartialVolume.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/geometric/objectivePartialVolume/objectivePartialVolume.H @@ -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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.C index 393f792ca111ff2bed482f1710a0887d588ed9a3..d201396112cdac90a802b579781af38e8f8a91a1 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveForce/objectiveForce.C @@ -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(); } } diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C index 9c54784d847211ca8aad03392eaec6f673034be0..8fb87d88e64fd69f1d68b75bca6fe90450dfc8df 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.C @@ -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); diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.H index eb2b89fae94a58d4fc4ddf4098e5b28293e7b1d4..8af411bf18e49fff4a43043449d06ba8f55775fc 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressible.H @@ -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() - {} - - virtual void update_dSdbMultiplier() - {} - - virtual void update_dndbMultiplier() - {} + //- Vector sources can be given only to the adjoint momentum equations. + //- Implemented in base objectiveIncompressible + virtual void addSource(fvVectorMatrix& matrix); - virtual void update_dxdbMultiplier() + //- 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_dxdbDirectMultiplier() - {} //- Some objectives need to store some auxiliary values. //- If averaging is enabled, update these mean values here. diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressibleI.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressibleI.H index a1f72dafb37ac335707815aeda7d5c37b2a06b6c..3e3b05324dc0acf44ad6bc4dfa9589fabe0c8c0b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressibleI.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveIncompressible/objectiveIncompressibleI.H @@ -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_); diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.C index 52765b47e18909d14d9439442644b5a9b65d32a6..f1dd11d622aab086bd4e899930c87241067322ab 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveMoment/objectiveMoment.C @@ -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 diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.C index debd1ae1a026e700322ce24a356e6c0124149dcc..96e868c0861f01f9f2c67669aee772e9d06342db 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.C @@ -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_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), 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) + 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 diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.H index a429c6d6a9ed68d3e029166facfb11ecd3dd5046..4b3b875258323f3a47e6c41579d45b52c6b339e8 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveNutSqr/objectiveNutSqr.H @@ -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); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.C index ae7f98112a96f4acd30f48519dce7fd1af6c5b0c..2a910db9a252a44611de3564d25b94a7946fb789 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.C @@ -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_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), 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) + 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_(); + } } diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.H b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.H index 4f2379d113e98399f5448ab192e404b5b5a1c0ef..6f744de07b75e66cd95b9f4b9558bb716f6d0ac4 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePowerDissipation/objectivePowerDissipation.H @@ -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); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.C index 20ee9e921f5c616b26c9bb0cd11cd1fc8652b9a0..fef3492b9579d4f1c2b18ae483a5f2dcd2d643cb 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectivePtLosses/objectivePtLosses.C @@ -107,7 +107,7 @@ void objectivePtLosses::initialize() const scalar mass = gSum(phiPatch); if (mag(mass) > SMALL) { - objectiveReportPatches.append(patchI); + objectiveReportPatches.push_back(patchI); } } } diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityCellZone/objectiveUniformityCellZone.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityCellZone/objectiveUniformityCellZone.C index 62fcd785042216b229f4123679e12de376f112da..7314896024b6cb98268bfab4486067c863f553d0 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityCellZone/objectiveUniformityCellZone.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityCellZone/objectiveUniformityCellZone.C @@ -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_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), 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) + dimensionedScalar(sqr(dimLength)/pow3(dimTime), Zero), + fvPatchFieldBase::zeroGradientType() ) ); } diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityPatch/objectiveUniformityPatch.C b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityPatch/objectiveUniformityPatch.C index f1a73419517bb2cef90608dd618da8bc8ee849a4..c6f5bd91debc0e802def6a369e02dacd04caa04d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityPatch/objectiveUniformityPatch.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/incompressible/objectiveUniformityPatch/objectiveUniformityPatch.C @@ -106,7 +106,7 @@ void objectiveUniformityPatch::initialize() const scalar mass = gSum(phiPatch); if (mass > SMALL) { - objectiveReportPatches.append(patchI); + objectiveReportPatches.push_back(patchI); } } } diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C index 76c4fb4e3a6bc1ae5b47bb64d2ef666c30bef71a..eca940fdf7af312e0ddb1ed7d3e00f75e76fe0ed 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.C @@ -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 @@ -260,7 +277,14 @@ scalar objective::JCycle() const // Subtract target, in case the objective is used as a constraint if (target_.valid()) { - J -= target_(); + if (negate) + { + J = - J + targetLeft_(); + } + else + { + J -= target_(); + } } // Normalize here, in order to get the correct value for line search @@ -268,6 +292,7 @@ scalar objective::JCycle() const { 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) - ) - ); - } - - return *dJdbPtr_; -} + // Objective function value + J(); + // 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(); } diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H index 49f3d46343d43d507cc4eb9c7dfe6ba42df181d4..7d0270d8cc4a2c511a1e9b56823264108f91ec6f 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objective.H @@ -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; }; diff --git a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveI.H b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveI.H index 4c11fa047d44b707b1b7fff8a3f8ae183f4d248d..5cb1f9d5e985cae08c236eb8fe2877e7ad2f08c5 100644 --- a/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveI.H +++ b/src/optimisation/adjointOptimisation/adjoint/objectives/objective/objectiveI.H @@ -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; +} + + // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointEikonalSolver/adjointEikonalSolver.C similarity index 71% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.C rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointEikonalSolver/adjointEikonalSolver.C index bdffd2682eb2bacec758f5189c1e5a8d97b2b818..782f4c1e7834390fc7d73121e2f68bfc30a35c54 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointEikonalSolver/adjointEikonalSolver.C @@ -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()); @@ -262,32 +289,35 @@ boundaryVectorField& adjointEikonalSolver::distanceSensitivities() } -tmp<volTensorField> adjointEikonalSolver::getFISensitivityTerm() const +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 ( - IOobject + tmp<volVectorField>::New ( - "gradDDa", - mesh_.time().timeName(), + IOobject + ( + "gradDDa", + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::AUTO_WRITE + ), mesh_, - IOobject::NO_READ, - IOobject::AUTO_WRITE - ), - mesh_, - dimensionedVector(d.dimensions()*da_.dimensions()/dimLength, Zero), - patchDistMethod::patchTypes<vector>(mesh_, wallPatchIDs_) + 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 // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointEikonalSolver/adjointEikonalSolver.H similarity index 91% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointEikonalSolver/adjointEikonalSolver.H index 7bfd9b5e29c3656f991096bc529ae177b4716b0a..3613265d4dcdacbda6ee61d4e46e658526285eed 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointEikonalSolver/adjointEikonalSolverIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointEikonalSolver/adjointEikonalSolver.H @@ -27,7 +27,7 @@ License Class - Foam::incompressible::adjointEikonalSolver + Foam::adjointEikonalSolver Description Solver of the adjoint to the eikonal PDE @@ -123,25 +123,26 @@ 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 + Class adjointEikonalSolver Declaration \*---------------------------------------------------------------------------*/ class adjointEikonalSolver @@ -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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivity.C similarity index 58% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.C rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivity.C index 0cd4e7565f097d8bd51d77f3c649aa6ea1b239f5..326c096f58bb328fa3b25ed05ff351f5b19e5a6c 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivity.C @@ -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,81 +117,84 @@ autoPtr<adjointSensitivity> adjointSensitivity::New // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // -const scalarField& adjointSensitivity::calculateSensitivities() +bool adjointSensitivity::readDict(const dictionary& dict) { - assembleSensitivities(); - write(type()); - return derivatives_; -} + 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; + } -const scalarField& adjointSensitivity::getSensitivities() const -{ - return derivatives_; + return false; } -void adjointSensitivity::clearSensitivities() +bool adjointSensitivity::computeDxDbInternalField() const { - derivatives_ = scalar(0); - if (fieldSensPtr_) - { - fieldSensPtr_().primitiveFieldRef() = scalar(0); - } + return false; } -void adjointSensitivity::write(const word& baseName) +void adjointSensitivity::assembleSensitivities +( + autoPtr<designVariables>& designVars +) { - sensitivity::write(baseName); + derivatives_ = designVars->assembleSensitivities(*this); } -tmp<volTensorField> adjointSensitivity::computeGradDxDbMultiplier() +const scalarField& adjointSensitivity::calculateSensitivities +( + autoPtr<designVariables>& designVars +) { - return adjointSolver_.computeGradDxDbMultiplier(); + assembleSensitivities(designVars); + write(type()); + return derivatives_; } -tmp<volVectorField> adjointSensitivity::adjointMeshMovementSource() +const scalarField& adjointSensitivity::getSensitivities() const { - 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) - ) - ); + return derivatives_; +} - volVectorField& source = tadjointMeshMovementSource.ref(); - source -= fvc::div(gradDxDbMult.T()); +void adjointSensitivity::clearSensitivities() +{ + derivatives_ = Zero; + if (fieldSensPtr_) + { + fieldSensPtr_().primitiveFieldRef() = Zero; + } + if (eikonalSolver_) + { + eikonalSolver_->reset(); + } + if (adjointMeshMovementSolver_) + { + adjointMeshMovementSolver_->reset(); + } +} - // Terms from fvOptions - fv::options::New(this->mesh_).postProcessSens - ( - source.primitiveFieldRef(), adjointVars_.solverName() - ); - return (tadjointMeshMovementSource); +void adjointSensitivity::write(const word& baseName) +{ + sensitivity::write(baseName); } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace incompressible } // End namespace Foam // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivity.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivity.H new file mode 100644 index 0000000000000000000000000000000000000000..a476777a096cddfb99edd84ab43269a260f21c2f --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivity.H @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivityI.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivityI.H new file mode 100644 index 0000000000000000000000000000000000000000..a84fa65405ecb7c9b99bee91fa81e6694b4a2c3b --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/adjointSensitivity/adjointSensitivityI.H @@ -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_; +} + + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/multiple/sensitivityMultiple.C similarity index 82% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.C rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/multiple/sensitivityMultiple.C index 2945d88272ba952a8ee51b488c9d615618fc81a4..f616b5aaeb1d27fb74ad7bd42315b4aa03b288bf 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/multiple/sensitivityMultiple.C @@ -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 // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/multiple/sensitivityMultiple.H similarity index 89% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/multiple/sensitivityMultiple.H index 09a14d66edcc5e8b1e1b3868221dc4c996edb83b..c882c7afe76d09840c66c0afdf19e6df3d5a15e8 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityMultiple/sensitivityMultipleIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/multiple/sensitivityMultiple.H @@ -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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/ESI/sensitivityShapeESI.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/ESI/sensitivityShapeESI.C new file mode 100644 index 0000000000000000000000000000000000000000..0e3c15ab24d5380e7554e2e89978ecfd34ab20c0 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/ESI/sensitivityShapeESI.C @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementBezier/optMeshMovementBezier.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/ESI/sensitivityShapeESI.H similarity index 59% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementBezier/optMeshMovementBezier.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/ESI/sensitivityShapeESI.H index 94d19f2fa4aca4fe984e2b0d46d77b162a74e51c..d3f2ca8cc1714f096bf08bd804624138f3fde170 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementBezier/optMeshMovementBezier.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/ESI/sensitivityShapeESI.H @@ -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(); - - //- Compute eta value based on max displacement - virtual scalar computeEta(const scalarField& correction); + //- Read dict if changed + virtual bool readDict(const dictionary& dict); - //- 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 + ); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/FI/sensitivityShapeFI.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/FI/sensitivityShapeFI.C new file mode 100644 index 0000000000000000000000000000000000000000..d68f332896c643bd592b7ed3ec2df4e7e236b083 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/FI/sensitivityShapeFI.C @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementNULL/optMeshMovementNULL.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/FI/sensitivityShapeFI.H similarity index 66% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementNULL/optMeshMovementNULL.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/FI/sensitivityShapeFI.H index eaccf4d71cdde16a11219b601ee9aa5bf0928e48..7edbc1a3b85fe2cbf2f6e506d4610dcda32d091b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementNULL/optMeshMovementNULL.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/FI/sensitivityShapeFI.H @@ -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 + ); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/adjointMeshMovementSolver/adjointMeshMovementSolver.C similarity index 53% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/adjointMeshMovementSolver/adjointMeshMovementSolver.C index 663db50998daa3e5bbeac91d1872e577541a49a0..ea19da52b741373456d5a2bfe8a75292694f2a3b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/adjointMeshMovementSolver/adjointMeshMovementSolver.C @@ -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 // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/adjointMeshMovementSolver/adjointMeshMovementSolver.H similarity index 58% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/adjointMeshMovementSolver/adjointMeshMovementSolver.H index 814777256a6203c7d6b70fd441517536c1803386..1764cae2e1167ae90d8530f34a2450deb7893482 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointMeshMovementSolver/adjointMeshMovementSolverIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/adjointMeshMovementSolver/adjointMeshMovementSolver.H @@ -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 - 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, 1–18. - http://doi.org/10.1016/j.jcp.2015.08.012 + 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, 1–18. + 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,44 +131,44 @@ 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; // Member Functions - //- Read dict if changed - virtual bool readDict(const dictionary& dict); - - //- Accumulate source term - void accumulateIntegrand(const scalar dt); + //- Read dict if changed + virtual bool readDict(const dictionary& dict); - //- Calculate the adjoint distance field - void solve(); + //- Calculate the adjoint distance field + virtual void solve(); - //- Reset source term - void reset(); + //- Reset the source term + void reset(); - //- Return the sensitivity term depending on da - boundaryVectorField& meshMovementSensitivities(); + //- Return the sensitivity term depending on ma + boundaryVectorField& meshMovementSensitivities(); - //- Return the adjoint distance field - const volVectorField& ma(); + //- Return the adjoint distance field + inline const volVectorField& ma() const + { + return ma_; + } }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace incompressible } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #endif +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBase.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBase.C similarity index 50% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBase.C rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBase.C index 4206d7b787afeb8cf42e96c5310bde445bd27d06..b788697ca1ba3f88db1991c6b643128af2d11f65 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBase.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBase.C @@ -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() { - writeFaceBasedSens(); - writePointBasedSens(); + 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::setSuffix(const word& suffix) +void Foam::ShapeSensitivitiesBase::clearMultipliers() { - surfaceFieldSuffix_ = suffix; + 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(); } 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_(); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBase.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBase.H similarity index 67% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBase.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBase.H index 5389e6de82a74f9ac279dcd8d2cb5590400a1b60..e923ed5f4fcbc701551563088afd9ca245655121 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBase.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBase.H @@ -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, 1–18. + 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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBaseTemplates.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBaseTemplates.C similarity index 89% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBaseTemplates.C rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBaseTemplates.C index ef77ae31432822b9a00a53778d8d03fbdba7cfdd..fe12e31d730bad35b1f92d990ace39f7157baf6a 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/shapeSensitivitiesBase/shapeSensitivitiesBaseTemplates.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/shapeSensitivityBase/ShapeSensitivitiesBaseTemplates.C @@ -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 ) ); diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surface/sensitivitySurface.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surface/sensitivitySurface.C new file mode 100644 index 0000000000000000000000000000000000000000..3d1b1dfd898fe2c79c0d970e7469660330d96c07 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surface/sensitivitySurface.C @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surface/sensitivitySurface.H similarity index 52% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surface/sensitivitySurface.H index a1939835dee0dc040b10595ef1ffd459eb5afbc9..1b1571837ac0e77a7115467a472f1aa35039eb3d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surface/sensitivitySurface.H @@ -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 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); - + //- Assemble sensitivities + virtual void assembleSensitivities + ( + autoPtr<designVariables>& designVars + ); }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace incompressible } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -#include "sensitivitySurfaceIncompressibleI.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - #endif // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surfacePoints/sensitivitySurfacePoints.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surfacePoints/sensitivitySurfacePoints.C new file mode 100644 index 0000000000000000000000000000000000000000..15cc2fc5c61125040fd9baa801ef6adebb976010 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surfacePoints/sensitivitySurfacePoints.C @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surfacePoints/sensitivitySurfacePoints.H similarity index 55% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surfacePoints/sensitivitySurfacePoints.H index bbadffb4c606c885cb17a940b07b5958782a0eed..d432d98bfe2c66c584339aea614699fee1ad0e14 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/adjointSensitivity/shape/surfacePoints/sensitivitySurfacePoints.H @@ -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_; - - //- 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_; - - autoPtr<adjointEikonalSolver> eikonalSolver_; + //- Is point belonging to a symmetry{Plane} + boolList isSymmetryPoint_; - autoPtr<adjointMeshMovementSolver> meshMovementSolver_; + //- Local point normal per symmetry point + vectorField symmPointNormal_;; - //- 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 dict if changed - virtual bool readDict(const dictionary& dict); + //- Read controls and update solver pointers if necessary + void read(); - //- Accumulate sensitivity integrands - virtual void accumulateIntegrand(const scalar dt); + //- Read dict if changed + virtual bool readDict(const dictionary& dict); - //- Assemble sensitivities - virtual void assembleSensitivities(); + //- Return set of patches on which to compute direct sensitivities + virtual const labelHashSet& geometryVariationIntegrationPatches() const; - //- Zero sensitivity fields and their constituents - virtual void clearSensitivities(); + //- Assemble sensitivities + virtual void assembleSensitivities + ( + autoPtr<designVariables>& designVars + ); - virtual void write(const word& baseName = word::null); + //- 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 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/FIBase/FIBaseIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/FIBase/FIBaseIncompressible.C deleted file mode 100644 index c41eda00134d5ee99af6b7e6859d5197288cc0e7..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/FIBase/FIBaseIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/SIBase/SIBaseIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/SIBase/SIBaseIncompressible.C deleted file mode 100644 index ee26064a7effa7ecdaf2e7d7238603013ab9b530..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/SIBase/SIBaseIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.H deleted file mode 100644 index eebb436e9ca9347dafd45c0e910a62434f36ce18..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/adjointSensitivity/adjointSensitivityIncompressible.H +++ /dev/null @@ -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, 1–18. - 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), 255–299. - 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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezier/sensitivityBezierIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezier/sensitivityBezierIncompressible.C deleted file mode 100644 index 2a50491bc1fb581d661dd80754af67a02b54de5e..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezier/sensitivityBezierIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezier/sensitivityBezierIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezier/sensitivityBezierIncompressible.H deleted file mode 100644 index 0422edadeb3dfbc5bdc940ac053be7f16e348024..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezier/sensitivityBezierIncompressible.H +++ /dev/null @@ -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 diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezierFI/sensitivityBezierFIIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezierFI/sensitivityBezierFIIncompressible.C deleted file mode 100644 index aa0411d9a935af1bcbfb5b41b6547dad9c9d91ab..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezierFI/sensitivityBezierFIIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezierFI/sensitivityBezierFIIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezierFI/sensitivityBezierFIIncompressible.H deleted file mode 100644 index 56df11726d28960ee0f201fb70367d0552bb8763..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityBezierFI/sensitivityBezierFIIncompressible.H +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.C deleted file mode 100644 index 3b93e7cbcfad24a337cf22a3bf8e75aa5789f071..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurface/sensitivitySurfaceIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C deleted file mode 100644 index 74e6455ea38cfb46a8eb22ec6a244fd2ba8f8d38..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivitySurfacePoints/sensitivitySurfacePointsIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplines/sensitivityVolBSplinesIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplines/sensitivityVolBSplinesIncompressible.C deleted file mode 100644 index bcd0e1729d28788a1baac9fb9f3aa8a2fa1a2a8f..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplines/sensitivityVolBSplinesIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplines/sensitivityVolBSplinesIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplines/sensitivityVolBSplinesIncompressible.H deleted file mode 100644 index 6343fcf2da2ec4ddc5590f51b20a1f381e3a58b7..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplines/sensitivityVolBSplinesIncompressible.H +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplinesFI/sensitivityVolBSplinesFIIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplinesFI/sensitivityVolBSplinesFIIncompressible.C deleted file mode 100644 index abd779ab9e8c8d60d10863fde542fa7ce3d950df..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplinesFI/sensitivityVolBSplinesFIIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplinesFI/sensitivityVolBSplinesFIIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplinesFI/sensitivityVolBSplinesFIIncompressible.H deleted file mode 100644 index 7077df12baca023e6521991ae364001dda085461..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/sensitivityVolBSplinesFI/sensitivityVolBSplinesFIIncompressible.H +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/shapeSensitivities/shapeSensitivitiesIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/shapeSensitivities/shapeSensitivitiesIncompressible.C deleted file mode 100644 index 9f765dbae5ebba14e5f9d1d102341f3827cf2c4e..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/shapeSensitivities/shapeSensitivitiesIncompressible.C +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/shapeSensitivities/shapeSensitivitiesIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/shapeSensitivities/shapeSensitivitiesIncompressible.H deleted file mode 100644 index 100ea1748d8f6efeda6e58030d95941d67620cbf..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/shapeSensitivities/shapeSensitivitiesIncompressible.H +++ /dev/null @@ -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 - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.C index 6694ed50d76ccb990c0082a29be97edb70b90994..787ee0187698fb5573e1b232ff062a2cb58c4c84 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.C @@ -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(); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.H index aa706a913b94a7f5c863f0464ed9e2e645d79ad4..9a4790c2cbbec73f161d61de41f111de1b69d368 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/sensitivity/sensitivity.H @@ -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); - }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariables.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariables.C new file mode 100644 index 0000000000000000000000000000000000000000..459b4ed2d669f1105477c8b8f1cb55fea2036bb5 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariables.C @@ -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 +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariables.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariables.H new file mode 100644 index 0000000000000000000000000000000000000000..7a684a7a14ff6d3c13fd6ddd040a7f0607d391e4 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariables.H @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementNULL/optMeshMovementNULL.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariablesI.H similarity index 61% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementNULL/optMeshMovementNULL.C rename to src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariablesI.H index a6e1a6de7e25272cf546f93a8afb038b3f29ff7e..928bd54968ec22f0a4a38c38632f386d92634f17 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementNULL/optMeshMovementNULL.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/designVariables/designVariablesI.H @@ -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" +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // +inline const Foam::labelList& +Foam::designVariables::activeDesignVariables() const +{ + return activeDesignVariables_; +} -namespace Foam + +bool Foam::designVariables::isMaxInitChangeSet() const { - defineTypeNameAndDebug(optMeshMovementNULL, 0); - addToRunTimeSelectionTable - ( - optMeshMovement, - optMeshMovementNULL, - dictionary - ); + return maxInitChange_.valid(); } -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // +void Foam::designVariables::setMaxInitChange(const scalar maxInitChange) +{ + maxInitChange_.reset(new scalar(maxInitChange)); +} -Foam::optMeshMovementNULL::optMeshMovementNULL -( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs -) -: - optMeshMovement(mesh, dict, patchIDs) -{} +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_; +} -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -void Foam::optMeshMovementNULL::moveMesh() +Foam::scalarField& Foam::designVariables::lowerBoundsRef() { - // Do nothing + return lowerBounds_.ref(); } -Foam::scalar -Foam::optMeshMovementNULL::computeEta(const scalarField& correction) +Foam::scalarField& Foam::designVariables::upperBoundsRef() { - return scalar(0); + return upperBounds_.ref(); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/Bezier/BezierDesignVariables.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/Bezier/BezierDesignVariables.C new file mode 100644 index 0000000000000000000000000000000000000000..05e11c7614243c838bfa7a98e54c4e03b79d94f2 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/Bezier/BezierDesignVariables.C @@ -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); +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/Bezier/BezierDesignVariables.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/Bezier/BezierDesignVariables.H new file mode 100644 index 0000000000000000000000000000000000000000..02a57434554e6f4816ea01cab84999408cd912f1 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/Bezier/BezierDesignVariables.H @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/shapeDesignVariables/shapeDesignVariables.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/shapeDesignVariables/shapeDesignVariables.C new file mode 100644 index 0000000000000000000000000000000000000000..c1eca2034bcbe36eeb65d91bbb166cdc60f2a518 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/shapeDesignVariables/shapeDesignVariables.C @@ -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; +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/shapeDesignVariables/shapeDesignVariables.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/shapeDesignVariables/shapeDesignVariables.H new file mode 100644 index 0000000000000000000000000000000000000000..66d1010c2ddfcc3aa0bd13853e33a429dd9d03a3 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/shapeDesignVariables/shapeDesignVariables.H @@ -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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/morphingBoxConstaint/morphingBoxConstraint.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/morphingBoxConstaint/morphingBoxConstraint.C new file mode 100644 index 0000000000000000000000000000000000000000..377230d2424d89f163493bef2183251cdd4142e9 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/morphingBoxConstaint/morphingBoxConstraint.C @@ -0,0 +1,220 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "morphingBoxConstraint.H" +#include "volumetricBSplinesDesignVariables.H" +#include "createZeroField.H" +#include "IOmanip.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * * // + +namespace Foam +{ + defineRunTimeSelectionTable(morphingBoxConstraint, dictionary); + defineTypeNameAndDebug(morphingBoxConstraint, 0); +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::morphingBoxConstraint::writeDVSensitivities +( + const scalarField& sens, + const word& solverName +) +{ + if (Pstream::master()) + { + OFstream derivFile + (derivativesFolder_/solverName + mesh_.time().timeName()); + + unsigned int width = IOstream::defaultPrecision() + 7; + derivFile + << setw(width) << "#varID" << " " + << setw(width) << "adjointSensitivity" + << endl; + + const labelList& activeVars = designVariables_.activeDesignVariables(); + forAll(activeVars, varI) + { + const label activeVarI = activeVars[varI]; + derivFile + << setw(width) << activeVarI << " " + << setw(width) << sens[activeVarI] << endl; + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::morphingBoxConstraint::morphingBoxConstraint +( + const fvMesh& mesh, + const dictionary& dict, + volumetricBSplinesDesignVariables& designVariables +) +: + mesh_(mesh), + dict_(dict), + designVariables_(designVariables), + volBSplinesBase_(designVariables.getVolBSplinesBase()), + initialCPs_(3*volBSplinesBase_.getTotalControlPointsNumber()), + initialiseVars_(true), + derivativesFolder_("optimisation"/type() + "Derivatives") +{ + // Store initial control points + const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxes(); + label varID(0); + for (const NURBS3DVolume& boxI : boxes) + { + const vectorField& cps = boxI.getControlPoints(); + for (const vector& cpI : cps) + { + initialCPs_[varID++] = cpI.x(); + initialCPs_[varID++] = cpI.y(); + initialCPs_[varID++] = cpI.z(); + } + } + + // Create sensitivities folder + mkDir(derivativesFolder_); +} + + +// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::morphingBoxConstraint> Foam::morphingBoxConstraint::New +( + const fvMesh& mesh, + const dictionary& dict, + volumetricBSplinesDesignVariables& designVariables +) +{ + const word modelType(dict.getOrDefault<word>("constraintType", "none")); + + Info<< "morphingBoxConstraint type : " << modelType << endl; + + auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType); + + if (!cstrIter.found()) + { + FatalErrorInLookup + ( + "constraintType", + modelType, + *dictionaryConstructorTablePtr_ + ) << exit(FatalError); + } + + return autoPtr<morphingBoxConstraint> + ( + cstrIter()(mesh, dict, designVariables) + ); +} + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // + +void Foam::morphingBoxConstraint::computeBounds +( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds +) +{ + if (lowerBounds || upperBounds) + { + NotImplemented; + } +} + + +void Foam::morphingBoxConstraint::updateBounds +( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds +) +{ + if (designVariables_.updateBounds() && (lowerBounds || upperBounds)) + { + NotImplemented; + } +} + + +Foam::tmp<Foam::scalarField> Foam::morphingBoxConstraint::postProcessSens +( + const scalarField& controlPointSens, + const word& adjointSolverName +) +{ + // Sensitivities w.r.t. the design variables + auto tdvSens + (tmp<scalarField>::New(designVariables_.scalarField::size(), Zero)); + scalarField& dvSens = tdvSens.ref(); + computeDVsSensitivities(dvSens, controlPointSens); + writeDVSensitivities(dvSens, adjointSolverName); + + return tdvSens; +} + + +Foam::scalar Foam::morphingBoxConstraint::computeEta +( + scalarField& correction, + const scalar maxInitChange +) +{ + vectorField cpMovement(designVariables_.controlPointMovement(correction)); + const scalar maxDisplacement + ( + volBSplinesBase_.computeMaxBoundaryDisplacement + ( + cpMovement, + designVariables_.getPatches().toc() + ) + ); + + Info<< "maxAllowedDisplacement/maxDisplacement of boundary\t" + << maxInitChange << "/" << maxDisplacement << endl; + const scalar eta(maxInitChange/ maxDisplacement); + + Info<< "Setting eta value to " << eta << endl; + correction *= eta; + + return eta; +} + + +bool Foam::morphingBoxConstraint::writeData(Ostream& os) const +{ + return true; +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/morphingBoxConstaint/morphingBoxConstraint.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/morphingBoxConstaint/morphingBoxConstraint.H new file mode 100644 index 0000000000000000000000000000000000000000..ec4d6f87a7a607c615f1e8cc9442678639ac0578 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/morphingBoxConstaint/morphingBoxConstraint.H @@ -0,0 +1,239 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::morphingBoxConstraint + +Description + Abstract base class for defining constraints for the control points of + volumetric B-Splines morphing boxes + +SourceFiles + morphingBoxConstraint.C + +\*---------------------------------------------------------------------------*/ + +#ifndef morphingBoxConstraint_H +#define morphingBoxConstraint_H + +#include "volBSplinesBase.H" +#include "runTimeSelectionTables.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declaration +class volumetricBSplinesDesignVariables; + +/*---------------------------------------------------------------------------*\ + Class morphingBoxConstraint Declaration +\*---------------------------------------------------------------------------*/ + +class morphingBoxConstraint +{ +protected: + + // Protected data + + //- Mesh reference + const fvMesh& mesh_; + + //- Volumetric B-Splines variables dict + const dictionary dict_; + + //- Reference to underlaying volumetric B-Splines morpher + volumetricBSplinesDesignVariables& designVariables_; + + //- Easy access to the volBSplinesBase resting in the designVariables_ + volBSplinesBase& volBSplinesBase_; + + //- Initial CPs stored in scalarField + scalarField initialCPs_; + + //- Initialise the design variables + bool initialiseVars_; + + //- Folder holding the twist sensitivities + fileName derivativesFolder_; + + + // Protected Member Functions + + //- Compute sensitivities wrt the design variables (chain rule) + void virtual computeDVsSensitivities + ( + scalarField& dvSens, + const scalarField& cpSens + ) = 0; + + //- Write sensitivities w.r.t. the design variables + void virtual writeDVSensitivities + ( + const scalarField& sens, + const word& name + ); + + +private: + + // Private Member Functions + + //- Disallow default bitwise copy construct + morphingBoxConstraint(const morphingBoxConstraint&) = delete; + + //- Disallow default bitwise assignment + void operator=(const morphingBoxConstraint&) = delete; + + +public: + + //- Runtime type information + TypeName("morphingBoxConstraint"); + + + // Declare run-time constructor selection table + + declareRunTimeSelectionTable + ( + autoPtr, + morphingBoxConstraint, + dictionary, + ( + const fvMesh& mesh, + const dictionary& dict, + volumetricBSplinesDesignVariables& designVariables + ), + (mesh, dict, designVariables) + ); + + + // Constructors + + //- Construct from components + morphingBoxConstraint + ( + const fvMesh& mesh, + const dictionary& dict, + volumetricBSplinesDesignVariables& designVariables + ); + + + // Selectors + + //- Construct and return the selected morphingBoxConstraint + static autoPtr<morphingBoxConstraint> New + ( + const fvMesh& mesh, + const dictionary& dict, + volumetricBSplinesDesignVariables& designVariables + ); + + + //- Destructor + virtual ~morphingBoxConstraint() = default; + + + // Member Functions + + //- Compute the active design variables based on the IDs of the + //- active control point coordinates + virtual labelList computeActiveDesignVariables + ( + const labelList& activeCPCoors + ) = 0; + + //- Transform bounds from control points to design variables + // WIP + virtual void computeBounds + ( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds + ); + + //- Update the bounds of the design variables + // WIP + virtual void updateBounds + ( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds + ); + + //- Convert design variables to control points, stored in a scalarField + virtual tmp<scalarField> designVariablesToControlPoints + ( + const scalarField& designVariables + ) = 0; + + //- Return the design variables corresponding to the given control + //- points + virtual tmp<scalarField> controlPointsToDesignVariables + ( + const scalarField& cps + ) = 0; + + //- Convert the correction of the design variables to the correction of + //- the control points + virtual tmp<scalarField> correctionCPs + ( + const scalarField& correction + ) = 0; + + //- Chain rule from control points to design variables + virtual tmp<scalarField> postProcessSens + ( + const scalarField& controlPointSens, + const word& adjointSolverName + ); + + //- Compute eta if not set in the first step + virtual scalar computeEta + ( + scalarField& correction, + const scalar maxInitChange + ); + + //- Initialise the design variables? + inline bool initialiseVars() const + { + return initialiseVars_; + } + + //- Append useful information to the design variables IOdictionary + virtual bool writeData(Ostream& os) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/none/noConstraint.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/none/noConstraint.C new file mode 100644 index 0000000000000000000000000000000000000000..7c43cf9e4576ed61672fad3bc27dd9ff707c4382 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/none/noConstraint.C @@ -0,0 +1,286 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "noConstraint.H" +#include "volumetricBSplinesDesignVariables.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(noConstraint, 1); + addToRunTimeSelectionTable + ( + morphingBoxConstraint, + noConstraint, + dictionary + ); +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::noConstraint::computeDVsSensitivities +( + scalarField& dvSens, + const scalarField& cpSens +) +{ + dvSens = cpSens; +} + + +void Foam::noConstraint::updateInternalBounds +( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds, + const NURBS3DVolume& boxI, + const label passed +) +{ + const vectorField& cps = boxI.getControlPoints(); + const Vector<label> nCPsDir = boxI.nCPsPerDirection(); + // Internal points + for (label k = 1; k < nCPsDir[2] - 1; ++k) + { + for (label j = 1; j < nCPsDir[1] - 1; ++j) + { + for (label i = 1; i < nCPsDir[0] - 1; ++i) + { + label cpID(boxI.getCPID(i, j, k)); + for (label idir = 0; idir < 3; ++idir) + { + label iIncr(idir == 0); + label jIncr(idir == 1); + label kIncr(idir == 2); + label prevCP + (boxI.getCPID(i - iIncr, j - jIncr, k - kIncr)); + label nextCP + (boxI.getCPID(i + iIncr, j + jIncr, k + kIncr)); + lowerBounds()[3*cpID + idir + passed] = + 0.5 + *( + cps[prevCP].component(idir) + + cps[cpID].component(idir) + ); + upperBounds()[3*cpID + idir + passed] = + 0.5 + *( + cps[nextCP].component(idir) + + cps[cpID].component(idir) + ); + } + } + } + } +} + + +void Foam::noConstraint::updateBoundaryBounds +( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds, + const NURBS3DVolume& boxI, + const label passed +) +{ + const vectorField& cps = boxI.getControlPoints(); + const Vector<label> nCPsDir = boxI.nCPsPerDirection(); + // Loop over boundaries in all directions of the box + for (label ibound = 0; ibound < 3; ++ibound) + { + // Start of iterators in the three directions + Vector<label> minID(1, 1, 1); + // End of iterators in the three directions + Vector<label> maxID(nCPsDir[0] - 2, nCPsDir[1] - 2, nCPsDir[2] - 2); + // Increment of iterators in the three directions + Vector<label> incr(1, 1, 1); + + // Adjust looping in the direction we are examining + minID[ibound] = 0; + maxID[ibound] = nCPsDir[ibound]; + incr[ibound] = nCPsDir[ibound] - 1; + Vector<label> indices(Zero); + label& i = indices[0]; + label& j = indices[1]; + label& k = indices[2]; + + for (k = minID[2]; k < maxID[2]; k += incr[2]) + { + for (j = minID[1]; j < maxID[1]; j += incr[1]) + { + for (i = minID[0]; i < maxID[0]; i += incr[0]) + { + label cpID(boxI.getCPID(i, j, k)); + for (label dir = 0; dir < 3; ++dir) + { + Vector<label> incrMinus(dir == 0, dir == 1, dir == 2); + Vector<label> incrPlus(dir == 0, dir == 1, dir == 2); + // Adjust increment for the ibound direction + incrMinus[ibound] = + label + ( + incrMinus[ibound] + && indices[ibound] == nCPsDir[ibound] - 1 + ); + incrPlus[ibound] = + label(incrMinus[ibound] && indices[ibound] == 0); + label prevCP = + boxI.getCPID + ( + i - incrMinus[0], + j - incrMinus[1], + k - incrMinus[2] + ); + label nextCP = + boxI.getCPID + ( + i + incrPlus[0], + j + incrPlus[1], + k + incrPlus[2] + ); + if (incrMinus[ibound]) + { + lowerBounds()[3*cpID + dir + passed] = + 0.5 + *( + cps[prevCP].component(dir) + + cps[cpID].component(dir) + ); + } + if (incrPlus[ibound]) + { + upperBounds()[3*cpID + dir + passed] = + 0.5 + *( + cps[nextCP].component(dir) + + cps[cpID].component(dir) + ); + } + } + } + } + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::noConstraint::noConstraint +( + const fvMesh& mesh, + const dictionary& dict, + volumetricBSplinesDesignVariables& designVariables +) +: + morphingBoxConstraint(mesh, dict, designVariables) +{ + designVariables_.setSize(3*volBSplinesBase_.getTotalControlPointsNumber()); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // + +void Foam::noConstraint::computeBounds +( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds +) +{ + // Does nothing +} + + +void Foam::noConstraint::updateBounds +( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds +) +{ + if (designVariables_.nonOverlappingCPs() && designVariables_.updateBounds()) + { + DebugInfo + << "Updating bounds for the design variables " << endl; + const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); + label passed(0); + for (const NURBS3DVolume& boxI : boxes) + { + // Bounds for internal control points + updateInternalBounds(lowerBounds, upperBounds, boxI, passed); + // Bounds for boundary points. + // Assumes that the boundary edges remain fixed + updateBoundaryBounds(lowerBounds, upperBounds, boxI, passed); + passed += 3*boxI.getControlPoints().size(); + } + DebugInfo + << "lower bounds " << lowerBounds() << endl; + DebugInfo + << "upper bounds " << upperBounds() << endl; + } +} + + +Foam::labelList Foam::noConstraint::computeActiveDesignVariables +( + const labelList& activeCPCoors +) +{ + return activeCPCoors; +} + + +Foam::tmp<Foam::scalarField> Foam::noConstraint::designVariablesToControlPoints +( + const scalarField& designVariables +) +{ + return designVariables; +} + + +Foam::tmp<Foam::scalarField> Foam::noConstraint::controlPointsToDesignVariables +( + const scalarField& cps +) +{ + return cps; +} + + +Foam::tmp<Foam::scalarField> Foam::noConstraint::correctionCPs +( + const scalarField& correction +) +{ + return correction; +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/none/noConstraint.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/none/noConstraint.H new file mode 100644 index 0000000000000000000000000000000000000000..1fe0113573a4240c16791a8c2ed469eb35136f38 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/morphingBoxConstraints/none/noConstraint.H @@ -0,0 +1,175 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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/>. + +Class + Foam::noConstraint + +Description + Applies no constraints to the control points. + Enforces the non-overlapping bounds, if present. + +SourceFiles + noConstraint.C + +\*---------------------------------------------------------------------------*/ + +#ifndef noConstraint_H +#define noConstraint_H + +#include "morphingBoxConstraint.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class noConstraint Declaration +\*---------------------------------------------------------------------------*/ + +class noConstraint +: + public morphingBoxConstraint +{ + +protected: + + // Protected Member Functions + + //- Compute sensitivities wrt the design variables (chain rule) + void virtual computeDVsSensitivities + ( + scalarField& dvSens, + const scalarField& cpSens + ); + + //- Update the bounds of the internal control points + void updateInternalBounds + ( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds, + const NURBS3DVolume& boxI, + const label passed + ); + + //- Update the bounds of the boundary control points + void updateBoundaryBounds + ( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds, + const NURBS3DVolume& boxI, + const label passed + ); + + +private: + + // Private Member Functions + + //- Disallow default bitwise copy construct + noConstraint(const noConstraint&) = delete; + + //- Disallow default bitwise assignment + void operator=(const noConstraint&) = delete; + + +public: + + //- Runtime type information + TypeName("none"); + + + // Constructors + + //- Construct from components + noConstraint + ( + const fvMesh& mesh, + const dictionary& dict, + volumetricBSplinesDesignVariables& designVariables + ); + + + //- Destructor + virtual ~noConstraint() = default; + + + // Member Functions + + //- Compute the active design variables based on the IDs of the + //- active control point coordinates + virtual labelList computeActiveDesignVariables + ( + const labelList& activeCPCoors + ); + + //- Transform bounds from control points to design variables + // Does nothing in this case + virtual void computeBounds + ( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds + ); + + //- Update the bounds of the design variables + // Will update the bound values if nonOverlappingCPs is active + virtual void updateBounds + ( + autoPtr<scalarField>& lowerBounds, + autoPtr<scalarField>& upperBounds + ); + + //- Convert design variables to control points, stored in a scalarField + virtual tmp<scalarField> designVariablesToControlPoints + ( + const scalarField& designVariables + ); + + //- Return the design variables corresponding to the given control + //- points + virtual tmp<scalarField> controlPointsToDesignVariables + ( + const scalarField& cps + ); + + //- Convert the correction of the design variables to the correction of + //- the control points + virtual tmp<scalarField> correctionCPs + ( + const scalarField& correctionDVs + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/volumetricBSplinesDesignVariables.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/volumetricBSplinesDesignVariables.C new file mode 100644 index 0000000000000000000000000000000000000000..d20d3e08b7de961d0c97d661481faa536ccab182 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/volumetricBSplinesDesignVariables.C @@ -0,0 +1,600 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "volumetricBSplinesDesignVariables.H" +#include "pointVolInterpolation.H" +#include "displacementMethodvolumetricBSplinesMotionSolver.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(volumetricBSplinesDesignVariables, 0); + addToRunTimeSelectionTable + ( + shapeDesignVariables, + volumetricBSplinesDesignVariables, + dictionary + ); +} + + +// * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * * // + +Foam::label Foam::volumetricBSplinesDesignVariables::sensSize() const +{ + return 3*volBSplinesBase_.getTotalControlPointsNumber(); +} + + +const Foam::labelList& +Foam::volumetricBSplinesDesignVariables::activeSensitivities() const +{ + return volBSplinesBase_.getActiveDesignVariables(); +} + + +void Foam::volumetricBSplinesDesignVariables::setActiveDesignVariables() +{ + // Active design variables pertaining to the CPs numbering + labelList activeVarsInCPs = volBSplinesBase_.getActiveDesignVariables(); + + // Convert the aforementioned list to the numbering of the actual design + // variables + activeDesignVariables_ = + constraint_().computeActiveDesignVariables(activeVarsInCPs); +} + + +void Foam::volumetricBSplinesDesignVariables::designVariablesToControlPoints() +{ + const scalarField& dvs = *this; + + // Convert design variables to CPs coordinates, stored in a scalarField + scalarField cpsScalar(constraint_().designVariablesToControlPoints(dvs)); + + // Convert the scalarField to vectorFields and transfer to morphing boxes + PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); + label varID(0); + for (NURBS3DVolume& boxI : boxes) + { + vectorField cps(boxI.getControlPoints().size(), Zero); + for (vector& cpI : cps) + { + cpI.x() = cpsScalar[varID++]; + cpI.y() = cpsScalar[varID++]; + cpI.z() = cpsScalar[varID++]; + } + boxI.setControlPoints(cps); + } +} + + +void Foam::volumetricBSplinesDesignVariables::controlPointsToDesignVariables() +{ + // Store CP coordinates to a scalarField + scalarField cpsScalar(3*volBSplinesBase_.getTotalControlPointsNumber()); + const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxes(); + label varID(0); + for (const NURBS3DVolume& boxI : boxes) + { + const vectorField& cps = boxI.getControlPoints(); + for (const vector& cpI : cps) + { + cpsScalar[varID++] = cpI.x(); + cpsScalar[varID++] = cpI.y(); + cpsScalar[varID++] = cpI.z(); + } + } + + // Convert this scalarField to the design variables + scalarField::operator= + (constraint_().controlPointsToDesignVariables(cpsScalar)); +} + + +void Foam::volumetricBSplinesDesignVariables::controlPointsToDesignVariables +( + const vectorField& controlPoints +) +{ + // Store CP coordinates to a scalarField + scalarField cpsScalar(3*volBSplinesBase_.getTotalControlPointsNumber()); + const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxes(); + label varID(0); + for (const NURBS3DVolume& boxI : boxes) + { + const label nCPs(boxI.getControlPoints().size()); + for (label cpI = 0; cpI < nCPs; ++cpI) + { + cpsScalar[varID++] = controlPoints[cpI].x(); + cpsScalar[varID++] = controlPoints[cpI].y(); + cpsScalar[varID++] = controlPoints[cpI].z(); + } + } + + // Convert this scalarField to the design variables + scalarField::operator= + (constraint_().controlPointsToDesignVariables(cpsScalar)); +} + + +void Foam::volumetricBSplinesDesignVariables::readBounds +( + autoPtr<scalar> lowerBoundPtr, + autoPtr<scalar> upperBoundPtr +) +{ + designVariables::readBounds(lowerBoundPtr, upperBoundPtr); + readBounds(lowerBounds_, "lower", -1); + readBounds(upperBounds_, "upper", 1); + + // Update bounds based on the constraints - WIP + constraint_().computeBounds(lowerBounds_, upperBounds_); +} + + +void Foam::volumetricBSplinesDesignVariables::readBounds +( + autoPtr<scalarField>& bounds, + const word& boundsName, + const label sign +) +{ + // Read global bounds for the control points + if (dict_.found(boundsName + "CPBounds")) + { + bounds.reset(new scalarField(getVars().size())); + + vector CPBounds(dict_.get<vector>(boundsName + "CPBounds")); + const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); + label varID(0); + for (const NURBS3DVolume& boxI : boxes) + { + const label nCPs(boxI.getControlPoints().size()); + for (label iCP = 0; iCP < nCPs; ++iCP) + { + bounds()[varID++] = CPBounds.x(); + bounds()[varID++] = CPBounds.y(); + bounds()[varID++] = CPBounds.z(); + } + } + } + // Read in bounds from the designVariables dictionary if present. + // If nonOverlappingCPs is used, the current CPs are used to determine the + // bounds of the CPs. If we continue from a previous solution, the current + // CPs are different from the initial ones and, hence, different bounds + // will be computed for the continuation run. Instead, read the bounds + // from the designVariables dict, if present + else if (localIOdictionary::found(boundsName + "Bounds")) + { + DebugInfo + << "Reading " << boundsName << "Bounds from dict " << endl; + bounds.reset + (new scalarField(boundsName + "Bounds", *this, getVars().size())); + + } + else if (nonOverlappingCPs_) + { + DebugInfo + << "Setting " << boundsName << "Bounds from nonOverlappingCPs" + << endl; + bounds.reset(new scalarField(getVars().size())); + const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); + label varID(0); + for (const NURBS3DVolume& boxI : boxes) + { + const vectorField& cps = boxI.getControlPoints(); + const Vector<label> nCPsDir = boxI.nCPsPerDirection(); + vector dists(Zero); + for (label idir = 0; idir < 3; ++idir) + { + dists[idir] = + (max(cps.component(idir)) - min(cps.component(idir))) + /scalar(nCPsDir[idir] - 1); + } + const label nCPs(boxI.getControlPoints().size()); + for (label iCP = 0; iCP < nCPs; ++iCP) + { + const vector& cp = cps[iCP]; + bounds()[varID++] = cp.x() + sign*0.5*dists.x(); + bounds()[varID++] = cp.y() + sign*0.5*dists.y(); + bounds()[varID++] = cp.z() + sign*0.5*dists.z(); + } + } + } +} + + +void Foam::volumetricBSplinesDesignVariables::writeBounds +( + const scalarField& bounds, + const word& name +) const +{ + if (Pstream::master()) + { + const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); + label passed(0); + for (const NURBS3DVolume& boxI : boxes) + { + OFstream file + ( + word("optimisation")/word("controlPoints")/boxI.name() + + name + mesh_.time().timeName() + ".csv" + ); + // Write header + file<< "\"Points : 0\", \"Points : 1\", \"Points : 2\"," + << "\"i\", \"j\", \"k\""<< endl; + + const vectorField& cps = boxI.getControlPoints(); + const label nCPsU = boxI.basisU().nCPs(); + const label nCPsV = boxI.basisV().nCPs(); + forAll(cps, cpI) + { + const label k = cpI/label(nCPsU*nCPsV); + const label j = (cpI - k*nCPsU*nCPsV)/nCPsU; + const label i = (cpI - k*nCPsU*nCPsV - j*nCPsU); + + file<< bounds[3*cpI + passed] << ", " + << bounds[3*cpI + 1 + passed] << ", " + << bounds[3*cpI + 2 + passed] << ", " + << i << ", " + << j << ", " + << k << endl; + } + passed += 3*cps.size(); + } + } +} + + +void Foam::volumetricBSplinesDesignVariables::setDisplacement +( + const vectorField& cpMovement +) +{ + displacementMethod& dm = displMethodPtr_.ref(); + // Are volumetric B-Splines also used to move the mesh ? + if (isA<displacementMethodvolumetricBSplinesMotionSolver>(dm)) + { + // Communicate the control points movement to the displacement method + displMethodPtr_->setControlField(cpMovement); + } + else + { + // This will also update the control point positions + tmp<vectorField> tnewPoints = + volBSplinesBase_.computeBoundaryDisplacement + ( + cpMovement, + parametertisedPatches_.toc() + ); + const vectorField& newPoints = tnewPoints(); + + pointVectorField dx + ( + IOobject + ( + "dx", + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ), + pointMesh::New(mesh_), + dimensionedVector(dimless, Zero) + ); + + for (const label pI : parametertisedPatches_) + { + dx.boundaryField()[pI].setInInternalField + ( + dx.primitiveFieldRef(), + vectorField(newPoints, mesh_.boundaryMesh()[pI].meshPoints()) + ); + } + + // Set boundary movement of motion solver + displMethodPtr_->setMotionField(dx); + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::volumetricBSplinesDesignVariables::volumetricBSplinesDesignVariables +( + fvMesh& mesh, + const dictionary& dict +) +: + shapeDesignVariables(mesh, dict), + localIOdictionary + ( + IOobject + ( + "volumetricBSplinesDesignVariables", + mesh.time().timeName(), + fileName("uniform"), + mesh, + IOobject::READ_IF_PRESENT, + IOobject::AUTO_WRITE + ), + word::null + ), + volBSplinesBase_(const_cast<volBSplinesBase&>(volBSplinesBase::New(mesh))), + nonOverlappingCPs_(dict_.getOrDefault<bool>("nonOverlappingCPs", false)), + updateBounds_(dict_.getOrDefault<bool>("updateBounds", true)), + constraint_(morphingBoxConstraint::New(mesh, dict, *this)) +{ + // Read in design variables if present or initialise them + if (localIOdictionary::found("designVariables")) + { + scalarField::operator= + (scalarField("designVariables", *this, scalarField::size())); + } + else if (constraint_().initialiseVars()) + { + controlPointsToDesignVariables(); + } + + // Set the active design variables + setActiveDesignVariables(); + + // Read bounds for design variables, if present + readBounds(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // + +Foam::tmp<Foam::vectorField> +Foam::volumetricBSplinesDesignVariables::controlPointMovement +( + const scalarField& correction +) +{ + auto tcpMovement + ( + tmp<vectorField>::New + ( + volBSplinesBase_.getTotalControlPointsNumber(), + Zero + ) + ); + vectorField& cpMovement = tcpMovement.ref(); + + // Convert the correction pertaining to the design variables to a + // scalarField correction for the control points + const scalarField correctionCPs(constraint_().correctionCPs(correction)); + + // scalarField to vectorField conversion + forAll(cpMovement, iCP) + { + cpMovement[iCP].x() = correctionCPs[3*iCP]; + cpMovement[iCP].y() = correctionCPs[3*iCP + 1]; + cpMovement[iCP].z() = correctionCPs[3*iCP + 2]; + } + volBSplinesBase_.boundControlPointMovement(cpMovement); + + return tcpMovement; +} + + +void Foam::volumetricBSplinesDesignVariables::update(scalarField& correction) +{ + // Get controlPoint movement from correction + tmp<vectorField> tcpMovement = controlPointMovement(correction); + const vectorField& cpMovement = tcpMovement(); + + // Set the field driving the displacement method + setDisplacement(cpMovement); + + // Do the actual mesh movement + // Updates also the control point positions + moveMesh(); + + // Update the design variables + scalarField::operator+=(correction); +} + + +void Foam::volumetricBSplinesDesignVariables::resetDesignVariables() +{ + shapeDesignVariables::resetDesignVariables(); + designVariablesToControlPoints(); +} + + +Foam::scalar +Foam::volumetricBSplinesDesignVariables::computeEta(scalarField& correction) +{ + return constraint_().computeEta(correction, maxInitChange_()); +} + + +bool Foam::volumetricBSplinesDesignVariables::globalSum() const +{ + return false; +} + + +Foam::tmp<Foam::scalarField> +Foam::volumetricBSplinesDesignVariables::assembleSensitivities +( + adjointSensitivity& adjointSens +) +{ + return + constraint_().postProcessSens + ( + shapeDesignVariables::assembleSensitivities(adjointSens)(), + adjointSens.getAdjointSolver().solverName() + ); +} + + +void Foam::volumetricBSplinesDesignVariables::evolveNumber() +{ + constraint_().updateBounds(lowerBounds_, upperBounds_); +} + + +bool Foam::volumetricBSplinesDesignVariables::writeData(Ostream& os) const +{ + scalarField::writeEntry("designVariables", os); + if (lowerBounds_) + { + lowerBounds_().writeEntry("lowerBounds", os); + writeBounds(lowerBounds_(), "lowerBounds"); + } + if (upperBounds_) + { + upperBounds_().writeEntry("upperBounds", os); + writeBounds(upperBounds_(), "upperBounds"); + } + return constraint_().writeData(os); +} + + +Foam::tmp<Foam::vectorField> Foam::volumetricBSplinesDesignVariables::dxdbVol +( + const label varID +) const +{ + const displacementMethod& dm = displMethodPtr_(); + if (isA<displacementMethodvolumetricBSplinesMotionSolver>(dm)) + { + Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID); + const label boxI = decomposed.x(); + const label cpILocal = decomposed.y(); + const label dir = decomposed.z(); + + pointTensorField dxdb(volBSplinesBase_.boxRef(boxI).getDxDb(cpILocal)); + return unzipCol(dxdb, dir); + } + return tmp<vectorField>::New(0); +} + + +Foam::tmp<Foam::vectorField> Foam::volumetricBSplinesDesignVariables::dxdbFace +( + const label patchI, + const label varID +) const +{ + Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID); + const label boxI = decomposed.x(); + const label cpILocal = decomposed.y(); + const label dir = decomposed.z(); + + tensorField dxdb + (volBSplinesBase_.boxRef(boxI).patchDxDbFace(patchI, cpILocal)); + return unzipCol(dxdb, dir); +} + + +Foam::tmp<Foam::vectorField> Foam::volumetricBSplinesDesignVariables::dndb +( + const label patchI, + const label varID +) const +{ + Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID); + const label boxI = decomposed.x(); + const label cpILocal = decomposed.y(); + const label dir = decomposed.z(); + + tensorField dndb + ( + volBSplinesBase_.boxRef(boxI). + dndbBasedSensitivities(patchI, cpILocal, false) + ); + return unzipCol(dndb, dir); +} + + +Foam::tmp<Foam::vectorField> Foam::volumetricBSplinesDesignVariables::dSdb +( + const label patchI, + const label varID +) const +{ + Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID); + const label boxI = decomposed.x(); + const label cpILocal = decomposed.y(); + const label dir = decomposed.z(); + + tensorField dndb + ( + volBSplinesBase_.boxRef(boxI).dndbBasedSensitivities(patchI, cpILocal) + ); + return unzipCol(dndb, dir); +} + + +Foam::tmp<Foam::volVectorField> Foam::volumetricBSplinesDesignVariables::dCdb +( + const label varID +) const +{ + Vector<label> decomposed = volBSplinesBase_.decomposeDV(varID); + const label boxI = decomposed.x(); + const label cpILocal = decomposed.y(); + const label dir = decomposed.z(); + NURBS3DVolume& box = volBSplinesBase_.boxRef(boxI); + pointVolInterpolation volPointInter(pointMesh::New(mesh_), mesh_); + // WIP: we compute the entire dxdb tensor corresponding to the contol point + // and then extract the desired direction. This is quite expensive. + // Specific functions returning what we want should be implemented in + // NURBS3DVolume to reduce the cost + tmp<volTensorField> dxdb = volPointInter.interpolate(box.getDxDb(cpILocal)); + auto tdxdbDir = + tmp<volVectorField>::New + ( + IOobject + ( + "dxdbDir", + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedVector(dimless, Zero) + ); + volVectorField& dxdbDir = tdxdbDir.ref(); + unzipCol(dxdb(), vector::components(dir), dxdbDir); + return tdxdbDir; +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/volumetricBSplinesDesignVariables.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/volumetricBSplinesDesignVariables.H new file mode 100644 index 0000000000000000000000000000000000000000..8e033f21549d855f5f0fb67a12ac08eeecbda96e --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/designVariables/shape/volumetricBSplines/volumetricBSplinesDesignVariables.H @@ -0,0 +1,263 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::volumetricBSplinesDesignVariables + +Description + Volumetric B-Splines design variables for shape optimisation + +SourceFiles + volumetricBSplinesDesignVariables.C + +\*---------------------------------------------------------------------------*/ + +#ifndef volumetricBSplinesDesignVariables_H +#define volumetricBSplinesDesignVariables_H + +#include "shapeDesignVariables.H" +#include "volBSplinesBase.H" +#include "morphingBoxConstraint.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class volumetricBSplinesDesignVariables Declaration +\*---------------------------------------------------------------------------*/ + +class volumetricBSplinesDesignVariables +: + public shapeDesignVariables, + public localIOdictionary +{ +protected: + + // Protected data + + //- Reference to underlaying volumetric B-Splines morpher + volBSplinesBase& volBSplinesBase_; + + //- Should the control points be non-overlapping + bool nonOverlappingCPs_; + + //- Should the bounds of the non-overlapping control points be updated + //- in each optimisation cycle + bool updateBounds_; + + //- Constraint imposed on the movement of the design variables. + // Can be used to e.g. impose a uniform movement of the control points + // in one direction, etc. + autoPtr<morphingBoxConstraint> constraint_; + + + // Protected Member Functions + + //- Size of the active control points + virtual label sensSize() const; + + //- Components of the active control points + virtual const labelList& activeSensitivities() const; + + //- Set IDs of active design variables + // Might be different than what volBSplinesBase_ returns, if + // constraint_ changes the number of design variables + void setActiveDesignVariables(); + + //- Set control points based on current design variables values + void designVariablesToControlPoints(); + + //- Set the design variables based on the current control points + void controlPointsToDesignVariables(); + + //- Set the design variables based on the given control points + void controlPointsToDesignVariables(const vectorField& controlPoints); + + //- Read bounds for design variables, if present + void readBounds + ( + autoPtr<scalar> lowerBoundPtr = nullptr, + autoPtr<scalar> upperBoundPtr = nullptr + ); + + //- Read one set of bounds (lower, upper) + void readBounds + ( + autoPtr<scalarField>& bounds, + const word& boundsName, + const label sign + ); + + //- Write current bounds to file + void writeBounds(const scalarField& bounds, const word& name) const; + + //- Set the field driving the displacement method. + // Can be either the movement of the control points or the boundary + // displacement, depending on the method used to move the mesh + void setDisplacement(const vectorField& cpMovement); + + +private: + + // Private Member Functions + + //- Disallow default bitwise copy construct + volumetricBSplinesDesignVariables + ( + const volumetricBSplinesDesignVariables& + ) = delete; + + //- Disallow default bitwise assignment + void operator=(const volumetricBSplinesDesignVariables&) = delete; + + +public: + + //- Runtime type information + TypeName("volumetricBSplines"); + + + // Constructors + + //- Construct from components + volumetricBSplinesDesignVariables + ( + fvMesh& mesh, + const dictionary& dict + ); + + + //- Destructor + virtual ~volumetricBSplinesDesignVariables() = default; + + + // Member Functions + + //- Are control points non-overlapping + inline bool nonOverlappingCPs() const + { + return nonOverlappingCPs_; + } + + //- Are bounds to be updated after each optmisation cycle + inline bool updateBounds() const + { + return updateBounds_; + } + + //- Constant access to the volBSplinesBase object + inline const volBSplinesBase& getVolBSplinesBase() const + { + return volBSplinesBase_; + } + + //- Non-constant access to the volBSplinesBase object + inline volBSplinesBase& getVolBSplinesBase() + { + return volBSplinesBase_; + } + + //- Transform correction of design variables to control points movement + tmp<vectorField> controlPointMovement + ( + const scalarField& correction + ); + + //- Update design variables based on a given correction + virtual void update(scalarField& correction); + + //- Reset to starting point of line search + virtual void resetDesignVariables(); + + //- 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; + + //- Assemble the sensitivity derivatives, by also applying possible + //- constraints + virtual tmp<scalarField> assembleSensitivities + ( + adjointSensitivity& adjointSens + ); + + //- For design variables with a dynamic character (i.e. changing + // number), perform the evolution. + // Hijacked here to evolve the bounds of the design variables + // after the end of each optimisation cycle + virtual void evolveNumber(); + + //- Write fields to support continuation + virtual bool writeData(Ostream& os) const; + + // Fields related to sensitivity computations + + //- Get dxdb for all mesh points + virtual tmp<vectorField> dxdbVol + ( + const label varID + ) const; + + //- 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 + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.C index 20f2efc38d0314feaa9c2b9a33a41e0370b93ca3..0ec06af702861190f32909f44c688f43aa64f2a8 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.C @@ -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 @@ -34,7 +34,7 @@ License namespace Foam { - defineTypeNameAndDebug(ArmijoConditions, 0); + defineTypeNameAndDebug(ArmijoConditions, 1); addToRunTimeSelectionTable ( lineSearch, @@ -49,10 +49,11 @@ namespace Foam Foam::ArmijoConditions::ArmijoConditions ( const dictionary& dict, - const Time& time + const Time& time, + updateMethod& UpdateMethod ) : - lineSearch(dict, time), + lineSearch(dict, time, UpdateMethod), c1_(coeffsDict().getOrDefault<scalar>("c1", 1.e-4)) {} @@ -61,9 +62,15 @@ Foam::ArmijoConditions::ArmijoConditions bool Foam::ArmijoConditions::converged() { - Info<< "New merit function value " << newMeritValue_ << endl; - Info<< "Old merit function value " << oldMeritValue_ << endl; - Info<< "Extrapolated merit function value " + DebugInfo + << "New merit function value " << newMeritValue_ << endl; + DebugInfo + << "Old merit function value " << oldMeritValue_ << endl; + DebugInfo + << "c1, step, directionalDeriv " + << c1_ << " " << step_ << " " <<directionalDeriv_ + << endl; + DebugInfo<< "Extrapolated merit function value " << oldMeritValue_ + c1_*step_*directionalDeriv_ << endl; return newMeritValue_ < oldMeritValue_ + c1_*step_*directionalDeriv_; } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.H index 3e1890e045514f77e35ff94a23d20e7d51eb1f77..2c16c84e95843a03a87c7eb632d11470f8a36850 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/ArmijoConditions/ArmijoConditions.H @@ -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 @@ -80,25 +80,15 @@ public: TypeName("ArmijoConditions"); - // Declare run-time constructor selection table - - declareRunTimeSelectionTable - ( - autoPtr, - ArmijoConditions, - dictionary, - ( - const dictionary& dict, - const Time& time - ), - (dict) - ); - - // Constructors //- Construct from components - ArmijoConditions(const dictionary& dict, const Time& time); + ArmijoConditions + ( + const dictionary& dict, + const Time& time, + updateMethod& UpdatheMethod + ); // Destructor diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.C index 0701dae6eb1a8b77609cab2f2c46b3aed387d13c..8ae94392d36ad4b2b5068838307847d57d73b64e 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.C @@ -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-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -49,7 +49,12 @@ const Foam::dictionary& Foam::lineSearch::coeffsDict() // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::lineSearch::lineSearch(const dictionary& dict, const Time& time) +Foam::lineSearch::lineSearch +( + const dictionary& dict, + const Time& time, + updateMethod& UpdateMethod +) : dict_(dict), lineSearchDict_ @@ -77,6 +82,7 @@ Foam::lineSearch::lineSearch(const dictionary& dict, const Time& time) minStep_(dict.getOrDefault<scalar>("minStep", 0.3)), step_(Zero), iter_(lineSearchDict_.getOrDefault<label>("iter", 0)), + innerIter_(0), maxIters_(dict.getOrDefault<label>("maxIters", 4)), extrapolateInitialStep_ ( @@ -86,7 +92,8 @@ Foam::lineSearch::lineSearch(const dictionary& dict, const Time& time) false ) ), - stepUpdate_(stepUpdate::New(dict)) + stepUpdate_(stepUpdate::New(dict)), + updateMethod_(UpdateMethod) {} @@ -95,7 +102,8 @@ Foam::lineSearch::lineSearch(const dictionary& dict, const Time& time) Foam::autoPtr<Foam::lineSearch> Foam::lineSearch::New ( const dictionary& dict, - const Time& time + const Time& time, + updateMethod& UpdateMethod ) { autoPtr<lineSearch> lineSrch(nullptr); @@ -119,7 +127,7 @@ Foam::autoPtr<Foam::lineSearch> Foam::lineSearch::New ) << exit(FatalIOError); } - lineSrch.reset((ctorPtr(dict, time)).ptr()); + lineSrch.reset((ctorPtr(dict, time, UpdateMethod)).ptr()); } else { @@ -140,9 +148,9 @@ void Foam::lineSearch::setDeriv(const scalar deriv) } -void Foam::lineSearch::setDirection(const scalarField& direction) +void Foam::lineSearch::setNewDeriv(const scalar deriv) { - direction_ = direction; + // Does nothing in base } @@ -162,6 +170,7 @@ void Foam::lineSearch::setOldMeritValue(const scalar value) void Foam::lineSearch::reset() { + innerIter_ = 0; if (extrapolateInitialStep_ && iter_ != 0) { // step_ = 2*(oldMeritValue_-prevMeritValue_)/directionalDeriv_; @@ -181,35 +190,57 @@ void Foam::lineSearch::reset() } -Foam::label Foam::lineSearch::maxIters() const +void Foam::lineSearch::updateStep(const scalar newStep) { - return maxIters_; + step_ = newStep; } -Foam::scalar Foam::lineSearch::step() const +void Foam::lineSearch::updateCorrection(scalarField& correction) { - return step_; + correction *= step_; } -void Foam::lineSearch::updateStep(const scalar newStep) +bool Foam::lineSearch::loop() { - step_ = newStep; + const bool isRunning = innerIter_ < maxIters_; + + if (isRunning) + { + ++innerIter_; + } + + return isRunning; +} + + +bool Foam::lineSearch::computeGradient() const +{ + return false; +} + + +void Foam::lineSearch::postUpdate() +{ + this->operator++(); } Foam::lineSearch& Foam::lineSearch::operator++() { - iter_++; + ++iter_; prevMeritDeriv_ = directionalDeriv_; lineSearchDict_.add<scalar>("prevMeritDeriv", prevMeritDeriv_, true); lineSearchDict_.add<label>("iter", iter_, true); - lineSearchDict_.regIOobject::writeObject - ( - IOstreamOption(IOstreamOption::ASCII), - true - ); + if (lineSearchDict_.time().writeTime()) + { + lineSearchDict_.regIOobject::writeObject + ( + IOstreamOption(IOstreamOption::ASCII), + true + ); + } return *this; } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.H index 0904559bd83c34506c3074cfb1e8fe55c41473ba..52cf061cfd03bad258d29eafae9591a5266a4a71 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/lineSearch/lineSearch.H @@ -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 @@ -44,6 +44,7 @@ SourceFiles #include "IOdictionary.H" #include "scalarField.H" #include "stepUpdate.H" +#include "updateMethod.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -90,9 +91,12 @@ protected: //- Correction multiplier scalar step_; - //- Inner line search iteration + //- Optimisation cycle label iter_; + //- Inner line search iteration + label innerIter_; + //- Maximum line search iterations label maxIters_; @@ -104,6 +108,9 @@ protected: //- Mechanism to update method if line search conditions are not set autoPtr<stepUpdate> stepUpdate_; + //- Reference to the update method related to the line search + updateMethod& updateMethod_; + // Protected Member Functions @@ -137,16 +144,22 @@ public: dictionary, ( const dictionary& dict, - const Time& time + const Time& time, + updateMethod& UpdateMethod ), - (dict, time) + (dict, time, UpdateMethod) ); // Constructors //- Construct from components - lineSearch(const dictionary& dict, const Time& time); + lineSearch + ( + const dictionary& dict, + const Time& time, + updateMethod& UpdateMethod + ); // Selectors @@ -154,7 +167,8 @@ public: static autoPtr<lineSearch> New ( const dictionary& dict, - const Time& time + const Time& time, + updateMethod& UpdateMethod ); @@ -164,46 +178,80 @@ public: // Member Functions - //- Set objective derivative - virtual void setDeriv(const scalar deriv); + //- Set directional derivative + virtual void setDeriv(const scalar deriv); + + //- Set new directional derivative. + // Does nothing in base. Only used by methods that require the + // gradient information to be computed at the new point + virtual void setNewDeriv(const scalar deriv); + + //- Set direction + inline void setDirection(const scalarField& direction) + { + direction_ = direction; + } + + //- Set new objective value + void setNewMeritValue(const scalar value); + + //- Set old objective value + void setOldMeritValue(const scalar value); + + //- Reset step to initial value + virtual void reset(); + + //- Get inner line search iteration + inline label innerIter() const + { + return innerIter_; + } - //- Set direction - void setDirection(const scalarField& direction); + //- Get max number of iterations + inline label maxIters() const + { + return maxIters_; + } - //- Set new objective value - void setNewMeritValue(const scalar value); + //- Get current step + inline scalar step() const + { + return step_; + } - //- Set old objective value - void setOldMeritValue(const scalar value); + //- Return the correction of the design variables + virtual bool converged() = 0; - //- Reset step to initial value - virtual void reset(); + //- Update the line search step based on the specific line search + //- strategy, e.g. bisection, quadratic fit, etc. + virtual void updateStep() = 0; - //- Get max number of iterations - label maxIters() const; + //- Update the step using the supplied value + virtual void updateStep(const scalar newStep); - //- Get current step - scalar step() const; + //- Update the correction. + // Multiplies with step in base + virtual void updateCorrection(scalarField& correction); - //- Return the correction of the design variables - virtual bool converged() = 0; + //- Return true if lineSearch should continue and if so increment inner + // iteration + virtual bool loop(); - //- Update the line search step based on the specific line search - //- strategy, e.g. bisection, quadratic fit, etc. - virtual void updateStep() = 0; + //- Does line search need to update the gradient? + virtual bool computeGradient() const; - //- Update the step using the supplied value - virtual void updateStep(const scalar newStep); + //- Execute steps at the end of the line search iterations + virtual void postUpdate(); // Member operators - //- Increment iteration number and store merit value corresponding to - //- the previous optimisation cycle - virtual lineSearch& operator++(); + //- Increment iteration number and store merit value corresponding to + //- the previous optimisation cycle + virtual lineSearch& operator++(); - //- Postfix increment. Necessary for compilation - virtual lineSearch& operator++(int); + //- Postfix increment. Necessary for compilation + virtual lineSearch& operator++(int); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/quadratic/quadratic.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/quadratic/quadratic.C index 7a73727b5576e3842908ac749c56dd489efd9e56..6e4722a9262790c8fba18bc4c583048751924c0b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/quadratic/quadratic.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/lineSearch/stepUpdate/quadratic/quadratic.C @@ -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 @@ -60,10 +60,10 @@ Foam::quadratic::quadratic(const dictionary& dict) void Foam::quadratic::updateStep(scalar& step) { - Info<< "f(0)" << firstMeritValue_ << endl; - Info<< "f(a0)" << secondMeritValue_ << endl; - Info<< "df(0)" << meritDerivative_ << endl; - Info<< "a0 " << step << endl; + Info<< "First merit value, f(0) = " << firstMeritValue_ << endl; + Info<< "Second merit value, f(a0) = " << secondMeritValue_ << endl; + Info<< "Merit derivative, df(0) = " << meritDerivative_ << endl; + Info<< "Previous step, a0 = " << step << endl; scalar denom = 1./(step*step); scalar coeff1 = (secondMeritValue_ - meritDerivative_*step - firstMeritValue_) diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovement/optMeshMovement.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovement/optMeshMovement.C deleted file mode 100644 index f4e156f457b76c7019816515ed2cf63a30198cfc..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovement/optMeshMovement.C +++ /dev/null @@ -1,208 +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-2021 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 "optMeshMovement.H" -#include "cellQuality.H" -#include "createZeroField.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - defineTypeNameAndDebug(optMeshMovement, 0); - defineRunTimeSelectionTable(optMeshMovement, dictionary); -} - - -// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // - -Foam::scalar Foam::optMeshMovement::getMaxAllowedDisplacement() const -{ - if (!maxAllowedDisplacement_) - { - FatalErrorInFunction - << "maxAllowedDisplacement requested but not set" << nl - << exit(FatalError); - } - - return maxAllowedDisplacement_(); -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::optMeshMovement::optMeshMovement -( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs -) -: - maxAllowedDisplacement_(nullptr), - mesh_(mesh), - dict_(dict), - correction_(0), - patchIDs_(patchIDs), - pointsInit_(mesh.points()), - displMethodPtr_(displacementMethod::New(mesh_, patchIDs_)), - writeMeshQualityMetrics_ - ( - dict.getOrDefault("writeMeshQualityMetrics", false) - ) -{ - // Set maxAllowedDisplacement if provided - if (dict.found("maxAllowedDisplacement")) - { - maxAllowedDisplacement_.reset - ( - new scalar(dict.get<scalar>("maxAllowedDisplacement")) - ); - } -} - - -// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * // - -Foam::autoPtr<Foam::optMeshMovement> Foam::optMeshMovement::New -( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs -) -{ - const word modelType(dict.get<word>("type")); - - Info<< "optMeshMovement type : " << modelType << endl; - - auto* ctorPtr = dictionaryConstructorTable(modelType); - - if (!ctorPtr) - { - FatalIOErrorInLookup - ( - dict, - "type", - modelType, - *dictionaryConstructorTablePtr_ - ) << exit(FatalIOError); - } - - return autoPtr<optMeshMovement>(ctorPtr(mesh, dict, patchIDs)); -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // - -void Foam::optMeshMovement::setCorrection(const scalarField& correction) -{ - correction_ = correction; -} - - -void Foam::optMeshMovement::moveMesh() -{ - // Move mesh - displMethodPtr_->update(); - - // Check mesh quality - mesh_.checkMesh(true); - - // If needed, plot mesh quality metrics - writeMeshQualityMetrics(); -} - - -Foam::autoPtr<Foam::displacementMethod>& -Foam::optMeshMovement::returnDisplacementMethod() -{ - return displMethodPtr_; -} - - -const Foam::labelList& Foam::optMeshMovement::getPatchIDs() -{ - return patchIDs_; -} - - -void Foam::optMeshMovement::writeMeshQualityMetrics() -{ - if (writeMeshQualityMetrics_) - { - cellQuality cellQualityEngine(mesh_); - tmp<scalarField> cellNonOrtho(cellQualityEngine.nonOrthogonality()); - tmp<scalarField> cellSkewness(cellQualityEngine.skewness()); - Info<< "Average, Max cell non - orthogonality " - << gAverage(cellNonOrtho()) - << " " << gMax(cellNonOrtho()) << endl; - Info<< "Average, Max cell skewness " << gAverage(cellSkewness()) - << " " << gMax(cellSkewness()) << endl; - autoPtr<volScalarField> nonOrthoPtr - ( - createZeroFieldPtr<scalar>(mesh_, "nonOrtho", dimless) - ); - autoPtr<volScalarField> skewnessPtr - ( - createZeroFieldPtr<scalar>(mesh_, "skewness", dimless) - ); - nonOrthoPtr().primitiveFieldRef() = cellNonOrtho(); - skewnessPtr().primitiveFieldRef() = cellSkewness(); - nonOrthoPtr().write(); - skewnessPtr().write(); - } -} - - -void Foam::optMeshMovement::storeDesignVariables() -{ - pointsInit_ = mesh_.points(); -} - - -void Foam::optMeshMovement::resetDesignVariables() -{ - Info<< "optMeshMovement:: resetting mesh points" << endl; - mesh_.movePoints(pointsInit_); -} - - -bool Foam::optMeshMovement::maxAllowedDisplacementSet() const -{ - return bool(maxAllowedDisplacement_); -} - - -Foam::labelList Foam::optMeshMovement::getActiveDesignVariables() const -{ - NotImplemented; - return labelList(0); -} - - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovement/optMeshMovement.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovement/optMeshMovement.H deleted file mode 100644 index 5d96fc65c5555f554d861c938409f499f6260297..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovement/optMeshMovement.H +++ /dev/null @@ -1,201 +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/>. - - -Class - Foam::optMeshMovement - -Description - Abstract base class for translating an update of the design variables - into mesh movement - -SourceFiles - optMeshMovement.C - -\*---------------------------------------------------------------------------*/ - -#ifndef optMeshMovement_H -#define optMeshMovement_H - -#include "displacementMethod.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -/*---------------------------------------------------------------------------*\ - Class optMeshMovement Declaration -\*---------------------------------------------------------------------------*/ - -class optMeshMovement -{ -private: - - // Private Member Functions - - //- Max allowed boundary displacement for the first optimisation cycle - autoPtr<scalar> maxAllowedDisplacement_; - - - // Private Member Functions - - //- No copy construct - optMeshMovement(const optMeshMovement&) = delete; - - //- No copy assignment - void operator=(const optMeshMovement&) = delete; - - -protected: - - // Protected data - - fvMesh& mesh_; - const dictionary& dict_; - - //- Correction of design variables - scalarField correction_; - - //- IDs of patches to be moved - labelList patchIDs_; - - //- Fall back points in case line-search is used - vectorField pointsInit_; - - //- Mesh movement engine and interface for applying mesh movement - //- boundary conditions - autoPtr<displacementMethod> displMethodPtr_; - - //- Whether to write the mesh quality metrics to files each time the - //- mesh is updated - bool writeMeshQualityMetrics_; - - - // Protected Member Functions - - //- Get maxAllowedDisplacement, is set - scalar getMaxAllowedDisplacement() const; - - -public: - - //- Runtime type information - TypeName("optMeshMovement"); - - - // Declare run-time constructor selection table - - declareRunTimeSelectionTable - ( - autoPtr, - optMeshMovement, - dictionary, - ( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs - ), - ( - mesh, - dict, - patchIDs - ) - ); - - - // Constructors - - //- Construct from components - optMeshMovement - ( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs - ); - - - // Selectors - - static autoPtr<optMeshMovement> New - ( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs - ); - - - //- Destructor - virtual ~optMeshMovement() = default; - - - // Member Functions - - //- Set design variable correction - void setCorrection(const scalarField& correction); - - //- Calculates mesh movemnt based on the correction of the design - //- variables - virtual void moveMesh(); - - //- Return displacementMethod - autoPtr<displacementMethod>& returnDisplacementMethod(); - - //- Return patchIDs - const labelList& getPatchIDs(); - - //- Write mesh quality metrics - void writeMeshQualityMetrics(); - - //- Store design variables and mesh, to act as the starting point of - //- line search - virtual void storeDesignVariables(); - - //- Reset to starting point of line search - virtual void resetDesignVariables(); - - //- Compute eta value based on max displacement - virtual scalar computeEta(const scalarField& correction) = 0; - - //- Whether maxAllowedDisplacement has been set - bool maxAllowedDisplacementSet() const; - - //- Return active design variables. - // Implemented only for certain parametetisations - virtual labelList getActiveDesignVariables() const; -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementBezier/optMeshMovementBezier.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementBezier/optMeshMovementBezier.C deleted file mode 100644 index 11c0e384480d487e92bd4b5e3cb8307db5a7b2be..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementBezier/optMeshMovementBezier.C +++ /dev/null @@ -1,160 +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 "optMeshMovementBezier.H" -#include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - defineTypeNameAndDebug(optMeshMovementBezier, 0); - addToRunTimeSelectionTable - ( - optMeshMovement, - optMeshMovementBezier, - dictionary - ); -} - - -// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // - -void Foam::optMeshMovementBezier::computeBoundaryMovement -( - const scalarField& correction -) -{ - // Re-initialize movement to zero - dx_.primitiveFieldRef() = vector::zero; - - // Compute boundary mesh movement using derivatives of the control points - // and parameterization information - const label nBezier = Bezier_.nBezier(); - const boolList& confineXmovement = Bezier_.confineXmovement(); - const boolList& confineYmovement = Bezier_.confineYmovement(); - const boolList& confineZmovement = Bezier_.confineZmovement(); - vectorField actualMovement(nBezier, Zero); - for (label iCP = 0; iCP < nBezier; iCP++) - { - // Confine x movement - if (!confineXmovement[iCP]) - { - actualMovement[iCP].x() = correction[iCP]; - } - // Confine y movement - if (!confineYmovement[iCP]) - { - actualMovement[iCP].y() = correction[iCP + nBezier]; - } - // Confine z movement - if (!confineZmovement[iCP]) - { - actualMovement[iCP].z() = correction[iCP + 2*nBezier]; - } - dx_ += Bezier_.dxidXj()[iCP] & actualMovement[iCP]; - } - - // Add to cumulative control point change (wrong in the first optimisation - // cycle if initial eta not set) - cumulativeChange_ += actualMovement; - Info<< "Cumulative control point change " << cumulativeChange_ << endl; -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::optMeshMovementBezier::optMeshMovementBezier -( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs -) -: - optMeshMovement(mesh, dict, patchIDs), - Bezier_(mesh, mesh.lookupObject<IOdictionary>("optimisationDict")), - dx_ - ( - IOobject - ( - "dx", - mesh_.time().timeName(), - mesh_, - IOobject::NO_READ, - IOobject::NO_WRITE, - IOobject::NO_REGISTER - ), - pointMesh::New(mesh), - dimensionedVector(dimless, Zero) - ), - cumulativeChange_(Bezier_.nBezier(), Zero) -{} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::optMeshMovementBezier::moveMesh() -{ - // Update the boundary movement - computeBoundaryMovement(correction_); - - // Set boundary movement of motion solver - displMethodPtr_->setMotionField(dx_); - - // Move the mesh and check quality - optMeshMovement::moveMesh(); -} - - -Foam::scalar -Foam::optMeshMovementBezier::computeEta(const scalarField& correction) -{ - // Set unscaled correction - computeBoundaryMovement(correction); - - // Get maximum boundary movement - const scalar maxDisplacement = gMax(mag(dx_.primitiveField())); - - // Compute eta value - Info<< "maxAllowedDisplacement/maxDisplacement \t" - << getMaxAllowedDisplacement() << "/" << maxDisplacement << endl; - const scalar eta = getMaxAllowedDisplacement()/maxDisplacement; - Info<< "Setting eta value to " << eta << endl; - - return eta; -} - - -Foam::labelList Foam::optMeshMovementBezier::getActiveDesignVariables() const -{ - return Bezier_.getActiveDesignVariables(); -} - - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplines/optMeshMovementVolumetricBSplines.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplines/optMeshMovementVolumetricBSplines.C deleted file mode 100644 index 0a494c137ec0e53f748b5a25a78829d39dd62d5c..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplines/optMeshMovementVolumetricBSplines.C +++ /dev/null @@ -1,173 +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 "optMeshMovementVolumetricBSplines.H" -#include "addToRunTimeSelectionTable.H" - - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - defineTypeNameAndDebug(optMeshMovementVolumetricBSplines, 0); - addToRunTimeSelectionTable - ( - optMeshMovement, - optMeshMovementVolumetricBSplines, - dictionary - ); -} - - -// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // - -Foam::vectorField Foam::optMeshMovementVolumetricBSplines::controlPointMovement -( - const scalarField& correction -) -{ - const label nControlPoints(correction.size()/3); - vectorField cpMovement(nControlPoints, Zero); - - for (label iCP = 0; iCP < nControlPoints; ++iCP) - { - cpMovement[iCP].x() = correction[3*iCP]; - cpMovement[iCP].y() = correction[3*iCP + 1]; - cpMovement[iCP].z() = correction[3*iCP + 2]; - } - displMethodPtr_->boundControlField(cpMovement); - - return cpMovement; -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::optMeshMovementVolumetricBSplines::optMeshMovementVolumetricBSplines -( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs -) -: - optMeshMovement(mesh, dict, patchIDs), - volBSplinesBase_ - ( - const_cast<volBSplinesBase&>(volBSplinesBase::New(mesh)) - ), - cpsInit_(volBSplinesBase_.getNumberOfBoxes()) -{ - PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); - - forAll(boxes, boxI) - { - cpsInit_[boxI].setSize - ( - boxes[boxI].getControlPoints().size() - ); - cpsInit_[boxI] = boxes[boxI].getControlPoints(); - } -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::optMeshMovementVolumetricBSplines::moveMesh() -{ - // Get controlPoint movement from correction - vectorField cpMovement = controlPointMovement(correction_); - - // Set movement of the B-Splines control points - displMethodPtr_->setControlField(cpMovement); - - // Move the mesh and check quality - optMeshMovement::moveMesh(); -} - - -void Foam::optMeshMovementVolumetricBSplines::storeDesignVariables() -{ - optMeshMovement::storeDesignVariables(); - const PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxes(); - forAll(boxes, boxI) - { - cpsInit_[boxI] = boxes[boxI].getControlPoints(); - } -} - - -void Foam::optMeshMovementVolumetricBSplines::resetDesignVariables() -{ - // Reset mesh points - optMeshMovement::resetDesignVariables(); - - DebugInfo - << "optMeshMovementVolumetricBSplines:: resetting control points" - << endl; - - PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); - forAll(boxes, boxI) - { - boxes[boxI].setControlPoints(cpsInit_[boxI]); - } -} - - -Foam::scalar Foam::optMeshMovementVolumetricBSplines::computeEta -( - const scalarField& correction -) -{ - const vectorField cpMovement(controlPointMovement(correction)); - const scalar maxDisplacement - ( - volBSplinesBase_.computeMaxBoundaryDisplacement - ( - cpMovement, - patchIDs_ - ) - ); - - Info<< "maxAllowedDisplacement/maxDisplacement of boundary\t" - << getMaxAllowedDisplacement() << "/" << maxDisplacement << endl; - scalar eta = getMaxAllowedDisplacement() / maxDisplacement; - Info<< "Setting eta value to " << eta << endl; - - return eta; -} - - -Foam::labelList -Foam::optMeshMovementVolumetricBSplines::getActiveDesignVariables() const -{ - return volBSplinesBase_.getActiveDesignVariables(); -} - - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplinesExternalMotionSolver/optMeshMovementVolumetricBSplinesExternalMotionSolver.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplinesExternalMotionSolver/optMeshMovementVolumetricBSplinesExternalMotionSolver.C deleted file mode 100644 index cdde7b1a575f6635c3fb10f750af476b9169ac22..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplinesExternalMotionSolver/optMeshMovementVolumetricBSplinesExternalMotionSolver.C +++ /dev/null @@ -1,190 +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 "optMeshMovementVolumetricBSplinesExternalMotionSolver.H" -#include "addToRunTimeSelectionTable.H" - - -// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // - -namespace Foam -{ - defineTypeNameAndDebug - ( - optMeshMovementVolumetricBSplinesExternalMotionSolver, - 0 - ); - addToRunTimeSelectionTable - ( - optMeshMovement, - optMeshMovementVolumetricBSplinesExternalMotionSolver, - dictionary - ); -} - - -// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // - -void Foam::optMeshMovementVolumetricBSplinesExternalMotionSolver:: -computeBoundaryMovement -( - const scalarField& correction -) -{ - const label nCPs(volBSplinesBase_.getTotalControlPointsNumber()); - dx_.primitiveFieldRef() = vector::zero; - cpMovement_ = vector::zero; - - for (label iCP = 0; iCP < nCPs; iCP++) - { - cpMovement_[iCP].x() = correction[3*iCP]; - cpMovement_[iCP].y() = correction[3*iCP + 1]; - cpMovement_[iCP].z() = correction[3*iCP + 2]; - } - - // Bound control point movement for non-active CPs - volBSplinesBase_.boundControlPointMovement(cpMovement_); - - // Compute boundary movement - label passedCPs(0); - PtrList<NURBS3DVolume>& boxes = volBSplinesBase_.boxesRef(); - forAll(boxes, iNURB) - { - const label nb = boxes[iNURB].getControlPoints().size(); - for (label cpI = 0; cpI < nb; ++cpI) - { - const label globalCP = passedCPs + cpI; - forAll(patchIDs_, pI) - { - const label patchI = patchIDs_[pI]; - vectorField boundaryMovement - ( - boxes[iNURB].patchDxDb(patchI, cpI) - & cpMovement_[globalCP] - ); - dx_.boundaryField()[patchI].addToInternalField - ( - dx_.primitiveFieldRef(), - boundaryMovement - ); - } - } - - // Increment number of passed sensitivities - passedCPs += nb; - } -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::optMeshMovementVolumetricBSplinesExternalMotionSolver:: -optMeshMovementVolumetricBSplinesExternalMotionSolver -( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs -) -: - optMeshMovement(mesh, dict, patchIDs), - volBSplinesBase_ - ( - const_cast<volBSplinesBase&>(volBSplinesBase::New(mesh)) - ), - dx_ - ( - IOobject - ( - "dx", - mesh.time().timeName(), - mesh, - IOobject::NO_READ, - IOobject::NO_WRITE, - IOobject::NO_REGISTER - ), - pointMesh::New(mesh), - dimensionedVector(dimless, Zero) - ), - cpMovement_(volBSplinesBase_.getTotalControlPointsNumber(), Zero) -{} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::optMeshMovementVolumetricBSplinesExternalMotionSolver::moveMesh() -{ - // Compute boundary movement - computeBoundaryMovement(correction_); - - // Set boundary movement of motion solver - displMethodPtr_->setMotionField(dx_); - - // Positions of control points have not changed since only the boundary dx - // has been computed. - // Use correction to update them - volBSplinesBase_.moveControlPoints(cpMovement_); - - // Write control points to files - volBSplinesBase_.writeControlPoints(); - - // Move the mesh and check quality - optMeshMovement::moveMesh(); -} - - -Foam::scalar -Foam::optMeshMovementVolumetricBSplinesExternalMotionSolver::computeEta -( - const scalarField& correction -) -{ - computeBoundaryMovement(correction); - - // Get maximum boundary movement - scalar maxDisplacement = gMax(mag(dx_.primitiveField())); - - // Compute eta value - Info<< "maxAllowedDisplacement/maxDisplacement \t" - << getMaxAllowedDisplacement() << "/" << maxDisplacement << endl; - scalar eta = getMaxAllowedDisplacement() / maxDisplacement; - Info<< "Setting eta value to " << eta << endl; - - return eta; -} - - -Foam::labelList -Foam::optMeshMovementVolumetricBSplinesExternalMotionSolver::getActiveDesignVariables() -const -{ - return volBSplinesBase_.getActiveDesignVariables(); -} - - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplinesExternalMotionSolver/optMeshMovementVolumetricBSplinesExternalMotionSolver.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplinesExternalMotionSolver/optMeshMovementVolumetricBSplinesExternalMotionSolver.H deleted file mode 100644 index 57d8e976be6a5428296357475ab3179cde7c5030..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optMeshMovement/optMeshMovementVolumetricBSplinesExternalMotionSolver/optMeshMovementVolumetricBSplinesExternalMotionSolver.H +++ /dev/null @@ -1,138 +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/>. - -Class - Foam::optMeshMovementVolumetricBSplinesExternalMotionSolver - -Description - Converts NURBS volume control points update to actual mesh movement. - Internal points are moved based on a motionSolver other than - volumetricBSplinesExternalMotionSolver. - -SourceFiles - optMeshMovementVolumetricBSplinesExternalMotionSolver.C - -\*---------------------------------------------------------------------------*/ - -#ifndef optMeshMovementVolumetricBSplinesExternalMotionSolver_H -#define optMeshMovementVolumetricBSplinesExternalMotionSolver_H - -#include "optMeshMovement.H" -#include "volBSplinesBase.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -/*---------------------------------------------------------------------------*\ - Class optMeshMovementVolumetricBSplinesExternalMotionSolver Declaration -\*---------------------------------------------------------------------------*/ - -class optMeshMovementVolumetricBSplinesExternalMotionSolver -: - public optMeshMovement -{ -protected: - - // Protected data - - //- Reference to underlaying volumetric B-Splines morpher - volBSplinesBase& volBSplinesBase_; - - //- Boundary movement due to change of NURBS control points - pointVectorField dx_; - - //- Movement of control points - vectorField cpMovement_; - - - // Protected Member Functions - - void computeBoundaryMovement(const scalarField& correction); - - -private: - - // Private Member Functions - - //- No copy construct - optMeshMovementVolumetricBSplinesExternalMotionSolver - ( - const optMeshMovementVolumetricBSplinesExternalMotionSolver& - ) = delete; - - //- No copy assignment - void operator= - ( - const optMeshMovementVolumetricBSplinesExternalMotionSolver& - ) = delete; - - -public: - - //- Runtime type information - TypeName("volumetricBSplinesExternalMotionSolver"); - - - // Constructors - - //- Construct from components - optMeshMovementVolumetricBSplinesExternalMotionSolver - ( - fvMesh& mesh, - const dictionary& dict, - const labelList& patchIDs - ); - - - //- Destructor - virtual ~optMeshMovementVolumetricBSplinesExternalMotionSolver() = default; - - - // Member Functions - - //- Calculates surface mesh movement - void moveMesh(); - - //- Compute eta value based on max displacement - virtual scalar computeEta(const scalarField& correction); - - //- Return active design variables - virtual labelList getActiveDesignVariables() const; -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/designVariablesUpdate/designVariablesUpdate.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/designVariablesUpdate/designVariablesUpdate.C new file mode 100644 index 0000000000000000000000000000000000000000..eecea7e7226dac17f56984521ff028ff3a0a62bf --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/designVariablesUpdate/designVariablesUpdate.C @@ -0,0 +1,573 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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-2021 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 "adjointSolverManager.H" +#include "designVariablesUpdate.H" +#include "constrainedOptimisationMethod.H" +#include "IOmanip.H" +#include "runTimeSelectionTables.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(designVariablesUpdate, 0); +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +Foam::label Foam::designVariablesUpdate::nConstraints +( + PtrList<adjointSolverManager>& adjointSolverManagers +) const +{ + // Figure out number of adjoint solvers corresponding to constraints. + // Looks in all operating points + label nConstraints(0); + for (const adjointSolverManager& adjManagerI : adjointSolvManagers_) + { + nConstraints += adjManagerI.nConstraints(); + } + // Add constraints that might emerge from the design variables + tmp<scalarField> designVarsConstraints = designVars_().constraintValues(); + if (designVarsConstraints) + { + nConstraints += designVarsConstraints().size(); + } + return nConstraints; +} + + +Foam::label Foam::designVariablesUpdate::nAdjointSolvers() const +{ + label n(0); + for (const adjointSolverManager& adjSolvManager : adjointSolvManagers_) + { + n += adjSolvManager.nAdjointSolvers(); + } + return n; +} + + +void Foam::designVariablesUpdate::writeCPUcostHeader() +{ + unsigned int width(IOstream::defaultPrecision() + 5); + CPUcostFile_ + << setw(width) << "#Cycle" << " " + << setw(width) << "LineSearchIters" << " " + << setw(width) << "CycleCPUcost" << " " + << setw(width) << "CyclePrimalSolutions" << " " + << setw(width) << "CycleAdjointSolutions" << " " + << setw(width) << "TotalCPUcost" << " " + << setw(width) << "TotalPrimalSolutions" << " " + << setw(width) << "TotalAdjointSolutions" << endl; +} + + +void Foam::designVariablesUpdate::writeToCostFile(bool zeroAdjointSolns) +{ + unsigned int width(IOstream::defaultPrecision() + 5); + label cyclePrimalSolutions(nPrimalsPerCycle_); + label cycleAdjointSolutions(nAdjointsPerCycle_); + label lineSearchIters(1); + if (lineSearch_) + { + lineSearchIters = lineSearch_().innerIter(); + cyclePrimalSolutions *= lineSearchIters; + if (lineSearch_().computeGradient()) + { + cycleAdjointSolutions *= lineSearchIters; + } + } + if (zeroAdjointSolns) + { + cycleAdjointSolutions = 0; + } + nPrimalSolutions_ += cyclePrimalSolutions; + nAdjointSolutions_ += cycleAdjointSolutions; + const scalar elapsedCpuTime = mesh_.time().elapsedCpuTime(); + const scalar cycleCost = elapsedCpuTime - CPUcost_; + CPUcost_ = elapsedCpuTime; + + CPUcostFile_ + << setw(width) << mesh_.time().timeName() << " " + << setw(width) << lineSearchIters << " " + << setw(width) << cycleCost << " " + << setw(width) << cyclePrimalSolutions << " " + << setw(width) << cycleAdjointSolutions << " " + << setw(width) << CPUcost_ << " " + << setw(width) << nPrimalSolutions_ << " " + << setw(width) << nAdjointSolutions_ << endl; + +} + + +void Foam::designVariablesUpdate::checkConvergence +( + const scalarField& oldCorrection +) +{ + bool converged(false); + // Design variables convergence check + if (designVarsThreshold_) + { + const labelList& activeVarIDs = + designVars_->activeDesignVariables(); + const scalarField correction(oldCorrection, activeVarIDs); + const scalarField activeVars(designVars_->getVars(), activeVarIDs); + const scalar scaledCorrection = + gMax(mag(correction)/(mag(activeVars) + SMALL)); + DebugInfo + << "Current correction " << correction << nl + << "Active vars " << activeVars << endl; + Info<< "Max. scaled correction of the design variables = " + << scaledCorrection + << endl; + if (scaledCorrection < designVarsThreshold_()) + { + Info<< tab << "Design variables have converged " << endl; + converged = true; + } + } + // Objective convergence check + if (objectiveThreshold_) + { + const scalar newObjective = computeObjectiveValue(); + const scalar oldObjective = updateMethod_->getObjectiveValueOld(); + const scalar relativeUpdate = + mag(newObjective - oldObjective)/(mag(oldObjective) + SMALL); + Info<< "Relative change of the objective value = " + << relativeUpdate + << endl; + if (relativeUpdate < objectiveThreshold_()) + { + Info<< tab << "Objective function has converged " << endl; + converged = true; + } + } + // Feasibility check + const scalarField& constraints = updateMethod_->getConstraintValues(); + const scalar feasibility = sum(pos(constraints)*constraints); + Info<< "Feasibility = " << feasibility << endl; + if (converged && feasibility < feasibilityThreshold_) + { + Info<< "Stopping criteria met and all constraints satisfied." << nl + << "Optimisation has converged, stopping ..." << nl << nl + << "End" << nl + << endl; + // Force writing of all objective and constraint functions, to get + // the converged results to files + for (adjointSolverManager& am : adjointSolvManagers_) + { + for (adjointSolver& as : am.adjointSolvers()) + { + // Use dummy weighted objective + as.getObjectiveManager().writeObjectives(); + } + } + writeToCostFile(true); + if (UPstream::parRun()) + { + UPstream::exit(0); + } + else + { + std::exit(0); + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::designVariablesUpdate::designVariablesUpdate +( + fvMesh& mesh, + const dictionary& dict, + PtrList<adjointSolverManager>& adjointSolverManagers, + autoPtr<designVariables>& designVars +) +: + mesh_(mesh), + dict_(dict), + adjointSolvManagers_(adjointSolverManagers), + designVars_(designVars), + updateMethod_ + ( + updateMethod::New + ( + mesh_, + dict_.subDict("updateMethod"), + designVars_, + nConstraints(adjointSolverManagers) + ) + ), + lineSearch_ + ( + lineSearch::New + ( + dict_.subDict("updateMethod").subOrEmptyDict("lineSearch"), + mesh.time(), + updateMethod_.ref() + ) + ), + CPUcostFile_(mesh_.time().globalPath()/"optimisation"/"CPUcost"), + nPrimalsPerCycle_(adjointSolverManagers.size()), + nAdjointsPerCycle_(nAdjointSolvers()), + nPrimalSolutions_(nPrimalsPerCycle_), + nAdjointSolutions_(nAdjointsPerCycle_), + CPUcost_(0), + designVarsThreshold_(nullptr), + objectiveThreshold_(nullptr), + convergenceCriteriaDefined_(false), + feasibilityThreshold_ + ( + dict.subOrEmptyDict("convergence"). + getOrDefault<scalar>("feasibilityThreshold", 1.e-06) + ) +{ + dictionary convergenceDict = dict.subOrEmptyDict("convergence"); + if (convergenceDict.found("designVariables")) + { + designVarsThreshold_.reset + (new scalar(convergenceDict.get<scalar>("designVariables"))); + } + if (convergenceDict.found("objective")) + { + objectiveThreshold_.reset + (new scalar(convergenceDict.get<scalar>("objective"))); + } + convergenceCriteriaDefined_ = designVarsThreshold_ || objectiveThreshold_; + // Check whether eta of maxInitChange are set + if (!designVars_().isMaxInitChangeSet() && !updateMethod_().initialEtaSet()) + { + FatalErrorInFunction + << "Neither eta (updateMethod) or maxInitChange (designVariables) " + << "is set." + << exit(FatalError); + } + + label nConstr(nConstraints(adjointSolvManagers_)); + // Sanity checks for combinations of number of constraints and + // optimisation methods + if + ( + nConstr + && !isA<constrainedOptimisationMethod>(updateMethod_()) + ) + { + const auto& cnstrTable = + *(constrainedOptimisationMethod::dictionaryConstructorTablePtr_); + + // Has constraints but is not a constraint optimisation method + FatalErrorInFunction + << "Found " << nConstr << " adjoint solvers corresponding to " + << "constraints but the optimisation method (" + << updateMethod_().type() + << ") is not a constrainedOptimisationMethod." << nl + << "Available constrainedOptimisationMethods:" << nl + << cnstrTable.sortedToc() + << exit(FatalError); + } + else if + ( + !nConstr + && isA<constrainedOptimisationMethod>(updateMethod_()) + ) + { + // Does not have constraints but is a constrained optimisation method + WarningInFunction + << "Did not find any adjoint solvers corresponding to " + << "constraints but the optimisation method (" + << updateMethod_().type() + << ") is a constrainedOptimisationMethod." << nl << nl + << "This can cause some constraintOptimisationMethods to misbehave." + << nl << nl + << "Either the isConstraint bool is not set in one of the adjoint " + << "solvers or you should consider using an updateMethod " + << "that is not a constrainedOptimisationMethod" + << nl << endl; + } + + if (designVarsThreshold_) + { + Info<< "Optimisation will run until the max. scaled correction " + << "of the design variables is < " << designVarsThreshold_() + << endl; + } + if (objectiveThreshold_) + { + Info<< "Optimisation will run until the relative update of the " + << "objective function is < " << objectiveThreshold_() + << endl; + } + if (!convergenceCriteriaDefined_) + { + Info<< "No convergence criterion defined for optimsation" << nl + << "It will run for " << mesh_.time().endTime().value() + << " optimisation cycles " << nl << endl; + } + Info<< "Feasibility threshold is " << feasibilityThreshold_ << endl; + + // Write header of the cost file + writeCPUcostHeader(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // + +void Foam::designVariablesUpdate::update() +{ + // Compute update of the design variables + tmp<scalarField> tcorrection(computeDirection()); + scalarField& correction = tcorrection.ref(); + + // Set the old value of the objective function + setOldObjectiveValue(); + + // Update the design variables + designVars_->update(correction); + + // If direction has been scaled (say by setting the initial eta), the + // old correction has to be updated + postUpdate(correction); +} + + +void Foam::designVariablesUpdate::update(const scalarField& direction) +{ + // Multiply with line search step, if necessary + scalarField correction(direction); + if (lineSearch_.valid()) + { + lineSearch_->updateCorrection(correction); + } + + // Update the design variables + designVars_->update(correction); +} + + +Foam::tmp<Foam::scalarField> Foam::designVariablesUpdate::computeDirection() +{ + updateGradientsAndValues(); + updateMethod_->computeCorrection(); + scalarField& correction = updateMethod_->returnCorrection(); + + // Compute eta if needed + if (!updateMethod_->initialEtaSet() || designVars_->resetEta()) + { + const scalar eta(designVars_->computeEta(correction)); + updateMethod_->modifyStep(eta); + updateMethod_->initialEtaSet() = true; + } + + // Intentionally copies result to new field + return tmp<scalarField>::New(correction); +} + + +void Foam::designVariablesUpdate::updateGradientsAndValues() +{ + scalarField objectiveSens; + PtrList<scalarField> constraintSens; + scalar objectiveValue(Zero); + DynamicList<scalar> constraintValues; + + for (adjointSolverManager& adjSolvManager : adjointSolvManagers_) + { + const scalar opWeight = adjSolvManager.operatingPointWeight(); + + // Aggregate sensitivities of solvers corresponding to objectives + // (i.e. not constraints) + tmp<scalarField> tadjointSolverManagerSens = + adjSolvManager.aggregateSensitivities(); + + // Aggregate objective values of solvers corresponding to objectives + // (i.e. not constraints) + objectiveValue += opWeight*adjSolvManager.objectiveValue(); + + // Get constraint sensitivities + PtrList<scalarField> adjointSolverManagerConstSens = + adjSolvManager.constraintSensitivities(); + + // Post process sensitivities if needed. + // Done here since each adjointSolverManager might post-process + // its sensitivities in a different way + designVars_->postProcessSens + ( + tadjointSolverManagerSens.ref(), + adjointSolverManagerConstSens, + adjSolvManager.adjointSolversNames(), + adjSolvManager.isMaster() + ); + + if (objectiveSens.empty()) + { + objectiveSens.setSize(tadjointSolverManagerSens().size(), Zero); + } + + // Accumulate sensitivities + objectiveSens += opWeight*tadjointSolverManagerSens(); + forAll(adjointSolverManagerConstSens, sI) + { + constraintSens. + push_back(adjointSolverManagerConstSens.set(sI, nullptr)); + } + constraintValues.push_back(adjSolvManager.constraintValues()); + } + // Add contraint values and gradients from the design variables + tmp<scalarField> designVarsConstValues = designVars_->constraintValues(); + PtrList<scalarField> designVarsConstDerivs = + designVars_->constraintDerivatives(); + if (designVarsConstValues && designVarsConstDerivs.size()) + { + if (designVarsConstValues().size() != designVarsConstDerivs.size()) + { + FatalErrorInFunction + << "Size of design variables constraints and derivatives differ" + << endl + << exit(FatalError); + } + constraintValues.push_back(designVarsConstValues()); + constraintSens.push_back(std::move(designVarsConstDerivs)); + } + + // Update objective/constraint values/gradients, known by the update method + updateMethod_->setObjectiveDeriv(objectiveSens); + updateMethod_->setConstraintDeriv(constraintSens); + updateMethod_->setObjectiveValue(objectiveValue); + updateMethod_->setConstraintValues + (scalarField(std::move(constraintValues))); +} + + +Foam::scalar Foam::designVariablesUpdate::computeObjectiveValue() +{ + scalar objectiveValue(Zero); + for (adjointSolverManager& adjSolvManager : adjointSolvManagers_) + { + const scalar opWeight = adjSolvManager.operatingPointWeight(); + objectiveValue += opWeight*adjSolvManager.objectiveValue(); + } + return objectiveValue; +} + + +void Foam::designVariablesUpdate::setOldObjectiveValue() +{ + updateMethod_->setObjectiveValueOld(computeObjectiveValue()); +} + + +Foam::scalar Foam::designVariablesUpdate::computeMeritFunction() +{ + // Compute new objective and constraint values and update the ones + // in updateMethod + scalar objectiveValue(Zero); + DynamicList<scalar> constraintValues; + + for (adjointSolverManager& adjSolvManager : adjointSolvManagers_) + { + const scalar opWeight = adjSolvManager.operatingPointWeight(); + + objectiveValue += opWeight*adjSolvManager.objectiveValue(); + constraintValues.push_back(adjSolvManager.constraintValues()); + } + + // Add constraints directly imposed to the design variables + tmp<scalarField> designVarsConstValues = designVars_->constraintValues(); + if (designVarsConstValues) + { + constraintValues.push_back(designVarsConstValues()); + } + updateMethod_->setObjectiveValue(objectiveValue); + updateMethod_->setConstraintValues + (scalarField(std::move(constraintValues))); + + return updateMethod_->computeMeritFunction(); +} + + +Foam::scalar Foam::designVariablesUpdate::meritFunctionDirectionalDerivative() +{ + return updateMethod_->meritFunctionDirectionalDerivative(); +} + + +void Foam::designVariablesUpdate::updateOldCorrection +( + const scalarField& oldCorrection +) +{ + updateMethod_->updateOldCorrection(oldCorrection); +} + + +void Foam::designVariablesUpdate::write() +{ + updateMethod_->writeAuxiliaryData(); + designVars_->writeDesignVars(); + writeToCostFile(); +} + + +void Foam::designVariablesUpdate::postUpdate(const scalarField& oldCorrection) +{ + updateOldCorrection(oldCorrection); + write(); + designVars_->evolveNumber(); + if (lineSearch_.valid()) + { + lineSearch_().postUpdate(); + // Append additional empty line at the end of the instantaneous + // objective file to indicate the end of the block corresponding to + // this optimisation cycle + for (adjointSolverManager& am : adjointSolvManagers_) + { + for (adjointSolver& as : am.adjointSolvers()) + { + PtrList<objective>& objectives = + as.getObjectiveManager().getObjectiveFunctions(); + for (objective& obj : objectives) + { + obj.writeInstantaneousSeparator(); + } + } + } + } + if (convergenceCriteriaDefined_) + { + checkConvergence(oldCorrection); + } +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/designVariablesUpdate/designVariablesUpdate.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/designVariablesUpdate/designVariablesUpdate.H new file mode 100644 index 0000000000000000000000000000000000000000..2ed9edddf2b0f9268c6bef087663840fc15595b9 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/designVariablesUpdate/designVariablesUpdate.H @@ -0,0 +1,241 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::designVariablesUpdate + +Description + A class encapsulating functionality neccessary to perform an optimisation + loop, such as updating the design variables, checking the + sufficient reduction/adhetion of objective and constraint values in each + optimisation cycle by performing a line-search and checking the overall + convergence of the optimisation loop, if the corresponding criteria are + provided. + + Kept separate from optimisationManager to isolate functionality required + only when the update of the design variables is performed. + +SourceFiles + designVariablesUpdate.C + +\*---------------------------------------------------------------------------*/ + +#ifndef designVariablesUpdate_H +#define designVariablesUpdate_H + +#include "adjointSolverManager.H" +#include "designVariables.H" +#include "updateMethod.H" +#include "lineSearch.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class designVariablesUpdate Declaration +\*---------------------------------------------------------------------------*/ + +class designVariablesUpdate +{ +protected: + + // Protected data + + fvMesh& mesh_; + const dictionary dict_; + PtrList<adjointSolverManager>& adjointSolvManagers_; + autoPtr<designVariables>& designVars_; + + //- Method to update the design variables based on the provided + //- sensitivity derivatives + autoPtr<updateMethod> updateMethod_; + + //- Line search mechanism to approximate the update step length + autoPtr<lineSearch> lineSearch_; + + // Variables related to the computation of the CPU cost + + //- Output file + OFstream CPUcostFile_; + + //- Primal solutions per optimisation cycle + label nPrimalsPerCycle_; + + //- Adjoint solutions per optimisation cycle + label nAdjointsPerCycle_; + + //- Primal evaluations performed so far + label nPrimalSolutions_; + + //- Adjoint evaluations performed so far + label nAdjointSolutions_; + + //- CPU cost (in seconds) + scalar CPUcost_; + + // Convergence criteria + + //- The maximum of the correction/designVariables values + //- must be lower that this threshold to consider the run converged + autoPtr<scalar> designVarsThreshold_; + + //- The relative update of the objective value w.r.t. to its last + //- value should be smaller than this value to considered the run + //- converged + autoPtr<scalar> objectiveThreshold_; + + //- Is at least a single convergence criterion defined + bool convergenceCriteriaDefined_; + + //- In case of a constrained optimisation, the sum of positive + //- constraints should be lower than this value to consider the + //- run converged (i.e. this tolerates some deviation from + //- satisfying all constraints) + scalar feasibilityThreshold_; + + + // Protected Member Functions + + //- Get the number of adjoint solvers that correspond to constraints + label nConstraints + ( + PtrList<adjointSolverManager>& adjointSolverManagers + ) const; + + //- Get total number of adjoint solvers + label nAdjointSolvers() const; + + //- Write CPU cost header + void writeCPUcostHeader(); + + //- Write to cost file + void writeToCostFile(bool zeroAdjointSolns = false); + + //- Check if the optimisation loop has converged based on the provided + //- criteria + // May terminate the program + void checkConvergence(const scalarField& oldCorrection); + + +private: + + // Private Member Functions + + //- No copy construct + designVariablesUpdate(const designVariablesUpdate&) = delete; + + //- No copy assignment + void operator=(const designVariablesUpdate&) = delete; + + +public: + + //- Runtime type information + TypeName("designVariablesUpdate"); + + + // Constructors + + //- Construct from components + designVariablesUpdate + ( + fvMesh& mesh, + const dictionary& dict, + PtrList<adjointSolverManager>& adjointSolverManagers, + autoPtr<designVariables>& designVars + ); + + //- Destructor + virtual ~designVariablesUpdate() = default; + + + // Member Functions + + //- Update design variables + void update(); + + //- Update design variables based on a given correction + void update(const scalarField& correction); + + //- Compute update direction + tmp<scalarField> computeDirection(); + + //- Compute cumulative objective and constraint gradients + void updateGradientsAndValues(); + + //- Sum objective values from all adjointSolverManagers + scalar computeObjectiveValue(); + + //- Set the old objective value known by the updateMethod + // Used to check convergence of the optimisation loop + void setOldObjectiveValue(); + + //- Compute the merit function of the optimisation problem. + // Could be different than the objective function in case of + // constraint optimisation + scalar computeMeritFunction(); + + //- Derivative of the merit function + scalar meritFunctionDirectionalDerivative(); + + //- Update old correction. Needed for quasi-Newton Methods + void updateOldCorrection(const scalarField&); + + //- Write useful quantities to files + void write(); + + //- Steps to be executed after the susccessfull update of the design + //- varibles, i.e. the last step of line search or the simple update + //- in the fixedStep approach + void postUpdate(const scalarField& oldCorrection); + + //- Get access to design variables + inline autoPtr<designVariables>& getDesignVariables() + { + return designVars_; + } + + //- Get a reference to the line search object + inline autoPtr<lineSearch>& getLineSearch() + { + return lineSearch_; + } +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.C index caae3b7b09945b08aef3a07018c06d595a6269f8..6073e1e7d740ff9b11c1f51439dca3625f6446c7 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.C @@ -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 @@ -27,6 +27,8 @@ License \*---------------------------------------------------------------------------*/ +#include "adjointSolverManager.H" +#include "dictionary.H" #include "optimisationManager.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -38,28 +40,164 @@ namespace Foam } -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -Foam::optimisationManager::optimisationManager(fvMesh& mesh) -: - IOdictionary - ( - IOobject - ( - "optimisationDict", - mesh.time().system(), - mesh, - IOobject::MUST_READ_IF_MODIFIED, - IOobject::NO_WRITE, - IOobject::REGISTER - ) - ), - mesh_(mesh), - time_(const_cast<Time&>(mesh.time())), - primalSolvers_(), - adjointSolverManagers_(), - managerType_(get<word>("optimisationManager")), - optType_(nullptr) +void Foam::optimisationManager::resetTime +( + const dimensionedScalar startTime, + const label startTimeIndex, + const scalar endTime +) +{ + // Does nothing in base +} + + +void Foam::optimisationManager::lineSearchUpdate() +{ + // Compute direction of update + tmp<scalarField> tdirection = dvUpdate_->computeDirection(); + const scalarField& direction = tdirection.ref(); + + // Grab reference to line search + autoPtr<lineSearch>& lineSrch = dvUpdate_->getLineSearch(); + + // Store starting point + dvUpdate_->getDesignVariables()->storeDesignVariables(); + + // Compute merit function before update + scalar meritFunction = dvUpdate_->computeMeritFunction(); + lineSrch->setOldMeritValue(meritFunction); + dvUpdate_->setOldObjectiveValue(); + + // Get merit function derivative + scalar dirDerivative = + dvUpdate_->meritFunctionDirectionalDerivative(); + lineSrch->setDeriv(dirDerivative); + lineSrch->setDirection(direction); + + // Reset initial step. + // Might be interpolated from previous optimisation cycles + lineSrch->reset(); + + // Perform line search + while (lineSrch->loop()) + { + Info<< "\n- - - - - - - - - - - - - - -" << endl; + Info<< "Line search iteration " << lineSrch->innerIter() << endl; + Info<< "- - - - - - - - - - - - - - -\n" << endl; + + // Update design variables. Multiplication with line search step + // happens inside the update(direction) function + moveDesignVariables(direction); + + const dimensionedScalar startTime = mesh_.time(); + const label startTimeIndex = mesh_.time().timeIndex(); + const scalar primalEndTime = mesh_.time().endTime().value(); + // Solve all primal equations + solvePrimalEquations(); + + // Compute and set new merit function + meritFunction = dvUpdate_->computeMeritFunction(); + lineSrch->setNewMeritValue(meritFunction); + + if (lineSrch->computeGradient()) + { + // Reset adjoint sensitivities in all adjoint solver managers + clearSensitivities(); + + // Solve all adjoint equations + solveAdjointEquations(); + + // Update objective and gradient information known by updateMethod + dvUpdate_->updateGradientsAndValues(); + + // Update the directional derivative + dirDerivative = + dvUpdate_->meritFunctionDirectionalDerivative(); + lineSrch->setNewDeriv(dirDerivative); + } + + if (lineSrch->converged()) + { + // If line search criteria have been met, proceed + Info<< "Line search converged in " << lineSrch->innerIter() + << " iterations." << endl; + scalarField scaledCorrection(lineSrch->step()*direction); + dvUpdate_->postUpdate(scaledCorrection); + break; + } + else + { + // If maximum number of iteration has been reached, continue + if (lineSrch->innerIter() == lineSrch->maxIters()) + { + Info<< "Line search reached max. number of iterations.\n" + << "Proceeding to the next optimisation cycle" << endl; + scalarField scaledCorrection(lineSrch->step()*direction); + dvUpdate_->postUpdate(scaledCorrection); + } + // Reset to initial design variables and update step + else + { + //- Reset time if necessary + this->resetTime(startTime, startTimeIndex, primalEndTime); + dvUpdate_->getDesignVariables()->resetDesignVariables(); + lineSrch->updateStep(); + } + } + } + + // If line search did not need to get the new gradient, do it now in order + // to have it for the next optimisation cycle + if (!lineSrch->computeGradient()) + { + // Reset adjoint sensitivities in all adjoint solver managers + clearSensitivities(); + + // Solve all adjoint equations + solveAdjointEquations(); + } +} + + +void Foam::optimisationManager::fixedStepUpdate() +{ + // Update design variables + if (shouldUpdateDesignVariables_) + { + moveDesignVariables(); + } + + // Solve primal equations + solvePrimalEquations(); + + // Reset adjoint sensitivities in all adjoint solver managers + clearSensitivities(); + + // Solve all adjoint equations + solveAdjointEquations(); +} + + +void Foam::optimisationManager::moveDesignVariables() +{ + // Update design variables + dvUpdate_->update(); +} + + +void Foam::optimisationManager::moveDesignVariables +( + const scalarField& direction +) +{ + // Update design variables + dvUpdate_->update(direction); +} + + +void Foam::optimisationManager::initialize() { dictionary& primalSolversDict = subDict("primalSolvers"); const wordList& primalSolverNames = primalSolversDict.toc(); @@ -79,20 +217,42 @@ Foam::optimisationManager::optimisationManager(fvMesh& mesh) solveri, primalSolver::New ( - mesh, + mesh_, managerType_, - solverDict + solverDict, + primalSolverNames[solveri] ) ); } // Construct adjointSolverManagers const dictionary& adjointManagersDict = subDict("adjointManagers"); - const wordList& adjointManagerNames = adjointManagersDict.toc(); + const wordList adjointManagerNames = adjointManagersDict.toc(); adjointSolverManagers_.setSize(adjointManagerNames.size()); - label nAdjointSolvers(0); - bool overrideUseSolverName(adjointSolverManagers_.size() > 1); + // Determine the number of adjoint solvers which are not null (i.e. need to + // allocate adjoint fields). Used to determine whether the adjoint field + // names should be appended by the solver name + label nNotNullAdjointSolvers(0); + for (const word& adjManager : adjointManagerNames) + { + const dictionary& adjSolversDict = + adjointManagersDict.subDict(adjManager).subDict("adjointSolvers"); + const wordList adjointSolverNames = adjSolversDict.toc(); + for (const word& adjSolver : adjointSolverNames) + { + if (adjSolversDict.subDict(adjSolver).get<word>("type") != "null") + { + ++nNotNullAdjointSolvers; + } + } + } + Info<< "Found " + << nNotNullAdjointSolvers + << " adjoint solvers that allocate fields" + << endl; + bool overrideUseSolverName(nNotNullAdjointSolvers > 1); + forAll(adjointSolverManagers_, manageri) { adjointSolverManagers_.set @@ -100,13 +260,13 @@ Foam::optimisationManager::optimisationManager(fvMesh& mesh) manageri, new adjointSolverManager ( - mesh, + mesh_, + designVars_, managerType_, adjointManagersDict.subDict(adjointManagerNames[manageri]), overrideUseSolverName ) ); - nAdjointSolvers += adjointSolverManagers_[manageri].nAdjointSolvers(); } // Sanity checks on the naming convention @@ -126,7 +286,7 @@ Foam::optimisationManager::optimisationManager(fvMesh& mesh) } } - if (nAdjointSolvers > 1) + if (nNotNullAdjointSolvers > 1) { for (const adjointSolverManager& amI : adjointSolverManagers_) { @@ -145,9 +305,49 @@ Foam::optimisationManager::optimisationManager(fvMesh& mesh) } } } + if (designVars_) + { + designVars_().addFvOptions(primalSolvers_, adjointSolverManagers_); + } } +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::optimisationManager::optimisationManager(fvMesh& mesh) +: + IOdictionary + ( + IOobject + ( + "optimisationDict", + mesh.time().system(), + mesh, + IOobject::MUST_READ_IF_MODIFIED, + IOobject::NO_WRITE, + IOobject::REGISTER + ) + ), + mesh_(mesh), + time_(const_cast<Time&>(mesh.time())), + designVars_ + ( + this->subOrEmptyDict("optimisation").isDict("designVariables") ? + designVariables::New + ( + mesh_, + subDict("optimisation").subDict("designVariables") + ) : + nullptr + ), + primalSolvers_(), + adjointSolverManagers_(), + managerType_(get<word>("optimisationManager")), + dvUpdate_(nullptr), + shouldUpdateDesignVariables_(true) +{} + + // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * // Foam::autoPtr<Foam::optimisationManager> Foam::optimisationManager::New @@ -208,6 +408,12 @@ bool Foam::optimisationManager::read() man.readDict(adjointManagersDict.subDict(man.managerName())); } + if (designVars_) + { + designVars_->readDict + (subDict("optimisation").subDict("designVariables")); + } + return true; } @@ -215,16 +421,18 @@ bool Foam::optimisationManager::read() } -Foam::PtrList<Foam::primalSolver>& Foam::optimisationManager::primalSolvers() -{ - return primalSolvers_; -} - - -Foam::PtrList<Foam::adjointSolverManager>& -Foam::optimisationManager::adjointSolverManagers() +void Foam::optimisationManager::updateDesignVariables() { - return adjointSolverManagers_; + // Update design variables using either a line-search scheme or + // a fixed-step update + if (dvUpdate_->getLineSearch()) + { + lineSearchUpdate(); + } + else + { + fixedStepUpdate(); + } } @@ -258,6 +466,15 @@ void Foam::optimisationManager::computeSensitivities() } +void Foam::optimisationManager::clearSensitivities() +{ + for (adjointSolverManager& adjSolvManager : adjointSolverManagers_) + { + adjSolvManager.clearSensitivities(); + } +} + + void Foam::optimisationManager::updatePrimalBasedQuantities() { forAll(adjointSolverManagers_, amI) diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.H index ecd752586a843c06d426631748c2b729dcabaa5c..8fe371432608a4d5fab3b6eea6821a9d348832a4 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/optimisationManager/optimisationManager.H @@ -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 @@ -42,8 +42,9 @@ SourceFiles #include "runTimeSelectionTables.H" #include "IOdictionary.H" -#include "optimisationTypeIncompressible.H" #include "primalSolver.H" +#include "designVariables.H" +#include "designVariablesUpdate.H" #include "adjointSolverManager.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -63,12 +64,63 @@ protected: // Protected data + //- Reference to the mesh fvMesh& mesh_; + + //- Reference to the time Time& time_; + + //- Design variables of the optimisation problem. + // Constructed before the adjoint solvers, since + // some objective functions depend on their values + autoPtr<designVariables> designVars_; + + //- List of primal solvers to be included in the optimisation PtrList<primalSolver> primalSolvers_; + + //- List of adjoint solver managers to be included in the optimisation PtrList<adjointSolverManager> adjointSolverManagers_; + + //- Type of the optimisation manager (singleRun, (un)steadyOptimisation) const word managerType_; - autoPtr<incompressible::optimisationType> optType_; + + //- Helper class managing parts of the optimisation. + // Allocated only when an actual optimisation is conducted. + autoPtr<designVariablesUpdate> dvUpdate_; + + //- Switch defining if the design variables should be updated or not. + Switch shouldUpdateDesignVariables_; + + + // Protected Member Functions + + //- Reset time + // Does nothing in base, useful in unsteady adjoint + virtual void resetTime + ( + const dimensionedScalar startTime, + const label startTimeIndex, + const scalar endTime + ); + + //- Update design variables + virtual void moveDesignVariables(); + + //- Update design variables. Multiplication with line search step + // happens inside the update(direction) function + virtual void moveDesignVariables + ( + const scalarField& direction + ); + + //- Update design variables using a line-search + void lineSearchUpdate(); + + //- Update design variables using a fixed step + void fixedStepUpdate(); + + //- Initialization. Construct primal and adjoint solvers + virtual void initialize(); private: @@ -120,44 +172,73 @@ public: // Member Functions - virtual PtrList<primalSolver>& primalSolvers(); + // Access + + //- Get the primal solvers + inline PtrList<primalSolver>& primalSolvers() + { + return primalSolvers_; + } + + //- Get the adjoint solver managers + inline PtrList<adjointSolverManager>& adjointSolverManagers() + { + return adjointSolverManagers_; + } + + //- Get the design variables + inline autoPtr<designVariables>& getDesignVariables() + { + return designVars_; + } + + //- Get the mechanism supporting the update of the design variables + inline autoPtr<designVariablesUpdate>& getOptimisationType() + { + return dvUpdate_; + } + + + // Evolution - virtual PtrList<adjointSolverManager>& adjointSolverManagers(); + //- Changes in case of run-time update of optimisationDict + virtual bool read(); - virtual bool read(); + //- Prefix increment + virtual optimisationManager& operator++() = 0; - //- Prefix increment, - virtual optimisationManager& operator++() = 0; + //- Postfix increment, this is identical to the prefix increment + virtual optimisationManager& operator++(int) = 0; - //- Postfix increment, this is identical to the prefix increment - virtual optimisationManager& operator++(int) = 0; + //- Return true if end of optimisation run. + // Also, updates the design variables if needed + virtual bool checkEndOfLoopAndUpdate() = 0; - //- Return true if end of optimisation run. - // Also, updates the design variables if needed - virtual bool checkEndOfLoopAndUpdate() = 0; + //- Return true if end of optimisation run + virtual bool end() = 0; - //- Return true if end of optimisation run - virtual bool end() = 0; + //- Whether to update the design variables + virtual bool update() = 0; - //- Whether to update the design variables - virtual bool update() = 0; + //- Update design variables. + // Might employ a line search to find a correction satisfying the + // step convergence criteria + virtual void updateDesignVariables(); - //- Update design variables. - // Might employ a line search to find a correction satisfying the step - // convergence criteria - virtual void updateDesignVariables() = 0; + //- Solve all primal equations + virtual void solvePrimalEquations(); - //- Solve all primal equations - virtual void solvePrimalEquations(); + //- Solve all adjoint equations + virtual void solveAdjointEquations(); - //- Solve all adjoint equations - virtual void solveAdjointEquations(); + //- Compute all adjoint sensitivities + virtual void computeSensitivities(); - //- Compute all adjoint sensitivities - virtual void computeSensitivities(); + //- Clear all adjoint sensitivities + virtual void clearSensitivities(); - //- Solve all primal equations - virtual void updatePrimalBasedQuantities(); + //- Solve all primal equations + virtual void updatePrimalBasedQuantities(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.C index eca6e739ecdfbf0611e4f78122d610558194083e..d841dd434d0a74c3607c7141a620c9117440abcd 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/singleRun/singleRun.C @@ -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 @@ -45,7 +45,13 @@ Foam::singleRun::singleRun(fvMesh& mesh) : optimisationManager(mesh), cycles_(Zero) -{} +{ + initialize(); + if (designVars_) + { + designVars_().setInitialValues(); + } +} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.C index 50a2507689dfa5bfad07ff11dd1b8af5ff1fd4d0..d6a0c9e8669ccfce785747ae60703a40ff37e5ad 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.C @@ -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 @@ -44,137 +44,37 @@ namespace Foam } -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -void Foam::steadyOptimisation::updateOptTypeSource() -{ - forAll(primalSolvers_, pI) - { - primalSolvers_[pI].updateOptTypeSource(optType_->sourcePtr()); - } - - forAll(adjointSolverManagers_, asmI) - { - PtrList<adjointSolver>& adjointSolvers = - adjointSolverManagers_[asmI].adjointSolvers(); - - forAll(adjointSolvers, aI) - { - adjointSolvers[aI].updateOptTypeSource(optType_->sourcePtr()); - } - } -} - - -// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // - -void Foam::steadyOptimisation::lineSearchUpdate() -{ - // Compute direction of update - tmp<scalarField> tdirection = optType_->computeDirection(); - scalarField& direction = tdirection.ref(); - - // Grab reference to line search - autoPtr<lineSearch>& lineSrch = optType_->getLineSearch(); - - // Store starting point - optType_->storeDesignVariables(); - - // Compute merit function before update - scalar meritFunction = optType_->computeMeritFunction(); - lineSrch->setOldMeritValue(meritFunction); - - // Get merit function derivative - const scalar dirDerivative = - optType_->meritFunctionDirectionalDerivative(); - lineSrch->setDeriv(dirDerivative); - lineSrch->setDirection(direction); - - // Reset initial step. - // Might be interpolated from previous optimisation cycles - lineSrch->reset(); - - // Perform line search - for (label iter = 0; iter < lineSrch->maxIters(); ++iter) - { - Info<< "\n- - - - - - - - - - - - - - -" << endl; - Info<< "Line search iteration " << iter << endl; - Info<< "- - - - - - - - - - - - - - -\n" << endl; - - // Update design variables. Multiplication with line search step - // happens inside the update(direction) function - optType_->update(direction); - - // Solve all primal equations - solvePrimalEquations(); - - // Compute and set new merit function - meritFunction = optType_->computeMeritFunction(); - lineSrch->setNewMeritValue(meritFunction); - - if (lineSrch->converged()) - { - // If line search criteria have been met, proceed - Info<< "Line search converged in " << iter + 1 - << " iterations." << endl; - scalarField scaledCorrection(lineSrch->step()*direction); - optType_->updateOldCorrection(scaledCorrection); - optType_->write(); - lineSrch()++; - break; - } - else - { - // If maximum number of iteration has been reached, continue - if (iter == lineSrch->maxIters() - 1) - { - Info<< "Line search reached max. number of iterations.\n" - << "Proceeding to the next optimisation cycle" << endl; - scalarField scaledCorrection(lineSrch->step()*direction); - optType_->updateOldCorrection(scaledCorrection); - optType_->write(); - lineSrch()++; - } - // Reset to initial design variables and update step - else - { - optType_->resetDesignVariables(); - lineSrch->updateStep(); - } - } - } -} - - -void Foam::steadyOptimisation::fixedStepUpdate() -{ - // Update design variables - optType_->update(); - - // Solve primal equations - solvePrimalEquations(); -} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::steadyOptimisation::steadyOptimisation(fvMesh& mesh) : optimisationManager(mesh) { - optType_.reset + initialize(); + // Force the construction of the design variables, if they are not + // already present + if (!designVars_) + { + designVars_.reset + ( + designVariables::New + ( + mesh_, + subDict("optimisation").subDict("designVariables") + ).ptr() + ); + } + designVars_().setInitialValues(); + dvUpdate_.reset ( - incompressible::optimisationType::New + new designVariablesUpdate ( mesh, subDict("optimisation"), - adjointSolverManagers_ - ).ptr() + adjointSolverManagers_, + designVars_ + ) ); - - // Update source ptrs in all solvers to look at the source held in optType - // Possible problem if mesh is adapted - updateOptTypeSource(); } @@ -203,7 +103,7 @@ bool Foam::steadyOptimisation::checkEndOfLoopAndUpdate() { if (update()) { - optType_->update(); + dvUpdate_->update(); } return end(); } @@ -221,25 +121,4 @@ bool Foam::steadyOptimisation::update() } -void Foam::steadyOptimisation::updateDesignVariables() -{ - // Update design variables using either a line-search scheme or - // a fixed-step update - if (optType_->getLineSearch()) - { - lineSearchUpdate(); - } - else - { - fixedStepUpdate(); - } - - // Reset adjoint sensitivities in all adjoint solver managers - for (adjointSolverManager& adjSolverManager : adjointSolverManagers_) - { - adjSolverManager.clearSensitivities(); - } -} - - // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.H index 0fad239c9c9b806f220d55b85be0a560c557b768..7ae292ee2e4faa693f313a22a078c43fcc199f7b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationManager/steadyOptimisation/steadyOptimisation.H @@ -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 @@ -60,9 +60,6 @@ private: // Private Member Functions - //- Update optimisationType source for all primal and adjoint solvers - void updateOptTypeSource(); - //- No copy construct steadyOptimisation(const steadyOptimisation&) = delete; @@ -114,10 +111,6 @@ public: //- Whether to update the design variables virtual bool update(); - - //- Do a line search to find a correction satisfying the step - //- convergence criteria - virtual void updateDesignVariables(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.C deleted file mode 100644 index ccbf08f466c9f7ab55af8b3a58b5ac083546d537..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.C +++ /dev/null @@ -1,344 +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-2021 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 "optimisationTypeIncompressible.H" -#include "constrainedOptimisationMethod.H" -#include "runTimeSelectionTables.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -namespace incompressible -{ - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -defineTypeNameAndDebug(optimisationType, 0); -defineRunTimeSelectionTable(optimisationType, dictionary); - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -optimisationType::optimisationType -( - fvMesh& mesh, - const dictionary& dict, - PtrList<adjointSolverManager>& adjointSolverManagers -) -: - mesh_(mesh), - dict_(dict), - adjointSolvManagers_(adjointSolverManagers), - updateMethod_ - ( - updateMethod::New(mesh_, dict_.subDict("updateMethod")) - ), - sourcePtr_(nullptr), - lineSearch_ - ( - lineSearch::New - ( - dict_.subDict("updateMethod").subOrEmptyDict("lineSearch"), - mesh.time() - ) - ) -{ - // Figure out number of adjoint solvers corresponding to constraints. - // Looks in all operating poitns - label nConstraints(0); - for (const adjointSolverManager& adjManagerI : adjointSolvManagers_) - { - nConstraints += adjManagerI.nConstraints(); - } - - // Sanity checks for combinations of number of constraints and - // optimisation methods - if - ( - nConstraints - && !isA<constrainedOptimisationMethod>(updateMethod_()) - ) - { - const auto& cnstrTable = - *(constrainedOptimisationMethod::dictionaryConstructorTablePtr_); - - // Has constraints but is not a constraint optimisation method - FatalErrorInFunction - << "Found " << nConstraints << " adjoint solvers corresponding to " - << "constraints but the optimisation method (" - << updateMethod_().type() - << ") is not a constrainedOptimisationMethod." << nl - << "Available constrainedOptimisationMethods:" << nl - << cnstrTable.sortedToc() - << exit(FatalError); - } - else if - ( - !nConstraints - && isA<constrainedOptimisationMethod>(updateMethod_()) - ) - { - // Does not have constraints but is a constrained optimisation method - WarningInFunction - << "Did not find any adjoint solvers corresponding to " - << "constraints but the optimisation method (" - << updateMethod_().type() - << ") is a constrainedOptimisationMethod." << nl << nl - << "This can cause some constraintOptimisationMethods to misbehave." - << nl << nl - << "Either the isConstraint bool is not set in one of the adjoint " - << "solvers or you should consider using an updateMethod " - << "that is not a constrainedOptimisationMethod" - << nl << endl; - } -} - - -// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * // - -autoPtr<optimisationType> optimisationType::New -( - fvMesh& mesh, - const dictionary& dict, - PtrList<adjointSolverManager>& adjointSolverManagers -) -{ - const word modelType(dict.subDict("optimisationType").get<word>("type")); - - Info<< "optimisationType type : " << modelType << endl; - - auto* ctorPtr = dictionaryConstructorTable(modelType); - - if (!ctorPtr) - { - FatalIOErrorInLookup - ( - dict, - "optimisationType", - modelType, - *dictionaryConstructorTablePtr_ - ) << exit(FatalIOError); - } - - return autoPtr<optimisationType> - ( - ctorPtr(mesh, dict, adjointSolverManagers) - ); -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // - -void optimisationType::update() -{ - // Compute update of the design variables - tmp<scalarField> tcorrection(computeDirection()); - scalarField& correction = tcorrection.ref(); - - // Update design variables given the correction - update(correction); - - // If direction has been scaled (say by setting the initial eta), the - // old correction has to be updated - updateOldCorrection(correction); - write(); -} - - -void optimisationType::update(scalarField& direction) -{ - // Multiply with line search step, if necessary - scalarField correction(direction); - if (lineSearch_) - { - correction *= lineSearch_->step(); - } - - // Update the design variables - updateDesignVariables(correction); -} - - -tmp<scalarField> optimisationType::computeDirection() -{ - // Sum contributions for sensitivities and objective/constraint values - scalarField objectiveSens; - PtrList<scalarField> constraintSens; - scalar objectiveValue(Zero); - scalarField constraintValues; - - updateGradientsAndValues - ( - objectiveSens, - constraintSens, - objectiveValue, - constraintValues - ); - - // Based on the sensitivities, return design variables correction - updateMethod_->setObjectiveDeriv(objectiveSens); - updateMethod_->setConstraintDeriv(constraintSens); - updateMethod_->setObjectiveValue(objectiveValue); - updateMethod_->setConstraintValues(constraintValues); - tmp<scalarField> tcorrection - ( - new scalarField(objectiveSens.size(), Zero) - ); - scalarField& correction = tcorrection.ref(); - correction = updateMethod_->returnCorrection(); - - // Compute eta if needed - computeEta(correction); - - return tcorrection; -} - - -void optimisationType::updateGradientsAndValues -( - scalarField& objectiveSens, - PtrList<scalarField>& constraintSens, - scalar& objectiveValue, - scalarField& constraintValues -) -{ - for (adjointSolverManager& adjSolvManager : adjointSolvManagers_) - { - const scalar opWeight = adjSolvManager.operatingPointWeight(); - - // Allocate objective sens size if necessary - tmp<scalarField> tadjointSolverManagerSens = - adjSolvManager.aggregateSensitivities(); - - if (objectiveSens.empty()) - { - objectiveSens.setSize(tadjointSolverManagerSens().size(), Zero); - } - - objectiveSens += opWeight*tadjointSolverManagerSens(); - objectiveValue += opWeight*adjSolvManager.objectiveValue(); - - // Allocate constraint sens size if necessary - PtrList<scalarField> adjointSolverManagerConstSens = - adjSolvManager.constraintSensitivities(); - - tmp<scalarField> cValues = adjSolvManager.constraintValues(); - - if (constraintSens.empty()) - { - constraintSens.setSize(adjointSolverManagerConstSens.size()); - forAll(constraintSens, cI) - { - constraintSens.set - ( - cI, - new scalarField - ( - adjointSolverManagerConstSens[cI].size(), - Zero - ) - ); - constraintValues.setSize(cValues().size()); - constraintValues = Zero; - } - } - - forAll(constraintSens, cI) - { - constraintSens[cI] += opWeight*adjointSolverManagerConstSens[cI]; - } - constraintValues += opWeight*cValues(); - } -} - - -scalar optimisationType::computeMeritFunction() -{ - // Compute new objective and constraint values and update the ones - // in updateMethod - scalar objectiveValue(Zero); - scalarField constraintValues; - - for (adjointSolverManager& adjSolvManager : adjointSolvManagers_) - { - const scalar opWeight = adjSolvManager.operatingPointWeight(); - - objectiveValue += opWeight*adjSolvManager.objectiveValue(); - tmp<scalarField> cValues = adjSolvManager.constraintValues(); - - if (constraintValues.empty()) - { - constraintValues.setSize(cValues().size(), Zero); - } - constraintValues += opWeight*cValues(); - } - updateMethod_->setObjectiveValue(objectiveValue); - updateMethod_->setConstraintValues(constraintValues); - - return updateMethod_->computeMeritFunction(); -} - - -scalar optimisationType::meritFunctionDirectionalDerivative() -{ - return updateMethod_->meritFunctionDirectionalDerivative(); -} - - -void optimisationType::updateOldCorrection(const scalarField& oldCorrection) -{ - updateMethod_->updateOldCorrection(oldCorrection); -} - - -void optimisationType::write() -{ - updateMethod_->write(); -} - - -const autoPtr<volScalarField>& optimisationType::sourcePtr() -{ - return sourcePtr_; -} - - -autoPtr<lineSearch>& optimisationType::getLineSearch() -{ - return lineSearch_; -} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace incompressible -} // End namespace Foam - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.H deleted file mode 100644 index 1c1a75619fb239e515bfadc3cb1f570457fe4fb7..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/optimisationType/optimisationTypeIncompressible.H +++ /dev/null @@ -1,193 +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::optimisationType - -Description - Abstract base class for optimisation methods - -SourceFiles - optimisationType.C - -\*---------------------------------------------------------------------------*/ - -#ifndef optimisationTypeIncompressible_H -#define optimisationTypeIncompressible_H - -#include "adjointSolverManager.H" -#include "updateMethod.H" -#include "lineSearch.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -namespace incompressible -{ - -/*---------------------------------------------------------------------------*\ - Class optimisationType Declaration -\*---------------------------------------------------------------------------*/ - -class optimisationType -{ -protected: - - // Protected data - - fvMesh& mesh_; - const dictionary dict_; - PtrList<adjointSolverManager>& adjointSolvManagers_; - autoPtr<updateMethod> updateMethod_; - autoPtr<volScalarField> sourcePtr_; - autoPtr<lineSearch> lineSearch_; - - //- Update the design variables given their correction - virtual void updateDesignVariables(scalarField& correction) = 0; - - //- Compute eta if not set in the first step - virtual void computeEta(scalarField& correction) = 0; - - -private: - - // Private Member Functions - - //- No copy construct - optimisationType(const optimisationType&) = delete; - - //- No copy assignment - void operator=(const optimisationType&) = delete; - - -public: - - //- Runtime type information - TypeName("optimisationType"); - - - // Declare run-time constructor selection table - - declareRunTimeSelectionTable - ( - autoPtr, - optimisationType, - dictionary, - ( - fvMesh& mesh, - const dictionary& dict, - PtrList<adjointSolverManager>& adjointSolverManagers - ), - (mesh, dict, adjointSolverManagers) - ); - - - - // Constructors - - //- Construct from components - optimisationType - ( - fvMesh& mesh, - const dictionary& dict, - PtrList<adjointSolverManager>& adjointSolverManagers - ); - - // Selectors - - //- Return a reference to the selected turbulence model - static autoPtr<optimisationType> New - ( - fvMesh& mesh, - const dictionary& dict, - PtrList<adjointSolverManager>& adjointSolverManagers - ); - - - // Destructor - - virtual ~optimisationType() = default; - - //- Update design variables - virtual void update(); - - //- Update design variables based on a given correction - virtual void update(scalarField& correction); - - //- Store design variables, as the starting point for line search - virtual void storeDesignVariables() = 0; - - //- Reset to starting point of line search - virtual void resetDesignVariables() = 0; - - //- Compute update direction - virtual tmp<scalarField> computeDirection(); - - //- Compute cumulative objective and constraint gradients - virtual void updateGradientsAndValues - ( - scalarField& objectiveSens, - PtrList<scalarField>& constraintSens, - scalar& objectiveValue, - scalarField& constraintValues - ); - - //- Compute the merit function of the optimisation problem. - // Could be different than the objective function in case of - // constraint optimisation - virtual scalar computeMeritFunction(); - - //- Derivative of the merit function - virtual scalar meritFunctionDirectionalDerivative(); - - //- Update old correction. Needed for quasi-Newton Methods - virtual void updateOldCorrection(const scalarField&); - - //- Write useful quantities to files - virtual void write(); - - //- Get source term - const autoPtr<volScalarField>& sourcePtr(); - - //- Get a reference to the line search object - autoPtr<lineSearch>& getLineSearch(); -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace incompressible -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/shapeOptimisation/shapeOptimisationIncompressible.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/shapeOptimisation/shapeOptimisationIncompressible.C deleted file mode 100644 index 7a71d5ea6bc861bf4a0369ed05857c208de88909..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/shapeOptimisation/shapeOptimisationIncompressible.C +++ /dev/null @@ -1,207 +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 "shapeOptimisationIncompressible.H" -#include "addToRunTimeSelectionTable.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -namespace incompressible -{ - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -defineTypeNameAndDebug(shapeOptimisation, 0); -addToRunTimeSelectionTable -( - optimisationType, - shapeOptimisation, - dictionary -); - -// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // - -void shapeOptimisation::updateDesignVariables(scalarField& correction) -{ - // Communicate the movement to optMeshMovement - optMeshMovement_->setCorrection(correction); - - if (updateGeometry_) - { - // Update the mesh - optMeshMovement_->moveMesh(); - - if (writeEachMesh_) - { - Info<< " Writing new mesh points " << endl; - pointIOField points - ( - IOobject - ( - "points", - mesh_.pointsInstance(), - mesh_.meshSubDir, - mesh_, - IOobject::NO_READ, - IOobject::NO_WRITE, - IOobject::NO_REGISTER - ), - mesh_.points() - ); - points.write(); - } - } -} - - -void shapeOptimisation::computeEta -( - scalarField& correction -) -{ - if (!updateMethod_->initialEtaSet()) - { - // In the unlikely event that eta is not set and the line search step - // is not 1, multiply with it - // if (lineSearch_) correction *= lineSearch_->step(); - - // Compute eta based on desirable mesh movement size - scalar eta = optMeshMovement_->computeEta(correction); - correction *= eta; - - // Update eta known by the optimisation method and inform it that is - // has been set - updateMethod_->setStep(eta); - updateMethod_->initialEtaSet() = true; - - // If a backtracking should be made at the first optimisation cycle, - // the direction of the subsequent line searches of the same cycle - // should also be scaled with the newly computed eta. We do this by - // changing the line search step. This will happen only at the first - // optimisation cycle since the updated value of eta will be included - // in the line search direction in all subsequent optimisation cycles - //correction *= eta; - } -} - - -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -shapeOptimisation::shapeOptimisation -( - fvMesh& mesh, - const dictionary& dict, - PtrList<adjointSolverManager>& adjointSolverManagers -) -: - optimisationType(mesh, dict, adjointSolverManagers), - optMeshMovement_(nullptr), - writeEachMesh_ - ( - dict.subDict("optimisationType"). - getOrDefault<bool>("writeEachMesh", false) - ), - updateGeometry_ - ( - dict.subDict("optimisationType"). - getOrDefault<bool>("updateGeometry", true) - ) -{ - // Note: to be updated - labelHashSet patches - ( - mesh_.boundaryMesh().patchSet - ( - dict_.subDict("sensitivities").get<wordRes>("patches") - ) - ); - if (patches.empty()) - { - WarningInFunction - << "There is no patch on which to compute sensitivities. " - << "Check optimisationDict \n" - << endl; - } - labelList sensitivityPatchIDs = patches.toc(); - optMeshMovement_.reset - ( - optMeshMovement::New - ( - mesh_, - dict_.subDict("meshMovement"), - sensitivityPatchIDs - ).ptr() - ); - - // Sanity checks: at least one of eta or maxAllowedDisplacement must be set - if - ( - !updateMethod_->initialEtaSet() - && !optMeshMovement_().maxAllowedDisplacementSet() - ) - { - FatalErrorInFunction - << "Neither eta (updateMethod) " - << "nor maxAllowedDisplacement (meshMovement) have been set" - << nl - << exit(FatalError); - } -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void shapeOptimisation::storeDesignVariables() -{ - optMeshMovement_->storeDesignVariables(); -} - - -void shapeOptimisation::resetDesignVariables() -{ - optMeshMovement_->resetDesignVariables(); -} - - -void shapeOptimisation::write() -{ - optimisationType::write(); - updateMethod_->writeCorrection(); -} - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace incompressible -} // End namespace Foam - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/shapeOptimisation/shapeOptimisationIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/shapeOptimisation/shapeOptimisationIncompressible.H deleted file mode 100644 index 421feaba671710687f9422582921254b701a11a1..0000000000000000000000000000000000000000 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/optimisationType/incompressible/shapeOptimisation/shapeOptimisationIncompressible.H +++ /dev/null @@ -1,140 +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/>. - - - -Description - Shape optimisation support library - -Class - Foam::incompressible::shapeOptimisation - -Description - Calculates shape sensitivities using the adjoint approach, - computes boundaryMesh movement and propagates it to the volume mesh - -SourceFiles - shapeOptimisation.C - -\*---------------------------------------------------------------------------*/ - -#ifndef shapeOptimisationIncompressible_H -#define shapeOptimisationIncompressible_H - -#include "optimisationTypeIncompressible.H" -#include "optMeshMovement.H" - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -namespace Foam -{ - -namespace incompressible -{ - -/*---------------------------------------------------------------------------*\ - Class shapeOptimisation Declaration -\*---------------------------------------------------------------------------*/ - -class shapeOptimisation -: - public optimisationType -{ -protected: - - // Protected data - - autoPtr<optMeshMovement> optMeshMovement_; - - bool writeEachMesh_; - bool updateGeometry_; - - - // Protected Member Functions - - //- Update the design variables given their correction - virtual void updateDesignVariables(scalarField& correction); - - //- Compute eta if not set in the first step - virtual void computeEta(scalarField& correction); - - -private: - - // Private Member Functions - - //- No copy construct - shapeOptimisation(const shapeOptimisation&) = delete; - - //- No copy assignment - void operator=(const shapeOptimisation&) = delete; - - -public: - - //- Runtime type information - TypeName("shapeOptimisation"); - - - // Constructors - - //- Construct from components - shapeOptimisation - ( - fvMesh& mesh, - const dictionary& dict, - PtrList<adjointSolverManager>& adjointSolverManagers - ); - - - //- Destructor - virtual ~shapeOptimisation() = default; - - - // Member Functions - - //- Store design variables, as the starting point for line search - virtual void storeDesignVariables(); - - //- Store design variables, as the starting point for line search - virtual void resetDesignVariables(); - - //- Write useful quantities to files - virtual void write(); -}; - - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -} // End namespace incompressible -} // End namespace Foam - -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // - -#endif - -// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.C index b451f6b66017e511bef51d3ac2ee4217931f69b8..05aa86d2b7e3d1bea0abf0321d0515c74db6e8a7 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.C @@ -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 @@ -46,24 +46,6 @@ namespace Foam // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -void Foam::BFGS::allocateMatrices() -{ - // Set active design variables, if necessary - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(objectiveDerivatives_.size()); - } - - // Set previous HessianInv to be a diagonal matrix - SquareMatrix<scalar> temp(activeDesignVars_.size(), I); - - // Allocate correct size and content to HessianInv matrices - // has a max. capability of approximately 34000 variables. - HessianInvOld_ = temp; - HessianInv_ = temp; -} - - void Foam::BFGS::updateHessian() { // Vectors needed to construct the inverse HessianInv matrix @@ -73,14 +55,22 @@ void Foam::BFGS::updateHessian() s.map(correctionOld_, activeDesignVars_); scalar ys = globalSum(s*y); - if (counter_ == 1 && scaleFirstHessian_) { - scalar scaleFactor = ys/globalSum(y*y); - Info<< "Scaling Hessian with factor " << scaleFactor << endl; - forAll(activeDesignVars_, varI) + if (ys > scalar(0)) { - HessianInvOld_[varI][varI] *= scaleFactor; + scalar scaleFactor = ys/globalSum(y*y); + Info<< "Scaling Hessian with factor " << scaleFactor << endl; + forAll(activeDesignVars_, varI) + { + Hessian_()[varI][varI] *= scaleFactor; + } + } + else + { + WarningInFunction + << "y*s is negative. Skipping the scaling of the first Hessian" + << endl; } } @@ -95,13 +85,12 @@ void Foam::BFGS::updateHessian() << "Hessian curvature index " << ys << endl; // Construct the inverse HessianInv - HessianInv_ = - HessianInvOld_ - + (ys + globalSum(leftMult(y, HessianInvOld_)*y))/sqr(ys)*outerProd(s, s) + Hessian_() += + (ys + globalSum(leftMult(y, Hessian_())*y))/sqr(ys)*outerProd(s, s) - (scalar(1)/ys)* ( - outerProd(rightMult(HessianInvOld_, y), s) - + outerProd(s, leftMult(y, HessianInvOld_)) + outerProd(rightMult(Hessian_(), y), s) + + outerProd(s, leftMult(y, Hessian_())) ); } @@ -113,9 +102,12 @@ void Foam::BFGS::update() if (counter_ < nSteepestDescent_) { Info<< "Using steepest descent to update design variables" << endl; - correction_ = -eta_*objectiveDerivatives_; + for (const label varI : activeDesignVars_) + { + correction_[varI] = -eta_*objectiveDerivatives_[varI]; + } } - // else use BFGS formula to update the design variables + // Else use BFGS formula to update the design variables else { // Compute correction for active design variables @@ -123,7 +115,7 @@ void Foam::BFGS::update() activeDerivs.map(objectiveDerivatives_, activeDesignVars_); scalarField activeCorrection ( - -etaHessian_*rightMult(HessianInv_, activeDerivs) + -etaHessian_*rightMult(Hessian_(), activeDerivs) ); // Transfer correction to the global list @@ -137,29 +129,6 @@ void Foam::BFGS::update() // Store fields for the next iteration derivativesOld_ = objectiveDerivatives_; correctionOld_ = correction_; - HessianInvOld_ = HessianInv_; -} - - -void Foam::BFGS::readFromDict() -{ - if (optMethodIODict_.headerOk()) - { - optMethodIODict_.readEntry("HessianInvOld", HessianInvOld_); - optMethodIODict_.readEntry("derivativesOld", derivativesOld_); - optMethodIODict_.readEntry("correctionOld", correctionOld_); - optMethodIODict_.readEntry("counter", counter_); - optMethodIODict_.readEntry("eta", eta_); - - const label n(HessianInvOld_.n()); - HessianInv_ = SquareMatrix<scalar>(n, Zero); - correction_ = scalarField(correctionOld_.size(), Zero); - - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(n); - } - } } @@ -168,88 +137,19 @@ void Foam::BFGS::readFromDict() Foam::BFGS::BFGS ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ) : - updateMethod(mesh, dict), - etaHessian_ - ( - coeffsDict().getOrDefault<scalar>("etaHessian", 1) - ), - nSteepestDescent_ - ( - coeffsDict().getOrDefault<label>("nSteepestDescent", 1) - ), - activeDesignVars_(0), - scaleFirstHessian_ - ( - coeffsDict().getOrDefault<bool>("scaleFirstHessian", false) - ), + quasiNewton(mesh, dict, designVars, nConstraints, type), curvatureThreshold_ ( - coeffsDict().getOrDefault<scalar>("curvatureThreshold", 1e-10) - ), - // Construct null matrix since we dont know the dimension yet - HessianInv_(), - HessianInvOld_(), - derivativesOld_(0), - correctionOld_(0), - counter_(Zero) -{ - if - ( - !coeffsDict().readIfPresent("activeDesignVariables", activeDesignVars_) + coeffsDict(type).getOrDefault<scalar>("curvatureThreshold", 1e-10) ) - { - // If not, all available design variables will be used. Number is not - // know at the moment - Info<< "\t Did not find explicit definition of active design variables." - << " Treating all available ones as active" << endl; - } - - // Read old hessian, correction and derivatives, if present - readFromDict(); -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::BFGS::computeCorrection() -{ - if (counter_ == 0) - { - allocateMatrices(); - } - else - { - updateHessian(); - } - - update(); - ++counter_; -} - - -void Foam::BFGS::updateOldCorrection(const scalarField& oldCorrection) { - updateMethod::updateOldCorrection(oldCorrection); - correctionOld_ = oldCorrection; -} - - -void Foam::BFGS::write() -{ - optMethodIODict_.add<SquareMatrix<scalar>> - ( - "HessianInvOld", - HessianInvOld_, - true - ); - optMethodIODict_.add<scalarField>("derivativesOld", derivativesOld_, true); - optMethodIODict_.add<scalarField>("correctionOld", correctionOld_, true); - optMethodIODict_.add<label>("counter", counter_, true); - - updateMethod::write(); + allocateHessian(); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.H index 4995f7f502e52c4f89cbb511f1a8e3b9ae7d3af1..9daa6cd15d93f8733cbf61e425ca853998b30e29 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/BFGS/BFGS.H @@ -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 @@ -30,7 +30,8 @@ Class Foam::BFGS Description - The quasi-Newton BFGS formula + The quasi-Newton BFGS formula. + quasiNewton::Hessian corresponds to the inverse Hessian matrix in BFGS SourceFiles BFGS.C @@ -40,8 +41,7 @@ SourceFiles #ifndef BFGS_H #define BFGS_H -#include "updateMethod.H" -#include "scalarMatrices.H" +#include "quasiNewton.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -54,7 +54,7 @@ namespace Foam class BFGS : - public updateMethod + public quasiNewton { private: @@ -71,48 +71,17 @@ protected: // Protected data - //- Step for the Newton method - scalar etaHessian_; - - //- Number of first steepest descent steps - label nSteepestDescent_; - - //- Map to active design variables - labelList activeDesignVars_; - - //- Scale the iniitial unitary Hessian approximation - bool scaleFirstHessian_; - //- Curvature threshold scalar curvatureThreshold_; - //- The Hessian inverse. Should have the size of the active design - //- variables - SquareMatrix<scalar> HessianInv_; - - //- The previous Hessian inverse - SquareMatrix<scalar> HessianInvOld_; - - //- The previous derivatives - scalarField derivativesOld_; - - //- The previous correction - scalarField correctionOld_; - //- Optimisation cycle counter - label counter_; - - //- Allocate matrices in the first optimisation cycle - void allocateMatrices(); + // Protected Member Functions //- Update approximation of the inverse Hessian - void updateHessian(); + virtual void updateHessian(); //- Update design variables - void update(); - - //- Read old info from dict - void readFromDict(); + virtual void update(); public: @@ -124,24 +93,18 @@ public: // Constructors //- Construct from components - BFGS(const fvMesh& mesh, const dictionary& dict); + BFGS + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor virtual ~BFGS() = default; - - - // Member Functions - - //- Compute design variables correction - void computeCorrection(); - - //- Update old correction. Useful for quasi-Newton methods coupled with - //- line search - virtual void updateOldCorrection(const scalarField& oldCorrection); - - //- Write old info to dict - virtual void write(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.C index 6f38c121317d03e2cb1d5b3f63d954116d5c9f3b..4d1e2aa32f72079dbdd3d105c6b8036d05bdd5dd 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.C @@ -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 @@ -46,24 +46,6 @@ namespace Foam // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -void Foam::DBFGS::allocateMatrices() -{ - // Set active design variables, if necessary - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(objectiveDerivatives_.size()); - } - - // Set previous Hessian to be a diagonal matrix - SquareMatrix<scalar> temp(activeDesignVars_.size(), I); - - // Allocate correct size and content to Hessian matrices - // has a max. capability of approximately 34000 variables. - HessianOld_ = temp; - Hessian_ = temp; -} - - void Foam::DBFGS::updateHessian() { // Vectors needed to construct the inverse Hessian matrix @@ -73,18 +55,26 @@ void Foam::DBFGS::updateHessian() s.map(correctionOld_, activeDesignVars_); scalar ys = globalSum(s*y); - if (counter_ == 1 && scaleFirstHessian_) { - scalar scaleFactor = ys/globalSum(y*y); - Info<< "Scaling Hessian with factor " << scaleFactor << endl; - forAll(activeDesignVars_, varI) + if (ys > scalar(0)) { - HessianOld_[varI][varI] /= scaleFactor; + scalar scaleFactor = ys/globalSum(y*y); + Info<< "Scaling Hessian with factor " << scaleFactor << endl; + forAll(activeDesignVars_, varI) + { + Hessian_()[varI][varI] /= scaleFactor; + } + } + else + { + WarningInFunction + << "y*s is negative. Skipping the scaling of the first Hessian" + << endl; } } - scalar sBs = globalSum(leftMult(s, HessianOld_)*s); + scalar sBs = globalSum(leftMult(s, Hessian_())*s); // Check curvature condition and apply dampening is necessary scalar theta(1); @@ -98,26 +88,28 @@ void Foam::DBFGS::updateHessian() DebugInfo << "Hessian curvature index " << ys << endl; - scalarField r(theta*y + (scalar(1)-theta)*rightMult(HessianOld_, s)); + scalarField r(theta*y + (scalar(1)-theta)*rightMult(Hessian_(), s)); // Construct the inverse Hessian - Hessian_ = - HessianOld_ - - outerProd(rightMult(HessianOld_, s), leftMult(s/sBs, HessianOld_)) + Hessian_() += + - outerProd(rightMult(Hessian_(), s), leftMult(s/sBs, Hessian_())) + outerProd(r, r/globalSum(s*r)); } void Foam::DBFGS::update() { - SquareMatrix<scalar> HessianInv = inv(Hessian_); + SquareMatrix<scalar> HessianInv = inv(Hessian_()); // In the first few iterations, use steepest descent but update the Hessian // matrix if (counter_ < nSteepestDescent_) { Info<< "Using steepest descent to update design variables" << endl; - correction_ = -eta_*objectiveDerivatives_; + for (const label varI : activeDesignVars_) + { + correction_[varI] = -eta_*objectiveDerivatives_[varI]; + } } // Else use DBFGS formula to update design variables else @@ -141,29 +133,6 @@ void Foam::DBFGS::update() // Store fields for the next iteration derivativesOld_ = objectiveDerivatives_; correctionOld_ = correction_; - HessianOld_ = Hessian_; -} - - -void Foam::DBFGS::readFromDict() -{ - if (optMethodIODict_.headerOk()) - { - optMethodIODict_.readEntry("HessianOld", HessianOld_); - optMethodIODict_.readEntry("derivativesOld", derivativesOld_); - optMethodIODict_.readEntry("correctionOld", correctionOld_); - optMethodIODict_.readEntry("counter", counter_); - optMethodIODict_.readEntry("eta", eta_); - - label n = HessianOld_.n(); - Hessian_ = SquareMatrix<scalar>(n, Zero); - correction_ = scalarField(correctionOld_.size(), Zero); - - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(n); - } - } } @@ -172,86 +141,20 @@ void Foam::DBFGS::readFromDict() Foam::DBFGS::DBFGS ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ) : - updateMethod(mesh, dict), - - // Construct null matrix since we dont know the dimension yet - etaHessian_ - ( - coeffsDict().getOrDefault<scalar>("etaHessian", 1) - ), - nSteepestDescent_ - ( - coeffsDict().getOrDefault<label>("nSteepestDescent", 1) - ), - activeDesignVars_(0), - scaleFirstHessian_ - ( - coeffsDict().getOrDefault<bool>("scaleFirstHessian", false) - ), + quasiNewton(mesh, dict, designVars, nConstraints, type), curvatureThreshold_ ( - coeffsDict().getOrDefault<scalar>("curvatureThreshold", 1e-10) + coeffsDict(type).getOrDefault<scalar>("curvatureThreshold", 1e-10) ), - Hessian_(), - HessianOld_(), - derivativesOld_(0), - correctionOld_(0), - counter_(0), - gamma_(coeffsDict().getOrDefault<scalar>("gamma", 0.2)) - -{ - if - ( - !coeffsDict().readIfPresent("activeDesignVariables", activeDesignVars_) - ) - { - // If not, all available design variables will be used. Number is not - // know at the moment - Info<< "\t Did not find explicit definition of active design variables." - " Treating all available ones as active " << endl; - } - - // read old hessian, correction and derivatives, if present - readFromDict(); -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::DBFGS::computeCorrection() -{ - if (counter_ == 0) - { - allocateMatrices(); - } - else - { - updateHessian(); - } - - update(); - ++counter_; -} - - -void Foam::DBFGS::updateOldCorrection(const scalarField& oldCorrection) + gamma_(coeffsDict(type).getOrDefault<scalar>("gamma", 0.2)) { - updateMethod::updateOldCorrection(oldCorrection); - correctionOld_ = oldCorrection; -} - - -void Foam::DBFGS::write() -{ - optMethodIODict_.add<SquareMatrix<scalar>>("HessianOld", HessianOld_, true); - optMethodIODict_.add<scalarField>("derivativesOld", derivativesOld_, true); - optMethodIODict_.add<scalarField>("correctionOld", correctionOld_, true); - optMethodIODict_.add<label>("counter", counter_, true); - - updateMethod::write(); + allocateHessian(); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.H index 44d171fd7f1c4a0b05f4c1247c23f25a5dd4db69..55983504b105b366e0b6c318b726876c5646aa58 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/DBFGS/DBFGS.H @@ -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 @@ -40,8 +40,7 @@ SourceFiles #ifndef DBFGS_H #define DBFGS_H -#include "updateMethod.H" -#include "scalarMatrices.H" +#include "quasiNewton.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -54,59 +53,27 @@ namespace Foam class DBFGS : - public updateMethod + public quasiNewton { protected: // Protected data - //- Step for the Newton method - scalar etaHessian_; - - //- Number of first steepest descent steps - label nSteepestDescent_; - - //- Map to active design variables - labelList activeDesignVars_; - - //- Scale the initial unitary Hessian approximation - bool scaleFirstHessian_; - //- Curvature threshold scalar curvatureThreshold_; - //- The Hessian. Should have the size of the active design variables - SquareMatrix<scalar> Hessian_; - - //- The previous Hessian - SquareMatrix<scalar> HessianOld_; - - //- The previous derivatives - scalarField derivativesOld_; - - //- The previous correction - scalarField correctionOld_; - - //- Optimisation cycle counter - label counter_; - //- Threshold for damping scalar gamma_; // Protected Member Functions - //- Allocate matrices in the first optimisation cycle - void allocateMatrices(); - //- Update approximation of the inverse Hessian void updateHessian(); //- Update design variables void update(); - //- Read old info from dict - void readFromDict(); private: @@ -124,27 +91,22 @@ public: //- Runtime type information TypeName("DBFGS"); + // Constructors //- Construct from components - DBFGS(const fvMesh& mesh, const dictionary& dict); + DBFGS + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor virtual ~DBFGS() = default; - - - // Member Functions - - //- Compute design variables correction - void computeCorrection(); - - //- Update old correction. Useful for quasi-Newton methods coupled with - //- line search - virtual void updateOldCorrection(const scalarField& oldCorrection); - - //- Write old info to dict - virtual void write(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/ISQP/ISQP.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/ISQP/ISQP.C new file mode 100644 index 0000000000000000000000000000000000000000..9e0eb0d66784f883a13c892464955b57bfde0429 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/ISQP/ISQP.C @@ -0,0 +1,1048 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020-2021 PCOpt/NTUA + Copyright (C) 2020-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 "ISQP.H" +#include "IOmanip.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(ISQP, 0); + addToRunTimeSelectionTable + ( + updateMethod, + ISQP, + dictionary + ); + addToRunTimeSelectionTable + ( + constrainedOptimisationMethod, + ISQP, + dictionary + ); +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::ISQP::updateSizes() +{ + const label n = activeDesignVars_.size(); + if (n != deltaP_.size()) + { + // Correction fields + p_.setSize(n, Zero); + deltaP_.setSize(n, Zero); + + // Lagrange multipliers and slack variables for bound constraints + if (includeBoundConstraints_) + { + lTilda_().setSize(n, Zero); + ls_().setSize(n, Zero); + uTilda_().setSize(n, Zero); + us_().setSize(n, Zero); + + deltaLTilda_().setSize(n, Zero); + deltaLs_().setSize(n, Zero); + deltaUTilda_().setSize(n, Zero); + deltaUs_().setSize(n, Zero); + } + + // Fields used to compute the Hessian + for (label i = 0; i < nPrevSteps_; ++i) + { + y_[i].setSize(n, Zero); + s_[i].setSize(n, Zero); + } + } +} + + +void Foam::ISQP::allocateBoundMultipliers() +{ + if (includeBoundConstraints_) + { + // Number of constraints + const label n(activeDesignVars_.size()); + + if (!lTilda_) + { + lTilda_.reset(autoPtr<scalarField>::New(n, Zero)); + } + ls_.reset(autoPtr<scalarField>::New(n, Zero)); + if (!uTilda_) + { + uTilda_.reset(autoPtr<scalarField>::New(n, Zero)); + } + us_.reset(autoPtr<scalarField>::New(n, Zero)); + + deltaLTilda_.reset(autoPtr<scalarField>::New(n, Zero)); + deltaLs_.reset(autoPtr<scalarField>::New(n, Zero)); + deltaUTilda_.reset(autoPtr<scalarField>::New(n, Zero)); + deltaUs_.reset(autoPtr<scalarField>::New(n, Zero)); + } +} + + +void Foam::ISQP::allocateLagrangeMultipliers() +{ + // Number of constraints + const label m(nConstraints_); + // Allocate the extra variables ensuring the feasibility + if (includeExtraVars_) + { + extraVars_.reset(autoPtr<scalarField>::New(m, 1)); + z_.reset(autoPtr<scalarField>::New(m, max(1, 0.5*c_))); + + deltaExtraVars_.reset(autoPtr<scalarField>::New(m, Zero)); + deltaZ_.reset(autoPtr<scalarField>::New(m, Zero)); + } + + doAllocateLagrangeMultipliers_ = false; +} + + +void Foam::ISQP::updateYS() +{ + // Compute the Lagranian and old Lagrangian derivatives + scalarField LagrangianDerivativesOld(derivativesOld_); + forAll(constraintDerivatives_, cI) + { + LagrangianDerivatives_ += lamdas_[cI]*constraintDerivatives_[cI]; + LagrangianDerivativesOld += lamdas_[cI]*constraintDerivativesOld_[cI]; + } + + if (includeBoundConstraints_) + { + forAll(activeDesignVars_, aI) + { + const label varI(activeDesignVars_[aI]); + const scalar contr(uTilda_()[aI] - lTilda_()[aI]); + LagrangianDerivatives_[varI] += contr; + LagrangianDerivativesOld[varI] += contr; + } + } + + // Update vectors associated to the inverse Hessian matrix + updateVectors(LagrangianDerivatives_, LagrangianDerivativesOld); +} + + +void Foam::ISQP::initialize() +{ + const scalarField x(designVars_().getVars(), activeDesignVars_); + + // Quantities related to design variables + p_ = Zero; + if (includeBoundConstraints_) + { + lTilda_() = scalar(1); + uTilda_() = scalar(1); + ls_() = scalar(1); + us_() = scalar(1); + } + + // Quantities related to constraints + lamdas_ = scalar(1); + gs_ = scalar(1); + + if (includeExtraVars_) + { + extraVars_() = scalar(1); + z_() = max(1, 0.5*c_); + } + + // Reset eps + eps_ = 1; +} + + +void Foam::ISQP::zeroUpdates() +{ + deltaP_ = Zero; + deltaLamda_ = Zero; + deltaGs_ = Zero; + + if (includeBoundConstraints_) + { + deltaLTilda_() = Zero; + deltaLs_() = Zero; + deltaUTilda_() = Zero; + deltaUs_() = Zero; + } + + if (includeExtraVars_) + { + deltaExtraVars_() = Zero; + deltaZ_() = Zero; + } +} + + +void Foam::ISQP::solveDeltaPEqn() +{ + // Explicit part of the right hand side of the deltaX equation + scalarField FDx(-resFL()); + if (includeBoundConstraints_) + { + FDx += + (uTilda_()*resFus() + resFuTilda())/us_() + - (lTilda_()*resFls() + resFlTilda())/ls_(); + } + scalarField AMult(resFlamda()/lamdas_ - resFGs()); + scalarField mult(gs_/lamdas_); + if (includeExtraVars_) + { + mult += extraVars_()/z_(); + AMult -= (extraVars_()*resFExtraVars() + resFz())/z_(); + } + AMult /= mult; + forAll(FDx, aI) + { + const label varI(activeDesignVars_[aI]); + forAll(constraintDerivatives_, cI) + { + FDx[aI] += constraintDerivatives_[cI][varI]*AMult[cI]; + } + } + CGforDeltaP(FDx); + /* + //Info<< "FDx::" << FDx << endl; + //Info<< "invHFL::" << invHFL() << endl; + + // Loop to obtain deltaX. Part of the LHS is treated explicitly, to + // avoid solving a (potentially) dense system with the size of the design + // variables + scalarField rhs(computeRHSForDeltaX(FDx)); + scalar res(sqrt(globalSum(magSqr(deltaP_ - rhs)))); + scalar resInit(res); + label iter(0); + do + { + deltaP_ = rhs; + rhs = computeRHSForDeltaX(FDx); + res = sqrt(globalSum(magSqr(deltaP_ - rhs))); + DebugInfo + << "Solving for deltaX, Initial Residual " << resInit + << ", Final Residual " << res << endl; + resInit = res; + } while (iter++ < maxDxIters_ && res > 1.e-07); +// Info<< "deltaX solution " << deltaP_ << endl; +// */ +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::computeRHSForDeltaX +( + const scalarField& FDx +) +{ + tmp<scalarField> trhs(tmp<scalarField>::New(-FDx)); + scalarField& rhs = trhs.ref(); + + // Compute (Gs)^(-1)*Λ*A*Dp + scalarField GsLADp(cValues_.size(), Zero); + forAll(constraintDerivatives_, cI) + { + const scalarField& cDerivsI = constraintDerivatives_[cI]; + GsLADp[cI] += + globalSum(scalarField(cDerivsI, activeDesignVars_)*deltaP_); + } + GsLADp *= lamdas_/gs_; + + // Multiply with A^T + forAll(rhs, aI) + { + const label varI(activeDesignVars_[aI]); + forAll(constraintDerivatives_, cI) + { + rhs[aI] += constraintDerivatives_[cI][varI]*GsLADp[cI]; + } + } + + // Contributions from bounds + if (includeBoundConstraints_) + { + rhs += (lTilda_()/ls_() + uTilda_()/us_())*deltaP_; + } + + rhs = -invHessianVectorProduct(rhs); + + rhs = 0.95*deltaP_ + 0.05*rhs; + return trhs; +} + + +void Foam::ISQP::CGforDeltaP(const scalarField& FDx) +{ + scalarField precond(deltaPDiagPreconditioner()); + scalarField r(FDx - DeltaPMatrixVectorProduct(deltaP_)); + scalarField z(precond*r); + scalarField p(z); + scalar res(sqrt(globalSum(r*r))); + scalar resInit(res); + scalar rz(globalSum(r*z)); + scalar rzOld(rz); + label iter(0); + do + { + scalarField Ap(DeltaPMatrixVectorProduct(p)); + scalar a = rz/globalSum(p*Ap); + deltaP_ += a*p; + r -= a*Ap; + res = sqrt(globalSum(r*r)); + z = precond*r; + rz = globalSum(r*z); + scalar beta = rz/rzOld; + p = z + beta*p; + rzOld = rz; + } while (iter++ < maxDxIters_ && res > 1.e-09); + DebugInfo + << "CG, Solving for deltaP, Initial Residual " << resInit + << ", Final Residual " << res + << ", No Iterations " << iter << endl; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::deltaPDiagPreconditioner() +{ + tmp<scalarField> tpreconditioner(HessianDiag()); + //tmp<scalarField> tpreconditioner(SR1HessianDiag()); + scalarField& preconditioner = tpreconditioner.ref(); + + // Part related to the constraints + forAll(constraintDerivatives_, cI) + { + scalarField cDerivs(constraintDerivatives_[cI], activeDesignVars_); + scalar mult(gs_[cI]/lamdas_[cI]); + if (includeExtraVars_) + { + mult += extraVars_()[cI]/z_()[cI]; + } + preconditioner += sqr(cDerivs)/mult; + } + + if (includeBoundConstraints_) + { + preconditioner += lTilda_()/ls_() + uTilda_()/us_(); + } + + preconditioner = 1./preconditioner; + + return tpreconditioner; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::DeltaPMatrixVectorProduct +( + const scalarField& vector +) +{ + tmp<scalarField> tAp(HessianVectorProduct(vector)); + //tmp<scalarField> tAp(SR1HessianVectorProduct(vector)); + scalarField& Ap = tAp.ref(); + scalarField GsLAv(cValues_.size(), Zero); + forAll(constraintDerivatives_, cI) + { + const scalarField& cDerivsI = constraintDerivatives_[cI]; + GsLAv[cI] = + globalSum(scalarField(cDerivsI, activeDesignVars_)*vector); + } + scalarField mult(gs_/lamdas_); + if (includeExtraVars_) + { + mult += extraVars_()/z_(); + } + GsLAv /= mult; + + // Multiply with A^T + forAll(Ap, aI) + { + const label varI(activeDesignVars_[aI]); + forAll(constraintDerivatives_, cI) + { + Ap[aI] += constraintDerivatives_[cI][varI]*GsLAv[cI]; + } + } + + // Contributions from bounds + if (includeBoundConstraints_) + { + Ap += (lTilda_()/ls_() + uTilda_()/us_())*vector; + } + + + return tAp; +} + + +void Foam::ISQP::computeNewtonDirection() +{ + // Zero the updates computed in the previous optimisation cycle + //zeroUpdates(); + + // Solve equation for deltaP_. The expensive part of the step. Everything + // else can be computed based on this + solveDeltaPEqn(); + + // deltaLamda + forAll(constraintDerivatives_, cI) + { + const scalarField& cDerivsI = constraintDerivatives_[cI]; + deltaLamda_[cI] = + globalSum(scalarField(cDerivsI, activeDesignVars_)*deltaP_); + } + scalarField mult(gs_/lamdas_); + if (includeExtraVars_) + { + mult += extraVars_()/z_(); + deltaLamda_ += (resFz() + extraVars_()*resFExtraVars())/z_(); + } + deltaLamda_ += resFGs() - resFlamda()/lamdas_; + deltaLamda_ /= mult; + + // deltaGs + deltaGs_ = -(gs_*deltaLamda_ + resFlamda())/lamdas_; + + if (includeBoundConstraints_) + { + // deltaLs + deltaLs_() = deltaP_ + resFls(); + + // deltaUs + deltaUs_() = -deltaP_ + resFus(); + + // deltaLTilda + deltaLTilda_() = -(lTilda_()*deltaLs_() + resFlTilda())/ls_(); + + // deltaUTilda + deltaUTilda_() = -(uTilda_()*deltaUs_() + resFuTilda())/us_(); + } + + if (includeExtraVars_) + { + deltaZ_() = -deltaLamda_ + resFExtraVars(); + deltaExtraVars_() = - (extraVars_()*deltaZ_() + resFz())/z_(); + } +} + + +Foam::scalar Foam::ISQP::lineSearch() +{ + const label n(p_.size()); + const label m(cValues_.size()); + scalar step(1.); + + if (includeBoundConstraints_) + { + for (label i = 0; i < n; ++i) + { + adjustStep(step, ls_()[i], deltaLs_()[i]); + adjustStep(step, us_()[i], deltaUs_()[i]); + adjustStep(step, lTilda_()[i], deltaLTilda_()[i]); + adjustStep(step, uTilda_()[i], deltaUTilda_()[i]); + } + } + + // Perform bound checks and adjust step accordingly + for (label i = 0; i < m; ++i) + { + adjustStep(step, lamdas_[i], deltaLamda_[i]); + adjustStep(step, gs_[i], deltaGs_[i]); + if (includeExtraVars_) + { + adjustStep(step, extraVars_()[i], deltaExtraVars_()[i]); + adjustStep(step, z_()[i], deltaZ_()[i]); + } + } + + // Each processor might have computed a different step, if design variables + // are distributed. Get the global minimum + if (globalSum_) + { + reduce(step, minOp<scalar>()); + } + + step = min(1, step); + + if (debug > 1) + { + Info<< "Step before line search is " << step << endl; + } + + // Old residual + scalar normResOld = sqrt(globalSum(magSqr(computeResiduals()))); + scalar maxRes(GREAT); + + for (label i = 0; i < maxLineSearchIters_ ; ++i) + { + // Update the solution with given step + updateSolution(step); + + // Compute new residuals and their max value + scalarField resNew(computeResiduals()); + scalar normResNew = sqrt(globalSum(magSqr(resNew))); + maxRes = gMax(mag(resNew)); + + if (normResNew < normResOld) + { + DebugInfo + << "Initial residual = " << normResOld << ", " + << "Final residual = " << normResNew << ", " + << "No of LineSearch Iterations = " << i + 1 + << endl; + break; + } + else + { + // Return solution to previous and reduce step + if (i != maxLineSearchIters_ - 1) + { + updateSolution(-step); + step *= 0.5; + } + else + { + Info<< tab << "Line search did not converge. " + << "Procceding with the last compute step" << endl; + } + } + } + + if (debug > 1) + { + Info<< "Step after line search is " << step << nl << endl; + } + + return maxRes; +} + + +void Foam::ISQP::adjustStep +( + scalar& step, + const scalar value, + const scalar update +) +{ + if (0.99*value + step*update < scalar(0)) + { + step = -0.99*value/update; + } +} + + +void Foam::ISQP::updateSolution(const scalar step) +{ + p_ += step*deltaP_; + lamdas_ += step*deltaLamda_; + gs_ += step*deltaGs_; + if (includeBoundConstraints_) + { + lTilda_() += step*deltaLTilda_(); + ls_() += step*deltaLs_(); + uTilda_() += step*deltaUTilda_(); + us_() += step*deltaUs_(); + } + if (includeExtraVars_) + { + extraVars_() += step*deltaExtraVars_(); + z_() += step*deltaZ_(); + } +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::computeResiduals() +{ + const label n(activeDesignVars_.size()); + const label m(cValues_.size()); + label size(includeBoundConstraints_ ? 5*n + 2*m : n + 2*m); + if (includeExtraVars_) + { + size += 2*m; + } + tmp<scalarField> tres(tmp<scalarField>::New(size, Zero)); + scalarField& res = tres.ref(); + + label iRes(0); + + // Gradient of the Lagrangian + res.rmap(resFL()(), identity(n)); + iRes = n; + + // Inequality constraints slacks + res.rmap(resFGs()(), identity(m, iRes)); + iRes += m; + + // Inequality constraints complementarity slackness + res.rmap(resFlamda()(), identity(m, iRes)); + iRes += m; + + if (includeBoundConstraints_) + { + // Lower bounds slacks + res.rmap(resFls()(), identity(n, iRes)); + iRes += n; + + // Upper bounds slacks + res.rmap(resFus()(), identity(n, iRes)); + iRes += n; + + // Lower bounds complementarity slackness + res.rmap(resFlTilda()(), identity(n, iRes)); + iRes += n; + + // Upper bounds complementarity slackness + res.rmap(resFuTilda()(), identity(n, iRes)); + iRes += n; + } + + if (includeExtraVars_) + { + // Lagragian derivative wrt the extra variables + res.rmap(resFExtraVars()(), identity(m, iRes)); + iRes += m; + + // Lagrange multipliers for the extra variables positiveness + res.rmap(resFz(), identity(m, iRes)); + iRes += m; + } + + return tres; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFL() +{ + tmp<scalarField> tgradL + (tmp<scalarField>::New(objectiveDerivatives_, activeDesignVars_)); + scalarField& gradL = tgradL.ref(); + + scalarField Hp(HessianVectorProduct(p_)); + //scalarField Hp = SR1HessianVectorProduct(p_); + gradL += Hp; + + if (debug > 2) + { + scalarField H1Hp(invHessianVectorProduct(Hp)); + Info << "Diff H1Hp - p " << gSum(mag(H1Hp - p_)) << endl; + } + + forAll(constraintDerivatives_, cI) + { + gradL += + lamdas_[cI] + *scalarField(constraintDerivatives_[cI], activeDesignVars_); + } + + if (includeBoundConstraints_) + { + gradL += uTilda_() - lTilda_(); + } + + return tgradL; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::invHFL() +{ + tmp<scalarField> tinvHFL + (tmp<scalarField>::New(objectiveDerivatives_, activeDesignVars_)); + scalarField& invHFL = tinvHFL.ref(); + + forAll(constraintDerivatives_, cI) + { + invHFL += + lamdas_[cI] + *scalarField(constraintDerivatives_[cI], activeDesignVars_); + } + + if (includeBoundConstraints_) + { + invHFL += uTilda_() - lTilda_(); + } + + invHFL = invHessianVectorProduct(invHFL); + invHFL += p_; + + return tinvHFL; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFGs() +{ + tmp<scalarField> tFGs(tmp<scalarField>::New(gs_ + cValues_)); + scalarField& FGs = tFGs.ref(); + + forAll(constraintDerivatives_, cI) + { + FGs[cI] += + globalSum + ( + scalarField(constraintDerivatives_[cI], activeDesignVars_)*p_ + ); + } + + if (includeExtraVars_) + { + FGs -= extraVars_(); + } + + return tFGs; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFlamda() +{ + return (lamdas_*gs_ - eps_); +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFls() +{ + if (includeBoundConstraints_) + { + const scalarField x(designVars_().getVars(), activeDesignVars_); + const scalarField xMin + (designVars_().lowerBounds()(), activeDesignVars_); + + return (x + p_ - xMin - ls_()); + } + return nullptr; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFus() +{ + if (includeBoundConstraints_) + { + const scalarField x(designVars_().getVars(), activeDesignVars_); + const scalarField xMax + (designVars_().upperBounds()(), activeDesignVars_); + + return (xMax - x - p_ - us_()); + } + return nullptr; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFlTilda() +{ + if (includeBoundConstraints_) + { + return (lTilda_()*ls_() - eps_); + } + return nullptr; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFuTilda() +{ + if (includeBoundConstraints_) + { + return (uTilda_()*us_() - eps_); + } + return nullptr; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFExtraVars() +{ + if (includeExtraVars_) + { + return (c_ - lamdas_ - z_()); + } + return nullptr; +} + + +Foam::tmp<Foam::scalarField> Foam::ISQP::resFz() +{ + if (includeExtraVars_) + { + return (z_()*extraVars_() - eps_); + } + return nullptr; +} + + +void Foam::ISQP::solveSubproblem() +{ + zeroUpdates(); + if (includeBoundConstraints_ || !cValues_.empty()) + { + scalar resMax(gMax(mag(computeResiduals()))); + label iter(0); + do + { + DebugInfo + << "Newton iter " << iter << nl << endl; + + // Decrease eps + if (resMax < 0.9*eps_) + { + eps_ *= 0.1; + } + + // Computes Newton direction for the subproblem + computeNewtonDirection(); + + // Perform line search and return max residual of the solution + // satisfying the bound constraints and the residual reduction. + // Upates solution. + resMax = lineSearch(); + DebugInfo + << "max residual = " << resMax << ", " + << "eps = " << eps_ << nl << endl; + } while + ( + iter++ < maxNewtonIters_ && (eps_ > epsMin_ || resMax > 0.9*eps_) + ); + if (iter == maxNewtonIters_) + { + WarningInFunction + << "Iterative solution of the QP problem did not converge" + << endl; + } + if (debug) + { + scalarField vars(designVars_().getVars(), activeDesignVars_); + scalarField newVars(vars + p_); + Info<< "Min of updated vars " << gMin(newVars) << endl; + Info<< "Max of updated vars " << gMax(newVars) << endl; + + Info<< "Min of lamda " << gMin(lamdas_) << endl; + Info<< "Max of gs " << gMax(gs_) << endl; + Info<< "Max of lamda*gs " << gMax(lamdas_*gs_) << endl; + + if (includeBoundConstraints_) + { + Info<< "Min of lTilda " << gMin(lTilda_()) << endl; + Info<< "Min of uTilda " << gMin(uTilda_()) << endl; + Info<< "Min of ls " << gMin(ls_()) << endl; + Info<< "Min of us " << gMin(us_()) << endl; + Info<< "Max of lTilda*ls " << gMax(lTilda_()*ls_()) << endl; + Info<< "Max of uTilda*us " << gMax(uTilda_()*us_()) << endl; + } + if (includeExtraVars_) + { + Info<< "Min of extraVars " << gMin(extraVars_()) << endl; + Info<< "Max of extraVars*z " << gMax(extraVars_()*z_()) << endl; + } + } + } + else + { + computeNewtonDirection(); + lineSearch(); + } + + // Pass update to correction field + correction_.rmap(p_, activeDesignVars_); + if (!counter_) + { + correction_ *= eta_; + } + else + { + correction_ *= etaHessian_; + } +} + + +void Foam::ISQP::storeOldFields() +{ + derivativesOld_ = objectiveDerivatives_; + if (constraintDerivativesOld_.empty()) + { + constraintDerivativesOld_.setSize(constraintDerivatives_.size()); + } + forAll(constraintDerivativesOld_, cI) + { + constraintDerivativesOld_[cI] = constraintDerivatives_[cI]; + } + correctionOld_ = correction_; +} + + +Foam::scalar Foam::ISQP::meritFunctionConstraintPart() const +{ + // Assumes that all constraints are known by all processors + // What about constraints directly imposed on distributed design variables? + // These should be met in each iteration of the algorithm, so, + // most probably, there is no problem + return sum(pos(cValues_)*cValues_); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::ISQP::ISQP +( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type +) +: + LBFGS(mesh, dict, designVars, nConstraints, type), + SQPBase(mesh, dict, designVars, *this, type), + + doAllocateLagrangeMultipliers_(true), + includeBoundConstraints_ + ( + designVars->upperBounds() && designVars->lowerBounds() + ), + includeExtraVars_ + ( + coeffsDict(type).getOrDefault<bool>("includeExtraVars", false) + ), + p_(activeDesignVars_.size(), Zero), + gs_(nConstraints_, 1), + lTilda_ + ( + includeBoundConstraints_ && found("lTilda") ? + new scalarField("lTilda", *this, activeDesignVars_.size()) : + nullptr + ), + ls_(nullptr), + uTilda_ + ( + includeBoundConstraints_ && found("uTilda") ? + new scalarField("uTilda", *this, activeDesignVars_.size()) : + nullptr + ), + us_(nullptr), + extraVars_(nullptr), + z_(nullptr), + c_(coeffsDict(type).getOrDefault<scalar>("c", 100)), + deltaP_(activeDesignVars_.size(), Zero), + deltaLamda_(nConstraints_, Zero), + deltaGs_(nConstraints_, Zero), + deltaLTilda_(nullptr), + deltaLs_(nullptr), + deltaUTilda_(nullptr), + deltaUs_(nullptr), + deltaExtraVars_(nullptr), + deltaZ_(nullptr), + eps_(1), + epsMin_(coeffsDict(type).getOrDefault<scalar>("epsMin", 1.e-07)), + maxNewtonIters_(coeffsDict(type).getOrDefault<label>("maxIters", 1000)), + maxLineSearchIters_ + ( + coeffsDict(type).getOrDefault<label>("maxLineSearchIters", 10) + ), + maxDxIters_(coeffsDict(type).getOrDefault<label>("maxDpIters", 1000)), + meritFunctionFile_(nullptr) +{ + // Always apply damping of s in ISQP + useYDamping_ = true; + useSDamping_ = false; + + // Allocate multipliers and slack variables for the bound constraints + allocateBoundMultipliers(); + allocateLagrangeMultipliers(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::ISQP::computeCorrection() +{ + // Update sizes of fields related to the active design variables + updateSizes(); + + // The first iteration uses a unitary Hessian. No need to update + LagrangianDerivatives_ = objectiveDerivatives_; + if (counter_) + { + updateYS(); + } + + // Initiaze variables + initialize(); + + // Solve subproblem using a Newton optimiser + solveSubproblem(); + + // Store fields for the next iteration and write them to file + storeOldFields(); + + // Increase counter + ++counter_; +} + + +Foam::scalar Foam::ISQP::computeMeritFunction() +{ + mu_ = max(pos(cValues_)*lamdas_) + delta_; + scalar L = objectiveValue_ + mu_*sum(pos(cValues_)*cValues_); + + return L; +} + + +Foam::scalar Foam::ISQP::meritFunctionDirectionalDerivative() +{ + scalar deriv = + globalSum(objectiveDerivatives_*correction_) + - mu_*sum(pos(cValues_)*cValues_); + + return deriv; +} + + +void Foam::ISQP::updateOldCorrection(const scalarField& oldCorrection) +{ + updateMethod::updateOldCorrection(oldCorrection); + correctionOld_ = oldCorrection; +} + + +bool Foam::ISQP::writeData(Ostream& os) const +{ + if (includeBoundConstraints_) + { + uTilda_().writeEntry("uTilda", os); + lTilda_().writeEntry("lTilda", os); + } + + return LBFGS::writeData(os) && SQPBase::addToFile(os); +} + + +bool Foam::ISQP::writeAuxiliaryData() +{ + return SQPBase::writeMeritFunction(*this); +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/ISQP/ISQP.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/ISQP/ISQP.H new file mode 100644 index 0000000000000000000000000000000000000000..56336c41cbe78dab9ea2f5cd2c34d2d59b7c6c84 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/ISQP/ISQP.H @@ -0,0 +1,345 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2020-2021 PCOpt/NTUA + Copyright (C) 2020-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/>. + + +Class + Foam::ISQP + +Description + An L-BFGS-based SQP algorithm for computing the update of the design + variables in the presence of inequality constraints. The QP problem is + solved using the interior point method (hence the I in the classe name, + which is not standard in the terminology used in the literature). The + (potentially dense) linear system formulated by the interior point method + is solved using Conjugate Gradient with a diagonal preconditioner, using + matrix-vector products to avoid storing the LHS matrix. + + Bound constraints on the design variables will also be included, if set by + the designVariables known by the updateMethod. If the QP problem is + infeasible, the algorithm can still be used by setting includeExtraVars_ + to true, to allow a computation of an update, despite not being able to + satisfy all the constraints of the QP problem. + + +SourceFiles + ISQP.C + +\*---------------------------------------------------------------------------*/ + +#ifndef ISQP_H +#define ISQP_H + +#include "LBFGS.H" +#include "SQPBase.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class ISQP Declaration +\*---------------------------------------------------------------------------*/ + +class ISQP +: + public LBFGS, + public SQPBase +{ +protected: + + // Protected data + + //- Should Lagrange multipliers be allocated + bool doAllocateLagrangeMultipliers_; + + //- Are bound constraints included? + bool includeBoundConstraints_; + + //- Are additional design variables included? + // These are introduced to find relaxed solutions, even if the + // original problem does not have any feasible points + bool includeExtraVars_; + + //- The set of design variables being updated during the subproblem. + // Size is that of the active design variables. + // Correction will end up being the difference of this and the old + // design variables. + scalarField p_; + + // Lagrange multipliers and slack variables + + //- Lagrange multipliers for the inequality constraints + // Inheritated from SQPBase + //scalarField lamdas_; + + //- Slack variables for the inequality constraints + scalarField gs_; + + //- Lagrange multipliers for the lower bound constraints + autoPtr<scalarField> lTilda_; + + //- Slack variables the lower bound constraints + autoPtr<scalarField> ls_; + + //- Lagrange multipliers for the upper bound constraints + autoPtr<scalarField> uTilda_; + + //- Slack variables the upper bound constraints + autoPtr<scalarField> us_; + + //- Extra variables for finding solutions even in infeasible + //- problems + autoPtr<scalarField> extraVars_; + + //- Lagrange multipliers for positive extra variables + autoPtr<scalarField> z_; + + //- Multiplier of the additional variables y in the Lagrangian, to + //- make them 'expensive' + scalar c_; + + + // Fields holding updates of the design, Lagrange and slack variables + + scalarField deltaP_; + scalarField deltaLamda_; + scalarField deltaGs_; + autoPtr<scalarField> deltaLTilda_; + autoPtr<scalarField> deltaLs_; + autoPtr<scalarField> deltaUTilda_; + autoPtr<scalarField> deltaUs_; + autoPtr<scalarField> deltaExtraVars_; + autoPtr<scalarField> deltaZ_; + + + //- Infinitesimal quantity + // Updated during the inner iterations of the subproblem + scalar eps_; + + //- Final eps quantity to be reached during the solution of the + //- subproblem + scalar epsMin_; + + //- Maxmimum number of Newton iterations for the subproblem + label maxNewtonIters_; + + //- Maxmimum number of line search iterations for each iteration of the + //- subproblem + label maxLineSearchIters_; + + //- Maxmimum number of iterations for the deltaX equation + label maxDxIters_; + + //- File including the l1 merit function + autoPtr<OFstream> meritFunctionFile_; + + + // Protected Member Functions + + //- Update sizes of fields related to the active design variables + void updateSizes(); + + //- Allocate multipliers for the bound constraints + void allocateBoundMultipliers(); + + //- Allocate Lagrange multipliers for the inequality constraints + void allocateLagrangeMultipliers(); + + //- Update the vectors accosiated with the Hessian matrix + void updateYS(); + + //- Allocate fields related to constraints + void initialize(); + + + // Functions related to the solution of the primal-dual subproblem + + //- Solve subproblem using a Newton optimiser + void solveSubproblem(); + + //- Compute direction for the Newton problem + void computeNewtonDirection(); + + //- Zero the updates computed in the previous optimisation cycle + void zeroUpdates(); + + //- Solve the equation for deltaX, which is the expensive part of + //- the Newtopn step. + // All other corrections can be computed based on this + void solveDeltaPEqn(); + + //- Compute the RHS for the deltaX equation + tmp<scalarField> computeRHSForDeltaX(const scalarField& FDx); + + //- CG algorithm for the solution of the deltaP eqn + void CGforDeltaP(const scalarField& FDx); + + //- Diagonal preconditioner of the deltaP eqn + tmp<scalarField> deltaPDiagPreconditioner(); + + //- Procudt of the LHS of the deltaP eqn with a vector + tmp<scalarField> DeltaPMatrixVectorProduct + ( + const scalarField& vector + ); + + //- Perform line search and return max residual corresponding to + //- the updated solution + scalar lineSearch(); + + //- Adjust step to satisfy cireteria + void adjustStep + ( + scalar& step, + const scalar value, + const scalar update + ); + + //- Update the current solution using the known direction and the + //- given step length + void updateSolution(const scalar step); + + + // Residuals of the various KKT conditions + + //- Compute and return residuals based on the current solution + tmp<scalarField> computeResiduals(); + + //- Residual of the gradient of the Lagrangian + // Size is that of the active design variables + tmp<scalarField> resFL(); + + //- Product of the inverse Hessian with the residual of the + //- gradient of the Lagrangian. + // Avoid the formation of the Hessian matrix. + // Size is that of the active design variables. + tmp<scalarField> invHFL(); + + //- Residual of the inequality constraint slackness + tmp<scalarField> resFGs(); + + //- Residual of the complementarity slackness for the + //- inequality constraints + tmp<scalarField> resFlamda(); + + //- Residual of the lower bounds slackness + tmp<scalarField> resFls(); + + //- Residual of the upper bounds slackness + tmp<scalarField> resFus(); + + //- Residual of the complementarity slackness for the + //- lower bound constraints + tmp<scalarField> resFlTilda(); + + //- Residual of the complementarity slackness for the + //- upper bound constraints + tmp<scalarField> resFuTilda(); + + //- Residual of the Lagrangian derivative wrt the extra variables + tmp<scalarField> resFExtraVars(); + + //- Residual of the complementarity slackness for the + //- extra variables + tmp<scalarField> resFz(); + + + //- Store old fields needed for the next iter + void storeOldFields(); + + //- Get the part the merit function that depends on the constraints + virtual scalar meritFunctionConstraintPart() const; + + +private: + + // Private Member Functions + + //- No copy construct + ISQP(const ISQP&) = delete; + + //- No copy assignment + void operator=(const ISQP&) = delete; + + +public: + + //- Runtime type information + TypeName("ISQP"); + + + // Constructors + + //- Construct from components + ISQP + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); + + + //- Destructor + virtual ~ISQP() = default; + + + // Member Functions + + //- Compute design variables correction + void computeCorrection(); + + //- Compute merit function. Could be different than the objective + //- in the presence of constraints + virtual scalar computeMeritFunction(); + + //- Derivative of the merit function. Could be different than the + //- objective derivative in the presence of constraints + virtual scalar meritFunctionDirectionalDerivative(); + + //- Update old correction. Useful for quasi-Newton methods coupled with + //- line search + virtual void updateOldCorrection(const scalarField& oldCorrection); + + //- Write useful quantities to files + virtual bool writeData(Ostream& os) const; + + //- Write merit function information + virtual bool writeAuxiliaryData(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.C index 2aa335053f5f3f7956a7970a0e02234db65d218b..6d82c97299f799fb96dd4e0e5b2ce84940b06b01 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.C @@ -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 @@ -34,7 +34,7 @@ License namespace Foam { - defineTypeNameAndDebug(LBFGS, 0); + defineTypeNameAndDebug(LBFGS, 1); addToRunTimeSelectionTable ( updateMethod, @@ -46,20 +46,27 @@ namespace Foam // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -void Foam::LBFGS::allocateMatrices() +void Foam::LBFGS::allocateVectors() { - // Set active design variables, if necessary - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(objectiveDerivatives_.size()); - } - - // Allocate vectors label nVars(activeDesignVars_.size()); - for (label i = 0; i < nPrevSteps_; i++) + for (label i = 0; i < nPrevSteps_; ++i) { - y_.set(i, new scalarField(nVars, Zero)); - s_.set(i, new scalarField(nVars, Zero)); + if (!y_.get(i)) + { + y_.set(i, new scalarField(nVars, Zero)); + } + if (!s_.get(i)) + { + s_.set(i, new scalarField(nVars, Zero)); + } + if (found("y" + Foam::name(i))) + { + y_[i] = scalarField("y" + Foam::name(i), *this, nVars); + } + if (found("s" + Foam::name(i))) + { + s_[i] = scalarField("s" + Foam::name(i), *this, nVars); + } } } @@ -87,187 +94,553 @@ void Foam::LBFGS::pivotFields(PtrList<scalarField>& list, const scalarField& f) } -void Foam::LBFGS::updateVectors() +void Foam::LBFGS::updateVectors +( + const scalarField& derivatives, + const scalarField& derivativesOld +) { - // Update list of y. Can only be done here since objectiveDerivatives_ - // was not known at the end of the previous loop - scalarField yRecent - (objectiveDerivatives_ - derivativesOld_, activeDesignVars_); - pivotFields(y_, yRecent); + // Sanity checks + if + ( + (derivatives.size() != derivativesOld.size()) + || (derivatives.size() != designVars_().getVars().size()) + ) + { + FatalErrorInFunction + << "Sizes of input derivatives and design variables do not match" + << exit(FatalError); + } + + // Update list of y. Can only be done here since derivatives + // were not known at the end of the previous cycle + scalarField yRecent(derivatives - derivativesOld, activeDesignVars_); // Update list of s. // correction_ holds the previous correction scalarField sActive(correctionOld_, activeDesignVars_); + applyDamping(yRecent, sActive); + + pivotFields(y_, yRecent); pivotFields(s_, sActive); +} + +void Foam::LBFGS::applyDamping(scalarField& y, scalarField& s) +{ + const scalar sy(globalSum(s*y)); + if (useSDamping_) + { + const scalarField Hy(invHessianVectorProduct(y, counter_ - 1)); + const scalar yHy(globalSum(y*Hy)); + scalar theta(1); + if (sy < 0.2*yHy) + { + WarningInFunction + << "y*s is below threshold. Using damped form" << nl + << "sy, yHy " << sy << " " << yHy << endl; + + theta = 0.8*yHy/(yHy - sy); + } + s = theta*s + (1 - theta)*Hy; + } + else if (useYDamping_) + { + const scalarField Bs(HessianVectorProduct(s, counter_ - 1)); + const scalar sBs(globalSum(s*Bs)); + scalar theta(1); + if (sy < 0.2*sBs) + { + WarningInFunction + << "y*s is below threshold. Using damped form" << nl + << "sy, sBs " << sy << " " << sBs << endl; + + theta = 0.8*sBs/(sBs - sy); + } + y = theta*y + (1 - theta)*Bs; + } DebugInfo - << "y fields" << nl << y_ << endl; - DebugInfo - << "s fields" << nl << s_ << endl; + << "Curvature index (sy) is " << sy << endl; } -void Foam::LBFGS::steepestDescentUpdate() +Foam::tmp<Foam::scalarField> +Foam::LBFGS::invHessianVectorProduct(const scalarField& vector) { - Info<< "Using steepest descent to update design variables" << endl; - correction_ = -eta_*objectiveDerivatives_; + return invHessianVectorProduct(vector, counter_); } -void Foam::LBFGS::LBFGSUpdate() +Foam::tmp<Foam::scalarField> +Foam::LBFGS::invHessianVectorProduct +( + const scalarField& vector, + const label counter +) { - // L-BFGS two loop recursion - //~~~~~~~~~~~~~~~~~~~~~~~~~~ - label nSteps(min(counter_, nPrevSteps_)); - label nLast(nSteps - 1); - scalarField q(objectiveDerivatives_, activeDesignVars_); - scalarField a(nSteps, Zero); - scalarField r(nSteps, Zero); - for (label i = nLast; i > -1; --i) + // Sanity checks + tmp<scalarField> tq(tmp<scalarField>::New(activeDesignVars_.size(), Zero)); + scalarField& q = tq.ref(); + if (vector.size() == designVars_().getVars().size()) { - r[i] = 1./globalSum(y_[i]*s_[i]); - a[i] = r[i]*globalSum(s_[i]*q); - q -= a[i]*y_[i]; + q.map(vector, activeDesignVars_); } - - scalar gamma = - globalSum(y_[nLast]*s_[nLast])/globalSum(y_[nLast]*y_[nLast]); - q *= gamma; - - scalarField b(activeDesignVars_.size(), Zero); - for (label i = 0; i < nSteps; ++i) + else if (vector.size() == activeDesignVars_.size()) { - b = r[i]*globalSum(y_[i]*q); - q += s_[i]*(a[i] -b); + q = vector; + } + else + { + FatalErrorInFunction + << "Size of input vector is equal to neither the number of " + << " design variabes nor that of the active design variables" + << exit(FatalError); } - // Update correction - forAll(activeDesignVars_, varI) + if (counter != 0) { - correction_[activeDesignVars_[varI]] = -etaHessian_*q[varI]; + // L-BFGS two loop recursion + //~~~~~~~~~~~~~~~~~~~~~~~~~~ + label nSteps(min(counter, nPrevSteps_)); + label nLast(nSteps - 1); + scalarField a(nSteps, 0.); + scalarField r(nSteps, 0.); + for (label i = nLast; i > -1; --i) + { + //Info << "Y " << y_[i] << endl; + //Info << "S " << s_[i] << endl; + r[i] = 1./globalSum(y_[i]*s_[i]); + a[i] = r[i]*globalSum(s_[i]*q); + q -= a[i]*y_[i]; + } + + scalar gamma = + globalSum(y_[nLast]*s_[nLast])/globalSum(y_[nLast]*y_[nLast]); + q *= gamma; + + scalarField b(activeDesignVars_.size(), Zero); + for (label i = 0; i < nSteps; ++i) + { + b = r[i]*globalSum(y_[i]*q); + q += s_[i]*(a[i] - b); + } } + + return tq; } -void Foam::LBFGS::update() +Foam::tmp<Foam::scalarField> +Foam::LBFGS::HessianVectorProduct(const scalarField& vector) { - // In the first few iterations, use steepest descent but update the Hessian - // matrix - if (counter_ < nSteepestDescent_) + return HessianVectorProduct(vector, counter_); +} + + +Foam::tmp<Foam::scalarField> +Foam::LBFGS::HessianVectorProduct +( + const scalarField& vector, + const label counter +) +{ + // Sanity checks + tmp<scalarField> tq(tmp<scalarField>::New(activeDesignVars_.size(), Zero)); + scalarField& q = tq.ref(); + + scalarField source; + if (vector.size() == designVars_().getVars().size()) { - steepestDescentUpdate(); + source = scalarField(vector, activeDesignVars_); + } + else if (vector.size() == activeDesignVars_.size()) + { + source = vector; } - // else use LBFGS formula to update the design variables else { - LBFGSUpdate(); + FatalErrorInFunction + << "Size of input vector is equal to neither the number of " + << " design variabes nor that of the active design variables" + << exit(FatalError); } - // Store fields for the next iteration - derivativesOld_ = objectiveDerivatives_; - correctionOld_ = correction_; + if (counter != 0) + { + const label nSteps(min(counter, nPrevSteps_)); + const label nLast(nSteps - 1); + const scalar delta = + globalSum(y_[nLast]*y_[nLast])/globalSum(y_[nLast]*s_[nLast]); + + // Product of the last matrix on the right with the input vector + scalarField SKsource(2*nSteps, Zero); + for(label i = 0; i < nSteps; ++i) + { + SKsource[i] = delta*globalSum(s_[i]*source); + SKsource[i + nSteps] = globalSum(y_[i]*source); + } + + // Form the middle matrix to be inverted + SquareMatrix<scalar> M(2*nSteps, 2*nSteps, Zero); + for (label i = 0; i < nSteps; ++i) + { + // Lower diagonal part + M[nSteps + i][nSteps + i] = - globalSum(s_[i]*y_[i]); + // Upper left part + for (label j = 0; j < nSteps; ++j) + { + M[i][j] = delta*globalSum(s_[i]*s_[j]); + } + } + + // Upper right and lower left parts + for (label j = 0; j < nSteps; ++j) + { + for (label i = j + 1; i < nSteps; ++i) + { + scalar value = globalSum(s_[i]*y_[j]); + M[i][j + nSteps] = value; + M[j + nSteps][i] = value; + } + } + SquareMatrix<scalar> invM(inv(M)); + + // Product of the inverted middle matrix with the right vector + scalarField invMSource(rightMult(invM, SKsource)); + + // Left vector multiplication with the rest of contributions + // vag: parallel comms + forAll(q, i) + { + for (label j = 0; j < nSteps; ++j) + { + q[i] -= + delta*s_[j][i]*invMSource[j] + + y_[j][i]*invMSource[j + nSteps]; + } + } + + q += delta*source; + } + else + { + q = source; + } + + return tq; } -void Foam::LBFGS::readFromDict() +Foam::tmp<Foam::scalarField> Foam::LBFGS::HessianDiag() { - if (optMethodIODict_.headerOk()) + // Sanity checks + const label n(activeDesignVars_.size()); + tmp<scalarField> tdiag(tmp<scalarField>::New(n, 1)); + scalarField& diag = tdiag.ref(); + + if (counter_ != 0) { - optMethodIODict_.readEntry("y", y_); - optMethodIODict_.readEntry("s", s_); - optMethodIODict_.readEntry("derivativesOld", derivativesOld_); - optMethodIODict_.readEntry("counter", counter_); - optMethodIODict_.readEntry("eta", eta_); - optMethodIODict_.readEntry("correctionOld", correctionOld_); + const label nSteps(min(counter_, nPrevSteps_)); + const label nLast(nSteps - 1); + const scalar delta = + globalSum(y_[nLast]*y_[nLast])/globalSum(y_[nLast]*s_[nLast]); + diag *= delta; + + // Form the middle matrix to be inverted + SquareMatrix<scalar> M(2*nSteps, 2*nSteps, Zero); + for (label i = 0; i < nSteps; ++i) + { + // Lower diagonal part + M[nSteps + i][nSteps + i] = - globalSum(s_[i]*y_[i]); + // Upper left part + for (label j = 0; j < nSteps; ++j) + { + M[i][j] = delta*globalSum(s_[i]*s_[j]); + } + } + + // Upper right and lower left parts + for (label j = 0; j < nSteps; ++j) + { + for (label i = j + 1; i < nSteps; ++i) + { + scalar value = globalSum(s_[i]*y_[j]); + M[i][j + nSteps] = value; + M[j + nSteps][i] = value; + } + } - correction_ = scalarField(correctionOld_.size(), Zero); + // Invert the matrix + SquareMatrix<scalar> invM(inv(M)); - if (activeDesignVars_.empty()) + // Product of the inverse of the middle matrix with the right vector + List<scalarField> MR(2*nSteps, scalarField(n, Zero)); + for(label k = 0; k < n; ++k) { - activeDesignVars_ = identity(derivativesOld_.size()); + for(label i = 0; i < 2*nSteps; ++i) + { + for(label j = 0; j < nSteps; ++j) + { + MR[i][k] += + invM[i][j]*delta*s_[j][k] + + invM[i][j + nSteps]*y_[j][k]; + } + } + } + + // Part of the Hessian diagonal computed by the multiplication + // of the above matrix with the left matrix of the recursive Hessian + // reconstruction + for(label k = 0; k < n; ++k) + { + for(label j = 0; j < nSteps; ++j) + { + diag[k] -= + delta*s_[j][k]*MR[j][k] + y_[j][k]*MR[j + nSteps][k]; + } } } + + return tdiag; } -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // +Foam::tmp<Foam::scalarField> +Foam::LBFGS::SR1HessianVectorProduct(const scalarField& vector) +{ + return SR1HessianVectorProduct(vector, counter_); +} -Foam::LBFGS::LBFGS + +Foam::tmp<Foam::scalarField> +Foam::LBFGS::SR1HessianVectorProduct ( - const fvMesh& mesh, - const dictionary& dict + const scalarField& vector, + const label counter ) -: - updateMethod(mesh, dict), +{ + // Sanity checks + tmp<scalarField> tq(tmp<scalarField>::New(activeDesignVars_.size(), Zero)); + scalarField& q = tq.ref(); - // Construct null matrix since we dont know the dimension yet - etaHessian_ - ( - coeffsDict().getOrDefault<scalar>("etaHessian", 1) - ), - nSteepestDescent_ - ( - coeffsDict().getOrDefault<label>("nSteepestDescent", 1) - ), - activeDesignVars_(0), - nPrevSteps_ - ( - coeffsDict().getOrDefault<label>("nPrevSteps", 10) - ), - y_(nPrevSteps_), - s_(nPrevSteps_), - derivativesOld_(0), - counter_(Zero) + scalarField source; + if (vector.size() == designVars_().getVars().size()) + { + source = scalarField(vector, activeDesignVars_); + } + else if (vector.size() == activeDesignVars_.size()) + { + source = vector; + } + else + { + FatalErrorInFunction + << "Size of input vector is equal to neither the number of " + << " design variabes nor that of the active design variables" + << exit(FatalError); + } + + if (counter != 0) + { + const label nSteps(min(counter, nPrevSteps_)); + const label nLast(nSteps - 1); + const scalar delta = + globalSum(y_[nLast]*y_[nLast])/globalSum(y_[nLast]*s_[nLast]); + + // Product of the last matrix on the right with the input vector + scalarField YBSsource(nSteps, Zero); + for(label i = 0; i < nSteps; ++i) + { + YBSsource[i] = globalSum((y_[i] - delta*s_[i])*source); + } + + // Form the middle matrix to be inverted + SquareMatrix<scalar> M(nSteps, nSteps, Zero); + for (label i = 0; i < nSteps; ++i) + { + // D part + M[i][i] += globalSum(s_[i]*y_[i]); + // (S^T)BS part + for (label j = 0; j < nSteps; ++j) + { + M[i][j] -= delta*globalSum(s_[i]*s_[j]); + } + } + + // Upper right and lower left parts + for (label j = 0; j < nSteps; ++j) + { + for (label i = j + 1; i < nSteps; ++i) + { + scalar value = globalSum(s_[i]*y_[j]); + M[i][j] += value; + M[j][i] += value; + } + } + SquareMatrix<scalar> invM(inv(M)); + + // Product of the inverted middle matrix with the right vector + scalarField invMSource(rightMult(invM, YBSsource)); + + // Left vector multiplication with the rest of contributions + // vag: parallel comms + forAll(q, i) + { + for (label j = 0; j < nSteps; ++j) + { + q[i] += (y_[j][i] - delta*s_[j][i])*invMSource[j]; + } + } + + q += delta*source; + } + else + { + q = source; + } + + return tq; +} + + +Foam::tmp<Foam::scalarField> Foam::LBFGS::SR1HessianDiag() { - if - ( - !coeffsDict().readIfPresent("activeDesignVariables", activeDesignVars_) - ) + // Sanity checks + const label n(activeDesignVars_.size()); + tmp<scalarField> tdiag(tmp<scalarField>::New(n, 1)); + scalarField& diag = tdiag.ref(); + + if (counter_ != 0) { - // If not, all available design variables will be used. Number is not - // know at the moment - Info<< "\t Did not find explicit definition of active design variables. " - << "Treating all available ones as active " << endl; + const label nSteps(min(counter_, nPrevSteps_)); + const label nLast(nSteps - 1); + const scalar delta = + globalSum(y_[nLast]*y_[nLast])/globalSum(y_[nLast]*s_[nLast]); + diag *= delta; + + // Form the middle matrix to be inverted + SquareMatrix<scalar> M(nSteps, nSteps, Zero); + for (label i = 0; i < nSteps; ++i) + { + // D part + M[i][i] += globalSum(s_[i]*y_[i]); + // (S^T)BS part + for (label j = 0; j < nSteps; ++j) + { + M[i][j] -= delta*globalSum(s_[i]*s_[j]); + } + } + + // Upper right and lower left parts + for (label j = 0; j < nSteps; ++j) + { + for (label i = j + 1; i < nSteps; ++i) + { + scalar value = globalSum(s_[i]*y_[j]); + M[i][j] += value; + M[j][i] += value; + } + } + SquareMatrix<scalar> invM(inv(M)); + + // Product of the inverse of the middle matrix with the right vector + List<scalarField> MR(nSteps, scalarField(n, Zero)); + for(label k = 0; k < n; ++k) + { + for(label i = 0; i < nSteps; ++i) + { + for(label j = 0; j < nSteps; ++j) + { + MR[i][k] += invM[i][j]*(y_[j][k] - delta*s_[j][k]); + } + } + } + + // Part of the Hessian diagonal computed by the multiplication + // of the above matrix with the left matrix of the recursive Hessian + // reconstruction + for(label k = 0; k < n; ++k) + { + for(label j = 0; j < nSteps; ++j) + { + diag[k] += (y_[j][k] - delta*s_[j][k])*MR[j][k]; + } + } } - // Read old Hessian, correction and derivatives, if present - readFromDict(); + return tdiag; } -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +void Foam::LBFGS::updateHessian() +{ + updateVectors(objectiveDerivatives_, derivativesOld_); +} + -void Foam::LBFGS::computeCorrection() +void Foam::LBFGS::update() { - if (counter_ == 0) + // In the first few iterations, use steepest descent but update the Hessian + // matrix + if (counter_ < nSteepestDescent_) { - allocateMatrices(); + Info<< "Using steepest descent to update design variables" << endl; + for (const label varI : activeDesignVars_) + { + correction_[varI] = -eta_*objectiveDerivatives_[varI]; + } } + // else use LBFGS formula to update the design variables else { - updateVectors(); + scalarField q(invHessianVectorProduct(objectiveDerivatives_)); + forAll(activeDesignVars_, varI) + { + correction_[activeDesignVars_[varI]] = -etaHessian_*q[varI]; + } } - update(); - ++counter_; + // Store fields for the next iteration + derivativesOld_ = objectiveDerivatives_; + correctionOld_ = correction_; } -void Foam::LBFGS::updateOldCorrection(const scalarField& oldCorrection) +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::LBFGS::LBFGS +( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type +) +: + quasiNewton(mesh, dict, designVars, nConstraints, type), + nPrevSteps_(coeffsDict(type).getOrDefault<label>("nPrevSteps", 10)), + y_(nPrevSteps_), + s_(nPrevSteps_), + useSDamping_(coeffsDict(type).getOrDefault<bool>("useSDamping", false)), + useYDamping_(coeffsDict(type).getOrDefault<bool>("useYDamping", false)) { - updateMethod::updateOldCorrection(oldCorrection); - correctionOld_ = oldCorrection; + // Allocate the correct sizes for y and s + allocateVectors(); } -void Foam::LBFGS::write() +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::LBFGS::writeData(Ostream& os) const { - optMethodIODict_.add<PtrList<scalarField>>("y", y_, true); - optMethodIODict_.add<PtrList<scalarField>>("s", s_, true); - optMethodIODict_.add<scalarField>("derivativesOld", derivativesOld_, true); - optMethodIODict_.add<scalarField>("correctionOld", correctionOld_, true); - optMethodIODict_.add<label>("counter", counter_, true); + // Write each component of y and s as a separate field so as to allow for + // reading them also in binary, since PtrList does not support this + forAll(y_, i) + { + y_[i].writeEntry(word("y" + Foam::name(i)), os); + s_[i].writeEntry(word("s" + Foam::name(i)), os); + } - updateMethod::write(); + return quasiNewton::writeData(os); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.H index 7bffc387e86c7ba18e015eedd3ab2bcb1e99a321..2f6db818889879853d589083fee07a28e2d0db82 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/LBFGS/LBFGS.H @@ -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 @@ -41,8 +41,7 @@ SourceFiles #ifndef LBFGS_H #define LBFGS_H -#include "updateMethod.H" -#include "scalarMatrices.H" +#include "quasiNewton.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -50,12 +49,12 @@ namespace Foam { /*---------------------------------------------------------------------------*\ - Class LBFGS Declaration + Class LBFGS Declaration \*---------------------------------------------------------------------------*/ class LBFGS : - public updateMethod + public quasiNewton { private: @@ -72,15 +71,6 @@ protected: // Protected data - //- Step for the Newton method - scalar etaHessian_; - - //- Number of first steepest descent steps - label nSteepestDescent_; - - //- Map to active design variables - labelList activeDesignVars_; - //- Number of old corrections and grad differences kept label nPrevSteps_; @@ -90,36 +80,107 @@ protected: //- The previous correction. Holds nPrevSteps_ fields PtrList<scalarField> s_; - //- The previous derivatives - scalarField derivativesOld_; + //- Use damping for s to ensure positive-definitiveness + bool useSDamping_; - //- The previous correction - scalarField correctionOld_; + //- Use damping for s to ensure positive-definitiveness + bool useYDamping_; - //- Optimisation cycle counter - label counter_; + + // Protected Member Functions //- Allocate matrices in the first optimisation cycle - void allocateMatrices(); + void allocateVectors(); //- Move pointers in PtrList to the left and replace last element with //- given field void pivotFields(PtrList<scalarField>& list, const scalarField& f); //- Update y and s vectors - void updateVectors(); + void updateVectors + ( + const scalarField& derivatives, + const scalarField& derivativesOld + ); + + //- Use the damped version of s to ensure positive-definitiveness + // Usefull in conjunction with SQP + void applyDamping + ( + scalarField& y, + scalarField& s + ); + + //- Update the Hessian matrix by updating the base vectors + virtual void updateHessian(); //- Update design variables - void update(); - - //- Update based on steepest descent - void steepestDescentUpdate(); - - //- Update based on LBFGS - void LBFGSUpdate(); - - //- Read old info from dict - void readFromDict(); + virtual void update(); + + //- Compute the inverse Hessian - vector product + // Input should have the size of all design variables or the active + // ones, output is the size of the active design variables + virtual tmp<scalarField> invHessianVectorProduct + ( + const scalarField& vector + ); + + //- Same as previous one, but with an explicit counter provided + tmp<scalarField> invHessianVectorProduct + ( + const scalarField& vector, + const label counter + ); + + //- Compute the Hessian - vector product + // Requires the solution of a system of equations twice the size of + // the bases. This should be OK since the latter is small. + // Input should have the size of all design variables or the active + // ones, output is the size of the active design variables + virtual tmp<scalarField> HessianVectorProduct + ( + const scalarField& vector + ); + + //- Same as previous one, but with an explicit counter provided + tmp<scalarField> HessianVectorProduct + ( + const scalarField& vector, + const label counter + ); + + //- Return the diagonal of the Hessian. + // Requires the solution of a system of equations twice the size of + // the bases. This should be OK since the latter is small. + // Useful for preconditioning + tmp<scalarField> HessianDiag(); + + + // Similar functions, but using the SR1 formula instead of BFGS. + // Should become a separate class at some point + + //- Compute the Hessian - vector product + // Requires the solution of a system of equations twice the size + // of the bases. This should be OK since the latter is small. + // Input should have the size of all design variables or the + // active ones, output is the size of the active design variables + virtual tmp<scalarField> SR1HessianVectorProduct + ( + const scalarField& vector + ); + + //- Same as previous one, but with an explicit counter provided + tmp<scalarField> SR1HessianVectorProduct + ( + const scalarField& vector, + const label counter + ); + + //- Return the diagonal of the Hessian. + // Requires the solution of a system of equations twice the size + // of the bases. This should be OK since the latter is small. + // Useful for preconditioning + tmp<scalarField> SR1HessianDiag(); public: @@ -131,7 +192,14 @@ public: // Constructors //- Construct from components - LBFGS(const fvMesh& mesh, const dictionary& dict); + LBFGS + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor @@ -140,15 +208,8 @@ public: // Member Functions - //- Compute design variables correction - void computeCorrection(); - - //- Update old correction. Useful for quasi-Newton methods coupled with - //- line search - virtual void updateOldCorrection(const scalarField& oldCorrection); - - //- Write old info to dict - virtual void write(); + //- Write useful quantities to files + virtual bool writeData(Ostream& os) const; }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.C index 7626776fed34873a30faf807ec2e90db5a7c45af..03562ad4a68b148429441d78d43cac634fbb9a05 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.C @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -53,38 +53,12 @@ namespace Foam // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // -void Foam::SQP::allocateMatrices() -{ - // Set active design variables, if necessary - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(objectiveDerivatives_.size()); - } - - // Set previous Hessian to be a diagonal matrix - SquareMatrix<scalar> temp(activeDesignVars_.size(), I); - - // Allocate correct size and content to Hessian matrices - // Has a max. capability of approximately 34000 variables. - HessianOld_ = temp; - Hessian_ = temp; - - // Set size of Lagrange multipliers - lamdas_.setSize(constraintDerivatives_.size()); - lamdas_ = Zero; - - // Set corerction size - correction_.setSize(objectiveDerivatives_.size()); - correction_ = Zero; -} - - void Foam::SQP::updateHessian() { // Vectors needed to construct the (inverse) Hessian matrix scalarField y(activeDesignVars_.size(), Zero); scalarField s(activeDesignVars_.size(), Zero); - scalarField LagrangianDerivativesOld = objectiveDerivativesOld_; + scalarField LagrangianDerivativesOld = derivativesOld_; forAll(constraintDerivatives_, cI) { LagrangianDerivatives_ -= lamdas_[cI] * constraintDerivatives_[cI]; @@ -102,7 +76,7 @@ void Foam::SQP::updateHessian() Info<< "Scaling Hessian with factor " << scaleFactor << endl; forAll(activeDesignVars_, varI) { - HessianOld_[varI][varI] /= scaleFactor; + Hessian_()[varI][varI] /= scaleFactor; } } else @@ -112,7 +86,7 @@ void Foam::SQP::updateHessian() << endl; } } - scalar sBs = globalSum(leftMult(s, HessianOld_)*s); + scalar sBs = globalSum(leftMult(s, Hessian_())*s); // Check curvature condition scalar theta(1); @@ -122,28 +96,28 @@ void Foam::SQP::updateHessian() << " y*s is below threshold. Using damped form" << endl; theta = (1 - dumpingThreshold_)*sBs/(sBs - ys); } - scalarField r(theta*y + (scalar(1) - theta)*rightMult(HessianOld_, s)); + scalarField r(theta*y + (scalar(1) - theta)*rightMult(Hessian_(), s)); DebugInfo << "Unmodified Hessian curvature index " << ys << endl; DebugInfo << "Modified Hessian curvature index " << globalSum(r*s) << endl; // Update the Hessian - Hessian_ = - HessianOld_ - - outerProd(rightMult(HessianOld_, s), leftMult(s/sBs, HessianOld_)) + Hessian_() += + - outerProd(rightMult(Hessian_(), s), leftMult(s/sBs, Hessian_())) + outerProd(r, r/globalSum(s*r)); } -void Foam::SQP::computeLagrangeMultipliersAndCorrect() +void Foam::SQP::update() { - SquareMatrix<scalar> HessianInv = inv(Hessian_); //also denoted below as W + // Also denoted below as W + SquareMatrix<scalar> HessianInv = inv(Hessian_()); if (debug > 1) { - Info<< "Hessian " << Hessian_ << endl; + Info<< "Hessian " << Hessian_() << endl; Info<< "HessianInv " << HessianInv << endl; - label n = Hessian_.n(); + label n = Hessian_().n(); SquareMatrix<scalar> test(n, Zero); for (label k = 0; k < n; k++) { @@ -152,7 +126,7 @@ void Foam::SQP::computeLagrangeMultipliersAndCorrect() scalar elem(Zero); for (label i = 0; i < n; i++) { - elem += Hessian_[k][i] * HessianInv[i][l]; + elem += Hessian_()[k][i] * HessianInv[i][l]; } test[k][l]=elem; } @@ -229,7 +203,7 @@ void Foam::SQP::computeLagrangeMultipliersAndCorrect() void Foam::SQP::storeOldFields() { - objectiveDerivativesOld_ = objectiveDerivatives_; + derivativesOld_ = objectiveDerivatives_; if (constraintDerivativesOld_.empty()) { constraintDerivativesOld_.setSize(constraintDerivatives_.size()); @@ -239,99 +213,38 @@ void Foam::SQP::storeOldFields() constraintDerivativesOld_[cI] = constraintDerivatives_[cI]; } correctionOld_ = correction_; - HessianOld_ = Hessian_; } -void Foam::SQP::readFromDict() +Foam::scalar Foam::SQP::meritFunctionConstraintPart() const { - if (optMethodIODict_.headerOk()) - { - optMethodIODict_.readEntry("Hessian", Hessian_); - optMethodIODict_.readEntry("HessianOld", HessianOld_); - optMethodIODict_.readEntry - ( - "objectiveDerivativesOld", - objectiveDerivativesOld_ - ); - optMethodIODict_.readEntry - ( - "constraintDerivativesOld", - constraintDerivativesOld_ - ); - optMethodIODict_.readEntry("correctionOld", correctionOld_); - optMethodIODict_.readEntry("lamdas", lamdas_); - optMethodIODict_.readEntry("counter", counter_); - optMethodIODict_.readEntry("eta", eta_); - - correction_ = scalarField(correctionOld_.size(), Zero); - - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(correction_.size()); - } - } + // Assumes that all constraints are known by all processors + // What about constraints directly imposed on distributed design variables? + // These should be met in each iteration of the algorithm, so, + // most probably, there is no problem + return sum(mag(cValues_)); } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::SQP::SQP(const fvMesh& mesh, const dictionary& dict) +Foam::SQP::SQP +( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type +) : - constrainedOptimisationMethod(mesh, dict), - - etaHessian_ - ( - coeffsDict().getOrDefault<scalar>("etaHessian", 1) - ), - activeDesignVars_(0), - scaleFirstHessian_ - ( - coeffsDict().getOrDefault<bool>("scaleFirstHessian", false) - ), + quasiNewton(mesh, dict, designVars, nConstraints, type), + SQPBase(mesh, dict, designVars, *this, type), dumpingThreshold_ ( - coeffsDict().getOrDefault<scalar>("dumpingThreshold", 0.2) - ), - LagrangianDerivatives_(0), - Hessian_(), // construct null matrix since we dont know the dimension yet - HessianOld_(), - objectiveDerivativesOld_(0), - constraintDerivativesOld_(0), - correctionOld_(0), - lamdas_(0), - counter_(0), - objFunctionFolder_ - ( - mesh_.time().globalPath()/"optimisation"/"objective"/ - mesh_.time().timeName() - ), - meritFunctionFile_(nullptr), - mu_(Zero), - delta_ - ( - coeffsDict().getOrDefault<scalar>("delta", 0.1) + coeffsDict(type).getOrDefault<scalar>("dumpingThreshold", 0.2) ) { - if - ( - !coeffsDict().readIfPresent("activeDesignVariables", activeDesignVars_) - ) - { - // If not, all available design variables will be used. Number is not - // know at the moment - Info<< "\t Did not find explicit definition of active design " - << "variables. Treating all available ones as active " << endl; - } - - // Create folder to merit function - if (Pstream::master()) - { - mkDir(objFunctionFolder_); - } - - // Read old hessian, correction and derivatives, if present - readFromDict(); + allocateHessian(); } @@ -339,26 +252,11 @@ Foam::SQP::SQP(const fvMesh& mesh, const dictionary& dict) void Foam::SQP::computeCorrection() { - // Allocate correct sizes in first update - if (counter_ == 0) - { - allocateMatrices(); - } - - // The first iteration uses a unitary Hessian. No need to update LagrangianDerivatives_ = objectiveDerivatives_; - if (counter_ != 0) - { - updateHessian(); - } - - // Update lamdas and desing vars - computeLagrangeMultipliersAndCorrect(); + quasiNewton::computeCorrection(); // Store fields for the next iteration and write them to file storeOldFields(); - - counter_++; } @@ -389,83 +287,15 @@ Foam::scalar Foam::SQP::meritFunctionDirectionalDerivative() } -void Foam::SQP::updateOldCorrection(const scalarField& oldCorrection) +bool Foam::SQP::writeData(Ostream& os) const { - updateMethod::updateOldCorrection(oldCorrection); - correctionOld_ = oldCorrection; + return quasiNewton::writeData(os) && SQPBase::addToFile(os); } -void Foam::SQP::write() +bool Foam::SQP::writeAuxiliaryData() { - // Write updateMethod dictionary - optMethodIODict_.add<SquareMatrix<scalar>>("Hessian", Hessian_, true); - optMethodIODict_.add<SquareMatrix<scalar>>("HessianOld", HessianOld_, true); - optMethodIODict_. - add<scalarField> - ( - "objectiveDerivativesOld", objectiveDerivativesOld_, true - ); - optMethodIODict_. - add<List<scalarField>> - ( - "constraintDerivativesOld", constraintDerivativesOld_, true - ); - optMethodIODict_.add<scalarField>("correctionOld", correctionOld_, true); - optMethodIODict_.add<scalarField>("lamdas", lamdas_, true); - optMethodIODict_.add<label>("counter", counter_, true); - - updateMethod::write(); - - // Write merit function - scalar constraintPart = sum(mag(cValues_)); - scalar merit = objectiveValue_ + mu_*constraintPart; - if (Pstream::master()) - { - unsigned int width = IOstream::defaultPrecision() + 6; - unsigned int constraintsSize = lamdas_.size(); - constraintsSize = constraintsSize*(width + 1) + 2; - - // Open file and write header - if (!meritFunctionFile_) - { - meritFunctionFile_.reset - ( - new OFstream(objFunctionFolder_/word("meritFunction")) - ); - - meritFunctionFile_() - << setw(1) << "#" << " " - << setw(width) << "merit" << " " - << setw(width) << "J" << " " - << setw(constraintsSize) << "lamdas" << " " - << setw(constraintsSize) << "constraints" << " " - << setw(width) << "mu" << " " - << setw(width) << "constraintContr" << endl; - - } - - meritFunctionFile_() - << setw(1) << mesh_.time().value() -1 << " " - << setw(width) << merit << " " - << setw(width) << objectiveValue_ << " " - << setw(1) << "("; - - forAll(lamdas_, cI) - { - meritFunctionFile_() - << setw(width) << lamdas_[cI] << setw(1) << " "; - } - meritFunctionFile_() << setw(3) << ")("; - forAll(cValues_, cI) - { - meritFunctionFile_() - << setw(width) << cValues_[cI] << setw(1) << " "; - } - meritFunctionFile_() << setw(2) << ") "; - meritFunctionFile_() << setw(width) << mu_ << " "; - meritFunctionFile_() << setw(width) << constraintPart << endl; - } + return SQPBase::writeMeritFunction(*this); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.H index 191770765c0791bdbdf7f38897972a2f29c2d3d7..bc491a6bb50149078282dbb98be35712063590aa 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQP/SQP.H @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -40,8 +40,8 @@ SourceFiles #ifndef SQP_H #define SQP_H -#include "constrainedOptimisationMethod.H" -#include "OFstream.H" +#include "quasiNewton.H" +#include "SQPBase.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -54,61 +54,16 @@ namespace Foam class SQP : - public constrainedOptimisationMethod + public quasiNewton, + public SQPBase { protected: // Protected data - //- Step for the Newton method - scalar etaHessian_; - - //- Map to active design variables - labelList activeDesignVars_; - - //- Scale the initial unitary Hessian approximation - bool scaleFirstHessian_; - //- Curvature threshold scalar dumpingThreshold_; - //- Derivatives of the Lagrangian function - scalarField LagrangianDerivatives_; - - //- The Hessian inverse. Should have the size of the active design - //- variables - SquareMatrix<scalar> Hessian_; - - //- The previous Hessian inverse - SquareMatrix<scalar> HessianOld_; - - //- The previous objective derivatives - scalarField objectiveDerivativesOld_; - - //- The previous constraint derivatives - List<scalarField> constraintDerivativesOld_; - - //- The previous correction - scalarField correctionOld_; - - //- Lagrange multipliers - scalarField lamdas_; - - //- Optimisation cycle count - label counter_; - - //- Name of the objective folder - fileName objFunctionFolder_; - - //- File including the l1 merit function - autoPtr<OFstream> meritFunctionFile_; - - //- Penalty value for the merit function - scalar mu_; - - //- Safety factor - scalar delta_; - private: @@ -120,24 +75,17 @@ private: //- No copy assignment void operator=(const SQP&) = delete; - //- Make folder holding the Lagrangian file - void makeFolder(); - - //- Allocate fields and matrices when size of design variables - //- is known - void allocateMatrices(); - //- Update the Hessian matrix - void updateHessian(); + virtual void updateHessian(); //- Compute new lamdas and update correction - void computeLagrangeMultipliersAndCorrect(); + virtual void update(); //- Store old fields needed for the next iter void storeOldFields(); - //- Read old values from dict, if present - void readFromDict(); + //- Get the part the merit function that depends on the constraints + virtual scalar meritFunctionConstraintPart() const; public: @@ -149,7 +97,14 @@ public: // Constructors //- Construct from components - SQP(const fvMesh& mesh, const dictionary& dict); + SQP + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor @@ -158,23 +113,22 @@ public: // Member Functions - //- Compute design variables correction - void computeCorrection(); + //- Compute design variables correction + void computeCorrection(); - //- Compute merit function. Could be different than the objective - //- in the presence of constraints - virtual scalar computeMeritFunction(); + //- Compute merit function. Could be different than the objective + //- in the presence of constraints + virtual scalar computeMeritFunction(); - //- Derivative of the merit function. Could be different than the - //- objective derivative in the presence of constraints - virtual scalar meritFunctionDirectionalDerivative(); + //- Derivative of the merit function. Could be different than the + //- objective derivative in the presence of constraints + virtual scalar meritFunctionDirectionalDerivative(); - //- Update old correction. Useful for quasi-Newton methods coupled with - //- line search - virtual void updateOldCorrection(const scalarField& oldCorrection); + //- Write useful quantities to files + virtual bool writeData(Ostream& os) const; - //- Write useful quantities to files - virtual void write(); + //- Write merit function information + virtual bool writeAuxiliaryData(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQPBase/SQPBase.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQPBase/SQPBase.C new file mode 100644 index 0000000000000000000000000000000000000000..fdd380f9f5857892533248c1a2e6e82b4c1cccac --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQPBase/SQPBase.C @@ -0,0 +1,178 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 +------------------------------------------------------------------------------- +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 "SQPBase.H" +#include "IOmanip.H" +#include "updateMethod.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(SQPBase, 1); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::SQPBase::SQPBase +( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const updateMethod& UpdateMethod, + const word& type +) +: + constrainedOptimisationMethod + ( + mesh, + dict, + designVars, + UpdateMethod.nConstraints(), + type + ), + LagrangianDerivatives_(designVars().getVars().size(), Zero), + constraintDerivativesOld_ + ( + UpdateMethod.nConstraints(), + scalarField(LagrangianDerivatives_.size(), Zero) + ), + lamdas_ + ( + UpdateMethod.found("lamdas") ? + scalarField("lamdas", UpdateMethod, UpdateMethod.nConstraints()) : + scalarField(UpdateMethod.nConstraints(), Zero) + ), + objFunctionFolder_ + ( + mesh.time().globalPath()/"optimisation"/"objective"/ + mesh.time().timeName() + ), + meritFunctionFile_(nullptr), + mu_(Zero), + delta_ + ( + UpdateMethod.coeffsDict(type).getOrDefault<scalar>("delta", 0.1) + ) +{ + // Read in old constraint derivatives if present + forAll(lamdas_, cI) + { + if (UpdateMethod.found("constraintDerivativesOld" + Foam::name(cI))) + { + constraintDerivativesOld_[cI] = + scalarField + ( + "constraintDerivativesOld" + Foam::name(cI), + UpdateMethod, + LagrangianDerivatives_.size() + ); + } + } + // Create folder to merit function + if (Pstream::master()) + { + mkDir(objFunctionFolder_); + } +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::SQPBase::addToFile(Ostream& os) const +{ + forAll(constraintDerivativesOld_, cI) + { + constraintDerivativesOld_[cI]. + writeEntry("constraintDerivativesOld" + Foam::name(cI), os); + } + lamdas_.writeEntry("lamdas", os); + + return true; +} + + +bool Foam::SQPBase::writeMeritFunction(const updateMethod& UpdateMethod) +{ + scalar objectivePart = UpdateMethod.getObjectiveValue(); + scalar constraintPart = mu_*meritFunctionConstraintPart(); + scalar merit = objectivePart + constraintPart; + const scalarField& cValues = UpdateMethod.getConstraintValues(); + if (Pstream::master()) + { + unsigned int width = IOstream::defaultPrecision() + 6; + unsigned int constraintsSize = lamdas_.size(); + constraintsSize = constraintsSize*(width + 1) + 2; + + // Open file and write header + if (!meritFunctionFile_) + { + meritFunctionFile_.reset + ( + new OFstream(objFunctionFolder_/word("meritFunction")) + ); + + meritFunctionFile_() + << setw(1) << "#" << " " + << setw(width) << "merit" << " " + << setw(width) << "J" << " " + << setw(constraintsSize) << "lamdas" << " " + << setw(constraintsSize) << "constraints" << " " + << setw(width) << "mu" << " " + << setw(width) << "constraintContr" << endl; + + } + + meritFunctionFile_() + << setw(1) << UpdateMethod.getCycle() << " " + << setw(width) << merit << " " + << setw(width) << objectivePart << " " + << setw(1) << "("; + + forAll(lamdas_, cI) + { + meritFunctionFile_() + << setw(width) << lamdas_[cI] << setw(1) << " "; + } + meritFunctionFile_() << setw(3) << ")("; + forAll(cValues, cI) + { + meritFunctionFile_() + << setw(width) << cValues[cI] << setw(1) << " "; + } + meritFunctionFile_() << setw(2) << ") "; + meritFunctionFile_() << setw(width) << mu_ << " "; + meritFunctionFile_() << setw(width) << constraintPart << endl; + } + return true; +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/FIBase/FIBaseIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQPBase/SQPBase.H similarity index 56% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/FIBase/FIBaseIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQPBase/SQPBase.H index a2e69d75b1732a64f5e120b2de260b755c6629c5..73595d3bcb52e298005dd35328693ad483eaf712 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/FIBase/FIBaseIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SQPBase/SQPBase.H @@ -5,9 +5,8 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2007-2020 PCOpt/NTUA - Copyright (C) 2013-2020 FOSS GP - Copyright (C) 2019 OpenCFD Ltd. + Copyright (C) 2007-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -25,64 +24,68 @@ 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::FIBase + Foam::SQPBase Description - Base class for Field Integral-based sensitivity derivatives + Base class for Sequantial Quadratic Programming (SQP) methods SourceFiles - FIBase.C + SQPBase.C \*---------------------------------------------------------------------------*/ -#ifndef FIBaseIncompressible_H -#define FIBaseIncompressible_H +#ifndef SQPBase_H +#define SQPBase_H -#include "adjointSensitivityIncompressible.H" -#include "shapeSensitivitiesIncompressible.H" -#include "adjointEikonalSolverIncompressible.H" +#include "constrainedOptimisationMethod.H" +#include "quasiNewton.H" +#include "OFstream.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -namespace incompressible -{ - /*---------------------------------------------------------------------------*\ - Class FIBase Declaration + Class SQPBase Declaration \*---------------------------------------------------------------------------*/ -class FIBase +class SQPBase : - public shapeSensitivities + public constrainedOptimisationMethod { protected: // Protected data - //- grad(dx/db) multiplier - volTensorField gradDxDbMult_; + //- Derivatives of the Lagrangian function + scalarField LagrangianDerivatives_; + + //- The previous constraint derivatives + List<scalarField> constraintDerivativesOld_; - //- div(dx/db) multiplier - scalarField divDxDbMult_; + //- Lagrange multipliers + scalarField lamdas_; - //- dx/db multiplier coming from fvOptions - vectorField optionsDxDbMult_; + //- Name of the objective folder + fileName objFunctionFolder_; - //- Include distance variation in sens computation - bool includeDistance_; + //- File including the l1 merit function + autoPtr<OFstream> meritFunctionFile_; - //- Adjoint eikonal equation solver - autoPtr<adjointEikonalSolver> eikonalSolver_; + //- Penalty value for the merit function + scalar mu_; + + //- Safety factor + scalar delta_; // Protected Member Functions - //- Read options and update solver pointers if necessary - void read(); + //- Get the part the merit function that depends on the constraints + virtual scalar meritFunctionConstraintPart() const = 0; private: @@ -90,52 +93,50 @@ private: // Private Member Functions //- No copy construct - FIBase(const FIBase&) = delete; + SQPBase(const SQPBase&) = delete; //- No copy assignment - void operator=(const FIBase&) = delete; + void operator=(const SQPBase&) = delete; + + //- Make folder holding the Lagrangian file + void makeFolder(); public: //- Runtime type information - TypeName("volumetricBSplinesFI"); + TypeName("SQPBase"); // Constructors //- Construct from components - FIBase + SQPBase ( const fvMesh& mesh, const dictionary& dict, - incompressibleAdjointSolver& adjointSolver + autoPtr<designVariables>& designVars, + const updateMethod& UpdateMethod, + const word& type ); //- Destructor - virtual ~FIBase() = default; + virtual ~SQPBase() = default; // Member Functions - //- Read dict if changed - virtual bool readDict(const dictionary& dict); - - //- Accumulate sensitivity integrands - virtual void accumulateIntegrand(const scalar dt); - - //- Assemble sensitivities - virtual void assembleSensitivities() = 0; + //- Write continuation info + virtual bool addToFile(Ostream& os) const; - //- Zero sensitivity fields and their constituents - virtual void clearSensitivities(); + //- Write info about the merit function + virtual bool writeMeritFunction(const updateMethod& UpdateMethod); }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace incompressible } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.C index 6cba4953fe3dd102181eaccde7e8ed3a8a785ebd..74bec23639267c7b4f2c880099d8e062fccbc469 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.C @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -46,28 +46,6 @@ namespace Foam // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -void Foam::SR1::allocateMatrices() -{ - // Set active design variables, if necessary - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(objectiveDerivatives_.size()); - } - - // Set previous HessianInv to be a diagonal matrix - SquareMatrix<scalar> temp(activeDesignVars_.size(), Zero); - forAll(activeDesignVars_, i) - { - temp[i][i] = scalar(1); - } - - // Allocate correct size and content to HessianInv matrices - // has a max. capability of approximately 34000 variables. - HessianInvOld_ = temp; - HessianInv_ = temp; -} - - void Foam::SR1::updateHessian() { // Vectors needed to construct the inverse HessianInv matrix @@ -76,25 +54,22 @@ void Foam::SR1::updateHessian() y.map(objectiveDerivatives_ - derivativesOld_, activeDesignVars_); s.map(correctionOld_, activeDesignVars_); - scalarField temp(s - rightMult(HessianInvOld_, y)); + scalarField temp(s - rightMult(Hessian_(), y)); // Construct the inverse HessianInv scalar tempMag = sqrt(globalSum(sqr(temp))); scalar yMag = sqrt(globalSum(sqr(y))); - scalar HessYMag = sqrt(globalSum(sqr(rightMult(HessianInvOld_, y)))); + scalar HessYMag = sqrt(globalSum(sqr(rightMult(Hessian_(), y)))); // Stability check if (tempMag > ratioThreshold_ * yMag * HessYMag) { - HessianInv_ = - HessianInvOld_ - + (scalar(1)/(globalSum(temp*y)))*outerProd(temp, temp); + Hessian_() += (scalar(1)/(globalSum(temp*y)))*outerProd(temp, temp); } else { WarningInFunction << "Denominator of update too small. Keeping old Hessian" << endl; - HessianInv_ = HessianInvOld_; } } @@ -105,8 +80,11 @@ void Foam::SR1::update() // matrix if (counter_ < nSteepestDescent_) { - Info<< "Using steepest descent to update design variables ... " << endl; - correction_ = -eta_*objectiveDerivatives_; + Info<< "Using steepest descent to update design variables" << endl; + for (const label varI : activeDesignVars_) + { + correction_[varI] = -eta_*objectiveDerivatives_[varI]; + } } else { @@ -114,7 +92,7 @@ void Foam::SR1::update() activeDerivs.map(objectiveDerivatives_, activeDesignVars_); scalarField activeCorrection ( - -etaHessian_*rightMult(HessianInv_, activeDerivs) + -etaHessian_*rightMult(Hessian_(), activeDerivs) ); // Transfer correction to the global list @@ -128,112 +106,27 @@ void Foam::SR1::update() // Store fields for the next iteration derivativesOld_ = objectiveDerivatives_; correctionOld_ = correction_; - HessianInvOld_ = HessianInv_; -} - - -void Foam::SR1::readFromDict() -{ - if (optMethodIODict_.headerOk()) - { - optMethodIODict_.readEntry("HessianInvOld", HessianInvOld_); - optMethodIODict_.readEntry("derivativesOld", derivativesOld_); - optMethodIODict_.readEntry("correctionOld", correctionOld_); - optMethodIODict_.readEntry("counter", counter_); - optMethodIODict_.readEntry("eta", eta_); - - const label n(HessianInvOld_.n()); - HessianInv_ = SquareMatrix<scalar>(n, Zero); - correction_ = scalarField(correctionOld_.size(), Zero); - - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(n); - } - } } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::SR1::SR1(const fvMesh& mesh, const dictionary& dict) +Foam::SR1::SR1 +( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type +) : - updateMethod(mesh, dict), - - // Construct null matrix since we dont know the dimension yet - etaHessian_ - ( - coeffsDict().getOrDefault<scalar>("etaHessian", 1) - ), - nSteepestDescent_ - ( - coeffsDict().getOrDefault<label>("nSteepestDescent", 1) - ), + quasiNewton(mesh, dict, designVars, nConstraints, type), ratioThreshold_ ( - coeffsDict().getOrDefault<scalar>("ratioThreshold", 1e-08) - ), - activeDesignVars_(0), - HessianInv_(), - HessianInvOld_(), - derivativesOld_(0), - correctionOld_(0), - counter_(0) -{ - if - ( - !coeffsDict().readIfPresent("activeDesignVariables", activeDesignVars_) + coeffsDict(type).getOrDefault<scalar>("ratioThreshold", 1e-08) ) - { - // If not, all available design variables will be used. Number is not - // know at the moment - Info<< "\t Didn't find explicit definition of active design variables. " - << "Treating all available ones as active " << endl; - } - - // Read old hessian, correction and derivatives, if present - readFromDict(); -} - - -// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // - -void Foam::SR1::computeCorrection() { - if (counter_ == 0) - { - allocateMatrices(); - } - else - { - updateHessian(); - } - - update(); - ++counter_; -} - - -void Foam::SR1::updateOldCorrection(const scalarField& oldCorrection) -{ - updateMethod::updateOldCorrection(oldCorrection); - correctionOld_ = oldCorrection; -} - - -void Foam::SR1::write() -{ - optMethodIODict_.add<SquareMatrix<scalar>> - ( - "HessianInvOld", - HessianInvOld_, - true - ); - optMethodIODict_.add<scalarField>("derivativesOld", derivativesOld_, true); - optMethodIODict_.add<scalarField>("correctionOld", correctionOld_, true); - optMethodIODict_.add<label>("counter", counter_, true); - - updateMethod::write(); + allocateHessian(); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.H index fa8fa1d5f05edf8a0ec578f241f1231f5901b5a8..c350798a3e36de7006d37e4a2ee8e56819a706cc 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/SR1/SR1.H @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -30,7 +30,8 @@ Class Foam::SR1 Description - The quasi-Newton Symmetric Rank One formula + The quasi-Newton Symmetric Rank One formula. + The quasiNewton::Hessian corresponds to Hessian inverse for SR1 SourceFiles SR1.C @@ -40,8 +41,7 @@ SourceFiles #ifndef SR1_H #define SR1_H -#include "updateMethod.H" -#include "scalarMatrices.H" +#include "quasiNewton.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -54,54 +54,23 @@ namespace Foam class SR1 : - public updateMethod + public quasiNewton { protected: // Protected data - //- Step for the Newton method - scalar etaHessian_; - - //- Number of first steepest descent steps - label nSteepestDescent_; - //- For stability check scalar ratioThreshold_; - //- Map to active design variables - labelList activeDesignVars_; - - //- The Hessian inverse. Should have the size of the active design - //- variables - SquareMatrix<scalar> HessianInv_; - - //- The previous Hessian inverse - SquareMatrix<scalar> HessianInvOld_; - - //- The previous derivatives - scalarField derivativesOld_; - - //- The previous correction - scalarField correctionOld_; - - //- Optimisation counter - label counter_; - - // Protected functions - - //- Allocate matrices in the first optimisation cycle - void allocateMatrices(); + // Protected Member Functions //- Update approximation of the inverse Hessian - void updateHessian(); + virtual void updateHessian(); //- Update design variables - void update(); - - //- Read old info from dict - void readFromDict(); + virtual void update(); private: @@ -124,24 +93,18 @@ public: // Constructors //- Construct from components - SR1(const fvMesh& mesh, const dictionary& dict); + SR1 + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor virtual ~SR1() = default; - - - // Member Functions - - //- Compute design variables correction - void computeCorrection(); - - //- Update old correction. Useful for quasi-Newton methods coupled with - //- line search - virtual void updateOldCorrection(const scalarField& oldCorrection); - - //- Write old info to dict - virtual void write(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.C index bba5598e5cc5a08061324792dcda01f38bb8b412..fc0e9a9e467177881e2d2a8e28ef17bc497565aa 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.C @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -44,72 +44,23 @@ namespace Foam } -// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // - -void Foam::conjugateGradient::allocateFields() -{ - // Set active design variables, if necessary - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(objectiveDerivatives_.size()); - } - - // Allocate old fields - dxOld_ = scalarField(activeDesignVars_.size(), Zero); - sOld_ = scalarField(activeDesignVars_.size(), Zero); -} - - -void Foam::conjugateGradient::readFromDict() -{ - if (optMethodIODict_.headerOk()) - { - optMethodIODict_.readEntry("dxOld", dxOld_); - optMethodIODict_.readEntry("sOld", sOld_); - optMethodIODict_.readEntry("counter", counter_); - optMethodIODict_.readEntry("eta", eta_); - - label nDVs = optMethodIODict_.get<label>("nDVs"); - correction_ = scalarField(nDVs, Zero); - - if (activeDesignVars_.empty()) - { - activeDesignVars_ = identity(nDVs); - } - } -} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::conjugateGradient::conjugateGradient ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ) : - updateMethod(mesh, dict), + updateMethod(mesh, dict, designVars, nConstraints, type), - activeDesignVars_(0), - dxOld_(0), - sOld_(0), - counter_(0), - betaType_ - ( - coeffsDict().getOrDefault<word>("betaType", "FletcherReeves") - ) + dxOld_(readOrZeroField("dxOld", activeDesignVars_.size())), + sOld_(readOrZeroField("sOld", activeDesignVars_.size())), + betaType_(coeffsDict(type).getOrDefault<word>("betaType", "FletcherReeves")) { - if - ( - !coeffsDict().readIfPresent("activeDesignVariables", activeDesignVars_) - ) - { - // If not, all available design variables will be used. - // Number is not know at the moment - Info<< "\t Did not find explicit definition of active design variables. " - << "Treating all available ones as active " << endl; - } - // Check if beta type is valid if ( @@ -124,9 +75,6 @@ Foam::conjugateGradient::conjugateGradient << nl << nl << exit(FatalError); } - - // Read old dx and s, if present - readFromDict(); } @@ -136,17 +84,18 @@ void Foam::conjugateGradient::computeCorrection() { if (counter_ == 0) { - allocateFields(); - Info<< "Using steepest descent for the first iteration" << endl; - correction_ = -eta_*objectiveDerivatives_; + for (const label varI : activeDesignVars_) + { + correction_[varI] = -eta_*objectiveDerivatives_[varI]; + } dxOld_.map(-objectiveDerivatives_, activeDesignVars_); sOld_ = dxOld_; } else { - scalarField dx = scalarField(activeDesignVars_.size(), Zero); + scalarField dx(activeDesignVars_.size(), Zero); dx.map(-objectiveDerivatives_, activeDesignVars_); scalar beta(Zero); @@ -200,14 +149,12 @@ void Foam::conjugateGradient::updateOldCorrection } -void Foam::conjugateGradient::write() +bool Foam::conjugateGradient::writeData(Ostream& os) const { - optMethodIODict_.add<scalarField>("dxOld", dxOld_, true); - optMethodIODict_.add<scalarField>("sOld", sOld_, true); - optMethodIODict_.add<label>("counter", counter_, true); - optMethodIODict_.add<label>("nDVs", objectiveDerivatives_.size(), true); + dxOld_.writeEntry("dxOld", os); + sOld_.writeEntry("sOld", os); - updateMethod::write(); + return updateMethod::writeData(os); } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.H index 5c42ecdcfd53b0df62e0ff3fcffb623dc2bc5c49..5954ea74fd0d0715b869b1f5a7dc6fad8fa5a346 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/conjugateGradient/conjugateGradient.H @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -63,22 +63,11 @@ protected: // Protected data - labelList activeDesignVars_; scalarField dxOld_; scalarField sOld_; - label counter_; word betaType_; - // Protected Member Functions - - //- Allocate matrices in the first optimisation cycle - void allocateFields(); - - //- Read old info from dict - void readFromDict(); - - private: // Private Member Functions @@ -99,7 +88,14 @@ public: // Constructors //- Construct from components - conjugateGradient(const fvMesh& mesh, const dictionary& dict); + conjugateGradient + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor @@ -108,14 +104,14 @@ public: // Member Functions - //- Compute design variables correction - void computeCorrection(); + //- Compute design variables correction + void computeCorrection(); - //- Update old correction. For use when eta has been changed externally - virtual void updateOldCorrection(const scalarField& oldCorrection); + //- Update old correction. For use when eta has been changed externally + virtual void updateOldCorrection(const scalarField& oldCorrection); - //- Write old info to dict - virtual void write(); + //- Write useful quantities to files + virtual bool writeData(Ostream& os) const; }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C index b8c058644f86584fa95d5c193b22efc2237c371a..9e75e19eab16c5dd6f468b97ac9aa05c479fe4e9 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.C @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -43,10 +43,11 @@ namespace Foam Foam::constrainedOptimisationMethod::constrainedOptimisationMethod ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ) -: - updateMethod(mesh, dict) {} diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.H index 278f44d77def9dd2a3ac73f47f9b3115226b4772..de4059fc2264694f77c5d84ee1341ee8deb6b5e5 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constrainedOptimisationMethod/constrainedOptimisationMethod.H @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -42,7 +42,10 @@ SourceFiles #ifndef constrainedOptimisationMethod_H #define constrainedOptimisationMethod_H -#include "updateMethod.H" +#include "runTimeSelectionTables.H" +#include "fvMesh.H" +#include "dictionary.H" +#include "designVariables.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -54,8 +57,6 @@ namespace Foam \*---------------------------------------------------------------------------*/ class constrainedOptimisationMethod -: - public updateMethod { private: @@ -87,9 +88,12 @@ public: dictionary, ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ), - (mesh, dict) + (mesh, dict, designVars, nConstraints, type) ); @@ -99,18 +103,15 @@ public: constrainedOptimisationMethod ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ); //- Destructor virtual ~constrainedOptimisationMethod() = default; - - - // Member Functions - - //- Return the correction of the design variables - virtual void computeCorrection()=0; }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.C index 25cb7f27c7fbc04b35400966b7318a1a3546ffb3..16de65310364e4d9095be718b625d03a133654f9 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.C @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -55,14 +55,16 @@ namespace Foam Foam::constraintProjection::constraintProjection ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ) : - constrainedOptimisationMethod(mesh, dict), - useCorrection_ - ( - coeffsDict().getOrDefault<bool>("useCorrection", true) - ) + constrainedOptimisationMethod(mesh, dict, designVars, nConstraints, type), + updateMethod(mesh, dict, designVars, nConstraints, type), + useCorrection_(coeffsDict(type).getOrDefault<bool>("useCorrection", true)), + delta_(coeffsDict(type).getOrDefault<scalar>("delta", 0.1)) {} @@ -73,7 +75,6 @@ void Foam::constraintProjection::computeCorrection() // Reset to zero const label n = objectiveDerivatives_.size(); const label m = constraintDerivatives_.size(); - correction_ = scalarField(n, Zero); // Matrix with constraint derivatives and its inverse scalarSquareMatrix MMT(m, Zero); @@ -114,13 +115,24 @@ void Foam::constraintProjection::computeCorrection() } // Final correction - correction_ = objectiveDerivatives_ - constraintContribution; - correction_ *= -eta_; + scalarField correction(objectiveDerivatives_ - constraintContribution); + correction *= -eta_; if (useCorrection_) { - correction_ -= nonLinearContribution; + correction -= nonLinearContribution; + } + + for (const label varI : activeDesignVars_) + { + correction_[varI] = correction[varI]; } } +Foam::scalar Foam::constraintProjection::computeMeritFunction() +{ + return objectiveValue_ + delta_*sum(mag(cValues_)); +} + + // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.H index 0bea873fb951355c2329148c816ca61686c2ad23..b054665698dfc588d4698fd481192521b5f5cb4b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/constraintProjection/constraintProjection.H @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -44,6 +44,7 @@ SourceFiles #define constraintProjection_H #include "constrainedOptimisationMethod.H" +#include "updateMethod.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -56,7 +57,8 @@ namespace Foam class constraintProjection : - public constrainedOptimisationMethod + public constrainedOptimisationMethod, + public updateMethod { protected: @@ -65,6 +67,9 @@ protected: //- Correct for non-linearities bool useCorrection_; + //- Weight of the aggregated constraint values in the merit function + scalar delta_; + private: @@ -86,7 +91,14 @@ public: // Constructors //- Construct from components - constraintProjection(const fvMesh& mesh, const dictionary& dict); + constraintProjection + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor @@ -95,8 +107,12 @@ public: // Member Functions - //- Compute design variables correction - void computeCorrection(); + //- Compute design variables correction + void computeCorrection(); + + //- Compute merit function. Could be different than the objective + //- in the presence of constraints + virtual scalar computeMeritFunction(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/quasiNewton/quasiNewton.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/quasiNewton/quasiNewton.C new file mode 100644 index 0000000000000000000000000000000000000000..a6c356367540e76cd673c1667397f9fec80811b5 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/quasiNewton/quasiNewton.C @@ -0,0 +1,129 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "quasiNewton.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(quasiNewton, 0); +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::quasiNewton::allocateHessian() +{ + Hessian_.reset(new SquareMatrix<scalar>(activeDesignVars_.size(), I)); + // Read in Hessian Matrix or initialiase + const label nDVs(designVars_().activeDesignVariables().size()); + forAll(designVars_().activeDesignVariables(), iDV) + { + if (found("Hessian" + Foam::name(iDV))) + { + Hessian_().subColumn(iDV) = + scalarField("Hessian" + Foam::name(iDV), *this, nDVs); + } + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::quasiNewton::quasiNewton +( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type +) +: + updateMethod(mesh, dict, designVars, nConstraints, type), + etaHessian_(coeffsDict(type).getOrDefault<scalar>("etaHessian", 1)), + nSteepestDescent_ + ( + coeffsDict(type).getOrDefault<label>("nSteepestDescent", 1) + ), + scaleFirstHessian_ + ( + coeffsDict(type).getOrDefault<bool>("scaleFirstHessian", false) + ), + Hessian_(nullptr), + derivativesOld_ + ( + readOrZeroField("derivativesOld", objectiveDerivatives_.size()) + ), + correctionOld_(readOrZeroField("correctionOld", correction_.size())) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::quasiNewton::computeCorrection() +{ + // The first iteration uses a unitary Hessian. No need to update + if (counter_ != 0) + { + updateHessian(); + } + + update(); + ++counter_; +} + + +void Foam::quasiNewton::updateOldCorrection(const scalarField& oldCorrection) +{ + updateMethod::updateOldCorrection(oldCorrection); + correctionOld_ = oldCorrection; +} + + +bool Foam::quasiNewton::writeData(Ostream& os) const +{ + if (Hessian_) + { + // Matrices cannot be written/read in binary. + // Circumvent this by writing separate columns as scalarFields + forAll(designVars_().activeDesignVariables(), iDV) + { + Hessian_().subColumn(iDV).operator Field<scalar>(). + writeEntry("Hessian" + Foam::name(iDV), os); + } + } + derivativesOld_.writeEntry("derivativesOld", os); + correctionOld_.writeEntry("correctionOld", os); + + return updateMethod::writeData(os); +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/SIBase/SIBaseIncompressible.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/quasiNewton/quasiNewton.H similarity index 54% rename from src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/SIBase/SIBaseIncompressible.H rename to src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/quasiNewton/quasiNewton.H index 0420c38383fc2d44ab3e1cff7142a17996d2e292..6d2358690b12ea743d2f18815fd709cb2b905090 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/adjointSensitivity/incompressible/SIBase/SIBaseIncompressible.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/quasiNewton/quasiNewton.H @@ -5,9 +5,8 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2007-2020 PCOpt/NTUA - Copyright (C) 2013-2020 FOSS GP - 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,59 +26,70 @@ License Class - Foam::incompressible::SIBase + Foam::quasiNewton Description - Base class for Surface Integral-based sensitivity derivatives + Base class for quasi-Newton methods SourceFiles - SIBase.C + quasiNewton.C \*---------------------------------------------------------------------------*/ -#ifndef SIBaseIncompressible_H -#define SIBaseIncompressible_H +#ifndef quasiNewton_H +#define quasiNewton_H -#include "shapeSensitivitiesIncompressible.H" -#include "sensitivitySurfaceIncompressible.H" +#include "updateMethod.H" +#include "scalarMatrices.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { -namespace incompressible -{ - /*---------------------------------------------------------------------------*\ - Class SIBase Declaration + Class quasiNewton Declaration \*---------------------------------------------------------------------------*/ -class SIBase +class quasiNewton : - public shapeSensitivities + public updateMethod { protected: // Protected data - //- Surface sensitivities - sensitivitySurface surfaceSensitivity_; + //- Step for the Newton method + scalar etaHessian_; + + //- Number of first steepest descent steps + label nSteepestDescent_; + + //- Scale the initial unitary Hessian approximation + bool scaleFirstHessian_; + + //- The Hessian or its inverse, depending on the deriving class. + // Has the size of the active design variables. + // autoPtr to avoid allocation by limited memory variants + autoPtr<SquareMatrix<scalar>> Hessian_; - //- Whether to include direct sensitivities or not. - // Used to avoid double contributions from both here and the - // sensitivitySurface object which might have already accounted for - // them - bool includeObjective_; + //- The previous derivatives + scalarField derivativesOld_; - //- Write sensitivity map upon write - bool writeSensitivityMap_; + //- The previous correction + scalarField correctionOld_; // Protected Member Functions - //- Read options from dict - void read(); + //- Update approximation of the inverse Hessian + virtual void updateHessian() = 0; + + //- Update design variables + virtual void update() = 0; + + //- Allocate the Hessian matrix + void allocateHessian(); private: @@ -87,58 +97,51 @@ private: // Private Member Functions //- No copy construct - SIBase(const SIBase&) = delete; + quasiNewton(const quasiNewton&) = delete; //- No copy assignment - void operator=(const SIBase&) = delete; + void operator=(const quasiNewton&) = delete; public: //- Runtime type information - TypeName("volumetricBSplinesFI"); + TypeName("quasiNewton"); // Constructors //- Construct from components - SIBase + quasiNewton ( const fvMesh& mesh, const dictionary& dict, - incompressibleAdjointSolver& adjointSolver + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ); //- Destructor - virtual ~SIBase() = default; + virtual ~quasiNewton() = default; // Member Functions - //- Read dict if changed - virtual bool readDict(const dictionary& dict); - - //- Accumulate sensitivity integrands - virtual void accumulateIntegrand(const scalar dt); - - //- Assemble sensitivities - virtual void assembleSensitivities() = 0; - - //- Zero sensitivity fields and their constituents - virtual void clearSensitivities(); + //- Compute design variables correction + void computeCorrection(); - //- Return reference to underlaying surface sensitivities - const sensitivitySurface& getSurfaceSensitivities() const; + //- Update old correction. Useful for quasi-Newton methods coupled with + //- line search + virtual void updateOldCorrection(const scalarField& oldCorrection); - //- Write sensitivity map - virtual void write(const word& baseName = word::null); + //- Write useful quantities to files + virtual bool writeData(Ostream& os) const; }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace incompressible } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.C index 9251b948aa9b9e10511aadba65cfa572c54b738a..89964254984d33653694e99b7f30c7e078976b93 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.C @@ -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-2021 PCOpt/NTUA + Copyright (C) 2013-2021 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -49,10 +49,13 @@ namespace Foam Foam::steepestDescent::steepestDescent ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ) : - updateMethod(mesh, dict) + updateMethod(mesh, dict, designVars, nConstraints, type) {} @@ -60,7 +63,10 @@ Foam::steepestDescent::steepestDescent void Foam::steepestDescent::computeCorrection() { - correction_ = -eta_*objectiveDerivatives_; + for (const label varI : activeDesignVars_) + { + correction_[varI] = -eta_*objectiveDerivatives_[varI]; + } } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.H index 46599167954ae3ff24c21d0427ccb59491700c21..f8dc2e4b9c487ac2ebef051f681cffd5f0145a9d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/steepestDescent/steepestDescent.H @@ -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 @@ -74,7 +74,14 @@ public: // Constructors //- Construct from components - steepestDescent(const fvMesh& mesh, const dictionary& dict); + steepestDescent + ( + const fvMesh& mesh, + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type + ); //- Destructor diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.C b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.C index fd550bbab356723005083f818cca00bb0378d902..84a7ad4f7fe6a868db812d48c5e7903606370a04 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.C +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.C @@ -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-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -195,48 +195,63 @@ Foam::scalar Foam::updateMethod::globalSum(tmp<scalarField>& tfield) } +Foam::label Foam::updateMethod::globalSum(const label size) +{ + label res(0); + if (globalSum_) + { + res = returnReduce(size, sumOp<label>()); + } + else + { + res = size; + } + return res; +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::updateMethod::updateMethod ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ) : - mesh_(mesh), - dict_(dict), - optMethodIODict_ + localIOdictionary ( IOobject ( "updateMethodDict", - mesh_.time().timeName(), + mesh.time().timeName(), "uniform", - mesh_, + mesh, IOobject::READ_IF_PRESENT, - IOobject::NO_WRITE - ) + IOobject::AUTO_WRITE + ), + word::null // avoid type checking ), - objectiveDerivatives_(0), + mesh_(mesh), + dict_(dict), + designVars_(designVars), + nConstraints_(nConstraints), + activeDesignVars_(designVars().activeDesignVariables()), + objectiveDerivatives_(designVars().getVars().size(), Zero), constraintDerivatives_(0), objectiveValue_(0), + objectiveValueOld_(0), cValues_(0), - correction_(0), + correction_(readOrZeroField("correction", designVars().getVars().size())), cumulativeCorrection_(0), eta_(1), + counter_(getOrDefault<label>("counter", Zero)), initialEtaSet_(false), correctionFolder_(mesh_.time().globalPath()/"optimisation"/"correction"), - globalSum_ - ( - dict.getOrDefault<bool>("globalSum", false) - ) + globalSum_(designVars_->globalSum()) { - // Create folder to store corrections - if (Pstream::master()) - { - mkDir(correctionFolder_); - } - // Set initial eta, if present. It might be set either in the // optimisationDict or in the specific dictionary dedicated to the // updateMethod @@ -244,16 +259,25 @@ Foam::updateMethod::updateMethod { initialEtaSet_ = true; } - else if (optMethodIODict_.readIfPresent("eta", eta_)) + else if (this->readIfPresent("eta", eta_)) { initialEtaSet_ = true; } } -Foam::dictionary Foam::updateMethod::coeffsDict() +Foam::tmp<Foam::scalarField> Foam::updateMethod::readOrZeroField +( + const word& name, + const label size +) { - return dict_.subOrEmptyDict(type()); + return tmp<scalarField> + ( + found(name) ? + new scalarField(name, *this, size) : + new scalarField(size, Zero) + ); } @@ -262,7 +286,9 @@ Foam::dictionary Foam::updateMethod::coeffsDict() Foam::autoPtr<Foam::updateMethod> Foam::updateMethod::New ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints ) { const word modelType(dict.get<word>("method")); @@ -282,12 +308,19 @@ Foam::autoPtr<Foam::updateMethod> Foam::updateMethod::New ) << exit(FatalIOError); } - return autoPtr<updateMethod>(ctorPtr(mesh, dict)); + return autoPtr<updateMethod> + (ctorPtr(mesh, dict, designVars, nConstraints, modelType)); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * // +Foam::dictionary Foam::updateMethod::coeffsDict(const word& type) const +{ + return dict_.optionalSubDict(type); +} + + void Foam::updateMethod::setObjectiveDeriv(const scalarField& derivs) { objectiveDerivatives_ = derivs; @@ -309,27 +342,74 @@ void Foam::updateMethod::setObjectiveValue(const scalar value) } +void Foam::updateMethod::setObjectiveValueOld(const scalar value) +{ + objectiveValueOld_ = value; +} + + void Foam::updateMethod::setConstraintValues(const scalarField& values) { cValues_ = values; } +Foam::scalar Foam::updateMethod::getObjectiveValue() const +{ + return objectiveValue_; +} + + +Foam::scalar Foam::updateMethod::getObjectiveValueOld() const +{ + return objectiveValueOld_; +} + + +const Foam::scalarField& Foam::updateMethod::getConstraintValues() const +{ + return cValues_; +} + + +Foam::label Foam::updateMethod::getCycle() const +{ + return counter_; +} + + void Foam::updateMethod::setStep(const scalar eta) { eta_ = eta; } +void Foam::updateMethod::modifyStep(const scalar multiplier) +{ + eta_ *= multiplier; +} + + void Foam::updateMethod::setGlobalSum(const bool useGlobalSum) { globalSum_ = useGlobalSum; } +void Foam::updateMethod::setConstaintsNumber(const label nConstraints) +{ + nConstraints_ = nConstraints; +} + + +Foam::label Foam::updateMethod::nConstraints() const +{ + return nConstraints_; +} + + Foam::scalarField& Foam::updateMethod::returnCorrection() { - computeCorrection(); return correction_; } @@ -395,27 +475,25 @@ void Foam::updateMethod::updateOldCorrection } -void Foam::updateMethod::write() +bool Foam::updateMethod::writeData(Ostream& os) const { // Insert eta if set if (initialEtaSet_) { - optMethodIODict_.add<scalar>("eta", eta_, true); + os.writeEntry("eta", eta_); } - optMethodIODict_.add<scalarField>("correction", correction_, true); + os.writeEntry("counter", counter_); + correction_.writeEntry("correction", os); - // Write IOdictionary - // Always write in ASCII format. - // Even when choosing to write in binary through controlDict, - // the content is written in ASCII format but with a binary header. - // This creates problems when the content is read back in - // (e.g. continuation) - optMethodIODict_.regIOobject::writeObject - ( - IOstreamOption(IOstreamOption::ASCII, mesh_.time().writeCompression()), - true - ); + return true; +} + + +bool Foam::updateMethod::writeAuxiliaryData() +{ + // Does nothing in base + return true; } diff --git a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.H b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.H index 0cec839afd7c2d02961df9790b485dfc2bf6ed09..49ee8c61c622e2fbd33c813c0a06f9de2d926065 100644 --- a/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.H +++ b/src/optimisation/adjointOptimisation/adjoint/optimisation/updateMethod/updateMethod/updateMethod.H @@ -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 @@ -39,9 +39,9 @@ SourceFiles #ifndef updateMethod_H #define updateMethod_H +#include "localIOdictionary.H" +#include "designVariables.H" #include "runTimeSelectionTables.H" -#include "IOdictionary.H" -#include "fvMesh.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -53,6 +53,8 @@ namespace Foam \*---------------------------------------------------------------------------*/ class updateMethod +: + public localIOdictionary { protected: @@ -62,8 +64,14 @@ protected: const dictionary dict_; - //- Used to output values useful for continuation runs - IOdictionary optMethodIODict_; + //- Design variables + autoPtr<designVariables>& designVars_; + + //- Number of constraints + label nConstraints_; + + //- Map to active design variables + const labelList& activeDesignVars_; //- Derivatives of the objective functions scalarField objectiveDerivatives_; @@ -74,6 +82,10 @@ protected: //- Objective value scalar objectiveValue_; + //- Old objective value + // Used for convergence checking + scalar objectiveValueOld_; + //- Constraint values scalarField cValues_; @@ -87,6 +99,9 @@ protected: //- Step multiplying the correction scalar eta_; + //- Optimisation cycle count + label counter_; + //- Is initially set? bool initialEtaSet_; @@ -128,8 +143,12 @@ protected: //- Compute either global or local sum, based on globalSum flag scalar globalSum(tmp<scalarField>& tfield); - //- Return optional dictionary with parameters specific to each method - dictionary coeffsDict(); + //- Compute either global or local sum, based on globalSum flag + label globalSum(const label); + + //- Helper function to either read a scalarField of certain size + //- from a dictionary, or construct a zero field + tmp<scalarField> readOrZeroField(const word& name, const label size); private: @@ -158,9 +177,12 @@ public: dictionary, ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ), - (mesh, dict) + (mesh, dict, designVars, nConstraints, type) ); @@ -170,7 +192,10 @@ public: updateMethod ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints, + const word& type ); @@ -180,7 +205,9 @@ public: static autoPtr<updateMethod> New ( const fvMesh& mesh, - const dictionary& dict + const dictionary& dict, + autoPtr<designVariables>& designVars, + const label nConstraints ); @@ -190,54 +217,84 @@ public: // Member Functions - //- Set objective derivative - void setObjectiveDeriv(const scalarField& derivs); + //- Return optional dictionary with parameters specific to each method + dictionary coeffsDict(const word& type) const; + + //- Set objective derivative + void setObjectiveDeriv(const scalarField& derivs); + + //- Set constraints derivative + void setConstraintDeriv(const PtrList<scalarField>& derivs); + + //- Set objective value + void setObjectiveValue(const scalar value); + + //- Set old objective value + void setObjectiveValueOld(const scalar value); + + //- Set values of constraints + void setConstraintValues(const scalarField& values); + + //- Get objective value + scalar getObjectiveValue() const; + + //- Get old objective value + scalar getObjectiveValueOld() const; + + //- Get values of constraints + const scalarField& getConstraintValues() const; + + //- Get optimisation cycle + label getCycle() const; + + //- Set step for optimisation methods + void setStep(const scalar eta); - //- Set constraints derivative - void setConstraintDeriv(const PtrList<scalarField>& derivs); + //- Multiply step + void modifyStep(const scalar multiplier); - //- Set constraints derivative - void setObjectiveValue(const scalar value); + //- Set globalSum variable. + // Should be set by the optimisationManager owning the updateMethod + void setGlobalSum(const bool useGlobalSum); - //- Set constraints derivative - void setConstraintValues(const scalarField& values); + //- Set the number of constraints + void setConstaintsNumber(const label nConstraints); - //- Set step for optimisation methods - void setStep(const scalar eta); + //- Get the number of constraints + label nConstraints() const; - //- Set globalSum variable. - // Should be set by the optimisationType owining the updateMethod - void setGlobalSum(const bool useGlobalSum); + //- Return the correction of the design variables + virtual void computeCorrection() = 0; - //- Return the correction of the design variables - virtual void computeCorrection()=0; + //- Return the correction of the design variables + //const scalarField& returnCorrection() const; - //- Return the correction of the design variables - //const scalarField& returnCorrection() const; + //- Return the correction of the design variables + scalarField& returnCorrection(); - //- Return the correction of the design variables - scalarField& returnCorrection(); + void writeCorrection(); - void writeCorrection(); + //- Compute merit function. Could be different than the objective + //- in the presence of constraints + virtual scalar computeMeritFunction(); - //- Compute merit function. Could be different than the objective - //- in the presence of constraints - virtual scalar computeMeritFunction(); + //- Directional derivative of the merit function, in the direction of + //- the correction. Could be different than the objective directional + //- derivative in the presence of constraints + virtual scalar meritFunctionDirectionalDerivative(); - //- Directional derivative of the merit function, in the direction of - //- the correction. Could be different than the objective directional - //- derivative in the presence of constraints - virtual scalar meritFunctionDirectionalDerivative(); + //- Return whether initial eta was set + bool& initialEtaSet(); - //- Return whether initial eta was set - bool& initialEtaSet(); + //- Update old correction. Useful for quasi-newton methods coupled with + //- line search + virtual void updateOldCorrection(const scalarField& oldCorrection); - //- Update old correction. useful for quasi-newton methods coupled with - //- line search - virtual void updateOldCorrection(const scalarField& oldCorrection); + //- Write continuation data under uniform + virtual bool writeData(Ostream& os) const; - //- Write useful quantities to files - virtual void write(); + //- Write non-continuation data, usually under the optimisation folder + virtual bool writeAuxiliaryData(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/Bezier/Bezier.C b/src/optimisation/adjointOptimisation/adjoint/parameterization/Bezier/Bezier.C index 6653c2ed483e3e7045f2182e00bc4c44dc917972..457af29dfebe9c62fc3398f9b4897676c3fc6ea4 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/Bezier/Bezier.C +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/Bezier/Bezier.C @@ -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-2019, 2022-2023 PCOpt/NTUA + Copyright (C) 2013-2019, 2022-2023 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -91,7 +91,7 @@ Bezier::Bezier(const fvMesh& mesh, const dictionary& dict) { for (label iCP = 0; iCP < nBezier_; ++iCP) { - if (confineMovement_[iDir][iCP]) + if (!confineMovement_[iDir][iCP]) { activeDesignVariables_[iActive++] = iDir*nBezier_ + iCP; } diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C index 89839e07b65c30bd899e6c69a3f0c15ce5711ef4..fc43049d1f9771305e9ca8298a9fa91a6e0658d7 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.C @@ -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 @@ -350,7 +350,7 @@ bool Foam::NURBS3DVolume::bound vector& vec, scalar minValue, scalar maxValue -) +) const { bool boundPoint(false); // Lower value bounding @@ -427,6 +427,70 @@ void Foam::NURBS3DVolume::determineActiveDesignVariablesAndPoints() activeControlPoints_[cpI] = false; } } + + // Deactivate design varibles if they affect no mesh point + confineInertControlPoints(); +} + + +void Foam::NURBS3DVolume::confineInertControlPoints() +{ + // Loop over all active control points and check whether they parameterize + // at least one mesh point of the ones laying within the morphing box + const labelList& map = getMap(); + const pointVectorField& parametricCoors = getParametricCoordinates(); + + const scalarField& knotsU = basisU_.knots(); + const scalarField& knotsV = basisV_.knots(); + const scalarField& knotsW = basisW_.knots(); + + const label pU = basisU_.degree(); + const label pV = basisV_.degree(); + const label pW = basisW_.degree(); + forAll(activeControlPoints_, cpI) + { + if (activeControlPoints_[cpI]) + { + // Get i, j, k corresponding to this control point + label i(-1), j(-1), k(-1); + getIJK(i, j, k, cpI); + + const scalar uMin(knotsU[i]); + const scalar uMax(knotsU[i + pU + 1]); + const scalar vMin(knotsV[j]); + const scalar vMax(knotsV[j + pV + 1]); + const scalar wMin(knotsW[k]); + const scalar wMax(knotsW[k + pW + 1]); + bool foundParamPt(false); + for (const label paramI : map) + { + const vector& paramCoors = parametricCoors()[paramI]; + if + ( + paramCoors.x() >= uMin && paramCoors.x() < uMax + && paramCoors.y() >= vMin && paramCoors.y() < vMax + && paramCoors.z() >= wMin && paramCoors.z() < wMax + ) + { + foundParamPt = true; + break; + } + } + reduce(foundParamPt, orOp<bool>()); + if (!foundParamPt) + { + activeControlPoints_[cpI] = false; + activeDesignVariables_[3*cpI] = false; + activeDesignVariables_[3*cpI + 1] = false; + activeDesignVariables_[3*cpI + 2] = false; + Info<< "Disabling control " << cpI + << " and variables " + << "(" << 3*cpI << ", " << 3*cpI+1 << ", " << 3*cpI+2 << ")" + << " since they does not parameterize any mesh point" + << endl; + } + } + } } @@ -765,7 +829,6 @@ Foam::NURBS3DVolume::NURBS3DVolume { controlPointsDefinition::New(*this); } - determineActiveDesignVariablesAndPoints(); } @@ -801,6 +864,114 @@ Foam::autoPtr<Foam::NURBS3DVolume> Foam::NURBS3DVolume::New // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::tmp<Foam::vectorField> Foam::NURBS3DVolume::computeParametricCoordinates +( + const vectorField& points +) const +{ + tmp<vectorField> tparamCoors(tmp<vectorField>::New(points.size(), Zero)); + vectorField& paramCoors = tparamCoors.ref(); + // Initialize parametric coordinates based on min/max of control points + scalar minX1 = min(cps_.component(0)); + scalar maxX1 = max(cps_.component(0)); + scalar minX2 = min(cps_.component(1)); + scalar maxX2 = max(cps_.component(1)); + scalar minX3 = min(cps_.component(2)); + scalar maxX3 = max(cps_.component(2)); + + scalar oneOverDenomX(1./(maxX1 - minX1)); + scalar oneOverDenomY(1./(maxX2 - minX2)); + scalar oneOverDenomZ(1./(maxX3 - minX3)); + + forAll(points, pI) + { + paramCoors[pI].x() = (points[pI].x() - minX1)*oneOverDenomX; + paramCoors[pI].y() = (points[pI].y() - minX2)*oneOverDenomY; + paramCoors[pI].z() = (points[pI].z() - minX3)*oneOverDenomZ; + } + + // Indices of points that failed to converge + // (i.e. are bounded for nMaxBound iters) + boolList dropOffPoints(points.size(), false); + label nDropedPoints(0); + + // Initial cartesian coordinates + tmp<vectorField> tsplinesBasedCoors(coordinates(paramCoors)); + vectorField& splinesBasedCoors = tsplinesBasedCoors.ref(); + + // Newton-Raphson loop to compute parametric coordinates + // based on cartesian coordinates and the known control points + Info<< "Mapping of mesh points to parametric space for box " << name_ + << " ..." << endl; + // Do loop on a point-basis and check residual of each point equation + label maxIterNeeded(0); + forAll(points, pI) + { + label iter(0); + label nBoundIters(0); + vector res(GREAT, GREAT, GREAT); + do + { + vector& uVec = paramCoors[pI]; + vector& coorPointI = splinesBasedCoors[pI]; + uVec += ((inv(JacobianUVW(uVec))) & (points[pI] - coorPointI)); + // Bounding might be needed for the first iterations + // If multiple bounds happen, point is outside of the control + // boxes and should be discarded + if (bound(uVec)) + { + ++nBoundIters; + } + if (nBoundIters > nMaxBound_) + { + dropOffPoints[pI] = true; + ++nDropedPoints; + break; + } + // Update current cartesian coordinates based on parametric ones + coorPointI = coordinates(uVec); + // Compute residual + res = cmptMag(points[pI] - coorPointI); + } + while + ( + (iter++ < maxIter_) + && ( + res.component(0) > tolerance_ + || res.component(1) > tolerance_ + || res.component(2) > tolerance_ + ) + ); + if (iter > maxIter_) + { + WarningInFunction + << "Mapping to parametric space for point " << pI + << " failed." << endl + << "Residual after " << maxIter_ + 1 << " iterations : " + << res << endl + << "parametric coordinates " << paramCoors[pI] + << endl + << "Local system coordinates " << points[pI] << endl + << "Threshold residual per direction : " << tolerance_ + << endl; + } + maxIterNeeded = max(maxIterNeeded, iter); + } + reduce(maxIterNeeded, maxOp<label>()); + + label nParameterizedPoints = points.size() - nDropedPoints; + + reduce(nDropedPoints, sumOp<label>()); + reduce(nParameterizedPoints, sumOp<label>()); + Info<< "Found " << nDropedPoints + << " to discard from morphing boxes" << endl; + Info<< "Keeping " << nParameterizedPoints + << " parameterized points in boxes" << endl; + return tparamCoors; +} + + Foam::vector Foam::NURBS3DVolume::volumeDerivativeU ( const scalar u, @@ -1502,6 +1673,23 @@ Foam::label Foam::NURBS3DVolume::getCPID } +void Foam::NURBS3DVolume::getIJK +( + label& i, + label& j, + label& k, + const label cpID +) const +{ + const label nCPsU = basisU_.nCPs(); + const label nCPsV = basisV_.nCPs(); + k = cpID/(nCPsU*nCPsV); + const label inKplaneID = (cpID - k*(nCPsU*nCPsV)); + j = inKplaneID/nCPsU; + i = inKplaneID - j*nCPsU; +} + + void Foam::NURBS3DVolume::setControlPoints(const vectorField& newCps) { if (cps_.size() != newCps.size()) diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.H b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.H index b9e6fbd2b169b5dbd01238630f3719a8eeafde39..4d61349a14a5ed79d68cda2014369a977b9eab17 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.H +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolume.H @@ -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 @@ -170,7 +170,7 @@ protected: vector& vec, scalar minValue = 1e-7, scalar maxValue = 0.999999 - ); + ) const; //- Create lists with active design variables and control points void determineActiveDesignVariablesAndPoints(); @@ -184,6 +184,9 @@ protected: //- Confine movement in all control points for user-defined directions void confineControlPointsDirections(); + //- Deactivate control points if they affect no mesh point + void confineInertControlPoints(); + //- Confine all three movements for a prescribed control point void confineControlPoint(const label cpI); @@ -262,6 +265,13 @@ public: // Member Functions + //- Compute parametric coordinates for a given set of points + // (not necessarily the mesh ones) + tmp<vectorField> computeParametricCoordinates + ( + const vectorField& points + ) const; + // Derivatives wrt parametric coordinates //- Volume point derivative wrt u at point u,v,w @@ -384,6 +394,9 @@ public: //- Get control point ID from its I-J-K coordinates label getCPID(const label i, const label j, const label k) const; + //- Get I-J-K coordinates from control point ID + void getIJK(label& i, label& j, label& k, const label cpID) const; + //- Set new control points // New values should be on the coordinates system original CPs // were defined diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolumeI.H b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolumeI.H index 80872f97cd08493e7f6d61ab6ef4e13fb69b127c..8609f43c05431957f69441f39dc224f53ef76778 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolumeI.H +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/NURBS3DVolume/NURBS3DVolumeI.H @@ -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 @@ -97,6 +97,13 @@ const Foam::NURBSbasis& Foam::NURBS3DVolume::basisW() const } +inline Foam::Vector<Foam::label> +Foam::NURBS3DVolume::nCPsPerDirection() const +{ + return Vector<label>(basisU_.nCPs(), basisV_.nCPs(), basisW_.nCPs()); +} + + const Foam::fvMesh& Foam::NURBS3DVolume::mesh() const { return mesh_; diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cartesian/NURBS3DVolumeCartesian.C b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cartesian/NURBS3DVolumeCartesian.C index 1ab353df04721110ac6be5ce85e6d87a570bbca5..5753398ae67ac4e7e6b47540216d991f1e5ce2b7 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cartesian/NURBS3DVolumeCartesian.C +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cartesian/NURBS3DVolumeCartesian.C @@ -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 @@ -89,6 +89,7 @@ void Foam::NURBS3DVolumeCartesian::updateLocalCoordinateSystem if (computeParamCoors) { getParametricCoordinates(); + determineActiveDesignVariablesAndPoints(); } } diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.C b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.C index c132d15c3e6386a5d6d05c1a5663eadb4a756a22..31c10725aa4a1b797da4998e2ffe4d8d0c2c0cc3 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.C +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.C @@ -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 @@ -137,6 +137,7 @@ Foam::NURBS3DVolumeCylindrical::NURBS3DVolumeCylindrical if (computeParamCoors) { getParametricCoordinates(); + determineActiveDesignVariablesAndPoints(); } } diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.H b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.H index 2719ccd2332f2f211025d908c8366b0b423fbbfd..52f0730b12248c13cb5e5ddc1c7235fd055fe0a5 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.H +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/cylindrical/NURBS3DVolumeCylindrical.H @@ -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 @@ -106,6 +106,15 @@ public: //- Destructor virtual ~NURBS3DVolumeCylindrical() = default; + + + // Access + + //- Get the origin vector + inline const vector& getOrigin() const + { + return origin_; + } }; diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.C b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.C index c5515ba8436f0d99ef8ffb7cbeed9923b93efcdf..4ff3278479ba6b193774eda72d3e993dd8bdc5ae 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.C +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.C @@ -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 @@ -139,13 +139,13 @@ const vectorField& volBSplinesBase::getControlPoints(const label& iNURB) const vectorField volBSplinesBase::getAllControlPoints() const { - vectorField totalCPs(0); + DynamicList<vector> totalCPs(0); forAll(volume_, iNURB) { - totalCPs.append(volume_[iNURB].getControlPoints()); + totalCPs.push_back(volume_[iNURB].getControlPoints()); } - return totalCPs; + return vectorField(std::move(totalCPs)); } @@ -182,6 +182,12 @@ labelList volBSplinesBase::getStartCpID() const } +labelList volBSplinesBase::getStartVarID() const +{ + return 3*getStartCpID(); +} + + label volBSplinesBase::findBoxID(const label cpI) const { const labelList startCPID(getStartCpID()); @@ -200,6 +206,33 @@ label volBSplinesBase::findBoxID(const label cpI) const } +Vector<label> volBSplinesBase::decomposeDV(const label varID) const +{ + Vector<label> decomposed; + labelList startVarID = getStartVarID(); + label boxID(-1); + for (label iBox = 0; iBox < startVarID.size() - 1 ; ++iBox) + { + if (varID >= startVarID[iBox] && varID < startVarID[iBox + 1]) + { + boxID = iBox; + break; + } + } + const label localVarID = varID - startVarID[boxID]; + decomposed.x() = boxID; + decomposed.y() = localVarID/3; + decomposed.z() = localVarID%3; + DebugInfo + << "varID " << varID + << " belongs to box " << decomposed.x() + << " cpLocal " << decomposed.y() + << " dir " << decomposed.z() + << endl; + return decomposed; +} + + const Foam::labelList& volBSplinesBase::getActiveDesignVariables() const { return activeDesignVariables_; @@ -243,6 +276,43 @@ Foam::scalar Foam::volBSplinesBase::computeMaxBoundaryDisplacement } +Foam::tmp<vectorField> Foam::volBSplinesBase::computeBoundaryDisplacement +( + const vectorField& controlPointsMovement, + const labelList& patchesToBeMoved +) +{ + auto tdisplacement(tmp<vectorField>::New(mesh_.nPoints(), Zero)); + vectorField& displacement = tdisplacement.ref(); + + label pastControlPoints(0); + forAll(volume_, iNURB) + { + const label nb(volume_[iNURB].getControlPoints().size()); + vectorField localControlPointsMovement(nb, Zero); + + // Set localControlPointsMovement + forAll(localControlPointsMovement, iCPM) + { + localControlPointsMovement[iCPM] = + controlPointsMovement[pastControlPoints + iCPM]; + } + + displacement += + volume_[iNURB].computeNewBoundaryPoints + ( + localControlPointsMovement, + patchesToBeMoved + ) + - mesh_.points(); + + pastControlPoints += nb; + } + + return tdisplacement; +} + + void Foam::volBSplinesBase::boundControlPointMovement ( vectorField& controlPointsMovement diff --git a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.H b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.H index 6855f097976411cb889473ce678129fa07625325..93e03929f00b37d123dc221a5ec0413053eef6f9 100644 --- a/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.H +++ b/src/optimisation/adjointOptimisation/adjoint/parameterization/NURBS/NURBS3DVolume/volBSplinesBase/volBSplinesBase.H @@ -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 @@ -129,9 +129,15 @@ public: //- Get start CP ID for each box labelList getStartCpID() const; + //- Get start CP ID for each box + labelList getStartVarID() const; + //- Find box of certain control point label findBoxID(const label cpI) const; + //- From design variable ID, return boxID, cpID and direction + Vector<label> decomposeDV(const label dvI) const; + //- Get active design variables const labelList& getActiveDesignVariables() const; @@ -143,6 +149,13 @@ public: const labelList& patchesToBeMoved ); + //- Get the updated boundary points only + tmp<vectorField> computeBoundaryDisplacement + ( + const vectorField& controlPointsMovement, + const labelList& patchesToBeMoved + ); + //- Bound control points movement void boundControlPointMovement ( diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.C index cbe65c281a7bb921dce0ff10e0380fee3b91edb7..ed51b74da3c895920dd3cbaf188c848ac93fc888 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.C @@ -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 @@ -28,6 +28,7 @@ License \*---------------------------------------------------------------------------*/ #include "adjointSolverManager.H" +#include "primalSolver.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -42,6 +43,7 @@ namespace Foam Foam::adjointSolverManager::adjointSolverManager ( fvMesh& mesh, + autoPtr<designVariables>& designVars, const word& managerType, const dictionary& dict, bool overrideUseSolverName @@ -62,14 +64,18 @@ Foam::adjointSolverManager::adjointSolverManager mesh_(mesh), dict_(dict), managerName_(dict.dictName()), + managerType_(managerType), primalSolverName_(dict.get<word>("primalSolver")), adjointSolvers_(0), objectiveSolverIDs_(0), - constraintSolverIDs_(0), + oneSidedConstraintSolverIDs_(0), + doubleSidedConstraintSolverIDs_(0), operatingPointWeight_ ( dict.getOrDefault<scalar>("operatingPointWeight", 1) - ) + ), + nActiveAdjointSolvers_(0), + designVars_(designVars) { dictionary& adjointSolversDict = const_cast<dictionary&>(dict.subDict("adjointSolvers")); @@ -77,14 +83,16 @@ Foam::adjointSolverManager::adjointSolverManager const wordList adjSolverNames = adjointSolversDict.toc(); adjointSolvers_.setSize(adjSolverNames.size()); objectiveSolverIDs_.setSize(adjSolverNames.size()); - constraintSolverIDs_.setSize(adjSolverNames.size()); + oneSidedConstraintSolverIDs_.setSize(adjSolverNames.size()); + doubleSidedConstraintSolverIDs_.setSize(adjSolverNames.size()); label nObjectives(0); - label nConstraints(0); + label nOneSidedConstraints(0); + label nDoubleSidedConstraints(0); forAll(adjSolverNames, namei) { dictionary& solverDict = adjointSolversDict.subDict(adjSolverNames[namei]); - if (overrideUseSolverName || adjointSolvers_.size() > 1) + if (overrideUseSolverName) { solverDict.add<bool>("useSolverNameForFields", true); } @@ -96,13 +104,21 @@ Foam::adjointSolverManager::adjointSolverManager mesh_, managerType, solverDict, - primalSolverName_ + primalSolverName_, + adjSolverNames[namei] ) ); - - if (adjointSolvers_[namei].isConstraint()) + if (adjointSolvers_[namei].active()) + { + nActiveAdjointSolvers_++; + } + if (adjointSolvers_[namei].isDoubleSidedConstraint()) { - constraintSolverIDs_[nConstraints++] = namei; + doubleSidedConstraintSolverIDs_[nDoubleSidedConstraints++] = namei; + } + else if (adjointSolvers_[namei].isConstraint()) + { + oneSidedConstraintSolverIDs_[nOneSidedConstraints++] = namei; } else { @@ -110,10 +126,17 @@ Foam::adjointSolverManager::adjointSolverManager } } objectiveSolverIDs_.setSize(nObjectives); - constraintSolverIDs_.setSize(nConstraints); + oneSidedConstraintSolverIDs_.setSize(nOneSidedConstraints); + doubleSidedConstraintSolverIDs_.setSize(nDoubleSidedConstraints); + + Info<< "Found " << nOneSidedConstraints + << " adjoint solvers acting as single-sided constraints" << endl; - Info<< "Found " << nConstraints - << " adjoint solvers acting as constraints" << endl; + Info<< "Found " << nDoubleSidedConstraints + << " adjoint solvers acting as double-sided constraints" << endl; + + Info<< "Found " << nActiveAdjointSolvers_ + << " active adjoint solvers" << endl; // Having more than one non-aggregated objectives per operating point // is needlessly expensive. Issue a warning @@ -122,7 +145,7 @@ Foam::adjointSolverManager::adjointSolverManager WarningInFunction << "Number of adjoint solvers corresponding to objectives " << "is greater than 1 (" << objectiveSolverIDs_.size() << ")" << nl - << "Consider aggregating your objectives to one" << endl; + << "Consider aggregating your objectives to one\n" << endl; } } @@ -177,15 +200,66 @@ Foam::adjointSolverManager::adjointSolvers() } +Foam::wordList Foam::adjointSolverManager::adjointSolversNames() const +{ + wordList names(adjointSolvers_.size()); + forAll(adjointSolvers_, sI) + { + names[sI] = adjointSolvers_[sI].name(); + } + return names; +} + + Foam::scalar Foam::adjointSolverManager::operatingPointWeight() const { return operatingPointWeight_; } +Foam::label Foam::adjointSolverManager::nActiveAdjointSolvers() const +{ + return nActiveAdjointSolvers_; +} + + +Foam::label Foam::adjointSolverManager::nActiveAdjointSolvers +( + const dictionary& dict +) +{ + const dictionary& adjointSolversDict = dict.subDict("adjointSolvers"); + const wordList adjSolverNames = adjointSolversDict.toc(); + label n(0); + Switch active(true); + forAll(adjSolverNames, namei) + { + active = adjointSolversDict.subDict(adjSolverNames[namei]). + getOrDefault<bool>("active", true); + if (active) + { + n++; + } + } + return n; +} + + Foam::label Foam::adjointSolverManager::nConstraints() const { - return constraintSolverIDs_.size(); + return nOneSidedConstraints() + 2*nDoubleSidedConstraints(); +} + + +Foam::label Foam::adjointSolverManager::nOneSidedConstraints() const +{ + return oneSidedConstraintSolverIDs_.size(); +} + + +Foam::label Foam::adjointSolverManager::nDoubleSidedConstraints() const +{ + return doubleSidedConstraintSolverIDs_.size(); } @@ -197,17 +271,29 @@ Foam::label Foam::adjointSolverManager::nObjectives() const Foam::label Foam::adjointSolverManager::nAdjointSolvers() const { - return nConstraints() + nObjectives(); + return nOneSidedConstraints() + nDoubleSidedConstraints() + nObjectives(); } void Foam::adjointSolverManager::solveAdjointEquations() { + // Solve all adjoint equations of this adjointSolverManager for (adjointSolver& solver : adjointSolvers_) { + // Update all primal-based quantities needed by the adjoint equations + solver.updatePrimalBasedQuantities(); + // Solve the adjoint equations taking into consideration the weighted // contribution of possibly multiple objectives solver.solve(); + + // Compute sensitivities and force writing to the adjoint dictionary + // if this an output time + solver.computeObjectiveSensitivities(designVars_); + if (mesh_.time().writeTime()) + { + solver.regIOobject::write(true); + } } } @@ -223,7 +309,7 @@ Foam::adjointSolverManager::aggregateSensitivities() { // Sum contributions const scalarField& solverSens = - adjointSolvers_[solveri].getObjectiveSensitivities(); + adjointSolvers_[solveri].getObjectiveSensitivities(designVars_); if (sens.empty()) { @@ -239,17 +325,28 @@ Foam::adjointSolverManager::aggregateSensitivities() Foam::PtrList<Foam::scalarField> Foam::adjointSolverManager::constraintSensitivities() { - PtrList<scalarField> constraintSens(constraintSolverIDs_.size()); - forAll(constraintSens, cI) + PtrList<scalarField> constraintSens(nConstraints()); + // Only one-sided constraints + label cI(0); + for (const label consI : oneSidedConstraintSolverIDs_) { - label consI = constraintSolverIDs_[cI]; constraintSens.set ( - cI, - new scalarField(adjointSolvers_[consI].getObjectiveSensitivities()) + cI++, + new scalarField + (adjointSolvers_[consI].getObjectiveSensitivities(designVars_)) ); } + // Two-sided constraints. Negated left-most side sensitivities + for (const label consI : doubleSidedConstraintSolverIDs_) + { + scalarField sens + (adjointSolvers_[consI].getObjectiveSensitivities(designVars_)); + constraintSens.set(cI++, new scalarField( sens)); + constraintSens.set(cI++, new scalarField(- sens)); + } + return constraintSens; } @@ -258,7 +355,7 @@ void Foam::adjointSolverManager::computeAllSensitivities() { for (adjointSolver& adjSolver : adjointSolvers_) { - adjSolver.computeObjectiveSensitivities(); + adjSolver.computeObjectiveSensitivities(designVars_); } } @@ -288,16 +385,24 @@ Foam::scalar Foam::adjointSolverManager::objectiveValue() Foam::tmp<Foam::scalarField> Foam::adjointSolverManager::constraintValues() { - tmp<scalarField> tconstraintValues - ( - new scalarField(constraintSolverIDs_.size(), Zero) - ); + auto tconstraintValues(tmp<scalarField>::New(nConstraints(), Zero)); scalarField& constraintValues = tconstraintValues.ref(); - forAll(constraintValues, cI) + label cI(0); + // One-sided constraints only + for (const label consI : oneSidedConstraintSolverIDs_) { objectiveManager& objManager = - adjointSolvers_[constraintSolverIDs_[cI]].getObjectiveManager(); - constraintValues[cI] = objManager.print(); + adjointSolvers_[consI].getObjectiveManager(); + constraintValues[cI++] = objManager.print(); + } + // Double-sided constraints + // Objective value of the left-most side is negated + for (const label consI : doubleSidedConstraintSolverIDs_) + { + objectiveManager& objManager = + adjointSolvers_[consI].getObjectiveManager(); + constraintValues[cI++] = objManager.print(false); + constraintValues[cI++] = objManager.print(true); } return tconstraintValues; @@ -316,4 +421,10 @@ void Foam::adjointSolverManager::updatePrimalBasedQuantities(const word& name) } +bool Foam::adjointSolverManager::isMaster() const +{ + return mesh_.lookupObject<primalSolver>(primalSolverName_).isMaster(); +} + + // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.H index 5ebb2bcbc6adec1b4c2de237baffa74d6b277c20..7ab01a1fc3f644846ccd056c7a166534335bb64b 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolverManager/adjointSolverManager.H @@ -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 @@ -77,16 +77,24 @@ protected: const word managerName_; + const word managerType_; + const word primalSolverName_; PtrList<adjointSolver> adjointSolvers_; labelList objectiveSolverIDs_; - labelList constraintSolverIDs_; + labelList oneSidedConstraintSolverIDs_; + + labelList doubleSidedConstraintSolverIDs_; scalar operatingPointWeight_; + label nActiveAdjointSolvers_; + + autoPtr<designVariables>& designVars_; + public: @@ -99,6 +107,7 @@ public: adjointSolverManager ( fvMesh& mesh, + autoPtr<designVariables>& designVars, const word& managerType, const dictionary& dict, bool overrideUseSolverName @@ -111,7 +120,7 @@ public: // Member Functions - virtual bool readDict(const dictionary& dict); + bool readDict(const dictionary& dict); // Access @@ -131,12 +140,33 @@ public: //- Non-const access to adjoint solvers PtrList<adjointSolver>& adjointSolvers(); + //- Return the names of all adjointSolvers + wordList adjointSolversNames() const; + //- Const access to adjoint solvers scalar operatingPointWeight() const; - //- Number of adjoint solvers corresponding to constraints + //- Return number of active adjoint solvers, either corresponding + // to objectives or constraints + label nActiveAdjointSolvers() const; + + //- Static function returning the number of active adjoint + // solvers reading dict + static label nActiveAdjointSolvers(const dictionary& dict); + + //- Number of constraints + // Is the sum of one-sided and double-sided constraints, the + // latter multiplied by two label nConstraints() const; + //- Number of adjoint solvers corresponding to one-sided + //- constraints + label nOneSidedConstraints() const; + + //- Number of adjoint solvers corresponding to double-sided + //- constraints + label nDoubleSidedConstraints() const; + //- Number of adjoint solvers corresponding to objectives label nObjectives() const; @@ -148,13 +178,13 @@ public: //- Update objective function-related values and solve adjoint //- equations - virtual void solveAdjointEquations(); + void solveAdjointEquations(); //- Aggregate sensitivities from various adjoint solvers - virtual tmp<scalarField> aggregateSensitivities(); + tmp<scalarField> aggregateSensitivities(); //- Get constraint sensitivities. One scalarField per constraint - virtual PtrList<scalarField> constraintSensitivities(); + PtrList<scalarField> constraintSensitivities(); //- Compute sensitivities for all adjoint solvers //- (both objective- and constraint-related ones) @@ -167,12 +197,17 @@ public: scalar objectiveValue(); //- Get constraint values - virtual tmp<scalarField> constraintValues(); + tmp<scalarField> constraintValues(); //- Update fields related to primal solution. // For instance, primal fields of adjoint turbulence models void updatePrimalBasedQuantities(const word& name); + //- Whether the primal solver corresponding to the + //- adjointSolverManager is the master one, in case of coupled + //- solvers + bool isMaster() const; + // IO diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.C index e212b596dc8975f9de1af1eaebb9add2fceb6447..9510d1977d0617d428bdb38a095d0066a0275ffb 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.C @@ -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 @@ -28,6 +28,8 @@ License \*---------------------------------------------------------------------------*/ #include "adjointSolver.H" +#include "adjointSensitivity.H" +#include "designVariables.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -38,6 +40,39 @@ namespace Foam } +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::adjointSolver::allocateSensitivities() +{ + if (computeSensitivities_) + { + adjointSensitivity_.reset + ( + adjointSensitivity::New(mesh_, designVarsDict(), *this).ptr() + ); + } +} + + +Foam::dictionary Foam::adjointSolver::designVarsDict() const +{ + // Re-read optimisationDict here to cover multi-region cases + return + IOdictionary + ( + IOobject + ( + "optimisationDict", + mesh_.time().globalPath()/"system", + mesh_, + IOobject::MUST_READ, + IOobject::NO_WRITE, + false + ) + ).subDict("optimisation").subDict("designVariables"); +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::adjointSolver::adjointSolver @@ -45,31 +80,38 @@ Foam::adjointSolver::adjointSolver fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ) : - solver(mesh, managerType, dict), + solver(mesh, managerType, dict, solverName), primalSolverName_(primalSolverName), - objectiveManagerPtr_ + objectiveManager_ ( - objectiveManager::New - ( - mesh, - dict.subDict("objectives"), - solverName_, - primalSolverName - ) + mesh, + dict.subDict("objectives"), + solverName_, + primalSolverName ), sensitivities_(nullptr), computeSensitivities_ ( dict.getOrDefault<bool>("computeSensitivities", true) ), - isConstraint_(dict.getOrDefault<bool>("isConstraint", false)) + isConstraint_(dict.getOrDefault<bool>("isConstraint", false)), + isDoubleSidedConstraint_ + (dict.getOrDefault<bool>("isDoubleSidedConstraint", false)), + adjointSensitivity_(nullptr) { + // Force solver to not be a (single-sided) contraint if flagged as + // double-sided + if (isDoubleSidedConstraint_) + { + isConstraint_ = false; + } // Update objective-related quantities to get correct derivatives // in case of continuation - objectiveManagerPtr_().update(); + objectiveManager_.update(); } @@ -80,7 +122,8 @@ Foam::autoPtr<Foam::adjointSolver> Foam::adjointSolver::New fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ) { const word solverType(dict.get<word>("type")); @@ -100,29 +143,13 @@ Foam::autoPtr<Foam::adjointSolver> Foam::adjointSolver::New return autoPtr<adjointSolver> ( - ctorPtr(mesh, managerType, dict, primalSolverName) + ctorPtr(mesh, managerType, dict, primalSolverName, solverName) ); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -const Foam::primalSolver& Foam::adjointSolver::getPrimalSolver() const -{ - return mesh_.lookupObject<primalSolver>(primalSolverName_); -} - - -Foam::primalSolver& Foam::adjointSolver::getPrimalSolver() -{ - return - const_cast<primalSolver&> - ( - mesh_.lookupObject<primalSolver>(primalSolverName_) - ); -} - - bool Foam::adjointSolver::readDict(const dictionary& dict) { if (solver::readDict(dict)) @@ -130,7 +157,12 @@ bool Foam::adjointSolver::readDict(const dictionary& dict) computeSensitivities_ = dict.getOrDefault<bool>("computeSensitivities", true); - objectiveManagerPtr_->readDict(dict.subDict("objectives")); + objectiveManager_.readDict(dict.subDict("objectives")); + + if (adjointSensitivity_) + { + adjointSensitivity_().readDict(designVarsDict()); + } return true; } @@ -139,38 +171,94 @@ bool Foam::adjointSolver::readDict(const dictionary& dict) } -const Foam::objectiveManager& Foam::adjointSolver::getObjectiveManager() const +bool Foam::adjointSolver::includeDistance() const +{ + return false; +} + + +Foam::dimensionSet Foam::adjointSolver::daDimensions() const +{ + NotImplemented; + return dimless; +} + + +Foam::dimensionSet Foam::adjointSolver::maDimensions() const +{ + NotImplemented; + return dimless; +} + + +Foam::tmp<Foam::volScalarField> Foam::adjointSolver::adjointEikonalSource() { - return objectiveManagerPtr_(); + return nullptr; } -Foam::objectiveManager& Foam::adjointSolver::getObjectiveManager() +Foam::tmp<Foam::volScalarField> Foam::adjointSolver::yWall() const { - return objectiveManagerPtr_(); + return nullptr; } -void Foam::adjointSolver::postLoop() +void Foam::adjointSolver::computeObjectiveSensitivities +( + autoPtr<designVariables>& designVars +) { - addProfiling(adjointSolver, "adjointSolver::postLoop"); - computeObjectiveSensitivities(); - // The solver dictionary has been already written after the termination - // of the adjoint loop. Force re-writing it to include the sensitivities - // as well - regIOobject::write(true); + if (computeSensitivities_) + { + preCalculateSensitivities(); + const scalarField& sens = + adjointSensitivity_->calculateSensitivities(designVars); + if (!sensitivities_) + { + sensitivities_.reset(new scalarField(sens.size(), Zero)); + } + sensitivities_.ref() = sens; + } + else + { + sensitivities_.reset(new scalarField()); + } } -bool Foam::adjointSolver::isConstraint() +const Foam::scalarField& Foam::adjointSolver::getObjectiveSensitivities +( + autoPtr<designVariables>& designVars +) { - return isConstraint_; + if (!sensitivities_) + { + // Read sensitivities from file in case of continuation + // Done here and not in allocateSensitivities since the size of the + // design variables and, hence, the sensitivities is not known there + if (dictionary::found("sensitivities")) + { + sensitivities_ = + tmp<scalarField>::New + ("sensitivities", *this, designVars().size()); + } + else + { + computeObjectiveSensitivities(designVars); + } + } + + return sensitivities_(); } void Foam::adjointSolver::clearSensitivities() { - sensitivities_.clear(); + if (computeSensitivities_) + { + adjointSensitivity_->clearSensitivities(); + sensitivities_.clear(); + } } diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.H index f3a7c8e765441e8b3c2d95c9ff14c89ea0bad6bd..6a1e228a3e2d8889c2253269e7747a870eb175c0 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolver.H @@ -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 @@ -42,8 +42,8 @@ Description #include "IOdictionary.H" #include "solver.H" #include "objectiveManager.H" -#include "sensitivity.H" #include "primalSolver.H" +#include "adjointSensitivity.H" #include "runTimeSelectionTables.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -51,6 +51,8 @@ Description namespace Foam { +class designVariables; + /*---------------------------------------------------------------------------*\ Class adjointSolver Declaration \*---------------------------------------------------------------------------*/ @@ -78,7 +80,7 @@ protected: const word primalSolverName_; //- Object to manage objective functions - autoPtr<objectiveManager> objectiveManagerPtr_; + objectiveManager objectiveManager_; //- Sensitivities field tmp<scalarField> sensitivities_; @@ -89,6 +91,29 @@ protected: //- Is the adjoint solver used to tackle a constraint bool isConstraint_; + //- Is the adjoint solver used to tackle a double-sided constraint + bool isDoubleSidedConstraint_; + + //- Sensitivity Derivatives engine + autoPtr<adjointSensitivity> adjointSensitivity_; + + + // Protected Member Functions + + //- Actions to be performed before calculating sensitivities + // Does noting in base + virtual void preCalculateSensitivities() + {} + + //- Allocate the sensitivity derivatives + // Since parts of the sensitivities depend on virtual functions + // implemented within derived classes, the actual allocation should + // happen there + void allocateSensitivities(); + + //- Return the dictionary corresponding to the design variables + dictionary designVarsDict() const; + public: @@ -109,9 +134,10 @@ public: fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ), - (mesh, managerType, dict, primalSolverName) + (mesh, managerType, dict, primalSolverName, solverName) ); @@ -123,7 +149,8 @@ public: fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ); @@ -135,7 +162,8 @@ public: fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ); @@ -150,47 +178,63 @@ public: virtual bool readDict(const dictionary& dict); //- Return the primal solver name - const word& primalSolverName() const - { - return primalSolverName_; - } + inline const word& primalSolverName() const; //- Return a const-reference to the primal solver //- corresponding to this adjoint solver - const primalSolver& getPrimalSolver() const; + inline const primalSolver& getPrimalSolver() const; //- Return a non const-reference to the primal solver //- corresponding to this adjoint solver - primalSolver& getPrimalSolver(); + inline primalSolver& getPrimalSolver(); //- Return a const reference to the objective manager - const objectiveManager& getObjectiveManager() const; + inline const objectiveManager& getObjectiveManager() const; //- Return a reference to the objective manager - objectiveManager& getObjectiveManager(); + inline objectiveManager& getObjectiveManager(); + //- Is the solving referring to a constraint + inline bool isConstraint(); - // Evolution + //- Is the solving referring to a double-sided constraint + inline bool isDoubleSidedConstraint(); - //- Functions to be called after loop - // Computes adjoint sensitivities - virtual void postLoop(); + //- Does the adjoint to an equation computing distances need to + //- taken into consideration + virtual bool includeDistance() const; - //- Compute sensitivities of the underlaying objectives - virtual void computeObjectiveSensitivities() = 0; + //- Return the dimensions of the adjoint distance field + virtual dimensionSet daDimensions() const; - //- Is the solving referring to a constraint - virtual bool isConstraint(); + //- Return the dimensions of the adjoint grid displacement variable + virtual dimensionSet maDimensions() const; + + //- Return the source the adjoint eikonal equation + virtual tmp<volScalarField> adjointEikonalSource(); + + //- Return the distance field, to be used in the solution of the + //- adjoint eikonal PDE + virtual tmp<volScalarField> yWall() const; + + + // Evolution + + //- Compute sensitivities of the underlaying objectives + virtual void computeObjectiveSensitivities + ( + autoPtr<designVariables>& designVars + ); //- Grab a reference to the computed sensitivities - virtual const scalarField& getObjectiveSensitivities() = 0; + virtual const scalarField& getObjectiveSensitivities + ( + autoPtr<designVariables>& designVars + ); //- Clears the sensitivity field known by the adjoint solver virtual void clearSensitivities(); - //- Return the base sensitivity object - virtual sensitivity& getSensitivityBase() = 0; - //- Update primal based quantities, e.g. the primal fields //- in adjoint turbulence models // Does nothing in the base @@ -198,6 +242,67 @@ public: //- Write the sensitivity derivatives virtual bool writeData(Ostream& os) const; + + // Functions related to the computation of sensitivity derivatives. + // All functions get the field to accumulate their contribution on + // as an argument and should be implemented by the derived classes + + // Shape optimisation + + //- Compute the multiplier for grad(dxdb) + // Used in shape sensitivity derivatives, computed with + // the FI and E-SI approaches + virtual void accumulateGradDxDbMultiplier + ( + volTensorField& gradDxDbMult, + const scalar dt + ) + {} + + //- Compute the multiplier for div(dxdb) + // Used in shape sensitivity derivatives, computed with + // the FI and E-SI approaches + virtual void accumulateDivDxDbMultiplier + ( + autoPtr<scalarField>& divDxDbMult, + const scalar dt + ) + {} + + //- Accumulate the multipliers of geometric quantities + //- defined at the boundary, usually through an objective + //- or constraint function + virtual void accumulateGeometryVariationsMultipliers + ( + autoPtr<boundaryVectorField>& dSfdbMult, + autoPtr<boundaryVectorField>& dnfdbMult, + autoPtr<boundaryVectorField>& dxdbDirectMult, + autoPtr<pointBoundaryVectorField>& pointDxDirectDbMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt + ) + {} + + //- Contributions from boundary functions that inlcude + //- geometric aspects in them and change when the geometry + //- is displaced, e.g. rotationWallVelocity + virtual void accumulateBCSensitivityIntegrand + ( + autoPtr<boundaryVectorField>& bcDxDbMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt + ) + {} + + //- Contributions from fvOptions that inlcude + //- geometric aspects in them and change when the geometry + //- is displaced, e.g. MRF + virtual void accumulateOptionsDxDbMultiplier + ( + vectorField& optionsDxDbMult, + const scalar dt + ) + {} }; @@ -207,6 +312,10 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#include "adjointSolverI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + #endif // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolverI.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolverI.H new file mode 100644 index 0000000000000000000000000000000000000000..cc02748fb1fd72f799af4af7889a4bb0b1b88475 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/adjointSolver/adjointSolverI.H @@ -0,0 +1,78 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +inline const Foam::word& Foam::adjointSolver::primalSolverName() const +{ + return primalSolverName_; +} + + +inline const Foam::primalSolver& Foam::adjointSolver::getPrimalSolver() const +{ + return mesh_.lookupObject<primalSolver>(primalSolverName_); +} + + +inline Foam::primalSolver& Foam::adjointSolver::getPrimalSolver() +{ + return + const_cast<primalSolver&> + ( + mesh_.lookupObject<primalSolver>(primalSolverName_) + ); +} + + +inline const Foam::objectiveManager& +Foam::adjointSolver::getObjectiveManager() const +{ + return objectiveManager_; +} + + +inline Foam::objectiveManager& Foam::adjointSolver::getObjectiveManager() +{ + return objectiveManager_; +} + + +inline bool Foam::adjointSolver::isConstraint() +{ + return isConstraint_; +} + + +inline bool Foam::adjointSolver::isDoubleSidedConstraint() +{ + return isDoubleSidedConstraint_; +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C index 926071a5b6d0bd339aafae8a86c2a0281beba50a..1b93b635c386c4dee95a86d1994b6cde3bc62dcb 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.C @@ -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 @@ -58,7 +58,7 @@ Foam::incompressibleAdjointVars& Foam::adjointSimple::allocateVars() ( mesh_, solverControl_(), - objectiveManagerPtr_(), + objectiveManager_, primalVars_ ) ); @@ -66,20 +66,6 @@ Foam::incompressibleAdjointVars& Foam::adjointSimple::allocateVars() } -void Foam::adjointSimple::addExtraSchemes() -{ - if (adjointVars_.useSolverNameForFields()) - { - WarningInFunction - << "useSolverNameForFields is set to true for adjointSolver " - << solverName() << nl << tab - << "Appending variable names with the solver name" << nl << tab - << "Please adjust the necessary entries in fvSchemes and fvSolution" - << nl << endl; - } -} - - void Foam::adjointSimple::continuityErrors() { const surfaceScalarField& phia = adjointVars_.phiaInst(); @@ -99,6 +85,12 @@ void Foam::adjointSimple::continuityErrors() } +void Foam::adjointSimple::preCalculateSensitivities() +{ + adjointSensitivity_->accumulateIntegrand(scalar(1)); +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::adjointSimple::adjointSimple @@ -106,14 +98,21 @@ Foam::adjointSimple::adjointSimple fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ) : - incompressibleAdjointSolver(mesh, managerType, dict, primalSolverName), + incompressibleAdjointSolver + ( + mesh, + managerType, + dict, + primalSolverName, + solverName + ), solverControl_(SIMPLEControl::New(mesh, managerType, *this)), adjointVars_(allocateVars()), - cumulativeContErr_(Zero), - adjointSensitivity_(nullptr) + cumulativeContErr_(Zero) { ATCModel_.reset ( @@ -126,7 +125,6 @@ Foam::adjointSimple::adjointSimple ).ptr() ); - addExtraSchemes(); setRefCell ( adjointVars_.paInst(), @@ -134,67 +132,21 @@ Foam::adjointSimple::adjointSimple solverControl_().pRefCell(), solverControl_().pRefValue() ); - - if (computeSensitivities_) - { - const IOdictionary& optDict = - mesh.lookupObject<IOdictionary>("optimisationDict"); - - adjointSensitivity_.reset - ( - incompressible::adjointSensitivity::New - ( - mesh, - optDict.subDict("optimisation").subDict("sensitivities"), - *this - ).ptr() - ); - // Read stored sensitivities, if they exist - // Need to know the size of the sensitivity field, retrieved after the - // allocation of the corresponding object - if (dictionary::found("sensitivities")) - { - sensitivities_ = - tmp<scalarField>::New - ( - "sensitivities", - *this, - adjointSensitivity_().getSensitivities().size() - ); - } - } + allocateSensitivities(); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::adjointSimple::readDict(const dictionary& dict) +void Foam::adjointSimple::solveIter() { - if (incompressibleAdjointSolver::readDict(dict)) + solverControl_().incrementIter(); + if (solverControl_().performIter()) { - if (adjointSensitivity_) - { - const IOdictionary& optDict = - mesh_.lookupObject<IOdictionary>("optimisationDict"); - - adjointSensitivity_().readDict - ( - optDict.subDict("optimisation").subDict("sensitivities") - ); - } - - return true; + preIter(); + mainIter(); + postIter(); } - - return false; -} - - -void Foam::adjointSimple::solveIter() -{ - preIter(); - mainIter(); - postIter(); } @@ -236,7 +188,7 @@ void Foam::adjointSimple::mainIter() UaEqn.boundaryManipulate(Ua.boundaryFieldRef()); // Add sources from volume-based objectives - objectiveManagerPtr_().addUaEqnSource(UaEqn); + objectiveManager_.addSource(UaEqn); // Add ATC term ATCModel_->addATC(UaEqn); @@ -321,8 +273,8 @@ void Foam::adjointSimple::mainIter() { dimensionedScalar maxUa = gMax(mag(Ua)()); dimensionedScalar maxpa = gMax(mag(pa)()); - Info<< "Max mag of adjoint velocity = " << maxUa.value() << endl; - Info<< "Max mag of adjoint pressure = " << maxpa.value() << endl; + Info<< "Max mag (" << Ua.name() << ") = " << maxUa.value() << endl; + Info<< "Max mag (" << pa.name() << ") = " << maxpa.value() << endl; } } @@ -362,67 +314,12 @@ bool Foam::adjointSimple::loop() void Foam::adjointSimple::preLoop() { - // Reset mean fields before solving + // Reset initial and mean fields before solving + adjointVars_.restoreInitValues(); adjointVars_.resetMeanFields(); } -void Foam::adjointSimple::computeObjectiveSensitivities() -{ - if (computeSensitivities_) - { - adjointSensitivity_->accumulateIntegrand(scalar(1)); - const scalarField& sens = adjointSensitivity_->calculateSensitivities(); - if (!sensitivities_) - { - sensitivities_.reset(new scalarField(sens.size(), Zero)); - } - sensitivities_.ref() = sens; - } - else - { - sensitivities_.reset(new scalarField()); - } -} - - -const Foam::scalarField& Foam::adjointSimple::getObjectiveSensitivities() -{ - if (!sensitivities_) - { - computeObjectiveSensitivities(); - } - - return sensitivities_(); -} - - -void Foam::adjointSimple::clearSensitivities() -{ - if (computeSensitivities_) - { - adjointSensitivity_->clearSensitivities(); - adjointSolver::clearSensitivities(); - } -} - - -Foam::sensitivity& Foam::adjointSimple::getSensitivityBase() -{ - if (!adjointSensitivity_) - { - FatalErrorInFunction - << "Sensitivity object not allocated" << nl - << "Turn computeSensitivities on in " - << solverName_ - << nl << nl - << exit(FatalError); - } - - return adjointSensitivity_(); -} - - void Foam::adjointSimple::addMomentumSource(fvVectorMatrix& matrix) { // Does nothing @@ -440,7 +337,48 @@ void Foam::adjointSimple::updatePrimalBasedQuantities() incompressibleAdjointSolver::updatePrimalBasedQuantities(); // Update objective function related quantities - objectiveManagerPtr_->updateAndWrite(); + objectiveManager_.updateAndWrite(); +} + + +void Foam::adjointSimple::addTopOFvOptions() const +{ + // Determine number of variables related to the adjoint turbulence model + autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence = + adjointVars_.adjointTurbulence(); + const wordList& turbVarNames = + adjointTurbulence().getAdjointTMVariablesBaseNames(); + label nTurbVars(turbVarNames.size()); + if (adjointTurbulence().includeDistance()) + { + nTurbVars++; + } + + // Determine names of fields to be added to the dictionary + wordList names(1 + nTurbVars); + label varID(0); + names[varID++] = adjointVars_.UaInst().name(); + for (const word& turbName : turbVarNames) + { + names[varID++] = turbName; + } + if (adjointTurbulence().includeDistance()) + { + names[varID++] = + word(useSolverNameForFields() ? "da" + solverName_ : "da"); + } + + // Add entries to dictionary + const word dictName("topOSource" + solverName_); + dictionary optionDict(dictName); + optionDict.add<word>("type", "topOSource"); + optionDict.add<wordList>("names", names); + optionDict.add<word>("function", "linear"); + optionDict.add<word>("interpolationField", "beta"); + + // Construct and append fvOption + fv::optionList& fvOptions(fv::options::New(this->mesh_)); + fvOptions.push_back(fv::option::New(dictName, optionDict, mesh_)); } diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H index 145e85b53e4c7adffd852b063a3c53ca34687596..3a6f74005265073076e898f25ce0afe37c08ec6d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/adjointSimple/adjointSimple.H @@ -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 @@ -49,9 +49,6 @@ Description #include "incompressibleAdjointSolver.H" #include "SIMPLEControl.H" -#include "incompressibleVars.H" -#include "incompressibleAdjointVars.H" -#include "adjointSensitivityIncompressible.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -93,9 +90,6 @@ protected: //- Cumulative continuity error scalar cumulativeContErr_; - //- Sensitivity Derivatives engine - autoPtr<incompressible::adjointSensitivity> adjointSensitivity_; - // Protected Member Functions @@ -103,16 +97,12 @@ protected: //- for convenience in the rest of the class. incompressibleAdjointVars& allocateVars(); - //- In case variable names are different than the base ones, - //- add extra schemes and relaxation factors to the appropriate dicts - // Note: 160813: Changes in the baseline solution and fvSchemes classes - // have to be made in order to add schemes in the dict at run time. - // Not supported for now - void addExtraSchemes(); - //- Compute continuity errors void continuityErrors(); + //- Accumulate the sensitivities integrand before calculating them + virtual void preCalculateSensitivities(); + public: @@ -130,7 +120,8 @@ public: fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ); @@ -140,10 +131,6 @@ public: // Member Functions - //- Read dict if updated - virtual bool readDict(const dictionary& dict); - - // Evolution //- Execute one iteration of the solution algorithm @@ -167,19 +154,6 @@ public: //- Functions to be called before loop virtual void preLoop(); - //- Compute sensitivities of the underlaying objectives - virtual void computeObjectiveSensitivities(); - - //- Grab a reference to the computed sensitivities - virtual const scalarField& getObjectiveSensitivities(); - - //- Clears the sensitivity field known by the adjoint solver - //- and zeros sensitivities constituents - virtual void clearSensitivities(); - - //- Return the base sensitivity object - virtual sensitivity& getSensitivityBase(); - // Source terms to be added to the adjoint equations @@ -189,6 +163,7 @@ public: //- Source terms for the continuity equation virtual void addPressureSource(fvScalarMatrix& matrix); + //- Update primal based quantities //- related to the objective functions. // Also writes the objective function values to files. @@ -197,6 +172,9 @@ public: // objectives of non-converged linearSearch iterations virtual void updatePrimalBasedQuantities(); + //- Add fvOptions for TopO + virtual void addTopOFvOptions() const; + //- Write average iteration virtual bool writeData(Ostream& os) const; }; diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C index c5691c4477c2f291dceaaffbc0f70161f779486e..16296e88fb32b41bb2f583d0182ed4d305f76cff 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.C @@ -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 @@ -30,6 +30,8 @@ License #include "incompressibleAdjointSolver.H" #include "incompressiblePrimalSolver.H" #include "wallFvPatch.H" +#include "adjointBoundaryConditions.H" +#include "adjointBoundaryConditionsFwd.H" #include "addToRunTimeSelectionTable.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // @@ -47,6 +49,38 @@ namespace Foam } +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +bool Foam::incompressibleAdjointSolver::hasBCdxdbMult +( + const labelHashSet& sensitivityPatchIDs +) +{ + if (hasBCdxdbMult_.bad()) + { + const volVectorField& Ua = getAdjointVars().Ua(); + hasBCdxdbMult_ = false; + for (const label patchI : sensitivityPatchIDs) + { + const fvPatchVectorField& Uab = Ua.boundaryField()[patchI]; + if (isA<adjointVectorBoundaryCondition>(Uab)) + { + adjointVectorBoundaryCondition& abc = + refCast<adjointVectorBoundaryCondition> + (const_cast<fvPatchVectorField&>(Uab)); + tmp<tensorField> dxdbMult = abc.dxdbMult(); + if (dxdbMult) + { + hasBCdxdbMult_ = true; + break; + } + } + } + } + return hasBCdxdbMult_; +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::incompressibleAdjointSolver::incompressibleAdjointSolver @@ -54,16 +88,18 @@ Foam::incompressibleAdjointSolver::incompressibleAdjointSolver fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ) : - adjointSolver(mesh, managerType, dict, primalSolverName), + adjointSolver(mesh, managerType, dict, primalSolverName, solverName), primalVars_ ( mesh.lookupObjectRef<incompressiblePrimalSolver>(primalSolverName). getIncoVars() ), - ATCModel_(nullptr) + ATCModel_(nullptr), + hasBCdxdbMult_(Switch::INVALID) {} @@ -75,7 +111,8 @@ Foam::incompressibleAdjointSolver::New fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ) { const word solverType(dict.get<word>("solver")); @@ -95,29 +132,13 @@ Foam::incompressibleAdjointSolver::New return autoPtr<incompressibleAdjointSolver> ( - ctorPtr(mesh, managerType, dict, primalSolverName) + ctorPtr(mesh, managerType, dict, primalSolverName, solverName) ); } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::incompressibleAdjointSolver::readDict(const dictionary& dict) -{ - if (adjointSolver::readDict(dict)) - { - return true; - } - - return false; -} - -bool Foam::incompressibleAdjointSolver::useSolverNameForFields() const -{ - return getAdjointVars().useSolverNameForFields(); -} - - const Foam::incompressibleVars& Foam::incompressibleAdjointSolver::getPrimalVars() const { @@ -152,6 +173,38 @@ Foam::incompressibleAdjointSolver::getATCModel() const } +bool Foam::incompressibleAdjointSolver::includeDistance() const +{ + return getAdjointVars().adjointTurbulence()->includeDistance(); +} + + +Foam::dimensionSet Foam::incompressibleAdjointSolver::daDimensions() const +{ + return sqr(dimLength)/pow3(dimTime); +} + + +Foam::dimensionSet Foam::incompressibleAdjointSolver::maDimensions() const +{ + return pow3(dimLength/dimTime); +} + + +Foam::tmp<Foam::volScalarField> +Foam::incompressibleAdjointSolver::adjointEikonalSource() +{ + return getAdjointVars().adjointTurbulence()->distanceSensitivities(); +} + + +Foam::tmp<Foam::volScalarField> +Foam::incompressibleAdjointSolver::yWall() const +{ + return getPrimalVars().RASModelVariables()->d(); +} + + Foam::autoPtr<Foam::ATCModel>& Foam::incompressibleAdjointSolver::getATCModel() { return ATCModel_; @@ -169,14 +222,17 @@ void Foam::incompressibleAdjointSolver::updatePrimalBasedQuantities() } -Foam::tmp<Foam::volTensorField> -Foam::incompressibleAdjointSolver::computeGradDxDbMultiplier() +void Foam::incompressibleAdjointSolver::accumulateGradDxDbMultiplier +( + volTensorField& gradDxDbMult, + const scalar dt +) { /* addProfiling ( incompressibleAdjointSolver, - "incompressibleAdjointSolver::computeGradDxDbMultiplier" + "incompressibleAdjointSolver::accumulateGradDxDbMultiplier" ); */ autoPtr<incompressibleAdjoint::adjointRASModel>& adjointRAS @@ -215,53 +271,32 @@ Foam::incompressibleAdjointSolver::computeGradDxDbMultiplier() tmp<volScalarField> tnuEff = adjointRAS->nuEff(); tmp<volSymmTensorField> stress = tnuEff()*twoSymm(gradU); - // Note: - // term4 (Ua & grad(stress)) is numerically tricky. Its div leads to third - // order spatial derivs in E-SI based computations. Applying the product - // derivative rule (putting Ua inside the grad) gives better results in - // NACA0012, SA, WF. However, the original formulation should be kept at - // the boundary in order to respect the Ua boundary conditions (necessary - // for E-SI to give the same sens as FI). A mixed approach is hence - // followed - - // Term 3, used also to allocated the return field tmp<volTensorField> tgradUa = fvc::grad(Ua); - auto tflowTerm = + + // Return field + auto tflowTerm + ( tmp<volTensorField>::New ( - "flowTerm", - - tnuEff*(gradU & twoSymm(tgradUa())) - ); + IOobject + ( + "flowTerm", + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero), + fvPatchFieldBase::zeroGradientType() + ) + ); volTensorField& flowTerm = tflowTerm.ref(); - // Term 4, only for the internal field - flowTerm.ref() += - ( - - (tgradUa & stress()) - + fvc::grad(Ua & stress()) - )().internalField(); + // Term 3 + flowTerm = - tnuEff*(gradU & twoSymm(tgradUa())); + // Term 4 + flowTerm += fvc::grad(Ua & stress()) - (tgradUa & stress()); - // Boundary conditions from term 4 - for (label idir = 0; idir < pTraits<vector>::nComponents; ++idir) - { - autoPtr<volVectorField> stressDirPtr - ( - createZeroFieldPtr<vector> - (mesh_, "stressDir", stress().dimensions()) - ); - // Components need to be in the [0-5] range since stress is a - // volSymmTensorField - unzipRow(stress(), idir, stressDirPtr()); - volTensorField gradStressDir(fvc::grad(stressDirPtr())); - forAll(mesh_.boundary(), pI) - { - if (!isA<coupledFvPatch>(mesh_.boundary()[pI])) - { - flowTerm.boundaryFieldRef()[pI] += - Ua.component(idir)().boundaryField()[pI] - *gradStressDir.boundaryField()[pI]; - } - } - } // Release memory stress.clear(); @@ -279,8 +314,7 @@ Foam::incompressibleAdjointSolver::computeGradDxDbMultiplier() flowTerm += T(adjointRAS->FISensitivityTerm()); // Term 7, term from objective functions - PtrList<objective>& functions - (objectiveManagerPtr_->getObjectiveFunctions()); + PtrList<objective>& functions = objectiveManager_.getObjectiveFunctions(); for (objective& objI : functions) { @@ -292,20 +326,137 @@ Foam::incompressibleAdjointSolver::computeGradDxDbMultiplier() flowTerm.correctBoundaryConditions(); + gradDxDbMult += flowTerm.T()*dt; //profiling::writeNow(); +} + + +void Foam::incompressibleAdjointSolver::accumulateDivDxDbMultiplier +( + autoPtr<scalarField>& divDxDbMult, + const scalar dt +) +{ + PtrList<objective>& functions = objectiveManager_.getObjectiveFunctions(); + for (objective& func : functions) + { + if (func.hasDivDxDbMult()) + { + divDxDbMult() += + func.weight()*func.divDxDbMultiplier().primitiveField()*dt; + } + } +} + + +void Foam::incompressibleAdjointSolver::accumulateGeometryVariationsMultipliers +( + autoPtr<boundaryVectorField>& dSfdbMult, + autoPtr<boundaryVectorField>& dnfdbMult, + autoPtr<boundaryVectorField>& dxdbDirectMult, + autoPtr<pointBoundaryVectorField>& pointDxDbDirectMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt +) +{ + 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(); + if (func.hasdSdbMult()) + { + dSfdbMult()[patchI] += wei*func.dSdbMultiplier(patchI)*dt; + } + if (func.hasdndbMult()) + { + dnfdbMult()[patchI] += wei*func.dndbMultiplier(patchI)*magSfDt; + } + if (func.hasdxdbDirectMult()) + { + dxdbDirectMult()[patchI] += + wei*func.dxdbDirectMultiplier(patchI)*magSfDt; + } + } + } +} - return (tflowTerm); + +void Foam::incompressibleAdjointSolver::accumulateBCSensitivityIntegrand +( + autoPtr<boundaryVectorField>& bcDxDbMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt +) +{ + if (!hasBCdxdbMult(sensitivityPatchIDs)) + { + return; + } + + // Grab references + const volVectorField& Ua = getAdjointVars().Ua(); + const autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence = + getAdjointVars().adjointTurbulence(); + + // Fields needed to calculate adjoint sensitivities + const autoPtr<incompressible::RASModelVariables>& + turbVars = primalVars_.RASModelVariables(); + const singlePhaseTransportModel& lamTransp = primalVars_.laminarTransport(); + volScalarField nuEff(lamTransp.nu() + turbVars->nut()); + tmp<volTensorField> tgradUa = fvc::grad(Ua); + const volTensorField::Boundary& gradUabf = tgradUa.cref().boundaryField(); + + // Avoid updating the event number to keep consistency with cases caching + // gradUa + auto& UaBoundary = getAdjointVars().Ua().boundaryFieldRef(false); + auto& nuEffBoundary = nuEff.boundaryField(); + + for (const label patchI : sensitivityPatchIDs) + { + fvPatchVectorField& Uab = UaBoundary[patchI]; + if (isA<adjointVectorBoundaryCondition>(Uab)) + { + const fvPatch& patch = mesh_.boundary()[patchI]; + tmp<vectorField> tnf = patch.nf(); + const scalarField& magSf = patch.magSf(); + + tmp<vectorField> DvDbMult = + nuEffBoundary[patchI]*(Uab.snGrad() + (gradUabf[patchI] & tnf)) + // - (nf*pa.boundaryField()[patchI]) + + adjointTurbulence().adjointMomentumBCSource()[patchI]; + bcDxDbMult()[patchI] += + ( + DvDbMult + & refCast<adjointVectorBoundaryCondition>(Uab).dxdbMult() + )*magSf*dt; + } + } } -void Foam::incompressibleAdjointSolver::additionalSensitivityMapTerms +void Foam::incompressibleAdjointSolver::accumulateOptionsDxDbMultiplier ( - boundaryVectorField& sensitivityMap, - const labelHashSet& patchIDs, + vectorField& optionsDxDbMult, const scalar dt ) { - // Does nothing in base + // Terms from fvOptions - missing contributions from turbulence models + const incompressibleAdjointVars& av = getAdjointVars(); + vectorField temp(mesh_.nCells(), Zero); + fv::options::New(this->mesh_).postProcessSens + ( + temp, av.UaInst().name(), av.solverName() + ); + optionsDxDbMult += temp*dt; + temp = Zero; + fv::options::New(this->mesh_).postProcessSens + ( + temp, av.paInst().name(), av.solverName() + ); + optionsDxDbMult += temp*dt; } diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.H index de5e821cab336b05e8f69b633bfd63d9d6150ee7..72523176e91fd1c858abdf92120ec0cad6f408dc 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolver.H @@ -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 @@ -79,6 +79,18 @@ protected: //- Adjoint Transpose Convection options autoPtr<ATCModel> ATCModel_; + //- Auxiliary bool to avoid a potentially expensive + //- part of the sensitivity computation + // As a Switch with delayed evaluation since adjointBoundaryConditions + // have not been allocated at the time of construction + Switch hasBCdxdbMult_; + + + // Protected Member Functions + + //- Compute, if necessary, and return the hasBCdxdbMult_ bool + bool hasBCdxdbMult(const labelHashSet& sensitivityPatchIDs); + public: @@ -100,9 +112,10 @@ public: fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ), - (mesh, managerType, dict, primalSolverName) + (mesh, managerType, dict, primalSolverName, solverName) ); @@ -114,7 +127,8 @@ public: fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ); @@ -126,7 +140,8 @@ public: fvMesh& mesh, const word& managerType, const dictionary& dict, - const word& primalSolverName + const word& primalSolverName, + const word& solverName ); @@ -136,13 +151,6 @@ public: // Member Functions - //- Read dict if updated - virtual bool readDict(const dictionary& dict); - - //- Should solver name be appended to fields - virtual bool useSolverNameForFields() const; - - // Access //- Access to the incompressible primal variables set @@ -160,6 +168,22 @@ public: //- Access to the ATC model autoPtr<ATCModel>& getATCModel(); + //- Should the adjoint to the eikonal equation be solved + virtual bool includeDistance() const; + + //- Return the dimensions of the adjoint distance field + virtual dimensionSet daDimensions() const; + + //- Return the dimensions of the adjoint grid displacement variable + virtual dimensionSet maDimensions() const; + + //- Return the source the adjoint eikonal equation + virtual tmp<volScalarField> adjointEikonalSource(); + + //- Return the distance field, to be used in the solution of the + //- adjoint eikonal PDE + virtual tmp<volScalarField> yWall() const; + // Evolution @@ -170,22 +194,62 @@ public: // Sensitivity related functions - //- Compute the multiplier for grad(dxdb) - // Used in shape sensitivity derivatives, computed with the FI - // and E-SI approaches - virtual tmp<volTensorField> computeGradDxDbMultiplier(); - - //- Terms to be added to the sensitivity map, depending - //- on the adjoint solver - // The typical terms associated with the typical incompressible - // flow equations are included in the sensitivity classes. - // This is to be used whenever additional physics is added - virtual void additionalSensitivityMapTerms - ( - boundaryVectorField& sensitivityMap, - const labelHashSet& patchIDs, - const scalar dt - ); + // Functions related to the computation of sensitivity derivatives + // All functions get the field to accumulate their contibution on + // as an argument. Should be implemented by the derived classes + // if the physics there adds terms to the sensitivity derivatives + + // Shape optimisation + + //- Compute the multiplier for grad(dxdb) + // Used in shape sensitivity derivatives, computed with + // the FI and E-SI approaches + virtual void accumulateGradDxDbMultiplier + ( + volTensorField& gradDxDbMult, + const scalar dt + ); + + //- Compute the multiplier for div(dxdb) + // Used in shape sensitivity derivatives, computed with + // the FI and E-SI approaches + virtual void accumulateDivDxDbMultiplier + ( + autoPtr<scalarField>& divDxDbMult, + const scalar dt + ); + + //- Accumulate the multipliers of geometric quantities + //- defined at the boundary, usually through an objective + //- or constraint function + virtual void accumulateGeometryVariationsMultipliers + ( + autoPtr<boundaryVectorField>& dSfdbMult, + autoPtr<boundaryVectorField>& dnfdbMult, + autoPtr<boundaryVectorField>& dxdbDirectMult, + autoPtr<pointBoundaryVectorField>& pointDxDirectDbMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt + ); + + //- Contributions from boundary functions that inlcude + //- geometric aspects in them and change when the geometry + //- is displaced, e.g. rotationWallVelocity + virtual void accumulateBCSensitivityIntegrand + ( + autoPtr<boundaryVectorField>& bcDxDbMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt + ); + + //- Contributions from fvOptions that inlcude + //- geometric aspects in them and change when the geometry + //- is displaced, e.g. MRF + virtual void accumulateOptionsDxDbMultiplier + ( + vectorField& optionsDxDbMult, + const scalar dt + ); // IO diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolverTemplates.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolverTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..ebadf74550f356772ecfdfd16c3772f8e279075d --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/incompressible/incompressibleAdjointSolver/incompressibleAdjointSolverTemplates.C @@ -0,0 +1,58 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2022-2023 PCOpt/NTUA + Copyright (C) 2022-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/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +template<class Type> +tmp<surfaceInterpolationScheme<Type>> +Foam::incompressibleAdjointSolver::convectionScheme +( + const word& varName, + word phiName +) const +{ + const surfaceScalarField& phi = primalVars_.phi(); + if (phiName == word::null) + { + phiName = primalVars_.phiInst().name(); + } + word divEntry("div(" + phiName + ',' + varName +')'); + ITstream& divScheme = mesh_.divScheme(divEntry); + // Skip the first entry which might be 'bounded' or 'Gauss'. + // If it is 'bounded', skip the second entry as well + word discarded(divScheme); + if (discarded == "bounded") + { + discarded = word(divScheme); + } + return surfaceInterpolationScheme<Type>::New(mesh_, phi, divScheme); +} + + +// ************************************************************************* // + diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/null/adjointNull.C b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/null/adjointNull.C new file mode 100644 index 0000000000000000000000000000000000000000..ae115b2c5e6b857277033af39f957d8cc1dc9afa --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/null/adjointNull.C @@ -0,0 +1,238 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "adjointNull.H" +#include "findRefCell.H" +#include "constrainHbyA.H" +#include "adjustPhi.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ + defineTypeNameAndDebug(adjointNull, 0); + addToRunTimeSelectionTable + ( + adjointSolver, + adjointNull, + adjointSolver + ); +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void Foam::adjointNull::preCalculateSensitivities() +{ + adjointSensitivity_->accumulateIntegrand(scalar(1)); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::adjointNull::adjointNull +( + fvMesh& mesh, + const word& managerType, + const dictionary& dict, + const word& primalSolverName, + const word& solverName +) +: + adjointSolver + ( + mesh, + managerType, + dict, + primalSolverName, + solverName + ) +{ + allocateSensitivities(); +} + + +// * * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::adjointNull> Foam::adjointNull::New +( + fvMesh& mesh, + const word& managerType, + const dictionary& dict, + const word& primalSolverName, + const word& solverName +) +{ + return autoPtr<adjointNull> + ( + new adjointNull + ( + mesh, + managerType, + dict, + primalSolverName, + solverName + ) + ); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::word Foam::adjointNull::simulationType() const +{ + return word("null"); +} + + +Foam::dimensionSet Foam::adjointNull::maDimensions() const +{ + return pow3(dimLength/dimTime); +} + + +void Foam::adjointNull::solveIter() +{ + // Does nothing +} + + +void Foam::adjointNull::solve() +{ + // Does nothing +} + + +bool Foam::adjointNull::loop() +{ + return false; +} + + +void Foam::adjointNull::updatePrimalBasedQuantities() +{ + // Update objective function related quantities + objectiveManager_.updateAndWrite(); +} + + +void Foam::adjointNull::accumulateGradDxDbMultiplier +( + volTensorField& gradDxDbMult, + const scalar dt +) +{ + tmp<volTensorField> tsens + ( + tmp<volTensorField>::New + ( + IOobject + ( + "flowTerm", + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero), + fvPatchFieldBase::zeroGradientType() + ) + ); + volTensorField& sens = tsens.ref(); + + PtrList<objective>& functions = objectiveManager_.getObjectiveFunctions(); + + for (objective& objI : functions) + { + if (objI.hasGradDxDbMult()) + { + sens += objI.weight()*objI.gradDxDbMultiplier(); + } + } + sens.correctBoundaryConditions(); + + gradDxDbMult += sens.T()*dt; +} + + +void Foam::adjointNull::accumulateDivDxDbMultiplier +( + autoPtr<scalarField>& divDxDbMult, + const scalar dt +) +{ + PtrList<objective>& functions = objectiveManager_.getObjectiveFunctions(); + for (objective& func : functions) + { + if (func.hasDivDxDbMult()) + { + divDxDbMult() += + func.weight()*func.divDxDbMultiplier().primitiveField()*dt; + } + } +} + + +void Foam::adjointNull::accumulateGeometryVariationsMultipliers +( + autoPtr<boundaryVectorField>& dSfdbMult, + autoPtr<boundaryVectorField>& dnfdbMult, + autoPtr<boundaryVectorField>& dxdbDirectMult, + autoPtr<pointBoundaryVectorField>& pointDxDbDirectMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt +) +{ + 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()); + if (func.hasdSdbMult()) + { + dSfdbMult()[patchI] += wei*func.dSdbMultiplier(patchI)*dt; + } + if (func.hasdndbMult()) + { + dnfdbMult()[patchI] += wei*func.dndbMultiplier(patchI)*magSfDt; + } + if (func.hasdxdbDirectMult()) + { + dxdbDirectMult()[patchI] += + wei*func.dxdbDirectMultiplier(patchI)*magSfDt; + } + } + } +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/null/adjointNull.H b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/null/adjointNull.H new file mode 100644 index 0000000000000000000000000000000000000000..aa2a0bdf099d5242c4c637ccfc91b04a9c76a59b --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/adjointSolvers/null/adjointNull.H @@ -0,0 +1,186 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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/>. + +Class + Foam::adjointNull + +Description + Dummy adjoint solver. + Used to add the derivatives of geometric constraints which do not require + the solution of adjoint PDEs + +\*---------------------------------------------------------------------------*/ + +#ifndef adjointNull_H +#define adjointNull_H + +#include "adjointSolver.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +/*---------------------------------------------------------------------------*\ + Class adjointNull Declaration +\*---------------------------------------------------------------------------*/ + +class adjointNull +: + public adjointSolver +{ + +private: + + // Private Member Functions + + //- No copy construct + adjointNull(const adjointNull&) = delete; + + //- No copy assignment + void operator=(const adjointNull&) = delete; + + +protected: + + // Protected data + + //- Accumulate the sensitivities integrand before calculating them + virtual void preCalculateSensitivities(); + + +public: + + // Static Data Members + + //- Run-time type information + TypeName("null"); + + + // Constructors + + //- Construct from mesh and dictionary + adjointNull + ( + fvMesh& mesh, + const word& managerType, + const dictionary& dict, + const word& primalSolverName, + const word& solverName + ); + + + // Selectors + + //- Return a reference to the selected turbulence model + static autoPtr<adjointNull> New + ( + fvMesh& mesh, + const word& managerType, + const dictionary& dict, + const word& primalSolverName, + const word& solverName + ); + + + //- Destructor + virtual ~adjointNull() = default; + + + // Member Functions + + // Access + + //- Return the type of simulation this solver pertains to + virtual const word simulationType() const; + + //- Return the dimensions of the adjoint grid displacement variable + virtual dimensionSet maDimensions() const; + + + // Evolution + + //- Execute one iteration of the solution algorithm + virtual void solveIter(); + + //- Main control loop + virtual void solve(); + + //- Looper (advances iters, time step) + virtual bool loop(); + + //- Update primal based quantities related to the objective + //- functions. + // Also writes the objective function values to files. + virtual void updatePrimalBasedQuantities(); + + // Functions related to the computation of sensitivity derivatives + + // Shape optimisation + + //- Compute the multiplier for grad(dxdb) + // Used in shape sensitivity derivatives, computed with + // the FI and E-SI approaches + virtual void accumulateGradDxDbMultiplier + ( + volTensorField& gradDxDbMult, + const scalar dt + ); + + //- Compute the multiplier for div(dxdb) + // Used in shape sensitivity derivatives, computed with + // the FI and E-SI approaches + virtual void accumulateDivDxDbMultiplier + ( + autoPtr<scalarField>& divDxDbMult, + const scalar dt + ); + + //- Accumulate the multipliers of geometric quantities + //- defined at the boundary, usually through an objective + //- or constraint function + virtual void accumulateGeometryVariationsMultipliers + ( + autoPtr<boundaryVectorField>& dSfdbMult, + autoPtr<boundaryVectorField>& dnfdbMult, + autoPtr<boundaryVectorField>& dxdbDirectMult, + autoPtr<pointBoundaryVectorField>& pointDxDirectDbMult, + const labelHashSet& sensitivityPatchIDs, + const scalar dt + ); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace Foam + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C index 575ea54196322434d298e27361ca3574a258e198..67b44b9bdbd1afde316d5e4dad5e9eb23baf35cb 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.C @@ -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 @@ -61,10 +61,17 @@ Foam::RASTurbulenceModel::RASTurbulenceModel ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ) : - incompressiblePrimalSolver(mesh, managerType, dict), + incompressiblePrimalSolver + ( + mesh, + managerType, + dict, + solverName + ), solverControl_(SIMPLEControl::New(mesh, managerType, *this)), incoVars_(allocateVars()) { diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.H index b4dd92895af71b28a3352ebde41f39089755b25a..2090f90c8929efec015bf6ef01508fea62c9860d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/RASTurbulenceModel/RASTurbulenceModel.H @@ -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 @@ -98,7 +98,8 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ); diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C index 5fa3f120c8415f2421cf3d6709bb225800459cc3..447c9a1880634cc7f5faf79b6ea04735b5053d36 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.C @@ -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-2021 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -55,10 +55,11 @@ Foam::incompressiblePrimalSolver::incompressiblePrimalSolver ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ) : - primalSolver(mesh, managerType, dict), + primalSolver(mesh, managerType, dict, solverName), phiReconstructionTol_ ( dict.subOrEmptyDict("fieldReconstruction"). @@ -79,7 +80,8 @@ Foam::incompressiblePrimalSolver::New ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ) { const word solverType(dict.get<word>("solver")); @@ -99,7 +101,7 @@ Foam::incompressiblePrimalSolver::New return autoPtr<incompressiblePrimalSolver> ( - ctorPtr(mesh, managerType, dict) + ctorPtr(mesh, managerType, dict, solverName) ); } @@ -144,12 +146,6 @@ Foam::incompressiblePrimalSolver::getObjectiveFunctions() const } -bool Foam::incompressiblePrimalSolver::useSolverNameForFields() const -{ - return vars_().useSolverNameForFields(); -} - - const Foam::incompressibleVars& Foam::incompressiblePrimalSolver::getIncoVars() const { diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.H index 9506e59fb5b82767ffc71f7f7d0c38f1dbe6f962..dcfc780640b764cc0a3e969b2a06430c59dfb12f 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/incompressiblePrimalSolver/incompressiblePrimalSolver.H @@ -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 @@ -95,9 +95,10 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ), - (mesh, managerType, dict) + (mesh, managerType, dict, solverName) ); @@ -108,7 +109,8 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ); @@ -119,7 +121,8 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ); @@ -132,9 +135,6 @@ public: //- Read dict if updated virtual bool readDict(const dictionary& dict); - //- Should solver name be appended to fields - bool useSolverNameForFields() const; - // Access diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.C index 90a3343709402298f4ea9bc2b788485d4ca3f82c..06cd7955285727c9515d985e9257c9b4a1c0c666 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.C @@ -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 @@ -92,13 +92,20 @@ Foam::simple::simple ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ) : - incompressiblePrimalSolver(mesh, managerType, dict), + incompressiblePrimalSolver + ( + mesh, + managerType, + dict, + solverName + ), solverControl_(SIMPLEControl::New(mesh, managerType, *this)), incoVars_(allocateVars()), - MRF_(mesh, word(useSolverNameForFields() ? solverName() : word::null)), + MRF_(mesh, word(useSolverNameForFields() ? solverName_ : word::null)), cumulativeContErr_(Zero), objectives_(0) { diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.H index 335df8280fc79f9045f4903c3a87f31973efd144..2635e0ba7c3944078a35f216469e9d5484467263 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/incompressible/simple/simple.H @@ -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 @@ -117,7 +117,8 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ); diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.C index 1f4c9e43f17f129866154b4cdfe0aa401ac46dce..8ea643c630072fac9968ac308af3968d3ed7c685 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.C @@ -46,10 +46,11 @@ Foam::primalSolver::primalSolver ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ) : - solver(mesh, managerType, dict) + solver(mesh, managerType, dict, solverName) {} @@ -59,7 +60,8 @@ Foam::autoPtr<Foam::primalSolver> Foam::primalSolver::New ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ) { const word solverType(dict.get<word>("type")); @@ -77,7 +79,8 @@ Foam::autoPtr<Foam::primalSolver> Foam::primalSolver::New ) << exit(FatalIOError); } - return autoPtr<primalSolver>(ctorPtr(mesh, managerType, dict)); + return + autoPtr<primalSolver>(ctorPtr(mesh, managerType, dict, solverName)); } diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.H index 2a859ff1a7539907a5c3e099d32b1ef130d261c9..c65a80d3112238e7b9bec1cc08efab2eebbc3c30 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/primalSolvers/primalSolver/primalSolver.H @@ -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 @@ -84,9 +84,10 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ), - (mesh, managerType, dict) + (mesh, managerType, dict, solverName) ); @@ -97,7 +98,8 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ); @@ -108,7 +110,8 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ); diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.C index 223ecde22b2e0370ec954ff4530a61ca4ecae469..2b8bb4714cd6bb41608b84d043be86381d28ab38 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.C @@ -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 @@ -42,14 +42,15 @@ Foam::solver::solver ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ) : localIOdictionary ( IOobject ( - dict.dictName(), + solverName, mesh.time().timeName(), fileName("uniform")/fileName("solvers"), mesh, @@ -62,21 +63,15 @@ Foam::solver::solver mesh_(mesh), managerType_(managerType), dict_(dict), - solverName_(dict.dictName()), - active_(dict.getOrDefault("active", true)), - optTypeSource_(nullptr), + solverName_(solverName), + active_(dict.getOrDefault<bool>("active", true)), + isMaster_(dict.getOrDefault<bool>("isMaster", true)), + useSolverNameForFields_ + (dict_.getOrDefault<bool>("useSolverNameForFields", false)), vars_(nullptr) {} -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::solver::~solver() -{ - optTypeSource_ = 0; -} - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // bool Foam::solver::readDict(const dictionary& dict) @@ -85,7 +80,7 @@ bool Foam::solver::readDict(const dictionary& dict) // Note: Slightly dangerous to change active_ while the solver is // running. At the very least, this should trigger writing before stopping. - // Additional problems if we have an adjontSolver corresponding to a + // Additional problems if we have an adjointSolver corresponding to a // constraint. To be revisited //active_ = dict.getOrDefault<bool>("active", true); @@ -93,41 +88,6 @@ bool Foam::solver::readDict(const dictionary& dict) } -const Foam::fvMesh& Foam::solver::mesh() const -{ - return mesh_; -} - -const Foam::word& Foam::solver::solverName() const -{ - return solverName_; -} - - -bool Foam::solver::active() -{ - return active_; -} - - -const Foam::dictionary& Foam::solver::dict() const -{ - return dict_; -} - - -const Foam::variablesSet& Foam::solver::getVariablesSet() const -{ - return vars_(); -} - - -Foam::variablesSet& Foam::solver::getVariablesSet() -{ - return vars_(); -} - - void Foam::solver::restoreInitValues() { // Does nothing in the base class @@ -146,16 +106,9 @@ void Foam::solver::postLoop() } -void Foam::solver::updateOptTypeSource -( - const autoPtr<volScalarField>& optSourcePtr -) +void Foam::solver::addTopOFvOptions() const { - if (optSourcePtr) - { - const volScalarField& optSource = optSourcePtr(); - optTypeSource_ = &optSource; - } + // Does nothing in the base class } diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.H index c67d3d3fb9999aed798eebb534eb6d0dc80ab432..9e72c7e8b5c32f4fdbeed8983bbe8ee9e579bc96 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solver.H @@ -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,7 +29,7 @@ Class Foam::solver Description - Base class for solution control classes + Base solver class \*---------------------------------------------------------------------------*/ @@ -72,11 +72,12 @@ protected: //- Solve equations? bool active_; - //- Pointer to a source term coming from the optimisationType - //- (e.g. porosity from topologyOptimisation) - // Will never allocate new memory, so no need to be deleted - // in the destructor - const volScalarField* optTypeSource_; + //- Is the solver the master one + // Used in cases where a solver needs to work in tandem with another + bool isMaster_; + + //- Append the variables related to the solver with it name + bool useSolverNameForFields_; //- Base variableSet pointer. // To be allocated in derived classes @@ -108,12 +109,13 @@ public: ( fvMesh& mesh, const word& managerType, - const dictionary& dict + const dictionary& dict, + const word& solverName ); //- Destructor - virtual ~solver(); + virtual ~solver() = default; // Member Functions @@ -124,25 +126,36 @@ public: // Access //- Return the solver mesh - const fvMesh& mesh() const; + inline const fvMesh& mesh() const; //- Return the solver name - const word& solverName() const; + inline const word& solverName() const; //- Use solver name as a suffix to the involved fields - virtual bool useSolverNameForFields() const = 0; + inline bool useSolverNameForFields() const; + + //- Given a variable name, return a name that is possibly appended + //- by the solverName, depending on useSolverNameForFields + inline word extendedVariableName(const word& varName) const; //- Return state of solver - virtual bool active(); + inline bool active(); //- Return the solver dictionary - virtual const dictionary& dict() const; + inline const dictionary& dict() const; //- Return constant reference to variableSet used by the solver - const variablesSet& getVariablesSet() const; + inline const variablesSet& getVariablesSet() const; //- Return non-constant reference to variableSet used by the solver - variablesSet& getVariablesSet(); + inline variablesSet& getVariablesSet(); + + //- Return the manager type + inline const word& managerType() const; + + //- Whether the solver is the master one, in case of coupled + //- solvers + inline bool isMaster() const; // Evolution @@ -165,12 +178,6 @@ public: //- Functions to be called after loop virtual void postLoop(); - //- Update source term related to optimisationType - void updateOptTypeSource - ( - const autoPtr<volScalarField>& optSourcePtr - ); - //- Main control loop. // Gets a list of function pointers to be called at the end of // each solver iteration @@ -181,9 +188,9 @@ public: List<void (Type::*)()>& funcs ); - //- Add source from optimisationType to underlaying equation - template<class Type> - void addOptimisationTypeSource(fvMatrix<Type>& matrix) const; + //- Add topO fvOptions + // Does nothing in base + virtual void addTopOFvOptions() const; // IO @@ -217,6 +224,7 @@ public: #ifdef NoRepository # include "solverTemplates.C" #endif +#include "solverI.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverI.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverI.H new file mode 100644 index 0000000000000000000000000000000000000000..1b17b69ac86eb00ad1939d453d74975032ecf5f9 --- /dev/null +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverI.H @@ -0,0 +1,91 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +const Foam::fvMesh& Foam::solver::mesh() const +{ + return mesh_; +} + + +const Foam::word& Foam::solver::solverName() const +{ + return solverName_; +} + + +bool Foam::solver::useSolverNameForFields() const +{ + return useSolverNameForFields_; +} + + +Foam::word Foam::solver::extendedVariableName(const word& varName) const +{ + return (useSolverNameForFields_ ? word(varName + solverName_) : varName); +} + + +bool Foam::solver::active() +{ + return active_; +} + + +const Foam::dictionary& Foam::solver::dict() const +{ + return dict_; +} + + +const Foam::variablesSet& Foam::solver::getVariablesSet() const +{ + return vars_(); +} + + +Foam::variablesSet& Foam::solver::getVariablesSet() +{ + return vars_(); +} + + +const Foam::word& Foam::solver::managerType() const +{ + return managerType_; +} + + +bool Foam::solver::isMaster() const +{ + return isMaster_; +} + + +// ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverTemplates.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverTemplates.C index 94fce6a37c78489a7ac61fa3fe01c5c976cbbfc3..ea45841b2b6825585bc86e114fdde0ea69eb1786 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverTemplates.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solver/solverTemplates.C @@ -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 @@ -55,20 +55,4 @@ void Foam::solver::solveWithArgs } -template<class Type> -void Foam::solver::addOptimisationTypeSource -( - fvMatrix<Type>& matrix -) const -{ - // If source has been allocated, add source * variable - if (optTypeSource_) - { - const GeometricField<Type, fvPatchField, volMesh>& psi = matrix.psi(); - - matrix += fvm::Sp(*optTypeSource_, psi); - } -} - - // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C index 6059ba45c7ac5b43b41b74aaa4feda52097a1a1c..9edba23b8fa42203f58f345cd4e612df472ec76d 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.C @@ -122,4 +122,22 @@ void Foam::SIMPLEControl::checkMeanSolution() const } +bool Foam::SIMPLEControl::converged() +{ + return simpleControl::criteriaSatisfied(); +} + + +bool Foam::SIMPLEControl::performIter() +{ + return true; +} + + +void Foam::SIMPLEControl::incrementIter() +{ + // Does nothing in base +} + + // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.H index 02a4b0de483bf442e7e0c3f9b908efa36a3207d8..8543b2b1b551011b3d48fa32ceea5941aa237cab 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/SIMPLEControl/SIMPLEControl.H @@ -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 @@ -161,6 +161,15 @@ public: //- Loop virtual bool loop() = 0; + + //- Is the solver converged + virtual bool converged(); + + //- Perform this iteration? + virtual bool performIter(); + + //- Increment iteration counter + virtual void incrementIter(); }; diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/optimisation/SIMPLEControlOpt.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/optimisation/SIMPLEControlOpt.C index 81336289bcf80d4bac9d1b8a7d33e27e9f5cd58e..c9feeab19c8f6753f1274f6aca93857f429fe0f9 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/optimisation/SIMPLEControlOpt.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/optimisation/SIMPLEControlOpt.C @@ -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 @@ -125,75 +125,97 @@ bool Foam::SIMPLEControlOpt::loop() Time& runTime = const_cast<Time&>(mesh_.time()); - // Sub-cycle time if this is the first iter - if (!subCycledTimePtr_) - { - subCycledTimePtr_.reset(new subCycleTime(runTime, nIters())); - Info<< "Solving equations for solver " - << solver_.solverName() << "\n" << endl; - deltaTSubSycle_ = runTime.deltaTValue(); - - // Reset iteration count to zero - iter_ = 0; - } - - // Increase index - subCycledTimePtr_()++; - iter_ = subCycledTimePtr_().index(); - bool doNextIter(true); - if (criteriaSatisfied()) + if (nIters() > 0) { - Info<< nl - << solver_.solverName() - << " solution converged in " - << subCycledTimePtr_->index() << " iterations" << nl << endl; - - subCycledTimePtr_->endSubCycle(); - subCycledTimePtr_.clear(); - - // Write solution before continuing to next solver - runTime.write(); - solver_.write(); - - // Check whether mean fields have not been computed due to an - // unexpectedly early convergence - checkMeanSolution(); - - doNextIter = false; + // Sub-cycle time if this is the first iter + if (!subCycledTimePtr_) + { + subCycledTimePtr_.reset(new subCycleTime(runTime, nIters())); + Info<< "Solving equations for solver " + << solver_.solverName() << "\n" << endl; + deltaTSubSycle_ = runTime.deltaTValue(); + + // Reset iteration count to zero + iter_ = 0; + + // Reset previous time index of fvMesh::data, to avoid the rare + // occurance of a solver satisfying the convergence criteria at the + // first iteration, which then causes all subsequent optimisation + // cycles to be seen as converged, irrespective of the residual + // level, since the data::prevTimeIndex_ is not updated + //mesh_.data::setPreviousTimeIndex(0); + } + + // Increase index + subCycledTimePtr_()++; + iter_ = subCycledTimePtr_().index(); + + + if (criteriaSatisfied()) + { + Info<< nl + << solver_.solverName() + << " solution converged in " + << subCycledTimePtr_->index() << " iterations" << nl << endl; + + subCycledTimePtr_->endSubCycle(); + subCycledTimePtr_.clear(); + + // Write solution before continuing to next solver + runTime.write(); + solver_.write(); + + // Check whether mean fields have not been computed due to an + // unexpectedly early convergence + checkMeanSolution(); + + doNextIter = false; + } + else if (subCycledTimePtr_->end()) + { + Info<< nl + << solver_.solverName() + << " solution reached max. number of iterations " + << subCycledTimePtr_().nSubCycles() << nl << endl; + + subCycledTimePtr_->endSubCycle(); + subCycledTimePtr_.clear(); + + // Write solution before continuing to next solver + runTime.write(); + solver_.write(); + + doNextIter = false; + } + else + { + // Since dicts are not updated when Time is sub-cycled, + // do it manually here + runTime.readModifiedObjects(); + resetDeltaT(); + + DebugInfo + << "Iteration " << subCycledTimePtr_().index() + << "|" << subCycledTimePtr_().nSubCycles() << endl; + + simpleControl::storePrevIterFields(); + + doNextIter = true; + } } - else if (subCycledTimePtr_->end()) + else { - Info<< nl + WarningInFunction + << "Number of iterations is non-positive (" << nIters() << ")." + << nl + << "Skipping the solution of the equations corresponding to solver " << solver_.solverName() - << " solution reached max. number of iterations " - << subCycledTimePtr_().nSubCycles() << nl << endl; - - subCycledTimePtr_->endSubCycle(); - subCycledTimePtr_.clear(); - - // Write solution before continuing to next solver - runTime.write(); - solver_.write(); + << nl << endl; doNextIter = false; } - else - { - // Since dicts are not updated when Time is sub-cycled, - // do it manually here - runTime.readModifiedObjects(); - resetDeltaT(); - - DebugInfo - << "Iteration " << subCycledTimePtr_().index() - << "|" << subCycledTimePtr_().nSubCycles() << endl; - - storePrevIterFields(); - - doNextIter = true; - } return doNextIter; } diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C index 8469547624b4433bf1adca7ccfc87a2e3e14dcba..5d1227122914fed917751a91ddb88fcf7c4e159e 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/SIMPLEControl/singleRun/SIMPLEControlSingleRun.C @@ -118,7 +118,7 @@ bool Foam::SIMPLEControlSingleRun::write(const bool valid) const void Foam::SIMPLEControlSingleRun::writeNow() { Time& time = const_cast<Time&>(mesh_.time()); - // Avoid writing fields if already in an outputTime iter + // Avoid writing fields if already in an writeTime iter // since results will be written by the solver class either way if (!time.writeTime()) { @@ -156,7 +156,7 @@ bool Foam::SIMPLEControlSingleRun::loop() else { initialised_ = true; - storePrevIterFields(); + simpleControl::storePrevIterFields(); } bool isRunning = runTime.loop(); diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.H index 29fa740981028f6bb24e65476d1b3c46de7162a1..f8d5f3f046c2ddd1d457d303a70c5ea936011917 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControl.H @@ -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 @@ -162,6 +162,9 @@ public: //- Whether averaging is enabled or not inline bool average() const; + + //- Return reference to the underlaying solver + inline const solver& getSolver() const; }; diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControlI.H b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControlI.H index 8817320a53d9fc6d796b110163708bc356c8a69e..8d37f646e0ab9041cb2652cb861dca5825fd93a8 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControlI.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/solverControl/solverControl/solverControlI.H @@ -110,4 +110,10 @@ inline bool Foam::solverControl::average() const } +inline const Foam::solver& Foam::solverControl::getSolver() const +{ + return solver_; +} + + // ************************************************************************* // diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C index 6bf4cbc2dfc4a9001b97ceb1ef10f6c57dea7b41..19695a6371e34ebe91cf22976e429b6053f16b02 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.C @@ -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 @@ -67,6 +67,19 @@ incompressibleAdjointVars::incompressibleAdjointVars // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // +void incompressibleAdjointVars::restoreInitValues() +{ + if (solverControl_.storeInitValues()) + { + Info<< "Restoring adjoint field to initial ones" << endl; + paInst() == dimensionedScalar(paInst().dimensions(), Zero); + UaInst() == dimensionedVector(UaInst().dimensions(), Zero); + phiaInst() == dimensionedScalar(phiaInst().dimensions(), Zero); + adjointTurbulence_().restoreInitValues(); + } +} + + void incompressibleAdjointVars::resetMeanFields() { if (solverControl_.average()) diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.H b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.H index 8bb60a23ebfcf47d96dded9aa4f11ffad774dbc1..fcfa216a91469d095016520c83dfb580ba47042f 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjoint/incompressibleAdjointVars.H @@ -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 @@ -68,10 +68,10 @@ protected: // Protected Member Functions //- No copy construct - incompressibleAdjointVars(const incompressibleAdjointVars&); + incompressibleAdjointVars(const incompressibleAdjointVars&) = delete; //- No copy assignment - void operator=(const incompressibleAdjointVars&); + void operator=(const incompressibleAdjointVars&) = delete; public: @@ -96,7 +96,7 @@ public: //- Destructor - virtual ~incompressibleAdjointVars(){}; + virtual ~incompressibleAdjointVars() = default; // Member Functions @@ -111,6 +111,9 @@ public: inline autoPtr<incompressibleAdjoint::adjointRASModel>& adjointTurbulence(); + //- Restore field values to the initial ones + void restoreInitValues(); + //- Reset mean fields to zero void resetMeanFields(); diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C index 7a23aba9254ffa9f3bbc863822bea61e6b39398c..2b03684a2d755b35fb8e26a3bea92c5a0c58c46e 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.C @@ -57,6 +57,7 @@ void incompressibleAdjointMeanFlowVars::setFields() mesh_.setFluxRequired(paPtr_->name()); } + void incompressibleAdjointMeanFlowVars::setMeanFields() { // Allocate mean fields diff --git a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.H b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.H index 9e523c61e2e86ed9af73114aeae26de363bdba04..87a0815bd5188df9308b555b75f2b9674ff4391c 100644 --- a/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.H +++ b/src/optimisation/adjointOptimisation/adjoint/solvers/variablesSet/incompressibleAdjointMeanFlow/incompressibleAdjointMeanFlowVars.H @@ -61,10 +61,10 @@ private: incompressibleAdjointMeanFlowVars ( const incompressibleAdjointMeanFlowVars& - ); + ) = delete; //- No copy assignment - void operator=(const incompressibleAdjointMeanFlowVars&); + void operator=(const incompressibleAdjointMeanFlowVars&) = delete; protected: diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C index f9e1d85bf9b4d09e928b9683f4d75448632f77ba..50f7c226daed88fc418a94647bc72675f41faac7 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.C @@ -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 @@ -61,6 +61,26 @@ void adjointRASModel::printCoeffs() } +void adjointRASModel::restoreInitValues() +{ + const solverControl& solControl = adjointVars_.getSolverControl(); + if (solControl.storeInitValues()) + { + if (adjointTMVariable1Ptr_) + { + volScalarField& var1 = adjointTMVariable1Ptr_.ref(); + var1 == dimensionedScalar(var1.dimensions(), Zero); + } + + if (adjointTMVariable2Ptr_) + { + volScalarField& var2 = adjointTMVariable2Ptr_.ref(); + var2 == dimensionedScalar(var2.dimensions(), Zero); + } + } +} + + void adjointRASModel::setMeanFields() { const solverControl& solControl = adjointVars_.getSolverControl(); @@ -352,7 +372,7 @@ autoPtr<volScalarField>& adjointRASModel::getAdjointTMVariable2InstPtr() } -const wordList& adjointRASModel::getAdjointTMVariablesBaseNames() +const wordList& adjointRASModel::getAdjointTMVariablesBaseNames() const { return adjointTMVariablesBaseNames_; } @@ -374,7 +394,7 @@ tmp<volScalarField> adjointRASModel::nutJacobianTMVar1() const mesh_, dimensionedScalar ( - nut().dimensions()/adjointTMVariable1Ptr_().dimensions(), + dimViscosity/adjointTMVariable1Ptr_().dimensions(), Zero ) ); @@ -397,7 +417,7 @@ tmp<volScalarField> adjointRASModel::nutJacobianTMVar2() const mesh_, dimensionedScalar ( - nut().dimensions()/adjointTMVariable2Ptr_().dimensions(), + dimViscosity/adjointTMVariable2Ptr_().dimensions(), Zero ) ); diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.H index ba9fff366fc56050fbd363be32a4cfeb4a5013ee..7f6dc022321da27ce49aeacde84f88b899235a86 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointRASModel/adjointRASModel.H @@ -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 @@ -263,7 +263,7 @@ public: //- Return reference to the adjoint turbulence model variables base //- names - const wordList& getAdjointTMVariablesBaseNames(); + const wordList& getAdjointTMVariablesBaseNames() const; //- Return the effective stress tensor including the laminar stress virtual tmp<volSymmTensorField> devReff() const = 0; @@ -314,12 +314,12 @@ public: virtual const boundaryVectorField& adjointMomentumBCSource() const = 0; //- Sensitivity terms for shape optimisation, emerging from - // the turbulence model differentiation. + //- the turbulence model differentiation. // Misses dxdb, to be added by the classes assembling the sensitivities virtual const boundaryVectorField& wallShapeSensitivities() = 0; //- Sensitivity terms for flow control, emerging from the - // turbulence model differentiation + //- turbulence model differentiation virtual const boundaryVectorField& wallFloCoSensitivities() = 0; //- Sensitivity terms resulting from the differentiation of the @@ -340,6 +340,9 @@ public: //- Set flag of changed primal solution to true void setChangedPrimalSolution(); + //- Restore field values to the initial ones + void restoreInitValues(); + //- Reset mean fields to zero void resetMeanFields(); diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C index 3ea09efc90b0dfe5a2c1f68298f290b2758f6f8b..3718c444025f021ca4c2311c6f9b9ec55130d351 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.C @@ -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-2023 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -35,6 +35,7 @@ License #include "boundaryAdjointContribution.H" #include "coupledFvPatch.H" #include "ATCModel.H" +#include "fvOptions.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // @@ -148,7 +149,7 @@ const volScalarField& adjointSpalartAllmaras::nuTilda() const } -const volScalarField& adjointSpalartAllmaras::nut() const +const volScalarField& adjointSpalartAllmaras::nutRef() const { return primalVars_.RASModelVariables()().nutRef(); } @@ -861,7 +862,7 @@ tmp<volScalarField> adjointSpalartAllmaras::distanceSensitivities() typedef nutUSpaldingWallFunctionFvPatchScalarField SAwallFunctionPatchField; - const volScalarField::Boundary& nutBoundary = nut().boundaryField(); + const volScalarField::Boundary& nutBoundary = nutRef().boundaryField(); const scalarField& V = mesh_.V().field(); tmp<volScalarField> tnuEff = nuEff(); @@ -945,7 +946,7 @@ tmp<volScalarField> adjointSpalartAllmaras::distanceSensitivities() tmp<volTensorField> adjointSpalartAllmaras::FISensitivityTerm() { - const volVectorField& U = primalVars_.U(); + const volVectorField& U = primalVars_.U(); tmp<volTensorField> tgradU = fvc::grad(U); const volTensorField& gradU = tgradU.cref(); @@ -997,10 +998,26 @@ tmp<volTensorField> adjointSpalartAllmaras::FISensitivityTerm() volScalarField dfw_dOmega (this->dfw_dOmega(Stilda_, dfw_dr, dStilda_dOmega)); - return + // Assemply of the return field + auto tFISens + ( tmp<volTensorField>::New ( - "volSensTerm", + IOobject + ( + type() + "flowTerm", + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedTensor(sqr(dimLength)/pow3(dimTime), Zero), + fvPatchFieldBase::zeroGradientType() + ) + ); + volTensorField& FISens = tFISens.ref(); + FISens = // jk, cm formulation for the TM model convection - (nuaTilda()*(U*gradNuTilda)) // jk, symmetric in theory @@ -1013,8 +1030,11 @@ tmp<volTensorField> adjointSpalartAllmaras::FISensitivityTerm() - Cb1_*nuTilda()*dStilda_dOmega + Cw1_*sqr(nuTilda()/y_)*dfw_dOmega ) - *nuaTilda()*deltaOmega // jk - ); + *nuaTilda()*deltaOmega; // jk + FISens.correctBoundaryConditions(); + + return tFISens; +} } @@ -1050,6 +1070,8 @@ void adjointSpalartAllmaras::correct() nuaTilda().storePrevIter(); + fv::options& fvOptions(fv::options::New(this->mesh_)); + tmp<fvScalarMatrix> nuaTildaEqn ( fvm::ddt(nuaTilda()) @@ -1065,23 +1087,26 @@ void adjointSpalartAllmaras::correct() //always a positive contribution to the lhs. no need for SuSp - fvm::Sp(Cw1_*fw_*nuTilda()/sqr(y_), nuaTilda()) - Cdnut_*gradUaR + + fvOptions(nuaTilda()) ); // Add sources from the objective functions - objectiveManager_.addTMEqn1Source(nuaTildaEqn.ref()); + objectiveManager_.addSource(nuaTildaEqn.ref()); nuaTildaEqn.ref().relax(); + fvOptions.constrain(nuaTildaEqn.ref()); solve(nuaTildaEqn); nuaTilda().correctBoundaryConditions(); nuaTilda().relax(); if (adjointVars_.getSolverControl().printMaxMags()) { - scalar maxDeltaNuaTilda = - gMax(mag(nuaTilda() - nuaTilda().prevIter())()); + dimensionedScalar maxDeltaNuaTilda = + max(mag(nuaTilda() - nuaTilda().prevIter())()); dimensionedScalar maxNuaTilda = max(mag(nuaTilda())); Info<< "Max mag of nuaTilda = " << maxNuaTilda.value() << endl; - Info<< "Max mag of delta nuaTilda = " << maxDeltaNuaTilda << endl; + Info<< "Max mag of delta nuaTilda = " << maxDeltaNuaTilda.value() + << endl; } } diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.H index 91606032411581530284e13890e30f4a336b68fa..b774d0254f9275b378813550abfafa1d65559b72 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointSpalartAllmaras/adjointSpalartAllmaras.H @@ -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 @@ -175,7 +175,7 @@ protected: //- References to the primal turbulence model variables const volScalarField& nuTilda() const; - const volScalarField& nut() const; + const volScalarField& nutRef() const; // Adjoint Spalart - Allmaras @@ -282,6 +282,12 @@ protected: return adjointTMVariable1Ptr_(); }; + //- Constant access to the adjoint Spalart - Allmaras field + inline const volScalarField& nuaTilda() const + { + return adjointTMVariable1Ptr_(); + }; + //- Update the constant primal-related fields void updatePrimalRelatedFields(); diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointkOmegaSST/adjointkOmegaSST.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointkOmegaSST/adjointkOmegaSST.C index 862cea770d408e2fd214543925878cbd4daef2c3..760a9730c35edaffb37109bdb105ae3a9a2a0861 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointkOmegaSST/adjointkOmegaSST.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointRAS/adjointkOmegaSST/adjointkOmegaSST.C @@ -5,8 +5,8 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2014-2022 PCOpt/NTUA - Copyright (C) 2014-2022 FOSS GP + Copyright (C) 2014-2023 PCOpt/NTUA + Copyright (C) 2014-2023 FOSS GP ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -2173,7 +2173,7 @@ void adjointkOmegaSST::correct() // Sources from the objective should be added after the boundary // manipulation - objectiveManager_.addTMEqn2Source(waEqn.ref()); + objectiveManager_.addSource(waEqn.ref()); waEqn.ref().solve(); // Adjoint Turbulent kinetic energy equation @@ -2195,7 +2195,7 @@ void adjointkOmegaSST::correct() kaEqn.ref().boundaryManipulate(ka().boundaryFieldRef()); addWallFunctionTerms(kaEqn.ref(), dR_dnut); // Add sources from the objective functions - objectiveManager_.addTMEqn1Source(kaEqn.ref()); + objectiveManager_.addSource(kaEqn.ref()); kaEqn.ref().solve(); diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.H index 04adc50c37e51e887e3e06dbb9ab3c7715b6a5a6..ebabdf33667f5f0d5d6e4c7d03b485d329d50276 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/incompressibleAdjoint/adjointTurbulenceModel/adjointTurbulenceModel.H @@ -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 @@ -159,9 +159,9 @@ public: } //- Return the turbulence viscosity - virtual const volScalarField& nut() const + virtual const tmp<volScalarField> nut() const { - return primalVars_.RASModelVariables()().nutRef(); + return primalVars_.RASModelVariables()().nut(); } //- Return the effective viscosity @@ -178,9 +178,8 @@ public: tmp<volScalarField>::New ( "nuEff", - lamTrans.nu()() + turbVars().nutRef() + lamTrans.nu() + turbVars().nut() ); - //return primalVars_.turbulence()().nuEff(); } //- Return the effective viscosity on a given patch @@ -193,11 +192,7 @@ public: const autoPtr<incompressible::RASModelVariables>& turbVars = primalVars_.RASModelVariables(); - return - ( - lamTrans.nu()().boundaryField()[patchI] - + turbVars().nutRef().boundaryField()[patchI] - ); + return (lamTrans.nu(patchI) + turbVars().nut(patchI)); } //- Return the effective stress tensor including the laminar stress diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C index e74372f42561e35c44e36e59eedfa388ca9faad5..a16f7677e7d164056a5a3ac1cb0152cb3f5a5895 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.C @@ -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-2023 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -373,17 +373,17 @@ void RASModelVariables::resetMeanFields() Info<< "Resetting mean turbulent fields to zero" << endl; // Reset fields to zero - if (hasTMVar1()) + if (TMVar1MeanPtr_) { TMVar1MeanPtr_.ref() == dimensionedScalar(TMVar1Inst().dimensions(), Zero); } - if (hasTMVar2()) + if (TMVar2MeanPtr_) { TMVar2MeanPtr_.ref() == dimensionedScalar(TMVar2Inst().dimensions(), Zero); } - if (hasNut()) + if (nutMeanPtr_) { nutMeanPtr_.ref() == dimensionedScalar(nutRefInst().dimensions(), Zero); @@ -436,7 +436,7 @@ tmp<volSymmTensorField> RASModelVariables::devReff IOobject::NO_READ, IOobject::NO_WRITE ), - - (laminarTransport.nu() + nutRef())*devTwoSymm(fvc::grad(U)) + - (laminarTransport.nu() + nut())*devTwoSymm(fvc::grad(U)) ); } diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.H index 21313d3e5aac24ab42a2368f7699609f7ecf257e..2d48ffa006ac4722041aab78ef3fe4db25009488 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariables.H @@ -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-2019, 2022-2023 PCOpt/NTUA + Copyright (C) 2013-2019, 2022-2023 FOSS GP Copyright (C) 2019-2020 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -176,10 +176,6 @@ public: inline const word& nutBaseName() const; //- Bools to identify which turbulent fields are present - // Apart from the distance pointer, all other pointers are - // allocated even if the the corresponding field does not exist. - // Hence, the pointer itself cannot be used to determine the - // existance of the field inline virtual bool hasTMVar1() const; inline virtual bool hasTMVar2() const; inline virtual bool hasNut() const; @@ -194,10 +190,16 @@ public: inline volScalarField& TMVar2(); inline const volScalarField& nutRef() const; inline volScalarField& nutRef(); + inline tmp<volScalarField> nut() const; inline const volScalarField& d() const; inline volScalarField& d(); - //- return references to instantaneous turbulence fields + inline tmp<scalarField> TMVar1(const label patchi) const; + inline tmp<scalarField> TMVar2(const label patchi) const; + inline tmp<scalarField> nut(const label patchi) const; + inline tmp<fvPatchScalarField> nutPatchField(const label patchi) const; + + //- Return references to instantaneous turbulence fields inline const volScalarField& TMVar1Inst() const; inline volScalarField& TMVar1Inst(); inline const volScalarField& TMVar2Inst() const; diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariablesI.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariablesI.H index 784f0ef2c887cb8491d59cfda3572ecb48278f93..ccbc5285b8d8a5a7279bec2d7ec188c491c2e952 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariablesI.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/RASModelVariables/RASModelVariablesI.H @@ -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 @@ -141,6 +141,30 @@ inline volScalarField& RASModelVariables::nutRef() } +inline tmp<volScalarField> RASModelVariables::nut() const +{ + if (hasNut()) + { + return tmp<volScalarField>(nutRef()); + } + + return + tmp<volScalarField>::New + ( + IOobject + ( + "dummylaminarNut", + mesh_.time().timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedScalar(dimViscosity, Zero) + ); +} + + inline const volScalarField& RASModelVariables::d() const { return distPtr_.cref(); @@ -153,6 +177,53 @@ inline volScalarField& RASModelVariables::d() } +inline tmp<scalarField> RASModelVariables::TMVar1(const label patchi) const +{ + if (hasTMVar1()) + { + return TMVar1().boundaryField()[patchi]; + } + + return tmp<scalarField>::New(mesh_.boundary()[patchi].size(), Zero); +} + + +inline tmp<scalarField> RASModelVariables::TMVar2(const label patchi) const +{ + if (hasTMVar2()) + { + return TMVar2().boundaryField()[patchi]; + } + + return tmp<scalarField>::New(mesh_.boundary()[patchi].size(), Zero); +} + + +inline tmp<scalarField> RASModelVariables::nut(const label patchi) const +{ + if (hasNut()) + { + return nutRef().boundaryField()[patchi]; + } + + return tmp<scalarField>::New(mesh_.boundary()[patchi].size(), Zero); +} + + +inline tmp<fvPatchScalarField> +RASModelVariables::nutPatchField(const label patchi) const +{ + if (hasNut()) + { + return nutRef().boundaryField()[patchi]; + } + + // Using dummy internalField + return + tmp<fvPatchScalarField>::New(mesh_.boundary()[patchi], mesh_.V(), Zero); +} + + inline const volScalarField& RASModelVariables::TMVar1Inst() const { return TMVar1Ptr_.cref(); diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C index 7ffd13e1e11bae1d291d2c3eceac140fe12f3f1b..9e17b38e59263943a96edf29f24b38948ee4398a 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.C @@ -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 @@ -58,24 +58,6 @@ SpalartAllmaras::SpalartAllmaras TMVar1BaseName_ = "nuTilda"; TMVar1Ptr_.ref(mesh_.lookupObjectRef<volScalarField>(TMVar1BaseName_)); - - TMVar2Ptr_.reset - ( - new volScalarField - ( - IOobject - ( - "dummySpalartAllmarasVar2", - mesh.time().timeName(), - mesh, - IOobject::NO_READ, - IOobject::NO_WRITE - ), - mesh, - dimensionedScalar(dimless, Zero) - ) - ); - nutPtr_.ref(mesh_.lookupObjectRef<volScalarField>(nutBaseName_)); // The wall dist name can vary depending on how wallDist was diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.H index f61317f65938021e07be32b4541c2297e8ac5ac1..8d30eaaf27fb9c8bd4352e298a7cf22ca1d7a513 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/SpalartAllmaras/SpalartAllmaras.H @@ -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 PCOpt/NTUA + Copyright (C) 2013-2023 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -80,21 +80,6 @@ public: // Member Functions - - // Bools to identify which turbulent fields are present - inline virtual bool hasTMVar1() const - { - return true; - } - inline virtual bool hasTMVar2() const - { - return false; - } - inline virtual bool hasNut() const - { - return true; - } - //- return nut Jacobian wrt the TM vars virtual tmp<volScalarField> nutJacobianVar1 ( diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C index a05a88cd4937cd9dde8dcd770ef760d2bae4cd7b..bd4f6f29e82906cbda6e1ca8d30947cf785b8018 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.C @@ -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 @@ -44,6 +44,35 @@ namespace RASVariables defineTypeNameAndDebug(kEpsilon, 0); addToRunTimeSelectionTable(RASModelVariables, kEpsilon, dictionary); + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +void kEpsilon::allocateMeanFields() +{ + RASModelVariables::allocateMeanFields(); + if (solverControl_.average()) + { + GMean_.reset + ( + new volScalarField::Internal + ( + IOobject + ( + "GMean", + mesh_.time().timeName(), + mesh_, + IOobject::READ_IF_PRESENT, + IOobject::AUTO_WRITE + ), + mesh_, + dimensionedScalar(dimArea/pow3(dimTime), Zero) + ) + ); + } +} + + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // kEpsilon::kEpsilon @@ -66,6 +95,74 @@ kEpsilon::kEpsilon } +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +tmp<volScalarField::Internal> kEpsilon::computeG() +{ + const turbulenceModel& turbModel = mesh_.lookupObject<turbulenceModel> + ( + IOobject::groupName + ( + turbulenceModel::propertiesName, + TMVar2().internalField().group() + ) + ); + // Recompute G and modify values next to the walls + // Ideally, grad(U) should be cached to avoid the overhead + const volVectorField& U = turbModel.U(); + tmp<volTensorField> tgradU = fvc::grad(U); + volScalarField::Internal GbyNu0 + ( + IOobject::scopedName(this->type(), "GbyNu"), + (tgradU() && devTwoSymm(tgradU())) + ); + + // NB: leave tmp registered (for correctBoundaryConditions) + auto tG = + tmp<volScalarField::Internal>::New + ( + turbModel.GName(), + nutRefInst()*GbyNu0 + ); + // Use correctBoundaryConditions instead of updateCoeffs to avoid + // messing with updateCoeffs in the next iteration of omegaEqn + TMVar2Inst().correctBoundaryConditions(); + + return tG; +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +tmp<volScalarField::Internal> kEpsilon::G() +{ + if (solverControl_.useAveragedFields()) + { + DebugInfo + << "Using GMean" << endl; + return tmp<volScalarField::Internal>(GMean_()); + } + DebugInfo + << "Using instantaneous G" << endl; + return computeG(); +} + + +void kEpsilon::computeMeanFields() +{ + RASModelVariables::computeMeanFields(); + if (solverControl_.doAverageIter()) + { + const label iAverageIter = solverControl_.averageIter(); + scalar avIter(iAverageIter); + scalar oneOverItP1 = 1./(avIter + 1); + scalar mult = avIter*oneOverItP1; + GMean_() = GMean_()*mult + computeG()*oneOverItP1; + } +} + + + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace RASVariables diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.H index 510f0cc7cf95fe573fa773e6b2d05519482b46fd..e0877a762c94e171132e685606df7717b3ee9a53 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kEpsilon/kEpsilon.H @@ -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 PCOpt/NTUA + Copyright (C) 2013-2023 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -59,6 +59,21 @@ class kEpsilon public RASModelVariables { +protected: + + // Protected data + + //- Average of the production term + // Avaraged separetely due the bi-zonal treatment next to the wall + autoPtr<volScalarField::Internal> GMean_; + + + // Protected Member functions + + virtual void allocateMeanFields(); + tmp<volScalarField::Internal> computeG(); + + public: //- Runtime type information @@ -81,19 +96,12 @@ public: // Member Functions - // Bools to identify which turbulent fields are present - inline virtual bool hasTMVar1() const - { - return true; - } - inline virtual bool hasTMVar2() const - { - return true; - } - inline virtual bool hasNut() const - { - return true; - } + //- Return the turbulence production term + virtual tmp<volScalarField::Internal> G(); + + //- Compute mean fields on the fly + virtual void computeMeanFields(); + }; diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C index b4ba121b47ebcc0a42c09577e00b5c20c24c34ef..cb02c4b7b6075dd1441632e26c7442f629956ade 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.C @@ -97,6 +97,8 @@ kOmegaSST::kOmegaSST } +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + tmp<volScalarField::Internal> kOmegaSST::computeG() { const turbulenceModel& turbModel = mesh_.lookupObject<turbulenceModel> diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.H b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.H index f6721bf042dfb89c35b8ce206e2532619fbabd2d..911b6915e6d7a4e1a553a1f037a791fe73880892 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.H +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/kOmegaSST/kOmegaSST.H @@ -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 PCOpt/NTUA + Copyright (C) 2013-2023 FOSS GP Copyright (C) 2019 OpenCFD Ltd. ------------------------------------------------------------------------------- License @@ -102,20 +102,6 @@ public: //- Compute mean fields on the fly virtual void computeMeanFields(); - // Bools to identify which turbulent fields are present - inline virtual bool hasTMVar1() const - { - return true; - } - inline virtual bool hasTMVar2() const - { - return true; - } - inline virtual bool hasNut() const - { - return true; - } - //- Correct boundary conditions of turbulent fields virtual void correctBoundaryConditions ( diff --git a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C index 3560e42a166ba312e6bf394b3e6b6cc850ded557..388a145f90c60264775c59c07a6546593ce51f92 100644 --- a/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C +++ b/src/optimisation/adjointOptimisation/adjoint/turbulenceModels/turbulenceModelVariables/RAS/laminar/laminar.C @@ -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 @@ -53,60 +53,7 @@ laminar::laminar ) : RASModelVariables(mesh, SolverControl) -{ - TMVar1Ptr_.reset - ( - new volScalarField - ( - IOobject - ( - "dummylaminarVar1", - mesh.time().timeName(), - mesh, - IOobject::NO_READ, - IOobject::NO_WRITE - ), - mesh, - dimensionedScalar(dimless, Zero) - ) - ); - - TMVar2Ptr_.reset - ( - new volScalarField - ( - IOobject - ( - "dummylaminarVar2", - mesh.time().timeName(), - mesh, - IOobject::NO_READ, - IOobject::NO_WRITE - ), - mesh, - dimensionedScalar(dimless, Zero) - ) - ); - - nutPtr_.reset - ( - new volScalarField - ( - IOobject - ( - "dummylaminarNut", - mesh.time().timeName(), - mesh, - IOobject::NO_READ, - IOobject::NO_WRITE - ), - mesh, - dimensionedScalar(sqr(dimLength)/dimTime, Zero) - ) - ); - - allocateInitValues(); -} +{} // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/motorBike/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/motorBike/system/optimisationDict index 4b831c0f71dc0e97b5fa68032d52b9ad2b535ce5..c18f84b1236048fea6c54ed5c2a6d8cbbe9d5ac2 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/motorBike/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/motorBike/system/optimisationDict @@ -106,63 +106,65 @@ adjointManagers optimisation { - sensitivities + designVariables { - // Used to compute a number of variants of the sensitivity map - // at once - type multiple; - patches (motorBikeGroup); - sensTypes - { - pointBased - { - type surfacePoints; - patches (motorBikeGroup); - includeSurfaceArea false; - adjointEikonalSolver - { - tolerance 1.e-5; - iters 1000; - epsilon 0.1; - } - } + sensitivityType multiple; + sensitivityTypes + ( + pointBased faceBased-unsmoothed - { - type surface; - patches (motorBikeGroup); - includeSurfaceArea false; - } faceBased-RMult_2 - { - type surface; - patches (motorBikeGroup); - includeSurfaceArea false; - smoothSensitivities true; - meanRadiusMultiplier 2; - suffix Rmult2; // suffix of the sensitivity map output files - iters 2000; - } faceBased-RMult_5 - { - type surface; - patches (motorBikeGroup); - includeSurfaceArea false; - smoothSensitivities true; - meanRadiusMultiplier 5; - suffix Rmult5; // suffix of the sensitivity map output files - iters 2000; - } faceBased-RMult_10 + ); + patches (motorBikeGroup); + pointBased + { + sensitivityType surfacePoints; + patches (motorBikeGroup); + adjointEikonalSolver { - type surface; - patches (motorBikeGroup); - includeSurfaceArea false; - smoothSensitivities true; - meanRadiusMultiplier 10; - suffix Rmult10; // suffix of the sensitivity map output files - iters 2000; + tolerance 1.e-5; + iters 1000; + epsilon 0.1; } } + faceBased-unsmoothed + { + sensitivityType surface; + patches (motorBikeGroup); + includeSurfaceArea true; + } + faceBased-RMult_2 + { + sensitivityType surface; + patches (motorBikeGroup); + includeSurfaceArea true; + smoothSensitivities true; + meanRadiusMultiplier 2; + suffix Rmult2; // suffix of the sensitivity map output files + iters 1000; + } + faceBased-RMult_5 + { + sensitivityType surface; + patches (motorBikeGroup); + includeSurfaceArea true; + smoothSensitivities true; + meanRadiusMultiplier 5; + suffix Rmult5; // suffix of the sensitivity map output files + iters 1000; + } + faceBased-RMult_10 + { + sensitivityType surface; + patches (motorBikeGroup); + includeSurfaceArea true; + smoothSensitivities true; + meanRadiusMultiplier 10; + suffix Rmult10; // suffix of the sensitivity map output files + iters 1000; + } } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/drag/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/drag/system/optimisationDict index 31b902b7d9fed647b74227fabfdb259456c4d4e1..a6325beff8d9fb32bcdff1ae14508b2dafbd2ec3 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/drag/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/drag/system/optimisationDict @@ -95,9 +95,9 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; + sensitivityType surfacePoints; patches (pressure suction); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/lift/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/lift/system/optimisationDict index dee8234a763a59caf3983760b5d9f46c0e8973d4..4ba2394ce16fa1d7c2907176221f0ee183099cf6 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/lift/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/lift/system/optimisationDict @@ -95,9 +95,9 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; + sensitivityType surfacePoints; patches (pressure suction); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/moment/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/moment/system/optimisationDict index 59a3b2268c29ad1cbaf58b8484ebada5b90df12b..3bdf8d043d9e002658232fd43a5b5ff2b31659ac 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/moment/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/laminar/moment/system/optimisationDict @@ -97,9 +97,9 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; + sensitivityType surfacePoints; patches (pressure suction); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftFullSetup/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftFullSetup/system/optimisationDict index bf0f6f3427d7bc810f8a23c76b65a0ee4dd2ec20..57c2ef4345f0c89c3c80075a907adc9ea5833858 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftFullSetup/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftFullSetup/system/optimisationDict @@ -103,14 +103,13 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; - patches (pressure suction); + sensitivityType surfacePoints; + patches (pressure suction); includeSurfaceArea false; includeDistance true; includeMeshMovement true; - includeObjectiveContribution true; writeAllSurfaceFiles true; adjointMeshMovementSolver { diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftMinimumSetup/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftMinimumSetup/system/optimisationDict index b4b5f2512b1c0836c175290b761002ca742038a8..9f1e1b53b82165cfa0b71b079ebd7f978bd70a1c 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftMinimumSetup/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/naca0012/turbulent/liftMinimumSetup/system/optimisationDict @@ -97,10 +97,10 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; - patches (pressure suction); + sensitivityType surfacePoints; + patches (pressure suction); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/laminar/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/laminar/system/optimisationDict index 220f2f7c5782963fd56e571a58dc7fd810d10319..5b66688d05e71d8fed9ab210f2db5d7f5ee3b99d 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/laminar/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/laminar/system/optimisationDict @@ -91,9 +91,9 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; + sensitivityType surfacePoints; patches (lower upper); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/highRe/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/highRe/system/optimisationDict index 398f6fe2a2aeaade745d45cafda3dc856be93b39..97618bf8a1013808cff42e96f95cbe17c308a0dc 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/highRe/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/highRe/system/optimisationDict @@ -91,9 +91,9 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; + sensitivityType surfacePoints; patches (lower upper); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/multiPoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/multiPoint/system/optimisationDict index a60e75897ea8b4e2a9cddf466b580c2e626141f3..4ec44012d0fc086ee8cbd00bd4b700f749a965db 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/multiPoint/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/multiPoint/system/optimisationDict @@ -163,10 +163,10 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; - patches (lower upper); + sensitivityType surfacePoints; + patches (lower upper); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/singlePoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/singlePoint/system/optimisationDict index 398f6fe2a2aeaade745d45cafda3dc856be93b39..97618bf8a1013808cff42e96f95cbe17c308a0dc 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/singlePoint/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/sensitivityMaps/sbend/turbulent/lowRe/singlePoint/system/optimisationDict @@ -91,9 +91,9 @@ adjointManagers optimisation { - sensitivities + designVariables { - type surfacePoints; + sensitivityType surfacePoints; patches (lower upper); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRate/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRate/system/optimisationDict index b273bf66d08ef4da89e5a89d899f5825bb033bb3..dcc9b7654c56e3431f81c354735b129167846f56 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRate/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRate/system/optimisationDict @@ -93,25 +93,18 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (upperWall lowerWall middleWall); + maxInitChange 1.e-3; } updateMethod { method conjugateGradient; } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 1.e-3; - } } // ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRatePartition/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRatePartition/system/optimisationDict index 04e72416da950d7328ebda8cfc1ab5c9b26f5c22..453d844e547f0c9869af3d34b6118b41104731e7 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRatePartition/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/flowRatePartition/system/optimisationDict @@ -97,25 +97,18 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (upperWall lowerWall middleWall); + maxInitChange 1.e-3; } updateMethod { method conjugateGradient; } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 1.e-3; - } } // ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/uniformityPatch/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/uniformityPatch/system/optimisationDict index cd43525df3bf00d46d0a4b4c40e03321ff9c1936..6be392101b5be4dc7d3e889c2c910da11d840b89 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/uniformityPatch/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/fork-uneven/uniformityPatch/system/optimisationDict @@ -93,25 +93,18 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (upperWall lowerWall middleWall); + maxInitChange 1.e-3; } updateMethod { method conjugateGradient; } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 1.e-3; - } } // ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/motorBike/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/motorBike/system/optimisationDict index e27a4dbf616497ffb7885d3e227ac4a8898d7bdc..f9df2a73dd745d2693cfebb886b50a1ea57a0a72 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/motorBike/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/motorBike/system/optimisationDict @@ -106,15 +106,13 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - sensitivities - { - type volumetricBSplinesFI; - patches (motorBikeGroup); + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (motorBikeGroup); + maxInitChange 2.e-3; } updateMethod { @@ -125,11 +123,6 @@ optimisation } //eta 1; //optional } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/kOmegaSST/lift/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/kOmegaSST/lift/system/optimisationDict index 708f7c9e409e70195654d6d2788ca1242b10110c..6c99208ebbd700a0e1ddb9b3310bc51b564c1a3f 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/kOmegaSST/lift/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/kOmegaSST/lift/system/optimisationDict @@ -97,9 +97,11 @@ adjointManagers optimisation { - sensitivities + designVariables { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (pressure suction); } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/drag/primalAdjoint/constant/dynamicMeshDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/drag/primalAdjoint/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..a6e30fa7e51907f31386178c34c007359e333f60 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/drag/primalAdjoint/constant/dynamicMeshDict @@ -0,0 +1,27 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2206 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solver laplacianMotionSolver; + +laplacianMotionSolverCoeffs +{ + diffusivity uniform; + iters 1000; + tolerance 1.e-06; +} + + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/drag/primalAdjoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/drag/primalAdjoint/system/optimisationDict index 1d6ddd34a630bf053a56920a66653c15ab3b4d76..5af1e7b95e5fa59ac519dccb7e29c05b5fbcf4b0 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/drag/primalAdjoint/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/drag/primalAdjoint/system/optimisationDict @@ -95,31 +95,28 @@ adjointManagers optimisation { - sensitivities + designVariables { - type multiple; // used to compute many kinds of sensitivities at the same time + type shape; + shapeType Bezier; + sensitivityType multiple; + sensitivityTypes (FI ESI SI); patches (pressure suction); - sensTypes + ESI { - ESI - { - type Bezier; - patches (pressure suction); - } - SI - { - type Bezier; - patches (pressure suction); - surfaceSensitivities - { - includeMeshMovement false; - } - } - FI - { - type BezierFI; - patches (pressure suction); - } + sensitivityType shapeESI; + patches (pressure suction); + } + SI + { + sensitivityType shapeESI; + patches (pressure suction); + includeMeshMovement false; + } + FI + { + sensitivityType shapeFI; + patches (pressure suction); } } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/lift/opt/constraintProjection/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/lift/opt/constraintProjection/system/optimisationDict index 4b5e2335bb5adbfd1a2bd9d7d50390cc31d90442..77303dd4909af7968e5077b545ea6588e3f42b4e 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/lift/opt/constraintProjection/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/lift/opt/constraintProjection/system/optimisationDict @@ -94,15 +94,14 @@ adjointManagers // choose adjoint solver //---------------------- active true; - type incompressible; - solver adjointSimple; + type null; isConstraint true; // manage objectives //------------------ objectives { - type incompressible; + type geometric; objectiveNames { vol @@ -113,25 +112,6 @@ adjointManagers } } } - - // ATC treatment - //-------------- - ATCModel - { - ATCModel standard; - } - - // solution control - //------------------ - solutionControls - { - nIters 3000; - residualControl - { - "pa.*" 1.e-7; - "Ua.*" 1.e-7; - } - } } } } @@ -139,25 +119,18 @@ adjointManagers optimisation { - optimisationType - { - type shapeOptimisation; - writeEachMesh true; - } - sensitivities + designVariables { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (pressure suction); + maxInitChange 5.e-3; } updateMethod { method constraintProjection; } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 5.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/moment/primalAdjoint/constant/dynamicMeshDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/moment/primalAdjoint/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..a6e30fa7e51907f31386178c34c007359e333f60 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/moment/primalAdjoint/constant/dynamicMeshDict @@ -0,0 +1,27 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2206 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solver laplacianMotionSolver; + +laplacianMotionSolverCoeffs +{ + diffusivity uniform; + iters 1000; + tolerance 1.e-06; +} + + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/moment/primalAdjoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/moment/primalAdjoint/system/optimisationDict index c18f88e42ee61ff9f06b8b2f10a1410950b72766..bcc6a46540474907de0193dd4657220dcb649e39 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/moment/primalAdjoint/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/moment/primalAdjoint/system/optimisationDict @@ -97,36 +97,28 @@ adjointManagers optimisation { - sensitivities + designVariables { - type multiple; // used to compute many kinds of sensitivities at the same time - patches (pressure suction); - sensTypes + type shape; + shapeType Bezier; + sensitivityType multiple; + sensitivityTypes (FI ESI SI); + patches (pressure suction); + ESI { - ESI - { - type Bezier; - patches (pressure suction); - } - SI - { - type Bezier; - patches (pressure suction); - surfaceSensitivities - { - includeMeshMovement false; - } - } - FI - { - type BezierFI; - patches (pressure suction); - } - surface - { - type surface; - patches (pressure suction); - } + sensitivityType shapeESI; + patches (pressure suction); + } + SI + { + sensitivityType shapeESI; + patches (pressure suction); + includeMeshMovement false; + } + FI + { + sensitivityType shapeFI; + patches (pressure suction); } } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/U b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/U new file mode 100644 index 0000000000000000000000000000000000000000..3f09bacf52a660a4b0637ac44d1082449222b99c --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/U @@ -0,0 +1,44 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object U; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [ 0 1 -1 0 0 0 0 ]; + +internalField uniform ( 5.996344962 0.20939698 0 ); + +boundaryField +{ + frontBack + { + type empty; + } + suction + { + type fixedValue; + value uniform ( 0 0 0 ); + } + pressure + { + type fixedValue; + value uniform ( 0 0 0 ); + } + inlet + { + type freestream; + freestreamValue uniform ( 5.996344962 0.20939698 0 ); + } +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/Ua b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/Ua new file mode 100644 index 0000000000000000000000000000000000000000..c374f446e8bdb808d0b6fdfab812a19e04d47fc7 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/Ua @@ -0,0 +1,44 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volVectorField; + object Ua; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [ 0 1 -1 0 0 0 0 ]; + +internalField uniform ( 0 0 0 ); + +boundaryField +{ + frontBack + { + type empty; + } + suction + { + type adjointWallVelocity; + value uniform ( 0 0 0 ); + } + pressure + { + type adjointWallVelocity; + value uniform ( 0 0 0 ); + } + inlet + { + type adjointFarFieldVelocity; + value uniform ( 0 0 0 ); + } +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/p b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/p new file mode 100644 index 0000000000000000000000000000000000000000..8a4f76887c62de68e4e44f51f9f10f0f3f084f7b --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/p @@ -0,0 +1,43 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object p; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [ 0 2 -2 0 0 0 0 ]; + +internalField uniform 0; + +boundaryField +{ + frontBack + { + type empty; + } + suction + { + type zeroGradient; + } + pressure + { + type zeroGradient; + } + inlet + { + type outletInlet; + outletValue uniform 0; + value uniform 0; + } +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/pa b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/pa new file mode 100644 index 0000000000000000000000000000000000000000..d496048b595d2215dc30ecf8c304e7471048290f --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/0/pa @@ -0,0 +1,42 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class volScalarField; + object pa; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +dimensions [ 0 2 -2 0 0 0 0 ]; + +internalField uniform 0; + +boundaryField +{ + frontBack + { + type empty; + } + suction + { + type zeroGradient; + } + pressure + { + type zeroGradient; + } + inlet + { + type adjointFarFieldPressure; + value uniform 0; + } +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/Allclean b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/Allclean new file mode 100755 index 0000000000000000000000000000000000000000..87ffba857ae48b5bf6e337ded76ab9b0fe85cf68 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/Allclean @@ -0,0 +1,9 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions +#------------------------------------------------------------------------------ + +cleanCase +rm -r constant/PARSEC 2> /dev/null + +#------------------------------------------------------------------------------ diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/Allrun b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/Allrun new file mode 100755 index 0000000000000000000000000000000000000000..b0961695d23414bf1405da19155288c34497b927 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/Allrun @@ -0,0 +1,12 @@ +#!/bin/sh +cd "${0%/*}" || exit # Run from this directory +. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions +#------------------------------------------------------------------------------ + +resourcesDir=$FOAM_TUTORIALS/incompressible/adjointOptimisationFoam/resources + +\cp -r $resourcesDir/meshes/naca0012/polyMesh constant +runApplication decomposePar +runParallel $(getApplication) + +#------------------------------------------------------------------------------ diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/adjointRASProperties b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/adjointRASProperties new file mode 100644 index 0000000000000000000000000000000000000000..5238b1310a8b19f32c4a90fe5a0fd74a32cc3fbb --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/adjointRASProperties @@ -0,0 +1,23 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object RASProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +adjointRASModel adjointLaminar; + +adjointTurbulence on; + +printCoeffs off; + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/dynamicMeshDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/dynamicMeshDict new file mode 100644 index 0000000000000000000000000000000000000000..52f5e65511b0dccbaf2225d8bf78e89622642ea2 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/dynamicMeshDict @@ -0,0 +1,45 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object dynamicMeshDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +solver volumetricBSplinesMotionSolver; + +volumetricBSplinesMotionSolverCoeffs +{ + duct + { + type cartesian; + nCPsU 8; + nCPsV 6; + nCPsW 3; + degreeU 3; + degreeV 3; + degreeW 2; + + controlPointsDefinition axisAligned; + lowerCpBounds ( 0.1 -0.25 -0.1); + upperCpBounds ( 0.9 0.25 1.1); + + confineUMovement false; + confineVMovement false; + confineWMovement true; + confineBoundaryControlPoints true; + + confineUMinCPs ( (true true true) (true true true) ); + confineUMaxCPs ( (true true true) (true true true) ); + } +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/transportProperties b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/transportProperties new file mode 100644 index 0000000000000000000000000000000000000000..5af049eb760a6f571e7fe62045b7dc8945ed83a1 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/transportProperties @@ -0,0 +1,21 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object transportProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +transportModel Newtonian; + +nu nu [ 0 2 -1 0 0 0 0 ] 6.e-03; + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/turbulenceProperties b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/turbulenceProperties new file mode 100644 index 0000000000000000000000000000000000000000..3d9b82f999ca91cee6ba89333c3a46c740e34946 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/constant/turbulenceProperties @@ -0,0 +1,19 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object turbulenceProperties; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +simulationType laminar; + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/plot.gp b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/plot.gp new file mode 100644 index 0000000000000000000000000000000000000000..6fb006f0722aa7db8616337d2b76710fc560c33f --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/plot.gp @@ -0,0 +1,15 @@ +set multiplot layout 2,2 +set grid + +set xl 'Optimization cycle' + +set yl 'C_d/C_{d,init}' +p 'optimisation/objective/0/dragas1' u 1:3 w lp notitle + +set yl 'C_l' +set yr [0.05266:0.05366] +p 'optimisation/objective/0/liftlift' u 1:2 w lp notitle, 0.05340147181439196 t 'upper bound', 0.05320147181439196 t 'lower bound' + +set autoscale y +set yl '(V-Vinit)/Vinit' +p 'optimisation/objective/0/volvol' u 1:2 w lp notitle, -0.15 t 'lower bound' diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/controlDict new file mode 100644 index 0000000000000000000000000000000000000000..56098a48357050a33833ff39cf4002c63e04a2c6 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/controlDict @@ -0,0 +1,47 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object controlDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +application adjointOptimisationFoam; + +startFrom latestTime; + +startTime 0; + +stopAt endTime; + +endTime 90; + +deltaT 1; + +writeControl timeStep; + +writeInterval 10; + +purgeWrite 0; + +writeFormat binary; + +writePrecision 16; + +writeCompression false; + +timeFormat general; + +timePrecision 6; + +runTimeModifiable yes; + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/decomposeParDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/decomposeParDict new file mode 100644 index 0000000000000000000000000000000000000000..ce2f8888c0e0a47c87695d3ff4b3d2f9d66ee142 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/decomposeParDict @@ -0,0 +1,26 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object decomposeParDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +numberOfSubdomains 4; + +method hierarchical; + +coeffs +{ + n (2 2 1); +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/fvSchemes b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/fvSchemes new file mode 100644 index 0000000000000000000000000000000000000000..1f3bb745fe04e9e3a930487b597f027c51707b61 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/fvSchemes @@ -0,0 +1,52 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSchemes; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +ddtSchemes +{ + default steadyState; +} + +gradSchemes +{ + default Gauss linear; + gradUConv cellLimited Gauss linear 0.5; +} + +divSchemes +{ + default Gauss linear; + div(phi,U) bounded Gauss linearUpwind gradUConv; + div(-phi,Uaas1) bounded Gauss linearUpwind gradUaConv; + div(-phi,Ualift) bounded Gauss linearUpwind gradUaConv; + div(-phi,Uamoment) bounded Gauss linearUpwind gradUaConv; +} + +laplacianSchemes +{ + default Gauss linear corrected; +} + +interpolationSchemes +{ + default linear; +} + +snGradSchemes +{ + default corrected; +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/fvSolution b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/fvSolution new file mode 100644 index 0000000000000000000000000000000000000000..ee43e55a5cfa4b0519c64aede2004a57eeceb625 --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/fvSolution @@ -0,0 +1,61 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object fvSolution; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +SIMPLE +{ + nNonOrthogonalCorrectors 0; +} + +solvers +{ + "p.*|pa.*" + { + solver PCG; + preconditioner DIC; + tolerance 1e-14; + relTol 0.01; + }; + "m|ma" + { + solver PCG; + preconditioner DIC; + tolerance 1e-14; + relTol 0.01; + }; + "U.*|Ua.*" + { + solver PBiCGStab; + preconditioner DILU; + tolerance 1e-14; + relTol 0.1; + } +} + +relaxationFactors +{ + fields + { + "p.*" 0.8; + "pa.*" 0.8; + } + equations + { + "U.*" 0.9; + "Ua.*" 0.9; + } +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/optimisationDict new file mode 100644 index 0000000000000000000000000000000000000000..54cb109b59e2f5f921d6753c1fb8c5a3e829b8bf --- /dev/null +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/naca0012/laminar/multipleConstraints/system/optimisationDict @@ -0,0 +1,209 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v2306 | +| \\ / A nd | Website: www.openfoam.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object optimisationDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +optimisationManager steadyOptimisation; + +primalSolvers +{ + p1 + { + active true; + type incompressible; + solver simple; + consistent true; + solutionControls + { + nIters 3000; + nInitialIters 10000; + consistent true; + residualControl + { + "p.*" 1.e-7; + "U.*" 1.e-7; + } + } + } +} + +adjointManagers +{ + am1 + { + primalSolver p1; + adjointSolvers + { + as1 + { + // choose adjoint solver + //---------------------- + active true; + type incompressible; + solver adjointSimple; + consistent true; + + // manage objectives + //------------------ + objectives + { + type incompressible; + objectiveNames + { + drag + { + weight 1.; + type force; + patches (pressure suction); + direction (0.9993908270189999 0.034899496703 0); + Aref 2.; + rhoInf 1.225; + UInf 6; + normalize true; + } + } + } + + // ATC treatment + //-------------- + ATCModel + { + ATCModel standard; + } + + // solution control + //------------------ + solutionControls + { + nIters 3000; + nInitialIters 10000; + consistent true; + residualControl + { + "pa.*" 1.e-7; + "Ua.*" 1.e-7; + } + } + } + lift + { + // choose adjoint solver + //---------------------- + active true; + type incompressible; + solver adjointSimple; + isDoubleSidedConstraint true; + consistent true; + + // manage objectives + //------------------ + objectives + { + type incompressible; + objectiveNames + { + lift + { + weight 1000.; + type force; + patches (pressure suction); + direction (-0.034899496703 0.9993908270189999 0); + Aref 2.; + rhoInf 1.225; + UInf 6; + target 0.05340147181439196; + targetLeft 0.05320147181439196; + } + } + } + + // ATC treatment + //-------------- + ATCModel + { + ATCModel standard; + } + + // solution control + //------------------ + solutionControls + { + nIters 3000; + nInitialIters 10000; + consistent true; + residualControl + { + "pa.*" 1.e-7; + "Ua.*" 1.e-7; + } + } + } + vol + { + // choose adjoint solver + //---------------------- + active true; + type null; + isConstraint true; + + // manage objectives + //------------------ + objectives + { + type geometric; + objectiveNames + { + vol + { + weight -1; + type partialVolume; + patches (pressure suction); + target -0.15; + } + } + } + } + } + } +} + +optimisation +{ + convergence + { + objective 1.e-04; + } + designVariables + { + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (pressure suction); + maxInitChange 5.e-3; + nonOverlappingCPs true; + } + updateMethod + { + method ISQP; + delta 1; + lineSearch + { + type ArmijoConditions; + stepUpdateType quadratic; + minRatio 0.05; + } + } +} + +// ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/constrained/SQP/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/constrained/SQP/system/optimisationDict index 881ac144c5fba29206a912eff1a3dcfae45220c6..f6cb8b0389c9395d48b22d18e7037aaa139ca5e3 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/constrained/SQP/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/constrained/SQP/system/optimisationDict @@ -88,14 +88,13 @@ adjointManagers // choose adjoint solver //---------------------- active true; - type incompressible; - solver adjointSimple; + type null; isConstraint true; // manage objectives //------------------ objectives { - type incompressible; + type geometric; objectiveNames { @@ -107,25 +106,6 @@ adjointManagers } } } - - // ATC treatment - //-------------- - ATCModel - { - ATCModel standard; - } - - // solution control - //------------------ - solutionControls - { - nIters 3000; - residualControl - { - "pa.*" 1.e-7; - "Ua.*" 1.e-7; - } - } } } } @@ -133,16 +113,13 @@ adjointManagers optimisation { - optimisationType - { - type shapeOptimisation; - writeEachMesh true; - } - - sensitivities + designVariables { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (lower upper); + maxInitChange 2.e-3; } updateMethod @@ -155,12 +132,6 @@ optimisation scaleFirstHessian true; } } - - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS-transformBox/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS-transformBox/system/optimisationDict index b072281b84c6d00f6f277617870d78ec2b947ccc..bad6497e5e4464a0ce6f168f07cc8535fcf91b2a 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS-transformBox/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS-transformBox/system/optimisationDict @@ -91,16 +91,13 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (lower upper); + maxInitChange 2.e-3; } updateMethod @@ -113,12 +110,6 @@ optimisation scaleFirstHessian true; } } - - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS/system/optimisationDict index b072281b84c6d00f6f277617870d78ec2b947ccc..bad6497e5e4464a0ce6f168f07cc8535fcf91b2a 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/BFGS/system/optimisationDict @@ -91,16 +91,13 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (lower upper); + maxInitChange 2.e-3; } updateMethod @@ -113,12 +110,6 @@ optimisation scaleFirstHessian true; } } - - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/SD/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/SD/system/optimisationDict index cddc8885b167b041a6a9a3ef9a7dccb799c02cb8..860e5996e30c691bf1def5e44f4c2bc76c16e464 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/SD/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/losses/SD/system/optimisationDict @@ -90,25 +90,18 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (lower upper); + maxInitChange 2.e-3; } updateMethod { method steepestDescent; } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/uniformityCellZone/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/uniformityCellZone/system/optimisationDict index 51028cddc98e8a33f0bb9198ae756299b4b588b4..c356a980f8341d57fd5cce797845737f6bced262 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/uniformityCellZone/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/opt/unconstrained/uniformityCellZone/system/optimisationDict @@ -91,16 +91,13 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (lower upper); + maxInitChange 2.e-3; } updateMethod @@ -113,12 +110,6 @@ optimisation scaleFirstHessian true; } } - - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/primalAdjoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/primalAdjoint/system/optimisationDict index ba6f484792acda27fb9fab1ffe55f16384bd175a..30ef057dc41fa598eec67ba9f877f6afbe91986a 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/primalAdjoint/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/laminar/primalAdjoint/system/optimisationDict @@ -92,50 +92,28 @@ adjointManagers optimisation { - sensitivities + designVariables { - type multiple; // used to compute many kinds of sensitivities at the same time - patches (lower upper); - sensTypes + type shape; + shapeType Bezier; + sensitivityType multiple; + sensitivityTypes (FI ESI SI); + patches (lower upper); + FI { - FIVolSplines - { - type volumetricBSplinesFI; - patches (lower upper); - } - ESIVolSplines - { - type volumetricBSplines; - patches (lower upper); - } - SIVolSplines - { - type volumetricBSplines; - patches (lower upper); - surfaceSensitivities - { - includeMeshMovement false; - } - } - FIBezier - { - type BezierFI; - patches (lower upper); - } - ESIBezier - { - type Bezier; - patches (lower upper); - } - SIBezier - { - type Bezier; - patches (lower upper); - surfaceSensitivities - { - includeMeshMovement false; - } - } + sensitivityType shapeFI; + patches (lower upper); + } + ESI + { + sensitivityType shapeESI; + patches (lower upper); + } + SI + { + sensitivityType shapeESI; + patches (lower upper); + includeMeshMovement false; } } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/controlDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/controlDict index d9ac5b98f9db4276180f796e519f7f56f7b4bad9..b4a97b7ec7fd971780b5fb585582b49ff062f21f 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/controlDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/controlDict @@ -1,10 +1,11 @@ /*--------------------------------*- C++ -*----------------------------------*\ | ========= | | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | -| \\ / O peration | Version: v2306 | +| \\ / O peration | Version: 2306 | | \\ / A nd | Website: www.openfoam.com | | \\/ M anipulation | | \*---------------------------------------------------------------------------*/ +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // FoamFile { version 2; @@ -12,7 +13,6 @@ FoamFile class dictionary; object controlDict; } -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // application adjointOptimisationFoam; diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/optimisationDict index 38b87855c1716832717092ee958ede11d256ba1c..7871c43408da4551e3468566aac8d54c4e0d8eae 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-continuation/system/optimisationDict @@ -92,17 +92,15 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (lower upper); + maxInitChange 2.e-3; } - sensitivities - { - type volumetricBSplinesFI; - patches (lower upper); - } updateMethod { method BFGS; @@ -110,27 +108,8 @@ optimisation { etaHessian 0.8; scaleFirstHessian true; - /* - activeDesignVariables - ( - 141 142 144 145 147 148 - 150 151 153 154 168 169 - 171 172 174 175 177 178 - 180 181 195 196 198 199 - 201 202 204 205 207 208 - 222 223 225 226 228 229 - 231 232 234 235 249 250 - 252 253 255 256 258 259 - 261 262 - ); - */ } } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-oneGo/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-oneGo/system/optimisationDict index 38b87855c1716832717092ee958ede11d256ba1c..7871c43408da4551e3468566aac8d54c4e0d8eae 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-oneGo/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS-oneGo/system/optimisationDict @@ -92,17 +92,15 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (lower upper); + maxInitChange 2.e-3; } - sensitivities - { - type volumetricBSplinesFI; - patches (lower upper); - } updateMethod { method BFGS; @@ -110,27 +108,8 @@ optimisation { etaHessian 0.8; scaleFirstHessian true; - /* - activeDesignVariables - ( - 141 142 144 145 147 148 - 150 151 153 154 168 169 - 171 172 174 175 177 178 - 180 181 195 196 198 199 - 201 202 204 205 207 208 - 222 223 225 226 228 229 - 231 232 234 235 249 250 - 252 253 255 256 258 259 - 261 262 - ); - */ } } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/multiPoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/multiPoint/system/optimisationDict index 14bca2ce560fcf1e1a619fdbd7ecd5cea2302ec2..734f4f21753a5a45e8a4090fe63f5b15920b12e1 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/multiPoint/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/multiPoint/system/optimisationDict @@ -163,17 +163,15 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (lower upper); + maxInitChange 2.e-3; } - sensitivities - { - type volumetricBSplinesFI; - patches (lower upper); - } updateMethod { method BFGS; @@ -184,11 +182,6 @@ optimisation scaleFirstHessian true; } } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op1/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op1/system/optimisationDict index bd10cc6a18f39ec5652b2cf2ba772dd20beb9851..558152e13cf053adb94dc9c009f19f07a8ac40dc 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op1/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op1/system/optimisationDict @@ -92,17 +92,15 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (lower upper); + maxInitChange 2.e-3; } - sensitivities - { - type volumetricBSplinesFI; - patches (lower upper); - } updateMethod { method BFGS; @@ -113,11 +111,6 @@ optimisation scaleFirstHessian true; } } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op2/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op2/system/optimisationDict index b072281b84c6d00f6f277617870d78ec2b947ccc..bad6497e5e4464a0ce6f168f07cc8535fcf91b2a 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op2/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/losses/BFGS/op2/system/optimisationDict @@ -91,16 +91,13 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches (lower upper); + maxInitChange 2.e-3; } updateMethod @@ -113,12 +110,6 @@ optimisation scaleFirstHessian true; } } - - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/nutSqr/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/nutSqr/system/optimisationDict index 2fb015f5e3123b6a846b218a9e59182b343224d7..ef3990dc4d5c82cfe40cb557ff1f217eb9b874f2 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/nutSqr/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/nutSqr/system/optimisationDict @@ -93,17 +93,15 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (lower upper); + maxInitChange 2.e-3; } - sensitivities - { - type volumetricBSplinesFI; - patches (lower upper); - } updateMethod { method BFGS; @@ -113,11 +111,7 @@ optimisation scaleFirstHessian true; } } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } + // ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/powerDissipation/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/powerDissipation/system/optimisationDict index 395fb48ee60640899feaff5e54d32dc2c83ce015..41f30823737ec0bae66aa8192f234223b602f90c 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/powerDissipation/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/opt/powerDissipation/system/optimisationDict @@ -93,17 +93,15 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; + patches (lower upper); + maxInitChange 2.e-3; } - sensitivities - { - type volumetricBSplinesFI; - patches (lower upper); - } updateMethod { method BFGS; @@ -113,11 +111,6 @@ optimisation scaleFirstHessian true; } } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 2.e-3; - } } // ************************************************************************* // diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjoint/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjoint/system/optimisationDict index ba6f484792acda27fb9fab1ffe55f16384bd175a..30ef057dc41fa598eec67ba9f877f6afbe91986a 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjoint/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjoint/system/optimisationDict @@ -92,50 +92,28 @@ adjointManagers optimisation { - sensitivities + designVariables { - type multiple; // used to compute many kinds of sensitivities at the same time - patches (lower upper); - sensTypes + type shape; + shapeType Bezier; + sensitivityType multiple; + sensitivityTypes (FI ESI SI); + patches (lower upper); + FI { - FIVolSplines - { - type volumetricBSplinesFI; - patches (lower upper); - } - ESIVolSplines - { - type volumetricBSplines; - patches (lower upper); - } - SIVolSplines - { - type volumetricBSplines; - patches (lower upper); - surfaceSensitivities - { - includeMeshMovement false; - } - } - FIBezier - { - type BezierFI; - patches (lower upper); - } - ESIBezier - { - type Bezier; - patches (lower upper); - } - SIBezier - { - type Bezier; - patches (lower upper); - surfaceSensitivities - { - includeMeshMovement false; - } - } + sensitivityType shapeFI; + patches (lower upper); + } + ESI + { + sensitivityType shapeESI; + patches (lower upper); + } + SI + { + sensitivityType shapeESI; + patches (lower upper); + includeMeshMovement false; } } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjointFullSetup/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjointFullSetup/system/optimisationDict index 03f7f9d4796e83eea7ed8b8880ffb1e42b99924f..aa22acfe8361588e660c6f0dae69a89d02464e06 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjointFullSetup/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/SA/primalAdjointFullSetup/system/optimisationDict @@ -94,132 +94,28 @@ adjointManagers optimisation { - sensitivities + designVariables { - type multiple; // used to compute many kinds of sensitivities at the same time - patches (lower upper); - sensTypes + type shape; + shapeType Bezier; + sensitivityType multiple; + sensitivityTypes (FI ESI SI); + patches (lower upper); + FI { - FIVolSplines - { - type volumetricBSplinesFI; - patches (lower upper); - includeDistance true; - adjointEikonalSolver - { - iters 1000; - tolerance 1.e-6; - } - } - ESIVolSplines - { - type volumetricBSplines; - patches (lower upper); - includeObjectiveContribution true; // one of this or the equivalent flag in - // surfaceSensitivities has to be set to true - // with this being the prefered one - surfaceSensitivities - { - patches (lower upper); - includeSurfaceArea true; - includeMeshMovement true; - includeDistance true; - includeObjectiveContribution false; - - // adjointEikonal and adjointMeshMovement solvers should be always nested - // within the dictionary of the sensitivity type they correspond to. - // For (E)SI based sensitivities, this means the surfaceSensitivities dict - // Default values are provided, so the dictionaries can be skipped - adjointEikonalSolver - { - iters 1000; - tolerance 1.e-6; - } - adjointMeshMovementSolver - { - iters 10000; - tolerance 1.e-6; - } - } - } - SIVolSplines - { - type volumetricBSplines; - patches (lower upper); - includeObjectiveContribution true; // same comment as above - surfaceSensitivities - { - patches (lower upper); - includeSurfaceArea true; - includeMeshMovement false; - includeDistance true; - includeObjectiveContribution false; - adjointEikonalSolver - { - iters 1000; - tolerance 1.e-6; - } - } - } - FIBezier - { - type BezierFI; - includeDistance true; - patches (lower upper); - dxdbSolver - { - iters 1000; - tolerance 1.e-6; - } - adjointEikonalSolver - { - iters 1000; - tolerance 1.e-6; - } - } - ESIBezier - { - type Bezier; - includeObjectiveContribution true; // same comment as above - surfaceSensitivities - { - patches (lower upper); - includeSurfaceArea true; - includeMeshMovement true; - includeDistance true; - includeObjectiveContribution false; - adjointEikonalSolver - { - iters 1000; - tolerance 1.e-6; - } - adjointMeshMovementSolver - { - iters 10000; - tolerance 1.e-6; - } - } - patches (lower upper); - } - SIBezier - { - type Bezier; - includeObjectiveContribution true; // same comment as above - surfaceSensitivities - { - patches (lower upper); - includeSurfaceArea true; - includeMeshMovement false; - includeDistance true; - includeObjectiveContribution false; - adjointEikonalSolver - { - iters 1000; - tolerance 1.e-6; - } - } - patches (lower upper); - } + sensitivityType shapeFI; + patches (lower upper); + } + ESI + { + sensitivityType shapeESI; + patches (lower upper); + } + SI + { + sensitivityType shapeESI; + patches (lower upper); + includeMeshMovement false; } } } diff --git a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/kOmegaSST/opt/system/optimisationDict b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/kOmegaSST/opt/system/optimisationDict index 4adb513df426ada0cf931188e41c7a8289fbac97..ef4ba5751e52c5f216262c09edc4cbff665fb431 100644 --- a/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/kOmegaSST/opt/system/optimisationDict +++ b/tutorials/incompressible/adjointOptimisationFoam/shapeOptimisation/sbend/turbulent/kOmegaSST/opt/system/optimisationDict @@ -95,25 +95,18 @@ adjointManagers optimisation { - optimisationType + designVariables { - type shapeOptimisation; - writeEachMesh true; - } - sensitivities - { - type volumetricBSplinesFI; + type shape; + shapeType volumetricBSplines; + sensitivityType shapeFI; patches ( lower upper ); + maxInitChange 0.002; } updateMethod { method BFGS; } - meshMovement - { - type volumetricBSplines; - maxAllowedDisplacement 0.002; - } } // ************************************************************************* //