MaMiCo 1.2
Loading...
Searching...
No Matches
LBCouetteSolver.h
1// Copyright (C) 2015 Technische Universitaet Muenchen
2// This file is part of the Mamico project. For conditions of distribution
3// and use, please see the copyright notice in Mamico's main folder
4#ifndef _MOLECULARDYNAMICS_COUPLING_SOLVERS_LBCOUETTESOLVER_H_
5#define _MOLECULARDYNAMICS_COUPLING_SOLVERS_LBCOUETTESOLVER_H_
6
7namespace coupling {
8namespace solvers {
11} // namespace solvers
12} // namespace coupling
13
14#if defined(_OPENMP)
15#include <omp.h>
16#endif
17#include "coupling/interface/PintableMacroSolver.h"
18#include "coupling/solvers/NumericalSolver.h"
19#include <cmath>
20
22public:
23 LBCouetteSolverState(int size) : _pdf(size, 0) {}
24
25 LBCouetteSolverState(int size, double* pdf) : LBCouetteSolverState(size) { std::copy(pdf, pdf + size, _pdf.data()); }
26
27 std::unique_ptr<State> clone() const override { return std::make_unique<LBCouetteSolverState>(*this); }
28
29 ~LBCouetteSolverState() {}
30
31 int getSizeBytes() const override { return sizeof(double) * _pdf.size(); }
32
33 std::unique_ptr<State> operator+(const State& rhs) override;
34 std::unique_ptr<State> operator-(const State& rhs) override;
35
36 double* getData() override { return _pdf.data(); }
37 const double* getData() const override { return _pdf.data(); }
38
39 void print(std::ostream& os) const override { os << "<LBCouetteSolverState instance with size " << getSizeBytes() << ">"; }
40
41protected:
42 bool __equals__(const State& rhs) const override {
43 const LBCouetteSolverState* other = dynamic_cast<const LBCouetteSolverState*>(&rhs);
44 if (other == nullptr)
45 return false;
46 return _pdf == other->_pdf;
47 }
48
49private:
50 std::vector<double> _pdf;
51};
52
58public:
74 LBCouetteSolver(const double channelheight, tarch::la::Vector<3, double> wallVelocity, const double kinVisc, const double dx, const double dt,
75 const int plotEveryTimestep, const bool plotAverageVelocity, const std::string filestem, const tarch::la::Vector<3, unsigned int> processes,
76 const unsigned int numThreads = 1, const Scenario* scen = nullptr)
77 : coupling::solvers::NumericalSolver(channelheight, dx, dt, kinVisc, plotEveryTimestep, filestem, processes, scen), _mode(Mode::coupling), _dt_pint(dt),
78 _omega(1.0 / (3.0 * (kinVisc * dt / (dx * dx)) + 0.5)), _wallVelocity((dt / dx) * wallVelocity), _plotAverageVelocity(plotAverageVelocity) {
79 // return if required
80 if (skipRank()) {
81 return;
82 }
83 _pdfsize = 19 * (_domainSizeX + 2) * (_domainSizeY + 2) * (_domainSizeZ + 2);
84 _pdf1 = new double[_pdfsize];
85 _pdf2 = new double[_pdfsize];
86#if defined(_OPENMP)
87 omp_set_num_threads(numThreads);
88#endif
89#if (COUPLING_MD_DEBUG == COUPLING_MD_YES)
90 std::cout << "Domain size=" << _domainSizeX << "," << _domainSizeY << "," << _domainSizeZ << std::endl;
91 std::cout << "tau=" << 1.0 / _omega << std::endl;
92 std::cout << "wallVelocity=" << _wallVelocity << std::endl;
93 for (int z = 0; z < _domainSizeZ + 2; z++) {
94 for (int y = 0; y < _domainSizeY + 2; y++) {
95 for (int x = 0; x < _domainSizeX + 2; x++) {
96 std::cout << x << "," << y << "," << z << "FLAG=" << _flag[get(x, y, z)] << std::endl;
97 }
98 }
99 }
100#endif
101 // check pointers
102 if ((_pdf1 == NULL) || (_pdf2 == NULL) || (_vel == NULL) || (_density == NULL) || (_flag == NULL)) {
103 std::cout << "ERROR LBCouetteSolver: NULL ptr!" << std::endl;
104 exit(EXIT_FAILURE);
105 }
106#if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
107 if ((_sendBufferX == NULL) || (_recvBufferX == NULL) || (_sendBufferY == NULL) || (_recvBufferY == NULL) || (_sendBufferZ == NULL) ||
108 (_recvBufferZ == NULL)) {
109 std::cout << "ERROR LBCouetteSolver: NULL ptr in send/recv!" << std::endl;
110 exit(EXIT_FAILURE);
111 }
112#endif
113// init everything with lattice weights
114#pragma omp parallel for
115 for (int i = 0; i < (_domainSizeX + 2) * (_domainSizeY + 2) * (_domainSizeZ + 2); i++) {
116 for (int q = 0; q < 19; q++) {
117 _pdf1[get(i) * 19 + q] = _W[q];
118 _pdf2[get(i) * 19 + q] = _W[q];
119 }
120 }
121 computeDensityAndVelocityEverywhere();
122 }
123
126 if (_pdf1 != NULL) {
127 delete[] _pdf1;
128 _pdf1 = NULL;
129 }
130 if (_pdf2 != NULL) {
131 delete[] _pdf2;
132 _pdf2 = NULL;
133 }
134 if (_vel != NULL) {
135 delete[] _vel;
136 _vel = NULL;
137 }
138 if (_density != NULL) {
139 delete[] _density;
140 _density = NULL;
141 }
142 if (_flag != NULL) {
143 delete[] _flag;
144 _flag = NULL;
145 }
146#if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
147 if (_sendBufferX != NULL) {
148 delete[] _sendBufferX;
149 _sendBufferX = NULL;
150 }
151 if (_sendBufferY != NULL) {
152 delete[] _sendBufferY;
153 _sendBufferY = NULL;
154 }
155 if (_sendBufferZ != NULL) {
156 delete[] _sendBufferZ;
157 _sendBufferZ = NULL;
158 }
159 if (_recvBufferX != NULL) {
160 delete[] _recvBufferX;
161 _recvBufferX = NULL;
162 }
163 if (_recvBufferY != NULL) {
164 delete[] _recvBufferY;
165 _recvBufferY = NULL;
166 }
167 if (_recvBufferZ != NULL) {
168 delete[] _recvBufferZ;
169 _recvBufferZ = NULL;
170 }
171#endif
172 }
173
176 void advance(double dt) override {
177 if (skipRank()) {
178 return;
179 }
180 const int timesteps = floor(dt / _dt + 0.5);
181 if (fabs(timesteps * _dt - dt) / _dt > 1.0e-8) {
182 std::cout << "ERROR LBCouetteSolver::advance(): time steps and dt do not match!" << std::endl;
183 exit(EXIT_FAILURE);
184 }
185 for (int i = 0; i < timesteps; i++) {
187 computeDensityAndVelocityEverywhere();
188 plot();
189 plot_avg_vel();
191 communicate(); // exchange between neighbouring MPI subdomains
192 _counter++;
193 }
194 }
195
201 if (skipRank()) {
202 return;
203 }
204#if (COUPLING_MD_ERROR == COUPLING_MD_YES)
205 if (_mode == Mode::supervising) {
206 std::cout << "ERROR LBCouetteSolver setMDBoundaryValues() called in supervising mode" << std::endl;
207 exit(EXIT_FAILURE);
208 }
209#endif
210 computeDensityAndVelocityEverywhere();
211
212 // loop over all received cells
213 for (auto pair : md2macroBuffer) {
214 I01 idx;
216 std::tie(couplingCell, idx) = pair;
217 // determine cell index of this cell in LB domain
218 tarch::la::Vector<3, unsigned int> globalCellCoords{idx.get()};
219 globalCellCoords[0] = (globalCellCoords[0] + _offset[0]) - _coords[0] * _avgDomainSizeX;
220 globalCellCoords[1] = (globalCellCoords[1] + _offset[1]) - _coords[1] * _avgDomainSizeY;
221 globalCellCoords[2] = (globalCellCoords[2] + _offset[2]) - _coords[2] * _avgDomainSizeZ;
222#if (COUPLING_MD_DEBUG == COUPLING_MD_YES)
223 std::cout << "Process coords: " << _coords << ": GlobalCellCoords for index " << idx << ": " << globalCellCoords << std::endl;
224#endif
225 const int index = get(globalCellCoords[0], globalCellCoords[1], globalCellCoords[2]);
226#if (COUPLING_MD_ERROR == COUPLING_MD_YES)
227 if (_flag[index] != MD_BOUNDARY) {
228 std::cout << "ERROR LBCouetteSolver::setMDBoundaryValues(): Cell " << index << " is no MD boundary cell!" << std::endl;
229 exit(EXIT_FAILURE);
230 }
231#endif
232 // set velocity value and pdfs in MD boundary cell (before streaming); the
233 // boundary velocities are interpolated between the neighbouring and this
234 // cell. This interpolation is valid for FLUID-MD_BOUNDARY neighbouring
235 // relations only. determine local velocity received from MaMiCo and
236 // convert it to LB units; store the velocity in _vel
237 // massFactor is used to ensure conservation of energy
238 tarch::la::Vector<3, double> localVel((1.0 / couplingCell->getMacroscopicMass()) * (_dt / _dx) * couplingCell->getMacroscopicMomentum());
239 for (unsigned int d = 0; d < 3; d++) {
240 _vel[3 * index + d] = localVel[d];
241 }
242 // loop over all pdfs and set them according to interpolated moving-wall
243 // conditions
244 for (unsigned int q = 0; q < 19; q++) {
245 // index of neighbour cell; only if cell is located inside local domain
246 if (((int)globalCellCoords[0] + _C[q][0] > 0) && ((int)globalCellCoords[0] + _C[q][0] < _domainSizeX + 1) &&
247 ((int)globalCellCoords[1] + _C[q][1] > 0) && ((int)globalCellCoords[1] + _C[q][1] < _domainSizeY + 1) &&
248 ((int)globalCellCoords[2] + _C[q][2] > 0) && ((int)globalCellCoords[2] + _C[q][2] < _domainSizeZ + 1)) {
249 const int nbIndex = get((_C[q][0] + globalCellCoords[0]), (_C[q][1] + globalCellCoords[1]), (_C[q][2] + globalCellCoords[2]));
250 const tarch::la::Vector<3, double> interpolVel(0.5 * (_vel[3 * index] + _vel[3 * nbIndex]), 0.5 * (_vel[3 * index + 1] + _vel[3 * nbIndex + 1]),
251 0.5 * (_vel[3 * index + 2] + _vel[3 * nbIndex + 2]));
252 _pdf1[19 * index + q] =
253 _pdf1[19 * nbIndex + 18 - q] -
254 6.0 * _W[q] * _density[nbIndex] * (_C[18 - q][0] * interpolVel[0] + _C[18 - q][1] * interpolVel[1] + _C[18 - q][2] * interpolVel[2]);
255 }
256 }
257 }
258 }
259
266 // check pos-data for process locality (todo: put this in debug mode in
267 // future releases)
268 if ((pos[0] < domainOffset[0]) || (pos[0] > domainOffset[0] + _domainSizeX * _dx) || (pos[1] < domainOffset[1]) ||
269 (pos[1] > domainOffset[1] + _domainSizeY * _dx) || (pos[2] < domainOffset[2]) || (pos[2] > domainOffset[2] + _domainSizeZ * _dx)) {
270 std::cout << "ERROR LBCouetteSolver::getVelocity(): Position " << pos << " out of range!" << std::endl;
271 std::cout << "domainOffset = " << domainOffset << std::endl;
272 std::cout << "_domainSizeX = " << _domainSizeX << std::endl;
273 std::cout << "_domainSizeY = " << _domainSizeY << std::endl;
274 std::cout << "_domainSizeZ = " << _domainSizeZ << std::endl;
275 std::cout << "_dx = " << _dx << std::endl;
276 exit(EXIT_FAILURE);
277 }
278 // compute index for respective cell (_dx+... for ghost cells); use coords
279 // to store local cell coordinates
280 for (unsigned int d = 0; d < 3; d++) {
281 coords[d] = (unsigned int)((_dx + pos[d] - domainOffset[d]) / _dx);
282 }
283 const int index = get(coords[0], coords[1], coords[2]);
285 // extract and scale velocity to "real"=MD units
286 for (int d = 0; d < 3; d++) {
287 vel[d] = _dx / _dt * _vel[3 * index + d];
288 }
289#if (COUPLING_MD_DEBUG == COUPLING_MD_YES)
290 std::cout << "Position " << pos << " corresponds to cell: " << coords << "; vel=" << vel << std::endl;
291#endif
292 return vel;
293 }
294
298 double getDensity(tarch::la::Vector<3, double> pos) const override {
301 // check pos-data for process locality (todo: put this in debug mode in
302 // future releases)
303 if ((pos[0] < domainOffset[0]) || (pos[0] > domainOffset[0] + _domainSizeX * _dx) || (pos[1] < domainOffset[1]) ||
304 (pos[1] > domainOffset[1] + _domainSizeY * _dx) || (pos[2] < domainOffset[2]) || (pos[2] > domainOffset[2] + _domainSizeZ * _dx)) {
305 std::cout << "ERROR LBCouetteSolver::getDensity(): Position " << pos << " out of range!" << std::endl;
306 exit(EXIT_FAILURE);
307 }
308 // compute index for respective cell (_dx+... for ghost cells); use coords
309 // to store local cell coordinates
310 for (unsigned int d = 0; d < 3; d++) {
311 coords[d] = (unsigned int)((_dx + pos[d] - domainOffset[d]) / _dx);
312 }
313 const int index = get(coords[0], coords[1], coords[2]);
314 return _density[index];
315 }
316
319 virtual void setWallVelocity(const tarch::la::Vector<3, double> wallVelocity) override { _wallVelocity = (_dt / _dx) * wallVelocity; }
320
324
325 std::unique_ptr<State> getState() override {
326 computeDensityAndVelocityEverywhere();
327 if (skipRank())
328 return std::make_unique<LBCouetteSolverState>(0);
329 return std::make_unique<LBCouetteSolverState>(_pdfsize, _pdf1);
330 }
331
332 void setState(const std::unique_ptr<State>& input, int cycle) override {
333 if (skipRank())
334 return;
335
336 const LBCouetteSolverState* state = dynamic_cast<const LBCouetteSolverState*>(input.get());
337
338#if (COUPLING_MD_ERROR == COUPLING_MD_YES)
339 if (state == nullptr) {
340 std::cout << "ERROR LBCouetteSolver setState() wrong state type" << std::endl;
341 exit(EXIT_FAILURE);
342 }
343#endif
344
345 std::copy(state->getData(), state->getData() + _pdfsize, _pdf1);
346 computeDensityAndVelocityEverywhere();
347
348 _counter = cycle;
349 }
350
351 std::unique_ptr<State> operator()(const std::unique_ptr<State>& input, int cycle) override {
352 setState(input, cycle);
353
354#if (COUPLING_MD_ERROR == COUPLING_MD_YES)
355 if (_mode != Mode::supervising) {
356 std::cout << "ERROR LBCouetteSolver operator() called but not in supervising mode" << std::endl;
357 exit(EXIT_FAILURE);
358 }
359#endif
360
361 advance(_dt_pint);
362 return getState();
363 }
364
365 Mode getMode() const override { return _mode; }
366
373 std::unique_ptr<PintableMacroSolver> getSupervisor(int num_cycles, double visc_multiplier) const override {
374#if (COUPLING_MD_ERROR == COUPLING_MD_YES)
375 if (_mode == Mode::supervising) {
376 std::cout << "ERROR LBCouetteSolver getSupervisor(): already in supervising mode" << std::endl;
377 exit(EXIT_FAILURE);
378 }
379#endif
380
381 int numThreads = 1;
382#if defined(_OPENMP)
383 numThreads = omp_get_num_threads();
384#endif
385
386 auto res = std::make_unique<LBCouetteSolver>(_channelheight, _wallVelocity * _dx / _dt, _kinVisc * visc_multiplier, _dx, _dt, _plotEveryTimestep,
387 _plotAverageVelocity, _filestem + std::string("_supervising"), _processes, numThreads, _scen);
388
389 res->_mode = Mode::supervising;
390 res->_dt_pint = _dt * num_cycles;
391
392 return res;
393 }
394
395 void print(std::ostream& os) const override {
396 if (_mode == Mode::supervising)
397 os << "<LBCouetteSolver instance in supervising mode >";
398 if (_mode == Mode::coupling)
399 os << "<LBCouetteSolver instance in coupling mode >";
400 }
401
402 double get_avg_vel(const std::unique_ptr<State>& state) const override {
403 if (skipRank())
404 return 0;
405 double vel[3];
406 double density;
407 double res[3]{0, 0, 0};
408 for (int i = 0; i < _pdfsize; i += 19) {
409 LBCouetteSolver::computeDensityAndVelocity(vel, density, state->getData() + i);
410 res[0] += vel[0];
411 res[1] += vel[1];
412 res[2] += vel[2];
413 }
414 if (_pdfsize > 0) {
415 res[0] /= (_pdfsize / 19);
416 res[1] /= (_pdfsize / 19);
417 res[2] /= (_pdfsize / 19);
418 }
419 return std::sqrt(res[0] * res[0] + res[1] * res[1] + res[2] * res[2]);
420 }
421
422 double get_avg_velX(const std::unique_ptr<State>& state) const {
423 if (skipRank())
424 return 0;
425 double vel[3];
426 double density;
427 double res{0};
428 for (int i = 0; i < _pdfsize; i += 19) {
429 LBCouetteSolver::computeDensityAndVelocity(vel, density, state->getData() + i);
430 res += vel[0];
431 }
432 if (_pdfsize > 0) {
433 res /= (_pdfsize / 19);
434 }
435 return res;
436 }
437
438private:
439 Mode _mode;
440 double _dt_pint;
441
442 void computeDensityAndVelocityEverywhere() {
443 if (skipRank())
444 return;
445 for (int z = 1; z < _domainSizeZ + 1; z++) {
446 for (int y = 1; y < _domainSizeY + 1; y++) {
447 for (int x = 1; x < _domainSizeX + 1; x++) {
448 const int index = get(x, y, z);
449 const int pI = 19 * index;
450 double* vel = &_vel[3 * index];
451 computeDensityAndVelocity(vel, _density[index], &_pdf1[pI]);
452 }
453 }
454 }
455 }
456
457 void plot_avg_vel() {
459 return;
460
461 int rank = 0;
462#if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
463 MPI_Comm_rank(coupling::indexing::IndexingService<3>::getInstance().getComm(), &rank);
464#endif
465 std::stringstream ss;
466 ss << _filestem << "_r" << rank;
467 if (_scen != nullptr) {
468 auto ts = _scen->getTimeIntegrationService();
469 if (ts != nullptr) {
470 if (ts->isPintEnabled())
471 ss << "_i" << ts->getIteration();
472 }
473 }
474 ss << ".csv";
475 std::string filename = ss.str();
476 std::ofstream file(filename.c_str(), _counter == 0 ? std::ofstream::out : std::ofstream::app);
477 if (!file.is_open()) {
478 std::cout << "ERROR LBCouetteSolver::plot_avg_vel(): Could not open file " << filename << "!" << std::endl;
479 exit(EXIT_FAILURE);
480 }
481
482 if (_counter == 0) {
483 file << "coupling_cycle ; avg_vel ; avg_velX" << std::endl;
484 }
485
486 std::unique_ptr<State> s = std::make_unique<LBCouetteSolverState>(_pdfsize, _pdf1);
487 double vel = get_avg_vel(s);
488 double velX = get_avg_velX(s);
489 file << _counter << " ; " << vel << " ; " << velX << std::endl;
490 file.close();
491 }
492
496
500#pragma omp parallel for
501 for (int z = 1; z < _domainSizeZ + 1; z++) {
502 for (int y = 1; y < _domainSizeY + 1; y++) {
503 for (int x = 1; x < _domainSizeX + 1; x++) {
504 const int index = get(x, y, z);
505 if (_flag[index] == FLUID) {
506 stream(index);
507 collide(index, x, y, z);
508 }
509 }
510 }
511 }
512 // swap fields
513 double* swap = _pdf1;
514 _pdf1 = _pdf2;
515 _pdf2 = swap;
516 }
517
519 void stream(int index) {
520 const int pI = 19 * index;
521 for (int q = 0; q < 9; q++) {
522 const int nb = 19 * (_C[q][0] + _C[q][1] * _xO + _C[q][2] * _yO);
523 _pdf2[pI + q] = _pdf1[pI + q - nb];
524 _pdf2[pI + 18 - q] = _pdf1[pI + 18 - q + nb];
525 }
526 _pdf2[pI + 9] = _pdf1[pI + 9];
527 }
528
530 void collide(int index, int x, int y, int z) {
531 // index of start of cell-local pdfs in AoS
532 const int pI = 19 * index;
533 // compute and store density, velocity
534 double* vel = &_vel[3 * index];
535 computeDensityAndVelocity(vel, _density[index], &_pdf2[pI]);
536 // collide (BGK); always handle pdfs no. q and inv(q)=18-q in one step
537 const double u2 = 1.0 - 1.5 * (vel[0] * vel[0] + vel[1] * vel[1] + vel[2] * vel[2]);
538 // pdf 0,18
539 double cu = -vel[1] - vel[2];
540 int nb = -_xO - _yO;
541 double feq = _W[0] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
542 _pdf2[pI] -= _omega * (_pdf2[pI] - feq);
543 boundary(_pdf2, pI, x, y, z, 0, _flag[index + nb], pI + 19 * nb);
544 feq -= 6.0 * _W[0] * _density[index] * cu;
545 _pdf2[pI + 18] -= _omega * (_pdf2[pI + 18] - feq);
546 boundary(_pdf2, pI, x, y, z, 18, _flag[index - nb], pI - 19 * nb);
547 // pdf 1,17
548 cu = -vel[0] - vel[2];
549 nb = -1 - _yO;
550 feq = _W[1] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
551 _pdf2[pI + 1] -= _omega * (_pdf2[pI + 1] - feq);
552 boundary(_pdf2, pI, x, y, z, 1, _flag[index + nb], pI + 19 * nb);
553 feq -= 6.0 * _W[1] * _density[index] * cu;
554 _pdf2[pI + 17] -= _omega * (_pdf2[pI + 17] - feq);
555 boundary(_pdf2, pI, x, y, z, 17, _flag[index - nb], pI - 19 * nb);
556 // pdf 2,16
557 cu = -vel[2];
558 nb = -_yO;
559 feq = _W[2] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
560 _pdf2[pI + 2] -= _omega * (_pdf2[pI + 2] - feq);
561 boundary(_pdf2, pI, x, y, z, 2, _flag[index + nb], pI + 19 * nb);
562 feq -= 6.0 * _W[2] * _density[index] * cu;
563 _pdf2[pI + 16] -= _omega * (_pdf2[pI + 16] - feq);
564 boundary(_pdf2, pI, x, y, z, 16, _flag[index - nb], pI - 19 * nb);
565 // pdf 3,15
566 cu = vel[0] - vel[2];
567 nb = 1 - _yO;
568 feq = _W[3] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
569 _pdf2[pI + 3] -= _omega * (_pdf2[pI + 3] - feq);
570 boundary(_pdf2, pI, x, y, z, 3, _flag[index + nb], pI + 19 * nb);
571 feq -= 6.0 * _W[3] * _density[index] * cu;
572 _pdf2[pI + 15] -= _omega * (_pdf2[pI + 15] - feq);
573 boundary(_pdf2, pI, x, y, z, 15, _flag[index - nb], pI - 19 * nb);
574 // pdf 4,14
575 cu = vel[1] - vel[2];
576 nb = _xO - _yO;
577 feq = _W[4] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
578 _pdf2[pI + 4] -= _omega * (_pdf2[pI + 4] - feq);
579 boundary(_pdf2, pI, x, y, z, 4, _flag[index + nb], pI + 19 * nb);
580 feq -= 6.0 * _W[4] * _density[index] * cu;
581 _pdf2[pI + 14] -= _omega * (_pdf2[pI + 14] - feq);
582 boundary(_pdf2, pI, x, y, z, 14, _flag[index - nb], pI - 19 * nb);
583 // pdf 5,13
584 cu = -vel[0] - vel[1];
585 nb = -1 - _xO;
586 feq = _W[5] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
587 _pdf2[pI + 5] -= _omega * (_pdf2[pI + 5] - feq);
588 boundary(_pdf2, pI, x, y, z, 5, _flag[index + nb], pI + 19 * nb);
589 feq -= 6.0 * _W[5] * _density[index] * cu;
590 _pdf2[pI + 13] -= _omega * (_pdf2[pI + 13] - feq);
591 boundary(_pdf2, pI, x, y, z, 13, _flag[index - nb], pI - 19 * nb);
592 // pdf 6,12
593 cu = -vel[1];
594 nb = -_xO;
595 feq = _W[6] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
596 _pdf2[pI + 6] -= _omega * (_pdf2[pI + 6] - feq);
597 boundary(_pdf2, pI, x, y, z, 6, _flag[index + nb], pI + 19 * nb);
598 feq -= 6.0 * _W[6] * _density[index] * cu;
599 _pdf2[pI + 12] -= _omega * (_pdf2[pI + 12] - feq);
600 boundary(_pdf2, pI, x, y, z, 12, _flag[index - nb], pI - 19 * nb);
601 // pdf 7,11
602 cu = vel[0] - vel[1];
603 nb = 1 - _xO;
604 feq = _W[7] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
605 _pdf2[pI + 7] -= _omega * (_pdf2[pI + 7] - feq);
606 boundary(_pdf2, pI, x, y, z, 7, _flag[index + nb], pI + 19 * nb);
607 feq -= 6.0 * _W[7] * _density[index] * cu;
608 _pdf2[pI + 11] -= _omega * (_pdf2[pI + 11] - feq);
609 boundary(_pdf2, pI, x, y, z, 11, _flag[index - nb], pI - 19 * nb);
610 // pdf 8,10
611 cu = -vel[0];
612 nb = -1;
613 feq = _W[8] * _density[index] * (u2 + 3.0 * cu + 4.5 * cu * cu);
614 _pdf2[pI + 8] -= _omega * (_pdf2[pI + 8] - feq);
615 boundary(_pdf2, pI, x, y, z, 8, _flag[index + nb], pI + 19 * nb);
616 feq -= 6.0 * _W[8] * _density[index] * cu;
617 _pdf2[pI + 10] -= _omega * (_pdf2[pI + 10] - feq);
618 boundary(_pdf2, pI, x, y, z, 10, _flag[index - nb], pI - 19 * nb);
619 // pdf 9
620 _pdf2[pI + 9] -= _omega * (_pdf2[pI + 9] - _W[9] * _density[index] * u2);
621 }
622
632 void boundary(double* const pdf, int index, int x, int y, int z, int q, const Flag& flag, int nbIndex) {
633 if (flag != FLUID) {
634 if (flag == NO_SLIP) {
635 // half-way bounce back
636 pdf[nbIndex + 18 - q] = pdf[index + q];
637 } else if (flag == MOVING_WALL) {
638 // half-way bounce back + moving wall acceleration (only x-direction for
639 // wall supported at the moment)
640 pdf[nbIndex + 18 - q] =
641 pdf[index + q] - 6.0 * _W[q] * _density[index / 19] * (_C[q][0] * _wallVelocity[0] + _C[q][1] * _wallVelocity[1] + _C[q][2] * _wallVelocity[2]);
642 } else if (flag == PERIODIC) {
643 // periodic treatment
644 int target[3] = {x, y, z};
645 if (target[0] + _C[q][0] == 0) {
646 target[0] = _domainSizeX + 1;
647 } else if (target[0] + _C[q][0] == _domainSizeX + 1) {
648 target[0] = 0;
649 }
650 if (target[1] + _C[q][1] == 0) {
651 target[1] = _domainSizeY + 1;
652 } else if (target[1] + _C[q][1] == _domainSizeY + 1) {
653 target[1] = 0;
654 }
655 if (target[2] + _C[q][2] == 0) {
656 target[2] = _domainSizeZ + 1;
657 } else if (target[2] + _C[q][2] == _domainSizeZ + 1) {
658 target[2] = 0;
659 }
660 const int periodicNb = target[0] + (_domainSizeX + 2) * (target[1] + (_domainSizeY + 2) * target[2]);
661 pdf[19 * periodicNb + q] = pdf[index + q];
662 }
663 }
664 }
665
670 static void computeDensityAndVelocity(double* const vel, double& density, const double* const pdf) {
671 vel[0] = -(pdf[1] + pdf[5] + pdf[8] + pdf[11] + pdf[15]);
672 density = pdf[3] + pdf[7] + pdf[10] + pdf[13] + pdf[17];
673 vel[1] = (pdf[4] + pdf[11] + pdf[12] + pdf[13] + pdf[18]) - (pdf[0] + pdf[5] + pdf[6] + pdf[7] + pdf[14]);
674 vel[0] = density + vel[0];
675 density = density + pdf[0] + pdf[1] + pdf[2] + pdf[4] + pdf[5] + pdf[6] + pdf[8] + pdf[9] + pdf[11] + pdf[12] + pdf[14] + pdf[15] + pdf[16] + pdf[18];
676 vel[2] = (pdf[14] + pdf[15] + pdf[16] + pdf[17] + pdf[18]) - (pdf[0] + pdf[1] + pdf[2] + pdf[3] + pdf[4]);
677 vel[0] = vel[0] / density;
678 vel[1] = vel[1] / density;
679 vel[2] = vel[2] / density;
680 }
681
696 void communicatePart(double* pdf, double* sendBuffer, double* recvBuffer, NbFlag nbFlagTo, NbFlag nbFlagFrom, tarch::la::Vector<3, int> startSend,
698#if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
699 // directions that point to LEFT/RIGHT,... -> same ordering as enums!
700 const int directions[6][5] = {{1, 5, 8, 11, 15}, {3, 7, 10, 13, 17}, {4, 11, 12, 13, 18}, {0, 5, 6, 7, 14}, {0, 1, 2, 3, 4}, {14, 15, 16, 17, 18}};
701 MPI_Request requests[2];
702 MPI_Status status[2];
704 tarch::la::Vector<2, int> domainSize;
705 // find out plane coordinates
706 if (nbFlagTo == LEFT || nbFlagTo == RIGHT) {
707 plane[0] = 1;
708 plane[1] = 2;
709 domainSize[0] = _domainSizeY;
710 domainSize[1] = _domainSizeZ;
711 } else if (nbFlagTo == FRONT || nbFlagTo == BACK) {
712 plane[0] = 0;
713 plane[1] = 2;
714 domainSize[0] = _domainSizeX;
715 domainSize[1] = _domainSizeZ;
716 } else if (nbFlagTo == TOP || nbFlagTo == BOTTOM) {
717 plane[0] = 0;
718 plane[1] = 1;
719 domainSize[0] = _domainSizeX;
720 domainSize[1] = _domainSizeY;
721 } else {
722 std::cout << "ERROR LBCouetteSolver::communicatePart: d >2 or d < 0!" << std::endl;
723 exit(EXIT_FAILURE);
724 }
725 // extract data and write to send buffer
727 for (coords[2] = startSend[2]; coords[2] < endSend[2]; coords[2]++) {
728 for (coords[1] = startSend[1]; coords[1] < endSend[1]; coords[1]++) {
729 for (coords[0] = startSend[0]; coords[0] < endSend[0]; coords[0]++) {
730 for (int q = 0; q < 5; q++) {
731 sendBuffer[q + 5 * getParBuf(coords[plane[0]], coords[plane[1]], domainSize[0], domainSize[1])] =
732 pdf[directions[nbFlagTo][q] + 19 * get(coords[0], coords[1], coords[2])];
733 }
734 }
735 }
736 }
737 // send and receive data
738 MPI_Irecv(recvBuffer, (domainSize[0] + 2) * (domainSize[1] + 2) * 5, MPI_DOUBLE, _parallelNeighbours[nbFlagFrom], 1000,
739 coupling::indexing::IndexingService<3>::getInstance().getComm(), &requests[0]);
740 MPI_Isend(sendBuffer, (domainSize[0] + 2) * (domainSize[1] + 2) * 5, MPI_DOUBLE, _parallelNeighbours[nbFlagTo], 1000,
741 coupling::indexing::IndexingService<3>::getInstance().getComm(), &requests[1]);
742 MPI_Waitall(2, requests, status);
743 // write data back to pdf field
744 if (_parallelNeighbours[nbFlagFrom] != MPI_PROC_NULL) {
745 for (coords[2] = startRecv[2]; coords[2] < endRecv[2]; coords[2]++) {
746 for (coords[1] = startRecv[1]; coords[1] < endRecv[1]; coords[1]++) {
747 for (coords[0] = startRecv[0]; coords[0] < endRecv[0]; coords[0]++) {
748 for (int q = 0; q < 5; q++) {
749 if (_flag[get(coords[0], coords[1], coords[2])] == PARALLEL_BOUNDARY) {
750 pdf[directions[nbFlagTo][q] + 19 * get(coords[0], coords[1], coords[2])] =
751 recvBuffer[q + 5 * getParBuf(coords[plane[0]], coords[plane[1]], domainSize[0], domainSize[1])];
752 }
753 }
754 }
755 }
756 }
757 }
758#endif
759 }
760
763 void communicate() {
764#if (COUPLING_MD_PARALLEL == COUPLING_MD_YES)
765 // send from right to left
769 // send from left to right
773 // send from back to front
777 // send from front to back
781 // send from top to bottom
785 // send from bottom to top
789#endif
790 }
791
793 const double _omega;
796 int _pdfsize{0};
798 double* _pdf1{NULL};
800 double* _pdf2{NULL};
802 const int _C[19][3]{{0, -1, -1}, {-1, 0, -1}, {0, 0, -1}, {1, 0, -1}, {0, 1, -1}, {-1, -1, 0}, {0, -1, 0}, {1, -1, 0}, {-1, 0, 0}, {0, 0, 0},
803 {1, 0, 0}, {-1, 1, 0}, {0, 1, 0}, {1, 1, 0}, {0, -1, 1}, {-1, 0, 1}, {0, 0, 1}, {1, 0, 1}, {0, 1, 1}};
804
805 const double _W[19]{1.0 / 36.0, 1.0 / 36.0, 1.0 / 18.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 18.0, 1.0 / 36.0, 1.0 / 18.0, 1.0 / 3.0,
806 1.0 / 18.0, 1.0 / 36.0, 1.0 / 18.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 18.0, 1.0 / 36.0, 1.0 / 36.0};
807
809};
810
811#endif // _MOLECULARDYNAMICS_COUPLING_SOLVERS_LBCOUETTESOLVER_H_
Definition Scenario.h:19
defines the cell type with cell-averaged quantities only (no linked cells).
Definition CouplingCell.h:29
const tarch::la::Vector< dim, double > & getMacroscopicMomentum() const
Definition CouplingCell.h:64
const double & getMacroscopicMass() const
Definition CouplingCell.h:58
provides access to coupling cells, which may belong to different indexing domains
Definition FlexibleCellContainer.h:30
value_T get() const
Definition CellIndex.h:138
Definition PintableMacroSolver.h:67
Definition PintableMacroSolver.h:30
Definition LBCouetteSolver.h:21
int getSizeBytes() const override
Definition LBCouetteSolver.h:31
std::unique_ptr< State > operator+(const State &rhs) override
const double * getData() const override
Definition LBCouetteSolver.h:37
bool __equals__(const State &rhs) const override
Definition LBCouetteSolver.h:42
void print(std::ostream &os) const override
Definition LBCouetteSolver.h:39
std::unique_ptr< State > operator-(const State &rhs) override
double * getData() override
Definition LBCouetteSolver.h:36
implements a three-dimensional Lattice-Boltzmann Couette flow solver.
Definition LBCouetteSolver.h:57
static void computeDensityAndVelocity(double *const vel, double &density, const double *const pdf)
refers to the LB method; computes density and velocity on pdf
Definition LBCouetteSolver.h:670
std::unique_ptr< State > operator()(const std::unique_ptr< State > &input, int cycle) override
Definition LBCouetteSolver.h:351
std::unique_ptr< PintableMacroSolver > getSupervisor(int num_cycles, double visc_multiplier) const override
Definition LBCouetteSolver.h:373
void communicatePart(double *pdf, double *sendBuffer, double *recvBuffer, NbFlag nbFlagTo, NbFlag nbFlagFrom, tarch::la::Vector< 3, int > startSend, tarch::la::Vector< 3, int > endSend, tarch::la::Vector< 3, int > startRecv, tarch::la::Vector< 3, int > endRecv)
Definition LBCouetteSolver.h:696
std::unique_ptr< State > getState() override
Definition LBCouetteSolver.h:325
double get_avg_vel(const std::unique_ptr< State > &state) const override
Definition LBCouetteSolver.h:402
const double _omega
relaxation frequency
Definition LBCouetteSolver.h:793
const int _C[19][3]
lattice velocities
Definition LBCouetteSolver.h:802
void setMDBoundaryValues(coupling::datastructures::FlexibleCellContainer< 3 > &md2macroBuffer) override
applies the values received from the MD-solver within the conntinuum solver
Definition LBCouetteSolver.h:200
double * _pdf1
partical distribution function field
Definition LBCouetteSolver.h:798
void collide(int index, int x, int y, int z)
Definition LBCouetteSolver.h:530
void boundary(double *const pdf, int index, int x, int y, int z, int q, const Flag &flag, int nbIndex)
takes care of the correct boundary treatment for the LB method
Definition LBCouetteSolver.h:632
Mode getMode() const override
Definition LBCouetteSolver.h:365
const double _W[19]
lattice weights
Definition LBCouetteSolver.h:805
void communicate()
comunicates the boundary field data between the different processes
Definition LBCouetteSolver.h:763
tarch::la::Vector< 3, double > getVelocity(tarch::la::Vector< 3, double > pos) const override
returns velocity at a certain position
Definition LBCouetteSolver.h:263
void advance(double dt) override
advances one time step dt in time and triggers vtk plot if required
Definition LBCouetteSolver.h:176
virtual ~LBCouetteSolver()
a simple destructor
Definition LBCouetteSolver.h:125
virtual void setWallVelocity(const tarch::la::Vector< 3, double > wallVelocity) override
changes the velocity at the moving wall (z=0)
Definition LBCouetteSolver.h:319
tarch::la::Vector< 3, double > _wallVelocity
velocity of moving wall of Couette flow
Definition LBCouetteSolver.h:795
const bool _plotAverageVelocity
enables avg_vel CSV output
Definition LBCouetteSolver.h:808
void collidestream()
collide-stream algorithm for the Lattice-Boltzmann method
Definition LBCouetteSolver.h:499
void setState(const std::unique_ptr< State > &input, int cycle) override
Definition LBCouetteSolver.h:332
void print(std::ostream &os) const override
Definition LBCouetteSolver.h:395
double * _pdf2
partial distribution function field (stores the old time step)
Definition LBCouetteSolver.h:800
LBCouetteSolver(const double channelheight, tarch::la::Vector< 3, double > wallVelocity, const double kinVisc, const double dx, const double dt, const int plotEveryTimestep, const bool plotAverageVelocity, const std::string filestem, const tarch::la::Vector< 3, unsigned int > processes, const unsigned int numThreads=1, const Scenario *scen=nullptr)
a simple constructor
Definition LBCouetteSolver.h:74
void stream(int index)
the stream part of the LB algorithm (from pdf1 to pdf2)
Definition LBCouetteSolver.h:519
double getDensity(tarch::la::Vector< 3, double > pos) const override
returns density at a certain position
Definition LBCouetteSolver.h:298
is a virtual base class for the interface for a numerical fluid solver for the Couette scenario
Definition NumericalSolver.h:33
const int _domainSizeX
domain size in x-direction
Definition NumericalSolver.h:554
double * _recvBufferY
buffer to receive data from from front/back neighbour
Definition NumericalSolver.h:584
double * _sendBufferX
buffer to send data from left/right to right/left neighbour
Definition NumericalSolver.h:578
const double _channelheight
the height and width of the channel in z and y direction
Definition NumericalSolver.h:539
const double _kinVisc
kinematic viscosity of the fluid
Definition NumericalSolver.h:545
int _counter
time step counter
Definition NumericalSolver.h:569
int get(int i) const
returns i and performs checks in debug mode
Definition NumericalSolver.h:360
const int _yO
offset for z-direction
Definition NumericalSolver.h:593
double * _recvBufferZ
buffer to receive data from from top/buttom neighbour
Definition NumericalSolver.h:588
const int _avgDomainSizeZ
avg. domain size in MPI-parallel simulation in z-direction
Definition NumericalSolver.h:564
int getParBuf(int x, int y, int lengthx, int lengthy) const
returns index in 2D parallel buffer with buffer dimensions lengthx+2,lengthy+2. Performs checks in de...
Definition NumericalSolver.h:409
double * _sendBufferY
buffer to send data from front/back to front/back neighbour
Definition NumericalSolver.h:582
const int _xO
offset for y-direction (lexicographic grid ordering)
Definition NumericalSolver.h:591
double * _sendBufferZ
buffer to send data from top/buttom to top/buttom neighbour
Definition NumericalSolver.h:586
NumericalSolver(const double channelheight, const double dx, const double dt, const double kinVisc, const int plotEveryTimestep, const std::string filestem, const tarch::la::Vector< 3, unsigned int > processes, const Scenario *scen=nullptr)
a simple constructor
Definition NumericalSolver.h:46
Flag * _flag
flag field
Definition NumericalSolver.h:575
const int _avgDomainSizeY
avg. domain size in MPI-parallel simulation in y-direction
Definition NumericalSolver.h:562
const tarch::la::Vector< 3, unsigned int > _coords
coordinates of this process (=1,1,1, unless parallel run of the solver )
Definition NumericalSolver.h:567
const int _domainSizeY
domain size in y-direction
Definition NumericalSolver.h:556
const double _dt
time step
Definition NumericalSolver.h:543
tarch::la::Vector< 3, unsigned int > _processes
domain decomposition on MPI rank basis; total number is given by multipling all entries
Definition NumericalSolver.h:548
double * _density
density field
Definition NumericalSolver.h:573
tarch::la::Vector< 6, int > _parallelNeighbours
neighbour ranks
Definition NumericalSolver.h:595
const std::string _filestem
file stem for vtk plot
Definition NumericalSolver.h:552
NbFlag
The flags are used on parallel boundaries to define in which direction the boundary goes.
Definition NumericalSolver.h:530
@ LEFT
a parallel boundary to the left
Definition NumericalSolver.h:531
@ RIGHT
a parallel boundary to the right
Definition NumericalSolver.h:532
@ BOTTOM
a parallel boundary to the bottom
Definition NumericalSolver.h:535
@ FRONT
a parallel boundary to the front
Definition NumericalSolver.h:534
@ TOP
a parallel boundary to the top
Definition NumericalSolver.h:536
@ BACK
a parallel boundary to the back
Definition NumericalSolver.h:533
Flag
for every cell exists a flag entry, upon this is defined how the cell is handled
Definition NumericalSolver.h:519
@ MD_BOUNDARY
a cell on the boundary to md
Definition NumericalSolver.h:524
@ PERIODIC
a cell on a periodic boundary
Definition NumericalSolver.h:523
@ PARALLEL_BOUNDARY
a cell on a inner boundary of a splitted domain in a parallel run
Definition NumericalSolver.h:525
@ NO_SLIP
a cell on the no slip (non-moving) wall
Definition NumericalSolver.h:521
@ FLUID
a normal fluid cell
Definition NumericalSolver.h:520
@ MOVING_WALL
a cell on the moving wall
Definition NumericalSolver.h:522
const int _plotEveryTimestep
number of time steps between vtk plots
Definition NumericalSolver.h:550
double * _vel
velocity field
Definition NumericalSolver.h:571
const int _avgDomainSizeX
avg. domain size in MPI-parallel simulation in x-direction
Definition NumericalSolver.h:560
bool skipRank() const
returns true, if this rank is not of relevance for the LB simulation
Definition NumericalSolver.h:509
double * _recvBufferX
buffer to receive data from from left/right neighbour
Definition NumericalSolver.h:580
tarch::la::Vector< 3, int > _offset
offset of the md domain
Definition NumericalSolver.h:597
const double _dx
mesh size, dx=dy=dz
Definition NumericalSolver.h:541
const int _domainSizeZ
domain size in z-direction
Definition NumericalSolver.h:558
Definition Vector.h:25
all numerical solvers are defined in the namespace, and their interfaces
Definition CouetteSolver.h:14
everything necessary for coupling operations, is defined in here
Definition AdditiveMomentumInsertion.h:15