Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
ldz_electric_field.cpp
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2016 Finnish Meteorological Institute
4 *
5 * For details of usage, see the COPYING file and read the "Rules of the Road"
6 * at http://www.physics.helsinki.fi/vlasiator/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (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 License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
23#include <algorithm>
24#include <cstdlib>
25
26#include "fs_common.h"
28
29#ifdef DEBUG_VLASIATOR
30#define DEBUG_FSOLVER
31#endif
32
33namespace pc = physicalconstants;
34using namespace std;
35
36struct Wavespeeds {
37private:
41
42 // Effective wave speeds for advection and CFL calculation
43 // Note that these are calculated as if the plasma is purely made up of hydrogen, which
44 // is a reasonable approximation if it is proton-dominant.
45 // Simulations which predominantly contain heavier ion species will have to change this!
46 //
47 // See
48 // T E Stringer, Low-frequency waves in an unbounded plasma
49 // Journal of Nuclear Energy. Part C, Plasma Physics, Accelerators, Thermonuclear Research
50 // Volume 5, Number 2, page 89
51 // Section BC in Fig. 1 and Table 1, referenced later e.g. by Gary, for the current one,
52 // and the below for the heavy ions
53 // https://www.ann-geophys.net/26/1605/2008/ (Whistler waves)
54 // and
55 // http://iopscience.iop.org/article/10.1088/0253-6102/43/2/026/meta (Alfven waves)
56 // for details.
57public:
58 Wavespeeds(Real bmag2, Real rhom, Real p11, Real p22, Real p33, const std::array<Real, 3>& gridSpacing)
59 : alfvenSq(divideIfNonZero(bmag2, pc::MU_0 * rhom)), soundSq(divideIfNonZero(p11 + p22 + p33, 2.0 * rhom)),
60 whistler(Parameters::ohmHallTerm > 0 ?
61 sqrt(alfvenSq) * (1 + divideIfNonZero(2*M_PI*M_PI*pc::MASS_PROTON*pc::MASS_PROTON, gridSpacing[0]*gridSpacing[0]*rhom*pc::CHARGE*pc::CHARGE*pc::MU_0)
62 / sqrt(1 + divideIfNonZero( M_PI*M_PI*pc::MASS_PROTON*pc::MASS_PROTON, gridSpacing[0]*gridSpacing[0]*rhom*pc::CHARGE*pc::CHARGE*pc::MU_0)))
63 : 0.0) {}
64
66
81 Real cflSpeed(Real v0, Real v1) const {
82 const Real v = sqrt(v0 * v0 + v1 * v1);
83 const Real vMS = sqrt(alfvenSq + soundSq);
84 return max(v + vMS, v + whistler);
85 }
86};
87
88struct Limits {
89 Real min = 0.0;
90 Real max = 0.0;
91};
92
106private:
107 const std::array<Real, fsgrids::bfield::N_BFIELD>& perb;
108 const std::array<Real, fsgrids::bfield::N_BFIELD>& nbr_perb;
109 const std::array<Real, fsgrids::dperb::N_DPERB>& dperb;
110 const std::array<Real, fsgrids::dperb::N_DPERB>& nbr_dperb;
111 const std::array<Real, fsgrids::bgbfield::N_BGB>& bgb;
112 const std::array<Real, fsgrids::bgbfield::N_BGB>& nbr_bgb;
113 const std::array<Real, fsgrids::moments::N_MOMENTS>& moment;
114 const std::array<Real, fsgrids::dmoments::N_DMOMENTS>& dmoment;
116
117 template <size_t N>
118 std::tuple<Real, Real> compute(const std::array<Real, N>& nbr_arr, const std::array<Real, N>& arr, size_t i,
119 size_t j, Real mul0, Real mul1) const {
120 const Real a = nbr_arr[i] + nbr_bgb[j];
121 const Real b = arr[i] + bgb[j];
122
123 return {mul0 * (a + b), mul1 * (a - b)};
124 }
125
136 Real interpolateAndLimitMoments(Real dir0, Real dir1, size_t i, size_t j, size_t k, Real min, Real max) const {
137 return std::clamp(moment[i] + HALF * (dir0 * dmoment[j] + dir1 * dmoment[k]), min, max);
138 }
139
140public:
145 fsgrids::constdmomentsspan dMoments, size_t self, size_t nbr,
146 const Limits& rhomLimits)
147 : perb(perB[self]), nbr_perb(perB[nbr]), dperb(dPerB[self]), nbr_dperb(dPerB[nbr]), bgb(BgB[self]),
148 nbr_bgb(BgB[nbr]), moment(moments[self]), dmoment(dMoments[self]), rhomLimits(rhomLimits) {}
149
150 std::tuple<Real, Real> perBCoeffs(size_t i, size_t j) const { return compute(nbr_perb, perb, i, j, HALF, 1.0); }
151
152 std::tuple<Real, Real> dPerBCoeffs(size_t i, size_t j) const { return compute(nbr_dperb, dperb, i, j, 1.0, 1.0); }
153
154 Real rhom(Real dir0, Real dir1, size_t i, size_t j, size_t k) const {
155 return interpolateAndLimitMoments(dir0, dir1, i, j, k, rhomLimits.min, rhomLimits.max);
156 }
157
158 Real p(Real dir0, Real dir1, size_t i, size_t j, size_t k) const {
159 return interpolateAndLimitMoments(dir0, dir1, i, j, k, 0.0, std::numeric_limits<Real>::max());
160 }
161
162 static Real squared(Real a, Real b) { return a * a + TWELWTH * b * b; }
163};
164
198 const std::array<Real, 3>& gridSpacing, const Limits& rhomLimits, size_t self,
199 size_t nbr, Real By, Real Bz, Real dBydx, Real dBydz, Real dBzdx, Real dBzdy, Real ydir,
200 Real zdir) {
201 const Reconstructions rec(perB, dPerB, BgB, moments, dMoments, self, nbr, rhomLimits);
202
203 const Real rhom =
208
209 const auto [A_0, A_X] = rec.perBCoeffs(fsgrids::bfield::PERBX, fsgrids::bgbfield::BGBX);
212
213 const Real bx2 = Reconstructions::squared(A_0 + HALF * (ydir * A_Y + zdir * A_Z), A_X + HALF * (ydir * A_XY + zdir * A_XZ));
214 const Real by2 = Reconstructions::squared(By + zdir * HALF * dBydz, dBydx);
215 const Real bz2 = Reconstructions::squared(Bz + ydir * HALF * dBzdy, dBzdx);
216
217 return Wavespeeds(bx2 + by2 + bz2, rhom, p11, p22, p33, gridSpacing);
218}
219
252 const std::array<Real, 3>& gridSpacing, const Limits& rhomLimits, size_t self,
253 size_t nbr, Real Bx, Real Bz, Real dBxdy, Real dBxdz, Real dBzdx, Real dBzdy, Real xdir,
254 Real zdir) {
255 const Reconstructions rec(perB, dPerB, BgB, moments, dMoments, self, nbr, rhomLimits);
256
257 const Real rhom =
262
263 const auto [B_0, B_Y] = rec.perBCoeffs(fsgrids::bfield::PERBY, fsgrids::bgbfield::BGBY);
266
267 const Real by2 = Reconstructions::squared(B_0 + HALF * (xdir * B_X + zdir * B_Z), B_Y + HALF * (xdir * B_XY + zdir * B_YZ));
268 const Real bx2 = Reconstructions::squared(Bx + zdir * HALF * dBxdz, dBxdy);
269 const Real bz2 = Reconstructions::squared(Bz + xdir * HALF * dBzdx, dBzdy);
270
271 return Wavespeeds(bx2 + by2 + bz2, rhom, p11, p22, p33, gridSpacing);
272}
273
306 const std::array<Real, 3>& gridSpacing, const Limits& rhomLimits, size_t self,
307 size_t nbr, Real Bx, Real By, Real dBxdy, Real dBxdz, Real dBydx, Real dBydz, Real xdir,
308 Real ydir) {
309 const Reconstructions rec(perB, dPerB, BgB, moments, dMoments, self, nbr, rhomLimits);
310
311 const Real rhom =
316
317 const auto [C_0, C_Z] = rec.perBCoeffs(fsgrids::bfield::PERBZ, fsgrids::bgbfield::BGBZ);
320
321 const Real bz2 = Reconstructions::squared(C_0 + HALF * (xdir * C_X + ydir * C_Y), C_Z + HALF * (xdir * C_XZ + ydir * C_YZ));
322 const Real bx2 = Reconstructions::squared(Bx + ydir * HALF * dBxdy, dBxdz);
323 const Real by2 = Reconstructions::squared(By + xdir * HALF * dBydx, dBydz);
324
325 return Wavespeeds(bx2 + by2 + bz2, rhom, p11, p22, p33, gridSpacing);
326}
327
328void fsdebugCheck([[maybe_unused]] const fsgrid::FsStencil& stencil, [[maybe_unused]] size_t len,
329 [[maybe_unused]] const char* file, [[maybe_unused]] uint32_t line) {
330#ifdef DEBUG_FSOLVER
331 const bool ok = stencil.ooo() < len &&
332 stencil.oom() < len && stencil.omo() < len && stencil.moo() < len &&
333 stencil.omm() < len && stencil.mom() < len && stencil.mmo() < len;
334
335 if (!ok) {
336 cerr << "Out-of-bounds access in " << file << ":" << line << std::endl;
337 exit(1);
338 }
339#endif
340}
341
343Limits getRhomLimits(const std::array<std::array<Real, fsgrids::moments::N_MOMENTS>, 4>& moments) {
344 Real minRhom = std::numeric_limits<Real>::max();
345 Real maxRhom = std::numeric_limits<Real>::min();
346 for (const auto& m : moments) {
347 const auto rhom = m[fsgrids::moments::RHOM];
348 minRhom = min(minRhom, rhom);
349 maxRhom = max(maxRhom, rhom);
350 }
351 return {
352 minRhom,
353 maxRhom,
354 };
355}
356
357Real resistiveTerm(const auto& bgb, const auto& perb, const auto& dperb, Real rhoq, std::array<size_t, 2> indices,
358 std::array<Real, 2> spacing) {
359 const auto x = bgb[fsgrids::bgbfield::BGBX] + perb[fsgrids::bfield::PERBX];
360 const auto y = bgb[fsgrids::bgbfield::BGBY] + perb[fsgrids::bfield::PERBY];
361 const auto z = bgb[fsgrids::bgbfield::BGBZ] + perb[fsgrids::bfield::PERBZ];
362
363 return Parameters::resistivity * sqrt(x * x + y * y + z * z) / rhoq / physicalconstants::MU_0 *
364 (dperb[indices[0]] / spacing[0] - dperb[indices[1]] / spacing[1]);
365}
366
368 Real E_NE = 0.0;
369 Real E_SE = 0.0;
370 Real E_NW = 0.0;
371 Real E_SW = 0.0;
372 Real apos = 0.0;
373 Real aneg = 0.0;
374 Real bpos = 0.0;
375 Real bneg = 0.0;
384
385 Real operator()() const {
386 Real efield = apos * bpos * E_NE + apos * bneg * E_SE + aneg * bpos * E_NW + aneg * bneg * E_SW;
387 efield /= ((apos + aneg) * (bpos + bneg) + EPS);
389#ifdef FS_1ST_ORDER_SPACE
390 // 1st order diffusive terms:
391 efield -= bpos * bneg / (bpos + bneg + EPS) * (perB_S - perB_N);
392 efield += apos * aneg / (apos + aneg + EPS) * (perB_W - perB_E);
393#else
394 // 2nd order diffusive terms
395 efield -= bpos * bneg / (bpos + bneg + EPS) * ((perB_S - HALF * dperB_S) - (perB_N + HALF * dperB_N));
396 efield += apos * aneg / (apos + aneg + EPS) * ((perB_W - HALF * dperB_W) - (perB_E + HALF * dperB_E));
397#endif
398 }
399
400 return efield;
401 }
402};
403
405 size_t sw = 0;
406 size_t se = 0;
407 size_t nw = 0;
408 size_t ne = 0;
409};
410
412 const std::array<Real, fsgrids::bfield::N_BFIELD>& perb;
413 const std::array<Real, fsgrids::dperb::N_DPERB>& dperb;
414 const std::array<Real, fsgrids::moments::N_MOMENTS>& moments;
415 const std::array<Real, fsgrids::dmoments::N_DMOMENTS>& dmoments;
416 const std::array<Real, fsgrids::bgbfield::N_BGB>& bgb;
417
424};
425
456 fsgrids::technicalspan technical, const fsgrid::FsStencil& stencil,
457 int32_t RKCase, const std::array<Real, 3>& gridSpacing) {
458 fsdebugCheck(stencil, perb.size(), __FILE__, __LINE__);
459
460 // An edge has four neighbouring spatial cells. Calculate
461 // electric field in each of the four cells per edge.
462 Real ay_pos, ay_neg; // Max. characteristic velocities to y-direction
463 Real az_pos, az_neg; // Max. characteristic velocities to z-direction
464 Real maxV = 0.0; // Max velocity for CFL purposes
465 Real c_y, c_z; // Wave speeds to yz-directions
466
467 const CardinalIndices ci{stencil.ooo(), stencil.omo(), stencil.oom(), stencil.omm()};
468 const DataArrays sw{perb, dperb, moments, dmoments, bgb, ci.sw};
469 const DataArrays se{perb, dperb, moments, dmoments, bgb, ci.se};
470 const DataArrays nw{perb, dperb, moments, dmoments, bgb, ci.nw};
471 const DataArrays ne{perb, dperb, moments, dmoments, bgb, ci.ne};
472
473 const auto rhomLimits = getRhomLimits({
474 sw.moments,
475 se.moments,
476 nw.moments,
477 ne.moments,
478 });
479
484 const Real perBy_S = sw.perb[fsgrids::bfield::PERBY];
485 const Real perBz_W = sw.perb[fsgrids::bfield::PERBZ];
486 const Real perBz_E = se.perb[fsgrids::bfield::PERBZ];
487 const Real perBy_N = nw.perb[fsgrids::bfield::PERBY];
490
499 creal dperBydz_S = sw.dperb[fsgrids::dperb::dPERBydz];
500 creal dperBydz_N = nw.dperb[fsgrids::dperb::dPERBydz];
501 creal dperBzdy_W = sw.dperb[fsgrids::dperb::dPERBzdy];
502 creal dperBzdy_E = se.dperb[fsgrids::dperb::dPERBzdy];
503
504 // Ex and characteristic speeds on this cell:
505 // 1st order terms:
506 Real Ex_SW = By_S * Vz0 - Bz_W * Vy0;
507
508#ifndef FS_1ST_ORDER_SPACE
509 // 2nd order terms:
510 Ex_SW += +HALF * ((By_S - HALF * dBydz_S) * (-sw.dmoments[fsgrids::dmoments::dVzdy] - sw.dmoments[fsgrids::dmoments::dVzdz]) - dBydz_S * Vz0 + SIXTH * dBydx_S * sw.dmoments[fsgrids::dmoments::dVzdx]);
511 Ex_SW += -HALF * ((Bz_W - HALF * dBzdy_W) * (-sw.dmoments[fsgrids::dmoments::dVydy] - sw.dmoments[fsgrids::dmoments::dVydz]) - dBzdy_W * Vy0 + SIXTH * dBzdx_W * sw.dmoments[fsgrids::dmoments::dVydx]);
512#endif
513 size_t self = stencil.ooo();
514 size_t nbr = stencil.poo();
515 auto wavespeeds = calculateWaveSpeedYZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, By_S,
516 Bz_W, dBydx_S, dBydz_S, dBzdx_W, dBzdy_W, MINUS, MINUS);
517 c_y = wavespeeds.minVelocity();
518 c_z = c_y;
519 ay_neg = max(ZERO, -Vy0 + c_y);
520 ay_pos = max(ZERO, +Vy0 + c_y);
521 az_neg = max(ZERO, -Vz0 + c_z);
522 az_pos = max(ZERO, +Vz0 + c_z);
523 maxV = max(maxV, wavespeeds.cflSpeed(Vy0, Vz0));
524
525 // Ex and characteristic speeds on SE neighbour:
528
529 // 1st order terms:
530 Real Ex_SE = By_S * Vz0 - Bz_E * Vy0;
531
532#ifndef FS_1ST_ORDER_SPACE
533 // 2nd order terms:
534 Ex_SE += +HALF * ((By_S - HALF * dBydz_S) * (+se.dmoments[fsgrids::dmoments::dVzdy] - se.dmoments[fsgrids::dmoments::dVzdz]) - dBydz_S * Vz0 + SIXTH * dBydx_S * se.dmoments[fsgrids::dmoments::dVzdx]);
535 Ex_SE += -HALF * ((Bz_E + HALF * dBzdy_E) * (+se.dmoments[fsgrids::dmoments::dVydy] - se.dmoments[fsgrids::dmoments::dVydz]) + dBzdy_E * Vy0 + SIXTH * dBzdx_E * se.dmoments[fsgrids::dmoments::dVydx]);
536#endif
537
538 self = stencil.omo();
539 nbr = stencil.pmo();
540 wavespeeds = calculateWaveSpeedYZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, By_S,
541 Bz_E, dBydx_S, dBydz_S, dBzdx_E, dBzdy_E, PLUS, MINUS);
542 c_y = wavespeeds.minVelocity();
543 c_z = c_y;
544 ay_neg = max(ay_neg, -Vy0 + c_y);
545 ay_pos = max(ay_pos, +Vy0 + c_y);
546 az_neg = max(az_neg, -Vz0 + c_z);
547 az_pos = max(az_pos, +Vz0 + c_z);
548 maxV = max(maxV, wavespeeds.cflSpeed(Vy0, Vz0));
549
550 // Ex and characteristic speeds on NW neighbour:
553
554 // 1st order terms:
555 Real Ex_NW = By_N * Vz0 - Bz_W * Vy0;
556
557#ifndef FS_1ST_ORDER_SPACE
558 // 2nd order terms:
559 Ex_NW += +HALF * ((By_N + HALF * dBydz_N) * (-nw.dmoments[fsgrids::dmoments::dVzdy] + nw.dmoments[fsgrids::dmoments::dVzdz]) + dBydz_N * Vz0 + SIXTH * dBydx_N * nw.dmoments[fsgrids::dmoments::dVzdx]);
560 Ex_NW += -HALF * ((Bz_W - HALF * dBzdy_W) * (-nw.dmoments[fsgrids::dmoments::dVydy] + nw.dmoments[fsgrids::dmoments::dVydz]) - dBzdy_W * Vy0 + SIXTH * dBzdx_W * nw.dmoments[fsgrids::dmoments::dVydx]);
561#endif
562
563 self = stencil.oom();
564 nbr = stencil.pom();
565 wavespeeds = calculateWaveSpeedYZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, By_N,
566 Bz_W, dBydx_N, dBydz_N, dBzdx_W, dBzdy_W, MINUS, PLUS);
567 c_y = wavespeeds.minVelocity();
568 c_z = c_y;
569 ay_neg = max(ay_neg, -Vy0 + c_y);
570 ay_pos = max(ay_pos, +Vy0 + c_y);
571 az_neg = max(az_neg, -Vz0 + c_z);
572 az_pos = max(az_pos, +Vz0 + c_z);
573 maxV = max(maxV, wavespeeds.cflSpeed(Vy0, Vz0));
574
575 // Ex and characteristic speeds on NE neighbour:
576 Vy0 = ne.moments[fsgrids::moments::VY];
577 Vz0 = ne.moments[fsgrids::moments::VZ];
578
579 // 1st order terms:
580 Real Ex_NE = By_N * Vz0 - Bz_E * Vy0;
581
582#ifndef FS_1ST_ORDER_SPACE
583 // 2nd order terms:
584 Ex_NE += +HALF * ((By_N + HALF * dBydz_N) *
585 (+ne.dmoments[fsgrids::dmoments::dVzdy] + ne.dmoments[fsgrids::dmoments::dVzdz]) +
586 dBydz_N * Vz0 + SIXTH * dBydx_N * ne.dmoments[fsgrids::dmoments::dVzdx]);
587 Ex_NE += -HALF * ((Bz_E + HALF * dBzdy_E) *
588 (+ne.dmoments[fsgrids::dmoments::dVydy] + ne.dmoments[fsgrids::dmoments::dVydz]) +
589 dBzdy_E * Vy0 + SIXTH * dBzdx_E * ne.dmoments[fsgrids::dmoments::dVydx]);
590#endif
591
592 self = stencil.omm();
593 nbr = stencil.pmm();
594 wavespeeds = calculateWaveSpeedYZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, By_N,
595 Bz_E, dBydx_N, dBydz_N, dBzdx_E, dBzdy_E, PLUS, PLUS);
596 c_y = wavespeeds.minVelocity();
597 c_z = c_y;
598 ay_neg = max(ay_neg, -Vy0 + c_y);
599 ay_pos = max(ay_pos, +Vy0 + c_y);
600 az_neg = max(az_neg, -Vz0 + c_z);
601 az_pos = max(az_pos, +Vz0 + c_z);
602 maxV = max(maxV, wavespeeds.cflSpeed(Vy0, Vz0));
603
604 // Resistive terms
605 if (Parameters::resistivity > 0) {
606 const std::array indices = {static_cast<size_t>(fsgrids::dperb::dPERBzdy),
607 static_cast<size_t>(fsgrids::dperb::dPERBydz)};
608 const std::array spacing = {gridSpacing[1], gridSpacing[2]};
609
610 Ex_SW += resistiveTerm(sw.bgb, sw.perb, sw.dperb, sw.moments[fsgrids::moments::RHOQ], indices, spacing);
611 Ex_SE += resistiveTerm(se.bgb, se.perb, se.dperb, se.moments[fsgrids::moments::RHOQ], indices, spacing);
612 Ex_NW += resistiveTerm(nw.bgb, nw.perb, nw.dperb, nw.moments[fsgrids::moments::RHOQ], indices, spacing);
613 Ex_NE += resistiveTerm(ne.bgb, ne.perb, ne.dperb, ne.moments[fsgrids::moments::RHOQ], indices, spacing);
614 }
615
616 // Hall terms
617 if (Parameters::ohmHallTerm > 0) {
618 Ex_SW += ehall[ci.sw][fsgrids::ehall::EXHALL_000_100];
619 Ex_SE += ehall[ci.se][fsgrids::ehall::EXHALL_010_110];
620 Ex_NW += ehall[ci.nw][fsgrids::ehall::EXHALL_001_101];
621 Ex_NE += ehall[ci.ne][fsgrids::ehall::EXHALL_011_111];
622 }
623
624 // Electron pressure gradient terms
626 Ex_SW += egradpe[ci.sw][fsgrids::egradpe::EXGRADPE];
627 Ex_SE += egradpe[ci.se][fsgrids::egradpe::EXGRADPE];
628 Ex_NW += egradpe[ci.nw][fsgrids::egradpe::EXGRADPE];
629 Ex_NE += egradpe[ci.ne][fsgrids::egradpe::EXGRADPE];
630 }
631
632 // Calculate properly upwinded edge-averaged Ex:
633 const UpwindField f(Ex_NE, Ex_SE, Ex_NW, Ex_SW, ay_pos, ay_neg, az_pos, az_neg, perBy_S, perBy_N, perBz_W, perBz_E,
634 dperBydz_S, dperBydz_N, dperBzdy_W, dperBzdy_E);
635 e[ci.sw][fsgrids::efield::EX] = f();
636
637 if ((RKCase == RK_ORDER1) || (RKCase == RK_ORDER2_STEP2)) {
638 // compute maximum timestep for fieldsolver in this cell (CFL=1)
639 Real min_dx = std::numeric_limits<Real>::max();
640 min_dx = min(min_dx, gridSpacing[1]);
641 min_dx = min(min_dx, gridSpacing[2]);
642 // update max allowed timestep for field propagation in this cell, which is the minimum of CFL=1 timesteps
643 if (maxV != ZERO) {
644 auto& maxFsDt = technical[stencil.ooo()].maxFsDt;
645 maxFsDt = min(maxFsDt, min_dx / maxV);
646 }
647 }
648}
649
679 fsgrids::technicalspan technical, const fsgrid::FsStencil& stencil,
680 int32_t RKCase, const std::array<Real, 3>& gridSpacing) {
681 fsdebugCheck(stencil, perb.size(), __FILE__, __LINE__);
682
683 // An edge has four neighbouring spatial cells. Calculate
684 // electric field in each of the four cells per edge.
685 Real ax_pos, ax_neg; // Max. characteristic velocities to x-direction
686 Real az_pos, az_neg; // Max. characteristic velocities to z-direction
687 Real maxV = 0.0; // Max velocity for CFL purposes
688 Real c_x, c_z; // Wave speeds to xz-directions
689
690 const CardinalIndices ci{stencil.ooo(), stencil.oom(), stencil.moo(), stencil.mom()};
691 const DataArrays sw{perb, dperb, moments, dmoments, bgb, ci.sw};
692 const DataArrays se{perb, dperb, moments, dmoments, bgb, ci.se};
693 const DataArrays nw{perb, dperb, moments, dmoments, bgb, ci.nw};
694 const DataArrays ne{perb, dperb, moments, dmoments, bgb, ci.ne};
695
696 const auto rhomLimits = getRhomLimits({
697 sw.moments,
698 se.moments,
699 nw.moments,
700 ne.moments,
701 });
702 // Fetch required plasma parameters:
707 const Real perBz_S = sw.perb[fsgrids::bfield::PERBZ];
708 const Real perBx_W = sw.perb[fsgrids::bfield::PERBX];
709 const Real perBx_E = se.perb[fsgrids::bfield::PERBX];
710 const Real perBz_N = nw.perb[fsgrids::bfield::PERBZ];
713
722 creal dperBzdx_S = sw.dperb[fsgrids::dperb::dPERBzdx];
723 creal dperBzdx_N = nw.dperb[fsgrids::dperb::dPERBzdx];
724 creal dperBxdz_W = sw.dperb[fsgrids::dperb::dPERBxdz];
725 creal dperBxdz_E = se.dperb[fsgrids::dperb::dPERBxdz];
726
727 // Ey and characteristic speeds on this cell:
728 // 1st order terms:
729 Real Ey_SW = Bz_S * Vx0 - Bx_W * Vz0;
730
731#ifndef FS_1ST_ORDER_SPACE
732 // 2nd order terms
733 Ey_SW += +HALF * ((Bz_S - HALF * dBzdx_S) * (-sw.dmoments[fsgrids::dmoments::dVxdx] - sw.dmoments[fsgrids::dmoments::dVxdz]) - dBzdx_S * Vx0 + SIXTH * dBzdy_S * sw.dmoments[fsgrids::dmoments::dVxdy]);
734 Ey_SW += -HALF * ((Bx_W - HALF * dBxdz_W) * (-sw.dmoments[fsgrids::dmoments::dVzdx] - sw.dmoments[fsgrids::dmoments::dVzdz]) - dBxdz_W * Vz0 + SIXTH * dBxdy_W * sw.dmoments[fsgrids::dmoments::dVzdy]);
735#endif
736
737 size_t self = stencil.ooo();
738 size_t nbr = stencil.opo();
739 auto wavespeeds = calculateWaveSpeedXZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_W,
740 Bz_S, dBxdy_W, dBxdz_W, dBzdx_S, dBzdy_S, MINUS, MINUS);
741 c_z = wavespeeds.minVelocity();
742 c_x = c_z;
743 az_neg = max(ZERO, -Vz0 + c_z);
744 az_pos = max(ZERO, +Vz0 + c_z);
745 ax_neg = max(ZERO, -Vx0 + c_x);
746 ax_pos = max(ZERO, +Vx0 + c_x);
747 maxV = max(maxV, wavespeeds.cflSpeed(Vz0, Vx0));
748
749 // Ey and characteristic speeds on SE neighbour:
752
753 // 1st order terms:
754 Real Ey_SE = Bz_S * Vx0 - Bx_E * Vz0;
755
756#ifndef FS_1ST_ORDER_SPACE
757 // 2nd order terms:
758 Ey_SE += +HALF * ((Bz_S - HALF * dBzdx_S) * (-se.dmoments[fsgrids::dmoments::dVxdx] + se.dmoments[fsgrids::dmoments::dVxdz]) - dBzdx_S * Vx0 + SIXTH * dBzdy_S * se.dmoments[fsgrids::dmoments::dVxdy]);
759 Ey_SE += -HALF * ((Bx_E + HALF * dBxdz_E) * (-se.dmoments[fsgrids::dmoments::dVzdx] + se.dmoments[fsgrids::dmoments::dVzdz]) + dBxdz_E * Vz0 + SIXTH * dBxdy_E * se.dmoments[fsgrids::dmoments::dVzdy]);
760#endif
761
762 self = stencil.oom();
763 nbr = stencil.opm();
764 wavespeeds = calculateWaveSpeedXZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_E,
765 Bz_S, dBxdy_E, dBxdz_E, dBzdx_S, dBzdy_S, MINUS, PLUS);
766 c_z = wavespeeds.minVelocity();
767 c_x = c_z;
768 az_neg = max(az_neg, -Vz0 + c_z);
769 az_pos = max(az_pos, +Vz0 + c_z);
770 ax_neg = max(ax_neg, -Vx0 + c_x);
771 ax_pos = max(ax_pos, +Vx0 + c_x);
772 maxV = max(maxV, wavespeeds.cflSpeed(Vz0, Vx0));
773
774 // Ey and characteristic speeds on NW neighbour:
777
778 // 1st order terms:
779 Real Ey_NW = Bz_N * Vx0 - Bx_W * Vz0;
780
781#ifndef FS_1ST_ORDER_SPACE
782 // 2nd order terms:
783 Ey_NW += +HALF * ((Bz_N + HALF * dBzdx_N) * (+nw.dmoments[fsgrids::dmoments::dVxdx] - nw.dmoments[fsgrids::dmoments::dVxdz]) + dBzdx_N * Vx0 + SIXTH * dBzdy_N * nw.dmoments[fsgrids::dmoments::dVxdy]);
784 Ey_NW += -HALF * ((Bx_W - HALF * dBxdz_W) * (+nw.dmoments[fsgrids::dmoments::dVzdx] - nw.dmoments[fsgrids::dmoments::dVzdz]) - dBxdz_W * Vz0 + SIXTH * dBxdy_W * nw.dmoments[fsgrids::dmoments::dVzdy]);
785#endif
786
787 self = stencil.moo();
788 nbr = stencil.mpo();
789 wavespeeds = calculateWaveSpeedXZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_W,
790 Bz_N, dBxdy_W, dBxdz_W, dBzdx_N, dBzdy_N, PLUS, MINUS);
791 c_z = wavespeeds.minVelocity();
792 c_x = c_z;
793 az_neg = max(az_neg, -Vz0 + c_z);
794 az_pos = max(az_pos, +Vz0 + c_z);
795 ax_neg = max(ax_neg, -Vx0 + c_x);
796 ax_pos = max(ax_pos, +Vx0 + c_x);
797 maxV = max(maxV, wavespeeds.cflSpeed(Vz0, Vx0));
798
799 // Ey and characteristic speeds on NE neighbour:
800 Vz0 = ne.moments[fsgrids::moments::VZ];
801 Vx0 = ne.moments[fsgrids::moments::VX];
802
803 // 1st order terms:
804 Real Ey_NE = Bz_N * Vx0 - Bx_E * Vz0;
805
806#ifndef FS_1ST_ORDER_SPACE
807 // 2nd order terms:
808 Ey_NE += +HALF * ((Bz_N + HALF * dBzdx_N) * (+ne.dmoments[fsgrids::dmoments::dVxdx] + ne.dmoments[fsgrids::dmoments::dVxdz]) + dBzdx_N * Vx0 + SIXTH * dBzdy_N * ne.dmoments[fsgrids::dmoments::dVxdy]);
809 Ey_NE += -HALF * ((Bx_E + HALF * dBxdz_E) * (+ne.dmoments[fsgrids::dmoments::dVzdx] + ne.dmoments[fsgrids::dmoments::dVzdz]) + dBxdz_E * Vz0 + SIXTH * dBxdy_E * ne.dmoments[fsgrids::dmoments::dVzdy]);
810#endif
811
812 self = stencil.mom();
813 nbr = stencil.mpm();
814 wavespeeds = calculateWaveSpeedXZ(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_E,
815 Bz_N, dBxdy_E, dBxdz_E, dBzdx_N, dBzdy_N, PLUS, PLUS);
816 c_z = wavespeeds.minVelocity();
817 c_x = c_z;
818 az_neg = max(az_neg, -Vz0 + c_z);
819 az_pos = max(az_pos, +Vz0 + c_z);
820 ax_neg = max(ax_neg, -Vx0 + c_x);
821 ax_pos = max(ax_pos, +Vx0 + c_x);
822 maxV = max(maxV, wavespeeds.cflSpeed(Vz0, Vx0));
823
824 // Resistive terms
825 if (Parameters::resistivity > 0) {
826 const std::array indices = {static_cast<size_t>(fsgrids::dperb::dPERBxdz),
827 static_cast<size_t>(fsgrids::dperb::dPERBzdx)};
828 const std::array spacing = {gridSpacing[2], gridSpacing[0]};
829
830 Ey_SW += resistiveTerm(sw.bgb, sw.perb, sw.dperb, sw.moments[fsgrids::moments::RHOQ], indices, spacing);
831 Ey_SE += resistiveTerm(se.bgb, se.perb, se.dperb, se.moments[fsgrids::moments::RHOQ], indices, spacing);
832 Ey_NW += resistiveTerm(nw.bgb, nw.perb, nw.dperb, nw.moments[fsgrids::moments::RHOQ], indices, spacing);
833 Ey_NE += resistiveTerm(ne.bgb, ne.perb, ne.dperb, ne.moments[fsgrids::moments::RHOQ], indices, spacing);
834 }
835
836 // Hall terms
837 if (Parameters::ohmHallTerm > 0) {
838 Ey_SW += ehall[ci.sw][fsgrids::ehall::EYHALL_000_010];
839 Ey_SE += ehall[ci.se][fsgrids::ehall::EYHALL_001_011];
840 Ey_NW += ehall[ci.nw][fsgrids::ehall::EYHALL_100_110];
841 Ey_NE += ehall[ci.ne][fsgrids::ehall::EYHALL_101_111];
842 }
843
844 // Electron pressure gradient terms
846 Ey_SW += egradpe[ci.sw][fsgrids::egradpe::EYGRADPE];
847 Ey_SE += egradpe[ci.se][fsgrids::egradpe::EYGRADPE];
848 Ey_NW += egradpe[ci.nw][fsgrids::egradpe::EYGRADPE];
849 Ey_NE += egradpe[ci.ne][fsgrids::egradpe::EYGRADPE];
850 }
851
852 // Calculate properly upwinded edge-averaged Ey:
853 const UpwindField f(Ey_NE, Ey_SE, Ey_NW, Ey_SW, az_pos, az_neg, ax_pos, ax_neg, perBz_S, perBz_N, perBx_W, perBx_E,
854 dperBzdx_S, dperBzdx_N, dperBxdz_W, dperBxdz_E);
855 e[ci.sw][fsgrids::efield::EY] = f();
856
857 if ((RKCase == RK_ORDER1) || (RKCase == RK_ORDER2_STEP2)) {
858 // compute maximum timestep for fieldsolver in this cell (CFL=1)
859 Real min_dx = std::numeric_limits<Real>::max();
860 min_dx = min(min_dx, gridSpacing[0]);
861 min_dx = min(min_dx, gridSpacing[2]);
862 // update max allowed timestep for field propagation in this cell, which is the minimum of CFL=1 timesteps
863 if (maxV != ZERO) {
864 auto& maxFsDt = technical[stencil.ooo()].maxFsDt;
865 maxFsDt = min(maxFsDt, min_dx / maxV);
866 }
867 }
868}
869
899 fsgrids::technicalspan technical, const fsgrid::FsStencil& stencil,
900 int32_t RKCase, const std::array<Real, 3>& gridSpacing) {
901 fsdebugCheck(stencil, perb.size(), __FILE__, __LINE__);
902
903 // An edge has four neighbouring spatial cells. Calculate
904 // electric field in each of the four cells per edge.
905 Real ax_pos, ax_neg; // Max. characteristic velocities to x-direction
906 Real ay_pos, ay_neg; // Max. characteristic velocities to y-direction
907 Real maxV = 0.0; // Max velocity for CFL purposes
908 Real c_x, c_y; // Characteristic speeds to xy-directions
909
910 const CardinalIndices ci{stencil.ooo(), stencil.moo(), stencil.omo(), stencil.mmo()};
911 const DataArrays sw{perb, dperb, moments, dmoments, bgb, ci.sw};
912 const DataArrays se{perb, dperb, moments, dmoments, bgb, ci.se};
913 const DataArrays nw{perb, dperb, moments, dmoments, bgb, ci.nw};
914 const DataArrays ne{perb, dperb, moments, dmoments, bgb, ci.ne};
915
916 const auto rhomLimits = getRhomLimits({
917 sw.moments,
918 se.moments,
919 nw.moments,
920 ne.moments,
921 });
922
923 // Fetch needed plasma parameters/derivatives from the four cells:
928 const Real perBx_S = sw.perb[fsgrids::bfield::PERBX];
929 const Real perBy_W = sw.perb[fsgrids::bfield::PERBY];
930 const Real perBy_E = se.perb[fsgrids::bfield::PERBY];
931 const Real perBx_N = nw.perb[fsgrids::bfield::PERBX];
934
943 creal dperBxdy_S = sw.dperb[fsgrids::dperb::dPERBxdy];
944 creal dperBxdy_N = nw.dperb[fsgrids::dperb::dPERBxdy];
945 creal dperBydx_W = sw.dperb[fsgrids::dperb::dPERBydx];
946 creal dperBydx_E = se.dperb[fsgrids::dperb::dPERBydx];
947
948 // Ez and characteristic speeds on SW cell:
949 // 1st order terms:
950 Real Ez_SW = Bx_S * Vy0 - By_W * Vx0;
951
952#ifndef FS_1ST_ORDER_SPACE
953 // 2nd order terms:
954 Ez_SW += +HALF * ((Bx_S - HALF * dBxdy_S) * (-sw.dmoments[fsgrids::dmoments::dVydx] - sw.dmoments[fsgrids::dmoments::dVydy]) - dBxdy_S * Vy0 + SIXTH * dBxdz_S * sw.dmoments[fsgrids::dmoments::dVydz]);
955 Ez_SW += -HALF * ((By_W - HALF * dBydx_W) * (-sw.dmoments[fsgrids::dmoments::dVxdx] - sw.dmoments[fsgrids::dmoments::dVxdy]) - dBydx_W * Vx0 + SIXTH * dBydz_W * sw.dmoments[fsgrids::dmoments::dVxdz]);
956#endif
957
958 size_t self = stencil.ooo();
959 size_t nbr = stencil.oop();
960 auto wavespeeds = calculateWaveSpeedXY(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_S,
961 By_W, dBxdy_S, dBxdz_S, dBydx_W, dBydz_W, MINUS, MINUS);
962 c_x = wavespeeds.minVelocity();
963 c_y = c_x;
964 ax_neg = max(ZERO, -Vx0 + c_x);
965 ax_pos = max(ZERO, +Vx0 + c_x);
966 ay_neg = max(ZERO, -Vy0 + c_y);
967 ay_pos = max(ZERO, +Vy0 + c_y);
968 maxV = max(maxV, wavespeeds.cflSpeed(Vx0, Vy0));
969
970 // Ez and characteristic speeds on SE cell:
973
974 // 1st order terms:
975 Real Ez_SE = Bx_S * Vy0 - By_E * Vx0;
976
977#ifndef FS_1ST_ORDER_SPACE
978 // 2nd order terms:
979 Ez_SE += +HALF * ((Bx_S - HALF * dBxdy_S) * (+se.dmoments[fsgrids::dmoments::dVydx] - se.dmoments[fsgrids::dmoments::dVydy]) - dBxdy_S * Vy0 + SIXTH * dBxdz_S * se.dmoments[fsgrids::dmoments::dVydz]);
980 Ez_SE += -HALF * ((By_E + HALF * dBydx_E) * (+se.dmoments[fsgrids::dmoments::dVxdx] - se.dmoments[fsgrids::dmoments::dVxdy]) + dBydx_E * Vx0 + SIXTH * dBydz_E * se.dmoments[fsgrids::dmoments::dVxdz]);
981#endif
982
983 self = stencil.moo();
984 nbr = stencil.mop();
985 wavespeeds = calculateWaveSpeedXY(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_S,
986 By_E, dBxdy_S, dBxdz_S, dBydx_E, dBydz_E, PLUS, MINUS);
987 c_x = wavespeeds.minVelocity();
988 c_y = c_x;
989 ax_neg = max(ax_neg, -Vx0 + c_x);
990 ax_pos = max(ax_pos, +Vx0 + c_x);
991 ay_neg = max(ay_neg, -Vy0 + c_y);
992 ay_pos = max(ay_pos, +Vy0 + c_y);
993 maxV = max(maxV, wavespeeds.cflSpeed(Vx0, Vy0));
994
995 // Ez and characteristic speeds on NW cell:
998
999 // 1st order terms:
1000 Real Ez_NW = Bx_N * Vy0 - By_W * Vx0;
1001
1002#ifndef FS_1ST_ORDER_SPACE
1003 // 2nd order terms:
1004 Ez_NW += +HALF * ((Bx_N + HALF * dBxdy_N) * (-nw.dmoments[fsgrids::dmoments::dVydx] + nw.dmoments[fsgrids::dmoments::dVydy]) + dBxdy_N * Vy0 + SIXTH * dBxdz_N * nw.dmoments[fsgrids::dmoments::dVydz]);
1005 Ez_NW += -HALF * ((By_W - HALF * dBydx_W) * (-nw.dmoments[fsgrids::dmoments::dVxdx] + nw.dmoments[fsgrids::dmoments::dVxdy]) - dBydx_W * Vx0 + SIXTH * dBydz_W * nw.dmoments[fsgrids::dmoments::dVxdz]);
1006#endif
1007
1008 self = stencil.omo();
1009 nbr = stencil.omp();
1010 wavespeeds = calculateWaveSpeedXY(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_N,
1011 By_W, dBxdy_N, dBxdz_N, dBydx_W, dBydz_W, MINUS, PLUS);
1012 c_x = wavespeeds.minVelocity();
1013 c_y = c_x;
1014 ax_neg = max(ax_neg, -Vx0 + c_x);
1015 ax_pos = max(ax_pos, +Vx0 + c_x);
1016 ay_neg = max(ay_neg, -Vy0 + c_y);
1017 ay_pos = max(ay_pos, +Vy0 + c_y);
1018 maxV = max(maxV, wavespeeds.cflSpeed(Vx0, Vy0));
1019
1020 // Ez and characteristic speeds on NE cell:
1021 Vx0 = ne.moments[fsgrids::moments::VX];
1022 Vy0 = ne.moments[fsgrids::moments::VY];
1023
1024 // 1st order terms:
1025 Real Ez_NE = Bx_N * Vy0 - By_E * Vx0;
1026
1027#ifndef FS_1ST_ORDER_SPACE
1028 // 2nd order terms:
1029 Ez_NE += +HALF * ((Bx_N + HALF * dBxdy_N) * (+ne.dmoments[fsgrids::dmoments::dVydx] + ne.dmoments[fsgrids::dmoments::dVydy]) + dBxdy_N * Vy0 + SIXTH * dBxdz_N * ne.dmoments[fsgrids::dmoments::dVydz]);
1030 Ez_NE += -HALF * ((By_E + HALF * dBydx_E) * (+ne.dmoments[fsgrids::dmoments::dVxdx] + ne.dmoments[fsgrids::dmoments::dVxdy]) + dBydx_E * Vx0 + SIXTH * dBydz_E * ne.dmoments[fsgrids::dmoments::dVxdz]);
1031#endif
1032
1033 self = stencil.mmo();
1034 nbr = stencil.mmp();
1035 wavespeeds = calculateWaveSpeedXY(perb, moments, dperb, dmoments, bgb, gridSpacing, rhomLimits, self, nbr, Bx_N,
1036 By_E, dBxdy_N, dBxdz_N, dBydx_E, dBydz_E, PLUS, PLUS);
1037 c_x = wavespeeds.minVelocity();
1038 c_y = c_x;
1039 ax_neg = max(ax_neg, -Vx0 + c_x);
1040 ax_pos = max(ax_pos, +Vx0 + c_x);
1041 ay_neg = max(ay_neg, -Vy0 + c_y);
1042 ay_pos = max(ay_pos, +Vy0 + c_y);
1043 maxV = max(maxV, wavespeeds.cflSpeed(Vx0, Vy0));
1044
1045 // Resistive terms
1046 if (Parameters::resistivity > 0) {
1047 const std::array indices = {static_cast<size_t>(fsgrids::dperb::dPERBydx),
1048 static_cast<size_t>(fsgrids::dperb::dPERBxdy)};
1049 const std::array spacing = {gridSpacing[0], gridSpacing[1]};
1050
1051 Ez_SW += resistiveTerm(sw.bgb, sw.perb, sw.dperb, sw.moments[fsgrids::moments::RHOQ], indices, spacing);
1052 Ez_SE += resistiveTerm(se.bgb, se.perb, se.dperb, se.moments[fsgrids::moments::RHOQ], indices, spacing);
1053 Ez_NW += resistiveTerm(nw.bgb, nw.perb, nw.dperb, nw.moments[fsgrids::moments::RHOQ], indices, spacing);
1054 Ez_NE += resistiveTerm(ne.bgb, ne.perb, ne.dperb, ne.moments[fsgrids::moments::RHOQ], indices, spacing);
1055 }
1056
1057 // Hall terms
1058 if (Parameters::ohmHallTerm > 0) {
1059 Ez_SW += ehall[ci.sw][fsgrids::ehall::EZHALL_000_001];
1060 Ez_SE += ehall[ci.se][fsgrids::ehall::EZHALL_100_101];
1061 Ez_NW += ehall[ci.nw][fsgrids::ehall::EZHALL_010_011];
1062 Ez_NE += ehall[ci.ne][fsgrids::ehall::EZHALL_110_111];
1063 }
1064
1065 // Electron pressure gradient terms
1066 if (Parameters::ohmGradPeTerm > 0) {
1067 Ez_SW += egradpe[ci.sw][fsgrids::egradpe::EZGRADPE];
1068 Ez_SE += egradpe[ci.se][fsgrids::egradpe::EZGRADPE];
1069 Ez_NW += egradpe[ci.nw][fsgrids::egradpe::EZGRADPE];
1070 Ez_NE += egradpe[ci.ne][fsgrids::egradpe::EZGRADPE];
1071 }
1072
1073 // Calculate properly upwinded edge-averaged Ez:
1074 const UpwindField f(Ez_NE, Ez_SE, Ez_NW, Ez_SW, ax_pos, ax_neg, ay_pos, ay_neg, perBx_S, perBx_N, perBy_W, perBy_E,
1075 dperBxdy_S, dperBxdy_N, dperBydx_W, dperBydx_E);
1076 e[ci.sw][fsgrids::efield::EZ] = f();
1077
1078 if ((RKCase == RK_ORDER1) || (RKCase == RK_ORDER2_STEP2)) {
1079 // compute maximum timestep for fieldsolver in this cell (CFL=1)
1080 Real min_dx = std::numeric_limits<Real>::max();
1081 min_dx = min(min_dx, gridSpacing[0]);
1082 min_dx = min(min_dx, gridSpacing[1]);
1083 // update max allowed timestep for field propagation in this cell, which is the minimum of CFL=1 timesteps
1084 if (maxV != ZERO) {
1085 auto& maxFsDt = technical[stencil.ooo()].maxFsDt;
1086 maxFsDt = min(maxFsDt, min_dx / maxV);
1087 }
1088 }
1089}
1090
1120 fsgrids::technicalspan technical, const fsgrid::FsStencil& stencil,
1121 const std::array<Real, 3>& gridSpacing, SysBoundary& sysBoundaries, int32_t RKCase) {
1122 cuint cellSysBoundaryFlag = technical[stencil.ooo()].sysBoundaryFlag;
1123 cuint bitfield = technical[stencil.ooo()].SOLVE;
1124
1125 if (cellSysBoundaryFlag == sysboundarytype::DO_NOT_COMPUTE ||
1126 cellSysBoundaryFlag == sysboundarytype::OUTER_BOUNDARY_PADDING) {
1127 return;
1128 }
1129
1130 if ((bitfield & compute::EX) == compute::EX) {
1131 calculateEdgeElectricFieldX(perb, dperb, e, ehall, egradpe, moments, dmoments, bgb, technical, stencil, RKCase,
1132 gridSpacing);
1133 } else {
1134 sysBoundaries.getSysBoundary(cellSysBoundaryFlag)->fieldSolverBoundaryCondElectricField(e, stencil, 0);
1135 }
1136
1137 if ((bitfield & compute::EY) == compute::EY) {
1138 calculateEdgeElectricFieldY(perb, dperb, e, ehall, egradpe, moments, dmoments, bgb, technical, stencil, RKCase,
1139 gridSpacing);
1140 } else {
1141 sysBoundaries.getSysBoundary(cellSysBoundaryFlag)->fieldSolverBoundaryCondElectricField(e, stencil, 1);
1142 }
1143
1144 if ((bitfield & compute::EZ) == compute::EZ) {
1145 calculateEdgeElectricFieldZ(perb, dperb, e, ehall, egradpe, moments, dmoments, bgb, technical, stencil, RKCase,
1146 gridSpacing);
1147 } else {
1148 sysBoundaries.getSysBoundary(cellSysBoundaryFlag)->fieldSolverBoundaryCondElectricField(e, stencil, 2);
1149 }
1150}
1151
1178 fsgrids::perbspan perbdt2,
1181 fsgrids::ehallspan ehall,
1182 fsgrids::egradpespan egradpe,
1183 fsgrids::egradpespan egradpedt2,
1184 fsgrids::momentsspan moments,
1185 fsgrids::momentsspan momentsdt2,
1186 fsgrids::dperbspan dperb,
1187 fsgrids::dmomentsspan dmoments,
1188 fsgrids::dmomentsspan dmomentsdt2,
1189 fsgrids::bgbspan bgb,
1191 SysBoundary& sysBoundaries, int32_t RKCase,
1192 const bool communicateEGradPeOrMomentsDerivatives) {
1193 const size_t numCells = fsgrid.getNumCells();
1194
1195 if (not(RKCase == RK_ORDER1 || RKCase == RK_ORDER2_STEP2)) {
1196 perb = perbdt2;
1197 e = edt2;
1198 egradpe = egradpedt2;
1199 moments = momentsdt2;
1200 dmoments = dmomentsdt2;
1201 }
1202
1203 phiprof::Timer upwindedETimer{"Calculate upwinded electric field"};
1204
1205 phiprof::Timer mpiTimer{"Electric field ghost updates MPI", {"MPI"}};
1206
1207 // Update ghosts if necessary, unless previous terms have already updated them
1208 if (P::ohmHallTerm > 0) {
1209 fsgrid.updateGhostCells(ehall);
1210 }
1211
1212 if (P::ohmGradPeTerm > 0 && communicateEGradPeOrMomentsDerivatives) {
1213 fsgrid.updateGhostCells(egradpe);
1214 }
1215
1216 if (P::ohmHallTerm == 0) {
1217 fsgrid.updateGhostCells(dperb);
1218 }
1219
1220 if (P::ohmHallTerm == 0 && P::ohmGradPeTerm == 0 && communicateEGradPeOrMomentsDerivatives) {
1221 fsgrid.updateGhostCells(dmoments);
1222 }
1223
1224 mpiTimer.stop();
1225 // Calculate upwinded electric field
1226 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
1227 phiprof::initializeTimer("Electric field compute cells"), technical,
1228 [=, &sysBoundaries](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
1229 calculateElectricField(perb, dperb, e, ehall, egradpe, moments, dmoments, bgb, technical, stencil,
1230 coordinates.physicalGridSpacing, sysBoundaries, RKCase);
1231 });
1232
1233 mpiTimer.start();
1234 // Exchange electric field with neighbouring processes
1235 fsgrid.updateGhostCells(e);
1236 mpiTimer.stop();
1237
1238 upwindedETimer.stop(numCells, "Spatial Cells");
1239}
Binary file
Definition Dispersion.m:11
for i
Definition Dispersion.m:24
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
virtual void fieldSolverBoundaryCondElectricField(fsgrids::efieldspan e, const fsgrid::FsStencil &stencil, cuint component)=0
SysBoundary contains the SysBoundaryConditions used in the simulation.
Definition sysboundary.h:54
SBC::SysBoundaryCondition * getSysBoundary(cuint sysBoundaryType) const
@ RK_ORDER1
Definition common.h:508
@ RK_ORDER2_STEP2
Definition common.h:510
const uint32_t cuint
Definition definitions.h:50
float Real
Definition definitions.h:41
fsgrid::FsGrid< FS_STENCIL_WIDTH > FieldSolverGrid
Definition definitions.h:78
const float creal
Definition definitions.h:42
static const Real CHARGE
Real divideIfNonZero(creal numerator, creal denominator)
Helper function.
Definition fs_common.cpp:33
static creal EPS
Definition fs_common.h:61
const Real TWELWTH
Definition fs_common.h:57
const Real MINUS
Definition fs_common.h:50
const Real HALF
Definition fs_common.h:49
const Real PLUS
Definition fs_common.h:51
const Real ZERO
Definition fs_common.h:59
const Real SIXTH
Definition fs_common.h:54
const int j
const int k
void calculateEdgeElectricFieldZ(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::efieldspan e, fsgrids::constehallspan ehall, fsgrids::constegradpespan egradpe, fsgrids::constmomentsspan moments, fsgrids::constdmomentsspan dmoments, fsgrids::constbgbspan bgb, fsgrids::technicalspan technical, const fsgrid::FsStencil &stencil, int32_t RKCase, const std::array< Real, 3 > &gridSpacing)
Low-level electric field propagation function.
Limits getRhomLimits(const std::array< std::array< Real, fsgrids::moments::N_MOMENTS >, 4 > &moments)
Wavespeeds calculateWaveSpeedXY(fsgrids::perbspan perB, fsgrids::constmomentsspan moments, fsgrids::constdperbspan dPerB, fsgrids::constdmomentsspan dMoments, fsgrids::constbgbspan BgB, const std::array< Real, 3 > &gridSpacing, const Limits &rhomLimits, size_t self, size_t nbr, Real Bx, Real By, Real dBxdy, Real dBxdz, Real dBydx, Real dBydz, Real xdir, Real ydir)
Low-level helper function.
void calculateEdgeElectricFieldX(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::efieldspan e, fsgrids::constehallspan ehall, fsgrids::constegradpespan egradpe, fsgrids::constmomentsspan moments, fsgrids::constdmomentsspan dmoments, fsgrids::constbgbspan bgb, fsgrids::technicalspan technical, const fsgrid::FsStencil &stencil, int32_t RKCase, const std::array< Real, 3 > &gridSpacing)
Low-level electric field propagation function.
Real resistiveTerm(const auto &bgb, const auto &perb, const auto &dperb, Real rhoq, std::array< size_t, 2 > indices, std::array< Real, 2 > spacing)
void calculateUpwindedElectricFieldSimple(fsgrids::perbspan perb, fsgrids::perbspan perbdt2, fsgrids::efieldspan e, fsgrids::efieldspan edt2, fsgrids::ehallspan ehall, fsgrids::egradpespan egradpe, fsgrids::egradpespan egradpedt2, fsgrids::momentsspan moments, fsgrids::momentsspan momentsdt2, fsgrids::dperbspan dperb, fsgrids::dmomentsspan dmoments, fsgrids::dmomentsspan dmomentsdt2, fsgrids::bgbspan bgb, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, SysBoundary &sysBoundaries, int32_t RKCase, const bool communicateEGradPeOrMomentsDerivatives)
High-level electric field computation function.
Wavespeeds calculateWaveSpeedYZ(fsgrids::perbspan perB, fsgrids::constmomentsspan moments, fsgrids::constdperbspan dPerB, fsgrids::constdmomentsspan dMoments, fsgrids::constbgbspan BgB, const std::array< Real, 3 > &gridSpacing, const Limits &rhomLimits, size_t self, size_t nbr, Real By, Real Bz, Real dBydx, Real dBydz, Real dBzdx, Real dBzdy, Real ydir, Real zdir)
Low-level helper function.
Wavespeeds calculateWaveSpeedXZ(fsgrids::perbspan perB, fsgrids::constmomentsspan moments, fsgrids::constdperbspan dPerB, fsgrids::constdmomentsspan dMoments, fsgrids::constbgbspan BgB, const std::array< Real, 3 > &gridSpacing, const Limits &rhomLimits, size_t self, size_t nbr, Real Bx, Real Bz, Real dBxdy, Real dBxdz, Real dBzdx, Real dBzdy, Real xdir, Real zdir)
Low-level helper function.
void calculateElectricField(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::efieldspan e, fsgrids::constehallspan ehall, fsgrids::constegradpespan egradpe, fsgrids::constmomentsspan moments, fsgrids::constdmomentsspan dmoments, fsgrids::constbgbspan bgb, fsgrids::technicalspan technical, const fsgrid::FsStencil &stencil, const std::array< Real, 3 > &gridSpacing, SysBoundary &sysBoundaries, int32_t RKCase)
Electric field propagation function.
void calculateEdgeElectricFieldY(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::efieldspan e, fsgrids::constehallspan ehall, fsgrids::constegradpespan egradpe, fsgrids::constmomentsspan moments, fsgrids::constdmomentsspan dmoments, fsgrids::constbgbspan bgb, fsgrids::technicalspan technical, const fsgrid::FsStencil &stencil, int32_t RKCase, const std::array< Real, 3 > &gridSpacing)
Low-level electric field propagation function.
void fsdebugCheck(const fsgrid::FsStencil &stencil, size_t len, const char *file, uint32_t line)
#define index(i, j, k)
const uint EZ
Definition common.h:504
const uint EY
Definition common.h:503
const uint EX
Definition common.h:502
@ BGBY
Definition common.h:376
@ dBGBxdz
Definition common.h:385
@ dBGBydx
Definition common.h:386
@ BGBZ
Definition common.h:377
@ dBGBydz
Definition common.h:387
@ BGBX
Definition common.h:375
@ dBGBzdx
Definition common.h:388
@ dBGBxdy
Definition common.h:384
@ dBGBzdy
Definition common.h:389
std::span< std::array< Real, fsgrids::bfield::N_BFIELD > > perbspan
Definition common.h:434
std::span< const std::array< Real, fsgrids::dmoments::N_DMOMENTS > > constdmomentsspan
Definition common.h:449
@ EZGRADPE
Definition common.h:307
@ EYGRADPE
Definition common.h:306
@ EXGRADPE
Definition common.h:305
std::span< const std::array< Real, bgbfield::N_BGB > > constbgbspan
Definition common.h:445
std::span< const std::array< Real, fsgrids::moments::N_MOMENTS > > constmomentsspan
Definition common.h:447
std::span< std::array< Real, fsgrids::moments::N_MOMENTS > > momentsspan
Definition common.h:446
std::span< std::array< Real, fsgrids::egradpe::N_EGRADPE > > egradpespan
Definition common.h:440
std::span< std::array< Real, fsgrids::dmoments::N_DMOMENTS > > dmomentsspan
Definition common.h:448
@ P_22
Definition common.h:318
@ P_33
Definition common.h:319
@ RHOM
Definition common.h:312
@ P_11
Definition common.h:317
@ RHOQ
Definition common.h:313
std::span< technical > technicalspan
Definition common.h:452
std::span< const std::array< Real, fsgrids::ehall::N_EHALL > > constehallspan
Definition common.h:439
@ EZHALL_010_011
Definition common.h:295
@ EYHALL_101_111
Definition common.h:299
@ EYHALL_100_110
Definition common.h:292
@ EXHALL_010_110
Definition common.h:294
@ EZHALL_110_111
Definition common.h:296
@ EZHALL_000_001
Definition common.h:291
@ EYHALL_001_011
Definition common.h:298
@ EXHALL_001_101
Definition common.h:297
@ EYHALL_000_010
Definition common.h:290
@ EXHALL_000_100
Definition common.h:289
@ EXHALL_011_111
Definition common.h:300
@ EZHALL_100_101
Definition common.h:293
std::span< std::array< Real, bgbfield::N_BGB > > bgbspan
Definition common.h:444
std::span< std::array< Real, fsgrids::dperb::N_DPERB > > dperbspan
Definition common.h:442
@ dVydz
Definition common.h:363
@ dp11dz
Definition common.h:351
@ dVydx
Definition common.h:361
@ dp22dy
Definition common.h:353
@ drhomdy
Definition common.h:344
@ dp33dy
Definition common.h:356
@ dVzdz
Definition common.h:366
@ dVzdx
Definition common.h:364
@ dp11dy
Definition common.h:350
@ dp22dx
Definition common.h:352
@ dVxdy
Definition common.h:359
@ dp22dz
Definition common.h:354
@ dp11dx
Definition common.h:349
@ drhomdz
Definition common.h:345
@ dp33dz
Definition common.h:357
@ dp33dx
Definition common.h:355
@ dVxdz
Definition common.h:360
@ drhomdx
Definition common.h:343
@ dVzdy
Definition common.h:365
@ dVydy
Definition common.h:362
@ dVxdx
Definition common.h:358
std::span< std::array< Real, fsgrids::efield::N_EFIELD > > efieldspan
Definition common.h:436
@ PERBY
Definition common.h:276
@ PERBZ
Definition common.h:277
@ PERBX
Definition common.h:275
std::span< const std::array< Real, fsgrids::egradpe::N_EGRADPE > > constegradpespan
Definition common.h:441
std::span< std::array< Real, fsgrids::ehall::N_EHALL > > ehallspan
Definition common.h:438
@ dPERBzdy
Definition common.h:329
@ dPERBydx
Definition common.h:326
@ dPERBzdx
Definition common.h:328
@ dPERBxdy
Definition common.h:324
@ dPERBxdz
Definition common.h:325
@ dPERBydz
Definition common.h:327
std::span< const std::array< Real, fsgrids::dperb::N_DPERB > > constdperbspan
Definition common.h:443
const Real MU_0
Definition common.h:570
@ OUTER_BOUNDARY_PADDING
Definition common.h:493
static const Real MASS_PROTON
const std::array< Real, fsgrids::bfield::N_BFIELD > & perb
DataArrays(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::constmomentsspan moments, fsgrids::constdmomentsspan dmoments, fsgrids::constbgbspan bgb, size_t index)
const std::array< Real, fsgrids::bgbfield::N_BGB > & bgb
const std::array< Real, fsgrids::moments::N_MOMENTS > & moments
const std::array< Real, fsgrids::dperb::N_DPERB > & dperb
const std::array< Real, fsgrids::dmoments::N_DMOMENTS > & dmoments
static uint ohmGradPeTerm
Definition parameters.h:144
static bool fieldSolverDiffusiveEterms
Definition parameters.h:153
static uint ohmHallTerm
Definition parameters.h:142
static Real maxWaveVelocity
Definition parameters.h:139
static Real resistivity
Definition parameters.h:141
const std::array< Real, fsgrids::moments::N_MOMENTS > & moment
std::tuple< Real, Real > perBCoeffs(size_t i, size_t j) const
const std::array< Real, fsgrids::bfield::N_BFIELD > & nbr_perb
Real rhom(Real dir0, Real dir1, size_t i, size_t j, size_t k) const
const std::array< Real, fsgrids::dperb::N_DPERB > & dperb
const std::array< Real, fsgrids::bgbfield::N_BGB > & nbr_bgb
const std::array< Real, fsgrids::bgbfield::N_BGB > & bgb
std::tuple< Real, Real > compute(const std::array< Real, N > &nbr_arr, const std::array< Real, N > &arr, size_t i, size_t j, Real mul0, Real mul1) const
std::tuple< Real, Real > dPerBCoeffs(size_t i, size_t j) const
const std::array< Real, fsgrids::bfield::N_BFIELD > & perb
Reconstructions(fsgrids::perbspan perB, fsgrids::constdperbspan dPerB, fsgrids::constbgbspan BgB, fsgrids::constmomentsspan moments, fsgrids::constdmomentsspan dMoments, size_t self, size_t nbr, const Limits &rhomLimits)
const Limits & rhomLimits
Real interpolateAndLimitMoments(Real dir0, Real dir1, size_t i, size_t j, size_t k, Real min, Real max) const
Real p(Real dir0, Real dir1, size_t i, size_t j, size_t k) const
const std::array< Real, fsgrids::dmoments::N_DMOMENTS > & dmoment
static Real squared(Real a, Real b)
const std::array< Real, fsgrids::dperb::N_DPERB > & nbr_dperb
Real operator()() const
Real cflSpeed(Real v0, Real v1) const
Low-level helper function.
Wavespeeds(Real bmag2, Real rhom, Real p11, Real p22, Real p33, const std::array< Real, 3 > &gridSpacing)
Real minVelocity() const
static ARCH_HOSTDEV VecSimple< T > min(VecSimple< T > const &l, VecSimple< T > const &r)
static ARCH_HOSTDEV VecSimple< T > max(VecSimple< T > const &l, VecSimple< T > const &r)