/* Copyright 2021 * * This file is part of WarpX. * * License: BSD-3-Clause-LBNL */ #include "FiniteDifferenceSolver.H" #ifdef WARPX_DIM_RZ # include "FiniteDifferenceAlgorithms/CylindricalYeeAlgorithm.H" #endif #include "Utils/TextMsg.H" #include "Utils/WarpXAlgorithmSelection.H" #include "Utils/WarpXConst.H" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace amrex; /** * \brief Update the B field at the boundary, using the Silver-Mueller condition */ void FiniteDifferenceSolver::ApplySilverMuellerBoundary ( std::array< std::unique_ptr, 3 >& Efield, std::array< std::unique_ptr, 3 >& Bfield, amrex::Box domain_box, amrex::Real const dt, amrex::Vector field_boundary_lo, amrex::Vector field_boundary_hi) { // Ensure that we are using the Yee solver WARPX_ALWAYS_ASSERT_WITH_MESSAGE( m_fdtd_algo == MaxwellSolverAlgo::Yee, "The Silver-Mueller boundary conditions can only be used with the Yee solver." ); // Ensure that we are using the cells the domain domain_box.enclosedCells(); #ifdef WARPX_DIM_RZ // Calculate relevant coefficients amrex::Real const cdt = PhysConst::c*dt; amrex::Real const cdt_over_dr = cdt*m_h_stencil_coefs_r[0]; amrex::Real const coef1_r = (1._rt - cdt_over_dr)/(1._rt + cdt_over_dr); amrex::Real const coef2_r = 2._rt*cdt_over_dr/(1._rt + cdt_over_dr) / PhysConst::c; amrex::Real const coef3_r = cdt/(1._rt + cdt_over_dr) / PhysConst::c; amrex::Real const cdt_over_dz = cdt*m_h_stencil_coefs_z[0]; amrex::Real const coef1_z = (1._rt - cdt_over_dz)/(1._rt + cdt_over_dz); amrex::Real const coef2_z = 2._rt*cdt_over_dz/(1._rt + cdt_over_dz) / PhysConst::c; // Extract stencil coefficients Real const * const AMREX_RESTRICT coefs_z = m_stencil_coefs_z.dataPtr(); int const n_coefs_z = m_h_stencil_coefs_z.size(); // Extract cylindrical specific parameters Real const dr = m_dr; int const nmodes = m_nmodes; Real const rmin = m_rmin; // Infer whether the Silver-Mueller needs to be applied in each direction bool const apply_hi_r = (field_boundary_hi[0] == FieldBoundaryType::Absorbing_SilverMueller); bool const apply_lo_z = (field_boundary_lo[1] == FieldBoundaryType::Absorbing_SilverMueller); bool const apply_hi_z = (field_boundary_hi[1] == FieldBoundaryType::Absorbing_SilverMueller); // tiling is usually set by TilingIfNotGPU() // but here, we set it to false because of potential race condition, // since we grow the tiles by one guard cell after creating them. for ( MFIter mfi(*Efield[0], false); mfi.isValid(); ++mfi ) { // Extract field data for this grid/tile Array4 const& Er = Efield[0]->array(mfi); Array4 const& Et = Efield[1]->array(mfi); Array4 const& Ez = Efield[2]->array(mfi); Array4 const& Br = Bfield[0]->array(mfi); Array4 const& Bt = Bfield[1]->array(mfi); Array4 const& Bz = Bfield[2]->array(mfi); // Extract tileboxes for which to loop Box tbr = mfi.tilebox(Bfield[0]->ixType().toIntVect()); Box tbt = mfi.tilebox(Bfield[1]->ixType().toIntVect()); Box tbz = mfi.tilebox(Bfield[2]->ixType().toIntVect()); // We will modify the first (i.e. innermost) guard cell // (if it is outside of the physical domain) // Thus, the tileboxes here are grown by 1 guard cell tbr.grow(1); tbt.grow(1); tbz.grow(1); // Loop over the cells amrex::ParallelFor(tbr, tbt, tbz, [=] AMREX_GPU_DEVICE (int i, int j, int /*k*/){ // At the +z boundary (innermost guard cell) if ( apply_hi_z && (j==domain_box.bigEnd(1)+1) ){ for (int m=0; m<2*nmodes-1; m++) Br(i,j,0,m) = coef1_z*Br(i,j,0,m) - coef2_z*Et(i,j,0,m); } // At the -z boundary (innermost guard cell) if ( apply_lo_z && (j==domain_box.smallEnd(1)-1) ){ for (int m=0; m<2*nmodes-1; m++) Br(i,j,0,m) = coef1_z*Br(i,j,0,m) + coef2_z*Et(i,j+1,0,m); } }, [=] AMREX_GPU_DEVICE (int i, int j, int /*k*/){ // At the +z boundary (innermost guard cell) if ( apply_hi_z && (j==domain_box.bigEnd(1)+1) ){ for (int m=0; m<2*nmodes-1; m++) Bt(i,j,0,m) = coef1_z*Bt(i,j,0,m) + coef2_z*Er(i,j,0,m); } // At the -z boundary (innermost guard cell) if ( apply_lo_z && (j==domain_box.smallEnd(1)-1) ){ for (int m=0; m<2*nmodes-1; m++) Bt(i,j,0,m) = coef1_z*Bt(i,j,0,m) - coef2_z*Er(i,j+1,0,m); } // At the +r boundary (innermost guard cell) if ( apply_hi_r && (i==domain_box.bigEnd(0)+1) ){ // Mode 0 Bt(i,j,0,0) = coef1_r*Bt(i,j,0,0) - coef2_r*Ez(i,j,0,0) + coef3_r*CylindricalYeeAlgorithm::UpwardDz(Er, coefs_z, n_coefs_z, i, j, 0, 0); for (int m=1; m const& Ex = Efield[0]->array(mfi); Array4 const& Ey = Efield[1]->array(mfi); #ifndef WARPX_DIM_1D_Z Array4 const& Ez = Efield[2]->array(mfi); #endif Array4 const& Bx = Bfield[0]->array(mfi); Array4 const& By = Bfield[1]->array(mfi); #ifndef WARPX_DIM_1D_Z Array4 const& Bz = Bfield[2]->array(mfi); #endif // Extract the tileboxes for which to loop Box tbx = mfi.tilebox(Bfield[0]->ixType().toIntVect()); Box tby = mfi.tilebox(Bfield[1]->ixType().toIntVect()); Box tbz = mfi.tilebox(Bfield[2]->ixType().toIntVect()); // We will modify the first (i.e. innermost) guard cell // (if it is outside of the physical domain) // Thus, the tileboxes here are grown by 1 guard cell tbx.grow(1); tby.grow(1); tbz.grow(1); // Loop over cells amrex::ParallelFor(tbx, tby, tbz, // Apply Boundary condition to Bx [=] AMREX_GPU_DEVICE (int i, int j, int k){ #ifdef WARPX_DIM_3D // At the +y boundary (innermost guard cell) if ( apply_hi_y && ( j==domain_box.bigEnd(1)+1 ) ) Bx(i,j,k) = coef1_y * Bx(i,j,k) + coef2_y * Ez(i,j,k); // At the -y boundary (innermost guard cell) if ( apply_lo_y && ( j==domain_box.smallEnd(1)-1 ) ) Bx(i,j,k) = coef1_y * Bx(i,j,k) - coef2_y * Ez(i,j+1,k); // At the +z boundary (innermost guard cell) if ( apply_hi_z && ( k==domain_box.bigEnd(2)+1 ) ) Bx(i,j,k) = coef1_z * Bx(i,j,k) - coef2_z * Ey(i,j,k); // At the -z boundary (innermost guard cell) if ( apply_lo_z && ( k==domain_box.smallEnd(2)-1 ) ) Bx(i,j,k) = coef1_z * Bx(i,j,k) + coef2_z * Ey(i,j,k+1); #elif WARPX_DIM_XZ // At the +z boundary (innermost guard cell) if ( apply_hi_z && ( j==domain_box.bigEnd(1)+1 ) ) Bx(i,j,k) = coef1_z * Bx(i,j,k) - coef2_z * Ey(i,j,k); // At the -z boundary (innermost guard cell) if ( apply_lo_z && ( j==domain_box.smallEnd(1)-1 ) ) Bx(i,j,k) = coef1_z * Bx(i,j,k) + coef2_z * Ey(i,j+1,k); #elif WARPX_DIM_1D_Z // At the +z boundary (innermost guard cell) if ( apply_hi_z && ( i==domain_box.bigEnd(0)+1 ) ) Bx(i,j,k) = coef1_z * Bx(i,j,k) - coef2_z * Ey(i,j,k); // At the -z boundary (innermost guard cell) if ( apply_lo_z && ( i==domain_box.smallEnd(0)-1 ) ) Bx(i,j,k) = coef1_z * Bx(i,j,k) + coef2_z * Ey(i+1,j,k); #endif }, // Apply Boundary condition to By [=] AMREX_GPU_DEVICE (int i, int j, int k){ #if (defined WARPX_DIM_3D || WARPX_DIM_XZ) // At the +x boundary (innermost guard cell) if ( apply_hi_x && ( i==domain_box.bigEnd(0)+1 ) ) By(i,j,k) = coef1_x * By(i,j,k) - coef2_x * Ez(i,j,k); // At the -x boundary (innermost guard cell) if ( apply_lo_x && ( i==domain_box.smallEnd(0)-1 ) ) By(i,j,k) = coef1_x * By(i,j,k) + coef2_x * Ez(i+1,j,k); #endif #ifdef WARPX_DIM_3D // At the +z boundary (innermost guard cell) if ( apply_hi_z && ( k==domain_box.bigEnd(2)+1 ) ) By(i,j,k) = coef1_z * By(i,j,k) + coef2_z * Ex(i,j,k); // At the -z boundary (innermost guard cell) if ( apply_lo_z && ( k==domain_box.smallEnd(2)-1 ) ) By(i,j,k) = coef1_z * By(i,j,k) - coef2_z * Ex(i,j,k+1); #elif WARPX_DIM_XZ // At the +z boundary (innermost guard cell) if ( apply_hi_z && ( j==domain_box.bigEnd(1)+1 ) ) By(i,j,k) = coef1_z * By(i,j,k) + coef2_z * Ex(i,j,k); // At the -z boundary (innermost guard cell) if ( apply_lo_z && ( j==domain_box.smallEnd(1)-1 ) ) By(i,j,k) = coef1_z * By(i,j,k) - coef2_z * Ex(i,j+1,k); #elif WARPX_DIM_1D_Z // At the +z boundary (innermost guard cell) if ( apply_hi_z && ( i==domain_box.bigEnd(0)+1 ) ) By(i,j,k) = coef1_z * By(i,j,k) + coef2_z * Ex(i,j,k); // At the -z boundary (innermost guard cell) if ( apply_lo_z && ( i==domain_box.smallEnd(0)-1 ) ) By(i,j,k) = coef1_z * By(i,j,k) - coef2_z * Ex(i+1,j,k); #endif }, // Apply Boundary condition to Bz [=] AMREX_GPU_DEVICE (int i, int j, int k){ #if (defined WARPX_DIM_3D || WARPX_DIM_XZ) // At the +x boundary (innermost guard cell) if ( apply_hi_x && ( i==domain_box.bigEnd(0)+1 ) ) Bz(i,j,k) = coef1_x * Bz(i,j,k) + coef2_x * Ey(i,j,k); // At the -x boundary (innermost guard cell) if ( apply_lo_x && ( i==domain_box.smallEnd(0)-1 ) ) Bz(i,j,k) = coef1_x * Bz(i,j,k) - coef2_x * Ey(i+1,j,k); #endif #ifdef WARPX_DIM_3D // At the +y boundary (innermost guard cell) if ( apply_hi_y && ( j==domain_box.bigEnd(1)+1 ) ) Bz(i,j,k) = coef1_y * Bz(i,j,k) - coef2_y * Ex(i,j,k); // At the -y boundary (innermost guard cell) if ( apply_lo_y && ( j==domain_box.smallEnd(1)-1 ) ) Bz(i,j,k) = coef1_y * Bz(i,j,k) + coef2_y * Ex(i,j+1,k); #elif WARPX_DIM_1D_Z ignore_unused(i,j,k); #endif } ); } #endif // WARPX_DIM_RZ }