ENH: minor update in levelSet-based topology optimisation,

to keep the regularised design variables and the signed distance in
different fields
This commit is contained in:
Vaggelis Papoutsis
2023-11-23 14:59:41 +02:00
committed by Andrew Heather
parent 1f7fb08060
commit 46757d12ec
2 changed files with 62 additions and 94 deletions

View File

@ -26,7 +26,6 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#include "HashSet.H"
#include "levelSetDesignVariables.H" #include "levelSetDesignVariables.H"
#include "wallDist.H" #include "wallDist.H"
#include "zeroGradientFvPatchField.H" #include "zeroGradientFvPatchField.H"
@ -203,7 +202,7 @@ void levelSetDesignVariables::updateBeta()
// Compute the beta field by passing the distance field through // Compute the beta field by passing the distance field through
// a Heaviside function // a Heaviside function
scalarField& beta = beta_.primitiveFieldRef(); scalarField& beta = beta_.primitiveFieldRef();
interpolation_->interpolate(aTilda_.primitiveField(), beta); interpolation_->interpolate(signedDistances_.primitiveField(), beta);
beta = 1 - beta; beta = 1 - beta;
// Apply fixed values if necessary // Apply fixed values if necessary
applyFixedPorosityValues(); applyFixedPorosityValues();
@ -237,32 +236,38 @@ void Foam::levelSetDesignVariables::updateSignedDistances()
y.primitiveFieldRef() = aTilda_.primitiveFieldRef(); y.primitiveFieldRef() = aTilda_.primitiveFieldRef();
y.correctBoundaryConditions(); y.correctBoundaryConditions();
labelList changedFaces(mesh_.nFaces(), -1); changedFaces_.clear();
List<wallPoint> changedFacesInfo(mesh_.nFaces()); changedFaces_.setSize(mesh_.nFaces(), -1);
writeFluidSolidInterface(aTilda_, 0, changedFaces, changedFacesInfo);
List<wallPoint> allFaceInfo(mesh_.nFaces()); changedFacesInfo_.clear();
List<wallPoint> allCellInfo(mesh_.nCells()); changedFacesInfo_.setSize(mesh_.nFaces());
FaceCellWave<wallPoint> wave
writeFluidSolidInterface(aTilda_, 0, changedFaces_, changedFacesInfo_);
List<wallPointData<label>> allFaceInfo(mesh_.nFaces());
allCellInfo_.clear();
allCellInfo_.setSize(mesh_.nCells());
FaceCellWave<wallPointData<label>> wave
( (
mesh_, mesh_,
changedFaces, changedFaces_,
changedFacesInfo, changedFacesInfo_,
allFaceInfo, allFaceInfo,
allCellInfo, allCellInfo_,
mesh_.globalData().nTotalCells() + 1 mesh_.globalData().nTotalCells() + 1
); );
// Transfer the distance from cellInfo to the alphaTilda field // Transfer the distance from cellInfo to the alphaTilda field
forAll(allCellInfo, celli) forAll(allCellInfo_, celli)
{ {
if (allCellInfo[celli].valid(wave.data())) if (allCellInfo_[celli].valid(wave.data()))
{ {
aTilda_[celli] = signedDistances_[celli] =
sign(aTilda_[celli])*Foam::sqrt(allCellInfo[celli].distSqr()); sign(aTilda_[celli])*Foam::sqrt(allCellInfo_[celli].distSqr());
} }
} }
aTilda_.correctBoundaryConditions(); signedDistances_.correctBoundaryConditions();
} }
@ -281,6 +286,20 @@ levelSetDesignVariables::levelSetDesignVariables
regularisation_ regularisation_
(regularisationPDE::New(mesh, dict.subDict("regularisation"), zones_)), (regularisationPDE::New(mesh, dict.subDict("regularisation"), zones_)),
aTilda_ aTilda_
(
IOobject
(
"aTilda",
mesh_.time().timeName(),
mesh_,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
mesh_,
dimensionedScalar(dimless, Zero),
zeroGradientFvPatchField<scalar>::typeName
),
signedDistances_
( (
IOobject IOobject
( (
@ -313,7 +332,10 @@ levelSetDesignVariables::levelSetDesignVariables
), ),
fixATildaValues_(dict.getOrDefault<bool>("fixATildaValues", true)), fixATildaValues_(dict.getOrDefault<bool>("fixATildaValues", true)),
writeAllDistanceFields_ writeAllDistanceFields_
(dict.getOrDefault<bool>("writeAllDistanceFields", false)) (dict.getOrDefault<bool>("writeAllDistanceFields", false)),
changedFaces_(),
changedFacesInfo_(),
allCellInfo_()
{ {
// Read the alpha field if present, or set it based on the distance field // Read the alpha field if present, or set it based on the distance field
readField(); readField();
@ -382,20 +404,18 @@ void levelSetDesignVariables::update(scalarField& correction)
if (writeAllDistanceFields_) if (writeAllDistanceFields_)
{ {
writeDesignVars(); writeDesignVars();
aTilda_.rename("alphaSmoothed");
aTilda_.write(); aTilda_.write();
aTilda_.rename("signedDistances");
} }
// Make aTilda a signed distance field // Compute signed distances based on aTilda
updateSignedDistances(); updateSignedDistances();
// Set beta based on aTilda // Set beta based on the signed distances
updateBeta(); updateBeta();
if (writeAllDistanceFields_) if (writeAllDistanceFields_)
{ {
aTilda_.write(); signedDistances_.write();
beta_.write(); beta_.write();
} }
@ -411,77 +431,13 @@ void levelSetDesignVariables::update(scalarField& correction)
scalar levelSetDesignVariables::computeEta(scalarField& correction) scalar levelSetDesignVariables::computeEta(scalarField& correction)
{ {
// Back-up the old design variables and signed distances const scalar maxChange(gMax(mag(correction)));
scalarField& dvs = getVars(); Info<< "maxInitChange/maxChange \t"
scalarField oldDVs(getVars()); << maxInitChange_() << "/" << maxChange << endl;
scalarField oldSignedDistances(aTilda_.primitiveField()); const scalar eta(maxInitChange_() / maxChange);
// Compute the smooth alpha field corresponding to the initial variables
// Can't use current aTilda_ values since they correspond to signed
// distances at this point
scalarField oldATilda(aTilda_.primitiveField());
regularisation_->regularise
(
aTilda_, dvs, oldATilda,
true, radius_(), upperBounds_()[0], fixATildaValues_
);
// Compute the smooth alpha field corresponding to the updated variables
dvs += correction;
regularisation_->regularise
(
aTilda_, dvs, aTilda_.primitiveFieldRef(),
true, radius_(), upperBounds_()[0], fixATildaValues_
);
aTilda_.correctBoundaryConditions();
// We want to locate the min value of aTilda_ and scale the correction
// appropriately such that this min value takes on the prescribed one.
// A bit tricky in parallel since we need not only the min value but
// its cellId/processor too
const label proci = Pstream::myProcNo();
scalarList minVs(Pstream::nProcs(), pTraits<scalar>::max);
labelList minCells(Pstream::nProcs(), Zero);
scalarField diff(aTilda_.primitiveField() - oldATilda);
label minId = findMin(diff);
if (minId != -1)
{
minVs[proci] = diff[minId];
minCells[proci] = minId;
}
// Collect info from all processors
Pstream::allGatherList(minVs);
Pstream::allGatherList(minCells);
minId = findMin(minVs);
scalar aTildaAtMinChange(Zero);
if (proci == minId)
{
const label cellId = minCells[minId];
aTildaAtMinChange = aTilda_.primitiveField()[cellId];
}
reduce(aTildaAtMinChange, sumOp<scalar>());
DebugInfo
<< "AlphaSmoothed at min(alphaSmoothedUpdate) with eta 1/"
<< "min desirable value "
<< minVs[minId] << '/' << maxInitChange_()
<< endl;
// Compute eta
const scalar eta((maxInitChange_() - aTildaAtMinChange)/minVs[minId] + 1);
Info<< "Setting eta value to " << eta << endl; Info<< "Setting eta value to " << eta << endl;
correction *= eta; correction *= eta;
// Restore the dvs
dvs = oldDVs;
aTilda_.primitiveFieldRef() = oldSignedDistances;
return eta; return eta;
} }
@ -505,7 +461,8 @@ tmp<scalarField> levelSetDesignVariables::assembleSensitivities
scalarField& objectiveSens = tobjectiveSens.ref(); scalarField& objectiveSens = tobjectiveSens.ref();
// Multiply with dBetadAtilda // Multiply with dBetadAtilda
objectiveSens *= -interpolation_->derivative(aTilda_.primitiveField()); objectiveSens *=
-interpolation_->derivative(signedDistances_.primitiveField());
// Solve the adjoint to the regularisation equation // Solve the adjoint to the regularisation equation
regularisation_-> regularisation_->

View File

@ -92,11 +92,13 @@ protected:
//- Regularisation mechanism //- Regularisation mechanism
autoPtr<regularisationPDE> regularisation_; autoPtr<regularisationPDE> regularisation_;
//- The regularised field that is also transformed //- The regularised field
//- into signed distances
volScalarField aTilda_; volScalarField aTilda_;
//- Function to transform signed distances to the indicator field beta_ //- The signed distances field
volScalarField signedDistances_;
//- Function to transorm signed distances to the indicator field beta_
autoPtr<topOInterpolationFunction> interpolation_; autoPtr<topOInterpolationFunction> interpolation_;
//- The indicator field //- The indicator field
@ -108,6 +110,15 @@ protected:
//- Write all fields related to the distance calculation (debugging) //- Write all fields related to the distance calculation (debugging)
bool writeAllDistanceFields_; bool writeAllDistanceFields_;
//- Mesh faces acting as the source of MeshWave
labelList changedFaces_;
//- Seed distances to MeshWave and cell distances
// The data carried by each wallPoints corresponds to the origin
// mesh face ID
List<wallPointData<label>> changedFacesInfo_;
List<wallPointData<label>> allCellInfo_;
// Protected Member Functions // Protected Member Functions