25#ifndef OPTI_CASE_DUAL_HH
26#define OPTI_CASE_DUAL_HH
35template<
typename S,
template<
typename,SolverMode>
typename SOLVER,
typename C>
36void OptiCaseDual<S,SOLVER,C>::readFromXML(XMLreader
const& xml)
38 std::string type (
"");
39 xml.readOrWarn<std::string>(
"Optimization",
"ControlType",
"", type);
41 xml.readOrWarn<std::string>(
"Optimization",
"Projection",
"", _projectionName);
42 xml.readOrWarn<
int>(
"Optimization",
"ControlMaterial",
"", _controlMaterial);
43 xml.readOrWarn<S>(
"Optimization",
"RegAlpha",
"", _regAlpha);
45 xml.readOrWarn<std::string>(
"Optimization",
"StartValueType",
"", type);
46 if (type ==
"Porosity") {
48 }
else if (type ==
"Permeability") {
50 }
else if (type ==
"Control") {
55 xml.readOrWarn<
bool>(
"Optimization",
"ReferenceSolution",
"", _computeReference);
58template<
typename S,
template<
typename,SolverMode>
typename SOLVER,
typename C>
59void OptiCaseDual<S,SOLVER,C>::initialize(XMLreader
const& xml)
61 _converter = createUnitConverter<S,descriptor>(xml);
63 _referenceSolver = createLbSolver <SOLVER<S,SolverMode::Reference>> (xml);
64 if (_computeReference) {
65 _referenceSolver->solve();
68 _referenceSolver->buildAndReturn();
71 _referenceGeometry = _referenceSolver->parameters(names::Results()).geometry;
72 _referenceLattice = _referenceSolver->parameters(names::Results()).lattice;
80 _serializer = std::make_shared<SimpleGeometrySerializer<S,dim>>(*_referenceGeometry);
81 _dimCtrl = _serializer->getNoCells() * _fieldDim;
83 _controller =
new Controller<S>(_dimCtrl);
85 _primalSolver = createLbSolver <SOLVER<S,SolverMode::Primal>> (xml);
86 _dualSolver = createLbSolver <SOLVER<S,SolverMode::Dual>> (xml);
87 this->_postEvaluation = std::bind(&SOLVER<S,SolverMode::Primal>::postProcess, _primalSolver);
89 if (_computeReference) {
90 _primalSolver->parameters(names::Opti()).referenceSolution
91 = std::make_shared<SuperLatticePhysVelocity3D<S,descriptor>>(*_referenceLattice, *_converter);
92 _primalSolver->parameters(names::Opti()).referencePorosity
93 = std::make_shared<SuperLatticePorosity3D<S,descriptor>>(*_referenceLattice);
97template<
typename S,
template<
typename,SolverMode>
typename SOLVER,
typename C>
98void OptiCaseDual<S,SOLVER,C>::initializeFields()
100 _projection = projection::construct<S,descriptor>(*_converter, _projectionName);
102 _projectedControl = std::make_shared<SuperLatticeSerialDataF<S,descriptor>>(
107 [
this](S x) {
return _projection->project(x); });
108 _dProjectionDcontrol = std::make_shared<SuperLatticeSerialDataF<S,descriptor>>(
113 [
this](S x) {
return _projection->derivative(x); });
114 _primalSolver->parameters(names::Opti()).controlledField = _projectedControl;
115 _dualSolver->parameters(names::Opti()).controlledField = _projectedControl;
119template<
typename S,
template<
typename,SolverMode>
typename SOLVER,
typename C>
121 const C&
control,
unsigned optiStep)
124#ifdef mathiasProjection
126 const int nx = _dualSolver->getGeometry()->getCuboidGeometry().getMotherCuboid().getNx();
127 const int ny = _dualSolver->getGeometry()->getCuboidGeometry().getMotherCuboid().getNy();
128 const int nz = _dualSolver->getGeometry()->getCuboidGeometry().getMotherCuboid().getNz();
133 S wantedTotalD = T();
135 S upperBound, lowerBound, volumeRatio;
136 xml.readOrWarn<T>(
"Optimization",
"UpperBound",
"", upperBound);
137 xml.readOrWarn<T>(
"Optimization",
"LowerBound",
"", lowerBound);
138 xml.readOrWarn<T>(
"Optimization",
"VolumeRatio",
"", volumeRatio);
140 for (
int iX=1; iX<nx-1; iX++) {
141 for (
int iY=1; iY<ny-1; iY++) {
142 for (
int iZ=1; iZ<nz-1; iZ++) {
144 if (_dualSolver->getGeometry()->getMaterial(iX,iY,iZ)==6) {
145 S ctrl =
control[(iX-1)*(ny-1)*(nz-1)+(iY-1)*(nz-1)+(iZ-1)];
146 totalD += 1./(upperBound-lowerBound)*(ctrl-1.);
153 for (
int iX=1; iX<nx-1; iX++) {
154 for (
int iY=1; iY<ny-1; iY++) {
155 for (
int iZ=1; iZ<nz-1; iZ++) {
157 if (_dualSolver->getGeometry()->getMaterial(iX,iY,iZ)==6) {
158 control[(iX-1)*(ny-1)*(nz-1)+(iY-1)*(nz-1)+(iZ-1)]
160 + (
control[(iX-1)*(ny-1)*(nz-1)+(iY-1)*(nz-1)+(iZ-1)] - lowerBound)
161 * wantedTotalD * (1.-volumeRatio) / totalD;
168 _controller->setControl(
control, _dimCtrl);
170 _primalSolver->solve();
176template<
typename S,
template<
typename,SolverMode>
typename SOLVER,
typename C>
178 const C&
control, C& derivatives,
unsigned optiStep)
180 _controller->setControl(
control, _dimCtrl);
183 const auto& primalResults = _primalSolver->parameters(
names::Results());
184 auto& dualParams = _dualSolver->parameters(
names::Opti());
186 dualParams.fpop = primalResults.fpop;
187 dualParams.dObjectiveDf = primalResults.djdf;
188 dualParams.dObjectiveDcontrol = primalResults.djdalpha;
190 _dualSolver->solve();
192 derivativesFromDualSolution(derivatives);
195template<
typename S,
template<
typename,SolverMode>
typename SOLVER,
typename C>
199 const auto& primalGeometry = _primalSolver->parameters(
names::Results()).geometry;
200 const S omega = _converter->getLatticeRelaxationFrequency();
201 const int nC = primalGeometry->getCuboidGeometry().getNc();
203 for (
int iC = 0; iC < nC; iC++) {
205 const Vector<int,3> extend = primalGeometry->getCuboidGeometry().get(iC).getExtent();
207 for (
int iX = 0; iX < extend[0]; iX++) {
208 for (
int iY = 0; iY < extend[1]; iY++) {
209 for (
int iZ = 0; iZ < extend[2]; iZ++) {
213 C derivativesHelp(_fieldDim, 0);
216 const S rho_f = _primalSolver->parameters(
names::Results()).lattice->get(latticeR).computeRho();
217 S dProjectionDcontrol[_fieldDim];
218 (*_dProjectionDcontrol)(dProjectionDcontrol, latticeR.data());
221 S dObjectiveDcontrol[_fieldDim];
222 (*_primalSolver->parameters(
names::Results()).djdalpha)(dObjectiveDcontrol, latticeR.data());
223 for (
int iDim=0; iDim<_fieldDim; iDim++) {
224 for (
int jPop=0; jPop < descriptor::q; ++jPop) {
225 S phi_j = _dualSolver->parameters(
names::Results()).lattice->get(latticeR)[jPop];
226 derivativesHelp[iDim] -= rho_f * descriptors::t<S,descriptor>(jPop)
227 * descriptors::invCs2<S,descriptor>() * descriptors::c<descriptor>(jPop,iDim) * phi_j;
232 const int index = _serializer->getSerializedComponentIndex(latticeR, iDim, _fieldDim);
233 derivativesHelp[iDim] += _regAlpha * _controller->getControl(index)
234 + dObjectiveDcontrol[iDim] * dProjectionDcontrol[iDim];
239 _primalSolver->parameters(names::Results()).lattice->get(latticeR).computeU(u_f);
240 const S
d = _dualSolver->parameters(names::Results()).lattice->get(latticeR).template getField<descriptors::POROSITY>();
242 for (
int jPop = 0; jPop < descriptor::q; ++jPop) {
243 S phi_j = _dualSolver->parameters(names::Results()).lattice->get(latticeR)[jPop];
245 for (
int iDim = 0; iDim < descriptor::d; iDim++) {
246 derivativesHelp[0] += phi_j*feq_j*( descriptors::c<descriptor>(jPop,iDim) -
d*u_f[iDim] )*u_f[iDim]*dProjectionDcontrol[0];
249 derivativesHelp[0] *= -omega*descriptors::invCs2<S,descriptor>();
254#ifdef PARALLEL_MODE_MPI
255 singleton::mpi().
bCast(&derivativesHelp[0], _fieldDim, primalGeometry->getLoadBalancer().rank(iC));
257 for (
int iDim=0; iDim<_fieldDim; ++iDim) {
258 const int index = _serializer->getSerializedComponentIndex(latticeR, iDim, _fieldDim);
259 derivatives[index] = derivativesHelp[iDim];
268template<
typename S,
template<
typename,SolverMode>
typename SOLVER,
typename C>
271 assert((this->_computeReference) &&
"Reference solution has not yet been computed\n");
276 for (
int iC=0; iC<_referenceGeometry->getCuboidGeometry().getNc(); iC++) {
278 int nX = _referenceGeometry->getCuboidGeometry().get(iC).getNx();
279 int nY = _referenceGeometry->getCuboidGeometry().get(iC).getNy();
280 int nZ = _referenceGeometry->getCuboidGeometry().get(iC).getNz();
281 for (
int iX=0; iX<nX; iX++) {
283 for (
int iY=0; iY<nY; iY++) {
285 for (
int iZ=0; iZ<nZ; iZ++) {
289 C force_help(_fieldDim, 0);
291 for (
int iDim=0; iDim<_fieldDim; iDim++) {
292 const auto cell = _referenceLattice->get(latticeR);
294 = _projection->inverse(cell.template getFieldComponent<descriptors::FORCE>(iDim));
297#ifdef PARALLEL_MODE_MPI
298 singleton::mpi().
bCast(&force_help[0], _fieldDim, _referenceGeometry->getLoadBalancer().rank(iC));
300 for (
int iDim=0; iDim<_fieldDim; iDim++) {
301 const int index = _serializer->getSerializedComponentIndex(latticeR, iDim, _fieldDim);
302 result[index] = force_help[iDim];
310 clout <<
"getReferenceControl() is only implemented for forced optimization" << std::endl;
This class implements the evaluation of the goal functional and its derivatives by using adjoint LBM.
S evaluateObjective(const C &control, unsigned optiStep=0) override
Solve primal problem and evaluate objective.
void computeDerivatives(const C &control, C &derivatives, unsigned optiStep=0) override
Compute derivatives via adjoint problem.
C getReferenceControl() const
void bCast(T *sendBuf, int sendCount, int root=0, MPI_Comm comm=MPI_COMM_WORLD)
Broadcast data from one processor to multiple processors.
int getRank() const
Returns the process ID.
constexpr int d() any_platform
int getMaterialGlobally(SuperGeometry< S, dim > &sGeometry, LatticeR< dim+1 > latticeR)
Helper that gives global access to material numbers.
ADf< T, DIM > atan(const ADf< T, DIM > &a)
Top level namespace for all of OpenLB.
An OptiCase using Adjoint-based Differentiation.
static V secondOrder(int iPop, const RHO &rho, const U &u, const USQR &uSqr) any_platform
Computation of equilibrium distribution, second order in u.
Creates a container of type C.