OpenLB 1.7
Loading...
Searching...
No Matches
optiCaseDual.hh
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2*
3* Copyright (C) 2012-2021 Mathias J. Krause, Benjamin Förster, Julius Jeßberger
4* E-mail contact: info@openlb.net
5* The most recent release of OpenLB can be downloaded at
6* <http://www.openlb.net/>
7*
8* This program is free software; you can redistribute it and/or
9* modify it under the terms of the GNU General Public License
10* as published by the Free Software Foundation; either version 2
11* of the License, or (at your option) any later version.
12*
13* This program is distributed in the hope that it will be useful,
14* but WITHOUT ANY WARRANTY; without even the implied warranty of
15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16* GNU General Public License for more details.
17*
18* You should have received a copy of the GNU General Public
19* License along with this program; if not, write to the Free
20* Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21* Boston, MA 02110-1301, USA.
22*/
23
24
25#ifndef OPTI_CASE_DUAL_HH
26#define OPTI_CASE_DUAL_HH
27
28#include "optiCaseDual.h"
29#include "serialization.h"
30
31namespace olb {
32
33namespace opti {
34
35template<typename S, template<typename,SolverMode> typename SOLVER, typename C>
36void OptiCaseDual<S,SOLVER,C>::readFromXML(XMLreader const& xml)
37{
38 std::string type ("");
39 xml.readOrWarn<std::string>("Optimization", "ControlType", "", type);
40 _controlType = ((type == "Force") || (type == "force")) ? ForceControl : PorosityControl;
41 xml.readOrWarn<std::string>("Optimization", "Projection", "", _projectionName);
42 xml.readOrWarn<int>("Optimization", "ControlMaterial", "", _controlMaterial);
43 xml.readOrWarn<S>("Optimization", "RegAlpha", "", _regAlpha);
44 type = "";
45 xml.readOrWarn<std::string>("Optimization", "StartValueType", "", type);
46 if (type == "Porosity") {
47 _startValueType = Porosity;
48 } else if (type == "Permeability") {
49 _startValueType = Permeability;
50 } else if (type == "Control") {
51 _startValueType = Control;
52 } else {
53 _startValueType = ProjectedControl;
54 }
55 xml.readOrWarn<bool>("Optimization", "ReferenceSolution", "", _computeReference);
56}
57
58template<typename S, template<typename,SolverMode> typename SOLVER, typename C>
59void OptiCaseDual<S,SOLVER,C>::initialize(XMLreader const& xml)
60{
61 _converter = createUnitConverter<S,descriptor>(xml);
62
63 _referenceSolver = createLbSolver <SOLVER<S,SolverMode::Reference>> (xml);
64 if (_computeReference) {
65 _referenceSolver->solve();
66 } else {
67 // only build up geometry and lattice
68 _referenceSolver->buildAndReturn();
69 }
70
71 _referenceGeometry = _referenceSolver->parameters(names::Results()).geometry;
72 _referenceLattice = _referenceSolver->parameters(names::Results()).lattice;
73
74 if (_controlType == ForceControl) {
75 _fieldDim = dim;
76 } else {
77 _fieldDim = 1;
78 }
79
80 _serializer = std::make_shared<SimpleGeometrySerializer<S,dim>>(*_referenceGeometry);
81 _dimCtrl = _serializer->getNoCells() * _fieldDim;
82
83 _controller = new Controller<S>(_dimCtrl);
84
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);
88
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);
94 }
95}
96
97template<typename S, template<typename,SolverMode> typename SOLVER, typename C>
98void OptiCaseDual<S,SOLVER,C>::initializeFields()
99{
100 _projection = projection::construct<S,descriptor>(*_converter, _projectionName);
101
102 _projectedControl = std::make_shared<SuperLatticeSerialDataF<S,descriptor>>(
103 *_referenceLattice,
104 *_controller,
105 _fieldDim,
106 _serializer,
107 [this](S x) { return _projection->project(x); });
108 _dProjectionDcontrol = std::make_shared<SuperLatticeSerialDataF<S,descriptor>>(
109 *_referenceLattice,
110 *_controller,
111 _fieldDim,
112 _serializer,
113 [this](S x) { return _projection->derivative(x); });
114 _primalSolver->parameters(names::Opti()).controlledField = _projectedControl;
115 _dualSolver->parameters(names::Opti()).controlledField = _projectedControl;
116}
117
118
119template<typename S, template<typename,SolverMode> typename SOLVER, typename C>
121 const C& control, unsigned optiStep)
122{
123 //project control to enforce volume constraint
124#ifdef mathiasProjection
125
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();
129
130 S pi = 4.0 * util::atan(1.0);
131
132 S totalD = T();
133 S wantedTotalD = T();
134
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);
139
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++) {
143 // TODO: this seems to be fixed to material number = 6
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.);
147 wantedTotalD += 1.0;
148 }
149 }
150 }
151 }
152
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++) {
156 // TODO: this seems to be fixed to material number = 6
157 if (_dualSolver->getGeometry()->getMaterial(iX,iY,iZ)==6) {
158 control[(iX-1)*(ny-1)*(nz-1)+(iY-1)*(nz-1)+(iZ-1)]
159 = lowerBound
160 + (control[(iX-1)*(ny-1)*(nz-1)+(iY-1)*(nz-1)+(iZ-1)] - lowerBound)
161 * wantedTotalD * (1.-volumeRatio) / totalD;
162 }
163 }
164 }
165 }
166#endif
167
168 _controller->setControl(control, _dimCtrl);
169 _primalSolver->parameters(names::OutputOpti()).counterOptiStep = optiStep;
170 _primalSolver->solve();
171
172 return _primalSolver->parameters(names::Results()).objective;
173}
174
175
176template<typename S, template<typename,SolverMode> typename SOLVER, typename C>
178 const C& control, C& derivatives, unsigned optiStep)
179{
180 _controller->setControl(control, _dimCtrl);
181 _dualSolver->parameters(names::OutputOpti()).counterOptiStep = optiStep;
182
183 const auto& primalResults = _primalSolver->parameters(names::Results());
184 auto& dualParams = _dualSolver->parameters(names::Opti());
185
186 dualParams.fpop = primalResults.fpop;
187 dualParams.dObjectiveDf = primalResults.djdf;
188 dualParams.dObjectiveDcontrol = primalResults.djdalpha;
189
190 _dualSolver->solve();
191
192 derivativesFromDualSolution(derivatives);
193}
194
195template<typename S, template<typename,SolverMode> typename SOLVER, typename C>
197 C& derivatives)
198{
199 const auto& primalGeometry = _primalSolver->parameters(names::Results()).geometry;
200 const S omega = _converter->getLatticeRelaxationFrequency();
201 const int nC = primalGeometry->getCuboidGeometry().getNc();
202
203 for (int iC = 0; iC < nC; iC++) {
204
205 const Vector<int,3> extend = primalGeometry->getCuboidGeometry().get(iC).getExtent();
206
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++) {
210 const LatticeR<dim+1> latticeR(iC, iX, iY, iZ);
211
212 if (getMaterialGlobally(*_referenceGeometry, latticeR) == _controlMaterial) {
213 C derivativesHelp(_fieldDim, 0);
214
215 if (primalGeometry->getLoadBalancer().rank(iC) == singleton::mpi().getRank()) {
216 const S rho_f = _primalSolver->parameters(names::Results()).lattice->get(latticeR).computeRho();
217 S dProjectionDcontrol[_fieldDim];
218 (*_dProjectionDcontrol)(dProjectionDcontrol, latticeR.data());
219
220 if ( _controlType == ForceControl ) {
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;
228 }
229 // dObjectiveDcontrol is zero if objective does not depend on control
230 // --> dObjectiveDcontrol is 0 and therefore dProjectionDcontrol may be
231 // irrelevant for force and porosity optimisation
232 const int index = _serializer->getSerializedComponentIndex(latticeR, iDim, _fieldDim);
233 derivativesHelp[iDim] += _regAlpha * _controller->getControl(index)
234 + dObjectiveDcontrol[iDim] * dProjectionDcontrol[iDim];
235 }
236 }
237 else if ( _controlType == PorosityControl ) {
238 S u_f[3];
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>();
241
242 for (int jPop = 0; jPop < descriptor::q; ++jPop) {
243 S phi_j = _dualSolver->parameters(names::Results()).lattice->get(latticeR)[jPop];
244 S feq_j = equilibrium<descriptor>::secondOrder(jPop, rho_f, u_f) + descriptors::t<S,descriptor>(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];
247 }
248 }
249 derivativesHelp[0] *= -omega*descriptors::invCs2<S,descriptor>();
250 }
251 // correct processing of regularizing term has to be checked in both cases!
252 }
253
254#ifdef PARALLEL_MODE_MPI
255 singleton::mpi().bCast(&derivativesHelp[0], _fieldDim, primalGeometry->getLoadBalancer().rank(iC));
256#endif
257 for (int iDim=0; iDim<_fieldDim; ++iDim) {
258 const int index = _serializer->getSerializedComponentIndex(latticeR, iDim, _fieldDim);
259 derivatives[index] = derivativesHelp[iDim];
260 }
261 }
262 }
263 }
264 }
265 }
266}
267
268template<typename S, template<typename,SolverMode> typename SOLVER, typename C>
270{
271 assert((this->_computeReference) && "Reference solution has not yet been computed\n");
272 C result = util::ContainerCreator<C>::create(_dimCtrl);
273
274 if (_controlType == ForceControl) {
275 LatticeR<dim+1> latticeR;
276 for (int iC=0; iC<_referenceGeometry->getCuboidGeometry().getNc(); iC++) {
277 latticeR[0] = 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++) {
282 latticeR[1] = iX;
283 for (int iY=0; iY<nY; iY++) {
284 latticeR[2] = iY;
285 for (int iZ=0; iZ<nZ; iZ++) {
286 latticeR[3] = iZ;
287
288 if (getMaterialGlobally(*_referenceGeometry, latticeR) == _controlMaterial) {
289 C force_help(_fieldDim, 0);
290 if (_referenceGeometry->getLoadBalancer().rank(iC) == singleton::mpi().getRank()) {
291 for (int iDim=0; iDim<_fieldDim; iDim++) {
292 const auto cell = _referenceLattice->get(latticeR);
293 force_help[iDim]
294 = _projection->inverse(cell.template getFieldComponent<descriptors::FORCE>(iDim));
295 }
296 }
297#ifdef PARALLEL_MODE_MPI
298 singleton::mpi().bCast(&force_help[0], _fieldDim, _referenceGeometry->getLoadBalancer().rank(iC));
299#endif
300 for (int iDim=0; iDim<_fieldDim; iDim++) {
301 const int index = _serializer->getSerializedComponentIndex(latticeR, iDim, _fieldDim);
302 result[index] = force_help[iDim];
303 }
304 }
305 }
306 }
307 }
308 }
309 } else {
310 clout << "getReferenceControl() is only implemented for forced optimization" << std::endl;
311 exit(1);
312 }
313 return result;
314}
315
316} // namespace opti
317
318} // namespace olb
319
320#endif
Plain old scalar vector.
Definition vector.h:47
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.
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
@ ProjectedControl
Definition projection.h:42
int getMaterialGlobally(SuperGeometry< S, dim > &sGeometry, LatticeR< dim+1 > latticeR)
Helper that gives global access to material numbers.
MpiManager & mpi()
ADf< T, DIM > atan(const ADf< T, DIM > &a)
Definition aDiff.h:614
Top level namespace for all of OpenLB.
Optimization Code.
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.
Definition lbm.h:51
Creates a container of type C.