Skip to content

Commit 608b059

Browse files
authored
Fixing bug that only applied last field in the list of external field… (#5690)
…s. Changed to add all fields. This bug cropped up during code review and refactoring. I have re-implemented the field accumulations for multiply defined external fields. This was not caught by CI since the cylinder compression test only has a single uniform compression field. --------- Signed-off-by: S. Eric Clark <25495882+clarkse@users.noreply.github.com>
1 parent 263fd58 commit 608b059

File tree

6 files changed

+64
-44
lines changed

6 files changed

+64
-44
lines changed

Examples/Tests/ohm_solver_cylinder_compression/inputs_test_3d_ohm_solver_cylinder_compression_picmi.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ def __init__(self, test, verbose):
9595

9696
RM = np.sqrt(XM**2 + YM**2)
9797

98-
Ax_data = -0.5 * YM * self.dB
99-
Ay_data = 0.5 * XM * self.dB
98+
Ax_data = -0.25 * YM * self.dB
99+
Ay_data = 0.25 * XM * self.dB
100100
Az_data = np.zeros_like(RM)
101101

102102
# Write vector potential to file to exercise field loading via OpenPMD
@@ -261,11 +261,17 @@ def setup_run(self):
261261
#######################################################################
262262
# External Field definition. Sigmoid starting around 2.5 us
263263
A_ext = {
264-
"uniform": {
264+
"uniform_file": {
265265
"read_from_file": True,
266266
"path": "Afield.h5",
267267
"A_time_external_function": "1/(1+exp(5*(1-(t-t0_ramp)*sqrt(2)/tau_ramp)))",
268-
}
268+
},
269+
"uniform_analytical": {
270+
"Ax_external_function": f"-0.25*y*{self.dB}",
271+
"Ay_external_function": f"0.25*x*{self.dB}",
272+
"Az_external_function": "0",
273+
"A_time_external_function": "1/(1+exp(5*(1-(t-t0_ramp)*sqrt(2)/tau_ramp)))",
274+
},
269275
}
270276

271277
self.solver = picmi.HybridPICSolver(

Examples/Tests/ohm_solver_cylinder_compression/inputs_test_rz_ohm_solver_cylinder_compression_picmi.py

+10-4
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ def __init__(self, test, verbose):
9393
Ar_data = np.zeros_like(RM)
9494
Az_data = np.zeros_like(RM)
9595

96-
# Zero padded outside of domain
97-
At_data = 0.5 * RM * self.dB
96+
# Only include half of the compression field here
97+
At_data = 0.25 * RM * self.dB
9898

9999
# Write vector potential to file to exercise field loading via
100100
series = io.Series("Afield.h5", io.Access.create)
@@ -255,11 +255,17 @@ def setup_run(self):
255255
#######################################################################
256256
# External Field definition. Sigmoid starting around 2.5 us
257257
A_ext = {
258-
"uniform": {
258+
"uniform_file": {
259259
"read_from_file": True,
260260
"path": "Afield.h5",
261261
"A_time_external_function": "1/(1+exp(5*(1-(t-t0_ramp)*sqrt(2)/tau_ramp)))",
262-
}
262+
},
263+
"uniform_analytical": {
264+
"Ax_external_function": f"-0.25*y*{self.dB}",
265+
"Ay_external_function": f"0.25*x*{self.dB}",
266+
"Az_external_function": "0",
267+
"A_time_external_function": "1/(1+exp(5*(1-(t-t0_ramp)*sqrt(2)/tau_ramp)))",
268+
},
263269
}
264270

265271
self.solver = picmi.HybridPICSolver(
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
{
22
"lev=0": {
3-
"Bx": 0.5334253070691776,
4-
"By": 0.5318560243634998,
5-
"Bz": 2252.108905639938,
6-
"Ex": 10509838.331420777,
7-
"Ey": 10512676.798857061,
8-
"Ez": 8848.113963901804,
9-
"rho": 384112.2912140536
3+
"Bx": 0.5334251406746063,
4+
"By": 0.5318559382056761,
5+
"Bz": 2252.108858363565,
6+
"Ex": 10509826.248254433,
7+
"Ey": 10512665.210439455,
8+
"Ez": 8848.110632517377,
9+
"rho": 384112.2912140535
1010
},
1111
"ions": {
12-
"particle_momentum_x": 2.161294367543349e-16,
13-
"particle_momentum_y": 2.161870747294985e-16,
14-
"particle_momentum_z": 2.0513400435256855e-16,
15-
"particle_position_x": 769864.202585846,
16-
"particle_position_y": 769908.6569812088,
17-
"particle_position_z": 620721.1900338201,
12+
"particle_momentum_x": 2.1612944051250247e-16,
13+
"particle_momentum_y": 2.1618707843260381e-16,
14+
"particle_momentum_z": 2.0513400435259629e-16,
15+
"particle_position_x": 769864.2025705199,
16+
"particle_position_y": 769908.6569665589,
17+
"particle_position_z": 620721.1900338195,
1818
"particle_weight": 1.008292384042714e+19
1919
}
20-
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
11
{
22
"lev=0": {
3-
"Br": 0.01190012639573578,
4-
"Bt": 0.011313481779415917,
5-
"Bz": 11.684908684984164,
6-
"Er": 154581.58512851578,
7-
"Et": 4798.276941148807,
8-
"Ez": 193.22344271401872,
9-
"rho": 7968.182346905438
3+
"Br": 0.011900125915334049,
4+
"Bt": 0.011313482081775999,
5+
"Bz": 11.684907956225278,
6+
"Er": 154581.64325434464,
7+
"Et": 4797.794963571249,
8+
"Ez": 193.22336541793413,
9+
"rho": 7968.182346878508
1010
},
1111
"ions": {
12-
"particle_momentum_x": 3.1125151786241107e-18,
13-
"particle_momentum_y": 3.119385993047207e-18,
14-
"particle_momentum_z": 3.0289560038617916e-18,
15-
"particle_position_x": 13628.662686419664,
16-
"particle_position_y": 2285.6952310457755,
17-
"particle_theta": 115055.48935725243,
12+
"particle_momentum_x": 3.112515238421571e-18,
13+
"particle_momentum_y": 3.1193860531312334e-18,
14+
"particle_momentum_z": 3.0289560038609835e-18,
15+
"particle_position_x": 13628.662686094893,
16+
"particle_position_y": 2285.6952310456554,
17+
"particle_theta": 115055.48935714104,
1818
"particle_weight": 2.525423582445981e+18
1919
}
2020
}

Source/FieldSolver/FiniteDifferenceSolver/HybridPICModel/ExternalVectorPotential.H

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ public:
8686
void CalculateExternalCurlA (std::string& coil_name);
8787

8888
AMREX_FORCE_INLINE
89-
void PopulateExternalFieldFromVectorPotential (
89+
void AddExternalFieldFromVectorPotential (
9090
ablastr::fields::VectorField const& dstField,
9191
amrex::Real scale_factor,
9292
ablastr::fields::VectorField const& srcField,

Source/FieldSolver/FiniteDifferenceSolver/HybridPICModel/ExternalVectorPotential.cpp

+16-8
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ ExternalVectorPotential::ReadParameters ()
4646
m_A_external.resize(m_nFields);
4747

4848
m_A_ext_time_function.resize(m_nFields);
49-
for (std::string & field_time : m_A_ext_time_function) {field_time = "1.0"; }
49+
for (std::string & field_time : m_A_ext_time_function) { field_time = "1.0"; }
5050

5151
m_A_external_time_parser.resize(m_nFields);
5252
m_A_time_scale.resize(m_nFields);
@@ -272,7 +272,7 @@ ExternalVectorPotential::CalculateExternalCurlA (std::string& coil_name)
272272

273273
AMREX_FORCE_INLINE
274274
void
275-
ExternalVectorPotential::PopulateExternalFieldFromVectorPotential (
275+
ExternalVectorPotential::AddExternalFieldFromVectorPotential (
276276
ablastr::fields::VectorField const& dstField,
277277
amrex::Real scale_factor,
278278
ablastr::fields::VectorField const& srcField,
@@ -313,21 +313,21 @@ ExternalVectorPotential::PopulateExternalFieldFromVectorPotential (
313313
// Skip field update in the embedded boundaries
314314
if (update_Fx_arr && update_Fx_arr(i, j, k) == 0) { return; }
315315

316-
Fx(i,j,k) = scale_factor * Sx(i,j,k);
316+
Fx(i,j,k) += scale_factor * Sx(i,j,k);
317317
},
318318

319319
[=] AMREX_GPU_DEVICE (int i, int j, int k){
320320
// Skip field update in the embedded boundaries
321321
if (update_Fy_arr && update_Fy_arr(i, j, k) == 0) { return; }
322322

323-
Fy(i,j,k) = scale_factor * Sy(i,j,k);
323+
Fy(i,j,k) += scale_factor * Sy(i,j,k);
324324
},
325325

326326
[=] AMREX_GPU_DEVICE (int i, int j, int k){
327327
// Skip field update in the embedded boundaries
328328
if (update_Fz_arr && update_Fz_arr(i, j, k) == 0) { return; }
329329

330-
Fz(i,j,k) = scale_factor * Sz(i,j,k);
330+
Fz(i,j,k) += scale_factor * Sz(i,j,k);
331331
}
332332
);
333333
}
@@ -339,12 +339,20 @@ ExternalVectorPotential::UpdateHybridExternalFields (const amrex::Real t, const
339339
using ablastr::fields::Direction;
340340
auto& warpx = WarpX::GetInstance();
341341

342-
343342
ablastr::fields::MultiLevelVectorField B_ext =
344343
warpx.m_fields.get_mr_levels_alldirs(FieldType::hybrid_B_fp_external, warpx.finestLevel());
345344
ablastr::fields::MultiLevelVectorField E_ext =
346345
warpx.m_fields.get_mr_levels_alldirs(FieldType::hybrid_E_fp_external, warpx.finestLevel());
347346

347+
// Zero E and B external fields prior to accumulating external fields
348+
for (int lev = 0; lev <= warpx.finestLevel(); ++lev) {
349+
for (int idir = 0; idir < 3; ++idir) {
350+
B_ext[lev][Direction{idir}]->setVal(0.0_rt);
351+
E_ext[lev][Direction{idir}]->setVal(0.0_rt);
352+
}
353+
}
354+
355+
// Iterate over external fields and add together with individual time functions.
348356
for (int i = 0; i < m_nFields; ++i) {
349357
const std::string Aext_field = m_field_names[i] + std::string{"_Aext"};
350358
const std::string curlAext_field = m_field_names[i] + std::string{"_curlAext"};
@@ -363,8 +371,8 @@ ExternalVectorPotential::UpdateHybridExternalFields (const amrex::Real t, const
363371
warpx.m_fields.get_mr_levels_alldirs(curlAext_field, warpx.finestLevel());
364372

365373
for (int lev = 0; lev <= warpx.finestLevel(); ++lev) {
366-
PopulateExternalFieldFromVectorPotential(E_ext[lev], scale_factor_E, A_ext[lev], warpx.GetEBUpdateEFlag()[lev]);
367-
PopulateExternalFieldFromVectorPotential(B_ext[lev], scale_factor_B, curlA_ext[lev], warpx.GetEBUpdateBFlag()[lev]);
374+
AddExternalFieldFromVectorPotential(E_ext[lev], scale_factor_E, A_ext[lev], warpx.GetEBUpdateEFlag()[lev]);
375+
AddExternalFieldFromVectorPotential(B_ext[lev], scale_factor_B, curlA_ext[lev], warpx.GetEBUpdateBFlag()[lev]);
368376

369377
for (int idir = 0; idir < 3; ++idir) {
370378
E_ext[lev][Direction{idir}]->FillBoundary(warpx.Geom(lev).periodicity());

0 commit comments

Comments
 (0)