Skip to content

Commit 6be87d6

Browse files
Adding support for pml in domain for multiple patches (#4632)
* this works only on single proc, but lifts the assumption of single patch for do pml in domain * fix cbl * building reduced ba and cba * Removing print statements * removing comment * assert that box length must be greater than size of pml when its grown inwards * same assertion for box length for coarse grid * simplified_list and no need for assert in coarse, but if fine works, coarse should * boxlist instead of simplified list * comments * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * CI test for double patch with particles entering and leaving pml inside the patch * checksum for new particles in pml 2d mr test with double patch * renaming plt to diag1 again * include level 0 maxfield to capture no j damping effect * removing incorect comment about heavy paritcle in input --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent 5e66d0e commit 6be87d6

File tree

5 files changed

+136
-50
lines changed

5 files changed

+136
-50
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#!/usr/bin/env python3
2+
3+
# Copyright 2019-2020 Luca Fedeli, Maxence Thevenet, Remi Lehe
4+
#
5+
#
6+
# This file is part of WarpX.
7+
#
8+
# License: BSD-3-Clause-LBNL
9+
10+
"""
11+
This script tests the absorption of particles in the PML.
12+
13+
The input file inputs_2d/inputs is used: it features a positive and a
14+
negative particle, going in opposite direction and eventually
15+
leaving the box. This script tests that the field in the box
16+
is close to 0 once the particles have left. With regular
17+
PML, this test fails, since the particles leave a spurious
18+
charge, with associated fields, behind them.
19+
"""
20+
import os
21+
import sys
22+
23+
import yt
24+
25+
yt.funcs.mylog.setLevel(0)
26+
sys.path.insert(1, '../../../../warpx/Regression/Checksum/')
27+
import checksumAPI
28+
29+
# Open plotfile specified in command line
30+
filename = sys.argv[1]
31+
ds = yt.load( filename )
32+
33+
# Check that the field is low enough
34+
ad0 = ds.covering_grid(level=0, left_edge=ds.domain_left_edge, dims=ds.domain_dimensions)
35+
Ex_array_lev0 = ad0[('mesh','Ex')].to_ndarray()
36+
Ey_array_lev0 = ad0[('mesh','Ey')].to_ndarray()
37+
Ez_array_lev0 = ad0[('mesh','Ez')].to_ndarray()
38+
max_Efield_lev0 = max(Ex_array_lev0.max(), Ey_array_lev0.max(), Ez_array_lev0.max())
39+
print( "max_Efield level0 = %s" %max_Efield_lev0 )
40+
41+
ad1 = ds.covering_grid(level=1, left_edge=ds.domain_left_edge, dims=ds.domain_dimensions)
42+
Ex_array_lev1 = ad1[('mesh','Ex')].to_ndarray()
43+
Ey_array_lev1 = ad1[('mesh','Ey')].to_ndarray()
44+
Ez_array_lev1 = ad1[('mesh','Ez')].to_ndarray()
45+
max_Efield_lev1 = max(Ex_array_lev1.max(), Ey_array_lev1.max(), Ez_array_lev1.max())
46+
print( "max_Efield level1 = %s" %max_Efield_lev1 )
47+
48+
# The field associated with the particle does not have
49+
# the same amplitude in 2d and 3d
50+
if ds.dimensionality == 2:
51+
if ds.max_level == 0:
52+
tolerance_abs = 0.0003
53+
elif ds.max_level == 1:
54+
tolerance_abs = 0.0006
55+
elif ds.dimensionality == 3:
56+
if ds.max_level == 0:
57+
tolerance_abs = 10
58+
elif ds.max_level == 1:
59+
tolerance_abs = 110
60+
else:
61+
raise ValueError("Unknown dimensionality")
62+
63+
print("tolerance_abs: " + str(tolerance_abs))
64+
assert max_Efield_lev0 < tolerance_abs
65+
assert max_Efield_lev1 < tolerance_abs
66+
67+
test_name = os.path.split(os.getcwd())[1]
68+
checksumAPI.evaluate_checksum(test_name, filename)

Examples/Tests/particles_in_pml/inputs_mr_2d

+7-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
max_step = 200
1+
max_step = 300
22
amr.n_cell = 128 128
33

44
amr.blocking_factor = 16
5-
amr.max_grid_size = 1024
5+
amr.max_grid_size = 64
66
amr.max_level = 1
77

88
# Geometry
99
geometry.dims = 2
1010
geometry.prob_lo = -32.e-6 -32.e-6 # physical domain
1111
geometry.prob_hi = 32.e-6 32.e-6
12-
warpx.fine_tag_lo = -8.e-6 -8.e-6 # physical domain
13-
warpx.fine_tag_hi = 8.e-6 8.e-6
12+
warpx.ref_patch_function(x,y,z) = " ((x > -16.e-6)*(x<-10.e-6) + (x > 9.e-6)*(x<16.e-6))*(z>-8.e-6)*(z<8.e-6)"
1413

1514
# Boundary condition
1615
boundary.field_lo = pml pml pml
@@ -38,14 +37,14 @@ particles.species_names = electron proton
3837
electron.charge = -q_e
3938
electron.mass = m_e
4039
electron.injection_style = "singleparticle"
41-
electron.single_particle_pos = 0. 0. 0.
40+
electron.single_particle_pos = -12.e-6 0. 0.
4241
electron.single_particle_u = 2. 0. 0.
4342
electron.single_particle_weight = 1.
4443

4544
proton.charge = q_e
46-
proton.mass = m_p # Very heavy ; should not move
45+
proton.mass = m_p
4746
proton.injection_style = "singleparticle"
48-
proton.single_particle_pos = 0. 0. 0.
47+
proton.single_particle_pos = -12.e-6 0. 0.
4948
proton.single_particle_u = -2. 0. 0.
5049
proton.single_particle_weight = 1.
5150

@@ -54,6 +53,6 @@ algo.particle_shape = 1
5453

5554
# Diagnostics
5655
diagnostics.diags_names = diag1
57-
diag1.intervals = 200
56+
diag1.intervals = 300
5857
diag1.diag_type = Full
5958
diag1.fields_to_plot = Ex Ey Ez Bx By Bz jx jy jz

Regression/Checksum/benchmarks_json/particles_in_pml_2d_MR.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
{
22
"lev=0": {
33
"Bx": 0.0,
4-
"By": 3.578051588629885e-09,
4+
"By": 1.959394057951299e-09,
55
"Bz": 0.0,
6-
"Ex": 1.9699822913484977,
6+
"Ex": 1.2177330062543195,
77
"Ey": 0.0,
8-
"Ez": 0.5356004212513483,
8+
"Ez": 0.28770171464461436,
99
"jx": 0.0,
1010
"jy": 0.0,
1111
"jz": 0.0
1212
},
1313
"lev=1": {
1414
"Bx": 0.0,
15-
"By": 2.7629151306453947e-09,
15+
"By": 1.4999363537195907e-09,
1616
"Bz": 0.0,
17-
"Ex": 2.4597363065789337,
17+
"Ex": 1.5591272748392493,
1818
"Ey": 0.0,
19-
"Ez": 0.45901250290130735,
19+
"Ez": 0.29412053281248907,
2020
"jx": 0.0,
2121
"jy": 0.0,
2222
"jz": 0.0

Regression/WarpX-tests.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -2525,7 +2525,7 @@ numthreads = 1
25252525
compileTest = 0
25262526
doVis = 0
25272527
compareParticles = 0
2528-
analysisRoutine = Examples/Tests/particles_in_pml/analysis_particles_in_pml.py
2528+
analysisRoutine = Examples/Tests/particles_in_pml/analysis_particles_in_pml_2dmr.py
25292529

25302530
[particles_in_pml_3d_MR]
25312531
buildDir = .

Source/BoundaryConditions/PML.cpp

+54-35
Original file line numberDiff line numberDiff line change
@@ -560,40 +560,56 @@ PML::PML (const int lev, const BoxArray& grid_ba, const DistributionMapping& gri
560560
m_geom(geom),
561561
m_cgeom(cgeom)
562562
{
563-
// When `do_pml_in_domain` is true, the PML overlap with the last `ncell` of the physical domain
564-
// (instead of extending `ncell` outside of the physical domain)
565-
// In order to implement this, a reduced domain is created here (decreased by ncells in all direction)
566-
// and passed to `MakeBoxArray`, which surrounds it by PML boxes
567-
// (thus creating the PML boxes at the right position, where they overlap with the original domain)
568-
// minimalBox provides the bounding box around grid_ba for level, lev.
569-
// Note that this is okay to build pml inside domain for a single patch, or joint patches
570-
// with same [min,max]. But it does not support multiple disjoint refinement patches.
571-
Box domain0 = grid_ba.minimalBox();
563+
// When `do_pml_in_domain` is true, the PML overlap with the last `ncell` of the physical domain or fine patch(es)
564+
// (instead of extending `ncell` outside of the physical domain or fine patch(es))
565+
// In order to implement this, we define a new reduced Box Array ensuring that it does not
566+
// include ncells from the edges of the physical domain or fine patch.
567+
// (thus creating the PML boxes at the right position, where they overlap with the original domain or fine patch(es))
568+
569+
BoxArray grid_ba_reduced = grid_ba;
572570
if (do_pml_in_domain) {
573-
for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
574-
if (do_pml_Lo[idim]){
575-
domain0.growLo(idim, -ncell);
576-
}
577-
if (do_pml_Hi[idim]){
578-
domain0.growHi(idim, -ncell);
571+
BoxList bl = grid_ba.boxList();
572+
// Here we loop over all the boxes in the original grid_ba BoxArray
573+
// For each box, we find if its in the edge (or boundary), and the size of those boxes are decreased by ncell
574+
for (auto& b : bl) {
575+
for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
576+
if (do_pml_Lo[idim]) {
577+
// Get neighboring box on lower side in direction idim and check if it intersects with any of the boxes
578+
// in grid_ba. If no intersection, then the box, b, in the boxlist, is in the edge and we decrase
579+
// the size by ncells using growLo(idim,-ncell)
580+
Box const& bb = amrex::adjCellLo(b, idim);
581+
if ( ! grid_ba.intersects(bb) ) {
582+
WARPX_ALWAYS_ASSERT_WITH_MESSAGE(b.length(idim) > ncell, " box length must be greater that pml size");
583+
b.growLo(idim, -ncell);
584+
}
585+
}
586+
if (do_pml_Hi[idim]) {
587+
// Get neighboring box on higher side in direction idim and check if it intersects with any of the boxes
588+
// in grid_ba. If no intersection, then the box, b, in the boxlist, is in the edge and we decrase
589+
// the size by ncells using growHi(idim,-ncell)
590+
Box const& bb = amrex::adjCellHi(b, idim);
591+
if ( ! grid_ba.intersects(bb) ) {
592+
WARPX_ALWAYS_ASSERT_WITH_MESSAGE(b.length(idim) > ncell, " box length must be greater that pml size");
593+
b.growHi(idim, -ncell);
594+
}
595+
}
579596
}
580597
}
598+
grid_ba_reduced = BoxArray(std::move(bl));
581599
}
582-
const BoxArray grid_ba_reduced = (do_pml_in_domain) ?
583-
BoxArray(grid_ba.boxList().intersect(domain0)) : grid_ba;
584-
600+
Box const domain0 = grid_ba_reduced.minimalBox();
585601
const bool is_single_box_domain = domain0.numPts() == grid_ba_reduced.numPts();
586602
const BoxArray& ba = MakeBoxArray(is_single_box_domain, domain0, *geom, grid_ba_reduced,
587603
IntVect(ncell), do_pml_in_domain, do_pml_Lo, do_pml_Hi);
588604

605+
589606
if (ba.empty()) {
590607
m_ok = false;
591608
return;
592609
} else {
593610
m_ok = true;
594611
}
595-
596-
// Define the number of guard cells in each direction, for E, B, and F
612+
// Define the number of guard cells in each di;rection, for E, B, and F
597613
auto nge = IntVect(AMREX_D_DECL(2, 2, 2));
598614
auto ngb = IntVect(AMREX_D_DECL(2, 2, 2));
599615
int ngf_int = 0;
@@ -760,24 +776,28 @@ PML::PML (const int lev, const BoxArray& grid_ba, const DistributionMapping& gri
760776
BoxArray grid_cba = grid_ba;
761777
grid_cba.coarsen(ref_ratio);
762778

763-
// assuming that the bounding box around grid_cba is a single patch, and not disjoint patches, similar to fine patch.
764-
amrex::Box cdomain = grid_cba.minimalBox();
779+
BoxArray grid_cba_reduced = grid_cba;
765780
if (do_pml_in_domain) {
766-
for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
767-
if (do_pml_Lo[idim]){
768-
// ncell is divided by refinement ratio to ensure that the
769-
// physical width of the PML region is equal in fine and coarse patch
770-
cdomain.growLo(idim, -ncell/ref_ratio[idim]);
771-
}
772-
if (do_pml_Hi[idim]){
773-
// ncell is divided by refinement ratio to ensure that the
774-
// physical width of the PML region is equal in fine and coarse patch
775-
cdomain.growHi(idim, -ncell/ref_ratio[idim]);
781+
BoxList bl = grid_cba.boxList();
782+
for (auto& b : bl) {
783+
for (int idim = 0; idim < AMREX_SPACEDIM; ++idim) {
784+
if (do_pml_Lo[idim]) {
785+
Box const& bb = amrex::adjCellLo(b, idim);
786+
if ( ! grid_cba.intersects(bb) ) {
787+
b.growLo(idim, -ncell/ref_ratio[idim]);
788+
}
789+
}
790+
if (do_pml_Hi[idim]) {
791+
Box const& bb = amrex::adjCellHi(b, idim);
792+
if ( ! grid_cba.intersects(bb) ) {
793+
b.growHi(idim, -ncell/ref_ratio[idim]);
794+
}
795+
}
776796
}
777797
}
798+
grid_cba_reduced = BoxArray(std::move(bl));
778799
}
779-
const BoxArray grid_cba_reduced = (do_pml_in_domain) ?
780-
BoxArray(grid_cba.boxList().intersect(cdomain)) : grid_cba;
800+
Box const cdomain = grid_cba_reduced.minimalBox();
781801

782802
const IntVect cncells = IntVect(ncell)/ref_ratio;
783803
const IntVect cdelta = IntVect(delta)/ref_ratio;
@@ -792,7 +812,6 @@ PML::PML (const int lev, const BoxArray& grid_ba, const DistributionMapping& gri
792812
} else {
793813
cdm.define(cba);
794814
}
795-
796815
const amrex::BoxArray cba_Ex = amrex::convert(cba, WarpX::GetInstance().getEfield_cp(1,0).ixType().toIntVect());
797816
const amrex::BoxArray cba_Ey = amrex::convert(cba, WarpX::GetInstance().getEfield_cp(1,1).ixType().toIntVect());
798817
const amrex::BoxArray cba_Ez = amrex::convert(cba, WarpX::GetInstance().getEfield_cp(1,2).ixType().toIntVect());

0 commit comments

Comments
 (0)