36#include <Eigen/Sparse>
37#include <Eigen/Geometry>
99 std::array<Real, 3>
x = {0,0,0};
102 std::array<iSolverReal, N_IONOSPHERE_PARAMETERS>
parameters = {0};
151 std::array<AtmosphericLayer, numAtmosphereLevels>
atmosphere;
181 std::map< std::array<Real, 3>, std::array<
214 Real Asolve(uint nodeIndex,
int parameter,
bool transpose=
false);
219 Real & minPotentialN,
220 Real & maxPotentialN,
221 Real & minPotentialS,
228 Real & minPotentialN,
229 Real & maxPotentialN,
230 Real & minPotentialS,
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;
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]};
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]};
256 return 0.5 *
sqrt( area[0]*area[0] + area[1]*area[1] + area[2]*area[2] );
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;
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) {
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]};
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])};
286 std::array<Real, 3> r{
289 (a[2]+b[2]+
c[2]) *
THIRD};
290 if(area[0]*r[0] + area[1]*r[1] + area[2] *r[2] < 0) {
299 Eigen::Vector3d barycentre(0,0,0);
302 for(uint
i=0;
i<3;
i++) {
305 barycentre += corner;
313 Eigen::Vector3d circumcentre(0,0,0);
316 uint corner1 = element.
corners[0];
317 uint corner2 = element.
corners[1];
318 uint corner3 = element.
corners[2];
320 Eigen::Vector3d a(
nodes[corner1].x.data());
321 Eigen::Vector3d b(
nodes[corner2].x.data());
322 Eigen::Vector3d
c(
nodes[corner3].x.data());
324 Eigen::Vector3d edge1 = b - a;
325 Eigen::Vector3d edge2 =
c - a;
327 Eigen::Vector3d edge1Mid = a + edge1 / 2.;
328 Eigen::Vector3d edge2Mid = a + edge2 / 2.;
330 Eigen::Vector3d normal = edge1.cross(edge2).normalized();
332 if(normal.dot(a) < 0) {
336 Eigen::Vector3d edge1Perpendicular = normal.cross(edge1).normalized();
337 Eigen::Vector3d edge2Perpendicular = normal.cross(edge2).normalized();
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);
350 Eigen::Vector3d
intersection = edge1Mid + t(0) * edge1Perpendicular;
351 Eigen::Vector3d intersection2 = edge2Mid + t(1) * edge2Perpendicular;
353 cerr <<
"Circumcentre calculation failed, intersection points do not match: "
362 Eigen::Vector3d normal(0,0,0);
365 uint32_t corner1 = element.
corners[0];
366 uint32_t corner2 = element.
corners[1];
367 uint32_t corner3 = element.
corners[2];
369 Eigen::Vector3d a(
nodes[corner1].x.data());
370 Eigen::Vector3d b(
nodes[corner2].x.data());
371 Eigen::Vector3d
c(
nodes[corner3].x.data());
373 Eigen::Vector3d edge1 = b - a;
374 Eigen::Vector3d edge2 =
c - a;
376 normal = edge1.cross(edge2);
392 for(uint
i=0;
i<3;
i++) {
396 for(uint
j=0;
j<3;
j++) {
404 Eigen::Vector3d a(
nodes[corner1].x.data());
405 Eigen::Vector3d b(
nodes[corner2].x.data());
407 Eigen::Vector3d midpoint = (a + b) / 2.;
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());
427 int localC=0,localI=0,localJ=0;
428 for(
int c=0;
c < 3;
c++) {
429 if(element.
corners[
c] == gridNode) {
445 Real heighti = (nodePosition - midpointi).norm();
446 Real heightj = (nodePosition - midpointj).norm();
448 Real basei = (circumcentre - midpointi).norm();
449 Real basej = (circumcentre - midpointj).norm();
451 A += (0.5 * basei * heighti) + (0.5 * basej * heightj);
460 Eigen::Vector3d nodePosition(
nodes[gridNode].x.data());
463 int localC=0,localI=0,localJ=0;
464 for(
int c=0;
c < 3;
c++) {
465 if(element.
corners[
c] == gridNode) {
481 Real heighti = (nodePosition - midpointi).norm();
482 Real heightj = (nodePosition - midpointj).norm();
484 Real basei = (circumcentre - midpointi).norm();
485 Real basej = (circumcentre - midpointj).norm();
487 A += (0.5 * basei * heighti) + (0.5 * basej * heightj);
497 for(uint
i=0;
i<n.numTouchingElements;
i++) {
512 for(uint
i=0;
i<3;
i++) {
516 for(uint
j=0;
j<3;
j++) {
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()));
531 Eigen::Vector3d corner1Position(
nodes[corner1].x.data());
532 Eigen::Vector3d corner2Position(
nodes[corner2].x.data());
534 Eigen::Vector3d barycentre1ToBarycentre2 = (rotatedBarycentre2 - barycentre1).normalized();
535 Eigen::Vector3d corner1ToCorner2 = (corner2Position - corner1Position).normalized();
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;
555 std::array<Real,3>
computeGradT(
const std::array<Real, 3>& a,
const std::array<Real, 3>& b,
const std::array<Real, 3>&
c);
581 virtual void assignSysBoundary(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
583 virtual void applyInitialState(dccrg::Dccrg<SpatialCell, dccrg::Cartesian_Geometry>& mpiGrid,
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;
602 const fsgrid::FsStencil& stencil,
cuint RKCase,
cuint component)
override;
604 const fsgrid::FsStencil& stencil,
cuint component)
override;
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,
615 virtual void getFaces(
bool* faces)
override;
616 virtual std::string
getName()
const override;
617 virtual uint
getIndex()
const override;
sqrt(1.0+vA *vA/(c *c))) % Ion-acoustic wave cS
virtual void initSysBoundary(creal &t, Project &project) override
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
static std::vector< IonosphereSpeciesParameters > speciesParams
static Real unmappedNodeRho
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
virtual uint getIndex() const override
static Real downmapRadius
static Real shieldingLatitude
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
std::string atmosphericModelFile
static Real unmappedNodeTe
static bool solverPreconditioning
std::vector< Real > refineMaxLatitudes
virtual void assignSysBoundary(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid) override
static Real couplingInterval
static Real backgroundIonisation
spatial_cell::SpatialCell templateCell
static Real ridleyParallelConductivity
static Real downmapSamplingWidth
std::array< Real, 3 > fieldSolverGetNormalDirection(fsgrids::technicalspan technical, FieldSolverGrid &fsgrid, cint i, cint j, cint k)
static int solverMaxIterations
static Real couplingTimescale
std::vector< Real > refineMinLatitudes
virtual void vlasovBoundaryCondition(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, const CellID &cellID, const uint popID, const bool calculate_V_moments) override
void setCellFromTemplate(SpatialCell *cell, const uint popID)
static bool solverToggleMinimumResidualVariant
virtual void fieldSolverBoundaryCondDerivatives(fsgrids::dperbspan dperb, fsgrids::dmomentsspan dmoments, const fsgrid::FsStencil &stencil, cuint RKCase, cuint component) override
IonosphereConductivityModel
static enum SBC::Ionosphere::IonosphereConductivityModel conductivityModel
virtual void fieldSolverBoundaryCondBVOLDerivatives(fsgrids::volspan vols, const fsgrid::FsStencil &stencil, cuint component) override
Real earthAngularVelocity
virtual void fieldSolverBoundaryCondHallElectricField(fsgrids::ehallspan ehall, const fsgrid::FsStencil &stencil, cuint component) override
static bool solverUseMinimumResidualVariant
virtual void fieldSolverBoundaryCondGradPeElectricField(fsgrids::egradpespan EGradPe, const fsgrid::FsStencil &stencil, cuint component) override
static Real solverMaxErrorGrowthFactor
virtual void generateTemplateCell()
fsgrid::FsGrid< FS_STENCIL_WIDTH > FieldSolverGrid
std::function< double(double x, double y, double z, coordinate component, unsigned int derivative, coordinate dcomponent)> FieldFunction
IonosphereBoundaryVDFmode
static constexpr Real productionMinAccEnergy
static constexpr Real ion_electron_T_ratio
static constexpr Real productionMaxAccEnergy
static constexpr int productionNumAccEnergies
static constexpr int productionNumParticleEnergies
static constexpr Real productionMaxTemperature
SphericalTriGrid ionosphereGrid
static constexpr Real productionMinTemperature
IonosphereBoundaryVDFmode boundaryVDFmode
static const int MAX_DEPENDING_NODES
static constexpr int productionNumTemperatures
static const int MAX_TOUCHING_ELEMENTS
std::span< std::array< Real, fsgrids::bfield::N_BFIELD > > perbspan
std::span< const std::array< Real, bgbfield::N_BGB > > constbgbspan
std::span< std::array< Real, fsgrids::moments::N_MOMENTS > > momentsspan
std::span< std::array< Real, fsgrids::egradpe::N_EGRADPE > > egradpespan
std::span< std::array< Real, fsgrids::dmoments::N_DMOMENTS > > dmomentsspan
std::span< technical > technicalspan
std::span< std::array< Real, bgbfield::N_BGB > > bgbspan
std::span< std::array< Real, fsgrids::dperb::N_DPERB > > dperbspan
std::span< const technical > consttechnicalspan
std::span< std::array< Real, fsgrids::efield::N_EFIELD > > efieldspan
std::span< std::array< Real, fsgrids::volfields::N_VOL > > volspan
std::span< std::array< Real, fsgrids::ehall::N_EHALL > > ehallspan
std::span< const std::array< Real, fsgrids::dperb::N_DPERB > > constdperbspan
static const Real recombAlpha
std::array< uint32_t, 3 > corners
std::array< Real, 3 > xMapped
std::array< uint32_t, MAX_DEPENDING_NODES > dependingNodes
std::array< Real, MAX_DEPENDING_NODES > dependingCoeffs
std::array< iSolverReal, N_IONOSPHERE_PARAMETERS > parameters
std::array< uint32_t, MAX_TOUCHING_ELEMENTS > touchingElements
Real electronTemperature()
std::array< Real, MAX_DEPENDING_NODES > transposedCoeffs
std::array< Real, 9 > sigmaAverage(uint elementIndex)
std::tuple< Eigen::Vector3d, Eigen::Vector3d > connectingSegmentLengths(uint32_t el1, uint32_t el2)
void mapDownBoundaryData(fsgrids::perbspan perb, fsgrids::constdperbspan dperb, fsgrids::momentsspan moments, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
void initializeSphericalFibonacci(int n)
void initializeOctahedron()
Real lookupProductionValue(int heightindex, Real energy_keV, Real temperature_keV)
std::array< Real, 3 > BGB
std::array< std::array< std::array< Real, productionNumTemperatures >, productionNumAccEnergies >, numAtmosphereLevels > productionTable
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)
void setDipoleField(const FieldFunction &dipole)
std::array< Real, 3 > mappedElementArea(uint32_t elementIndex)
void calculatePrecipitation()
void setConstantBackgroundField(const std::array< Real, 3 > B)
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
FieldFunction dipoleField
Eigen::Vector3d commonEdgeMidpoint(uint32_t el1, uint32_t el2)
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
void addAllMatrixDependencies(uint nodeIndex)
void subdivideElement(uint32_t e)
Real dualPolygonArea(uint gridNode)
int32_t findElementNeighbour(uint32_t e, int n1, int n2)
void initializeTetrahedron()
void updateIonosphereCommunicator(dccrg::Dccrg< SpatialCell, dccrg::Cartesian_Geometry > &mpiGrid, fsgrids::technicalspan technical, FieldSolverGrid &fsgrid)
Real areaInDualPolygon(uint gridNode, uint gridElem)
std::vector< Node > nodes
IonosphereSolverGaugeFixing
Eigen::Vector3d elementNormal(uint32_t el)
void updateConnectivity()
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)
void stitchRefinementInterfaces()
std::vector< Element > elements
IonosphereIonizationModel
enum SBC::SphericalTriGrid::IonosphereSolverGaugeFixing gaugeFixing
enum SBC::SphericalTriGrid::IonosphereIonizationModel ionizationModel
void initializeIcosahedron()
Eigen::Vector3d elementBarycentre(uint32_t el)
Real nodeNeighbourArea(uint32_t nodeIndex)
std::array< AtmosphericLayer, numAtmosphereLevels > atmosphere
Real Asolve(uint nodeIndex, int parameter, bool transpose=false)
static constexpr int numAtmosphereLevels
std::vector< Eigen::Vector3d > elementCurlFreeCurrent
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)