Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PECInsulator boundary condition #4943

Merged
merged 34 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
841770b
Add pec_insulator boundary condition
dpgrote May 9, 2024
cf6f799
Give B_value a default value
dpgrote May 9, 2024
145e628
clang-tidy fix
dpgrote May 10, 2024
607ba8e
Add include in Source/Python/WarpX.cpp
dpgrote May 10, 2024
60613fd
Clean up const's and some spacing
dpgrote May 11, 2024
611c0df
Merge branch 'development' into add_insulator_BC
dpgrote May 13, 2024
7548cbe
Add const requested by clang-tidy
dpgrote May 13, 2024
5c4cfc2
Fix numeric literals
dpgrote May 14, 2024
9c8d11a
Major cleanup and reduction of the code
dpgrote May 17, 2024
e4aa5ae
Add documentation
dpgrote May 17, 2024
ab07778
Add extrapolation of tangential field
dpgrote May 17, 2024
ab6254b
Fix typos
dpgrote May 17, 2024
b3d9266
Made ApplyPEC_InsulatortoField public
dpgrote May 17, 2024
f915879
Fix class variable initialization
dpgrote May 17, 2024
1e8d517
Add CI test
dpgrote May 21, 2024
82fdbe7
Merge branch 'development' into add_insulator_BC
dpgrote May 21, 2024
8c60a03
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 21, 2024
a2212aa
Update documentation
dpgrote May 22, 2024
0846580
Merge branch 'development' into add_insulator_BC
dpgrote Jun 4, 2024
5498195
Merge branch 'development' into add_insulator_BC
dpgrote Jun 18, 2024
89837c6
Merge branch 'development' into add_insulator_BC
dpgrote Jul 3, 2024
1f5c72d
Fix xyz_min to match other changes
dpgrote Jul 3, 2024
37cbb0d
Merge branch 'development' into add_insulator_BC
dpgrote Aug 26, 2024
16078d2
Merge branch 'development' into add_insulator_BC
dpgrote Sep 23, 2024
59fc8f0
Rename CI test benchmark file
dpgrote Sep 23, 2024
0973a4e
Fixes related to the enum value
dpgrote Sep 23, 2024
0b25492
Merge branch 'development' into add_insulator_BC
dpgrote Oct 7, 2024
3163c2a
Fixes related to MF registry
dpgrote Oct 7, 2024
e074f45
Apply suggestions from code review
dpgrote Oct 10, 2024
2c3263c
Clean up
dpgrote Oct 10, 2024
ca50303
Update comment
dpgrote Oct 10, 2024
9a15278
Merge branch 'development' into add_insulator_BC
dpgrote Nov 4, 2024
f21e856
Remove the unnecessary routine get_cell_count_to_boundary
dpgrote Nov 5, 2024
5b1a429
Fix comments and documentation
dpgrote Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions Docs/source/usage/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,37 @@ Domain Boundary Conditions

* ``pec``: This option can be used to set a Perfect Electric Conductor at the simulation boundary. Please see the :ref:`PEC theory section <theory-bc-pec>` for more details. Note that PEC boundary is invalid at `r=0` for the RZ solver. Please use ``none`` option. This boundary condition does not work with the spectral solver.

* ``pec_insulator``: This option specifies a mixed perfect electric conductor and insulator boundary, where some part of the
boundary is PEC and some is insulator. In the insulator portion, the normal fields are extrapolated and the tangential fields
are either set to the specified value or extrapolated. The region that is insulator is specified using a spatially dependent expression with the insulator being in the area where the value of the expression is greater than zero.
The expressions are given for the low and high boundary on each axis, as listed below. The tangential fields are specified as
expressions that can depend on the location and time. The tangential fields are in two pairs, the electric fields and the
magnetic fields. In each pair, if one is specified, the other will be set to zero if not also specified.

* ``insulator.area_x_lo(y,z)``: For the lower x (or r) boundary, expression specifying the insulator location

* ``insulator.area_x_hi(y,z)``: For the upper x (or r) boundary, expression specifying the insulator location

* ``insulator.area_y_lo(x,z)``: For the lower y boundary, expression specifying the insulator location

* ``insulator.area_y_hi(x,z)``: For the upper y boundary, expression specifying the insulator location

* ``insulator.area_z_lo(x,y)``: For the lower z boundary, expression specifying the insulator location

* ``insulator.area_z_hi(x,y)``: For the upper z boundary, expression specifying the insulator location

* ``insulator.Ey_x_lo(y,z,t)``, ``insulator.Ez_x_lo(y,z,t)``, ``insulator.By_x_lo(y,z,t)``, ``insulator.Bz_x_lo(y,z,t)``: expressions of the tangential field values for the lower x (or r) boundary

* ``insulator.Ey_x_hi(y,z,t)``, ``insulator.Ez_x_hi(y,z,t)``, ``insulator.By_x_hi(y,z,t)``, ``insulator.Bz_x_hi(y,z,t)``: expressions of the tangential field values for the upper x (or r) boundary

* ``insulator.Ex_y_lo(x,z,t)``, ``insulator.Ez_y_lo(x,z,t)``, ``insulator.Bx_y_lo(x,z,t)``, ``insulator.Bz_y_lo(x,z,t)``: expressions of the tangential field values for the lower y boundary

* ``insulator.Ex_y_hi(x,z,t)``, ``insulator.Ez_y_hi(x,z,t)``, ``insulator.Bx_y_hi(x,z,t)``, ``insulator.Bz_y_hi(x,z,t)``: expressions of the tangential field values for the upper y boundary

* ``insulator.Ex_z_lo(x,y,t)``, ``insulator.Ey_z_lo(x,y,t)``, ``insulator.Bx_z_lo(x,y,t)``, ``insulator.By_z_lo(x,y,t)``: expressions of the tangential field values for the lower z boundary

* ``insulator.Ex_z_hi(x,y,t)``, ``insulator.Ey_z_hi(x,y,t)``, ``insulator.Bx_z_hi(x,y,t)``, ``insulator.By_z_hi(x,y,t)``: expressions of the tangential field values for the upper z boundary

* ``none``: No boundary condition is applied to the fields with the electromagnetic solver. This option must be used for the RZ-solver at `r=0`.

* ``neumann``: For the electrostatic multigrid solver, a Neumann boundary condition (with gradient of the potential equal to 0) will be applied on the specified boundary.
Expand Down
10 changes: 10 additions & 0 deletions Examples/Tests/pec/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,13 @@ add_warpx_test(
diags/diag1000020 # output
OFF # dependency
)

add_warpx_test(
test_2d_pec_field_insulator # name
2 # dims
2 # nprocs
inputs_test_2d_pec_field_insulator # inputs
analysis_default_regression.py # analysis
diags/diag1000010 # output
OFF # dependency
)
Comment on lines +34 to +42
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the complexity of the new feature, is there a physics analysis that can be done, beyond the checksums analysis?

Also, is this intentionally tested only in 2D? The implementation seems to be general for all dimensions, so maybe it could be worth adding tests for those as well. What do you think?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was copied from the test case for the same boundary condition in the picnic code. That code's primary use is 2D. I don't know of any physics analysis that could be done beyond checking that the fields at the boundary are as expected. I could add other cases that do that simple check.

34 changes: 34 additions & 0 deletions Examples/Tests/pec/inputs_test_2d_pec_field_insulator
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Maximum number of time steps
max_step = 10

# number of grid points
amr.n_cell = 32 32
amr.blocking_factor = 16

# Maximum level in hierarchy (for now must be 0, i.e., one level in total)
amr.max_level = 0

# Geometry
geometry.dims = 2
geometry.prob_lo = 0. 2.e-2 # physical domain
geometry.prob_hi = 1.e-2 3.e-2

# Boundary condition
boundary.field_lo = neumann periodic
boundary.field_hi = PECInsulator periodic

warpx.serialize_initial_conditions = 1

# Verbosity
warpx.verbose = 1

# CFL
warpx.cfl = 1.0

insulator.area_x_hi(y,z) = (2.25e-2 <= z and z <= 2.75e-2)
insulator.By_x_hi(y,z,t) = min(t/1.0e-12,1)*1.e1*3.3e-4

# Diagnostics
diagnostics.diags_names = diag1
diag1.intervals = 10
diag1.diag_type = Full
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"lev=0": {
"Bx": 0.0,
"By": 0.34938851065132936,
"Bz": 0.0,
"Ex": 31871402.236828588,
"Ey": 0.0,
"Ez": 104908439.18998256,
"jx": 0.0,
"jy": 0.0,
"jz": 0.0
}
}
1 change: 1 addition & 0 deletions Source/BoundaryConditions/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ foreach(D IN LISTS WarpX_DIMS)
warpx_set_suffix_dims(SD ${D})
target_sources(lib_${SD}
PRIVATE
PEC_Insulator.cpp
PML.cpp
WarpXEvolvePML.cpp
WarpXFieldBoundaries.cpp
Expand Down
1 change: 1 addition & 0 deletions Source/BoundaryConditions/Make.package
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
CEXE_sources += PEC_Insulator.cpp
CEXE_sources += PML.cpp WarpXEvolvePML.cpp
CEXE_sources += WarpXFieldBoundaries.cpp WarpX_PEC.cpp

Expand Down
180 changes: 180 additions & 0 deletions Source/BoundaryConditions/PEC_Insulator.H
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#ifndef PEC_INSULATOR_H_
#define PEC_INSULATOR_H_

#include "Utils/WarpXAlgorithmSelection.H"

#include <AMReX_Array.H>
#include <AMReX_Geometry.H>
#include <AMReX_Vector.H>

#include <AMReX_BaseFwd.H>

#include <array>
#include <memory>

class PEC_Insulator
{
public:

PEC_Insulator();

/**
* \brief Apply either the PEC or insulator boundary condition on the boundary and in the
* guard cells.
* In the PEC, the nodal fields (in a Yee mesh) are made even relative to the boundary,
* the non-nodal fields are made odd.
* In the insulator, the tangential fields are set to the value if specified, otherwise unchanged,
* and the normal fields extrapolated from the valid cells.
*
* \param[in,out] Efield
* \param[in] field_boundary_lo lower field boundary conditions
* \param[in] field_boundary_hi upper field boundary conditions
* \param[in] ng_fieldgather number of guard cells used by field gather
* \param[in] geom geometry object of level "lev"
* \param[in] lev level of the Multifab
* \param[in] patch_type coarse or fine
* \param[in] ref_ratios vector containing the refinement ratios of the refinement levels
* \param[in] time current time of the simulation
* \param[in] split_pml_field whether pml the multifab is the regular Efield or
* split pml field
*/
void ApplyPEC_InsulatortoEfield (std::array<amrex::MultiFab*, 3> Efield,
amrex::Array<FieldBoundaryType,AMREX_SPACEDIM> const & field_boundary_lo,
amrex::Array<FieldBoundaryType,AMREX_SPACEDIM> const & field_boundary_hi,
amrex::IntVect const & ng_fieldgather, amrex::Geometry const & geom,
int lev, PatchType patch_type, amrex::Vector<amrex::IntVect> const & ref_ratios,
amrex::Real time,
bool split_pml_field = false);
/**
* \brief Apply either the PEC or insulator boundary condition on the boundary and in the
* guard cells.
* In the PEC, the nodal fields (in a Yee mesh) are made even relative to the boundary,
* the non-nodal fields are made odd.
* In the insulator, the tangential fields are set to the value if specified, otherwise unchanged,
* and the normal fields extrapolated from the valid cells.
*
* \param[in,out] Bfield
* \param[in] field_boundary_lo lower field boundary conditions
* \param[in] field_boundary_hi upper field boundary conditions
* \param[in] ng_fieldgather number of guard cells used by field gather
* \param[in] geom geometry object of level "lev"
* \param[in] lev level of the Multifab
* \param[in] patch_type coarse or fine
* \param[in] ref_ratios vector containing the refinement ratios of the refinement levels
* \param[in] time current time of the simulation
*/
void ApplyPEC_InsulatortoBfield (std::array<amrex::MultiFab*, 3> Bfield,
amrex::Array<FieldBoundaryType,AMREX_SPACEDIM> const & field_boundary_lo,
amrex::Array<FieldBoundaryType,AMREX_SPACEDIM> const & field_boundary_hi,
amrex::IntVect const & ng_fieldgather, amrex::Geometry const & geom,
int lev, PatchType patch_type, amrex::Vector<amrex::IntVect> const & ref_ratios,
amrex::Real time);
Comment on lines +66 to +71
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't we need a split_pml_field argument for B, as for E? In other words, why is the splitting of B, which I think occurs in the PML, not relevant in this case?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. I copied this pattern from the PEC boundary conditions. Do you know why the split is done there?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah interesting, I don't know. I think this would be a question for @RevathiJambunathan or @roelof-groenewald.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pinging @RevathiJambunathan and @roelof-groenewald just to make sure that the PR doesn't get stalled.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the slow response. It looks like the flag was introduced in #2541 to fix an observed bug when one boundary is PEC and an adjacent one is PML. @RevathiJambunathan would know better but I expect it is not needed to apply the same to the B-field since the update to the E-field ensures that the B-field values come out appropriately in the B-field push.


/**
* \brief The work routine applying the boundary condition
*
* \param[in,out] field
* \param[in] field_boundary_lo lower field boundary conditions
* \param[in] field_boundary_hi upper field boundary conditions
* \param[in] ng_fieldgather number of guard cells used by field gather
* \param[in] geom geometry object of level "lev"
* \param[in] lev level of the Multifab
* \param[in] patch_type coarse or fine
* \param[in] ref_ratios vector containing the refinement ratios of the refinement levels
* \param[in] time current time of the simulation
* \param[in] split_pml_field whether pml the multifab is the regular Efield or
* split pml field
* \param[in] E_like whether the field is E like or B like
* \param[in] set_F_x_lo whether the tangential field at the boundary was specified
* \param[in] set_F_x_hi whether the tangential field at the boundary was specified
* \param[in] a_Fy_x_lo the parser for the tangential field at the boundary
* \param[in] a_Fz_x_lo the parser for the tangential field at the boundary
* \param[in] a_Fy_x_hi the parser for the tangential field at the boundary
* \param[in] a_Fz_x_hi the parser for the tangential field at the boundary
* \param[in] set_F_y_lo whether the tangential field at the boundary was specified
* \param[in] set_F_y_hi whether the tangential field at the boundary was specified
* \param[in] a_Fx_y_lo the parser for the tangential field at the boundary
* \param[in] a_Fz_y_lo the parser for the tangential field at the boundary
* \param[in] a_Fx_y_hi the parser for the tangential field at the boundary
* \param[in] a_Fz_y_hi the parser for the tangential field at the boundary
* \param[in] set_F_z_lo whether the tangential field at the boundary was specified
* \param[in] set_F_z_hi whether the tangential field at the boundary was specified
* \param[in] a_Fx_z_lo the parser for the tangential field at the boundary
* \param[in] a_Fy_z_lo the parser for the tangential field at the boundary
* \param[in] a_Fx_z_hi the parser for the tangential field at the boundary
* \param[in] a_Fy_z_hi the parser for the tangential field at the boundary
*/
void
ApplyPEC_InsulatortoField (std::array<amrex::MultiFab*, 3> field,
amrex::Array<FieldBoundaryType,AMREX_SPACEDIM> const & field_boundary_lo,
amrex::Array<FieldBoundaryType,AMREX_SPACEDIM> const & field_boundary_hi,
amrex::IntVect const & ng_fieldgather, amrex::Geometry const & geom,
int lev, PatchType patch_type, amrex::Vector<amrex::IntVect> const & ref_ratios,
amrex::Real time,
bool split_pml_field,
bool E_like,
#if (AMREX_SPACEDIM > 1)
bool set_F_x_lo, bool set_F_x_hi,
std::unique_ptr<amrex::Parser> const & a_Fy_x_lo, std::unique_ptr<amrex::Parser> const & a_Fz_x_lo,
std::unique_ptr<amrex::Parser> const & a_Fy_x_hi, std::unique_ptr<amrex::Parser> const & a_Fz_x_hi,
#endif
#if defined(WARPX_DIM_3D)
bool set_F_y_lo, bool set_F_y_hi,
std::unique_ptr<amrex::Parser> const & a_Fx_y_lo, std::unique_ptr<amrex::Parser> const & a_Fz_y_lo,
std::unique_ptr<amrex::Parser> const & a_Fx_y_hi, std::unique_ptr<amrex::Parser> const & a_Fz_y_hi,
#endif
bool set_F_z_lo, bool set_F_z_hi,
std::unique_ptr<amrex::Parser> const & a_Fx_z_lo, std::unique_ptr<amrex::Parser> const & a_Fy_z_lo,
std::unique_ptr<amrex::Parser> const & a_Fx_z_hi, std::unique_ptr<amrex::Parser> const & a_Fy_z_hi);

private:

/* \brief Reads in the parsers for the tangential fields, returning whether
* the input parameter was specified.
* \param[in] pp_insulator ParmParse instance
* \param[out] parser the parser generated from the input
* \param[in] input_name the name of the input parameter
* \param[in] coord1 the first coordinate in the plane
* \param[in] coord2 the second coordinate in the plane
*/
bool ReadTangentialFieldParser (amrex::ParmParse const & pp_insulator,
std::unique_ptr<amrex::Parser> & parser,
std::string const & input_name,
std::string const & coord1,
std::string const & coord2);

std::vector<std::unique_ptr<amrex::Parser>> m_insulator_area_lo;
std::vector<std::unique_ptr<amrex::Parser>> m_insulator_area_hi;

#if (AMREX_SPACEDIM > 1)
bool m_set_B_x_lo = false, m_set_B_x_hi = false;
std::unique_ptr<amrex::Parser> m_By_x_lo, m_Bz_x_lo;
std::unique_ptr<amrex::Parser> m_By_x_hi, m_Bz_x_hi;
#endif
#if defined(WARPX_DIM_3D)
bool m_set_B_y_lo = false, m_set_B_y_hi = false;
std::unique_ptr<amrex::Parser> m_Bx_y_lo, m_Bz_y_lo;
std::unique_ptr<amrex::Parser> m_Bx_y_hi, m_Bz_y_hi;
#endif
bool m_set_B_z_lo = false, m_set_B_z_hi = false;
std::unique_ptr<amrex::Parser> m_Bx_z_lo, m_By_z_lo;
std::unique_ptr<amrex::Parser> m_Bx_z_hi, m_By_z_hi;


#if (AMREX_SPACEDIM > 1)
bool m_set_E_x_lo = false, m_set_E_x_hi = false;
std::unique_ptr<amrex::Parser> m_Ey_x_lo, m_Ez_x_lo;
std::unique_ptr<amrex::Parser> m_Ey_x_hi, m_Ez_x_hi;
#endif
#if defined(WARPX_DIM_3D)
bool m_set_E_y_lo = false, m_set_E_y_hi = false;
std::unique_ptr<amrex::Parser> m_Ex_y_lo, m_Ez_y_lo;
std::unique_ptr<amrex::Parser> m_Ex_y_hi, m_Ez_y_hi;
#endif
bool m_set_E_z_lo = false, m_set_E_z_hi = false;
std::unique_ptr<amrex::Parser> m_Ex_z_lo, m_Ey_z_lo;
std::unique_ptr<amrex::Parser> m_Ex_z_hi, m_Ey_z_hi;


};
#endif // PEC_INSULATOR_H_
Loading
Loading