Skip to content

Commit b94a808

Browse files
committed
divergence free refluxing
BROKEN adding the patch refine strategy for the magnetic field 3D for magnetic regriding the path of the SAMRAI cleanup and comments back to NaNs 3d fixes + refactoring back to iterating on the fine field box (in mpi the fine_box might be different from the patch box) pr comments initial commit, E accumulation BROKEN refluxing without divB new magnetic field refinement implementing Toth and Roe (2002) adding the patch refine strategy for the magnetic field forcing even number of ghost cells 3D for magnetic regriding the path of the SAMRAI cleanup and comments back to NaNs 3d fixes + refactoring back to iterating on the fine field box (in mpi the fine_box might be different from the patch box) pr comments initial commit, E accumulation BROKEN adding the patch refine strategy for the magnetic field 3D for magnetic regriding the path of the SAMRAI cleanup and comments back to NaNs 3d fixes + refactoring back to iterating on the fine field box (in mpi the fine_box might be different from the patch box) pr comments BROKEN refluxing without divB rebase master
1 parent 3dbc7be commit b94a808

17 files changed

+560
-145
lines changed

src/amr/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ set( SOURCES_INC
1212
data/field/coarsening/coarsen_weighter.hpp
1313
data/field/coarsening/default_field_coarsener.hpp
1414
data/field/coarsening/magnetic_field_coarsener.hpp
15+
data/field/coarsening/flux_sum_coarsener.hpp
1516
data/field/field_data.hpp
1617
data/field/field_data_factory.hpp
1718
data/field/field_geometry.hpp
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
#ifndef PHARE_FLUX_SUM_COARSENER
2+
#define PHARE_FLUX_SUM_COARSENER
3+
4+
#include "core/data/grid/gridlayoutdefs.hpp"
5+
#include "core/utilities/constants.hpp"
6+
#include "amr/resources_manager/amr_utils.hpp"
7+
8+
9+
#include <SAMRAI/hier/Box.h>
10+
#include <stdexcept>
11+
12+
namespace PHARE::amr
13+
{
14+
using core::dirX;
15+
using core::dirY;
16+
using core::dirZ;
17+
/** @brief This class gives an operator() that performs the coarsening of N fine nodes onto a
18+
* given coarse node
19+
*
20+
* A MagneticFieldCoarsener object is created each time the refine() method of the
21+
* FieldCoarsenOperator is called and its operator() is called for each coarse index.
22+
* It is the default coarsening policy and used for any field that does not come with
23+
* specific constraints (such as conserving some property in the coarsening process).
24+
*
25+
*
26+
* This coarsening operation is defined so to conserve the magnetic flux.
27+
* This is done by assigning to a magnetic field component on a coarse face, the average
28+
* of the enclosed fine faces
29+
*
30+
*/
31+
template<std::size_t dimension>
32+
class FluxSumCoarsener
33+
{
34+
public:
35+
FluxSumCoarsener(std::array<core::QtyCentering, dimension> const centering,
36+
SAMRAI::hier::Box const& sourceBox, SAMRAI::hier::Box const& destinationBox,
37+
SAMRAI::hier::IntVector const& ratio)
38+
: centering_{centering}
39+
, sourceBox_{sourceBox}
40+
, destinationBox_{destinationBox}
41+
42+
{
43+
}
44+
45+
template<typename FieldT>
46+
void operator()(FieldT const& fineField, FieldT& coarseField,
47+
core::Point<int, dimension> coarseIndex)
48+
{
49+
// For the moment we only take the case of field with the same centering
50+
TBOX_ASSERT(fineField.physicalQuantity() == coarseField.physicalQuantity());
51+
52+
core::Point<int, dimension> fineStartIndex;
53+
54+
fineStartIndex[dirX] = coarseIndex[dirX] * this->ratio_;
55+
56+
if constexpr (dimension > 1)
57+
{
58+
fineStartIndex[dirY] = coarseIndex[dirY] * this->ratio_;
59+
if constexpr (dimension > 2)
60+
{
61+
fineStartIndex[dirZ] = coarseIndex[dirZ] * this->ratio_;
62+
}
63+
}
64+
65+
fineStartIndex = AMRToLocal(fineStartIndex, sourceBox_);
66+
coarseIndex = AMRToLocal(coarseIndex, destinationBox_);
67+
68+
if constexpr (dimension == 1)
69+
{
70+
if (centering_[dirX] == core::QtyCentering::dual) // ex
71+
{
72+
coarseField(coarseIndex[dirX])
73+
= 0.5 * (fineField(fineStartIndex[dirX] + 1) + fineField(fineStartIndex[dirX]));
74+
}
75+
else if (centering_[dirX] == core::QtyCentering::primal) // ey, ez
76+
{
77+
coarseField(coarseIndex[dirX]) = fineField(fineStartIndex[dirX]);
78+
}
79+
}
80+
81+
if constexpr (dimension == 2)
82+
{
83+
if (centering_[dirX] == core::QtyCentering::dual
84+
and centering_[dirY] == core::QtyCentering::primal) // ex
85+
{
86+
coarseField(coarseIndex[dirX], coarseIndex[dirY])
87+
= 0.5
88+
* (fineField(fineStartIndex[dirX], fineStartIndex[dirY])
89+
+ fineField(fineStartIndex[dirX] + 1, fineStartIndex[dirY]));
90+
}
91+
else if (centering_[dirX] == core::QtyCentering::primal
92+
and centering_[dirY] == core::QtyCentering::dual) // ey
93+
{
94+
coarseField(coarseIndex[dirX], coarseIndex[dirY])
95+
= 0.5
96+
* (fineField(fineStartIndex[dirX], fineStartIndex[dirY])
97+
+ fineField(fineStartIndex[dirX], fineStartIndex[dirY] + 1));
98+
}
99+
else if (centering_[dirX] == core::QtyCentering::primal
100+
and centering_[dirY] == core::QtyCentering::primal) // ez
101+
{
102+
coarseField(coarseIndex[dirX], coarseIndex[dirY])
103+
= fineField(fineStartIndex[dirX], fineStartIndex[dirY]);
104+
}
105+
else
106+
{
107+
throw std::runtime_error("no electric field should end up here");
108+
}
109+
}
110+
else if constexpr (dimension == 3)
111+
{
112+
if (centering_[dirX] == core::QtyCentering::dual
113+
and centering_[dirY] == core::QtyCentering::primal
114+
and centering_[dirZ] == core::QtyCentering::primal) // ex
115+
{
116+
coarseField(coarseIndex[dirX], coarseIndex[dirY], coarseIndex[dirZ])
117+
= 0.5
118+
* (fineField(fineStartIndex[dirX], fineStartIndex[dirY], fineStartIndex[dirZ])
119+
+ fineField(fineStartIndex[dirX] + 1, fineStartIndex[dirY],
120+
fineStartIndex[dirZ]));
121+
}
122+
else if (centering_[dirX] == core::QtyCentering::primal
123+
and centering_[dirY] == core::QtyCentering::dual
124+
and centering_[dirZ] == core::QtyCentering::primal) // ey
125+
{
126+
coarseField(coarseIndex[dirX], coarseIndex[dirY], coarseIndex[dirZ])
127+
= 0.5
128+
* (fineField(fineStartIndex[dirX], fineStartIndex[dirY], fineStartIndex[dirZ])
129+
+ fineField(fineStartIndex[dirX], fineStartIndex[dirY] + 1,
130+
fineStartIndex[dirZ]));
131+
}
132+
else if (centering_[dirX] == core::QtyCentering::primal
133+
and centering_[dirY] == core::QtyCentering::primal
134+
and centering_[dirZ] == core::QtyCentering::dual) // ez
135+
{
136+
coarseField(coarseIndex[dirX], coarseIndex[dirY], coarseIndex[dirZ])
137+
= 0.5
138+
* (fineField(fineStartIndex[dirX], fineStartIndex[dirY], fineStartIndex[dirZ])
139+
+ fineField(fineStartIndex[dirX], fineStartIndex[dirY],
140+
fineStartIndex[dirZ] + 1));
141+
}
142+
else
143+
{
144+
throw std::runtime_error("no electric field should end up here");
145+
}
146+
}
147+
}
148+
149+
private:
150+
std::array<core::QtyCentering, dimension> const centering_;
151+
SAMRAI::hier::Box const sourceBox_;
152+
SAMRAI::hier::Box const destinationBox_;
153+
static int constexpr ratio_ = 2;
154+
};
155+
156+
} // namespace PHARE::amr
157+
158+
#endif

src/amr/data/field/coarsening/magnetic_field_coarsener.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ class MagneticFieldCoarsener
7070
coarseIndex = AMRToLocal(coarseIndex, destinationBox_);
7171

7272
// the following kinda assumes where B is, i.e. Yee layout centering
73-
// as it only does faces pirmal-dual, dual-primal and dual-dual
73+
// as it only does faces primal-dual, dual-primal and dual-dual
7474

7575
if constexpr (dimension == 1)
7676
{

src/amr/data/field/refine/magnetic_refine_patch_strategy.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ class MagneticRefinePatchStrategy : public SAMRAI::xfer::RefinePatchStrategy
6767
{
6868
}
6969

70-
// We compute the values of the new fine magnetic faces using what was already refined, ie the
71-
// values on the old coarse faces.
70+
// We compute the values of the new fine magnetic faces using what was already refined, ie
71+
// the values on the old coarse faces.
7272
void postprocessRefine(SAMRAI::hier::Patch& fine, SAMRAI::hier::Patch const& coarse,
7373
SAMRAI::hier::Box const& fine_box,
7474
SAMRAI::hier::IntVector const& ratio) override

src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,15 @@
1010
#include "core/utilities/index/index.hpp"
1111
#include "refiner_pool.hpp"
1212
#include "synchronizer_pool.hpp"
13+
#include "amr/data/field/coarsening/field_coarsen_operator.hpp"
1314
#include "amr/data/field/coarsening/default_field_coarsener.hpp"
1415
#include "amr/data/field/coarsening/magnetic_field_coarsener.hpp"
16+
#include "amr/data/field/coarsening/flux_sum_coarsener.hpp"
1517
#include "amr/data/field/refine/field_refiner.hpp"
1618
#include "amr/data/field/refine/magnetic_field_refiner.hpp"
1719
#include "amr/data/field/refine/electric_field_refiner.hpp"
1820
#include "amr/data/field/time_interpolate/field_linear_time_interpolate.hpp"
1921
#include "amr/data/field/refine/field_refine_operator.hpp"
20-
#include "amr/data/field/coarsening/field_coarsen_operator.hpp"
2122
#include "amr/messengers/messenger_info.hpp"
2223
#include "amr/messengers/hybrid_messenger_info.hpp"
2324
#include "amr/messengers/hybrid_messenger_strategy.hpp"
@@ -35,6 +36,8 @@
3536

3637
#include "SAMRAI/xfer/RefineAlgorithm.h"
3738
#include "SAMRAI/xfer/RefineSchedule.h"
39+
#include "SAMRAI/xfer/CoarsenAlgorithm.h"
40+
#include "SAMRAI/xfer/CoarsenSchedule.h"
3841
#include "SAMRAI/xfer/BoxGeometryVariableFillPattern.h"
3942

4043

@@ -99,6 +102,7 @@ namespace amr
99102
using BaseCoarsenOp = FieldCoarsenOperator<GridLayoutT, GridT, Policy>;
100103
using MagneticCoarsenOp = BaseCoarsenOp<MagneticFieldCoarsener<dimension>>;
101104
using DefaultCoarsenOp = BaseCoarsenOp<DefaultFieldCoarsener<dimension>>;
105+
using FluxSumCoarsenOp = BaseCoarsenOp<FluxSumCoarsener<dimension>>;
102106

103107
public:
104108
static inline std::string const stratName = "HybridModel-HybridModel";
@@ -185,6 +189,42 @@ namespace amr
185189
BalgoNode.registerRefine(*bz_id, *bz_id, *bz_id, BfieldNodeRefineOp_,
186190
zVariableFillPattern);
187191

192+
// refluxing
193+
// we first want to coarsen the flux sum onto the coarser level
194+
auto ex_reflux_id = resourcesManager_->getID(hybridInfo->refluxElectric.xName);
195+
auto ey_reflux_id = resourcesManager_->getID(hybridInfo->refluxElectric.yName);
196+
auto ez_reflux_id = resourcesManager_->getID(hybridInfo->refluxElectric.zName);
197+
198+
auto ex_fluxsum_id = resourcesManager_->getID(hybridInfo->fluxSumElectric.xName);
199+
auto ey_fluxsum_id = resourcesManager_->getID(hybridInfo->fluxSumElectric.yName);
200+
auto ez_fluxsum_id = resourcesManager_->getID(hybridInfo->fluxSumElectric.zName);
201+
202+
if (!ex_reflux_id or !ey_reflux_id or !ez_reflux_id or !ex_fluxsum_id or !ey_fluxsum_id
203+
or !ez_fluxsum_id)
204+
{
205+
throw std::runtime_error(
206+
"HybridHybridMessengerStrategy: missing electric field variable IDs");
207+
}
208+
209+
RefluxAlgo.registerCoarsen(*ex_reflux_id, *ex_fluxsum_id, fluxSumCoarseningOp_,
210+
xVariableFillPattern);
211+
RefluxAlgo.registerCoarsen(*ey_reflux_id, *ey_fluxsum_id, fluxSumCoarseningOp_,
212+
yVariableFillPattern);
213+
RefluxAlgo.registerCoarsen(*ez_reflux_id, *ez_fluxsum_id, fluxSumCoarseningOp_,
214+
zVariableFillPattern);
215+
216+
// we then need to refill the ghosts so that they agree with the newly refluxed cells
217+
218+
GhostRefluxedAlgo.registerRefine(*ex_reflux_id, *ex_reflux_id, *ex_reflux_id,
219+
EfieldRefineOp_, xVariableFillPattern);
220+
221+
GhostRefluxedAlgo.registerRefine(*ey_reflux_id, *ey_reflux_id, *ey_reflux_id,
222+
EfieldRefineOp_, yVariableFillPattern);
223+
224+
GhostRefluxedAlgo.registerRefine(*ez_reflux_id, *ez_reflux_id, *ez_reflux_id,
225+
EfieldRefineOp_, zVariableFillPattern);
226+
227+
188228
registerGhostComms_(hybridInfo);
189229
registerInitComms(hybridInfo);
190230
registerSyncComms(hybridInfo);
@@ -210,6 +250,9 @@ namespace amr
210250
magGhostsRefineSchedules[levelNumber] = Balgo.createSchedule(
211251
level, levelNumber - 1, hierarchy, &magneticRefinePatchStrategy_);
212252

253+
// technically not needed for finest
254+
ghostRefluxedSchedules[levelNumber] = GhostRefluxedAlgo.createSchedule(level);
255+
213256
elecSharedNodesRefiners_.registerLevel(hierarchy, level);
214257
currentSharedNodesRefiners_.registerLevel(hierarchy, level);
215258

@@ -227,9 +270,14 @@ namespace amr
227270
// TODO this 'if' may not be OK if L0 is regrided
228271
if (levelNumber != rootLevelNumber)
229272
{
273+
// refluxing
274+
auto const& coarseLevel = hierarchy->getPatchLevel(levelNumber - 1);
275+
refluxSchedules[levelNumber] = RefluxAlgo.createSchedule(coarseLevel, level);
276+
230277
// those are for refinement
231278
magInitRefineSchedules[levelNumber] = Balgo.createSchedule(
232279
level, nullptr, levelNumber - 1, hierarchy, &magneticRefinePatchStrategy_);
280+
233281
electricInitRefiners_.registerLevel(hierarchy, level);
234282
domainParticlesRefiners_.registerLevel(hierarchy, level);
235283
lvlGhostPartOldRefiners_.registerLevel(hierarchy, level);
@@ -544,6 +592,7 @@ namespace amr
544592

545593

546594

595+
547596
/**
548597
* @brief prepareStep is the concrete implementation of the
549598
* HybridMessengerStrategy::prepareStep method For hybrid-Hybrid communications.
@@ -564,8 +613,7 @@ namespace amr
564613
for (auto& patch : level)
565614
{
566615
auto dataOnPatch = resourcesManager_->setOnPatch(
567-
*patch, hybridModel.state.electromag, hybridModel.state.J,
568-
hybridModel.state.ions, Jold_, NiOld_, ViOld_);
616+
*patch, hybridModel.state.J, hybridModel.state.ions, Jold_, NiOld_, ViOld_);
569617

570618
resourcesManager_->setTime(Jold_, *patch, currentTime);
571619
resourcesManager_->setTime(NiOld_, *patch, currentTime);
@@ -623,12 +671,20 @@ namespace amr
623671
PHARE_LOG_LINE_STR("synchronizing level " + std::to_string(levelNumber));
624672

625673
// call coarsning schedules...
626-
magnetoSynchronizers_.sync(levelNumber);
674+
// magnetoSynchronizers_.sync(levelNumber);
627675
electroSynchronizers_.sync(levelNumber);
628676
densitySynchronizers_.sync(levelNumber);
629677
ionBulkVelSynchronizers_.sync(levelNumber);
630678
}
631679

680+
681+
void reflux(int const coarserLevelNumber, int const fineLevelNumber,
682+
double const syncTime) override
683+
{
684+
refluxSchedules[fineLevelNumber]->coarsenData();
685+
ghostRefluxedSchedules[coarserLevelNumber]->fillData(syncTime);
686+
}
687+
632688
// after coarsening, domain nodes have been updated and therefore patch ghost nodes
633689
// will probably stop having the exact same value as their overlapped neighbor
634690
// domain node we thus fill ghost nodes. note that we first fill shared border nodes
@@ -654,7 +710,7 @@ namespace amr
654710
// level border with next coarser model B would invalidate divB on the first
655711
// fine domain cell since its border face only received a fraction of the
656712
// induction that has occured on the shared coarse face.
657-
magPatchGhostsRefineSchedules[levelNumber]->fillData(time);
713+
// magPatchGhostsRefineSchedules[levelNumber]->fillData(time);
658714
elecGhostsRefiners_.fill(hybridModel.state.electromag.E, levelNumber, time);
659715
rhoGhostsRefiners_.fill(levelNumber, time);
660716
velGhostsRefiners_.fill(hybridModel.state.ions.velocity(), levelNumber, time);
@@ -973,7 +1029,6 @@ namespace amr
9731029

9741030

9751031

976-
9771032
VecFieldT Jold_{stratName + "_Jold", core::HybridQuantity::Vector::J};
9781033
VecFieldT ViOld_{stratName + "_VBulkOld", core::HybridQuantity::Vector::V};
9791034
FieldT NiOld_{stratName + "_NiOld", core::HybridQuantity::Scalar::rho};
@@ -1011,6 +1066,10 @@ namespace amr
10111066
std::map<int, std::shared_ptr<SAMRAI::xfer::RefineSchedule>> magPatchGhostsRefineSchedules;
10121067
std::map<int, std::shared_ptr<SAMRAI::xfer::RefineSchedule>> magSharedNodeRefineSchedules;
10131068

1069+
SAMRAI::xfer::CoarsenAlgorithm RefluxAlgo{SAMRAI::tbox::Dimension{dimension}};
1070+
SAMRAI::xfer::RefineAlgorithm GhostRefluxedAlgo;
1071+
std::map<int, std::shared_ptr<SAMRAI::xfer::CoarsenSchedule>> refluxSchedules;
1072+
std::map<int, std::shared_ptr<SAMRAI::xfer::RefineSchedule>> ghostRefluxedSchedules;
10141073

10151074
//! store refiners for electric fields that need ghosts to be filled
10161075
SharedNodeRefinerPool elecSharedNodesRefiners_{resourcesManager_};
@@ -1069,6 +1128,7 @@ namespace amr
10691128
using CoarsenOperator_ptr = std::shared_ptr<SAMRAI::hier::CoarsenOperator>;
10701129
CoarsenOperator_ptr fieldCoarseningOp_{std::make_shared<DefaultCoarsenOp>()};
10711130
CoarsenOperator_ptr magneticCoarseningOp_{std::make_shared<MagneticCoarsenOp>()};
1131+
CoarsenOperator_ptr fluxSumCoarseningOp_{std::make_shared<FluxSumCoarsenOp>()};
10721132

10731133
MagneticRefinePatchStrategy<ResourcesManagerT, FieldDataT> magneticRefinePatchStrategy_{
10741134
*resourcesManager_};

src/amr/messengers/hybrid_messenger.hpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,14 @@ namespace amr
190190

191191
void synchronize(SAMRAI::hier::PatchLevel& level) override { strat_->synchronize(level); }
192192

193+
194+
void reflux(int const coarserLevelNumber, int const fineLevelNumber,
195+
double const syncTime) override
196+
{
197+
strat_->reflux(coarserLevelNumber, fineLevelNumber, syncTime);
198+
}
199+
200+
193201
void postSynchronize(IPhysicalModel& model, SAMRAI::hier::PatchLevel& level,
194202
double const time) override
195203
{
@@ -345,7 +353,7 @@ namespace amr
345353
virtual ~HybridMessenger() = default;
346354

347355
private:
348-
const std::unique_ptr<stratT> strat_;
356+
std::unique_ptr<stratT> const strat_;
349357
};
350358

351359

src/amr/messengers/hybrid_messenger_info.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@ namespace amr
6767
std::vector<VecFieldNames> ghostCurrent;
6868
std::vector<VecFieldNames> ghostBulkVelocity;
6969

70+
// below are the descriptions of the electric field that we use in the refluxing
71+
VecFieldNames refluxElectric;
72+
VecFieldNames fluxSumElectric;
73+
7074
virtual ~HybridMessengerInfo() = default;
7175
};
7276

0 commit comments

Comments
 (0)