60 tmp<scalarField> designVarsConstraints =
designVars_().constraintValues();
61 if (designVarsConstraints)
72 for (adjointSolverManager& adjSolvManager : adjointSolvManagers_)
74 for (adjointSolver& solver : adjSolvManager.adjointSolvers())
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_ <<
" "
141Foam::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"))
190 designVarsThreshold_.reset
191 (new scalar(convergenceDict.get<scalar>(
"designVariables")));
193 if (convergenceDict.
found(
"objective"))
195 objectiveThreshold_.reset
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
265 <<
"It will run for " <<
mesh_.time().endTime().value()
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());
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);
405 scalar objectiveValue(
Zero);
408 const scalar opWeight = adjSolvManager.operatingPointWeight();
409 objectiveValue += opWeight*adjSolvManager.objectiveValue();
411 return objectiveValue;
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);
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
565 as.getObjectiveManager().writeObjectives();
568 writeToCostFile(
true);
Istream and Ostream manipulators taking arguments.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
void push_back(const T &val)
Copy append an element to the end of this list.
static unsigned int defaultPrecision() noexcept
Return the default precision.
void setSize(label n)
Alias for resize().
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
const T * set(const label i) const
Return const pointer to element (can be nullptr), or nullptr for out-of-range access (ie,...
void push_back(T *ptr)
Append an element to the end of the list.
bool empty() const noexcept
True if List is empty (ie, size() is zero).
static bool parRun(const bool on) noexcept
Set as parallel run on/off.
static void exit(int errNo=1)
Shutdown (finalize) MPI as required and exit program with errNo.
label size() const noexcept
The number of entries in the list.
Class for managing adjoint solvers, which may be more than one per operating point.
Base class for adjoint solvers.
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
A class encapsulating functionality neccessary to perform an optimisation loop, such as updating the ...
void checkConvergence()
Check if the optimisation loop has converged based on the provided criteria.
scalar meritFunctionDirectionalDerivative()
Derivative of the merit function.
PtrList< adjointSolverManager > & adjointSolvManagers_
bool convergenceCriteriaDefined_
Is at least a single convergence criterion defined.
void writeCPUcostHeader()
Write CPU cost header.
scalar computeObjectiveValue()
Sum objective values from all adjointSolverManagers.
autoPtr< updateMethod > updateMethod_
Method to update the design variables based on the provided sensitivity derivatives.
void updateOldCorrection(const scalarField &)
Update old correction. Needed for quasi-Newton Methods.
label nAdjointSolvers() const
Get total number of adjoint solvers.
void updateGradientsAndValues()
Compute cumulative objective and constraint gradients.
label nConstraints(PtrList< adjointSolverManager > &adjointSolverManagers) const
Get the number of adjoint solvers that correspond to constraints.
tmp< scalarField > computeDirection()
Compute update direction.
label nAdjointSolutions_
Adjoint evaluations performed so far.
autoPtr< scalar > objectiveThreshold_
The relative update of the objective value w.r.t. to its last value should be smaller than this value...
autoPtr< lineSearch > lineSearch_
Line search mechanism to approximate the update step length.
scalar feasibilityThreshold_
In case of a constrained optimisation, the sum of positive constraints should be lower than this valu...
scalar computeMeritFunction()
Compute the merit function of the optimisation problem.
label nPrimalsPerCycle_
Primal solutions per optimisation cycle.
OFstream CPUcostFile_
Output file.
void write()
Write useful quantities to files.
label nAdjointsPerCycle_
Adjoint solutions per optimisation cycle.
void postUpdate(const scalarField &oldCorrection)
Steps to be executed after the susccessfull update of the design varibles, i.e. the last step of line...
void update()
Update design variables.
autoPtr< designVariables > & designVars_
autoPtr< scalar > designVarsThreshold_
The maximum of the correction/designVariables values must be lower that this threshold to consider th...
label nPrimalSolutions_
Primal evaluations performed so far.
void writeToCostFile(bool zeroAdjointSolns=false)
Write to cost file.
scalar CPUcost_
CPU cost (in seconds).
void setOldObjectiveValue()
Set the old objective value known by the updateMethod.
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
bool found(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Mesh data needed to do the Finite Volume discretisation.
Abstract base class for line search methods.
Abstract base class for objective functions. No point in making this runTime selectable since its chi...
A class for managing temporary objects.
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
T & ref() const
Return non-const reference to the contents of a non-null managed pointer.
Abstract base class for optimisation methods.
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
dimensionedScalar pos(const dimensionedScalar &ds)
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.
List< label > labelList
A List of labels.
messageStream Info
Information stream (stdout output on master, null elsewhere).
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Omanip< int > setw(const int i)
Ostream & endl(Ostream &os)
Add newline and flush stream.
const Type * isA(const U &obj)
Attempt dynamic_cast to Type.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1, const label comm)
static constexpr const zero Zero
Global zero (0).
tmp< fvMatrix< Type > > correction(const fvMatrix< Type > &)
Return the correction form of the given matrix by subtracting the matrix multiplied by the current fi...
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
errorManipArg< error, int > exit(error &err, const int errNo=1)
Type gMax(const FieldField< Field, Type > &f)
constexpr char nl
The newline '\n' character (0x0a).
constexpr char tab
The tab '\t' character(0x09).
Macros to ease declaration of run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
PtrList< adjointSolverManager > & adjointSolverManagers