ENH: nullSpace will now perturb the design variables

by a small amount, if all of them lay on the lower or upper bounds at
the beginning of the optimisation, to avoid singular matrices when
computing the update of the design variables.
This commit is contained in:
Vaggelis Papoutsis 2023-11-23 14:48:11 +02:00 committed by Andrew Heather
parent e764f7b573
commit bf18fb758c
2 changed files with 63 additions and 0 deletions

View File

@ -971,6 +971,7 @@ Foam::nullSpace::nullSpace
coeffsDict(type).
getOrDefault<scalar>("violatedConstraintsThreshold", 1.e-3)
),
epsPerturb_(coeffsDict(type). getOrDefault<scalar>("perturbation", 1.e-2)),
aJ_(coeffsDict(type).getOrDefault<scalar>("aJ", 1)),
aC_(coeffsDict(type).getOrDefault<scalar>("aC", 1)),
adaptiveStep_(coeffsDict(type).getOrDefault<bool>("adaptiveStep", true)),
@ -1003,6 +1004,64 @@ Foam::nullSpace::nullSpace
<< exit(FatalError);
}
// Sanity checks for the bounds of the design variables.
// If all design variables start from either their lower or upper bound
// and there is at least one active flow-related constraint, the systems
// providing the update of the desgin varaibles become singular.
// Issue a warning and change the initial values of the design variables
// by a small ammount, to kick start the optimisation
if (designVars_->lowerBounds() && designVars_->upperBounds())
{
const scalarField& lowerBounds = designVars_->lowerBoundsRef();
const scalarField& upperBounds = designVars_->upperBoundsRef();
scalarField& designVars = designVars_();
boolList isOnLowerBound(designVars.size(), false);
boolList isOnUpperBound(designVars.size(), false);
bool existsNonBoundVar = false;
for (const label activeVarI : designVars_->activeDesignVariables())
{
isOnLowerBound[activeVarI] =
mag(designVars[activeVarI] - lowerBounds[activeVarI]) < SMALL;
isOnUpperBound[activeVarI] =
mag(designVars[activeVarI] - upperBounds[activeVarI]) < SMALL;
existsNonBoundVar =
existsNonBoundVar
|| (!isOnLowerBound[activeVarI] && !isOnUpperBound[activeVarI]);
}
if (globalSum_)
{
reduce(existsNonBoundVar, orOp<bool>());
}
if (!existsNonBoundVar)
{
WarningInFunction
<< "All design variables lay on their bound values." << nl
<< tab << "This will lead to singular matrices in nullSpace"
<< nl
<< tab << "Perturbing the design variables by "
<< epsPerturb_ << "*(upperBound - lowerBounds)"
<< nl
<< endl;
scalarField update(designVars.size(), Zero);
for (const label activeVarI : designVars_->activeDesignVariables())
{
if (isOnLowerBound[activeVarI])
{
update[activeVarI] =
epsPerturb_
*(upperBounds[activeVarI] - lowerBounds[activeVarI]);
}
if (isOnUpperBound[activeVarI])
{
update[activeVarI] =
- epsPerturb_
*(upperBounds[activeVarI] - lowerBounds[activeVarI]);
}
}
designVars_->update(update);
}
}
// Read-in aJ in restarts
dictionary::readIfPresent("aJ", aJ_);
}

View File

@ -159,6 +159,10 @@ protected:
// constraints
scalar epsConstr_;
//- Value to perturb the design variables by, if all of them
//- lay on their bounds at the beginning of the optimisation
scalar epsPerturb_;
//- Multiplier of the null space update
scalar aJ_;