60 tmp<scalarField> designVarsConstraints =
designVars_().constraintValues();
61 if (designVarsConstraints)
72 for (adjointSolverManager& adjSolvManager : adjointSolvManagers_)
74 for (adjointSolver& solver : adjSolvManager.adjointSolvers())
76 if (!isA<adjointNull>(solver))
90 <<
setw(width) <<
"#Cycle" <<
" " 91 <<
setw(width) <<
"LineSearchIters" <<
" " 92 <<
setw(width) <<
"CycleCPUcost" <<
" " 93 <<
setw(width) <<
"CyclePrimalSolutions" <<
" " 94 <<
setw(width) <<
"CycleAdjointSolutions" <<
" " 95 <<
setw(width) <<
"TotalCPUcost" <<
" " 96 <<
setw(width) <<
"TotalPrimalSolutions" <<
" " 97 <<
setw(width) <<
"TotalAdjointSolutions" <<
endl;
104 label cyclePrimalSolutions(nPrimalsPerCycle_);
105 label cycleAdjointSolutions(nAdjointsPerCycle_);
106 label lineSearchIters(1);
109 lineSearchIters = lineSearch_().innerIter();
110 cyclePrimalSolutions *= lineSearchIters;
111 if (lineSearch_().computeGradient())
113 cycleAdjointSolutions *= lineSearchIters;
116 if (zeroAdjointSolns)
118 cycleAdjointSolutions = 0;
120 nPrimalSolutions_ += cyclePrimalSolutions;
121 nAdjointSolutions_ += cycleAdjointSolutions;
122 const scalar elapsedCpuTime = mesh_.time().elapsedCpuTime();
123 const scalar cycleCost = elapsedCpuTime - CPUcost_;
124 CPUcost_ = elapsedCpuTime;
127 <<
setw(width) << mesh_.time().timeName() <<
" " 128 <<
setw(width) << lineSearchIters <<
" " 129 <<
setw(width) << cycleCost <<
" " 130 <<
setw(width) << cyclePrimalSolutions <<
" " 131 <<
setw(width) << cycleAdjointSolutions <<
" " 132 <<
setw(width) << CPUcost_ <<
" " 133 <<
setw(width) << nPrimalSolutions_ <<
" " 134 <<
setw(width) << nAdjointSolutions_ <<
endl;
141 Foam::designVariablesUpdate::designVariablesUpdate
152 designVars_(designVars),
158 dict_.subDict(
"updateMethod"),
167 dict_.subDict(
"updateMethod").subOrEmptyDict(
"lineSearch"),
172 CPUcostFile_(mesh_.time().globalPath()/
"optimisation"/
"CPUcost"),
174 nAdjointsPerCycle_(nAdjointSolvers()),
175 nPrimalSolutions_(nPrimalsPerCycle_),
176 nAdjointSolutions_(nAdjointsPerCycle_),
178 designVarsThreshold_(nullptr),
179 objectiveThreshold_(nullptr),
180 convergenceCriteriaDefined_(false),
181 feasibilityThreshold_
183 dict.subOrEmptyDict(
"convergence").
184 getOrDefault<scalar>(
"feasibilityThreshold", 1.
e-06)
188 if (convergenceDict.
found(
"designVariables"))
191 (
new scalar(convergenceDict.
get<scalar>(
"designVariables")));
193 if (convergenceDict.
found(
"objective"))
196 (
new scalar(convergenceDict.
get<scalar>(
"objective")));
203 <<
"Neither eta (updateMethod) or maxInitChange (designVariables) " 217 const auto& cnstrTable =
218 *(constrainedOptimisationMethod::dictionaryConstructorTablePtr_);
222 <<
"Found " << nConstr <<
" adjoint solvers corresponding to " 223 <<
"constraints but the optimisation method (" 225 <<
") is not a constrainedOptimisationMethod." <<
nl 226 <<
"Available constrainedOptimisationMethods:" <<
nl 227 << cnstrTable.sortedToc()
238 <<
"Did not find any adjoint solvers corresponding to " 239 <<
"constraints but the optimisation method (" 241 <<
") is a constrainedOptimisationMethod." <<
nl <<
nl 242 <<
"This can cause some constraintOptimisationMethods to misbehave." 244 <<
"Either the isConstraint bool is not set in one of the adjoint " 245 <<
"solvers or you should consider using an updateMethod " 246 <<
"that is not a constrainedOptimisationMethod" 252 Info<<
"Optimisation will run until the max. scaled correction " 258 Info<<
"Optimisation will run until the relative update of the " 264 Info<<
"No convergence criterion defined for optimsation" <<
nl 266 <<
" optimisation cycles " <<
nl <<
endl;
284 setOldObjectiveValue();
311 updateGradientsAndValues();
312 updateMethod_->computeCorrection();
316 if (!updateMethod_->initialEtaSet() || designVars_->resetEta())
318 const scalar eta(designVars_->computeEta(
correction));
319 updateMethod_->modifyStep(eta);
320 updateMethod_->initialEtaSet() =
true;
331 PtrList<scalarField> constraintSens;
332 scalar objectiveValue(
Zero);
333 DynamicList<scalar> constraintValues;
335 for (adjointSolverManager& adjSolvManager : adjointSolvManagers_)
337 const scalar opWeight = adjSolvManager.operatingPointWeight();
341 tmp<scalarField> tadjointSolverManagerSens =
342 adjSolvManager.aggregateSensitivities();
346 objectiveValue += opWeight*adjSolvManager.objectiveValue();
349 PtrList<scalarField> adjointSolverManagerConstSens =
350 adjSolvManager.constraintSensitivities();
355 designVars_->postProcessSens
357 tadjointSolverManagerSens.ref(),
358 adjointSolverManagerConstSens,
359 adjSolvManager.adjointSolversNames(),
360 adjSolvManager.isMaster()
363 if (objectiveSens.empty())
365 objectiveSens.setSize(tadjointSolverManagerSens().size(),
Zero);
369 objectiveSens += opWeight*tadjointSolverManagerSens();
370 forAll(adjointSolverManagerConstSens, sI)
373 push_back(adjointSolverManagerConstSens.set(sI,
nullptr));
375 constraintValues.push_back(adjSolvManager.constraintValues());
378 tmp<scalarField> designVarsConstValues = designVars_->constraintValues();
379 PtrList<scalarField> designVarsConstDerivs =
380 designVars_->constraintDerivatives();
381 if (designVarsConstValues && designVarsConstDerivs.size())
383 if (designVarsConstValues().size() != designVarsConstDerivs.size())
386 <<
"Size of design variables constraints and derivatives differ" 390 constraintValues.push_back(designVarsConstValues());
391 constraintSens.push_back(std::move(designVarsConstDerivs));
395 updateMethod_->setObjectiveDeriv(objectiveSens);
396 updateMethod_->setConstraintDeriv(constraintSens);
397 updateMethod_->setObjectiveValue(objectiveValue);
398 updateMethod_->setConstraintValues
405 scalar objectiveValue(
Zero);
408 const scalar opWeight = adjSolvManager.operatingPointWeight();
409 objectiveValue += opWeight*adjSolvManager.objectiveValue();
411 return objectiveValue;
417 updateMethod_->setObjectiveValueOld(computeObjectiveValue());
425 scalar objectiveValue(
Zero);
430 const scalar opWeight = adjSolvManager.operatingPointWeight();
432 objectiveValue += opWeight*adjSolvManager.objectiveValue();
433 constraintValues.
push_back(adjSolvManager.constraintValues());
437 tmp<scalarField> designVarsConstValues = designVars_->constraintValues();
438 if (designVarsConstValues)
440 constraintValues.
push_back(designVarsConstValues());
442 updateMethod_->setObjectiveValue(objectiveValue);
443 updateMethod_->setConstraintValues
446 return updateMethod_->computeMeritFunction();
452 return updateMethod_->meritFunctionDirectionalDerivative();
461 updateMethod_->updateOldCorrection(oldCorrection);
467 updateMethod_->writeAuxiliaryData();
468 designVars_->writeDesignVars();
475 updateOldCorrection(oldCorrection);
477 designVars_->evolveNumber();
480 lineSearch_->postUpdate();
490 as.getObjectiveManager().getObjectiveFunctions();
493 obj.writeInstantaneousSeparator();
504 if (!convergenceCriteriaDefined_)
509 bool converged(
false);
510 const scalarField& oldCorrection = updateMethod_->returnCorrection();
512 if (designVarsThreshold_)
515 designVars_->activeDesignVariables();
517 const scalarField activeVars(designVars_->getVars(), activeVarIDs);
518 const scalar scaledCorrection =
522 <<
"Active vars " << activeVars <<
endl;
523 Info<<
"Max. scaled correction of the design variables = " 526 if (scaledCorrection < designVarsThreshold_())
528 Info<<
tab <<
"Design variables have converged " <<
endl;
533 if (objectiveThreshold_ && updateMethod_->getObjectiveValueOld())
535 const scalar newObjective = computeObjectiveValue();
536 const scalar oldObjective = updateMethod_->getObjectiveValueOld()();
537 const scalar relativeUpdate =
538 mag(newObjective - oldObjective)/(
mag(oldObjective) + SMALL);
539 Info<<
"Relative change of the objective value = " 542 if (relativeUpdate < objectiveThreshold_())
544 Info<<
tab <<
"Objective function has converged " <<
endl;
549 const scalarField& constraints = updateMethod_->getConstraintValues();
550 const scalar feasibility =
sum(
pos(constraints)*constraints);
551 Info<<
"Feasibility = " << feasibility <<
endl;
552 if (converged && feasibility < feasibilityThreshold_)
554 Info<<
"Stopping criteria met and all constraints satisfied." <<
nl 555 <<
"Optimisation has converged, stopping ..." <<
nl <<
nl 560 for (adjointSolverManager& am : adjointSolvManagers_)
562 for (adjointSolver& as : am.adjointSolvers())
565 as.getObjectiveManager().writeObjectives();
568 writeToCostFile(
true);
PtrList< adjointSolverManager > & adjointSolvManagers_
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
A class encapsulating functionality neccessary to perform an optimisation loop, such as updating the ...
void writeCPUcostHeader()
Write CPU cost header.
const Type & value() const noexcept
Return const reference to value.
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1)
void postUpdate(const scalarField &oldCorrection)
Steps to be executed after the susccessfull update of the design varibles, i.e. the last step of line...
errorManipArg< error, int > exit(error &err, const int errNo=1)
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
label nAdjointSolvers() const
Get total number of adjoint solvers.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
constexpr char nl
The newline '\n' character (0x0a)
Abstract base class for optimisation methods.
bool convergenceCriteriaDefined_
Is at least a single convergence criterion defined.
Ostream & endl(Ostream &os)
Add newline and flush stream.
static bool & parRun() noexcept
Test if this a parallel run.
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tf1, const word &name, const dimensionSet &dimensions, const bool initCopy=false)
Global function forwards to reuseTmpDimensionedField::New.
static unsigned int defaultPrecision() noexcept
Return the default precision.
Base class for adjoint solvers.
constexpr char tab
The tab '\t' character(0x09)
virtual dimensionedScalar endTime() const
Return end time.
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
const Time & time() const
Return the top-level database.
autoPtr< designVariables > & designVars_
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
label nConstraints(PtrList< adjointSolverManager > &adjointSolverManagers) const
Get the number of adjoint solvers that correspond to constraints.
#define forAll(list, i)
Loop across all elements in list.
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
dimensionedScalar pos(const dimensionedScalar &ds)
autoPtr< scalar > objectiveThreshold_
The relative update of the objective value w.r.t. to its last value should be smaller than this value...
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
tmp< scalarField > computeDirection()
Compute update direction.
const dimensionedScalar e
Elementary charge.
static void exit(int errNo=1)
Shutdown (finalize) MPI as required and exit program with errNo.
scalar feasibilityThreshold_
In case of a constrained optimisation, the sum of positive constraints should be lower than this valu...
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void write()
Write useful quantities to files.
scalar computeObjectiveValue()
Sum objective values from all adjointSolverManagers.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
#define DebugInfo
Report an information message using Foam::Info.
Istream and Ostream manipulators taking arguments.
Abstract base class for objective functions. No point in making this runTime selectable since its chi...
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
scalar meritFunctionDirectionalDerivative()
Derivative of the merit function.
scalar computeMeritFunction()
Compute the merit function of the optimisation problem.
void push_back(const T &val)
Copy append an element to the end of this list.
Abstract base class for line search methods.
void writeToCostFile(bool zeroAdjointSolns=false)
Write to cost file.
Class for managing adjoint solvers, which may be more than one per operating point.
autoPtr< scalar > designVarsThreshold_
The maximum of the correction/designVariables values must be lower that this threshold to consider th...
#define WarningInFunction
Report a warning using Foam::Warning.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Mesh data needed to do the Finite Volume discretisation.
void updateOldCorrection(const scalarField &)
Update old correction. Needed for quasi-Newton Methods.
void update()
Update design variables.
messageStream Info
Information stream (stdout output on master, null elsewhere)
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Omanip< int > setw(const int i)
Macros to ease declaration of run-time selection tables.
List< label > labelList
A List of labels.
autoPtr< updateMethod > updateMethod_
Method to update the design variables based on the provided sensitivity derivatives.
A class for managing temporary objects.
void updateGradientsAndValues()
Compute cumulative objective and constraint gradients.
PtrList< adjointSolverManager > & adjointSolverManagers
void setOldObjectiveValue()
Set the old objective value known by the updateMethod.
void checkConvergence()
Check if the optimisation loop has converged based on the provided criteria.
static constexpr const zero Zero
Global zero (0)