chombo-discharge
Loading...
Searching...
No Matches
CD_TracerParticleStepperImplem.H
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2021-2026 SINTEF Energy Research
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
13#ifndef CD_TRACERPARTICLESTEPPERIMPLEM_H
14#define CD_TRACERPARTICLESTEPPERIMPLEM_H
15
16// Chombo includes
17#include <CH_Timer.H>
18
19// Our includes
20#include <CD_ParticleLoops.H>
22#include <CD_Random.H>
24#include <CD_NamespaceHeader.H>
25
26using namespace Physics::TracerParticle;
27
28template <typename P>
30{
31 CH_TIME("TracerParticleStepper::TracerParticleStepper");
32
33 m_realm = Realm::Primal;
34 m_phase = phase::gas;
35
36 this->parseOptions();
37}
38
39template <typename P>
41{
42 CH_TIME("TracerParticleStepper::~TracerParticleStepper");
43 if (m_verbosity > 5) {
44 pout() << "TracerParticleStepper::~TracerParticleStepper" << endl;
45 }
46}
47
48template <typename P>
49inline void
51{
52 CH_TIME("TracerParticleStepper::setupSolvers()");
53 if (m_verbosity > 5) {
54 pout() << "TracerParticleStepper::setupSolvers()" << endl;
55 }
56
57 m_solver = RefCountedPtr<TracerParticleSolver<P>>(new TracerParticleSolver<P>(m_amr, m_computationalGeometry));
58
59 m_solver->setPhase(m_phase);
60 m_solver->setRealm(m_realm);
61 m_solver->parseOptions();
62}
63
64template <typename P>
65inline void
67{
68 CH_TIME("TracerParticleStepper::allocate()");
69 if (m_verbosity > 5) {
70 pout() << "TracerParticleStepper::allocate()" << endl;
71 }
72
73 m_amr->allocate(m_velocity, m_realm, m_phase, SpaceDim);
74 m_solver->allocate();
75}
76
77template <typename P>
78inline void
80{
81 CH_TIME("TracerParticleStepper::initialData()");
82 if (m_verbosity > 5) {
83 pout() << "TracerParticleStepper::initialData()" << endl;
84 }
85
86 this->setVelocity();
87 this->initialParticles();
88
89 m_solver->setVelocity(m_velocity);
90 m_solver->interpolateVelocities();
91}
92
93template <typename P>
94inline void
96{
97 CH_TIME("TracerParticleStepper::registerRealms()");
98 if (m_verbosity > 5) {
99 pout() << "TracerParticleStepper::registerRealms()" << endl;
100 }
101
102 m_amr->registerRealm(m_realm);
103}
104
105template <typename P>
106inline void
108{
109 CH_TIME("TracerParticleStepper::registerOperators()");
110 if (m_verbosity > 5) {
111 pout() << "TracerParticleStepper::registerOperators()" << endl;
112 }
113
114 m_solver->registerOperators();
115}
116
117template <typename P>
118inline void
120{
121 CH_TIME("TracerParticleStepper::parseOptions()");
122 if (m_verbosity > 5) {
123 pout() << "TracerParticleStepper::parseOptions()" << endl;
124 }
125
126 this->parseIntegrator();
127 this->parseVelocityField();
128 this->parseInitialConditions();
129}
130
131template <typename P>
132inline void
134{
135 CH_TIME("TracerParticleStepper::parseRuntimeOptions()");
136 if (m_verbosity > 5) {
137 pout() << "TracerParticleStepper::parseRuntimeOptions()" << endl;
138 }
139
140 this->parseIntegrator();
141
142 m_solver->parseRuntimeOptions();
143}
144
145template <typename P>
146inline void
148{
149 CH_TIME("TracerParticleStepper::parseIntegrator()");
150 if (m_verbosity > 5) {
151 pout() << "TracerParticleStepper::parseIntegrator()" << endl;
152 }
153
154 ParmParse pp("TracerParticleStepper");
155
156 std::string str;
157
158 pp.get("verbosity", m_verbosity);
159 pp.get("cfl", m_cfl);
160 pp.get("integration", str);
161 if (str == "euler") {
162 m_algorithm = IntegrationAlgorithm::Euler;
163 }
164 else if (str == "rk2") {
165 m_algorithm = IntegrationAlgorithm::RK2;
166 }
167 else if (str == "rk4") {
168 m_algorithm = IntegrationAlgorithm::RK4;
169 }
170 else {
171 MayDay::Error("TracerParticleStepper::parseIntegrator -- logic bust");
172 }
173}
174
175template <typename P>
176inline void
178{
179 CH_TIME("TracerParticleStepper::parseVelocityField()");
180 if (m_verbosity > 5) {
181 pout() << "TracerParticleStepper::parseVelocityField()" << endl;
182 }
183
184 ParmParse pp("TracerParticleStepper");
185
186 int v;
187 pp.get("velocity_field", v);
188
189 if (v == 0) {
190 m_velocityField = VelocityField::Diagonal;
191 }
192 else if (v == 1) {
193 m_velocityField = VelocityField::Rotational;
194 }
195 else {
196 MayDay::Error("TracerParticleStepper::parseVelocityField -- logic bust");
197 }
198}
199
200template <typename P>
201inline void
203{
204 CH_TIME("TracerParticleStepper::parseInitialConditions()");
205 if (m_verbosity > 5) {
206 pout() << "TracerParticleStepper::parseInitialConditions()" << endl;
207 }
208
209 ParmParse pp("TracerParticleStepper");
210
211 Real numParticles;
212 pp.get("initial_particles", numParticles);
213
214 m_numInitialParticles = size_t(std::max(0.0, numParticles));
215}
216
217#ifdef CH_USE_HDF5
218template <typename P>
219inline void
220TracerParticleStepper<P>::writeCheckpointData(HDF5Handle& a_handle, const int a_lvl) const
221{
222 CH_TIME("TracerParticleStepper::writeCheckpointData(HDF5Handle, int)");
223 if (m_verbosity > 5) {
224 pout() << "TracerParticleStepper::writeCheckpointData(HDF5Handle, int)" << endl;
225 }
226
227 m_solver->writeCheckpointLevel(a_handle, a_lvl);
228}
229#endif
230
231#ifdef CH_USE_HDF5
232template <typename P>
233inline void
234TracerParticleStepper<P>::readCheckpointData(HDF5Handle& a_handle, const int a_lvl)
235{
236 CH_TIME("TracerParticleStepper::readCheckpointData(HDF5Handle, int)");
237 if (m_verbosity > 5) {
238 pout() << "TracerParticleStepper::readCheckpointData(HDF5Handle, int)" << endl;
239 }
240
241 m_solver->readCheckpointLevel(a_handle, a_lvl);
242}
243#endif
244
245template <typename P>
246inline int
248{
249 CH_TIME("TracerParticleStepper::getNumberOfPlotVariables()");
250 if (m_verbosity > 5) {
251 pout() << "TracerParticleStepper::getNumberOfPlotVariables()" << endl;
252 }
253
254 return m_solver->getNumberOfPlotVariables();
255}
256
257template <typename P>
258inline Vector<std::string>
260{
261 CH_TIME("TracerParticleStepper::getPlotVariableNames()");
262 if (m_verbosity > 5) {
263 pout() << "TracerParticleStepper::getPlotVariableNames()" << endl;
264 }
265
266 return m_solver->getPlotVariableNames();
267}
268
269template <typename P>
270inline void
271TracerParticleStepper<P>::writePlotData(LevelData<EBCellFAB>& a_output,
272 int& a_icomp,
273 const std::string& a_outputRealm,
274 const int a_level) const
275{
276 CH_TIME("TracerParticleStepper::writePlotData(EBAMRCellData, Vector<std::string>, int)");
277 if (m_verbosity > 5) {
278 pout() << "TracerParticleStepper::writePlotData(EBAMRCellData, Vector<std::string>, int)" << endl;
279 }
280
281 CH_assert(a_level >= 0);
282 CH_assert(a_level <= m_amr->getFinestLevel());
283
284 m_solver->writePlotData(a_output, a_icomp, a_outputRealm, a_level);
285}
286
287template <typename P>
288inline Real
290{
291 CH_TIME("TracerParticleStepper::computeDt()");
292 if (m_verbosity > 5) {
293 pout() << "TracerParticleStepper::computeDt()" << endl;
294 }
295
296 return m_cfl * m_solver->computeDt();
297}
298
299template <typename P>
300inline Real
302{
303 CH_TIME("TracerParticleStepper::advance(Real)");
304 if (m_verbosity > 5) {
305 pout() << "TracerParticleStepper::advance(Real)" << endl;
306 }
307
308 switch (m_algorithm) {
309 case IntegrationAlgorithm::Euler: {
310 this->advanceParticlesEuler(a_dt);
311
312 break;
313 }
314 case IntegrationAlgorithm::RK2: {
315 this->advanceParticlesRK2(a_dt);
316
317 break;
318 }
319 case IntegrationAlgorithm::RK4: {
320 this->advanceParticlesRK4(a_dt);
321
322 break;
323 }
324 default: {
325 MayDay::Error("TracerParticleStepper::advance -- logic bust");
326 }
327 }
328
329 return a_dt;
330}
331
332template <typename P>
333inline void
334TracerParticleStepper<P>::synchronizeSolverTimes(const int a_step, const Real a_time, const Real a_dt)
335{
336 CH_TIME("TracerParticleStepper::synchronizeSolverTimes");
337 if (m_verbosity > 5) {
338 pout() << "TracerParticleStepper::synchronizeSolverTimes" << endl;
339 }
340
341 m_timeStep = a_step;
342 m_time = a_time;
343 m_dt = a_dt;
344
345 m_solver->setTime(a_step, a_time, a_dt);
346}
347
348template <typename P>
349inline void
350TracerParticleStepper<P>::preRegrid(const int a_lmin, const int a_oldFinestLevel)
351{
352 CH_TIME("TracerParticleStepper::preRegrid(int, int)");
353 if (m_verbosity > 5) {
354 pout() << "TracerParticleStepper::preRegrid(int, int)" << endl;
355 }
356
357 m_solver->preRegrid(a_lmin, a_oldFinestLevel);
358}
359
360template <typename P>
361inline void
362TracerParticleStepper<P>::regrid(const int a_lmin, const int a_oldFinestLevel, const int a_newFinestLevel)
363{
364 CH_TIME("TracerParticleStepper::regrid(int, int, int)");
365 if (m_verbosity > 5) {
366 pout() << "TracerParticleStepper::regrid(int, int, int)" << endl;
367 }
368
369 // Define velocity field on the new mesh.
370 m_amr->reallocate(m_velocity, m_phase, a_lmin);
371 DataOps::setValue(m_velocity, 0.0);
372
373 // Regrid tracer particles.
374 m_solver->regrid(a_lmin, a_oldFinestLevel, a_newFinestLevel);
375}
376
377template <typename P>
378inline void
380{
381 CH_TIME("TracerParticleStepper::postRegrid()");
382 if (m_verbosity > 5) {
383 pout() << "TracerParticleStepper::postRegrid()" << endl;
384 }
385
386 // Update particle velocities.
387 this->setVelocity();
388 m_solver->interpolateVelocities();
389}
390
391template <typename P>
392inline void
394{
395 CH_TIME("TracerParticleStepper::setVelocity()");
396 if (m_verbosity > 5) {
397 pout() << "TracerParticleStepper::setVelocity()" << endl;
398 }
399
400 std::function<RealVect(const RealVect a_position)> velFunc;
401
402 switch (m_velocityField) {
403 case VelocityField::Diagonal: {
404 velFunc = [](const RealVect& a_position) -> RealVect {
405 return RealVect::Unit;
406 };
407
408 break;
409 }
410 case VelocityField::Rotational: {
411 velFunc = [](const RealVect pos) -> RealVect {
412 const Real r = pos.vectorLength();
413 const Real theta = atan2(pos[1], pos[0]);
414
415 return RealVect(D_DECL(-r * sin(theta), r * cos(theta), 0.));
416 };
417
418 break;
419 }
420 }
421
422 DataOps::setValue(m_velocity,
423 velFunc,
424 m_amr->getProbLo(),
425 m_amr->getDx(),
426 m_amr->getMultiCutVofIterator(m_realm, m_phase));
427
428 m_amr->conservativeAverage(m_velocity, m_realm, m_phase);
429 m_amr->interpGhost(m_velocity, m_realm, m_phase);
430}
431
432template <typename P>
433inline void
435{
436 CH_TIME("TracerParticleStepper::initialParticles()");
437 if (m_verbosity > 5) {
438 pout() << "TracerParticleStepper::initialParticles()" << endl;
439 }
440
441 // clang-format off
442 // TLDR: This code draws distributed particles. Thanks to our nifty ParticleManagement and Random static classes this is just
443 // a matter of defining a distribution function. We define this as a lambda that draws particles uniformly distributed
444 // inside a box.
445 //
446 // After creating the distribution we draw the particles (MPI rank distribution being taken care of under the hood) and
447 // set their weight to one. Finally, we add these particles to the ParticleContainer and remove the particles that lie inside
448 // the EB.
449 // clang-format on
450
451 // Create a random distribution which draw particles uniformly distributed in the domain.
452 const RealVect probLo = m_amr->getProbLo();
453 const RealVect probHi = m_amr->getProbHi();
454
455 auto uniformDistribution = [probLo, probHi]() -> RealVect {
456 RealVect ret = probLo;
457
458 for (int dir = 0; dir < SpaceDim; dir++) {
459 ret[dir] += (probHi - probLo)[dir] * Random::getUniformReal01();
460 }
461
462 return ret;
463 };
464
465 // Draw particles (unit weight) into a free buffer (the List<P> analogue), then hand them to the
466 // container, which routes each particle to its owning patch/level/rank.
467 ParticleSoA<P> drawnParticles;
468 ParticleManagement::drawRandomParticles(drawnParticles, m_numInitialParticles, uniformDistribution);
469
470 ParticleContainer<P>& solverParticles = m_solver->getParticles();
471 solverParticles.clearParticles();
472 solverParticles.addParticlesDestructive(drawnParticles);
473
474 // Remove particles inside the EB.
475 m_amr->removeCoveredParticlesIF(solverParticles, m_phase, 0.0);
476}
477
478template <typename P>
479inline void
481{
482 CH_TIME("TracerParticleStepper::advanceParticlesEuler()");
483 if (m_verbosity > 5) {
484 pout() << "TracerParticleStepper::advanceParticlesEuler()" << endl;
485 }
486
487 // TLDR: The new position is just x^(k+1) = x^k + dt*v^k
488
489 ParticleContainer<P>& amrParticles = m_solver->getParticles();
490
491 for (int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
492 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
493 const DataIterator& dit = dbl.dataIterator();
494
495 const int nbox = dit.size();
496
497#pragma omp parallel for schedule(runtime)
498 for (int mybox = 0; mybox < nbox; mybox++) {
499 const DataIndex& din = dit[mybox];
500
501 ParticleSoA<P>& leaf = amrParticles[lvl][din];
502
503 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
504 const ParticleReal* const vel[SpaceDim] = {
505 D_DECL(leaf.template column<&P::v_x>(), leaf.template column<&P::v_y>(), leaf.template column<&P::v_z>())};
506
507 ParticleLoops::loop(leaf, [&](const std::size_t i) {
508 for (int dir = 0; dir < SpaceDim; dir++) {
509 pos[dir][i] += vel[dir][i] * a_dt; // x^(k+1) = x^k + dt * v^k
510 }
511 });
512 }
513 }
514
515 amrParticles.remap();
516 m_amr->removeCoveredParticlesIF(amrParticles, m_phase, 0.0);
517
518 m_solver->interpolateVelocities();
519}
520
521template <typename P>
522inline void
524{
525 CH_TIME("TracerParticleStepper::advanceParticlesRK2()");
526 if (m_verbosity > 5) {
527 pout() << "TracerParticleStepper::advanceParticlesRK2()" << endl;
528 }
529
530 // TLDR: The new positions are x^(k+1) = x^k + 0.5*dt*[ v(x^k) + v(x^*) ] where x^* = x^k + dt*v^k.
531
532 ParticleContainer<P>& amrParticles = m_solver->getParticles();
533
534 // First step. Store old position (xk) and velocity (k1), then do the Euler advance.
535 for (int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
536 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
537 const DataIterator& dit = dbl.dataIterator();
538
539 const int nbox = dit.size();
540
541#pragma omp parallel for schedule(runtime)
542 for (int mybox = 0; mybox < nbox; mybox++) {
543 const DataIndex& din = dit[mybox];
544
545 ParticleSoA<P>& leaf = amrParticles[lvl][din];
546
547 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
548 const ParticleReal* const vel[SpaceDim] = {
549 D_DECL(leaf.template column<&P::v_x>(), leaf.template column<&P::v_y>(), leaf.template column<&P::v_z>())};
550 double* const xk[SpaceDim] = {
551 D_DECL(leaf.template column<&P::xk_x>(), leaf.template column<&P::xk_y>(), leaf.template column<&P::xk_z>())};
552 ParticleReal* const k1[SpaceDim] = {
553 D_DECL(leaf.template column<&P::k1_x>(), leaf.template column<&P::k1_y>(), leaf.template column<&P::k1_z>())};
554
555 ParticleLoops::loop(leaf, [&](const std::size_t i) {
556 for (int dir = 0; dir < SpaceDim; dir++) {
557 xk[dir][i] = pos[dir][i]; // store x^k
558 k1[dir][i] = vel[dir][i]; // store v(x^k)
559 pos[dir][i] += vel[dir][i] * a_dt; // x^* = x^k + dt * v(x^k)
560 }
561 });
562 }
563 }
564
565 // Remap and interpolate the velocities again. This puts the velocity v = v(x^*) into the particles
566 amrParticles.remap();
567 m_amr->removeCoveredParticlesIF(amrParticles, m_phase, 0.0);
568 m_solver->interpolateVelocities();
569
570 // Do the second RK2 stage.
571 for (int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
572 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
573 const DataIterator& dit = dbl.dataIterator();
574
575 const int nbox = dit.size();
576
577#pragma omp parallel for schedule(runtime)
578 for (int mybox = 0; mybox < nbox; mybox++) {
579 const DataIndex& din = dit[mybox];
580
581 ParticleSoA<P>& leaf = amrParticles[lvl][din];
582
583 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
584 const ParticleReal* const vel[SpaceDim] = {
585 D_DECL(leaf.template column<&P::v_x>(), leaf.template column<&P::v_y>(), leaf.template column<&P::v_z>())};
586 const double* const xk[SpaceDim] = {
587 D_DECL(leaf.template column<&P::xk_x>(), leaf.template column<&P::xk_y>(), leaf.template column<&P::xk_z>())};
588 const ParticleReal* const k1[SpaceDim] = {
589 D_DECL(leaf.template column<&P::k1_x>(), leaf.template column<&P::k1_y>(), leaf.template column<&P::k1_z>())};
590
591 ParticleLoops::loop(leaf, [&](const std::size_t i) {
592 for (int dir = 0; dir < SpaceDim; dir++) {
593 // x^(k+1) = x^k + dt/2 * [ v(x^k) + v(x^*) ]
594 pos[dir][i] = xk[dir][i] + 0.5 * a_dt * (k1[dir][i] + vel[dir][i]);
595 }
596 });
597 }
598 }
599
600 // Remap and interpolate the velocities again
601 amrParticles.remap();
602 m_amr->removeCoveredParticlesIF(amrParticles, m_phase, 0.0);
603 m_solver->interpolateVelocities();
604}
605
606template <typename P>
607inline void
609{
610 CH_TIME("TracerParticleStepper::advanceParticlesRK4()");
611 if (m_verbosity > 5) {
612 pout() << "TracerParticleStepper::advanceParticlesRK4()" << endl;
613 }
614
615 // TLDR: Just the standard RK4 method.
616
617 ParticleContainer<P>& amrParticles = m_solver->getParticles();
618
619 const Real dtHalf = a_dt / 2.0;
620 const Real dtSixth = a_dt / 6.0;
621
622 // k1 step.
623 {
624 for (int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
625 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
626 const DataIterator& dit = dbl.dataIterator();
627
628 const int nbox = dit.size();
629
630#pragma omp parallel for schedule(runtime)
631 for (int mybox = 0; mybox < nbox; mybox++) {
632 const DataIndex& din = dit[mybox];
633
634 ParticleSoA<P>& leaf = amrParticles[lvl][din];
635
636 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
637 const ParticleReal* const vel[SpaceDim] = {
638 D_DECL(leaf.template column<&P::v_x>(), leaf.template column<&P::v_y>(), leaf.template column<&P::v_z>())};
639 double* const xk[SpaceDim] = {
640 D_DECL(leaf.template column<&P::xk_x>(), leaf.template column<&P::xk_y>(), leaf.template column<&P::xk_z>())};
641 ParticleReal* const k1[SpaceDim] = {
642 D_DECL(leaf.template column<&P::k1_x>(), leaf.template column<&P::k1_y>(), leaf.template column<&P::k1_z>())};
643
644 ParticleLoops::loop(leaf, [&](const std::size_t i) {
645 for (int dir = 0; dir < SpaceDim; dir++) {
646 xk[dir][i] = pos[dir][i]; // store x^k
647 k1[dir][i] = vel[dir][i]; // k1 = v(x^k)
648 pos[dir][i] = xk[dir][i] + dtHalf * vel[dir][i]; // x = x^k + 0.5*dt*k1
649 }
650 });
651 }
652 }
653
654 // Remap and compute v = v(x)
655 amrParticles.remap();
656 m_solver->interpolateVelocities();
657 }
658
659 // k2 step.
660 {
661 for (int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
662 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
663 const DataIterator& dit = dbl.dataIterator();
664
665 const int nbox = dit.size();
666
667#pragma omp parallel for schedule(runtime)
668 for (int mybox = 0; mybox < nbox; mybox++) {
669 const DataIndex& din = dit[mybox];
670
671 ParticleSoA<P>& leaf = amrParticles[lvl][din];
672
673 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
674 const ParticleReal* const vel[SpaceDim] = {
675 D_DECL(leaf.template column<&P::v_x>(), leaf.template column<&P::v_y>(), leaf.template column<&P::v_z>())};
676 const double* const xk[SpaceDim] = {
677 D_DECL(leaf.template column<&P::xk_x>(), leaf.template column<&P::xk_y>(), leaf.template column<&P::xk_z>())};
678 ParticleReal* const k2[SpaceDim] = {
679 D_DECL(leaf.template column<&P::k2_x>(), leaf.template column<&P::k2_y>(), leaf.template column<&P::k2_z>())};
680
681 ParticleLoops::loop(leaf, [&](const std::size_t i) {
682 for (int dir = 0; dir < SpaceDim; dir++) {
683 k2[dir][i] = vel[dir][i]; // k2 = v(x^k + 0.5*dt*k1)
684 pos[dir][i] = xk[dir][i] + dtHalf * vel[dir][i]; // x = x^k + 0.5*dt*k2
685 }
686 });
687 }
688 }
689
690 // Remap and compute v = v(x)
691 amrParticles.remap();
692 m_solver->interpolateVelocities();
693 }
694
695 // k3 step.
696 {
697 for (int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
698 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
699 const DataIterator& dit = dbl.dataIterator();
700
701 const int nbox = dit.size();
702
703#pragma omp parallel for schedule(runtime)
704 for (int mybox = 0; mybox < nbox; mybox++) {
705 const DataIndex& din = dit[mybox];
706
707 ParticleSoA<P>& leaf = amrParticles[lvl][din];
708
709 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
710 const ParticleReal* const vel[SpaceDim] = {
711 D_DECL(leaf.template column<&P::v_x>(), leaf.template column<&P::v_y>(), leaf.template column<&P::v_z>())};
712 const double* const xk[SpaceDim] = {
713 D_DECL(leaf.template column<&P::xk_x>(), leaf.template column<&P::xk_y>(), leaf.template column<&P::xk_z>())};
714 ParticleReal* const k3[SpaceDim] = {
715 D_DECL(leaf.template column<&P::k3_x>(), leaf.template column<&P::k3_y>(), leaf.template column<&P::k3_z>())};
716
717 ParticleLoops::loop(leaf, [&](const std::size_t i) {
718 for (int dir = 0; dir < SpaceDim; dir++) {
719 k3[dir][i] = vel[dir][i]; // k3 = v(x^k + 0.5*dt*k2)
720 pos[dir][i] = xk[dir][i] + a_dt * vel[dir][i]; // x = x^k + dt*k3
721 }
722 });
723 }
724 }
725
726 // Remap and compute v = v(x)
727 amrParticles.remap();
728 m_solver->interpolateVelocities();
729 }
730
731 // Final step.
732 {
733 for (int lvl = 0; lvl <= m_amr->getFinestLevel(); lvl++) {
734 const DisjointBoxLayout& dbl = m_amr->getGrids(m_realm)[lvl];
735 const DataIterator& dit = dbl.dataIterator();
736
737 const int nbox = dit.size();
738
739#pragma omp parallel for schedule(runtime)
740 for (int mybox = 0; mybox < nbox; mybox++) {
741 const DataIndex& din = dit[mybox];
742
743 ParticleSoA<P>& leaf = amrParticles[lvl][din];
744
745 double* const pos[SpaceDim] = {D_DECL(leaf.positionColumn(0), leaf.positionColumn(1), leaf.positionColumn(2))};
746 const ParticleReal* const vel[SpaceDim] = {
747 D_DECL(leaf.template column<&P::v_x>(), leaf.template column<&P::v_y>(), leaf.template column<&P::v_z>())};
748 const double* const xk[SpaceDim] = {
749 D_DECL(leaf.template column<&P::xk_x>(), leaf.template column<&P::xk_y>(), leaf.template column<&P::xk_z>())};
750 const ParticleReal* const k1[SpaceDim] = {
751 D_DECL(leaf.template column<&P::k1_x>(), leaf.template column<&P::k1_y>(), leaf.template column<&P::k1_z>())};
752 const ParticleReal* const k2[SpaceDim] = {
753 D_DECL(leaf.template column<&P::k2_x>(), leaf.template column<&P::k2_y>(), leaf.template column<&P::k2_z>())};
754 const ParticleReal* const k3[SpaceDim] = {
755 D_DECL(leaf.template column<&P::k3_x>(), leaf.template column<&P::k3_y>(), leaf.template column<&P::k3_z>())};
756
757 ParticleLoops::loop(leaf, [&](const std::size_t i) {
758 for (int dir = 0; dir < SpaceDim; dir++) {
759 pos[dir][i] = xk[dir][i] + dtSixth * k1[dir][i] + dtHalf * k2[dir][i] + dtHalf * k3[dir][i] +
760 dtSixth * vel[dir][i];
761 }
762 });
763 }
764 }
765
766 // Remap and compute v = v(x)
767 amrParticles.remap();
768 m_solver->interpolateVelocities();
769 }
770
771 m_amr->removeCoveredParticlesIF(amrParticles, m_phase, 0.0);
772}
773
774#include <CD_NamespaceFooter.H>
775
776#endif
Declaration of a namespace for SIMD-decorated loops over SoA particles.
Namespace containing various particle management utilities.
CD_PARTICLE_REAL ParticleReal
Floating-point type a user may use for payload columns.
Definition CD_ParticleSoA.H:156
File containing some useful static methods related to random number generation.
Declaration of the Physics::TracerParticle::TracerParticleStepper TimeStepper.
static void setValue(LevelData< MFInterfaceFAB< T > > &a_lhs, const T &a_value)
Set value in an MFInterfaceFAB data holder.
Definition CD_DataOpsImplem.H:24
AMR-hierarchy container of computational particles, stored per patch in Struct-of-Arrays form.
Definition CD_ParticleContainer.H:123
void clearParticles()
Drop all valid particles on every level (keeps each leaf's arena capacity).
Definition CD_ParticleContainer.H:442
void remap()
Redistribute every valid particle to the patch/level/rank that owns its cell.
Definition CD_ParticleContainerImplem.H:494
void addParticlesDestructive(ParticleSoA< P, Traits > &a_particles)
Add a free-standing buffer of particles to the container, routing each to its owner.
Definition CD_ParticleContainer.H:478
AMRParticlesSoA< P, Traits > & getParticles()
The valid particles on all levels.
Definition CD_ParticleContainer.H:317
Arena-backed Struct-of-Arrays particle container for a single grid patch.
Definition CD_ParticleSoA.H:655
double * positionColumn(const int a_dir) noexcept
Raw position component column dir (double*, for SIMD kernels).
Definition CD_ParticleSoA.H:1137
TimeStepper for advancing tracer particles in a prescribed velocity field on an AMR mesh.
Definition CD_TracerParticleStepper.H:56
void registerRealms() override
Register realms. Primal is the only realm we need.
Definition CD_TracerParticleStepperImplem.H:95
virtual void parseInitialConditions()
Parse initial conditions.
Definition CD_TracerParticleStepperImplem.H:202
void parseRuntimeOptions() override
Parse runtime options.
Definition CD_TracerParticleStepperImplem.H:133
void initialData() override
Fill problem with initial data.
Definition CD_TracerParticleStepperImplem.H:79
void registerOperators() override
Register operators.
Definition CD_TracerParticleStepperImplem.H:107
virtual Real computeDt() override
Compute a time step to be used by Driver.
Definition CD_TracerParticleStepperImplem.H:289
int getNumberOfPlotVariables() const override
Get number of plot variables for this physics module.
Definition CD_TracerParticleStepperImplem.H:247
virtual void advanceParticlesEuler(const Real a_dt)
Advance particles using explicit Euler rule.
Definition CD_TracerParticleStepperImplem.H:480
virtual void preRegrid(const int a_lmin, const int a_oldFinestLevel) override
Perform pre-regrid operations.
Definition CD_TracerParticleStepperImplem.H:350
void allocate() override
Allocate storage for solvers and time stepper.
Definition CD_TracerParticleStepperImplem.H:66
void writePlotData(LevelData< EBCellFAB > &a_output, int &a_icomp, const std::string &a_realm, const int a_level) const override
Write plot data to output holder.
Definition CD_TracerParticleStepperImplem.H:271
virtual void regrid(const int a_lmin, const int a_oldFinestLevel, const int a_newFinestLevel) override
Time stepper regrid method.
Definition CD_TracerParticleStepperImplem.H:362
virtual Real advance(const Real a_dt) override
Advancement method. Swaps between various kernels.
Definition CD_TracerParticleStepperImplem.H:301
void parseOptions()
Parse options.
Definition CD_TracerParticleStepperImplem.H:119
virtual void synchronizeSolverTimes(const int a_step, const Real a_time, const Real a_dt) override
Synchronize solver times and time steps.
Definition CD_TracerParticleStepperImplem.H:334
virtual void advanceParticlesRK2(const Real a_dt)
Advance particles using second order Runge-Kutta.
Definition CD_TracerParticleStepperImplem.H:523
void setupSolvers() override
Instantiate the tracer particle solver.
Definition CD_TracerParticleStepperImplem.H:50
virtual ~TracerParticleStepper()
Destructor.
Definition CD_TracerParticleStepperImplem.H:40
virtual void advanceParticlesRK4(const Real a_dt)
Advance particles using fourth order Runge-Kutta.
Definition CD_TracerParticleStepperImplem.H:608
Vector< std::string > getPlotVariableNames() const override
Get plot variable names.
Definition CD_TracerParticleStepperImplem.H:259
virtual void parseVelocityField()
Parse velocity field.
Definition CD_TracerParticleStepperImplem.H:177
virtual void parseIntegrator()
Parse integration algorithm from input script.
Definition CD_TracerParticleStepperImplem.H:147
virtual void postRegrid() override
Perform post-regrid operations.
Definition CD_TracerParticleStepperImplem.H:379
virtual void initialParticles()
Fill initial particles.
Definition CD_TracerParticleStepperImplem.H:434
TracerParticleStepper()
Constructor. Does nothing.
Definition CD_TracerParticleStepperImplem.H:29
virtual void setVelocity()
Set the velocity on the mesh.
Definition CD_TracerParticleStepperImplem.H:393
static Real getUniformReal01()
Get a uniform real number on the interval [0,1].
Definition CD_RandomImplem.H:156
static const std::string Primal
Identifier for perimal realm.
Definition CD_Realm.H:44
Base class for a tracer particle solver. This solver can advance particles in a pre-defined velocity ...
Definition CD_TracerParticleSolver.H:39
ALWAYS_INLINE void loop(const ParticleSoA< P, Traits > &a_soa, Functor &&a_kernel)
Launch a kernel over every particle in a ParticleSoA, decorating the loop with CD_PRAGMA_SIMD.
Definition CD_ParticleLoops.H:87
Namespace for encapsulating physics code for tracer particles.
Definition CD_TracerParticlePhysics.H:22
@ gas
Gas phase.
Definition CD_MultiFluidIndexSpace.H:39