diff options
-rw-r--r-- | Example/Langmuir/inputs.multi.2d.rt | 86 | ||||
-rw-r--r-- | Example/Langmuir/inputs.multi.rt | 12 | ||||
-rwxr-xr-x | Example/Langmuir/langmuir_multi_2d_analysis.py | 85 | ||||
-rw-r--r-- | Regression/WarpX-tests.ini | 21 | ||||
-rw-r--r-- | Source/WarpXFFT.cpp | 28 | ||||
-rw-r--r-- | Source/WarpX_f.H | 13 | ||||
-rw-r--r-- | Source/WarpX_fft.F90 | 5 | ||||
-rw-r--r-- | tests/CurrentDeposition/GNUmakefile | 2 | ||||
-rw-r--r-- | tests/FieldGather/GNUmakefile | 2 | ||||
-rw-r--r-- | tests/FieldSolver/GNUmakefile | 2 | ||||
-rw-r--r-- | tests/ParticlePusher/GNUmakefile | 2 |
11 files changed, 236 insertions, 22 deletions
diff --git a/Example/Langmuir/inputs.multi.2d.rt b/Example/Langmuir/inputs.multi.2d.rt new file mode 100644 index 000000000..6f301a7c2 --- /dev/null +++ b/Example/Langmuir/inputs.multi.2d.rt @@ -0,0 +1,86 @@ +# Maximum number of time steps +max_step = 80 + +# number of grid points +amr.n_cell = 128 128 + +# Maximum allowable size of each subdomain in the problem domain; +# this is used to decompose the domain for parallel calculations. +amr.max_grid_size = 64 + +# Maximum level in hierarchy (for now must be 0, i.e., one level in total) +amr.max_level = 0 + +amr.plot_int = 40 # How often to write plotfiles. "<= 0" means no plotfiles. + +# Geometry +geometry.coord_sys = 0 # 0: Cartesian +geometry.is_periodic = 1 1 # Is periodic? +geometry.prob_lo = -20.e-6 -20.e-6 # physical domain +geometry.prob_hi = 20.e-6 20.e-6 + +warpx.serialize_ics = 1 + +# Verbosity +warpx.verbose = 1 + +# Algorithms +algo.current_deposition = 3 +algo.charge_deposition = 0 +algo.field_gathering = 1 +algo.particle_pusher = 0 + +# Interpolation +interpolation.nox = 1 +interpolation.noy = 1 +interpolation.noz = 1 + +# CFL +warpx.cfl = 1.0 + +# Parameters for the plasma wave +constants.use_my_constants = 1 +constants.constant_names = epsilon kp k +constants.constant_values = 0.01 376357.71524190728 314159.2653589793 +# Note: kp is calculated in SI for a density of 4e24 (i.e. 2e24 electrons + 2e24 positrons) +# k is calculated so as to have 2 periods within the 40e-6 wide box. + +# Particles +particles.nspecies = 2 +particles.species_names = electrons positrons + +electrons.charge = -q_e +electrons.mass = m_e +electrons.injection_style = "NUniformPerCell" +electrons.num_particles_per_cell_each_dim = 2 2 +electrons.xmin = -20.e-6 +electrons.xmax = 20.e-6 +electrons.ymin = -20.e-6 +electrons.ymax = 20.e-6 +electrons.zmin = -20.e-6 +electrons.zmax = 20.e-6 + +electrons.profile = constant +electrons.density = 2.e24 # number of electrons per m^3 +electrons.momentum_distribution_type = parse_momentum_function +electrons.momentum_function_ux(x,y,z) = "epsilon * k/kp * sin(k*x) * cos(k*y) * cos(k*z)" +electrons.momentum_function_uy(x,y,z) = "epsilon * k/kp * cos(k*x) * sin(k*y) * cos(k*z)" +electrons.momentum_function_uz(x,y,z) = "epsilon * k/kp * cos(k*x) * cos(k*y) * sin(k*z)" + +positrons.charge = q_e +positrons.mass = m_e +positrons.injection_style = "NUniformPerCell" +positrons.num_particles_per_cell_each_dim = 2 2 +positrons.xmin = -20.e-6 +positrons.xmax = 20.e-6 +positrons.ymin = -20.e-6 +positrons.ymax = 20.e-6 +positrons.zmin = -20.e-6 +positrons.zmax = 20.e-6 + +positrons.profile = constant +positrons.density = 2.e24 # number of positrons per m^3 +positrons.momentum_distribution_type = parse_momentum_function +positrons.momentum_function_ux(x,y,z) = "-epsilon * k/kp * sin(k*x) * cos(k*y) * cos(k*z)" +positrons.momentum_function_uy(x,y,z) = "-epsilon * k/kp * cos(k*x) * sin(k*y) * cos(k*z)" +positrons.momentum_function_uz(x,y,z) = "-epsilon * k/kp * cos(k*x) * cos(k*y) * sin(k*z)" diff --git a/Example/Langmuir/inputs.multi.rt b/Example/Langmuir/inputs.multi.rt index edc5d3fa5..d2b648159 100644 --- a/Example/Langmuir/inputs.multi.rt +++ b/Example/Langmuir/inputs.multi.rt @@ -63,9 +63,9 @@ electrons.zmax = 20.e-6 electrons.profile = constant electrons.density = 2.e24 # number of electrons per m^3 electrons.momentum_distribution_type = parse_momentum_function -electrons.momentum_function_ux(x,y,z) = "epsilon * (k/kp) * sin(k*x) * cos(k*y) * cos(k*z)" -electrons.momentum_function_uy(x,y,z) = "epsilon * (k/kp) * cos(k*x) * sin(k*y) * cos(k*z)" -electrons.momentum_function_uz(x,y,z) = "epsilon * (k/kp) * cos(k*x) * cos(k*y) * sin(k*z)" +electrons.momentum_function_ux(x,y,z) = "epsilon * k/kp * sin(k*x) * cos(k*y) * cos(k*z)" +electrons.momentum_function_uy(x,y,z) = "epsilon * k/kp * cos(k*x) * sin(k*y) * cos(k*z)" +electrons.momentum_function_uz(x,y,z) = "epsilon * k/kp * cos(k*x) * cos(k*y) * sin(k*z)" positrons.charge = q_e positrons.mass = m_e @@ -81,6 +81,6 @@ positrons.zmax = 20.e-6 positrons.profile = constant positrons.density = 2.e24 # number of positrons per m^3 positrons.momentum_distribution_type = parse_momentum_function -positrons.momentum_function_ux(x,y,z) = "-epsilon * (k/kp) * sin(k*x) * cos(k*y) * cos(k*z)" -positrons.momentum_function_uy(x,y,z) = "-epsilon * (k/kp) * cos(k*x) * sin(k*y) * cos(k*z)" -positrons.momentum_function_uz(x,y,z) = "-epsilon * (k/kp) * cos(k*x) * cos(k*y) * sin(k*z)" +positrons.momentum_function_ux(x,y,z) = "-epsilon * k/kp * sin(k*x) * cos(k*y) * cos(k*z)" +positrons.momentum_function_uy(x,y,z) = "-epsilon * k/kp * cos(k*x) * sin(k*y) * cos(k*z)" +positrons.momentum_function_uz(x,y,z) = "-epsilon * k/kp * cos(k*x) * cos(k*y) * sin(k*z)" diff --git a/Example/Langmuir/langmuir_multi_2d_analysis.py b/Example/Langmuir/langmuir_multi_2d_analysis.py new file mode 100755 index 000000000..1006cdd77 --- /dev/null +++ b/Example/Langmuir/langmuir_multi_2d_analysis.py @@ -0,0 +1,85 @@ +#! /usr/bin/env python + +# This is a script that analyses the simulation results from +# the script `inputs.multi.rt`. This simulates a 3D periodic plasma wave. +# The electric field in the simulation is given (in theory) by: +# $$ E_x = \epsilon \,\frac{m_e c^2 k_x}{q_e}\sin(k_x x)\cos(k_y y)\cos(k_z z)\sin( \omega_p t)$$ +# $$ E_y = \epsilon \,\frac{m_e c^2 k_y}{q_e}\cos(k_x x)\sin(k_y y)\cos(k_z z)\sin( \omega_p t)$$ +# $$ E_z = \epsilon \,\frac{m_e c^2 k_z}{q_e}\cos(k_x x)\cos(k_y y)\sin(k_z z)\sin( \omega_p t)$$ +import sys +import matplotlib +matplotlib.use('Agg') +import matplotlib.pyplot as plt +import yt +yt.funcs.mylog.setLevel(50) +import numpy as np +from scipy.constants import e, m_e, epsilon_0, c + +# this will be the name of the plot file +fn = sys.argv[1] + +# Parameters (these parameters must match the parameters in `inputs.multi.rt`) +epsilon = 0.01 +n = 4.e24 +n_osc_x = 2 +n_osc_z = 2 +xmin = -20e-6; xmax = 20.e-6; Nx = 128 +zmin = -20e-6; zmax = 20.e-6; Nz = 128 + +# Wave vector of the wave +kx = 2.*np.pi*n_osc_x/(xmax-xmin) +kz = 2.*np.pi*n_osc_z/(zmax-zmin) +# Plasma frequency +wp = np.sqrt((n*e**2)/(m_e*epsilon_0)) + +k = {'Ex':kx, 'Ez':kz} +cos = {'Ex': (0,1,1), 'Ez':(1,1,0)} + +def get_contribution( is_cos, k ): + du = (xmax-xmin)/Nx + u = xmin + du*( 0.5 + np.arange(Nx) ) + if is_cos == 1: + return( np.cos(k*u) ) + else: + return( np.sin(k*u) ) + +def get_theoretical_field( field, t ): + amplitude = epsilon * (m_e*c**2*k[field])/e * np.sin(wp*t) + cos_flag = cos[field] + x_contribution = get_contribution( cos_flag[0], kx ) + z_contribution = get_contribution( cos_flag[2], kz ) + + E = amplitude * x_contribution[:, np.newaxis ] \ + * z_contribution[np.newaxis, :] + + return( E ) + +# Read the file +ds = yt.load(fn) +t0 = ds.current_time.to_ndarray().mean() +data = ds.covering_grid(level=0, left_edge=ds.domain_left_edge, + dims=ds.domain_dimensions) + +# Check the validity of the fields +overall_max_error = 0 +for field in ['Ex', 'Ez']: + E_sim = data[field].to_ndarray()[:,:,0] + E_th = get_theoretical_field(field, t0) + max_error = abs(E_sim-E_th).max()/abs(E_th).max() + print('%s: Max error: %.2e' %(field,max_error)) + overall_max_error = max( overall_max_error, max_error ) + +# Plot the last field from the loop (Ez at iteration 40) +plt.subplot2grid( (1,2), (0,0) ) +plt.imshow( E_sim ) +plt.colorbar() +plt.title('Ez, last iteration\n(simulation)') +plt.subplot2grid( (1,2), (0,1) ) +plt.imshow( E_th ) +plt.colorbar() +plt.title('Ez, last iteration\n(theory)') +plt.tight_layout() +plt.savefig('langmuir_multi_2d_analysis.png') + +# Automatically check the validity +assert overall_max_error < 0.02 diff --git a/Regression/WarpX-tests.ini b/Regression/WarpX-tests.ini index b57e5c51d..c5e57f63c 100644 --- a/Regression/WarpX-tests.ini +++ b/Regression/WarpX-tests.ini @@ -147,6 +147,7 @@ numthreads = 2 compileTest = 0 doVis = 0 compareParticles = 1 +runtime_params = warpx.do_dynamic_scheduling=0 particleTypes = particle0 particle1 analysisRoutine = Example/Langmuir/langmuir_multi_analysis.py analysisOutputImage = langmuir_multi_analysis.png @@ -169,6 +170,24 @@ particleTypes = particle0 particle1 analysisRoutine = Example/Langmuir/langmuir_multi_analysis.py analysisOutputImage = langmuir_multi_analysis.png +[Langmuir_multi_2d_psatd] +buildDir = . +inputFile = Example/Langmuir/inputs.multi.2d.rt +dim = 2 +addToCompileString = USE_PSATD=TRUE +restartTest = 0 +useMPI = 1 +numprocs = 4 +useOMP = 1 +numthreads = 1 +compileTest = 0 +doVis = 0 +compareParticles = 1 +runtime_params = psatd.fftw_plan_measure=0 +particleTypes = particle0 particle1 +analysisRoutine = Example/Langmuir/langmuir_multi_2d_analysis.py +analysisOutputImage = langmuir_multi_2d_analysis.png + [LaserInjection] buildDir = . inputFile = Example/laser_injection/inputs.rt @@ -250,7 +269,7 @@ dim = 3 restartTest = 0 useMPI = 1 numprocs = 2 -useOMP = 1 +useOMP = 0 numthreads = 0 compileTest = 0 doVis = 0 diff --git a/Source/WarpXFFT.cpp b/Source/WarpXFFT.cpp index f394d5f64..810a1b29c 100644 --- a/Source/WarpXFFT.cpp +++ b/Source/WarpXFFT.cpp @@ -266,7 +266,6 @@ void WarpX::FFTDomainDecompsition (int lev, BoxArray& ba_fft, DistributionMapping& dm_fft, BoxArray& ba_valid, Box& domain_fft, const Box& domain) { - AMREX_ALWAYS_ASSERT_WITH_MESSAGE(AMREX_SPACEDIM == 3, "PSATD only works in 3D"); IntVect nguards_fft(AMREX_D_DECL(nox_fft/2,noy_fft/2,noz_fft/2)); @@ -281,14 +280,15 @@ WarpX::FFTDomainDecompsition (int lev, BoxArray& ba_fft, DistributionMapping& dm // Ask FFTW to chop the current FFT sub-group domain in the z-direction // and give a chunk to each MPI rank in the current sub-group. int nz_fft, z0_fft; - warpx_fft_domain_decomp(&nz_fft, &z0_fft, BL_TO_FORTRAN_BOX(domain_fft)); + + warpx_fft_domain_decomp(&nz_fft, &z0_fft, WARPX_TO_FORTRAN_BOX(domain_fft)); // Each MPI rank adds a box with its chunk of the FFT grid // (given by the above decomposition) to the list `bx_fft`, // then list is shared among all MPI ranks via AllGather Vector<Box> bx_fft; if (nz_fft > 0) { Box b = domain_fft; - b.setRange(2, z0_fft+domain_fft.smallEnd(2), nz_fft); + b.setRange(AMREX_SPACEDIM-1, z0_fft+domain_fft.smallEnd(AMREX_SPACEDIM-1), nz_fft); bx_fft.push_back(b); } amrex::AllGatherBoxes(bx_fft); @@ -397,17 +397,17 @@ WarpX::PushPSATD (int lev, amrex::Real /* dt */) BL_PROFILE_VAR_START(blp_push_eb); for (MFIter mfi(*Efield_fp_fft[lev][0]); mfi.isValid(); ++mfi) { - warpx_fft_push_eb(BL_TO_FORTRAN_ANYD((*Efield_fp_fft[lev][0])[mfi]), - BL_TO_FORTRAN_ANYD((*Efield_fp_fft[lev][1])[mfi]), - BL_TO_FORTRAN_ANYD((*Efield_fp_fft[lev][2])[mfi]), - BL_TO_FORTRAN_ANYD((*Bfield_fp_fft[lev][0])[mfi]), - BL_TO_FORTRAN_ANYD((*Bfield_fp_fft[lev][1])[mfi]), - BL_TO_FORTRAN_ANYD((*Bfield_fp_fft[lev][2])[mfi]), - BL_TO_FORTRAN_ANYD((*current_fp_fft[lev][0])[mfi]), - BL_TO_FORTRAN_ANYD((*current_fp_fft[lev][1])[mfi]), - BL_TO_FORTRAN_ANYD((*current_fp_fft[lev][2])[mfi]), - BL_TO_FORTRAN_ANYD((*rho_prev_fp_fft[lev])[mfi]), - BL_TO_FORTRAN_ANYD((*rho_next_fp_fft[lev])[mfi])); + warpx_fft_push_eb(WARPX_TO_FORTRAN_ANYD((*Efield_fp_fft[lev][0])[mfi]), + WARPX_TO_FORTRAN_ANYD((*Efield_fp_fft[lev][1])[mfi]), + WARPX_TO_FORTRAN_ANYD((*Efield_fp_fft[lev][2])[mfi]), + WARPX_TO_FORTRAN_ANYD((*Bfield_fp_fft[lev][0])[mfi]), + WARPX_TO_FORTRAN_ANYD((*Bfield_fp_fft[lev][1])[mfi]), + WARPX_TO_FORTRAN_ANYD((*Bfield_fp_fft[lev][2])[mfi]), + WARPX_TO_FORTRAN_ANYD((*current_fp_fft[lev][0])[mfi]), + WARPX_TO_FORTRAN_ANYD((*current_fp_fft[lev][1])[mfi]), + WARPX_TO_FORTRAN_ANYD((*current_fp_fft[lev][2])[mfi]), + WARPX_TO_FORTRAN_ANYD((*rho_prev_fp_fft[lev])[mfi]), + WARPX_TO_FORTRAN_ANYD((*rho_next_fp_fft[lev])[mfi])); } BL_PROFILE_VAR_STOP(blp_push_eb); diff --git a/Source/WarpX_f.H b/Source/WarpX_f.H index 029c07377..377d8fd11 100644 --- a/Source/WarpX_f.H +++ b/Source/WarpX_f.H @@ -1,6 +1,19 @@ #include <AMReX_BLFort.H> +#ifdef __cplusplus + +#if AMREX_SPACEDIM==2 +#define WARPX_ARLIM_ANYD(x) std::array<int,3>{(x)[0], 0, (x)[1]}.data() +#else +#define WARPX_ARLIM_ANYD(x) x +#endif + +#define WARPX_TO_FORTRAN_BOX(x) WARPX_ARLIM_ANYD((x).loVect()), WARPX_ARLIM_ANYD((x).hiVect()) +#define WARPX_TO_FORTRAN_ANYD(x) (x).dataPtr(), WARPX_ARLIM_ANYD((x).loVect()), WARPX_ARLIM_ANYD((x).hiVect()) + +#endif + #if (AMREX_SPACEDIM == 3) #define WRPX_COMPUTE_DIVB warpx_compute_divb_3d diff --git a/Source/WarpX_fft.F90 b/Source/WarpX_fft.F90 index 406f3f90f..bdbdf7f3c 100644 --- a/Source/WarpX_fft.F90 +++ b/Source/WarpX_fft.F90 @@ -107,7 +107,6 @@ contains type(c_ptr), intent(inout) :: fft_data(ndata) real(c_double), intent(in) :: dx_wrpx(3), dt_wrpx - integer :: iret integer(idp) :: nopenmp integer :: nx_padded integer, dimension(3) :: shp @@ -297,7 +296,11 @@ contains rhoold => rhoold_wrpx ! Call the corresponding PICSAR function +#if (BL_SPACEDIM == 3) CALL push_psatd_ebfield_3d() +#elif (BL_SPACEDIM == 2) + CALL push_psatd_ebfield_2d() +#endif ex => null() ey => null() diff --git a/tests/CurrentDeposition/GNUmakefile b/tests/CurrentDeposition/GNUmakefile index bd400d019..05ac27a4b 100644 --- a/tests/CurrentDeposition/GNUmakefile +++ b/tests/CurrentDeposition/GNUmakefile @@ -17,6 +17,8 @@ include ./Make.package include $(AMREX_HOME)/Src/Base/Make.package include $(PICSAR_HOME)/src/Make.package +DEFINES += -DWARPX + default: $(executable) @echo SUCCESS diff --git a/tests/FieldGather/GNUmakefile b/tests/FieldGather/GNUmakefile index bd400d019..05ac27a4b 100644 --- a/tests/FieldGather/GNUmakefile +++ b/tests/FieldGather/GNUmakefile @@ -17,6 +17,8 @@ include ./Make.package include $(AMREX_HOME)/Src/Base/Make.package include $(PICSAR_HOME)/src/Make.package +DEFINES += -DWARPX + default: $(executable) @echo SUCCESS diff --git a/tests/FieldSolver/GNUmakefile b/tests/FieldSolver/GNUmakefile index bd400d019..05ac27a4b 100644 --- a/tests/FieldSolver/GNUmakefile +++ b/tests/FieldSolver/GNUmakefile @@ -17,6 +17,8 @@ include ./Make.package include $(AMREX_HOME)/Src/Base/Make.package include $(PICSAR_HOME)/src/Make.package +DEFINES += -DWARPX + default: $(executable) @echo SUCCESS diff --git a/tests/ParticlePusher/GNUmakefile b/tests/ParticlePusher/GNUmakefile index bd400d019..05ac27a4b 100644 --- a/tests/ParticlePusher/GNUmakefile +++ b/tests/ParticlePusher/GNUmakefile @@ -17,6 +17,8 @@ include ./Make.package include $(AMREX_HOME)/Src/Base/Make.package include $(PICSAR_HOME)/src/Make.package +DEFINES += -DWARPX + default: $(executable) @echo SUCCESS |