Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
ldz_magnetic_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#ifdef _OPENMP
24 #include <omp.h>
25#endif
26
28
30 fsgrids::perbspan perbdt2,
33 const fsgrid::FsStencil& stencil, Real dt, int32_t RKCase, bool doX, bool doY, bool doZ,
34 const std::array<Real, 3>& gridSpacing) {
35 creal dtdx = dt / gridSpacing[0];
36 creal dtdy = dt / gridSpacing[1];
37 creal dtdz = dt / gridSpacing[2];
38
39 std::array<Real, fsgrids::bfield::N_BFIELD>& perBGrid0 = perb[stencil.ooo()];
40
41 if (doX == true) {
42 switch (RKCase) {
43 case RK_ORDER1: {
44 const auto& EGrid0 = e[stencil.ooo()];
45 const auto& EGrid1 = e[stencil.opo()];
46 const auto& EGrid2 = e[stencil.oop()];
47 perBGrid0[fsgrids::bfield::PERBX] += dtdz * (EGrid2[fsgrids::efield::EY] - EGrid0[fsgrids::efield::EY]) +
48 dtdy * (EGrid0[fsgrids::efield::EZ] - EGrid1[fsgrids::efield::EZ]);
49 break;
50 }
51
52 case RK_ORDER2_STEP1: {
53 auto& perBDt2Grid0 = perbdt2[stencil.ooo()];
54 const auto& EGrid0 = e[stencil.ooo()];
55 const auto& EGrid1 = e[stencil.opo()];
56 const auto& EGrid2 = e[stencil.oop()];
57 perBDt2Grid0[fsgrids::bfield::PERBX] = perBGrid0[fsgrids::bfield::PERBX] +
58 0.5 * (dtdz * (EGrid2[fsgrids::efield::EY] - EGrid0[fsgrids::efield::EY]) +
59 dtdy * (EGrid0[fsgrids::efield::EZ] - EGrid1[fsgrids::efield::EZ]));
60 break;
61 }
62
63 case RK_ORDER2_STEP2: {
64 const auto& EGrid0 = edt2[stencil.ooo()];
65 const auto& EGrid1 = edt2[stencil.opo()];
66 const auto& EGrid2 = edt2[stencil.oop()];
67 perBGrid0[fsgrids::bfield::PERBX] += dtdz * (EGrid2[fsgrids::efield::EY] - EGrid0[fsgrids::efield::EY]) +
68 dtdy * (EGrid0[fsgrids::efield::EZ] - EGrid1[fsgrids::efield::EZ]);
69 break;
70 }
71
72 default:
73 std::cerr << __FILE__ << ":" << __LINE__ << ":" << "Invalid RK case." << std::endl;
74 abort();
75 }
76 }
77
78 if (doY == true) {
79 switch (RKCase) {
80 case RK_ORDER1: {
81 const auto& EGrid0 = e[stencil.ooo()];
82 const auto& EGrid1 = e[stencil.oop()];
83 const auto& EGrid2 = e[stencil.poo()];
84 perBGrid0[fsgrids::bfield::PERBY] += dtdx * (EGrid2[fsgrids::efield::EZ] - EGrid0[fsgrids::efield::EZ]) +
85 dtdz * (EGrid0[fsgrids::efield::EX] - EGrid1[fsgrids::efield::EX]);
86 break;
87 }
88 case RK_ORDER2_STEP1: {
89 auto& perBDt2Grid0 = perbdt2[stencil.ooo()];
90 const auto& EGrid0 = e[stencil.ooo()];
91 const auto& EGrid1 = e[stencil.oop()];
92 const auto& EGrid2 = e[stencil.poo()];
93 perBDt2Grid0[fsgrids::bfield::PERBY] = perBGrid0[fsgrids::bfield::PERBY] +
94 0.5 * (dtdx * (EGrid2[fsgrids::efield::EZ] - EGrid0[fsgrids::efield::EZ]) +
95 dtdz * (EGrid0[fsgrids::efield::EX] - EGrid1[fsgrids::efield::EX]));
96 break;
97 }
98 case RK_ORDER2_STEP2: {
99 const auto& EGrid0 = edt2[stencil.ooo()];
100 const auto& EGrid1 = edt2[stencil.oop()];
101 const auto& EGrid2 = edt2[stencil.poo()];
102 perBGrid0[fsgrids::bfield::PERBY] += dtdx * (EGrid2[fsgrids::efield::EZ] - EGrid0[fsgrids::efield::EZ]) +
103 dtdz * (EGrid0[fsgrids::efield::EX] - EGrid1[fsgrids::efield::EX]);
104 break;
105 }
106 default:
107 std::cerr << __FILE__ << ":" << __LINE__ << ":" << "Invalid RK case." << std::endl;
108 abort();
109 }
110 }
111
112 if (doZ == true) {
113 switch (RKCase) {
114 case RK_ORDER1: {
115 const auto& EGrid0 = e[stencil.ooo()];
116 const auto& EGrid1 = e[stencil.poo()];
117 const auto& EGrid2 = e[stencil.opo()];
118 perBGrid0[fsgrids::bfield::PERBZ] += dtdy * (EGrid2[fsgrids::efield::EX] - EGrid0[fsgrids::efield::EX]) +
119 dtdx * (EGrid0[fsgrids::efield::EY] - EGrid1[fsgrids::efield::EY]);
120 break;
121 }
122 case RK_ORDER2_STEP1: {
123 auto& perBDt2Grid0 = perbdt2[stencil.ooo()];
124 const auto& EGrid0 = e[stencil.ooo()];
125 const auto& EGrid1 = e[stencil.poo()];
126 const auto& EGrid2 = e[stencil.opo()];
127 perBDt2Grid0[fsgrids::bfield::PERBZ] = perBGrid0[fsgrids::bfield::PERBZ] +
128 0.5 * (dtdy * (EGrid2[fsgrids::efield::EX] - EGrid0[fsgrids::efield::EX]) +
129 dtdx * (EGrid0[fsgrids::efield::EY] - EGrid1[fsgrids::efield::EY]));
130 break;
131 }
132 case RK_ORDER2_STEP2: {
133 const auto& EGrid0 = edt2[stencil.ooo()];
134 const auto& EGrid1 = edt2[stencil.poo()];
135 const auto& EGrid2 = edt2[stencil.opo()];
136 perBGrid0[fsgrids::bfield::PERBZ] += dtdy * (EGrid2[fsgrids::efield::EX] - EGrid0[fsgrids::efield::EX]) +
137 dtdx * (EGrid0[fsgrids::efield::EY] - EGrid1[fsgrids::efield::EY]);
138 break;
139 }
140 default:
141 std::cerr << __FILE__ << ":" << __LINE__ << ":" << "Invalid RK case." << std::endl;
142 abort();
143 }
144 }
145}
146
165 fsgrids::perbspan perbdt2,
168 const std::array<Real, 3>& gridSpacing,
169 const std::array<fsgrid::FsSize_t, 3>& globalCoordinates,
170 const fsgrid::FsStencil& stencil, SysBoundary& sysBoundaries, int32_t RKCase,
171 uint32_t component) {
172 const bool case0 = RKCase == RK_ORDER1 || RKCase == RK_ORDER2_STEP2;
173 auto& out = case0 ? perb[stencil.ooo()] : perbdt2[stencil.ooo()];
174 const auto& pb = case0 ? perb : perbdt2;
175
176 out[fsgrids::bfield::PERBX + component] =
177 sysBoundaries.getSysBoundary(technical[stencil.ooo()].sysBoundaryFlag)
178 ->fieldSolverBoundaryCondMagneticField(pb, bgb, technical, gridSpacing, globalCoordinates, stencil,
179 component);
180}
181
200 fsgrids::perbspan perbdt2,
205 SysBoundary& sysBoundaries, creal& dt, cint& RKCase) {
206 phiprof::Timer propagateBTimer{"Propagate magnetic field"};
207 const auto* localSize = &fsgrid.getLocalSize()[0];
208 const auto& gridSpacing = fsgrid.getGridSpacing();
209 const size_t numCells = fsgrid.getNumCells();
210
211 int sysBoundaryTimerId{phiprof::initializeTimer("Magnetic Field compute sysboundary cells")};
212 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
213 phiprof::initializeTimer("Magnetic Field compute cells"), technical,
214 [=](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
215 cuint bitfield = technical[stencil.ooo()].SOLVE;
217 perb, perbdt2, e, edt2, stencil, dt, RKCase, ((bitfield & compute::BX) == compute::BX),
218 ((bitfield & compute::BY) == compute::BY), ((bitfield & compute::BZ) == compute::BZ), coordinates.physicalGridSpacing);
219 });
220
221 // This communication is needed for boundary conditions, in practice almost all
222 // of the communication is going to be redone in calculateDerivativesSimple
223 // TODO: do not transfer if there are no field boundaryconditions
224 phiprof::Timer mpiTimer{"MPI", {"MPI"}};
225 if (RKCase == RK_ORDER1 || RKCase == RK_ORDER2_STEP2) {
226 // Exchange PERBX,PERBY,PERBZ with neighbours
227 fsgrid.updateGhostCells(perb);
228 } else { // RKCase == RK_ORDER2_STEP1
229 // Exchange PERBX_DT2,PERBY_DT2,PERBZ_DT2 with neighbours
230 fsgrid.updateGhostCells(perbdt2);
231 }
232 mpiTimer.stop();
233
234 // The looping below was modified in https://github.com/fmihpc/vlasiator/pull/1110/files
235 // with a reported performance gain of 10% of field solver performance in production-like
236 // conditions. Unfortunately as of https://github.com/fmihpc/vlasiator/pull/1099 (fsgrid
237 // parallel_for mechanism) this split would become very cumbersome and is therefore
238 // reversed until more optimisation is needed on CPU or GPU.
239
240 // Propagate B on system boundary/process inner cells
241 phiprof::Timer sysBoundaryTimer {sysBoundaryTimerId};
242
243 // L1 pass
244 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
245 phiprof::initializeTimer("Magnetic field L1 pass"), technical,
246 [=, &sysBoundaries](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
247 if (sysBoundaryLayer == 1) {
248 cuint bitfield = technical[stencil.ooo()].SOLVE;
249 const auto globalCoordinates = coordinates.localToGlobal(stencil.i, stencil.j, stencil.k);
250 if ((bitfield & compute::BX) != compute::BX) {
251 propagateSysBoundaryMagneticField(perb, perbdt2, bgb, technical, gridSpacing, globalCoordinates, stencil, sysBoundaries, RKCase, 0);
252 }
253 if ((bitfield & compute::BY) != compute::BY) {
254 propagateSysBoundaryMagneticField(perb, perbdt2, bgb, technical, gridSpacing, globalCoordinates, stencil, sysBoundaries, RKCase, 1);
255 }
256 if ((bitfield & compute::BZ) != compute::BZ) {
257 propagateSysBoundaryMagneticField(perb, perbdt2, bgb, technical, gridSpacing, globalCoordinates, stencil, sysBoundaries, RKCase, 2);
258 }
259 }
260 });
261 sysBoundaryTimer.stop();
262
263 mpiTimer.start();
264 if (RKCase == RK_ORDER1 || RKCase == RK_ORDER2_STEP2) {
265 // Exchange PERBX,PERBY,PERBZ with neighbours
266 fsgrid.updateGhostCells(perb);
267 } else { // RKCase == RK_ORDER2_STEP1
268 // Exchange PERBX_DT2,PERBY_DT2,PERBZ_DT2 with neighbours
269 fsgrid.updateGhostCells(perbdt2);
270 }
271 mpiTimer.stop();
272
273 sysBoundaryTimer.start();
274 // L2 pass
275 fsgrid.parallel_for([](int timerId) -> phiprof::Timer { return phiprof::Timer{timerId}; },
276 phiprof::initializeTimer("Magnetic field L2 pass"), technical,
277 [=, &sysBoundaries](const fsgrid::Coordinates &coordinates, const fsgrid::FsStencil& stencil, cuint sysBoundaryFlag, cuint sysBoundaryLayer) {
278 if(sysBoundaryFlag != sysboundarytype::NOT_SYSBOUNDARY &&
279 sysBoundaryLayer == 2
280 ) {
281 cuint bitfield = technical[stencil.ooo()].SOLVE;
282 const auto globalCoordinates = coordinates.localToGlobal(stencil.i, stencil.j, stencil.k);
283 if ((bitfield & compute::BX) != compute::BX) {
284 propagateSysBoundaryMagneticField(perb, perbdt2, bgb, technical, gridSpacing, globalCoordinates, stencil, sysBoundaries, RKCase, 0);
285 }
286 if ((bitfield & compute::BY) != compute::BY) {
287 propagateSysBoundaryMagneticField(perb, perbdt2, bgb, technical, gridSpacing, globalCoordinates, stencil, sysBoundaries, RKCase, 1);
288 }
289 if ((bitfield & compute::BZ) != compute::BZ) {
290 propagateSysBoundaryMagneticField(perb, perbdt2, bgb, technical, gridSpacing, globalCoordinates, stencil, sysBoundaries, RKCase, 2);
291 }
292 }
293 });
294 sysBoundaryTimer.stop();
295 propagateBTimer.stop(numCells, "Spatial Cells");
296}
dt
Definition Dispersion.m:39
virtual Real fieldSolverBoundaryCondMagneticField(fsgrids::perbspan b, fsgrids::constbgbspan bgb, fsgrids::consttechnicalspan technical, const std::array< Real, 3 > &gridSpacing, const std::array< fsgrid::FsSize_t, 3 > &globalCoordinates, 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_ORDER2_STEP1
Definition common.h:509
@ 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
const int cint
Definition definitions.h:45
fsgrid::FsGrid< FS_STENCIL_WIDTH > FieldSolverGrid
Definition definitions.h:78
const float creal
Definition definitions.h:42
void propagateMagneticFieldSimple(fsgrids::perbspan perb, fsgrids::perbspan perbdt2, fsgrids::bgbspan bgb, fsgrids::efieldspan e, fsgrids::efieldspan edt2, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, SysBoundary &sysBoundaries, creal &dt, cint &RKCase)
High-level magnetic field propagation function.
void propagateMagneticField(fsgrids::perbspan perb, fsgrids::perbspan perbdt2, fsgrids::constefieldspan e, fsgrids::constefieldspan edt2, const fsgrid::FsStencil &stencil, Real dt, int32_t RKCase, bool doX, bool doY, bool doZ, const std::array< Real, 3 > &gridSpacing)
void propagateSysBoundaryMagneticField(fsgrids::perbspan perb, fsgrids::perbspan perbdt2, fsgrids::constbgbspan bgb, fsgrids::consttechnicalspan technical, const std::array< Real, 3 > &gridSpacing, const std::array< fsgrid::FsSize_t, 3 > &globalCoordinates, const fsgrid::FsStencil &stencil, SysBoundary &sysBoundaries, int32_t RKCase, uint32_t component)
Low-level magnetic field propagation function.
const uint BZ
Definition common.h:501
const uint BX
Definition common.h:499
const uint BY
Definition common.h:500
std::span< std::array< Real, fsgrids::bfield::N_BFIELD > > perbspan
Definition common.h:434
std::span< const std::array< Real, bgbfield::N_BGB > > constbgbspan
Definition common.h:445
std::span< const std::array< Real, fsgrids::efield::N_EFIELD > > constefieldspan
Definition common.h:437
std::span< technical > technicalspan
Definition common.h:452
std::span< std::array< Real, bgbfield::N_BGB > > bgbspan
Definition common.h:444
std::span< const technical > consttechnicalspan
Definition common.h:453
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