Vlasiator ebf0dd394 on dev (v5.4.0 + 1054 commits)
Loading...
Searching...
No Matches
ionosphere.h
Go to the documentation of this file.
1/*
2 * This file is part of Vlasiator.
3 * Copyright 2010-2020 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#ifndef IONOSPHERE_H
24#define IONOSPHERE_H
25
26#include <cstdint>
27#include <vector>
28#include <functional>
29#include "../definitions.h"
30#include "../readparameters.h"
35
36#include <Eigen/Sparse>
37#include <Eigen/Geometry>
38
39using namespace projects;
40using namespace std;
41
42namespace SBC {
43
44 // Hardcoded constants for calculating ion production table
45 // TODO: Make these parameters?
46 constexpr static int productionNumAccEnergies = 60;
47 constexpr static int productionNumTemperatures = 60;
48 constexpr static int productionNumParticleEnergies = 100;
49 constexpr static Real productionMinAccEnergy = 0.1; // keV
50 constexpr static Real productionMaxAccEnergy = 100.; // keV
51 constexpr static Real productionMinTemperature = 0.1; // keV
52 constexpr static Real productionMaxTemperature = 100.; // keV
53 constexpr static Real ion_electron_T_ratio = 4.; // TODO: Make this a parameter (and/or find value from kinetics)
54
55
61
62 enum IonosphereBoundaryVDFmode { // How are inner boundary VDFs constructed from the ionosphere
63 FixedMoments, // Predefine temperature, density and V = EXB drift on the inner boundary.
64 AverageMoments, // Copy averaged density and temperature from nearest cells, V = EXB drift
65 AverageAllMoments, // Same as above, but also copy V + add EXB drift to it
67 };
69
70 static const int MAX_TOUCHING_ELEMENTS = 12; // Maximum number of elements touching one node
71 static const int MAX_DEPENDING_NODES = 22; // Maximum number of depending nodes
72
73 typedef Real iSolverReal; // Datatype for the ionosphere solver internal state
74
75 // Ionosphere finite element grid
77
78 // One finite element, spanned between 3 nodes
79 struct Element {
80 int refLevel = 0;
81 std::array<uint32_t, 3> corners; // Node indices in the corners of this element
82
83 };
84 std::vector<Element> elements;
85 std::vector<Eigen::Vector3d> elementCurlFreeCurrent;
86 std::vector<Eigen::Vector3d> elementDivFreeCurrent;
87 // One grid node
88 struct Node {
89 // Elements touching this node
91 std::array<uint32_t, MAX_TOUCHING_ELEMENTS> touchingElements;
92
93 // List of nodes the current node depends on
94 uint numDepNodes = 0;
95 std::array<uint32_t, MAX_DEPENDING_NODES> dependingNodes;
96 std::array<Real, MAX_DEPENDING_NODES> dependingCoeffs;// Dependency coefficients
97 std::array<Real, MAX_DEPENDING_NODES> transposedCoeffs; // Transposed dependency coefficient
98
99 std::array<Real, 3> x = {0,0,0}; // Coordinates of the node
100 std::array<Real, 3> xMapped = {0,0,0}; // Coordinates mapped along fieldlines into simulation domain
101 int haveCouplingData = 0; // Does this rank carry coupling coordinate data for this node? (0 or 1)
102 std::array<iSolverReal, N_IONOSPHERE_PARAMETERS> parameters = {0}; // Parameters carried by the node, see common.h
103
105
106 // Some calculation helpers
107 Real electronDensity() { // Electron Density
109 }
110 Real electronTemperature() { // Electron Temperature
112 }
113 Real deltaPhi() { // Field aligned potential drop between i'sphere and m'sphere
114
115 // When the Knight-parameter is irrelevant, we can set this to zero
116 return 0;
117
118 // Alternative: Calculate it just like GUMCS does
119
120 //if(electronDensity() == 0) {
121 // return 0;
122 //}
123
124 //Real retval = physicalconstants::K_B * electronTemperature() / physicalconstants::CHARGE
125 // * ((parameters[ionosphereParameters::SOURCE] / (physicalconstants::CHARGE * electronDensity()))
126 // * sqrt(2. * M_PI * physicalconstants::MASS_ELECTRON / (physicalconstants::K_B * electronTemperature())) - 1.);
129 //if(retval < 0 || !isfinite(retval)) {
130 // retval = 0;
131 //}
132 //return retval;
133 }
134
135 };
136
137 std::vector<Node> nodes;
138
139 // Atmospheric height layers that are being integrated over
140 constexpr static int numAtmosphereLevels = 20;
151 std::array<AtmosphericLayer, numAtmosphereLevels> atmosphere;
152
153 enum IonosphereSolverGaugeFixing { // Potential solver gauge fixing method
154 None, // No gauge fixing, solver won't converge well
155 Pole, // Fixing north pole (node 0) potential to zero
156 Integral, // Fixing integral of potential to zero (unstable?)
157 Equator // Fixing all nodes within +-10 dgrees to zero
159
160 enum IonosphereIonizationModel { // Ionization production rate model
161 Rees1963, // Rees (1963)
162 Rees1989, // Rees (1989)
163 SergienkoIvanov, // Sergienko & Ivanov (1993)
164 Robinson2020, // Robinson et al (2020)
165 Juusola2025, // Juusola et al (2025)
166 FixedSigma, // Simple, homogeneous, fixed SigmaP and SigmaH values, for testing
168
169 // Ionisation production table
170 std::array< std::array< std::array< Real, productionNumTemperatures >, productionNumAccEnergies >, numAtmosphereLevels > productionTable;
171 Real lookupProductionValue(int heightindex, Real energy_keV, Real temperature_keV);
172
173 MPI_Comm communicator = MPI_COMM_NULL;
174 int rank = -1;
176 bool isCouplingInwards = true;
177 bool isCouplingOutwards = true;
179 std::array<Real, 3> BGB;
180
181 std::map< std::array<Real, 3>, std::array<
182 std::pair<int, Real>, 3> > vlasovGridCoupling;
183
184 void setDipoleField(const FieldFunction& dipole) {
185 dipoleField = dipole;
186 };
187 void setConstantBackgroundField(const std::array<Real, 3> B) {
188 BGB = B;
189 }
190 void readAtmosphericModelFile(const char* filename);
191 void storeNodeB();
192 void offset_FAC();
193 void normalizeRadius(Node& n, Real R);
194 void updateConnectivity();
195 void updateIonosphereCommunicator(dccrg::Dccrg<SpatialCell,dccrg::Cartesian_Geometry>& mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid);
196 void initializeTetrahedron();
197 void initializeOctahedron();
198 void initializeIcosahedron();
199 void initializeSphericalFibonacci(int n);
200 void initializeGridFromFile(std::string path);
201 int32_t findElementNeighbour(uint32_t e, int n1, int n2);
202 uint32_t findNodeAtCoordinates(std::array<Real,3> x);
203 void subdivideElement(uint32_t e);
206 void calculateConductivityTensor(const Real F10_7, const Real recombAlpha, const Real backgroundIonisation, const bool refillTensorAtRestart=false);
207 Real interpolateUpmappedPotential(const std::array<Real, 3>& x);
208
209 // Conjugate Gradient solver functions
210 void addMatrixDependency(uint node1, uint node2, Real coeff, bool transposed=false);
211 void addAllMatrixDependencies(uint nodeIndex);
212 void initSolver(bool zeroOut=true);
213 iSolverReal Atimes(uint nodeIndex, int parameter, bool transpose=false);
214 Real Asolve(uint nodeIndex, int parameter, bool transpose=false);
215 void solve(
216 int & iteration,
217 int & nRestarts,
218 Real & residual,
219 Real & minPotentialN,
220 Real & maxPotentialN,
221 Real & minPotentialS,
222 Real & maxPotentialS
223 );
224 void solveInternal(
225 int & iteration,
226 int & nRestarts,
227 Real & residual,
228 Real & minPotentialN,
229 Real & maxPotentialN,
230 Real & minPotentialS,
231 Real & maxPotentialS
232 );
233
234 // Map field-aligned currents, density and temperature
235 // down from the simulation boundary onto this grid
238 fsgrids::momentsspan moments,
240 );
241
242 // Returns the surface area of one element on the sphere
243 Real elementArea(uint32_t elementIndex) {
244 const std::array<Real, 3>& a = nodes[elements[elementIndex].corners[0]].x;
245 const std::array<Real, 3>& b = nodes[elements[elementIndex].corners[1]].x;
246 const std::array<Real, 3>& c = nodes[elements[elementIndex].corners[2]].x;
247
248 // Two edges e1 = b-c, e2 = c-a
249 std::array<Real, 3> e1{b[0]-c[0], b[1]-c[1],b[2]-c[2]};
250 std::array<Real, 3> e2{c[0]-a[0], c[1]-a[1],c[2]-a[2]};
251 // Area vector A = cross(e1 e2)
252 std::array<Real, 3> area{ e1[1]*e2[2] - e1[2]*e2[1],
253 e1[2]*e2[0] - e1[0]*e2[2],
254 e1[0]*e2[1] - e1[1]*e2[0]};
255
256 return 0.5 * sqrt( area[0]*area[0] + area[1]*area[1] + area[2]*area[2] );
257 }
258
259 // Returns the projected surface area of one element, mapped up along the magnetic field to
260 // the simulation boundary. If one of the nodes maps nowhere, returns 0.
261 // Returns an oriented vector, which can be dotted with B
262 std::array<Real, 3> mappedElementArea(uint32_t elementIndex) {
263 const std::array<Real, 3>& a = nodes[elements[elementIndex].corners[0]].xMapped;
264 const std::array<Real, 3>& b = nodes[elements[elementIndex].corners[1]].xMapped;
265 const std::array<Real, 3>& c = nodes[elements[elementIndex].corners[2]].xMapped;
266
267 // Check if any node maps to zero
268 if( sqrt( a[0]*a[0] + a[1]*a[1] + a[2]*a[2] ) == 0 ||
269 sqrt( b[0]*b[0] + b[1]*b[1] + b[2]*b[2] ) == 0 ||
270 sqrt( c[0]*c[0] + c[1]*c[1] + c[2]*c[2] ) == 0) {
271
272 return {0,0,0};
273 }
274
275 // Two edges e1 = b-c, e2 = c-a
276 std::array<Real, 3> e1{b[0]-c[0], b[1]-c[1],b[2]-c[2]};
277 std::array<Real, 3> e2{c[0]-a[0], c[1]-a[1],c[2]-a[2]};
278 // Area vector A = cross(e1 e2)
279 const Real HALF = 0.5;
280 const Real THIRD = 1./3.;
281 std::array<Real, 3> area{ HALF * (e1[1]*e2[2] - e1[2]*e2[1]),
282 HALF * (e1[2]*e2[0] - e1[0]*e2[2]),
283 HALF * (e1[0]*e2[1] - e1[1]*e2[0])};
284
285 // By definition, the area is oriented outwards, so if dot(r,A) < 0, flip it.
286 std::array<Real, 3> r{
287 (a[0]+b[0]+c[0]) * THIRD,
288 (a[1]+b[1]+c[1]) * THIRD,
289 (a[2]+b[2]+c[2]) * THIRD};
290 if(area[0]*r[0] + area[1]*r[1] + area[2] *r[2] < 0) {
291 area[0]*=-1.;
292 area[1]*=-1.;
293 area[2]*=-1.;
294 }
295 return area;
296 }
297
298 Eigen::Vector3d elementBarycentre(uint32_t el) {
299 Eigen::Vector3d barycentre(0,0,0);
300
301 Element& element = elements[el];
302 for(uint i=0; i<3; i++) {
303 Eigen::Vector3d corner(nodes[element.corners[i]].x.data());
304
305 barycentre += corner;
306 }
307 barycentre /= 3.;
308
309 return barycentre;
310 }
311
312 Eigen::Vector3d elementCircumcentre(uint el) {
313 Eigen::Vector3d circumcentre(0,0,0);
314
315 SphericalTriGrid::Element& element = elements[el];
316 uint corner1 = element.corners[0];
317 uint corner2 = element.corners[1];
318 uint corner3 = element.corners[2];
319
320 Eigen::Vector3d a(nodes[corner1].x.data());
321 Eigen::Vector3d b(nodes[corner2].x.data());
322 Eigen::Vector3d c(nodes[corner3].x.data());
323
324 Eigen::Vector3d edge1 = b - a;
325 Eigen::Vector3d edge2 = c - a;
326
327 Eigen::Vector3d edge1Mid = a + edge1 / 2.;
328 Eigen::Vector3d edge2Mid = a + edge2 / 2.;
329
330 Eigen::Vector3d normal = edge1.cross(edge2).normalized();
331
332 if(normal.dot(a) < 0) {
333 normal *= -1.;
334 }
335
336 Eigen::Vector3d edge1Perpendicular = normal.cross(edge1).normalized();
337 Eigen::Vector3d edge2Perpendicular = normal.cross(edge2).normalized();
338
339 Eigen::Matrix<Real, 3, 2> A;
340 A.col(0) = edge1Perpendicular;
341 A.col(1) = - edge2Perpendicular;
342 Eigen::Vector3d bVec = edge2Mid - edge1Mid;
343 Eigen::Vector2d t = A.colPivHouseholderQr().solve(bVec);
344 // Verify that the solution is correct
345 //Eigen::Vector3d residual = A * t - bVec;
346 //if (residual.norm() > 1e-6) {
347 // cerr << "Circumcentre calculation failed, residual: " << residual.norm() << endl;
348 //}
349
350 Eigen::Vector3d intersection = edge1Mid + t(0) * edge1Perpendicular;
351 Eigen::Vector3d intersection2 = edge2Mid + t(1) * edge2Perpendicular;
352 if((intersection - intersection2).norm() > 1e-6) {
353 cerr << "Circumcentre calculation failed, intersection points do not match: "
354 << (intersection - intersection2).norm() << endl;
355 }
356 circumcentre = intersection;
357
358 return circumcentre;
359 }
360
361 Eigen::Vector3d elementNormal(uint32_t el) {
362 Eigen::Vector3d normal(0,0,0);
363
364 SphericalTriGrid::Element& element = elements[el];
365 uint32_t corner1 = element.corners[0];
366 uint32_t corner2 = element.corners[1];
367 uint32_t corner3 = element.corners[2];
368
369 Eigen::Vector3d a(nodes[corner1].x.data());
370 Eigen::Vector3d b(nodes[corner2].x.data());
371 Eigen::Vector3d c(nodes[corner3].x.data());
372
373 Eigen::Vector3d edge1 = b - a;
374 Eigen::Vector3d edge2 = c - a;
375
376 normal = edge1.cross(edge2);
377
378 normal.normalized();
379
380 if(normal.dot(elementCircumcentre(el)) < 0) {
381 normal *= -1.;
382 }
383
384 return normal;
385 }
386
387 Eigen::Vector3d commonEdgeMidpoint(uint32_t el1, uint32_t el2) {
388 SphericalTriGrid::Element& element1 = elements[el1];
389 SphericalTriGrid::Element& element2 = elements[el2];
390
391 // Get common edge to these two elements
392 for(uint i=0; i<3; i++) {
393 if(element1.corners[i] == element2.corners[0] ||
394 element1.corners[i] == element2.corners[1] ||
395 element1.corners[i] == element2.corners[2]) {
396 for(uint j=0; j<3; j++) {
397 if(i != j && (element1.corners[j] == element2.corners[0] ||
398 element1.corners[j] == element2.corners[1] ||
399 element1.corners[j] == element2.corners[2])) {
400
401 uint corner1 = element1.corners[i];
402 uint corner2 = element1.corners[j];
403
404 Eigen::Vector3d a(nodes[corner1].x.data());
405 Eigen::Vector3d b(nodes[corner2].x.data());
406
407 Eigen::Vector3d midpoint = (a + b) / 2.;
408 return midpoint;
409 }
410 }
411 }
412 }
413
414 // We should never end up here.
415 return {0,0,0};
416 }
417
418 Real dualPolygonArea(uint gridNode){
419 Real A = 0.;
420
421 for(uint i = 0; i < nodes[gridNode].numTouchingElements; i++){
422 uint32_t gridEl = nodes[gridNode].touchingElements[i];
423 Eigen::Vector3d nodePosition(nodes[gridNode].x.data());
424
425 SphericalTriGrid::Element& element = elements[gridEl];
426
427 int localC=0,localI=0,localJ=0;
428 for(int c=0; c < 3; c++) {
429 if(element.corners[c] == gridNode) {
430 localC = c;
431 localI = (c+1)%3;
432 localJ = (c+2)%3;
433 break;
434 }
435 }
436
437 uint otherElementi = findElementNeighbour(gridEl, localC, localI);
438 uint otherElementj = findElementNeighbour(gridEl, localC, localJ);
439
440 Eigen::Vector3d midpointi = commonEdgeMidpoint(gridEl, otherElementi);
441 Eigen::Vector3d midpointj = commonEdgeMidpoint(gridEl, otherElementj);
442
443 Eigen::Vector3d circumcentre = elementCircumcentre(gridEl);
444
445 Real heighti = (nodePosition - midpointi).norm();
446 Real heightj = (nodePosition - midpointj).norm();
447
448 Real basei = (circumcentre - midpointi).norm();
449 Real basej = (circumcentre - midpointj).norm();
450
451 A += (0.5 * basei * heighti) + (0.5 * basej * heightj);
452 }
453
454 return A;
455 }
456
457 Real areaInDualPolygon(uint gridNode, uint gridElem) {
458 Real A = 0.;
459
460 Eigen::Vector3d nodePosition(nodes[gridNode].x.data());
461 SphericalTriGrid::Element& element = elements[gridElem];
462
463 int localC=0,localI=0,localJ=0;
464 for(int c=0; c < 3; c++) {
465 if(element.corners[c] == gridNode) {
466 localC = c;
467 localI = (c+1)%3;
468 localJ = (c+2)%3;
469 break;
470 }
471 }
472
473 uint otherElementi = findElementNeighbour(gridElem, localC, localI);
474 uint otherElementj = findElementNeighbour(gridElem, localC, localJ);
475
476 Eigen::Vector3d midpointi = commonEdgeMidpoint(gridElem, otherElementi);
477 Eigen::Vector3d midpointj = commonEdgeMidpoint(gridElem, otherElementj);
478
479 Eigen::Vector3d circumcentre = elementCircumcentre(gridElem);
480
481 Real heighti = (nodePosition - midpointi).norm();
482 Real heightj = (nodePosition - midpointj).norm();
483
484 Real basei = (circumcentre - midpointi).norm();
485 Real basej = (circumcentre - midpointj).norm();
486
487 A += (0.5 * basei * heighti) + (0.5 * basej * heightj);
488
489 return A;
490 }
491
492 Real nodeNeighbourArea(uint32_t nodeIndex) { // Summed area of all touching elements
493
494 Node& n = nodes[nodeIndex];
495 Real area=0;
496
497 for(uint i=0; i<n.numTouchingElements; i++) {
498 area += elementArea(n.touchingElements[i]);
499 }
500 return area;
501 }
502
503 // Calculate neighbor's Barycentre and dual polygon - edge - intersection point.
504 std::tuple<Eigen::Vector3d, Eigen::Vector3d> connectingSegmentLengths(uint32_t el1, uint32_t el2) {
505 SphericalTriGrid::Element& element1 = elements[el1];
506 SphericalTriGrid::Element& element2 = elements[el2];
507
508 Eigen::Vector3d barycentre1 = elementBarycentre(el1);
509 Eigen::Vector3d barycentre2 = elementBarycentre(el2);
510
511 // Get common edge to these two elements
512 for(uint i=0; i<3; i++) {
513 if(element1.corners[i] == element2.corners[0] ||
514 element1.corners[i] == element2.corners[1] ||
515 element1.corners[i] == element2.corners[2]) {
516 for(uint j=0; j<3; j++) {
517 if(i != j && (element1.corners[j] == element2.corners[0] ||
518 element1.corners[j] == element2.corners[1] ||
519 element1.corners[j] == element2.corners[2])) {
520
521 uint corner1 = element1.corners[i];
522 uint corner2 = element1.corners[j];
523
524 Eigen::Vector3d normal1 = elementNormal(el1);
525 Eigen::Vector3d normal2 = elementNormal(el2);
526
527 Eigen::Vector3d rotatedBarycentre2 = Eigen::Vector3d(nodes[corner1].x.data()) +
528 Eigen::Quaternion<Real>::FromTwoVectors(normal2, normal1).toRotationMatrix() *
529 (barycentre2 - Eigen::Vector3d(nodes[corner1].x.data()));
530
531 Eigen::Vector3d corner1Position(nodes[corner1].x.data());
532 Eigen::Vector3d corner2Position(nodes[corner2].x.data());
533
534 Eigen::Vector3d barycentre1ToBarycentre2 = (rotatedBarycentre2 - barycentre1).normalized();
535 Eigen::Vector3d corner1ToCorner2 = (corner2Position - corner1Position).normalized();
536
537 // Get intersection of line between barycenters and line between corners
538 Eigen::Matrix<double, 3, 2> A;
539 A.col(0) = barycentre1ToBarycentre2;
540 A.col(1) = - corner1ToCorner2;
541 Eigen::Vector3d b = corner1Position - barycentre1;
542 Eigen::Vector2d t = A.colPivHouseholderQr().solve(b);
543 Eigen::Vector3d intersection = barycentre1 + t(0) * barycentre1ToBarycentre2;
544
545 return std::make_tuple(barycentre2, intersection);
546 }
547 }
548 }
549 }
550
551 // Not found, something went bananas.
552 abort();
553 }
554
555 std::array<Real,3> computeGradT(const std::array<Real, 3>& a, const std::array<Real, 3>& b, const std::array<Real, 3>& c);
556 std::array<Real, 9> sigmaAverage(uint elementIndex);
557 double elementIntegral(uint elementIndex, int i, int j, bool transpose = false);
558
559 };
560
561 extern SphericalTriGrid ionosphereGrid;
562
573 public:
574 Ionosphere();
575 virtual ~Ionosphere();
576
577 static void addParameters();
578 virtual void getParameters() override;
579
580 virtual void initSysBoundary(creal& t, Project& project) override;
581 virtual void assignSysBoundary(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
582 fsgrids::technicalspan technical, FieldSolverGrid& fsgrid) override;
583 virtual void applyInitialState(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
587 Project& project) override;
591 const std::array<Real, 3>& gridSpacing,
592 const std::array<fsgrid::FsSize_t, 3>& globalCoordinates,
593 const fsgrid::FsStencil& stencil, cuint component) override;
595 const fsgrid::FsStencil& stencil, cuint component) override;
597 const fsgrid::FsStencil& stencil, cuint component) override;
599 const fsgrid::FsStencil& stencil, cuint component) override;
601 fsgrids::dmomentsspan dmoments,
602 const fsgrid::FsStencil& stencil, cuint RKCase, cuint component) override;
604 const fsgrid::FsStencil& stencil, cuint component) override;
605 // Compute and store the EXB drift into the cell's BULKV_FORCING_X/Y/Z fields
606 virtual void mapCellPotentialAndGetEXBDrift(std::array<Real, CellParams::N_SPATIAL_CELL_PARAMS>& cellParams) override;
607 virtual void vlasovBoundaryCondition(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
608 const CellID& cellID, const uint popID,
609 const bool calculate_V_moments) override;
610 virtual void updateState(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
613 fsgrids::bgbspan bgb, creal t) override;
614
615 virtual void getFaces(bool* faces) override;
616 virtual std::string getName() const override;
617 virtual uint getIndex() const override;
618 static Real radius;
619 static std::vector<IonosphereSpeciesParameters> speciesParams;
620
621 // Parameters of the ionosphere model
623 static bool useEigenSolver;
633
634 // TODO: Make these parameters of the IonosphereGrid
636 static Real F10_7;
640 static enum downmapSamplingMode { // How to sample possibly under-resolved FACs at the downmap radius
641 Pointwise, // Just sample the FAC at the downmapping point
642 Boxcar27 // 27-point boxcar, samples a cube of +-downmapSamplingWidth*fsgrid.dx/2 from the downmapping point
644
649 static int solveCount;
650 static enum IonosphereConductivityModel { // How should the conductivity tensor be assembled?
651 GUMICS, // Like GUMICS-5 does it? (Only SigmaH and SigmaP, B perp to surface)
652 Ridley, // Or like the Ridley 2004 paper (with 1000 mho longitudinal conductivity)
653 Koskinen // Like Koskinen's 2001 "Physics of Space Storms" book suggests
657
658 void generateTemplateCell(Project &project);
659 void setCellFromTemplate(SpatialCell* cell,const uint popID);
660
661 std::array<Real, 3> fieldSolverGetNormalDirection(
663 cint i,
664 cint j,
665 cint k
666 );
667
669 uint geometry;
670
671
672 std::string baseShape;
673 std::string path;
678
679 // Boundaries of refinement latitude bands
680 std::vector<Real> refineMinLatitudes;
681 std::vector<Real> refineMaxLatitudes;
682
684 };
685}
686
687#endif
for i
Definition Dispersion.m:24
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
Constants c
Definition Dispersion.m:45
virtual void initSysBoundary(creal &t, Project &project) override
static Real innerRadius
Definition ionosphere.h:622
static enum SBC::Ionosphere::downmapSamplingMode downmapFACsamplingMode
virtual void applyInitialState(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::bgbspan bgb, Project &project) override
static void addParameters()
static bool useEigenSolver
Definition ionosphere.h:623
std::string path
Definition ionosphere.h:673
static std::vector< IonosphereSpeciesParameters > speciesParams
Definition ionosphere.h:619
static Real unmappedNodeRho
Definition ionosphere.h:645
virtual std::string getName() const override
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) override
static Real solverRelativeL2ConvergenceThreshold
Definition ionosphere.h:625
virtual uint getIndex() const override
static Real downmapRadius
Definition ionosphere.h:638
static Real shieldingLatitude
Definition ionosphere.h:631
virtual void getParameters() override
virtual void mapCellPotentialAndGetEXBDrift(std::array< Real, CellParams::N_SPATIAL_CELL_PARAMS > &cellParams) override
virtual void updateState(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, fsgrids::perbspan perb, fsgrids::bgbspan bgb, creal t) override
virtual void fieldSolverBoundaryCondElectricField(fsgrids::efieldspan e, const fsgrid::FsStencil &stencil, cuint component) override
virtual void getFaces(bool *faces) override
static int solverMaxFailureCount
Definition ionosphere.h:626
static int solveCount
Definition ionosphere.h:649
std::string atmosphericModelFile
Definition ionosphere.h:677
static Real unmappedNodeTe
Definition ionosphere.h:646
static bool solverPreconditioning
Definition ionosphere.h:628
std::vector< Real > refineMaxLatitudes
Definition ionosphere.h:681
virtual void assignSysBoundary(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid) override
static Real couplingInterval
Definition ionosphere.h:648
static Real backgroundIonisation
Definition ionosphere.h:637
spatial_cell::SpatialCell templateCell
Definition ionosphere.h:683
static Real ridleyParallelConductivity
Definition ionosphere.h:632
static Real recombAlpha
Definition ionosphere.h:635
static Real downmapSamplingWidth
Definition ionosphere.h:639
std::array< Real, 3 > fieldSolverGetNormalDirection(fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, cint i, cint j, cint k)
static Real F10_7
Definition ionosphere.h:636
std::string baseShape
Definition ionosphere.h:672
static int solverMaxIterations
Definition ionosphere.h:624
static Real couplingTimescale
Definition ionosphere.h:647
std::vector< Real > refineMinLatitudes
Definition ionosphere.h:680
static Real radius
Definition ionosphere.h:618
virtual void vlasovBoundaryCondition(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellID, const uint popID, const bool calculate_V_moments) override
virtual ~Ionosphere()
void setCellFromTemplate(SpatialCell *cell, const uint popID)
static bool solverToggleMinimumResidualVariant
Definition ionosphere.h:630
virtual void fieldSolverBoundaryCondDerivatives(fsgrids::dperbspan dperb, fsgrids::dmomentsspan dmoments, const fsgrid::FsStencil &stencil, cuint RKCase, cuint component) override
static Real fixedSigmaH
Definition ionosphere.h:656
static enum SBC::Ionosphere::IonosphereConductivityModel conductivityModel
virtual void fieldSolverBoundaryCondBVOLDerivatives(fsgrids::volspan vols, const fsgrid::FsStencil &stencil, cuint component) override
Real earthAngularVelocity
Definition ionosphere.h:675
virtual void fieldSolverBoundaryCondHallElectricField(fsgrids::ehallspan ehall, const fsgrid::FsStencil &stencil, cuint component) override
static bool solverUseMinimumResidualVariant
Definition ionosphere.h:629
static Real fixedSigmaP
Definition ionosphere.h:655
virtual void fieldSolverBoundaryCondGradPeElectricField(fsgrids::egradpespan EGradPe, const fsgrid::FsStencil &stencil, cuint component) override
static Real solverMaxErrorGrowthFactor
Definition ionosphere.h:627
@ TEMPERATURE
Definition common.h:469
@ RHON
Definition common.h:468
const uint32_t cuint
Definition definitions.h:50
float Real
Definition definitions.h:41
const int cint
Definition definitions.h:45
uint64_t CellID
Definition definitions.h:54
fsgrid::FsGrid< FS_STENCIL_WIDTH > FieldSolverGrid
Definition definitions.h:78
const float creal
Definition definitions.h:42
std::function< double(double x, double y, double z, coordinate component, unsigned int derivative, coordinate dcomponent)> FieldFunction
const Real THIRD
Definition fs_common.h:52
const Real HALF
Definition fs_common.h:49
const Realf intersection
const int j
const int k
IonosphereBoundaryVDFmode
Definition ionosphere.h:62
@ AverageMoments
Definition ionosphere.h:64
@ FixedMoments
Definition ionosphere.h:63
@ CopyAndLosscone
Definition ionosphere.h:66
@ AverageAllMoments
Definition ionosphere.h:65
static constexpr Real productionMinAccEnergy
Definition ionosphere.h:49
static constexpr Real ion_electron_T_ratio
Definition ionosphere.h:53
static constexpr Real productionMaxAccEnergy
Definition ionosphere.h:50
static constexpr int productionNumAccEnergies
Definition ionosphere.h:46
static constexpr int productionNumParticleEnergies
Definition ionosphere.h:48
static constexpr Real productionMaxTemperature
Definition ionosphere.h:52
SphericalTriGrid ionosphereGrid
static constexpr Real productionMinTemperature
Definition ionosphere.h:51
Real iSolverReal
Definition ionosphere.h:73
IonosphereBoundaryVDFmode boundaryVDFmode
static const int MAX_DEPENDING_NODES
Definition ionosphere.h:71
static constexpr int productionNumTemperatures
Definition ionosphere.h:47
static const int MAX_TOUCHING_ELEMENTS
Definition ionosphere.h:70
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< 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
std::span< technical > technicalspan
Definition common.h:452
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
std::span< const technical > consttechnicalspan
Definition common.h:453
std::span< std::array< Real, fsgrids::efield::N_EFIELD > > efieldspan
Definition common.h:436
std::span< std::array< Real, fsgrids::volfields::N_VOL > > volspan
Definition common.h:450
std::span< std::array< Real, fsgrids::ehall::N_EHALL > > ehallspan
Definition common.h:438
std::span< const std::array< Real, fsgrids::dperb::N_DPERB > > constdperbspan
Definition common.h:443
static const Real recombAlpha
std::array< uint32_t, 3 > corners
Definition ionosphere.h:81
std::array< Real, 3 > xMapped
Definition ionosphere.h:100
std::array< uint32_t, MAX_DEPENDING_NODES > dependingNodes
Definition ionosphere.h:95
std::array< Real, MAX_DEPENDING_NODES > dependingCoeffs
Definition ionosphere.h:96
std::array< iSolverReal, N_IONOSPHERE_PARAMETERS > parameters
Definition ionosphere.h:102
std::array< uint32_t, MAX_TOUCHING_ELEMENTS > touchingElements
Definition ionosphere.h:91
std::array< Real, MAX_DEPENDING_NODES > transposedCoeffs
Definition ionosphere.h:97
std::array< Real, 3 > x
Definition ionosphere.h:99
std::array< Real, 9 > sigmaAverage(uint elementIndex)
std::tuple< Eigen::Vector3d, Eigen::Vector3d > connectingSegmentLengths(uint32_t el1, uint32_t el2)
Definition ionosphere.h:504
void mapDownBoundaryData(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::momentsspan moments, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
void initializeSphericalFibonacci(int n)
Real lookupProductionValue(int heightindex, Real energy_keV, Real temperature_keV)
std::array< Real, 3 > BGB
Definition ionosphere.h:179
std::array< std::array< std::array< Real, productionNumTemperatures >, productionNumAccEnergies >, numAtmosphereLevels > productionTable
Definition ionosphere.h:170
std::array< Real, 3 > computeGradT(const std::array< Real, 3 > &a, const std::array< Real, 3 > &b, const std::array< Real, 3 > &c)
Real elementArea(uint32_t elementIndex)
Definition ionosphere.h:243
void setDipoleField(const FieldFunction &dipole)
Definition ionosphere.h:184
std::array< Real, 3 > mappedElementArea(uint32_t elementIndex)
Definition ionosphere.h:262
void setConstantBackgroundField(const std::array< Real, 3 > B)
Definition ionosphere.h:187
uint32_t findNodeAtCoordinates(std::array< Real, 3 > x)
Real interpolateUpmappedPotential(const std::array< Real, 3 > &x)
std::map< std::array< Real, 3 >, std::array< std::pair< int, Real >, 3 > > vlasovGridCoupling
Definition ionosphere.h:182
FieldFunction dipoleField
Definition ionosphere.h:178
Eigen::Vector3d commonEdgeMidpoint(uint32_t el1, uint32_t el2)
Definition ionosphere.h:387
void normalizeRadius(Node &n, Real R)
void readAtmosphericModelFile(const char *filename)
void calculateConductivityTensor(const Real F10_7, const Real recombAlpha, const Real backgroundIonisation, const bool refillTensorAtRestart=false)
void initSolver(bool zeroOut=true)
void initializeGridFromFile(std::string path)
std::vector< Eigen::Vector3d > elementDivFreeCurrent
Definition ionosphere.h:86
void addAllMatrixDependencies(uint nodeIndex)
void subdivideElement(uint32_t e)
Real dualPolygonArea(uint gridNode)
Definition ionosphere.h:418
int32_t findElementNeighbour(uint32_t e, int n1, int n2)
void updateIonosphereCommunicator(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
Real areaInDualPolygon(uint gridNode, uint gridElem)
Definition ionosphere.h:457
std::vector< Node > nodes
Definition ionosphere.h:137
Eigen::Vector3d elementNormal(uint32_t el)
Definition ionosphere.h:361
void solveInternal(int &iteration, int &nRestarts, Real &residual, Real &minPotentialN, Real &maxPotentialN, Real &minPotentialS, Real &maxPotentialS)
iSolverReal Atimes(uint nodeIndex, int parameter, bool transpose=false)
Eigen::Vector3d elementCircumcentre(uint el)
Definition ionosphere.h:312
std::vector< Element > elements
Definition ionosphere.h:84
enum SBC::SphericalTriGrid::IonosphereSolverGaugeFixing gaugeFixing
enum SBC::SphericalTriGrid::IonosphereIonizationModel ionizationModel
Eigen::Vector3d elementBarycentre(uint32_t el)
Definition ionosphere.h:298
Real nodeNeighbourArea(uint32_t nodeIndex)
Definition ionosphere.h:492
std::array< AtmosphericLayer, numAtmosphereLevels > atmosphere
Definition ionosphere.h:151
Real Asolve(uint nodeIndex, int parameter, bool transpose=false)
static constexpr int numAtmosphereLevels
Definition ionosphere.h:140
std::vector< Eigen::Vector3d > elementCurlFreeCurrent
Definition ionosphere.h:85
double elementIntegral(uint elementIndex, int i, int j, bool transpose=false)
void solve(int &iteration, int &nRestarts, Real &residual, Real &minPotentialN, Real &maxPotentialN, Real &minPotentialS, Real &maxPotentialS)
void addMatrixDependency(uint node1, uint node2, Real coeff, bool transposed=false)