42 return grid.physicalToGlobal(x[0], x[1], x[2]);
49 std::array<fsgrid::FsIndex_t, 3> retval = grid.globalToLocal(globalInd[0], globalInd[1], globalInd[2]);
57 const std::array<fsgrid::FsIndex_t, 3> localStart = grid.getLocalStart();
58 std::array<fsgrid::FsIndex_t, 3> retval = {(fsgrid::FsIndex_t)globalInd[0] - localStart[0],
59 (fsgrid::FsIndex_t)globalInd[1] - localStart[1],
60 (fsgrid::FsIndex_t)globalInd[2] - localStart[2]};
66 return grid.physicalToCellFractional(x[0], x[1], x[2]);
148inline int ijk2Index(
int i,
int j,
int k, std::array<int, 3> dims) {
return i +
j * dims[0] +
k * dims[0] * dims[1]; }
151template <
typename REAL>
154template <
typename REAL>
158 const bool alongB, std::array<REAL, 3>& b) {
167 cerr << (string)(
"(fieldtracing) Error: fsgrid coupling trying to step outside of the global domain?\n");
176 std::array<fsgrid::FsSize_t, 3> fsgridCellu =
178 std::array<fsgrid::FsIndex_t, 3> fsgridCell = {(fsgrid::FsIndex_t)fsgridCellu[0], (fsgrid::FsIndex_t)fsgridCellu[1],
179 (fsgrid::FsIndex_t)fsgridCellu[2]};
180 const auto& localStart =
fsgrid.getLocalStart();
181 const auto* localSize = &
fsgrid.getLocalSize()[0];
183 fsgridCell[0] -= localStart[0];
184 fsgridCell[1] -= localStart[1];
185 fsgridCell[2] -= localStart[2];
187 if ( fsgridCell[0] > localSize[0]
188 || fsgridCell[1] > localSize[1]
189 || fsgridCell[2] > localSize[2]
190 || fsgridCell[0] < -1
191 || fsgridCell[1] < -1
192 || fsgridCell[2] < -1
194 cerr << (string)(
"(fieldtracing) Error: fsgrid coupling trying to access local ID " + to_string(fsgridCell[0]) +
" " + to_string(fsgridCell[1]) +
" " + to_string(fsgridCell[2])
195 +
" for local domain size " + to_string(localSize[0]) +
" " + to_string(localSize[1]) +
" " + to_string(localSize[2])
196 +
" at position " + to_string(r[0]) +
" " + to_string(r[1]) +
" " + to_string(r[2]) +
" radius " + to_string(
sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2]))
201 const auto stencil =
fsgrid.makeStencil(fsgridCell[0], fsgridCell[1], fsgridCell[2]);
203 const std::array<Real, 3> perB =
205 fsgridCell[0], fsgridCell[1], fsgridCell[2], {(Real)r[0], (Real)r[1], (Real)r[2]});
213 REAL norm = 1. /
sqrt(b[0]*b[0] + b[1]*b[1] + b[2]*b[2]);
214 for (
int c = 0;
c < 3;
c++) {
219 if (!(std::isfinite(b[0]) && std::isfinite(b[1]) && std::isfinite(b[2]))) {
220 cerr <<
"(fieldtracing) Error: magnetic field is nan or inf in getRadialBfieldDirection at location "
221 << r[0] <<
", " << r[1] <<
", " << r[2] <<
", with B = " << b[0] <<
", " << b[1] <<
", " << b[2] << endl;
243template <
typename REAL>
247 std::array<REAL, 3> bunit, crd, z0, zmid, z1;
249 REAL h = stepSize / (REAL)n;
252 BFieldFunction(r, outwards, bunit);
254 z1 = {r[0] + h * bunit[0], r[1] + h * bunit[1], r[2] + h * bunit[2]};
255 BFieldFunction(z1, outwards, bunit);
257 crd = {r[0] + h * bunit[0], r[1] + h * bunit[1], r[2] + h * bunit[2]};
259 for (
int m = 0; m <= n; m++) {
260 zmid = {z0[0] + 2 * h * bunit[0], z0[1] + 2 * h * bunit[1], z0[2] + 2 * h * bunit[2]};
263 crd = {crd[0] + h * bunit[0], crd[1] + h * bunit[1], crd[2] + h * bunit[2]};
264 BFieldFunction(crd, outwards, bunit);
268 for (
int c = 0;
c < 3;
c++) {
269 r1[
c] = 0.5 * (z0[
c] + z1[
c] + h * bunit[
c]);
274template <
typename REAL>
278 for (
int dim = 0; dim < 3; dim++) {
279 for (
k = 1;
k <
i + 1;
k++) {
284 (std::pow(4,
i) - 1);
289 if (thisError > maxError) {
290 maxError = thisError;
296template <
typename REAL>
297bool bulirschStoerStep(std::array<REAL, 3>& r, std::array<REAL, 3>& b, REAL& stepSize,
const REAL minStepSize,
307 const int ndim = kMax * kMax * 3;
308 std::array<int, 3> dims = {kMax, kMax, 3};
309 std::vector<REAL> table(ndim);
310 std::array<REAL, 3> rold, rnew, r1;
314 BFieldFunction(r, outwards, b);
324 for (
int c = 0;
c < 3; ++
c) {
328 for (
int i = 1;
i < kMax; ++
i) {
335 for (
int c = 0;
c < 3; ++
c) {
346 if (error < 1. || stepSize == minStepSize) {
354 stepSize = stepSize > maxStepSize ? maxStepSize : stepSize;
355 stepSize = stepSize < minStepSize ? minStepSize : stepSize;
359 BFieldFunction(r, outwards, b);
366 stepSize = stepSize < minStepSize ? minStepSize : stepSize;
370template <
typename REAL>
371bool dormandPrinceStep(std::array<REAL, 3>& r, std::array<REAL, 3>& b, REAL& stepSize,
const REAL minStepSize,
375 std::array<REAL, 7> kx, ky, kz;
376 std::array<REAL, 3> b_unit;
377 std::array<REAL, 3> _r{0, 0, 0};
380 proceed = BFieldFunction(r, outwards, b_unit);
381 kx[0] = stepSize * b_unit[0];
382 ky[0] = stepSize * b_unit[1];
383 kz[0] = stepSize * b_unit[2];
386 _r[0] = r[0] + (1. / 5.) * kx[0];
387 _r[1] = r[1] + (1. / 5.) * ky[0];
388 _r[2] = r[2] + (1. / 5.) * kz[0];
390 proceed = BFieldFunction(_r, outwards, b_unit);
392 kx[1] = stepSize * b_unit[0];
393 ky[1] = stepSize * b_unit[1];
394 kz[1] = stepSize * b_unit[2];
397 _r[0] = r[0] + (3. / 10.) * kx[1];
398 _r[1] = r[1] + (3. / 10.) * ky[1];
399 _r[2] = r[2] + (3. / 10.) * kz[1];
401 proceed = BFieldFunction(_r, outwards, b_unit);
403 kx[2] = stepSize * b_unit[0];
404 ky[2] = stepSize * b_unit[1];
405 kz[2] = stepSize * b_unit[2];
408 _r[0] = r[0] + (4. / 5.) * kx[2];
409 _r[1] = r[1] + (4. / 5.) * ky[2];
410 _r[2] = r[2] + (4. / 5.) * kz[2];
412 proceed = BFieldFunction(_r, outwards, b_unit);
414 kx[3] = stepSize * b_unit[0];
415 ky[3] = stepSize * b_unit[1];
416 kz[3] = stepSize * b_unit[2];
419 _r[0] = r[0] + (8. / 9.) * kx[3];
420 _r[1] = r[1] + (8. / 9.) * ky[3];
421 _r[2] = r[2] + (8. / 9.) * kz[3];
423 proceed = BFieldFunction(_r, outwards, b_unit);
425 kx[4] = stepSize * b_unit[0];
426 ky[4] = stepSize * b_unit[1];
427 kz[4] = stepSize * b_unit[2];
430 _r[0] = r[0] + kx[4];
431 _r[1] = r[1] + ky[4];
432 _r[2] = r[2] + kz[4];
434 proceed = BFieldFunction(_r, outwards, b_unit);
436 kx[5] = stepSize * b_unit[0];
437 ky[5] = stepSize * b_unit[1];
438 kz[5] = stepSize * b_unit[2];
441 _r[0] = r[0] + kx[5];
442 _r[1] = r[1] + ky[5];
443 _r[2] = r[2] + kz[5];
445 proceed = BFieldFunction(_r, outwards, b_unit);
447 kx[6] = stepSize * b_unit[0];
448 ky[6] = stepSize * b_unit[1];
449 kz[6] = stepSize * b_unit[2];
452 std::array<REAL, 3> rf;
455 std::array<REAL, 3> error_xyz;
456 rf[0] = r[0] + (35. / 384.) * kx[0] + (500. / 1113.) * kx[2] + (125. / 192.) * kx[3] - (2187. / 6784.) * kx[4] + (11. / 84.) * kx[5];
457 rf[1] = r[1] + (35. / 384.) * ky[0] + (500. / 1113.) * ky[2] + (125. / 192.) * ky[3] - (2187. / 6784.) * ky[4] + (11. / 84.) * ky[5];
458 rf[2] = r[2] + (35. / 384.) * kz[0] + (500. / 1113.) * kz[2] + (125. / 192.) * kz[3] - (2187. / 6784.) * kz[4] + (11. / 84.) * kz[5];
460 error_xyz[0] =
abs((71. / 57600.) * kx[0] - (71. / 16695.) * kx[2] + (71. / 1920.) * kx[3] - (17253. / 339200.) * kx[4] + (22. / 525.) * kx[5] - (1. / 40.) * kx[6]);
461 error_xyz[1] =
abs((71. / 57600.) * ky[0] - (71. / 16695.) * ky[2] + (71. / 1920.) * ky[3] - (17253. / 339200.) * ky[4] + (22. / 525.) * ky[5] - (1. / 40.) * ky[6]);
462 error_xyz[2] =
abs((71. / 57600.) * kz[0] - (71. / 16695.) * kz[2] + (71. / 1920.) * kz[3] - (17253. / 339200.) * kz[4] + (22. / 525.) * kz[5] - (1. / 40.) * kz[6]);
465 err = std::max(std::max(error_xyz[0], error_xyz[1]), error_xyz[2]);
467 stepSize = stepSize * s;
472 stepSize = stepSize > maxStepSize ? maxStepSize : stepSize;
473 stepSize = stepSize < minStepSize ? minStepSize : stepSize;
480 BFieldFunction(r, outwards, b);
486template <
typename REAL>
487bool adaptiveEulerStep(std::array<REAL, 3>& r, std::array<REAL, 3>& b, REAL& stepSize,
const REAL minStepSize,
490 std::array<REAL, 3> r1;
491 BFieldFunction(r, outwards, b);
493 for (
int c = 0;
c < 3;
c++) {
494 r1[
c] = r[
c] + stepSize * b[
c];
498 std::array<REAL, 3> r2, b2;
499 for (
int c = 0;
c < 3;
c++) {
500 r2[
c] = r[
c] + 0.5 * stepSize * b[
c];
503 BFieldFunction(r2, outwards, b2);
504 for (
int c = 0;
c < 3;
c++) {
505 r2[
c] = r2[
c] + 0.5 * stepSize * b2[
c];
509 std::array<REAL, 3> error_xyz{fabs(r2[0] - r1[0]), fabs(r2[1] - r1[1]), fabs(r2[2] - r1[2])};
512 const REAL err = std::max(std::max(error_xyz[0], error_xyz[1]), error_xyz[2]);
514 stepSize = stepSize > maxStepSize ? maxStepSize : stepSize;
515 stepSize = stepSize < minStepSize ? minStepSize : stepSize;
528template <
typename REAL>
529void eulerStep(std::array<REAL, 3>& x, std::array<REAL, 3>& v, REAL& stepSize,
532 BFieldFunction(x, outwards, v);
534 for (
int c = 0;
c < 3;
c++) {
535 x[
c] += stepSize * v[
c];
540template <
typename REAL>
541void stepFieldLine(std::array<REAL, 3>& x, std::array<REAL, 3>& v, REAL& stepsize,
const REAL minStepSize,
543 const bool outwards) {
545 uint32_t attempts = 0;
548 eulerStep(x, v, stepsize, BFieldFunction, outwards);
552 reTrace = !
adaptiveEulerStep(x, v, stepsize, minStepSize, maxStepSize, BFieldFunction, outwards);
556 logFile <<
"(fieldtracing) Warning: Adaptive Euler field line tracer exhausted all available attempts and "
557 "still did not converge."
563 reTrace = !
bulirschStoerStep(x, v, stepsize, minStepSize, maxStepSize, BFieldFunction, outwards);
569 reTrace = !
dormandPrinceStep(x, v, stepsize, minStepSize, maxStepSize, BFieldFunction, outwards);
573 logFile <<
"(fieldtracing) Warning: Dormand Prince field line tracer exhausted all available attempts and "
574 "still did not converge..."
579 std::cerr <<
"(fieldtracing) Error: No field line tracing method defined." << std::endl;
592 std::vector<SBC::SphericalTriGrid::Node>& nodes,
creal radius);
595std::array<std::pair<int, Real>, 3>
597 creal couplingRadius);
603 std::vector<SBC::SphericalTriGrid::Node>& nodes);
610 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid);
615 dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
616 std::vector<SBC::SphericalTriGrid::Node>& nodes);
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
fsgrid::FsGrid< FS_STENCIL_WIDTH > FieldSolverGrid
std::array< fsgrid::FsIndex_t, 3 > getLocalFsGridCellIndexWithGhostsForCoord(T &grid, const std::array< Real, 3 > &x)
std::array< Real, 3 > getFractionalFsGridCellForCoord(T &grid, const std::array< Real, 3 > &x)
std::array< fsgrid::FsIndex_t, 3 > getLocalFsGridCellIndexForCoord(T &grid, const std::array< Real, 3 > &x)
std::array< fsgrid::FsSize_t, 3 > getGlobalFsGridCellIndexForCoord(T &grid, const std::array< Real, 3 > &x)
std::array< Real, 3 > interpolatePerturbedB(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, std::map< std::array< int, 3 >, std::array< Real, Rec::N_REC_COEFFICIENTS > > &reconstructionCoefficientsCache, cint i, cint j, cint k, const std::array< Real, 3 > x)
void resetReconstructionCoefficientsCache()
int ijk2Index(int i, int j, int k, std::array< int, 3 > dims)
void traceOpenClosedConnection(fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::constdperbspan dperb, std::vector< SBC::SphericalTriGrid::Node > &nodes)
void traceFullBoxConnectionAndFluxRopes(fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::constdperbspan dperb, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid)
void richardsonExtrapolation(int i, std::vector< REAL > &table, REAL &maxError, std::array< int, 3 > dims)
void calculateIonosphereFsgridCoupling(fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::constdperbspan dperb, std::vector< SBC::SphericalTriGrid::Node > &nodes, creal couplingRadius)
bool bulirschStoerStep(std::array< REAL, 3 > &r, std::array< REAL, 3 > &b, REAL &stepSize, const REAL minStepSize, const REAL maxStepSize, TracingFieldFunction< REAL > &BFieldFunction, const bool outwards=true)
void stepFieldLine(std::array< REAL, 3 > &x, std::array< REAL, 3 > &v, REAL &stepsize, const REAL minStepSize, const REAL maxStepSize, TracingMethod method, TracingFieldFunction< REAL > &BFieldFunction, const bool outwards)
bool dormandPrinceStep(std::array< REAL, 3 > &r, std::array< REAL, 3 > &b, REAL &stepSize, const REAL minStepSize, const REAL maxStepSize, TracingFieldFunction< REAL > &BFieldFunction, const bool outwards=true)
bool traceFullFieldFunction(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, std::array< REAL, 3 > &r, const bool alongB, std::array< REAL, 3 > &b)
void modifiedMidpointMethod(std::array< REAL, 3 > r, std::array< REAL, 3 > &r1, int n, REAL stepSize, TracingFieldFunction< REAL > &BFieldFunction, const bool outwards=true)
std::function< bool(std::array< REAL, 3 > &, const bool, std::array< REAL, 3 > &)> TracingFieldFunction
bool adaptiveEulerStep(std::array< REAL, 3 > &r, std::array< REAL, 3 > &b, REAL &stepSize, const REAL minStepSize, const REAL maxStepSize, TracingFieldFunction< REAL > &BFieldFunction, const bool outwards=true)
void reduceData(fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::constdperbspan dperb, dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, std::vector< SBC::SphericalTriGrid::Node > &nodes)
FieldTracingParameters fieldTracingParameters
void eulerStep(std::array< REAL, 3 > &x, std::array< REAL, 3 > &v, REAL &stepSize, TracingFieldFunction< REAL > &BFieldFunction, const bool outwards=true)
std::array< std::pair< int, Real >, 3 > calculateIonosphereVlasovGridCoupling(std::array< Real, 3 > x, std::vector< SBC::SphericalTriGrid::Node > &nodes, creal couplingRadius)
TracingPointConnectionType
SphericalTriGrid ionosphereGrid
std::span< std::array< Real, fsgrids::bfield::N_BFIELD > > perbspan
std::span< technical > technicalspan
std::span< const std::array< Real, fsgrids::dperb::N_DPERB > > constdperbspan
uint32_t max_field_tracer_attempts
Real fluxrope_max_incomplete_cells
Real fullbox_and_fluxrope_max_distance
Real min_tracer_dx_full_box
Real fluxrope_max_curvature_radii_extent
std::map< std::array< int, 3 >, std::array< Real, Rec::N_REC_COEFFICIENTS > > reconstructionCoefficientsCache
const Real max_tracer_dx_ionospere_coupling
TracingMethod tracingMethod
const Real min_tracer_dx_ionospere_coupling
Real fluxrope_max_curvature_radii_to_trace
Real fullbox_max_incomplete_cells
static ARCH_HOSTDEV VecSimple< T > abs(const VecSimple< T > &l)