OpenLB 1.7
Loading...
Searching...
No Matches
inamuroNewtonRaphsonDynamics.hh
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2006, Orestis Malaspinas and Jonas Latt
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#ifndef INAMURO_NEWTON_RAPHSON_DYNAMICS_HH
25#define INAMURO_NEWTON_RAPHSON_DYNAMICS_HH
26
29#include "core/util.h"
30#include "dynamics/lbm.h"
31#include "utilities/omath.h"
32
33
34namespace olb {
35
36
37
38template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
40 : legacy::BasicDynamics<T,DESCRIPTOR,MOMENTA>(),
41 _boundaryDynamics(omega),
42 clout(std::cout,"InamuroNewtonRaphsonDynamics")
43{
44 this->getName() = "InamuroNewtonRaphsonDynamics";
45 _xi[0] = (T)1;
46 for (int iDim = 1; iDim < DESCRIPTOR::d; ++iDim) {
47 _xi[iDim] = T();
48 }
49}
50
51template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
53computeEquilibrium(int iPop, T rho, const T u[DESCRIPTOR::d], T uSqr) const
54{
55 return _boundaryDynamics.computeEquilibrium(iPop, rho, u, uSqr);
56}
57
58template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
61 LatticeStatistics<T>& statistics )
62{
63 typedef DESCRIPTOR L;
64
65 T rho, u[L::d];
66 MOMENTA().computeRhoU(cell,rho,u);
67
68 constexpr auto missingIndexes = util::subIndexOutgoing<L,direction,orientation>();
69 std::vector<int> knownIndexes;
70 bool test[L::q];
71 for (int iPop = 0; iPop < L::q; ++iPop) {
72 test[iPop] = true;
73 }
74
75 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
76 test[missingIndexes[iPop]] = false;
77 }
78 for (int iPop = 0; iPop < L::q; ++iPop) {
79 if (test[iPop]) {
80 knownIndexes.push_back(iPop);
81 }
82 }
83
84 T approxMomentum[L::d];
85
86 computeApproxMomentum(approxMomentum,cell,rho,u,_xi,knownIndexes,missingIndexes);
87
88 T error = computeError(rho, u,approxMomentum);
89 int counter = 0;
90
91 while (error > 1.0e-15) {
92 ++counter;
93
94 T gradError[L::d], gradGradError[L::d][L::d];
95 computeGradGradError(gradGradError,gradError,rho,u,_xi,approxMomentum,missingIndexes);
96
97 bool everythingWentFine = newtonRaphson(_xi,gradError,gradGradError);
98 if ((counter > 100000) || everythingWentFine == false) {
99 // if we need more that 100000 iterations or
100 // if we have a problem with the inversion of the
101 // jacobian matrix, we stop the program and
102 // print this error message on the screen.
103 clout << "Failed to converge...." << std::endl;
104 clout << "Error = " << error << std::endl;
105 clout << "u = (" << rho*u[0];
106 for (int iD=1; iD<DESCRIPTOR::d; ++iD) {
107 clout << ", " << rho*u[iD];
108 }
109 clout << ")" << std::endl;
110 clout << "uApprox = (" << approxMomentum[0];
111 for (int iD=1; iD<DESCRIPTOR::d; ++iD) {
112 clout << ", " << approxMomentum[iD];
113 }
114 clout << ")" << std::endl;
115 clout << "xi = (" << _xi[0];
116 for (int iD=1; iD<DESCRIPTOR::d; ++iD) {
117 clout << ", " << _xi[iD];
118 }
119 clout << ")" << std::endl;
120
121 exit(1);
122 }
123
124 computeApproxMomentum(approxMomentum,cell,rho,u,_xi,knownIndexes,missingIndexes);
125 error = computeError(rho, u,approxMomentum);
126
127 }
128
129 T uCs[L::d];
130 int counterDim = 0;
131 for (int iDim = 0; iDim < L::d; ++iDim) {
132 if (direction == iDim) {
133 ++counterDim;
134 uCs[iDim] = u[iDim];
135 }
136 else {
137 uCs[iDim] = u[iDim] + _xi[iDim+1-counterDim];
138 }
139 }
140
141 T uCsSqr = util::normSqr<T,L::d>(uCs);
142
143 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
144 cell[missingIndexes[iPop]] = computeEquilibrium(missingIndexes[iPop],_xi[0],uCs,uCsSqr);
145 }
146
147 _boundaryDynamics.collide(cell, statistics);
148}
149
150template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
155
156template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
158{
159 _boundaryDynamics.setOmega(omega);
160}
161
162template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
164computeApproxMomentum(T approxMomentum[DESCRIPTOR::d], ConstCell<T,DESCRIPTOR>& cell,
165 const T &rho, const T u[DESCRIPTOR::d], const T xi[DESCRIPTOR::d],
166 const std::vector<int> knownIndexes,const std::vector<int> missingIndexes)
167{
168 typedef DESCRIPTOR L;
169
170 T csVel[L::d];
171 int counter = 0;
172 for (int iDim = 0; iDim < L::d; ++iDim) {
173 if (direction == iDim) {
174 ++counter;
175 csVel[iDim] = u[iDim];
176 }
177 else {
178 csVel[iDim] = u[iDim] + xi[iDim+1-counter];
179 }
180 }
181
182 T csVelSqr = util::normSqr<T,L::d>(csVel);
183
184 for (int iDim = 0; iDim < L::d; ++iDim) {
185 approxMomentum[iDim] = T();
186 for (unsigned iPop = 0; iPop < knownIndexes.size(); ++iPop) {
187 approxMomentum[iDim] += descriptors::c<L>(knownIndexes[iPop],iDim) *
188 cell[knownIndexes[iPop]];
189 }
190 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
191 approxMomentum[iDim] += descriptors::c<L>(missingIndexes[iPop],iDim) *
192 computeEquilibrium(missingIndexes[iPop],xi[0],csVel,csVelSqr);
193 }
194 }
195}
196
197template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
198T InamuroNewtonRaphsonDynamics<T,DESCRIPTOR,Dynamics,MOMENTA,direction,orientation>::
199computeError(const T &rho, const T u[DESCRIPTOR::d], const T approxMomentum[DESCRIPTOR::d])
200{
201 typedef DESCRIPTOR L;
202
203 T err = T();
204 for (int iDim = 0; iDim < L::d; ++iDim) {
205 err += (rho * u[iDim]-approxMomentum[iDim]) * (rho * u[iDim]-approxMomentum[iDim]);
206 }
207 return util::sqrt(err);
208}
209
210template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
211void InamuroNewtonRaphsonDynamics<T,DESCRIPTOR,Dynamics,MOMENTA,direction,orientation>::computeGradGradError(
212 T gradGradError[DESCRIPTOR::d][DESCRIPTOR::d],T gradError[DESCRIPTOR::d],
213 const T &rho, const T u[DESCRIPTOR::d],const T xi[DESCRIPTOR::d],
214 const T approxMomentum[DESCRIPTOR::d],
215 const std::vector<int> missingIndexes)
216{
217 typedef DESCRIPTOR L;
218
219 T csVel[L::d];
220 int counter = 0;
221 for (int iDim = 0; iDim < L::d; ++iDim) {
222 if (direction == iDim) {
223 ++counter;
224 csVel[iDim] = u[iDim];
225 }
226 else {
227 csVel[iDim] = u[iDim] + xi[iDim+1-counter];
228 }
229 }
230 T csVelSqr = util::normSqr<T,L::d>(csVel);
231
232 std::vector<T> df[L::d];
233
234 for (int iXi = 0; iXi < L::d; ++iXi) {
235 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
236 df[iXi].push_back(T());
237 }
238 }
239
240 // all the null terms are allready contained in df (no need for else in the ifs)
241
242 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
243 T cu = T();
244 for (int iDim = 0; iDim < L::d; ++iDim) {
245 cu += descriptors::c<L>(missingIndexes[iPop],iDim) * csVel[iDim];
246 }
247 df[0][iPop] = descriptors::t<T,L>(missingIndexes[iPop])
248 * ((T)1+descriptors::invCs2<T,L>()*cu
249 + 0.5 * descriptors::invCs2<T,L>() * descriptors::invCs2<T,L>() * cu * cu
250 - 0.5 * descriptors::invCs2<T,L>() * csVelSqr);
251 }
252
253 counter = 0;
254 for (int iDim = 0; iDim < L::d; ++iDim) {
255 if (direction == iDim) {
256 ++counter;
257 }
258 else {
259 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
260 T temp = T();
261 for (int jDim = 0; jDim < L::d; ++jDim) {
262 temp += descriptors::c<L>(missingIndexes[iPop],jDim) * csVel[jDim];
263 }
264
265 df[iDim+1-counter][iPop] = xi[0]*descriptors::t<T,L>(missingIndexes[iPop]) *
266 (descriptors::invCs2<T,L>()*descriptors::c<L>(missingIndexes[iPop],iDim)
267 + descriptors::invCs2<T,L>()*descriptors::invCs2<T,L>()*descriptors::c<L>(missingIndexes[iPop],iDim)*temp
268 - descriptors::invCs2<T,L>()*csVel[iDim]);
269 }
270 }
271 }
272
273 std::vector<T> ddf[L::d][L::d];
274
275 for (int iAlpha = 0; iAlpha < L::d; ++iAlpha) {
276 for (int iBeta = 0; iBeta < L::d; ++iBeta) {
277 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
278 ddf[iAlpha][iBeta].push_back(T());
279 }
280 }
281 }
282
283 // ddf contains allready all the zero terms
284
285 counter = 0;
286 for (int iDim = 0; iDim < L::d; ++iDim) {
287 if (direction == iDim) {
288 ++counter;
289 }
290 else {
291 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
292 T temp = T();
293 for (int jDim = 0; jDim < L::d; ++jDim) {
294 temp += descriptors::c<L>(missingIndexes[iPop],jDim) * csVel[jDim];
295 }
296
297 T d_rho_sa = descriptors::t<T,L>(missingIndexes[iPop]) *
298 (descriptors::invCs2<T,L>()*descriptors::c<L>(missingIndexes[iPop],iDim)
299 + descriptors::invCs2<T,L>()*descriptors::invCs2<T,L>()*descriptors::c<L>(missingIndexes[iPop],iDim)*temp
300 - descriptors::invCs2<T,L>()*csVel[iDim]);
301
302 ddf[iDim+1-counter][0][iPop] = d_rho_sa;
303 ddf[0][iDim+1-counter][iPop] = d_rho_sa;
304 }
305 }
306 }
307
308 for (int iAlpha = 1; iAlpha < L::d; ++iAlpha) {
309 for (int iBeta = 1; iBeta < L::d; ++iBeta) {
310 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
311 ddf[iAlpha][iBeta][iPop] = descriptors::t<T,L>(missingIndexes[iPop])*xi[0] *
312 descriptors::invCs2<T,L>()*descriptors::invCs2<T,L>()*descriptors::c<L>(missingIndexes[iPop],iAlpha)*descriptors::c<L>(missingIndexes[iPop],iBeta);
313 if (iAlpha == iBeta) {
314 ddf[iAlpha][iBeta][iPop] -= descriptors::t<T,L>(missingIndexes[iPop])*xi[0] * descriptors::invCs2<T,L>();
315 }
316 }
317 }
318 }
319
320 // computation of the vector gradError
321 counter = 0;
322 for (int iDim = 0; iDim < L::d; ++iDim) {
323 T du[L::d];
324 gradError[iDim] = T();
325 for (int jDim = 0; jDim < L::d; ++jDim) {
326 du[jDim] = T();
327 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
328 du[jDim] += descriptors::c<L>(missingIndexes[iPop],jDim) * df[iDim][iPop];
329 }
330 gradError[iDim] += (approxMomentum[jDim]- rho * u[jDim]) * du[jDim];
331 }
332 gradError[iDim] *= (T)2;
333 }
334
335 // computation of the matrix gradGradError
336
337 for (int iAlpha = 0; iAlpha < L::d; ++iAlpha) {
338 for (int iBeta = 0; iBeta < L::d; ++iBeta) {
339 gradGradError[iAlpha][iBeta] = T();
340
341 T duAlpha[L::d], duBeta[L::d], ddu[L::d];
342 for (int iDim = 0; iDim < L::d; ++iDim) {
343 duAlpha[iDim] = T();
344 duBeta[iDim] = T();
345 ddu[iDim] = T();
346 for (unsigned iPop = 0; iPop < missingIndexes.size(); ++iPop) {
347 duAlpha[iDim] += descriptors::c<L>(missingIndexes[iPop],iDim)
348 * df[iAlpha][iPop];
349
350 duBeta[iDim] += descriptors::c<L>(missingIndexes[iPop],iDim)
351 * df[iBeta][iPop];
352
353 ddu[iDim] += descriptors::c<L>(missingIndexes[iPop],iDim)
354 * ddf[iAlpha][iBeta][iPop];
355 }
356 gradGradError[iAlpha][iBeta] += duAlpha[iDim] * duBeta[iDim]
357 + (approxMomentum[iDim]-rho * u[iDim]) * ddu[iDim];
358 }
359 gradGradError[iAlpha][iBeta] *= (T)2;
360 // gradGradError = 2*sum_alpha(du_alpha/dxi_beta*du_alpha/dxi_gamma +
361 // approxMomentum_alpha-u_alpha*d^2u_alpha/(dxi_gamma*dxi_beta))
362 }
363 }
364}
365
366template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
367bool InamuroNewtonRaphsonDynamics<T,DESCRIPTOR,Dynamics,MOMENTA,direction,orientation>::
368newtonRaphson(T xi[DESCRIPTOR::d],
369 const T gradError[DESCRIPTOR::d],
370 const T gradGradError[DESCRIPTOR::d][DESCRIPTOR::d])
371{
372 typedef DESCRIPTOR L;
373
374 T invGradGradError[L::d][L::d];
375 bool inversion = invert(gradGradError,invGradGradError);
376
377 for (int iXi = 0; iXi < L::d; ++iXi) {
378 T correction = T();
379 for (int iAlpha = 0; iAlpha < L::d; ++iAlpha) {
380 correction += invGradGradError[iXi][iAlpha] * gradError[iAlpha];
381 }
382
383 xi[iXi] -= correction;
384 }
385
386 return inversion;
387}
388
389template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
390bool InamuroNewtonRaphsonDynamics<T,DESCRIPTOR,Dynamics,MOMENTA,direction,orientation>::
391invert(const T a[2][2],T invA[2][2])
392{
393 T detA = a[0][0]*a[1][1] - a[0][1]*a[1][0];
394
395 if (util::fabs(detA) < 1.0e-13) {
396 clout << "error detA too small! = " << detA << std::endl;
397 for (int iAlpha = 0; iAlpha < 2; ++iAlpha) {
398 for (int iBeta = 0; iBeta < 2; ++iBeta) {
399 clout << a[iAlpha][iBeta] << "\t";
400 }
401 clout << std::endl;
402 }
403 return false;
404 }
405 else {
406 invA[0][0] = a[1][1];
407 invA[1][1] = a[0][0];
408
409 invA[0][1] = -a[1][0];
410 invA[1][0] = -a[0][1];
411
412 for (int iPop = 0; iPop < 2; ++iPop) {
413 for (int jPop = 0; jPop < 2; ++jPop) {
414 invA[iPop][jPop] /= detA;
415 }
416 }
417 return true;
418 }
419}
420
421template<typename T, typename DESCRIPTOR, typename Dynamics, typename MOMENTA, int direction, int orientation>
422bool InamuroNewtonRaphsonDynamics<T,DESCRIPTOR,Dynamics,MOMENTA,direction,orientation>::invert(const T a[3][3],T invA[3][3])
423{
424 T detA = a[0][0]*a[1][1]*a[2][2] + a[1][0]*a[2][1]*a[0][2] + a[2][0]*a[0][1]*a[1][2]
425 - a[0][0]*a[2][1]*a[1][2] - a[2][0]*a[1][1]*a[0][2] - a[1][0]*a[0][1]*a[2][2];
426
427
428 if (util::fabs(detA) < 1.0e-13) {
429 clout << "Error: detA too small! = " << detA << std::endl;
430 for (int iAlpha = 0; iAlpha < 3; ++iAlpha) {
431 for (int iBeta = 0; iBeta < 3; ++iBeta) {
432 clout << a[iAlpha][iBeta] << "\t";
433 }
434 clout << std::endl;
435 }
436 return false;
437 }
438 else {
439 invA[0][0] = a[1][1]*a[2][2]-a[1][2]*a[2][1];
440 invA[0][1] = a[0][2]*a[2][1]-a[0][1]*a[2][2];
441 invA[0][2] = a[0][1]*a[1][2]-a[0][2]*a[1][1];
442
443 invA[1][0] = a[1][2]*a[2][0]-a[1][0]*a[2][2];
444 invA[1][1] = a[0][0]*a[2][2]-a[0][2]*a[2][0];
445 invA[1][2] = a[0][2]*a[1][0]-a[0][0]*a[1][2];
446
447 invA[2][0] = a[1][0]*a[2][1]-a[1][1]*a[2][0];
448 invA[2][1] = a[0][1]*a[2][0]-a[0][0]*a[2][1];
449 invA[2][2] = a[0][0]*a[1][1]-a[0][1]*a[1][0];
450
451 for (int iPop = 0; iPop < 3; ++iPop) {
452 for (int jPop = 0; jPop < 3; ++jPop) {
453 invA[iPop][jPop] /= detA;
454 }
455 }
456 return true;
457 }
458}
459
460} // namespace olb
461
462
463#endif
Highest-level interface to Cell data.
Definition cell.h:148
Highest-level interface to read-only Cell data.
Definition cell.h:53
This class computes the inamuro BC with general dynamics.
T computeEquilibrium(int iPop, T rho, const T u[DESCRIPTOR::d], T uSqr) const override
Compute equilibrium distribution function.
T getOmega() const
Get local relaxation parameter of the dynamics.
void setOmega(T omega)
Set local relaxation parameter of the dynamics.
CellStatistic< T > collide(Cell< T, DESCRIPTOR > &cell, LatticeStatistics< T > &statistics) override
Collision step.
Descriptor for all types of 2D and 3D lattices.
cpu::simd::Pack< T > sqrt(cpu::simd::Pack< T > value)
Definition pack.h:100
cpu::simd::Pack< T > fabs(cpu::simd::Pack< T > value)
Definition pack.h:106
Top level namespace for all of OpenLB.
Return value of any collision.
Definition interface.h:43
virtual std::string getName() const
Return human-readable name.
Definition interface.h:63
Set of functions commonly used in LB computations – header file.