aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Edoardo Zoni <59625522+EZoni@users.noreply.github.com> 2022-12-07 15:40:02 -0800
committerGravatar GitHub <noreply@github.com> 2022-12-07 15:40:02 -0800
commit4073384c7b66b1848bcc94e6c986f7d532c7da11 (patch)
treea3a7d152098eff3f8c049638ac40b93a40551108
parent02447ce0f59e729865a8cbe9502bf6ca0c91e2cd (diff)
downloadWarpX-4073384c7b66b1848bcc94e6c986f7d532c7da11.tar.gz
WarpX-4073384c7b66b1848bcc94e6c986f7d532c7da11.tar.zst
WarpX-4073384c7b66b1848bcc94e6c986f7d532c7da11.zip
PSATD: Implement First-Order Equations (#3466)
* Implement First-Order PSATD Equations * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Fix Unused Parameter Warning * Fix RZ Build * Fix Normalization of G to Match PML * Add CI Test: 3D Uniform Plasma * Cleaning * Update 2D CI Checksums * Update 3D CI Checksums * Add F,G to CI Checksums of `uniform_plasma_multiJ` * Allow User to Choose First-Order v. Second-Order * Add WARPX_ALWAYS_ASSERT_WITH_MESSAGE * Rename New Class `PsatdAlgorithmFirstOrder` * Remove Inline Comment * Update RZ CI Checksums * Fix inline comment * Use auxiliary variables to avoid divisions * Use auxiliary variables to avoid divisions * Make `nci_psatd_stability` dir and merge inputs * Move all Galilean tests to `nci_psatd_stability` * Fix CI * Fix index for backward FFT of J Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
-rwxr-xr-xExamples/Tests/nci_psatd_stability/analysis_galilean.py (renamed from Examples/Tests/galilean/analysis.py)0
-rwxr-xr-xExamples/Tests/nci_psatd_stability/analysis_multiJ.py49
-rw-r--r--Examples/Tests/nci_psatd_stability/inputs_2d (renamed from Examples/Tests/galilean/inputs_2d)0
-rw-r--r--Examples/Tests/nci_psatd_stability/inputs_2d_hybrid (renamed from Examples/Tests/galilean/inputs_2d_hybrid)0
-rw-r--r--Examples/Tests/nci_psatd_stability/inputs_3d (renamed from Examples/Tests/galilean/inputs_3d)117
-rw-r--r--Examples/Tests/nci_psatd_stability/inputs_avg_2d (renamed from Examples/Tests/averaged_galilean/inputs_avg_2d)0
-rw-r--r--Examples/Tests/nci_psatd_stability/inputs_avg_3d (renamed from Examples/Tests/averaged_galilean/inputs_avg_3d)0
-rw-r--r--Examples/Tests/nci_psatd_stability/inputs_rz (renamed from Examples/Tests/galilean/inputs_rz)0
-rw-r--r--Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ.json24
-rw-r--r--Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ_nodal.json26
-rw-r--r--Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ.json36
-rw-r--r--Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ_nodal.json28
-rw-r--r--Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json40
-rw-r--r--Regression/Checksum/benchmarks_json/uniform_plasma_multiJ.json35
-rw-r--r--Regression/WarpX-tests.ini86
-rw-r--r--Source/BoundaryConditions/PML.H2
-rw-r--r--Source/BoundaryConditions/PML.cpp8
-rw-r--r--Source/Evolve/WarpXEvolve.cpp21
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/CMakeLists.txt1
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package1
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmComoving.cpp24
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.H100
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.cpp375
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmGalileanRZ.cpp12
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJConstantInTime.cpp42
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJLinearInTime.cpp6
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmRZ.cpp27
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralFieldData.H11
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp20
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralSolver.H3
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralSolver.cpp35
-rw-r--r--Source/FieldSolver/WarpXPushFieldsEM.cpp66
-rw-r--r--Source/Initialization/WarpXInitData.cpp4
-rw-r--r--Source/Utils/WarpXAlgorithmSelection.H11
-rw-r--r--Source/Utils/WarpXAlgorithmSelection.cpp10
-rw-r--r--Source/WarpX.H7
-rw-r--r--Source/WarpX.cpp22
37 files changed, 957 insertions, 292 deletions
diff --git a/Examples/Tests/galilean/analysis.py b/Examples/Tests/nci_psatd_stability/analysis_galilean.py
index 9fe6bab72..9fe6bab72 100755
--- a/Examples/Tests/galilean/analysis.py
+++ b/Examples/Tests/nci_psatd_stability/analysis_galilean.py
diff --git a/Examples/Tests/nci_psatd_stability/analysis_multiJ.py b/Examples/Tests/nci_psatd_stability/analysis_multiJ.py
new file mode 100755
index 000000000..1c68b114c
--- /dev/null
+++ b/Examples/Tests/nci_psatd_stability/analysis_multiJ.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+"""
+This script is used to test the results of the multi-J PSATD
+first-order equations, with one J deposition. It compares the
+energy of the electric field with a given reference energy.
+
+The reference energy is computed by running the same test with J constant
+in time, rho linear in time, and without divergence cleaning. The reference
+energy corresponds to unstable results due to NCI (suppressed by the use of
+both J and rho constant in time, and with divergence cleaning).
+"""
+import os
+import sys
+
+import numpy as np
+import scipy.constants as scc
+
+import yt ; yt.funcs.mylog.setLevel(0)
+sys.path.insert(1, '../../../../warpx/Regression/Checksum/')
+import checksumAPI
+
+filename = sys.argv[1]
+
+ds = yt.load(filename)
+
+# yt 4.0+ has rounding issues with our domain data:
+# RuntimeError: yt attempted to read outside the boundaries
+# of a non-periodic domain along dimension 0.
+if 'force_periodicity' in dir(ds): ds.force_periodicity()
+
+all_data = ds.covering_grid(level=0, left_edge=ds.domain_left_edge, dims=ds.domain_dimensions)
+Ex = all_data['boxlib', 'Ex'].squeeze().v
+Ey = all_data['boxlib', 'Ey'].squeeze().v
+Ez = all_data['boxlib', 'Ez'].squeeze().v
+
+# Set reference energy values, and tolerances for numerical stability and charge conservation
+tol_energy = 1e-8
+energy_ref = 66e6
+
+# Check numerical stability by comparing electric field energy to reference energy
+energy = np.sum(scc.epsilon_0/2*(Ex**2+Ey**2+Ez**2))
+err_energy = energy / energy_ref
+print('\nCheck numerical stability:')
+print(f'err_energy = {err_energy}')
+print(f'tol_energy = {tol_energy}')
+assert(err_energy < tol_energy)
+
+test_name = os.path.split(os.getcwd())[1]
+checksumAPI.evaluate_checksum(test_name, filename)
diff --git a/Examples/Tests/galilean/inputs_2d b/Examples/Tests/nci_psatd_stability/inputs_2d
index f19bfdde5..f19bfdde5 100644
--- a/Examples/Tests/galilean/inputs_2d
+++ b/Examples/Tests/nci_psatd_stability/inputs_2d
diff --git a/Examples/Tests/galilean/inputs_2d_hybrid b/Examples/Tests/nci_psatd_stability/inputs_2d_hybrid
index a9d1ecd14..a9d1ecd14 100644
--- a/Examples/Tests/galilean/inputs_2d_hybrid
+++ b/Examples/Tests/nci_psatd_stability/inputs_2d_hybrid
diff --git a/Examples/Tests/galilean/inputs_3d b/Examples/Tests/nci_psatd_stability/inputs_3d
index 7a0d80748..53305af12 100644
--- a/Examples/Tests/galilean/inputs_3d
+++ b/Examples/Tests/nci_psatd_stability/inputs_3d
@@ -1,84 +1,81 @@
-#################################
-####### GENERAL PARAMETERS ######
-#################################
-max_step = 300
-
-amr.n_cell = 32 32 32
-warpx.numprocs = 1 1 2
-amr.max_level = 0
-psatd.v_galilean = 0. 0. 0.99498743710662
-
-geometry.dims = 3
-geometry.prob_lo = -9.67 -9.67 -9.67
-geometry.prob_hi = 9.67 9.67 9.67
-
-#################################
-###### Boundary condition #######
-#################################
-boundary.field_lo = periodic periodic periodic
-boundary.field_hi = periodic periodic periodic
-
-#################################
-############ NUMERICS ###########
-#################################
-warpx.verbose = 1
-
+# algo
algo.current_deposition = direct
algo.maxwell_solver = psatd
algo.particle_pusher = vay
-
-warpx.cfl = 1.
algo.particle_shape = 3
-#################################
-############ PLASMA #############
-#################################
-particles.species_names = electrons ions
+# amr
+amr.max_level = 0
+amr.n_cell = 32 32 32
-warpx.do_nodal = 1
-warpx.use_filter = 1
+# boundary
+boundary.field_hi = periodic periodic periodic
+boundary.field_lo = periodic periodic periodic
-psatd.nox = 8
-psatd.noy = 8
-psatd.noz = 8
+# diag1
+diag1.diag_type = Full
+diag1.intervals = 300
+# diagnostics
+diagnostics.diags_names = diag1
+
+# electrons
electrons.charge = -q_e
-electrons.mass = m_e
+electrons.density = 282197938148984.7
electrons.injection_style = "NUniformPerCell"
+electrons.mass = m_e
+electrons.momentum_distribution_type = "gaussian"
electrons.num_particles_per_cell_each_dim = 1 1 1
electrons.profile = constant
-electrons.density = 282197938148984.7
-electrons.momentum_distribution_type = "gaussian"
-electrons.uz_m = 9.9498743710661994
-electrons.xmin = -9.67
-electrons.xmax = 9.67
-electrons.ymin = -9.67
-electrons.ymax = 9.67
-electrons.zmin = -9.67
-electrons.zmax = 9.67
electrons.ux_th = 0.0001
electrons.uy_th = 0.0001
+electrons.uz_m = 9.9498743710661994
electrons.uz_th = 0.0001
+electrons.xmax = 9.67
+electrons.xmin = -9.67
+electrons.ymax = 9.67
+electrons.ymin = -9.67
+electrons.zmax = 9.67
+electrons.zmin = -9.67
+
+# geometry
+geometry.dims = 3
+geometry.prob_hi = 9.67 9.67 9.67
+geometry.prob_lo = -9.67 -9.67 -9.67
+# ions
ions.charge = q_e
-ions.mass = m_p
+ions.density = 282197938148984.7
ions.injection_style = "NUniformPerCell"
+ions.mass = m_p
+ions.momentum_distribution_type = "gaussian"
ions.num_particles_per_cell_each_dim = 1 1 1
ions.profile = constant
-ions.density = 282197938148984.7
-ions.momentum_distribution_type = "gaussian"
-ions.uz_m = 9.9498743710661994
-ions.xmin = -9.67
-ions.xmax = 9.67
-ions.ymin = -9.67
-ions.ymax = 9.67
-ions.zmin = -9.67
-ions.zmax = 9.67
ions.ux_th = 0.0001
ions.uy_th = 0.0001
+ions.uz_m = 9.9498743710661994
ions.uz_th = 0.0001
+ions.xmax = 9.67
+ions.xmin = -9.67
+ions.ymax = 9.67
+ions.ymin = -9.67
+ions.zmax = 9.67
+ions.zmin = -9.67
-# Diagnostics
-diagnostics.diags_names = diag1
-diag1.intervals = 100
-diag1.diag_type = Full
+# max_step
+max_step = 300
+
+# particles
+particles.species_names = electrons ions
+
+# psatd
+psatd.nox = 8
+psatd.noy = 8
+psatd.noz = 8
+
+# warpx
+warpx.cfl = 1.
+warpx.do_nodal = 1
+warpx.numprocs = 1 1 2
+warpx.use_filter = 1
+warpx.verbose = 1
diff --git a/Examples/Tests/averaged_galilean/inputs_avg_2d b/Examples/Tests/nci_psatd_stability/inputs_avg_2d
index 2a2611906..2a2611906 100644
--- a/Examples/Tests/averaged_galilean/inputs_avg_2d
+++ b/Examples/Tests/nci_psatd_stability/inputs_avg_2d
diff --git a/Examples/Tests/averaged_galilean/inputs_avg_3d b/Examples/Tests/nci_psatd_stability/inputs_avg_3d
index bb76e4c47..bb76e4c47 100644
--- a/Examples/Tests/averaged_galilean/inputs_avg_3d
+++ b/Examples/Tests/nci_psatd_stability/inputs_avg_3d
diff --git a/Examples/Tests/galilean/inputs_rz b/Examples/Tests/nci_psatd_stability/inputs_rz
index 772711ddc..772711ddc 100644
--- a/Examples/Tests/galilean/inputs_rz
+++ b/Examples/Tests/nci_psatd_stability/inputs_rz
diff --git a/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ.json b/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ.json
index b0c362f0f..c342d9dca 100644
--- a/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ.json
+++ b/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ.json
@@ -1,29 +1,29 @@
{
"electrons": {
- "particle_momentum_x": 5.664739488600762e-20,
+ "particle_momentum_x": 5.663705657675969e-20,
"particle_momentum_y": 0.0,
- "particle_momentum_z": 5.664739488600764e-20,
- "particle_position_x": 0.6553599999999999,
+ "particle_momentum_z": 5.663705657675969e-20,
+ "particle_position_x": 0.65536,
"particle_position_y": 0.65536,
"particle_weight": 3200000000000000.5
},
"lev=0": {
"Bx": 0.0,
- "By": 3.4900393205053586,
+ "By": 3.4892704618136277,
"Bz": 0.0,
- "Ex": 3771422651410.755,
+ "Ex": 3771082786646.7104,
"Ey": 0.0,
- "Ez": 3771422651410.742,
- "jx": 1.0095457953459832e+16,
+ "Ez": 3771082786646.702,
+ "jx": 1.0093631772735916e+16,
"jy": 0.0,
- "jz": 1.0095457953459836e+16
+ "jz": 1.0093631772735912e+16
},
"positrons": {
- "particle_momentum_x": 5.664739488600754e-20,
+ "particle_momentum_x": 5.663705657675971e-20,
"particle_momentum_y": 0.0,
- "particle_momentum_z": 5.664739488600756e-20,
- "particle_position_x": 0.6553599999999999,
- "particle_position_y": 0.6553599999999999,
+ "particle_momentum_z": 5.663705657675969e-20,
+ "particle_position_x": 0.65536,
+ "particle_position_y": 0.65536,
"particle_weight": 3200000000000000.5
}
} \ No newline at end of file
diff --git a/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ_nodal.json b/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ_nodal.json
index 66c8e3e80..2aaa9e0f2 100644
--- a/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ_nodal.json
+++ b/Regression/Checksum/benchmarks_json/Langmuir_multi_2d_psatd_multiJ_nodal.json
@@ -1,29 +1,29 @@
{
"electrons": {
- "particle_momentum_x": 5.668522616618711e-20,
+ "particle_momentum_x": 5.668409581183492e-20,
"particle_momentum_y": 0.0,
- "particle_momentum_z": 5.668522616618715e-20,
- "particle_position_x": 0.6553600000002356,
- "particle_position_y": 0.6553600000002355,
+ "particle_momentum_z": 5.668409581183495e-20,
+ "particle_position_x": 0.6553600000004717,
+ "particle_position_y": 0.6553600000004718,
"particle_weight": 3200000000000000.5
},
"lev=0": {
"Bx": 0.0,
- "By": 5.6351165293218966,
+ "By": 5.634624433795568,
"Bz": 0.0,
- "Ex": 3747153697353.926,
+ "Ex": 3747068321640.6587,
"Ey": 0.0,
- "Ez": 3747153697353.9287,
- "jx": 1.0088631639558242e+16,
+ "Ez": 3747068321640.659,
+ "jx": 1.0088430505673088e+16,
"jy": 0.0,
- "jz": 1.0088631639558248e+16
+ "jz": 1.0088430505673096e+16
},
"positrons": {
- "particle_momentum_x": 5.66852261661871e-20,
+ "particle_momentum_x": 5.668409581183492e-20,
"particle_momentum_y": 0.0,
- "particle_momentum_z": 5.668522616618714e-20,
- "particle_position_x": 0.6553600000002356,
- "particle_position_y": 0.6553600000002356,
+ "particle_momentum_z": 5.668409581183495e-20,
+ "particle_position_x": 0.6553600000004718,
+ "particle_position_y": 0.6553600000004717,
"particle_weight": 3200000000000000.5
}
} \ No newline at end of file
diff --git a/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ.json b/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ.json
index c76d7cfc5..487d4a898 100644
--- a/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ.json
+++ b/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ.json
@@ -1,28 +1,28 @@
{
"electrons": {
- "particle_momentum_x": 9.629015522300135e-20,
- "particle_position_x": 2.621440000009873,
- "particle_position_y": 2.621440000009873,
- "particle_position_z": 2.6214399999999998,
+ "particle_momentum_x": 9.633869745818886e-20,
+ "particle_position_x": 2.621440000001177,
+ "particle_position_y": 2.6214400000011784,
+ "particle_position_z": 2.6214400000000007,
"particle_weight": 128000000000.00002
},
"lev=0": {
- "Bx": 79.96476923345703,
- "By": 79.96476923350225,
- "Bz": 79.96690317049361,
- "Ex": 84753887916472.72,
- "Ey": 84753887916472.66,
- "Ez": 84753877853695.67,
- "jx": 6.081254778189634e+16,
- "jy": 6.081254778189637e+16,
- "jz": 6.081251943036953e+16,
+ "Bx": 80.96035538655111,
+ "By": 80.96035538657691,
+ "Bz": 80.96271445263956,
+ "Ex": 84777489275096.88,
+ "Ey": 84777489275096.88,
+ "Ez": 84777485856239.4,
+ "jx": 6.08447015360442e+16,
+ "jy": 6.084470153604425e+16,
+ "jz": 6.084470085554113e+16,
"part_per_cell": 524288.0,
- "rho": 703417424.2676101
+ "rho": 703546536.8089281
},
"positrons": {
- "particle_momentum_z": 9.629011306229332e-20,
- "particle_position_x": 2.621440000009873,
- "particle_position_y": 2.621440000009873,
- "particle_position_z": 2.6214399999999998
+ "particle_momentum_z": 9.63386961193585e-20,
+ "particle_position_x": 2.621440000001177,
+ "particle_position_y": 2.621440000001179,
+ "particle_position_z": 2.6214400000000007
}
} \ No newline at end of file
diff --git a/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ_nodal.json b/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ_nodal.json
index 1f89c4dcb..e97556e55 100644
--- a/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ_nodal.json
+++ b/Regression/Checksum/benchmarks_json/Langmuir_multi_psatd_multiJ_nodal.json
@@ -1,28 +1,28 @@
{
"electrons": {
- "particle_momentum_x": 9.3282651765877e-20,
+ "particle_momentum_x": 9.320515980761094e-20,
"particle_position_x": 2.6214400000000015,
"particle_position_y": 2.621440000000001,
- "particle_position_z": 2.621440000000001,
+ "particle_position_z": 2.6214400000000007,
"particle_weight": 128000000000.00002
},
"lev=0": {
- "Bx": 17.338468210649435,
- "By": 17.338468210679473,
- "Bz": 17.338468210708463,
- "Ex": 86130544037694.12,
- "Ey": 86130544037694.16,
- "Ez": 86130544037694.16,
- "jx": 5.808322546347548e+16,
- "jy": 5.80832254634755e+16,
- "jz": 5.8083225463475464e+16,
+ "Bx": 17.319790986722108,
+ "By": 17.319790986747606,
+ "Bz": 17.319790986759728,
+ "Ex": 86079985956930.31,
+ "Ey": 86079985956930.3,
+ "Ez": 86079985956930.31,
+ "jx": 5.8033630197761816e+16,
+ "jy": 5.803363019776185e+16,
+ "jz": 5.803363019776182e+16,
"part_per_cell": 524288.0,
- "rho": 721143170.1131016
+ "rho": 720717041.7116292
},
"positrons": {
- "particle_momentum_z": 9.328265176587699e-20,
+ "particle_momentum_z": 9.320515980761093e-20,
"particle_position_x": 2.6214400000000015,
"particle_position_y": 2.621440000000001,
- "particle_position_z": 2.621440000000001
+ "particle_position_z": 2.6214400000000007
}
} \ No newline at end of file
diff --git a/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json b/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json
index 458117917..2a9620903 100644
--- a/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json
+++ b/Regression/Checksum/benchmarks_json/multi_J_rz_psatd.json
@@ -9,31 +9,31 @@
"particle_weight": 6241484108.424456
},
"lev=0": {
- "By": 24912.66260587033,
- "Ex": 4667306677660.305,
- "Ez": 4307437890419.4253,
- "jx": 362735950033724.2,
- "jz": 1937267340131275.2,
- "rho": 5308546.075566203,
- "rho_driver": 6288266.101815152,
- "rho_plasma_e": 49569864.00850832,
- "rho_plasma_p": 50769174.61530346
+ "By": 24045.34926330333,
+ "Ex": 4530500183998.0205,
+ "Ez": 4297045713383.818,
+ "jx": 361149490291532.8,
+ "jz": 1805428826325930.2,
+ "rho": 4895064.444869195,
+ "rho_driver": 6288266.101815153,
+ "rho_plasma_e": 49569825.13450765,
+ "rho_plasma_p": 50769176.974483095
},
"plasma_e": {
- "particle_momentum_x": 6.65811141013141e-20,
- "particle_momentum_y": 6.738987045495091e-20,
- "particle_momentum_z": 2.846571109435123e-20,
- "particle_position_x": 1.1423367495493797,
- "particle_position_y": 0.6139715590509269,
- "particle_theta": 20188.939948727297,
+ "particle_momentum_x": 6.649609416554171e-20,
+ "particle_momentum_y": 6.724424134488497e-20,
+ "particle_momentum_z": 2.81433599356851e-20,
+ "particle_position_x": 1.14233458508442,
+ "particle_position_y": 0.6140029351346352,
+ "particle_theta": 20188.939948727293,
"particle_weight": 1002457942911.3788
},
"plasma_p": {
- "particle_momentum_x": 6.640192720118765e-20,
- "particle_momentum_y": 6.767588557043428e-20,
- "particle_momentum_z": 5.58476124317102e-20,
- "particle_position_x": 1.1365201600226575,
- "particle_position_y": 0.6152066982817419,
+ "particle_momentum_x": 6.635739630451454e-20,
+ "particle_momentum_y": 6.761235868190358e-20,
+ "particle_momentum_z": 5.475884783890083e-20,
+ "particle_position_x": 1.1365201524804165,
+ "particle_position_y": 0.6152066555308389,
"particle_theta": 20286.92798337582,
"particle_weight": 1002457942911.3788
}
diff --git a/Regression/Checksum/benchmarks_json/uniform_plasma_multiJ.json b/Regression/Checksum/benchmarks_json/uniform_plasma_multiJ.json
new file mode 100644
index 000000000..e215428fe
--- /dev/null
+++ b/Regression/Checksum/benchmarks_json/uniform_plasma_multiJ.json
@@ -0,0 +1,35 @@
+{
+ "electrons": {
+ "particle_momentum_x": 2.4258140600451355e-21,
+ "particle_momentum_y": 2.4115944515722047e-21,
+ "particle_momentum_z": 8.903860561145549e-17,
+ "particle_position_x": 158433.52093622342,
+ "particle_position_y": 158432.7590925775,
+ "particle_position_z": 158433.27723231513,
+ "particle_weight": 2.041377132710917e+18
+ },
+ "ions": {
+ "particle_momentum_x": 1.3150385606388975e-18,
+ "particle_momentum_y": 1.3042988334363742e-18,
+ "particle_momentum_z": 1.6348805659682514e-13,
+ "particle_position_x": 158433.5805512471,
+ "particle_position_y": 158432.80155515939,
+ "particle_position_z": 158433.27779468897,
+ "particle_weight": 2.041377132710917e+18
+ },
+ "lev=0": {
+ "Bx": 0.054117593911342535,
+ "By": 0.053964421360199535,
+ "Bz": 0.0005552030959216721,
+ "divE": 18542936.02490211,
+ "Ex": 16260950.356941158,
+ "Ey": 16306834.079553638,
+ "Ez": 5784750.2181154955,
+ "F": 2.003020981926516e-02,
+ "G": 1.349588434641251e+03,
+ "jx": 984.2101557440694,
+ "jy": 1030.1973073214422,
+ "jz": 20803.708075753144,
+ "rho": 8.4139043087009e-05
+ }
+}
diff --git a/Regression/WarpX-tests.ini b/Regression/WarpX-tests.ini
index c3b1ad67a..57930ea44 100644
--- a/Regression/WarpX-tests.ini
+++ b/Regression/WarpX-tests.ini
@@ -412,7 +412,7 @@ analysisOutputImage = langmuir_multi_analysis.png
[Langmuir_multi_psatd_multiJ]
buildDir = .
inputFile = Examples/Tests/langmuir/inputs_3d_multi_rt
-runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.5773502691896258 algo.current_deposition=direct psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium
+runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.5773502691896258 algo.current_deposition=direct psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.solution_type=first-order psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium
dim = 3
addToCompileString = USE_PSATD=TRUE
cmakeSetupOpts = -DWarpX_DIMS=3 -DWarpX_PSATD=ON
@@ -431,7 +431,7 @@ analysisOutputImage = Langmuir_multi_psatd_multiJ.png
[Langmuir_multi_psatd_multiJ_nodal]
buildDir = .
inputFile = Examples/Tests/langmuir/inputs_3d_multi_rt
-runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.5773502691896258 algo.current_deposition=direct psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium warpx.do_nodal=1
+runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.5773502691896258 algo.current_deposition=direct psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.solution_type=first-order psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium warpx.do_nodal=1
dim = 3
addToCompileString = USE_PSATD=TRUE
cmakeSetupOpts = -DWarpX_DIMS=3 -DWarpX_PSATD=ON
@@ -697,7 +697,7 @@ analysisOutputImage = langmuir_multi_2d_analysis.png
[Langmuir_multi_2d_psatd_multiJ]
buildDir = .
inputFile = Examples/Tests/langmuir/inputs_2d_multi_rt
-runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.7071067811865475 psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium
+runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.7071067811865475 psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.solution_type=first-order psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium
dim = 2
addToCompileString = USE_PSATD=TRUE
cmakeSetupOpts = -DWarpX_DIMS=2 -DWarpX_PSATD=ON
@@ -716,7 +716,7 @@ analysisOutputImage = Langmuir_multi_2d_psatd_multiJ.png
[Langmuir_multi_2d_psatd_multiJ_nodal]
buildDir = .
inputFile = Examples/Tests/langmuir/inputs_2d_multi_rt
-runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.7071067811865475 psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium warpx.do_nodal=1
+runtime_params = algo.maxwell_solver=psatd warpx.cfl=0.7071067811865475 psatd.update_with_rho=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=2 psatd.solution_type=first-order psatd.J_in_time=linear warpx.abort_on_warning_threshold=medium warpx.do_nodal=1
dim = 2
addToCompileString = USE_PSATD=TRUE
cmakeSetupOpts = -DWarpX_DIMS=2 -DWarpX_PSATD=ON
@@ -2517,7 +2517,7 @@ analysisRoutine = Examples/Tests/particle_fields_diags/analysis_particle_diags_s
[galilean_2d_psatd]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_2d
+inputFile = Examples/Tests/nci_psatd_stability/inputs_2d
runtime_params = warpx.do_nodal=1 algo.current_deposition=direct psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 2
addToCompileString = USE_PSATD=TRUE
@@ -2531,11 +2531,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_2d_psatd_current_correction_psb]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_2d
+inputFile = Examples/Tests/nci_psatd_stability/inputs_2d
runtime_params = psatd.periodic_single_box_fft=1 psatd.update_with_rho=0 psatd.current_correction=1 diag1.fields_to_plot=Ex Ey Ez Bx By Bz jx jy jz rho divE
dim = 2
addToCompileString = USE_PSATD=TRUE
@@ -2549,11 +2549,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_2d_psatd_current_correction]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_2d
+inputFile = Examples/Tests/nci_psatd_stability/inputs_2d
runtime_params = psatd.periodic_single_box_fft=0 psatd.update_with_rho=0 psatd.current_correction=1 diag1.fields_to_plot=Ex Ey Ez Bx By Bz jx jy jz rho divE amr.max_grid_size=64 amr.blocking_factor=64
dim = 2
addToCompileString = USE_PSATD=TRUE
@@ -2567,11 +2567,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_2d_psatd_hybrid]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_2d_hybrid
+inputFile = Examples/Tests/nci_psatd_stability/inputs_2d_hybrid
runtime_params = psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 2
addToCompileString = USE_PSATD=TRUE
@@ -2607,7 +2607,7 @@ analysisRoutine = Examples/analysis_default_regression.py
[galilean_rz_psatd]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_rz
+inputFile = Examples/Tests/nci_psatd_stability/inputs_rz
runtime_params = warpx.do_dynamic_scheduling=0 warpx.serialize_initial_conditions=1 electrons.random_theta=0 ions.random_theta=0 psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 2
addToCompileString = USE_RZ=TRUE USE_PSATD=TRUE BLAS_LIB=-lblas LAPACK_LIB=-llapack
@@ -2621,11 +2621,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_rz_psatd_current_correction_psb]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_rz
+inputFile = Examples/Tests/nci_psatd_stability/inputs_rz
runtime_params = psatd.periodic_single_box_fft=1 psatd.current_correction=1 electrons.random_theta=0 ions.random_theta=0
dim = 2
addToCompileString = USE_RZ=TRUE USE_PSATD=TRUE BLAS_LIB=-lblas LAPACK_LIB=-llapack
@@ -2639,11 +2639,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_rz_psatd_current_correction]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_rz
+inputFile = Examples/Tests/nci_psatd_stability/inputs_rz
runtime_params = psatd.periodic_single_box_fft=0 psatd.current_correction=1 electrons.random_theta=0 ions.random_theta=0 amr.max_grid_size=32 amr.blocking_factor=32
dim = 2
addToCompileString = USE_RZ=TRUE USE_PSATD=TRUE BLAS_LIB=-lblas LAPACK_LIB=-llapack
@@ -2657,12 +2657,12 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_3d_psatd]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_3d
-runtime_params = warpx.do_nodal=1 algo.current_deposition=direct psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
+inputFile = Examples/Tests/nci_psatd_stability/inputs_3d
+runtime_params = psatd.v_galilean=0. 0. 0.99498743710662 psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 3
addToCompileString = USE_PSATD=TRUE
cmakeSetupOpts = -DWarpX_DIMS=3 -DWarpX_PSATD=ON
@@ -2675,12 +2675,12 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_3d_psatd_current_correction_psb]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_3d
-runtime_params = warpx.numprocs=1 1 1 psatd.periodic_single_box_fft=1 psatd.update_with_rho=0 psatd.current_correction=1 diag1.fields_to_plot=Ex Ey Ez Bx By Bz jx jy jz rho divE
+inputFile = Examples/Tests/nci_psatd_stability/inputs_3d
+runtime_params = psatd.v_galilean=0. 0. 0.99498743710662 warpx.numprocs=1 1 1 psatd.periodic_single_box_fft=1 psatd.update_with_rho=0 psatd.current_correction=1 diag1.fields_to_plot=Ex Ey Ez Bx By Bz jx jy jz rho divE
dim = 3
addToCompileString = USE_PSATD=TRUE
cmakeSetupOpts = -DWarpX_DIMS=3 -DWarpX_PSATD=ON
@@ -2693,12 +2693,12 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[galilean_3d_psatd_current_correction]
buildDir = .
-inputFile = Examples/Tests/galilean/inputs_3d
-runtime_params = warpx.numprocs=1 1 2 psatd.periodic_single_box_fft=0 psatd.update_with_rho=0 psatd.current_correction=1 diag1.fields_to_plot=Ex Ey Ez Bx By Bz jx jy jz rho divE
+inputFile = Examples/Tests/nci_psatd_stability/inputs_3d
+runtime_params = psatd.v_galilean=0. 0. 0.99498743710662 warpx.numprocs=1 1 2 psatd.periodic_single_box_fft=0 psatd.update_with_rho=0 psatd.current_correction=1 diag1.fields_to_plot=Ex Ey Ez Bx By Bz jx jy jz rho divE
dim = 3
addToCompileString = USE_PSATD=TRUE
cmakeSetupOpts = -DWarpX_DIMS=3 -DWarpX_PSATD=ON
@@ -2711,11 +2711,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[averaged_galilean_2d_psatd]
buildDir = .
-inputFile = Examples/Tests/averaged_galilean/inputs_avg_2d
+inputFile = Examples/Tests/nci_psatd_stability/inputs_avg_2d
runtime_params = psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 2
addToCompileString = USE_PSATD=TRUE
@@ -2729,11 +2729,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[averaged_galilean_2d_psatd_hybrid]
buildDir = .
-inputFile = Examples/Tests/averaged_galilean/inputs_avg_2d
+inputFile = Examples/Tests/nci_psatd_stability/inputs_avg_2d
runtime_params = amr.max_grid_size_x = 128 amr.max_grid_size_y = 64 warpx.do_nodal = 0 algo.field_gathering = momentum-conserving interpolation.field_centering_nox = 8 interpolation.field_centering_noz = 8 warpx.do_current_centering = 1 interpolation.current_centering_nox = 8 interpolation.current_centering_noz = 8 psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 2
addToCompileString = USE_PSATD=TRUE
@@ -2747,11 +2747,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[averaged_galilean_3d_psatd]
buildDir = .
-inputFile = Examples/Tests/averaged_galilean/inputs_avg_3d
+inputFile = Examples/Tests/nci_psatd_stability/inputs_avg_3d
runtime_params = psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 3
addToCompileString = USE_PSATD=TRUE
@@ -2765,11 +2765,11 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[averaged_galilean_3d_psatd_hybrid]
buildDir = .
-inputFile = Examples/Tests/averaged_galilean/inputs_avg_3d
+inputFile = Examples/Tests/nci_psatd_stability/inputs_avg_3d
runtime_params = warpx.do_nodal = 0 algo.field_gathering = momentum-conserving interpolation.field_centering_nox = 8 interpolation.field_centering_noy = 8 interpolation.field_centering_noz = 8 warpx.do_current_centering = 1 interpolation.current_centering_nox = 8 interpolation.current_centering_noy = 8 interpolation.current_centering_noz = 8 psatd.current_correction=0 warpx.abort_on_warning_threshold=medium
dim = 3
addToCompileString = USE_PSATD=TRUE
@@ -2783,7 +2783,7 @@ compileTest = 0
doVis = 0
compareParticles = 1
particleTypes = electrons ions
-analysisRoutine = Examples/Tests/galilean/analysis.py
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_galilean.py
[multi_J_rz_psatd]
buildDir = .
@@ -3748,3 +3748,21 @@ numthreads = 1
compileTest = 0
doVis = 0
analysisRoutine = Examples/Tests/btd_rz/analysis_BTD_laser_antenna.py
+
+[uniform_plasma_multiJ]
+buildDir = .
+inputFile = Examples/Tests/nci_psatd_stability/inputs_3d
+runtime_params = psatd.solution_type=first-order psatd.J_in_time=constant psatd.rho_in_time=constant warpx.do_dive_cleaning=1 warpx.do_divb_cleaning=1 warpx.do_multi_J=1 warpx.do_multi_J_n_depositions=1 diag1.fields_to_plot=Bx By Bz divE Ex Ey Ez F G jx jy jz rho warpx.abort_on_warning_threshold=medium
+dim = 3
+addToCompileString = USE_PSATD=TRUE
+cmakeSetupOpts = -DWarpX_DIMS=3 -DWarpX_PSATD=ON
+restartTest = 0
+useMPI = 1
+numprocs = 2
+useOMP = 1
+numthreads = 1
+compileTest = 0
+doVis = 0
+compareParticles = 1
+particleTypes = electrons ions
+analysisRoutine = Examples/Tests/nci_psatd_stability/analysis_multiJ.py
diff --git a/Source/BoundaryConditions/PML.H b/Source/BoundaryConditions/PML.H
index a1ce21a91..e519298ca 100644
--- a/Source/BoundaryConditions/PML.H
+++ b/Source/BoundaryConditions/PML.H
@@ -133,7 +133,7 @@ public:
int ncell, int delta, amrex::IntVect ref_ratio,
amrex::Real dt, int nox_fft, int noy_fft, int noz_fft, bool do_nodal,
int do_moving_window, int pml_has_particles, int do_pml_in_domain,
- const int J_in_time, const int rho_in_time,
+ const int psatd_solution_type, const int J_in_time, const int rho_in_time,
const bool do_pml_dive_cleaning, const bool do_pml_divb_cleaning,
const amrex::IntVect& fill_guards_fields,
const amrex::IntVect& fill_guards_current,
diff --git a/Source/BoundaryConditions/PML.cpp b/Source/BoundaryConditions/PML.cpp
index c7b773123..5e03822f1 100644
--- a/Source/BoundaryConditions/PML.cpp
+++ b/Source/BoundaryConditions/PML.cpp
@@ -548,7 +548,7 @@ PML::PML (const int lev, const BoxArray& grid_ba, const DistributionMapping& gri
int ncell, int delta, amrex::IntVect ref_ratio,
Real dt, int nox_fft, int noy_fft, int noz_fft, bool do_nodal,
int do_moving_window, int /*pml_has_particles*/, int do_pml_in_domain,
- const int J_in_time, const int rho_in_time,
+ const int psatd_solution_type, const int J_in_time, const int rho_in_time,
const bool do_pml_dive_cleaning, const bool do_pml_divb_cleaning,
const amrex::IntVect& fill_guards_fields,
const amrex::IntVect& fill_guards_current,
@@ -724,7 +724,7 @@ PML::PML (const int lev, const BoxArray& grid_ba, const DistributionMapping& gri
if (WarpX::electromagnetic_solver_id == ElectromagneticSolverAlgo::PSATD) {
#ifndef WARPX_USE_PSATD
- amrex::ignore_unused(lev, dt, J_in_time, rho_in_time);
+ amrex::ignore_unused(lev, dt, psatd_solution_type, J_in_time, rho_in_time);
# if(AMREX_SPACEDIM!=3)
amrex::ignore_unused(noy_fft);
# endif
@@ -745,7 +745,7 @@ PML::PML (const int lev, const BoxArray& grid_ba, const DistributionMapping& gri
spectral_solver_fp = std::make_unique<SpectralSolver>(lev, realspace_ba, dm,
nox_fft, noy_fft, noz_fft, do_nodal, v_galilean_zero,
v_comoving_zero, dx, dt, in_pml, periodic_single_box, update_with_rho,
- fft_do_time_averaging, J_in_time, rho_in_time, m_dive_cleaning, m_divb_cleaning);
+ fft_do_time_averaging, psatd_solution_type, J_in_time, rho_in_time, m_dive_cleaning, m_divb_cleaning);
#endif
}
@@ -852,7 +852,7 @@ PML::PML (const int lev, const BoxArray& grid_ba, const DistributionMapping& gri
spectral_solver_cp = std::make_unique<SpectralSolver>(lev, realspace_cba, cdm,
nox_fft, noy_fft, noz_fft, do_nodal, v_galilean_zero,
v_comoving_zero, cdx, dt, in_pml, periodic_single_box, update_with_rho,
- fft_do_time_averaging, J_in_time, rho_in_time, m_dive_cleaning, m_divb_cleaning);
+ fft_do_time_averaging, psatd_solution_type, J_in_time, rho_in_time, m_dive_cleaning, m_divb_cleaning);
#endif
}
}
diff --git a/Source/Evolve/WarpXEvolve.cpp b/Source/Evolve/WarpXEvolve.cpp
index e8e6a025b..8abfa0e7f 100644
--- a/Source/Evolve/WarpXEvolve.cpp
+++ b/Source/Evolve/WarpXEvolve.cpp
@@ -549,14 +549,14 @@ WarpX::OneStep_multiJ (const amrex::Real cur_time)
// 3) Deposit rho (in rho_new, since it will be moved during the loop)
// (after checking that pointer to rho_fp on MR level 0 is not null)
- if (rho_fp[0])
+ if (rho_fp[0] && rho_in_time == RhoInTime::Linear)
{
// Deposit rho at relative time -dt
// (dt[0] denotes the time step on mesh refinement level 0)
mypc->DepositCharge(rho_fp, -dt[0]);
// Filter, exchange boundary, and interpolate across levels
SyncRho();
- // Forward FFT of rho_new
+ // Forward FFT of rho
PSATDForwardTransformRho(rho_fp, rho_cp, 0, 1);
}
@@ -587,17 +587,14 @@ WarpX::OneStep_multiJ (const amrex::Real cur_time)
// Loop over multi-J depositions
for (int i_depose = 0; i_depose < n_loop; i_depose++)
{
- // Move J deposited previously, from new to old
- if (J_in_time == JInTime::Linear)
- {
- PSATDMoveJNewToJOld();
- }
+ // Move J from new to old if J is linear in time
+ if (J_in_time == JInTime::Linear) PSATDMoveJNewToJOld();
const amrex::Real t_depose_current = (J_in_time == JInTime::Linear) ?
(i_depose-n_depose+1)*sub_dt : (i_depose-n_depose+0.5_rt)*sub_dt;
- // TODO Update this when rho quadratic in time is implemented
- const amrex::Real t_depose_charge = (i_depose-n_depose+1)*sub_dt;
+ const amrex::Real t_depose_charge = (rho_in_time == RhoInTime::Linear) ?
+ (i_depose-n_depose+1)*sub_dt : (i_depose-n_depose+0.5_rt)*sub_dt;
// Deposit new J at relative time t_depose_current with time step dt
// (dt[0] denotes the time step on mesh refinement level 0)
@@ -616,14 +613,14 @@ WarpX::OneStep_multiJ (const amrex::Real cur_time)
// (after checking that pointer to rho_fp on MR level 0 is not null)
if (rho_fp[0])
{
- // Move rho deposited previously, from new to old
- PSATDMoveRhoNewToRhoOld();
+ // Move rho from new to old if rho is linear in time
+ if (rho_in_time == RhoInTime::Linear) PSATDMoveRhoNewToRhoOld();
// Deposit rho at relative time t_depose_charge
mypc->DepositCharge(rho_fp, t_depose_charge);
// Filter, exchange boundary, and interpolate across levels
SyncRho();
- // Forward FFT of rho_new
+ // Forward FFT of rho
PSATDForwardTransformRho(rho_fp, rho_cp, 0, 1);
}
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/CMakeLists.txt b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/CMakeLists.txt
index a370d4b2d..912ed47c4 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/CMakeLists.txt
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/CMakeLists.txt
@@ -1,5 +1,6 @@
target_sources(WarpX
PRIVATE
+ PsatdAlgorithmFirstOrder.cpp
PsatdAlgorithmJConstantInTime.cpp
PsatdAlgorithmJLinearInTime.cpp
PsatdAlgorithmPml.cpp
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package
index c798ffb01..40f9d0e9a 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/Make.package
@@ -1,4 +1,5 @@
CEXE_sources += SpectralBaseAlgorithm.cpp
+CEXE_sources += PsatdAlgorithmFirstOrder.cpp
CEXE_sources += PsatdAlgorithmJConstantInTime.cpp
CEXE_sources += PsatdAlgorithmJLinearInTime.cpp
CEXE_sources += PsatdAlgorithmPml.cpp
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmComoving.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmComoving.cpp
index 1d6248f8d..dfd7ffe92 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmComoving.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmComoving.cpp
@@ -103,9 +103,9 @@ PsatdAlgorithmComoving::pushSpectralFields (SpectralFieldData& f) const
const Complex Bz_old = fields(i,j,k,Idx.Bz);
// Shortcuts for the values of J and rho
- const Complex Jx = fields(i,j,k,Idx.Jx);
- const Complex Jy = fields(i,j,k,Idx.Jy);
- const Complex Jz = fields(i,j,k,Idx.Jz);
+ const Complex Jx = fields(i,j,k,Idx.Jx_mid);
+ const Complex Jy = fields(i,j,k,Idx.Jy_mid);
+ const Complex Jz = fields(i,j,k,Idx.Jz_mid);
const Complex rho_old = fields(i,j,k,Idx.rho_old);
const Complex rho_new = fields(i,j,k,Idx.rho_new);
@@ -447,9 +447,9 @@ void PsatdAlgorithmComoving::CurrentCorrection (SpectralFieldData& field_data)
amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
{
// Shortcuts for the values of J and rho
- const Complex Jx = fields(i,j,k,Idx.Jx);
- const Complex Jy = fields(i,j,k,Idx.Jy);
- const Complex Jz = fields(i,j,k,Idx.Jz);
+ const Complex Jx = fields(i,j,k,Idx.Jx_mid);
+ const Complex Jy = fields(i,j,k,Idx.Jy_mid);
+ const Complex Jz = fields(i,j,k,Idx.Jz_mid);
const Complex rho_old = fields(i,j,k,Idx.rho_old);
const Complex rho_new = fields(i,j,k,Idx.rho_new);
@@ -482,15 +482,15 @@ void PsatdAlgorithmComoving::CurrentCorrection (SpectralFieldData& field_data)
const Complex theta = amrex::exp(- I * k_dot_v * dt * 0.5_rt);
const Complex den = 1._rt - theta * theta;
- fields(i,j,k,Idx.Jx) = Jx - (kmod_dot_J + k_dot_v * theta * (rho_new - rho_old) / den) * kx_mod / (knorm_mod * knorm_mod);
- fields(i,j,k,Idx.Jy) = Jy - (kmod_dot_J + k_dot_v * theta * (rho_new - rho_old) / den) * ky_mod / (knorm_mod * knorm_mod);
- fields(i,j,k,Idx.Jz) = Jz - (kmod_dot_J + k_dot_v * theta * (rho_new - rho_old) / den) * kz_mod / (knorm_mod * knorm_mod);
+ fields(i,j,k,Idx.Jx_mid) = Jx - (kmod_dot_J + k_dot_v * theta * (rho_new - rho_old) / den) * kx_mod / (knorm_mod * knorm_mod);
+ fields(i,j,k,Idx.Jy_mid) = Jy - (kmod_dot_J + k_dot_v * theta * (rho_new - rho_old) / den) * ky_mod / (knorm_mod * knorm_mod);
+ fields(i,j,k,Idx.Jz_mid) = Jz - (kmod_dot_J + k_dot_v * theta * (rho_new - rho_old) / den) * kz_mod / (knorm_mod * knorm_mod);
} else {
- fields(i,j,k,Idx.Jx) = Jx - (kmod_dot_J - I * (rho_new - rho_old) / dt) * kx_mod / (knorm_mod * knorm_mod);
- fields(i,j,k,Idx.Jy) = Jy - (kmod_dot_J - I * (rho_new - rho_old) / dt) * ky_mod / (knorm_mod * knorm_mod);
- fields(i,j,k,Idx.Jz) = Jz - (kmod_dot_J - I * (rho_new - rho_old) / dt) * kz_mod / (knorm_mod * knorm_mod);
+ fields(i,j,k,Idx.Jx_mid) = Jx - (kmod_dot_J - I * (rho_new - rho_old) / dt) * kx_mod / (knorm_mod * knorm_mod);
+ fields(i,j,k,Idx.Jy_mid) = Jy - (kmod_dot_J - I * (rho_new - rho_old) / dt) * ky_mod / (knorm_mod * knorm_mod);
+ fields(i,j,k,Idx.Jz_mid) = Jz - (kmod_dot_J - I * (rho_new - rho_old) / dt) * kz_mod / (knorm_mod * knorm_mod);
}
}
});
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.H b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.H
new file mode 100644
index 000000000..c90b19e1a
--- /dev/null
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.H
@@ -0,0 +1,100 @@
+/* Copyright 2019
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+#ifndef WARPX_PSATD_ALGORITHM_FIRST_ORDER_H_
+#define WARPX_PSATD_ALGORITHM_FIRST_ORDER_H_
+
+#include "FieldSolver/SpectralSolver/SpectralFieldData.H"
+#include "FieldSolver/SpectralSolver/SpectralKSpace.H"
+#include "SpectralBaseAlgorithm.H"
+
+#include <AMReX_Array.H>
+#include <AMReX_Config.H>
+#include <AMReX_REAL.H>
+
+#include <AMReX_BaseFwd.H>
+
+#include <array>
+#include <memory>
+
+#if WARPX_USE_PSATD
+/*
+ * \brief Class that updates the fields in spectral space according to the first-order PSATD equations.
+ */
+class PsatdAlgorithmFirstOrder : public SpectralBaseAlgorithm
+{
+ public:
+
+ /**
+ * \brief Constructor of the class PsatdAlgorithmFirstOrder
+ *
+ * \param[in] spectral_kspace spectral space
+ * \param[in] dm distribution mapping
+ * \param[in] spectral_index object containing indices to access data in spectral space
+ * \param[in] norder_x order of the spectral solver along x
+ * \param[in] norder_y order of the spectral solver along y
+ * \param[in] norder_z order of the spectral solver along z
+ * \param[in] nodal whether the E and B fields are defined on a fully nodal grid or a Yee grid
+ * \param[in] dt time step of the simulation
+ * \param[in] div_cleaning whether to use divergence correction for both E and B (thus, F and G)
+ * \param[in] J_in_time time dependency of J (currently supported: constant, linear)
+ * \param[in] rho_in_time time dependency of rho (currently supported: constant, linear)
+ */
+ PsatdAlgorithmFirstOrder (
+ const SpectralKSpace& spectral_kspace,
+ const amrex::DistributionMapping& dm,
+ const SpectralFieldIndex& spectral_index,
+ const int norder_x,
+ const int norder_y,
+ const int norder_z,
+ const bool nodal,
+ const amrex::Real dt,
+ const bool div_cleaning,
+ const int J_in_time,
+ const int rho_in_time);
+
+ /**
+ * \brief Updates E, B, F, and G fields in spectral space,
+ * according to the first-order PSATD equations
+ *
+ * \param[in,out] f all the fields in spectral space
+ */
+ virtual void pushSpectralFields (SpectralFieldData& f) const override final;
+
+ /**
+ * \brief Virtual function for current correction in Fourier space
+ * (<a href="https://doi.org/10.1016/j.jcp.2013.03.010"> Vay et al, 2013</a>).
+ * This function overrides the virtual function \c CurrentCorrection in the
+ * base class \c SpectralBaseAlgorithm and cannot be overridden by further
+ * derived classes.
+ *
+ * \param[in,out] field_data All fields in Fourier space
+ */
+ virtual void CurrentCorrection (SpectralFieldData& field_data) override final;
+
+ /**
+ * \brief Virtual function for Vay current deposition in Fourier space
+ * (<a href="https://doi.org/10.1016/j.jcp.2013.03.010"> Vay et al, 2013</a>).
+ * This function overrides the virtual function \c VayDeposition in the
+ * base class \c SpectralBaseAlgorithm and cannot be overridden by further
+ * derived classes.
+ *
+ * \param[in,out] field_data All fields in Fourier space
+ */
+ virtual void VayDeposition (SpectralFieldData& field_data) override final;
+
+ private:
+
+ SpectralFieldIndex m_spectral_index;
+
+ // Other member variables
+ amrex::Real m_dt;
+ bool m_div_cleaning;
+ int m_J_in_time;
+ int m_rho_in_time;
+};
+#endif // WARPX_USE_PSATD
+#endif // WARPX_PSATD_ALGORITHM_FIRST_ORDER_H_
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.cpp
new file mode 100644
index 000000000..d32604760
--- /dev/null
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmFirstOrder.cpp
@@ -0,0 +1,375 @@
+/* Copyright 2019
+ *
+ * This file is part of WarpX.
+ *
+ * License: BSD-3-Clause-LBNL
+ */
+#include "PsatdAlgorithmFirstOrder.H"
+
+#include "Utils/TextMsg.H"
+#include "Utils/WarpXAlgorithmSelection.H"
+#include "Utils/WarpXConst.H"
+#include "Utils/WarpX_Complex.H"
+
+#include <AMReX_Array4.H>
+#include <AMReX_BLProfiler.H>
+#include <AMReX_BaseFab.H>
+#include <AMReX_BoxArray.H>
+#include <AMReX_GpuComplex.H>
+#include <AMReX_GpuLaunch.H>
+#include <AMReX_GpuQualifiers.H>
+#include <AMReX_IntVect.H>
+#include <AMReX_MFIter.H>
+#include <AMReX_PODVector.H>
+
+#include <cmath>
+
+#if WARPX_USE_PSATD
+
+using namespace amrex::literals;
+
+PsatdAlgorithmFirstOrder::PsatdAlgorithmFirstOrder(
+ const SpectralKSpace& spectral_kspace,
+ const amrex::DistributionMapping& dm,
+ const SpectralFieldIndex& spectral_index,
+ const int norder_x,
+ const int norder_y,
+ const int norder_z,
+ const bool nodal,
+ const amrex::Real dt,
+ const bool div_cleaning,
+ const int J_in_time,
+ const int rho_in_time)
+ // Initializer list
+ : SpectralBaseAlgorithm(spectral_kspace, dm, spectral_index, norder_x, norder_y, norder_z, nodal),
+ m_spectral_index(spectral_index),
+ m_dt(dt),
+ m_div_cleaning(div_cleaning),
+ m_J_in_time(J_in_time),
+ m_rho_in_time(rho_in_time)
+{}
+
+void
+PsatdAlgorithmFirstOrder::pushSpectralFields (SpectralFieldData& f) const
+{
+ const bool div_cleaning = m_div_cleaning;
+
+ const bool J_constant = (m_J_in_time == JInTime::Constant) ? true : false;
+ const bool J_linear = (m_J_in_time == JInTime::Linear ) ? true : false;
+ const bool rho_constant = (m_rho_in_time == RhoInTime::Constant) ? true : false;
+ const bool rho_linear = (m_rho_in_time == RhoInTime::Linear ) ? true : false;
+
+ const amrex::Real dt = m_dt;
+ const amrex::Real dt2 = dt*dt;
+
+ const SpectralFieldIndex& Idx = m_spectral_index;
+
+ // Loop over boxes
+ for (amrex::MFIter mfi(f.fields); mfi.isValid(); ++mfi)
+ {
+ const amrex::Box& bx = f.fields[mfi].box();
+
+ // Extract arrays for the fields to be updated
+ amrex::Array4<Complex> fields = f.fields[mfi].array();
+
+ // Extract pointers for the k vectors
+ const amrex::Real* modified_kx_arr = modified_kx_vec[mfi].dataPtr();
+#if defined(WARPX_DIM_3D)
+ const amrex::Real* modified_ky_arr = modified_ky_vec[mfi].dataPtr();
+#endif
+ const amrex::Real* modified_kz_arr = modified_kz_vec[mfi].dataPtr();
+
+ // Loop over indices within one box
+ amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
+ {
+ // Record old values of the fields to be updated
+ const Complex Ex_old = fields(i,j,k,Idx.Ex);
+ const Complex Ey_old = fields(i,j,k,Idx.Ey);
+ const Complex Ez_old = fields(i,j,k,Idx.Ez);
+ const Complex Bx_old = fields(i,j,k,Idx.Bx);
+ const Complex By_old = fields(i,j,k,Idx.By);
+ const Complex Bz_old = fields(i,j,k,Idx.Bz);
+
+ // Shortcuts for the values of J and rho
+ const Complex Jx_mid = (J_constant) ? fields(i,j,k,Idx.Jx_mid) : 0._rt;
+ const Complex Jy_mid = (J_constant) ? fields(i,j,k,Idx.Jy_mid) : 0._rt;
+ const Complex Jz_mid = (J_constant) ? fields(i,j,k,Idx.Jz_mid) : 0._rt;
+ const Complex Jx_old = (J_linear ) ? fields(i,j,k,Idx.Jx_old) : 0._rt;
+ const Complex Jy_old = (J_linear ) ? fields(i,j,k,Idx.Jy_old) : 0._rt;
+ const Complex Jz_old = (J_linear ) ? fields(i,j,k,Idx.Jz_old) : 0._rt;
+ const Complex Jx_new = (J_linear ) ? fields(i,j,k,Idx.Jx_new) : 0._rt;
+ const Complex Jy_new = (J_linear ) ? fields(i,j,k,Idx.Jy_new) : 0._rt;
+ const Complex Jz_new = (J_linear ) ? fields(i,j,k,Idx.Jz_new) : 0._rt;
+
+ const Complex Jx_c0 = (J_constant) ? Jx_mid : Jx_old;
+ const Complex Jy_c0 = (J_constant) ? Jy_mid : Jy_old;
+ const Complex Jz_c0 = (J_constant) ? Jz_mid : Jz_old;
+ const Complex Jx_c1 = (J_linear ) ? (Jx_new-Jx_old)/dt : 0._rt;
+ const Complex Jy_c1 = (J_linear ) ? (Jy_new-Jy_old)/dt : 0._rt;
+ const Complex Jz_c1 = (J_linear ) ? (Jz_new-Jz_old)/dt : 0._rt;
+
+ Complex rho_mid, rho_old, rho_new, F_old, G_old;
+ Complex rho_c0, rho_c1;
+ if (div_cleaning)
+ {
+ rho_mid = (rho_constant) ? fields(i,j,k,Idx.rho_mid) : 0._rt;
+ rho_old = (rho_linear ) ? fields(i,j,k,Idx.rho_old) : 0._rt;
+ rho_new = (rho_linear ) ? fields(i,j,k,Idx.rho_new) : 0._rt;
+
+ F_old = fields(i,j,k,Idx.F);
+ G_old = fields(i,j,k,Idx.G);
+
+ rho_c0 = (rho_constant) ? rho_mid : rho_old;
+ rho_c1 = (rho_linear ) ? (rho_new-rho_old)/dt : 0._rt;
+ }
+
+ // k vector values
+ const amrex::Real kx = modified_kx_arr[i];
+#if defined(WARPX_DIM_3D)
+ const amrex::Real ky = modified_ky_arr[j];
+ const amrex::Real kz = modified_kz_arr[k];
+#else
+ constexpr amrex::Real ky = 0._rt;
+ const amrex::Real kz = modified_kz_arr[j];
+#endif
+ // Physical constants and imaginary unit
+ constexpr amrex::Real c = PhysConst::c;
+ constexpr amrex::Real c2 = c*c;
+ constexpr amrex::Real inv_c = 1._rt/c;
+ constexpr amrex::Real mu0 = PhysConst::mu0;
+ constexpr Complex I = Complex{0._rt, 1._rt};
+
+ const amrex::Real kx2 = kx*kx;
+ const amrex::Real ky2 = ky*ky;
+ const amrex::Real kz2 = kz*kz;
+
+ const amrex::Real knorm = std::sqrt(kx2 + ky2 + kz2);
+ const amrex::Real knorm2 = knorm*knorm;
+ const amrex::Real knorm4 = knorm2*knorm2;
+
+ // Auxiliary variables
+ const amrex::Real inv_knorm = 1._rt/knorm;
+ const amrex::Real inv_knorm2 = 1._rt/knorm2;
+ const amrex::Real inv_knorm4 = 1._rt/knorm4;
+
+ const amrex::Real C = std::cos(c*knorm*dt);
+ const amrex::Real S = std::sin(c*knorm*dt);
+
+ // Update equations
+
+ if (knorm == 0._rt)
+ {
+ fields(i,j,k,Idx.Ex) = Ex_old - mu0*c2*dt*Jx_c0 - 0.5_rt*mu0*c2*dt2*Jx_c1;
+ fields(i,j,k,Idx.Ey) = Ey_old - mu0*c2*dt*Jy_c0 - 0.5_rt*mu0*c2*dt2*Jy_c1;
+ fields(i,j,k,Idx.Ez) = Ez_old - mu0*c2*dt*Jz_c0 - 0.5_rt*mu0*c2*dt2*Jz_c1;
+
+ if (div_cleaning)
+ {
+ fields(i,j,k,Idx.F) = F_old - mu0*c2*dt*rho_c0 - 0.5_rt*mu0*c2*dt2*rho_c1;
+ }
+ }
+ else // knorm != 0
+ {
+ Complex C01, C02, C03, C04, C05, C06, C07, C08,
+ C09, C10, C11, C12, C13, C14, C15, C16;
+
+ // Ex
+ C01 = (div_cleaning) ? C : (kx2+ky2*C+kz2*C)*inv_knorm2;
+ C02 = (div_cleaning) ? 0._rt : kx*ky*(1._rt-C)*inv_knorm2;
+ C03 = (div_cleaning) ? 0._rt : kx*kz*(1._rt-C)*inv_knorm2;
+ C04 = 0._rt;
+ C05 = -I*c*kz*S*inv_knorm;
+ C06 = I*c*ky*S*inv_knorm;
+ C07 = (div_cleaning) ? I*c*kx*S*inv_knorm : 0._rt;
+ C09 = (div_cleaning) ? -mu0*c*S*inv_knorm : -mu0*c*(dt*c*kx2*knorm2+ky2*knorm*S+kz2*knorm*S)*inv_knorm4;
+ C10 = (div_cleaning) ? 0._rt : mu0*c*kx*ky*(knorm*S-dt*c*knorm2)*inv_knorm4;
+ C11 = (div_cleaning) ? 0._rt : mu0*c*kx*kz*(knorm*S-dt*c*knorm2)*inv_knorm4;
+ C12 = 0._rt; // This is not redundant, do not remove this
+ if (J_linear) C12 = (div_cleaning) ? mu0*(C-1._rt)*inv_knorm2 : mu0*(2._rt*ky2*(C-1._rt)+2._rt*kz2*(C-1._rt)-dt2*c2*kx2*knorm2)*inv_knorm4*0.5_rt;
+ C13 = (J_linear && !div_cleaning) ? mu0*kx*ky*(2._rt*(1._rt-C)-dt2*c2*knorm2)*inv_knorm4*0.5_rt : 0._rt;
+ C14 = (J_linear && !div_cleaning) ? mu0*kx*kz*(2._rt*(1._rt-C)-dt2*c2*knorm2)*inv_knorm4*0.5_rt : 0._rt;
+ C15 = (div_cleaning) ? I*mu0*c2*kx*(C-1._rt)*inv_knorm2 : 0._rt;
+ C16 = (div_cleaning && rho_linear) ? I*mu0*c*kx*(knorm*S-dt*c*knorm2)*inv_knorm4 : 0._rt;
+
+ fields(i,j,k,Idx.Ex) = C01*Ex_old + C02*Ey_old + C03*Ez_old
+ + C04*Bx_old + C05*By_old + C06*Bz_old
+ + C07*F_old // only with div cleaning
+ + C09*Jx_c0 + C10*Jy_c0 + C11*Jz_c0
+ + C12*Jx_c1 + C13*Jy_c1 + C14*Jz_c1 // only with J linear in time
+ + C15*rho_c0 // only with div cleaning
+ + C16*rho_c1; // only with div cleaning and rho linear in time
+
+ // Ey
+ C01 = (div_cleaning) ? 0._rt : kx*ky*(1._rt-C)*inv_knorm2;
+ C02 = (div_cleaning) ? C : (kx2*C+ky2+kz2*C)*inv_knorm2;
+ C03 = (div_cleaning) ? 0._rt : ky*kz*(1._rt-C)*inv_knorm2;
+ C04 = I*c*kz*S*inv_knorm;
+ C05 = 0._rt;
+ C06 = -I*c*kx*S*inv_knorm;
+ C07 = (div_cleaning) ? I*c*ky*S*inv_knorm : 0._rt;
+ C09 = (div_cleaning) ? 0._rt : mu0*c*kx*ky*(knorm*S-dt*c*knorm2)*inv_knorm4;
+ C10 = (div_cleaning) ? -mu0*c*S*inv_knorm : -mu0*c*(dt*c*ky2*knorm2+kx2*knorm*S+kz2*knorm*S)*inv_knorm4;
+ C11 = (div_cleaning) ? 0._rt : mu0*c*ky*kz*(knorm*S-dt*c*knorm2)*inv_knorm4;
+ C12 = (J_linear && !div_cleaning) ? mu0*kx*ky*(2._rt*(1._rt-C)-dt2*c2*knorm2)*inv_knorm4*0.5_rt : 0._rt;
+ C13 = 0._rt; // This is not redundant, do not remove this
+ if (J_linear) C13 = (div_cleaning) ? mu0*(C-1._rt)*inv_knorm2 : mu0*(2._rt*kx2*(C-1._rt)+2._rt*kz2*(C-1._rt)-dt2*c2*ky2*knorm2)*inv_knorm4*0.5_rt;
+ C14 = (J_linear && !div_cleaning) ? mu0*ky*kz*(2._rt*(1._rt-C)-dt2*c2*knorm2)*inv_knorm4*0.5_rt : 0._rt;
+ C15 = (div_cleaning) ? I*mu0*c2*ky*(C-1._rt)*inv_knorm2 : 0._rt;
+ C16 = (div_cleaning && rho_linear) ? I*mu0*c*ky*(knorm*S-dt*c*knorm2)*inv_knorm4 : 0._rt;
+
+ fields(i,j,k,Idx.Ey) = C01*Ex_old + C02*Ey_old + C03*Ez_old
+ + C04*Bx_old + C05*By_old + C06*Bz_old
+ + C07*F_old // only with div cleaning
+ + C09*Jx_c0 + C10*Jy_c0 + C11*Jz_c0
+ + C12*Jx_c1 + C13*Jy_c1 + C14*Jz_c1 // only with J linear in time
+ + C15*rho_c0 // only with div cleaning
+ + C16*rho_c1; // only with div cleaning and rho linear in time
+
+ // Ez
+ C01 = (div_cleaning) ? 0._rt : kx*kz*(1._rt-C)*inv_knorm2;
+ C02 = (div_cleaning) ? 0._rt : ky*kz*(1._rt-C)*inv_knorm2;
+ C03 = (div_cleaning) ? C : (kx2*C+ky2*C+kz2)*inv_knorm2;
+ C04 = -I*c*ky*S*inv_knorm;
+ C05 = I*c*kx*S*inv_knorm;
+ C06 = 0._rt;
+ C07 = (div_cleaning) ? I*c*kz*S*inv_knorm : 0._rt;
+ C09 = (div_cleaning) ? 0._rt : mu0*c*kx*kz*(knorm*S-dt*c*knorm2)*inv_knorm4;
+ C10 = (div_cleaning) ? 0._rt : mu0*c*ky*kz*(knorm*S-dt*c*knorm2)*inv_knorm4;
+ C11 = (div_cleaning) ? -mu0*c*S*inv_knorm : -mu0*c*(dt*c*kz2*knorm2+kx2*knorm*S+ky2*knorm*S)*inv_knorm4;
+ C12 = (J_linear && !div_cleaning) ? mu0*kx*kz*(2._rt*(1._rt-C)-dt2*c2*knorm2)*inv_knorm4*0.5_rt : 0._rt;
+ C13 = (J_linear && !div_cleaning) ? mu0*ky*kz*(2._rt*(1._rt-C)-dt2*c2*knorm2)*inv_knorm4*0.5_rt : 0._rt;
+ C14 = 0._rt; // This is not redundant, do not remove this
+ if (J_linear) C14 = (div_cleaning) ? mu0*(C-1._rt)*inv_knorm2 : mu0*(2._rt*kx2*(C-1._rt)+2._rt*ky2*(C-1._rt)-dt2*c2*kz2*knorm2)*inv_knorm4*0.5_rt;
+ C15 = (div_cleaning) ? I*mu0*c2*kz*(C-1._rt)*inv_knorm2 : 0._rt;
+ C16 = (div_cleaning && rho_linear) ? I*mu0*c*kz*(knorm*S-dt*c*knorm2)*inv_knorm4 : 0._rt;
+
+ fields(i,j,k,Idx.Ez) = C01*Ex_old + C02*Ey_old + C03*Ez_old
+ + C04*Bx_old + C05*By_old + C06*Bz_old
+ + C07*F_old // only with div cleaning
+ + C09*Jx_c0 + C10*Jy_c0 + C11*Jz_c0
+ + C12*Jx_c1 + C13*Jy_c1 + C14*Jz_c1 // only with J linear in time
+ + C15*rho_c0 // only with div cleaning
+ + C16*rho_c1; // only with div cleaning and rho linear in time
+
+ // Bx
+ C01 = 0._rt;
+ C02 = I*kz*S*inv_knorm*inv_c;
+ C03 = -I*ky*S*inv_knorm*inv_c;
+ C04 = (div_cleaning) ? C : (kx2+ky2*C+kz2*C)*inv_knorm2;
+ C05 = (div_cleaning) ? 0._rt : kx*ky*(1._rt-C)*inv_knorm2;
+ C06 = (div_cleaning) ? 0._rt : kx*kz*(1._rt-C)*inv_knorm2;
+ C08 = (div_cleaning) ? I*kx*S*inv_knorm*inv_c : 0._rt;
+ C09 = 0._rt;
+ C10 = I*mu0*kz*(C-1._rt)*inv_knorm2;
+ C11 = -I*mu0*ky*(C-1._rt)*inv_knorm2;
+ C12 = 0._rt;
+ C13 = (J_linear) ? I*mu0*kz*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+ C14 = (J_linear) ? -I*mu0*ky*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+
+ fields(i,j,k,Idx.Bx) = C01*Ex_old + C02*Ey_old + C03*Ez_old
+ + C04*Bx_old + C05*By_old + C06*Bz_old
+ + C08*G_old // only with div cleaning
+ + C09*Jx_c0 + C10*Jy_c0 + C11*Jz_c0
+ + C12*Jx_c1 + C13*Jy_c1 + C14*Jz_c1; // only with J linear in time
+
+ // By
+ C01 = -I*kz*S*inv_knorm*inv_c;
+ C02 = 0._rt;
+ C03 = I*kx*S*inv_knorm*inv_c;
+ C04 = (div_cleaning) ? 0._rt : kx*ky*(1._rt-C)*inv_knorm2;
+ C05 = (div_cleaning) ? C : (kx2*C+ky2+kz2*C)*inv_knorm2;
+ C06 = (div_cleaning) ? 0._rt : ky*kz*(1._rt-C)*inv_knorm2;
+ C08 = (div_cleaning) ? I*ky*S*inv_knorm*inv_c : 0._rt;
+ C09 = -I*mu0*kz*(C-1._rt)*inv_knorm2;
+ C10 = 0._rt;
+ C11 = I*mu0*kx*(C-1._rt)*inv_knorm2;
+ C12 = (J_linear) ? -I*mu0*kz*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+ C13 = 0._rt;
+ C14 = (J_linear) ? I*mu0*kx*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+
+ fields(i,j,k,Idx.By) = C01*Ex_old + C02*Ey_old + C03*Ez_old
+ + C04*Bx_old + C05*By_old + C06*Bz_old
+ + C08*G_old // only with div cleaning
+ + C09*Jx_c0 + C10*Jy_c0 + C11*Jz_c0
+ + C12*Jx_c1 + C13*Jy_c1 + C14*Jz_c1; // only with J linear in time
+
+ // Bz
+ C01 = I*ky*S*inv_knorm*inv_c;
+ C02 = -I*kx*S*inv_knorm*inv_c;
+ C03 = 0._rt;
+ C04 = (div_cleaning) ? 0._rt : kx*kz*(1._rt-C)*inv_knorm2;
+ C05 = (div_cleaning) ? 0._rt : ky*kz*(1._rt-C)*inv_knorm2;
+ C06 = (div_cleaning) ? C : (kx2*C+ky2*C+kz2)*inv_knorm2;
+ C08 = (div_cleaning) ? I*kz*S*inv_knorm*inv_c : 0._rt;
+ C09 = I*mu0*ky*(C-1._rt)*inv_knorm2;
+ C10 = -I*mu0*kx*(C-1._rt)*inv_knorm2;
+ C11 = 0._rt;
+ C12 = (J_linear) ? I*mu0*ky*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+ C13 = (J_linear) ? -I*mu0*kx*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+ C14 = 0._rt;
+
+ fields(i,j,k,Idx.Bz) = C01*Ex_old + C02*Ey_old + C03*Ez_old
+ + C04*Bx_old + C05*By_old + C06*Bz_old
+ + C08*G_old // only with div cleaning
+ + C09*Jx_c0 + C10*Jy_c0 + C11*Jz_c0
+ + C12*Jx_c1 + C13*Jy_c1 + C14*Jz_c1; // only with J linear in time
+
+ if (div_cleaning)
+ {
+ // F
+ C01 = I*kx*S*inv_knorm*inv_c;
+ C02 = I*ky*S*inv_knorm*inv_c;
+ C03 = I*kz*S*inv_knorm*inv_c;
+ C07 = C;
+ C09 = I*mu0*kx*(C-1._rt)*inv_knorm2;
+ C10 = I*mu0*ky*(C-1._rt)*inv_knorm2;
+ C11 = I*mu0*kz*(C-1._rt)*inv_knorm2;
+ C12 = (J_linear) ? I*mu0*kx*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+ C13 = (J_linear) ? I*mu0*ky*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+ C14 = (J_linear) ? I*mu0*kz*(knorm*S-dt*c*knorm2)*inv_knorm4*inv_c : 0._rt;
+ C15 = -mu0*c*S*inv_knorm;
+ C16 = (rho_linear) ? mu0*(C-1._rt)*inv_knorm2 : 0._rt;
+
+ fields(i,j,k,Idx.F) = C01*Ex_old + C02*Ey_old + C03*Ez_old
+ + C07*F_old
+ + C09*Jx_c0 + C10*Jy_c0 + C11*Jz_c0
+ + C12*Jx_c1 + C13*Jy_c1 + C14*Jz_c1 // only with J linear in time
+ + C15*rho_c0
+ + C16*rho_c1; // only with rho linear in time
+
+ // G
+ C04 = I*c*kx*S*inv_knorm;
+ C05 = I*c*ky*S*inv_knorm;
+ C06 = I*c*kz*S*inv_knorm;
+ C08 = C;
+
+ fields(i,j,k,Idx.G) = C04*Bx_old + C05*By_old + C06*Bz_old
+ + C08*G_old;
+ }
+ }
+ });
+ }
+}
+
+void PsatdAlgorithmFirstOrder::CurrentCorrection (SpectralFieldData& field_data)
+{
+ // Profiling
+ BL_PROFILE("PsatdAlgorithmFirstOrder::CurrentCorrection");
+
+ amrex::ignore_unused(field_data);
+ amrex::Abort(Utils::TextMsg::Err(
+ "Current correction not implemented for first-order PSATD equations"));
+}
+
+void
+PsatdAlgorithmFirstOrder::VayDeposition (SpectralFieldData& field_data)
+{
+ // Profiling
+ BL_PROFILE("PsatdAlgorithmFirstOrder::VayDeposition()");
+
+ amrex::ignore_unused(field_data);
+ amrex::Abort(Utils::TextMsg::Err(
+ "Vay deposition not implemented for first-order PSATD equations"));
+}
+
+#endif // WARPX_USE_PSATD
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmGalileanRZ.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmGalileanRZ.cpp
index be850e252..af3e2e336 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmGalileanRZ.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmGalileanRZ.cpp
@@ -103,9 +103,9 @@ PsatdAlgorithmGalileanRZ::pushSpectralFields (SpectralFieldDataRZ & f)
auto const Bp_m = Idx.Bx + Idx.n_fields*mode;
auto const Bm_m = Idx.By + Idx.n_fields*mode;
auto const Bz_m = Idx.Bz + Idx.n_fields*mode;
- auto const Jp_m = Idx.Jx + Idx.n_fields*mode;
- auto const Jm_m = Idx.Jy + Idx.n_fields*mode;
- auto const Jz_m = Idx.Jz + Idx.n_fields*mode;
+ auto const Jp_m = Idx.Jx_mid + Idx.n_fields*mode;
+ auto const Jm_m = Idx.Jy_mid + Idx.n_fields*mode;
+ auto const Jz_m = Idx.Jz_mid + Idx.n_fields*mode;
auto const rho_old_m = Idx.rho_old + Idx.n_fields*mode;
auto const rho_new_m = Idx.rho_new + Idx.n_fields*mode;
@@ -323,9 +323,9 @@ PsatdAlgorithmGalileanRZ::CurrentCorrection (SpectralFieldDataRZ& field_data)
[=] AMREX_GPU_DEVICE(int i, int j, int k, int mode) noexcept
{
// All of the fields of each mode are grouped together
- auto const Jp_m = Idx.Jx + Idx.n_fields*mode;
- auto const Jm_m = Idx.Jy + Idx.n_fields*mode;
- auto const Jz_m = Idx.Jz + Idx.n_fields*mode;
+ auto const Jp_m = Idx.Jx_mid + Idx.n_fields*mode;
+ auto const Jm_m = Idx.Jy_mid + Idx.n_fields*mode;
+ auto const Jz_m = Idx.Jz_mid + Idx.n_fields*mode;
auto const rho_old_m = Idx.rho_old + Idx.n_fields*mode;
auto const rho_new_m = Idx.rho_new + Idx.n_fields*mode;
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJConstantInTime.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJConstantInTime.cpp
index 9d1fbf3e1..c52437bf8 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJConstantInTime.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJConstantInTime.cpp
@@ -190,9 +190,9 @@ PsatdAlgorithmJConstantInTime::pushSpectralFields (SpectralFieldData& f) const
const Complex Bz_old = fields(i,j,k,Idx.Bz);
// Shortcuts for the values of J
- const Complex Jx = fields(i,j,k,Idx.Jx);
- const Complex Jy = fields(i,j,k,Idx.Jy);
- const Complex Jz = fields(i,j,k,Idx.Jz);
+ const Complex Jx = fields(i,j,k,Idx.Jx_mid);
+ const Complex Jy = fields(i,j,k,Idx.Jy_mid);
+ const Complex Jz = fields(i,j,k,Idx.Jz_mid);
Complex F_old;
if (dive_cleaning)
@@ -751,9 +751,9 @@ void PsatdAlgorithmJConstantInTime::CurrentCorrection (SpectralFieldData& field_
ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
{
// Shortcuts for the values of J and rho
- const Complex Jx = fields(i,j,k,Idx.Jx);
- const Complex Jy = fields(i,j,k,Idx.Jy);
- const Complex Jz = fields(i,j,k,Idx.Jz);
+ const Complex Jx = fields(i,j,k,Idx.Jx_mid);
+ const Complex Jy = fields(i,j,k,Idx.Jy_mid);
+ const Complex Jz = fields(i,j,k,Idx.Jz_mid);
const Complex rho_old = fields(i,j,k,Idx.rho_old);
const Complex rho_new = fields(i,j,k,Idx.rho_new);
@@ -787,25 +787,25 @@ void PsatdAlgorithmJConstantInTime::CurrentCorrection (SpectralFieldData& field_
const Complex rho_old_mod = rho_old * amrex::exp(I * k_dot_vg * dt);
const Complex den = 1._rt - amrex::exp(I * k_dot_vg * dt);
- fields(i,j,k,Idx.Jx) = Jx - (k_dot_J - k_dot_vg * (rho_new - rho_old_mod) / den)
+ fields(i,j,k,Idx.Jx_mid) = Jx - (k_dot_J - k_dot_vg * (rho_new - rho_old_mod) / den)
* kx / (k_norm * k_norm);
- fields(i,j,k,Idx.Jy) = Jy - (k_dot_J - k_dot_vg * (rho_new - rho_old_mod) / den)
+ fields(i,j,k,Idx.Jy_mid) = Jy - (k_dot_J - k_dot_vg * (rho_new - rho_old_mod) / den)
* ky / (k_norm * k_norm);
- fields(i,j,k,Idx.Jz) = Jz - (k_dot_J - k_dot_vg * (rho_new - rho_old_mod) / den)
+ fields(i,j,k,Idx.Jz_mid) = Jz - (k_dot_J - k_dot_vg * (rho_new - rho_old_mod) / den)
* kz / (k_norm * k_norm);
}
else
{
- fields(i,j,k,Idx.Jx) = Jx - (k_dot_J - I * (rho_new - rho_old) / dt)
+ fields(i,j,k,Idx.Jx_mid) = Jx - (k_dot_J - I * (rho_new - rho_old) / dt)
* kx / (k_norm * k_norm);
- fields(i,j,k,Idx.Jy) = Jy - (k_dot_J - I * (rho_new - rho_old) / dt)
+ fields(i,j,k,Idx.Jy_mid) = Jy - (k_dot_J - I * (rho_new - rho_old) / dt)
* ky / (k_norm * k_norm);
- fields(i,j,k,Idx.Jz) = Jz - (k_dot_J - I * (rho_new - rho_old) / dt)
+ fields(i,j,k,Idx.Jz_mid) = Jz - (k_dot_J - I * (rho_new - rho_old) / dt)
* kz / (k_norm * k_norm);
}
}
@@ -840,11 +840,11 @@ PsatdAlgorithmJConstantInTime::VayDeposition (SpectralFieldData& field_data)
ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
{
// Shortcuts for the values of D
- const Complex Dx = fields(i,j,k,Idx.Jx);
+ const Complex Dx = fields(i,j,k,Idx.Jx_mid);
#if defined(WARPX_DIM_3D)
- const Complex Dy = fields(i,j,k,Idx.Jy);
+ const Complex Dy = fields(i,j,k,Idx.Jy_mid);
#endif
- const Complex Dz = fields(i,j,k,Idx.Jz);
+ const Complex Dz = fields(i,j,k,Idx.Jz_mid);
// Imaginary unit
constexpr Complex I = Complex{0._rt, 1._rt};
@@ -859,18 +859,18 @@ PsatdAlgorithmJConstantInTime::VayDeposition (SpectralFieldData& field_data)
#endif
// Compute Jx
- if (kx_mod != 0._rt) fields(i,j,k,Idx.Jx) = I * Dx / kx_mod;
- else fields(i,j,k,Idx.Jx) = 0._rt;
+ if (kx_mod != 0._rt) fields(i,j,k,Idx.Jx_mid) = I * Dx / kx_mod;
+ else fields(i,j,k,Idx.Jx_mid) = 0._rt;
#if defined(WARPX_DIM_3D)
// Compute Jy
- if (ky_mod != 0._rt) fields(i,j,k,Idx.Jy) = I * Dy / ky_mod;
- else fields(i,j,k,Idx.Jy) = 0._rt;
+ if (ky_mod != 0._rt) fields(i,j,k,Idx.Jy_mid) = I * Dy / ky_mod;
+ else fields(i,j,k,Idx.Jy_mid) = 0._rt;
#endif
// Compute Jz
- if (kz_mod != 0._rt) fields(i,j,k,Idx.Jz) = I * Dz / kz_mod;
- else fields(i,j,k,Idx.Jz) = 0._rt;
+ if (kz_mod != 0._rt) fields(i,j,k,Idx.Jz_mid) = I * Dz / kz_mod;
+ else fields(i,j,k,Idx.Jz_mid) = 0._rt;
});
}
}
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJLinearInTime.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJLinearInTime.cpp
index bd9df977e..861001c78 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJLinearInTime.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmJLinearInTime.cpp
@@ -120,9 +120,9 @@ PsatdAlgorithmJLinearInTime::pushSpectralFields (SpectralFieldData& f) const
const Complex Bz_old = fields(i,j,k,Idx.Bz);
// Shortcuts for the values of J and rho
- const Complex Jx_old = fields(i,j,k,Idx.Jx);
- const Complex Jy_old = fields(i,j,k,Idx.Jy);
- const Complex Jz_old = fields(i,j,k,Idx.Jz);
+ const Complex Jx_old = fields(i,j,k,Idx.Jx_old);
+ const Complex Jy_old = fields(i,j,k,Idx.Jy_old);
+ const Complex Jz_old = fields(i,j,k,Idx.Jz_old);
const Complex Jx_new = fields(i,j,k,Idx.Jx_new);
const Complex Jy_new = fields(i,j,k,Idx.Jy_new);
const Complex Jz_new = fields(i,j,k,Idx.Jz_new);
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmRZ.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmRZ.cpp
index 55b58821c..effb1cc2b 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmRZ.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/PsatdAlgorithmRZ.cpp
@@ -83,7 +83,7 @@ PsatdAlgorithmRZ::pushSpectralFields(SpectralFieldDataRZ & f)
const bool update_with_rho = m_update_with_rho;
const bool time_averaging = m_time_averaging;
- const bool J_in_time_linear = (m_J_in_time == JInTime::Linear) ? true : false;
+ const bool J_linear = (m_J_in_time == JInTime::Linear) ? true : false;
const bool dive_cleaning = m_dive_cleaning;
const bool divb_cleaning = m_divb_cleaning;
@@ -112,7 +112,7 @@ PsatdAlgorithmRZ::pushSpectralFields(SpectralFieldDataRZ & f)
amrex::Array4<const amrex::Real> X5_arr;
amrex::Array4<const amrex::Real> X6_arr;
- if (time_averaging && J_in_time_linear)
+ if (time_averaging && J_linear)
{
X5_arr = X5_coef[mfi].array();
X6_arr = X6_coef[mfi].array();
@@ -131,6 +131,9 @@ PsatdAlgorithmRZ::pushSpectralFields(SpectralFieldDataRZ & f)
amrex::ParallelFor(bx, modes,
[=] AMREX_GPU_DEVICE(int i, int j, int k, int mode) noexcept
{
+ int idx_jx = (J_linear) ? static_cast<int>(Idx.Jx_old) : static_cast<int>(Idx.Jx_mid);
+ int idx_jy = (J_linear) ? static_cast<int>(Idx.Jy_old) : static_cast<int>(Idx.Jy_mid);
+ int idx_jz = (J_linear) ? static_cast<int>(Idx.Jz_old) : static_cast<int>(Idx.Jz_mid);
// All of the fields of each mode are grouped together
int const Ep_m = Idx.Ex + Idx.n_fields*mode;
@@ -139,9 +142,9 @@ PsatdAlgorithmRZ::pushSpectralFields(SpectralFieldDataRZ & f)
int const Bp_m = Idx.Bx + Idx.n_fields*mode;
int const Bm_m = Idx.By + Idx.n_fields*mode;
int const Bz_m = Idx.Bz + Idx.n_fields*mode;
- int const Jp_m = Idx.Jx + Idx.n_fields*mode;
- int const Jm_m = Idx.Jy + Idx.n_fields*mode;
- int const Jz_m = Idx.Jz + Idx.n_fields*mode;
+ int const Jp_m = idx_jx + Idx.n_fields*mode;
+ int const Jm_m = idx_jy + Idx.n_fields*mode;
+ int const Jz_m = idx_jz + Idx.n_fields*mode;
int const rho_old_m = Idx.rho_old + Idx.n_fields*mode;
int const rho_new_m = Idx.rho_new + Idx.n_fields*mode;
@@ -238,7 +241,7 @@ PsatdAlgorithmRZ::pushSpectralFields(SpectralFieldDataRZ & f)
G_old = fields(i,j,k,G_m);
}
- if (J_in_time_linear)
+ if (J_linear)
{
const int Jp_m_new = Idx.Jx_new + Idx.n_fields*mode;
const int Jm_m_new = Idx.Jy_new + Idx.n_fields*mode;
@@ -335,7 +338,7 @@ PsatdAlgorithmRZ::pushSpectralFields(SpectralFieldDataRZ & f)
void PsatdAlgorithmRZ::InitializeSpectralCoefficients (SpectralFieldDataRZ const & f)
{
const bool time_averaging = m_time_averaging;
- const bool J_in_time_linear = (m_J_in_time == JInTime::Linear) ? true : false;
+ const bool J_linear = (m_J_in_time == JInTime::Linear) ? true : false;
// Fill them with the right values:
// Loop over boxes and allocate the corresponding coefficients
@@ -356,7 +359,7 @@ void PsatdAlgorithmRZ::InitializeSpectralCoefficients (SpectralFieldDataRZ const
amrex::Array4<amrex::Real> X5;
amrex::Array4<amrex::Real> X6;
- if (time_averaging && J_in_time_linear)
+ if (time_averaging && J_linear)
{
X5 = X5_coef[mfi].array();
X6 = X6_coef[mfi].array();
@@ -395,7 +398,7 @@ void PsatdAlgorithmRZ::InitializeSpectralCoefficients (SpectralFieldDataRZ const
X3(i,j,k,mode) = - c*c * dt*dt / (3._rt*ep0);
}
- if (time_averaging && J_in_time_linear)
+ if (time_averaging && J_linear)
{
constexpr amrex::Real c2 = PhysConst::c;
const amrex::Real dt3 = dt * dt * dt;
@@ -450,9 +453,9 @@ PsatdAlgorithmRZ::CurrentCorrection (SpectralFieldDataRZ& field_data)
[=] AMREX_GPU_DEVICE(int i, int j, int k, int mode) noexcept
{
// All of the fields of each mode are grouped together
- auto const Jp_m = Idx.Jx + Idx.n_fields*mode;
- auto const Jm_m = Idx.Jy + Idx.n_fields*mode;
- auto const Jz_m = Idx.Jz + Idx.n_fields*mode;
+ auto const Jp_m = Idx.Jx_mid + Idx.n_fields*mode;
+ auto const Jm_m = Idx.Jy_mid + Idx.n_fields*mode;
+ auto const Jz_m = Idx.Jz_mid + Idx.n_fields*mode;
auto const rho_old_m = Idx.rho_old + Idx.n_fields*mode;
auto const rho_new_m = Idx.rho_new + Idx.n_fields*mode;
diff --git a/Source/FieldSolver/SpectralSolver/SpectralFieldData.H b/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
index 4ab88f1a3..c7848d731 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralFieldData.H
@@ -83,18 +83,19 @@ class SpectralFieldIndex
// Always
int Ex = -1, Ey = -1, Ez = -1;
int Bx = -1, By = -1, Bz = -1;
- int Jx = -1, Jy = -1, Jz = -1;
- int rho_old = -1, rho_new = -1, divE = -1;
+ int divE = -1;
// Time averaging
int Ex_avg = -1, Ey_avg = -1, Ez_avg = -1;
int Bx_avg = -1, By_avg = -1, Bz_avg = -1;
- // J linear in time
+ // J
+ int Jx_old = -1, Jy_old = -1, Jz_old = -1;
+ int Jx_mid = -1, Jy_mid = -1, Jz_mid = -1;
int Jx_new = -1, Jy_new = -1, Jz_new = -1;
- // rho quadratic in time
- int rho_mid = -1;
+ // rho
+ int rho_old = -1, rho_mid = -1, rho_new = -1;
// div(E) and div(B) cleaning
int F = -1, G = -1;
diff --git a/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp b/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
index 56189e0ff..e1db4e5ab 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralFieldData.cpp
@@ -51,10 +51,8 @@ SpectralFieldIndex::SpectralFieldIndex (const bool update_with_rho,
{
Ex = c++; Ey = c++; Ez = c++;
Bx = c++; By = c++; Bz = c++;
- Jx = c++; Jy = c++; Jz = c++;
// TODO Allocate rho_old and rho_new only when needed
- rho_old = c++; rho_new = c++;
// Reuse data corresponding to index Bx = 3 to avoid storing extra memory
divE = 3;
@@ -69,17 +67,25 @@ SpectralFieldIndex::SpectralFieldIndex (const bool update_with_rho,
if (divb_cleaning) G = c++;
- if (J_in_time == JInTime::Linear)
+ if (J_in_time == JInTime::Constant)
{
- Jx_new = c++;
- Jy_new = c++;
- Jz_new = c++;
+ Jx_mid = c++; Jy_mid = c++; Jz_mid = c++;
+ }
+ else if (J_in_time == JInTime::Linear)
+ {
+ Jx_old = c++; Jy_old = c++; Jz_old = c++;
+ Jx_new = c++; Jy_new = c++; Jz_new = c++;
}
- if (rho_in_time == RhoInTime::Quadratic)
+ if (rho_in_time == RhoInTime::Constant)
{
rho_mid = c++;
}
+ else if (rho_in_time == RhoInTime::Linear)
+ {
+ rho_old = c++;
+ rho_new = c++;
+ }
if (pml_rz)
{
diff --git a/Source/FieldSolver/SpectralSolver/SpectralSolver.H b/Source/FieldSolver/SpectralSolver/SpectralSolver.H
index 38b242010..da4b9687b 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralSolver.H
+++ b/Source/FieldSolver/SpectralSolver/SpectralSolver.H
@@ -58,6 +58,8 @@ class SpectralSolver
* (no domain decomposition)
* \param[in] update_with_rho whether rho is used in the field update equations
* \param[in] fft_do_time_averaging whether the time averaging algorithm is used
+ * \param[in] psatd_solution_type whether the PSATD equations are derived
+ * from a first-order or second-order model
* \param[in] J_in_time integer that corresponds to the time dependency of J
* (constant, linear) for the PSATD algorithm
* \param[in] rho_in_time integer that corresponds to the time dependency of rho
@@ -80,6 +82,7 @@ class SpectralSolver
const bool periodic_single_box,
const bool update_with_rho,
const bool fft_do_time_averaging,
+ const int psatd_solution_type,
const int J_in_time,
const int rho_in_time,
const bool dive_cleaning,
diff --git a/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp b/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
index c0d7b8941..f29a0bd03 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralSolver.cpp
@@ -8,10 +8,12 @@
#include "FieldSolver/SpectralSolver/SpectralFieldData.H"
#include "SpectralAlgorithms/PsatdAlgorithmComoving.H"
#include "SpectralAlgorithms/PsatdAlgorithmPml.H"
+#include "SpectralAlgorithms/PsatdAlgorithmFirstOrder.H"
#include "SpectralAlgorithms/PsatdAlgorithmJConstantInTime.H"
#include "SpectralAlgorithms/PsatdAlgorithmJLinearInTime.H"
#include "SpectralKSpace.H"
#include "SpectralSolver.H"
+#include "Utils/TextMsg.H"
#include "Utils/WarpXProfilerWrapper.H"
#include <memory>
@@ -30,6 +32,7 @@ SpectralSolver::SpectralSolver(
const bool pml, const bool periodic_single_box,
const bool update_with_rho,
const bool fft_do_time_averaging,
+ const int psatd_solution_type,
const int J_in_time,
const int rho_in_time,
const bool dive_cleaning,
@@ -49,13 +52,13 @@ SpectralSolver::SpectralSolver(
// - Select the algorithm depending on the input parameters
// Initialize the corresponding coefficients over k space
- if (pml) // PSATD equations in the PML grids
+ if (pml) // PSATD equations in the PML region
{
algorithm = std::make_unique<PsatdAlgorithmPml>(
k_space, dm, m_spectral_index, norder_x, norder_y, norder_z, nodal,
dt, dive_cleaning, divb_cleaning);
}
- else // PSATD equations in the regulard grids
+ else // PSATD equations in the regular domain
{
// Comoving PSATD algorithm
if (v_comoving[0] != 0. || v_comoving[1] != 0. || v_comoving[2] != 0.)
@@ -64,7 +67,31 @@ SpectralSolver::SpectralSolver(
k_space, dm, m_spectral_index, norder_x, norder_y, norder_z, nodal,
v_comoving, dt, update_with_rho);
}
- else // PSATD algorithms: standard, Galilean, averaged Galilean, multi-J
+ // Galilean PSATD algorithm (only J constant in time)
+ else if (v_galilean[0] != 0. || v_galilean[1] != 0. || v_galilean[2] != 0.)
+ {
+ algorithm = std::make_unique<PsatdAlgorithmJConstantInTime>(
+ k_space, dm, m_spectral_index, norder_x, norder_y, norder_z, nodal,
+ v_galilean, dt, update_with_rho, fft_do_time_averaging,
+ dive_cleaning, divb_cleaning);
+ }
+ else if (psatd_solution_type == PSATDSolutionType::FirstOrder)
+ {
+ WARPX_ALWAYS_ASSERT_WITH_MESSAGE(
+ !fft_do_time_averaging,
+ "psatd.do_time_averaging=1 not supported when psatd.solution_type=first-order");
+
+ WARPX_ALWAYS_ASSERT_WITH_MESSAGE(
+ (!dive_cleaning && !divb_cleaning) || (dive_cleaning && divb_cleaning),
+ "warpx.do_dive_cleaning and warpx.do_divb_cleaning must be equal when psatd.solution_type=first-order");
+
+ const bool div_cleaning = (dive_cleaning && divb_cleaning);
+
+ algorithm = std::make_unique<PsatdAlgorithmFirstOrder>(
+ k_space, dm, m_spectral_index, norder_x, norder_y, norder_z, nodal,
+ dt, div_cleaning, J_in_time, rho_in_time);
+ }
+ else if (psatd_solution_type == PSATDSolutionType::SecondOrder)
{
if (J_in_time == JInTime::Constant)
{
@@ -73,7 +100,7 @@ SpectralSolver::SpectralSolver(
v_galilean, dt, update_with_rho, fft_do_time_averaging,
dive_cleaning, divb_cleaning);
}
- else // J linear in time
+ else if (J_in_time == JInTime::Linear)
{
algorithm = std::make_unique<PsatdAlgorithmJLinearInTime>(
k_space, dm, m_spectral_index, norder_x, norder_y, norder_z, nodal,
diff --git a/Source/FieldSolver/WarpXPushFieldsEM.cpp b/Source/FieldSolver/WarpXPushFieldsEM.cpp
index 3d68e8e52..9df4bb21b 100644
--- a/Source/FieldSolver/WarpXPushFieldsEM.cpp
+++ b/Source/FieldSolver/WarpXPushFieldsEM.cpp
@@ -280,9 +280,9 @@ void WarpX::PSATDForwardTransformJ (
{
Idx = spectral_solver_fp[lev]->m_spectral_index;
- idx_jx = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jx_new) : static_cast<int>(Idx.Jx);
- idx_jy = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jy_new) : static_cast<int>(Idx.Jy);
- idx_jz = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jz_new) : static_cast<int>(Idx.Jz);
+ idx_jx = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jx_new) : static_cast<int>(Idx.Jx_mid);
+ idx_jy = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jy_new) : static_cast<int>(Idx.Jy_mid);
+ idx_jz = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jz_new) : static_cast<int>(Idx.Jz_mid);
ForwardTransformVect(lev, *spectral_solver_fp[lev], J_fp[lev], idx_jx, idx_jy, idx_jz);
@@ -290,9 +290,9 @@ void WarpX::PSATDForwardTransformJ (
{
Idx = spectral_solver_cp[lev]->m_spectral_index;
- idx_jx = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jx_new) : static_cast<int>(Idx.Jx);
- idx_jy = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jy_new) : static_cast<int>(Idx.Jy);
- idx_jz = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jz_new) : static_cast<int>(Idx.Jz);
+ idx_jx = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jx_new) : static_cast<int>(Idx.Jx_mid);
+ idx_jy = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jy_new) : static_cast<int>(Idx.Jy_mid);
+ idx_jz = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jz_new) : static_cast<int>(Idx.Jz_mid);
ForwardTransformVect(lev, *spectral_solver_cp[lev], J_cp[lev], idx_jx, idx_jy, idx_jz);
}
@@ -304,11 +304,23 @@ void WarpX::PSATDForwardTransformJ (
{
for (int lev = 0; lev <= finest_level; ++lev)
{
- spectral_solver_fp[lev]->ApplyFilter(lev, Idx.Jx, Idx.Jy, Idx.Jz);
+ Idx = spectral_solver_fp[lev]->m_spectral_index;
+
+ idx_jx = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jx_new) : static_cast<int>(Idx.Jx_mid);
+ idx_jy = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jy_new) : static_cast<int>(Idx.Jy_mid);
+ idx_jz = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jz_new) : static_cast<int>(Idx.Jz_mid);
+
+ spectral_solver_fp[lev]->ApplyFilter(lev, idx_jx, idx_jy, idx_jz);
if (spectral_solver_cp[lev])
{
- spectral_solver_cp[lev]->ApplyFilter(lev, Idx.Jx, Idx.Jy, Idx.Jz);
+ Idx = spectral_solver_cp[lev]->m_spectral_index;
+
+ idx_jx = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jx_new) : static_cast<int>(Idx.Jx_mid);
+ idx_jy = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jy_new) : static_cast<int>(Idx.Jy_mid);
+ idx_jz = (J_in_time == JInTime::Linear) ? static_cast<int>(Idx.Jz_new) : static_cast<int>(Idx.Jz_mid);
+
+ spectral_solver_cp[lev]->ApplyFilter(lev, idx_jx, idx_jy, idx_jz);
}
}
}
@@ -328,9 +340,11 @@ void WarpX::PSATDBackwardTransformJ (
{
Idx = spectral_solver_fp[lev]->m_spectral_index;
- idx_jx = static_cast<int>(Idx.Jx);
- idx_jy = static_cast<int>(Idx.Jy);
- idx_jz = static_cast<int>(Idx.Jz);
+ // Note that these backward FFTs are currently called only
+ // with algorithms that do not support J linear in time
+ idx_jx = static_cast<int>(Idx.Jx_mid);
+ idx_jy = static_cast<int>(Idx.Jy_mid);
+ idx_jz = static_cast<int>(Idx.Jz_mid);
BackwardTransformVect(lev, *spectral_solver_fp[lev], J_fp[lev],
idx_jx, idx_jy, idx_jz, m_fill_guards_current);
@@ -339,9 +353,11 @@ void WarpX::PSATDBackwardTransformJ (
{
Idx = spectral_solver_cp[lev]->m_spectral_index;
- idx_jx = static_cast<int>(Idx.Jx);
- idx_jy = static_cast<int>(Idx.Jy);
- idx_jz = static_cast<int>(Idx.Jz);
+ // Note that these backward FFTs are currently called only
+ // with algorithms that do not support J linear in time
+ idx_jx = static_cast<int>(Idx.Jx_mid);
+ idx_jy = static_cast<int>(Idx.Jy_mid);
+ idx_jz = static_cast<int>(Idx.Jz_mid);
BackwardTransformVect(lev, *spectral_solver_cp[lev], J_cp[lev],
idx_jx, idx_jy, idx_jz, m_fill_guards_current);
@@ -359,7 +375,15 @@ void WarpX::PSATDForwardTransformRho (
const SpectralFieldIndex& Idx = spectral_solver_fp[0]->m_spectral_index;
// Select index in k space
- const int dst_comp = (dcomp == 0) ? Idx.rho_old : Idx.rho_new;
+ int dst_comp;
+ if (rho_in_time == RhoInTime::Constant)
+ {
+ dst_comp = Idx.rho_mid;
+ }
+ else // rho_in_time == RhoInTime::Linear
+ {
+ dst_comp = (dcomp == 0) ? Idx.rho_old : Idx.rho_new;
+ }
for (int lev = 0; lev <= finest_level; ++lev)
{
@@ -568,15 +592,15 @@ WarpX::PSATDMoveJNewToJOld ()
for (int lev = 0; lev <= finest_level; ++lev)
{
- spectral_solver_fp[lev]->CopySpectralDataComp(Idx.Jx_new, Idx.Jx);
- spectral_solver_fp[lev]->CopySpectralDataComp(Idx.Jy_new, Idx.Jy);
- spectral_solver_fp[lev]->CopySpectralDataComp(Idx.Jz_new, Idx.Jz);
+ spectral_solver_fp[lev]->CopySpectralDataComp(Idx.Jx_new, Idx.Jx_old);
+ spectral_solver_fp[lev]->CopySpectralDataComp(Idx.Jy_new, Idx.Jy_old);
+ spectral_solver_fp[lev]->CopySpectralDataComp(Idx.Jz_new, Idx.Jz_old);
if (spectral_solver_cp[lev])
{
- spectral_solver_cp[lev]->CopySpectralDataComp(Idx.Jx_new, Idx.Jx);
- spectral_solver_cp[lev]->CopySpectralDataComp(Idx.Jy_new, Idx.Jy);
- spectral_solver_cp[lev]->CopySpectralDataComp(Idx.Jz_new, Idx.Jz);
+ spectral_solver_cp[lev]->CopySpectralDataComp(Idx.Jx_new, Idx.Jx_old);
+ spectral_solver_cp[lev]->CopySpectralDataComp(Idx.Jy_new, Idx.Jy_old);
+ spectral_solver_cp[lev]->CopySpectralDataComp(Idx.Jz_new, Idx.Jz_old);
}
}
}
diff --git a/Source/Initialization/WarpXInitData.cpp b/Source/Initialization/WarpXInitData.cpp
index 0d3e919a0..32cd11dfd 100644
--- a/Source/Initialization/WarpXInitData.cpp
+++ b/Source/Initialization/WarpXInitData.cpp
@@ -480,7 +480,7 @@ WarpX::InitPML ()
pml_ncell, pml_delta, amrex::IntVect::TheZeroVector(),
dt[0], nox_fft, noy_fft, noz_fft, do_nodal,
do_moving_window, pml_has_particles, do_pml_in_domain,
- J_in_time, rho_in_time,
+ psatd_solution_type, J_in_time, rho_in_time,
do_pml_dive_cleaning, do_pml_divb_cleaning,
amrex::IntVect(0), amrex::IntVect(0),
guard_cells.ng_FieldSolver.max(),
@@ -517,7 +517,7 @@ WarpX::InitPML ()
pml_ncell, pml_delta, refRatio(lev-1),
dt[lev], nox_fft, noy_fft, noz_fft, do_nodal,
do_moving_window, pml_has_particles, do_pml_in_domain,
- J_in_time, rho_in_time, do_pml_dive_cleaning, do_pml_divb_cleaning,
+ psatd_solution_type, J_in_time, rho_in_time, do_pml_dive_cleaning, do_pml_divb_cleaning,
amrex::IntVect(0), amrex::IntVect(0),
guard_cells.ng_FieldSolver.max(),
v_particle_pml,
diff --git a/Source/Utils/WarpXAlgorithmSelection.H b/Source/Utils/WarpXAlgorithmSelection.H
index c3160cfad..936fd3d2b 100644
--- a/Source/Utils/WarpXAlgorithmSelection.H
+++ b/Source/Utils/WarpXAlgorithmSelection.H
@@ -84,6 +84,13 @@ struct GatheringAlgo {
};
};
+struct PSATDSolutionType {
+ enum {
+ FirstOrder = 0,
+ SecondOrder = 1
+ };
+};
+
struct JInTime {
enum {
Constant = 0,
@@ -93,8 +100,8 @@ struct JInTime {
struct RhoInTime {
enum {
- Linear = 1,
- Quadratic = 2
+ Constant = 0,
+ Linear = 1
};
};
diff --git a/Source/Utils/WarpXAlgorithmSelection.cpp b/Source/Utils/WarpXAlgorithmSelection.cpp
index b99459b46..c5ef16743 100644
--- a/Source/Utils/WarpXAlgorithmSelection.cpp
+++ b/Source/Utils/WarpXAlgorithmSelection.cpp
@@ -63,6 +63,12 @@ const std::map<std::string, int> gathering_algo_to_int = {
{"default", GatheringAlgo::EnergyConserving }
};
+const std::map<std::string, int> psatd_solution_type_to_int = {
+ {"first-order", PSATDSolutionType::FirstOrder},
+ {"second-order", PSATDSolutionType::SecondOrder},
+ {"default", PSATDSolutionType::SecondOrder}
+};
+
const std::map<std::string, int> J_in_time_to_int = {
{"constant", JInTime::Constant},
{"linear", JInTime::Linear},
@@ -70,8 +76,8 @@ const std::map<std::string, int> J_in_time_to_int = {
};
const std::map<std::string, int> rho_in_time_to_int = {
+ {"constant", RhoInTime::Constant},
{"linear", RhoInTime::Linear},
- {"quadratic", RhoInTime::Quadratic},
{"default", RhoInTime::Linear}
};
@@ -145,6 +151,8 @@ GetAlgorithmInteger( amrex::ParmParse& pp, const char* pp_search_key ){
algo_to_int = charge_deposition_algo_to_int;
} else if (0 == std::strcmp(pp_search_key, "field_gathering")) {
algo_to_int = gathering_algo_to_int;
+ } else if (0 == std::strcmp(pp_search_key, "solution_type")) {
+ algo_to_int = psatd_solution_type_to_int;
} else if (0 == std::strcmp(pp_search_key, "J_in_time")) {
algo_to_int = J_in_time_to_int;
} else if (0 == std::strcmp(pp_search_key, "rho_in_time")) {
diff --git a/Source/WarpX.H b/Source/WarpX.H
index 20d4e4210..2d1124c06 100644
--- a/Source/WarpX.H
+++ b/Source/WarpX.H
@@ -187,6 +187,11 @@ public:
*/
static amrex::Vector<ParticleBoundaryType> particle_boundary_hi;
+ //! Integer that corresponds to the order of the PSATD solution
+ //! (whether the PSATD equations are derived from first-order or
+ //! second-order solution)
+ static short psatd_solution_type;
+
//! Integers that correspond to the time dependency of J (constant, linear)
//! and rho (linear, quadratic) for the PSATD algorithm
static short J_in_time;
@@ -1639,7 +1644,7 @@ private:
const int icomp, const int dcomp, const bool apply_kspace_filter=true);
/**
- * \brief Copy rho_new to rho_old in spectral space
+ * \brief Copy rho_new to rho_old in spectral space (when rho is linear in time)
*/
void PSATDMoveRhoNewToRhoOld ();
diff --git a/Source/WarpX.cpp b/Source/WarpX.cpp
index 579387433..e51197089 100644
--- a/Source/WarpX.cpp
+++ b/Source/WarpX.cpp
@@ -120,6 +120,7 @@ short WarpX::charge_deposition_algo;
short WarpX::field_gathering_algo;
short WarpX::particle_pusher_algo;
short WarpX::electromagnetic_solver_id;
+short WarpX::psatd_solution_type;
short WarpX::J_in_time;
short WarpX::rho_in_time;
short WarpX::load_balance_costs_update_algo;
@@ -1148,6 +1149,11 @@ WarpX::ReadParameters ()
WARPX_ALWAYS_ASSERT_WITH_MESSAGE(noz_fft > 0, "PSATD order must be finite unless psatd.periodic_single_box_fft is used");
}
+ // Integer that corresponds to the order of the PSATD solution
+ // (whether the PSATD equations are derived from first-order or
+ // second-order solution)
+ psatd_solution_type = GetAlgorithmInteger(pp_psatd, "solution_type");
+
// Integers that correspond to the time dependency of J (constant, linear)
// and rho (linear, quadratic) for the PSATD algorithm
J_in_time = GetAlgorithmInteger(pp_psatd, "J_in_time");
@@ -1311,13 +1317,6 @@ WarpX::ReadParameters ()
);
}
- if (J_in_time == JInTime::Constant)
- {
- WARPX_ALWAYS_ASSERT_WITH_MESSAGE(
- rho_in_time == RhoInTime::Linear,
- "psatd.J_in_time=constant supports only psatd.rho_in_time=linear");
- }
-
if (J_in_time == JInTime::Linear)
{
WARPX_ALWAYS_ASSERT_WITH_MESSAGE(
@@ -1331,6 +1330,14 @@ WarpX::ReadParameters ()
WARPX_ALWAYS_ASSERT_WITH_MESSAGE(
v_comoving_is_zero,
"psatd.J_in_time=linear not implemented with comoving PSATD");
+
+ WARPX_ALWAYS_ASSERT_WITH_MESSAGE(
+ !current_correction,
+ "psatd.current_correction=1 not implemented with psatd.J_in_time=linear");
+
+ WARPX_ALWAYS_ASSERT_WITH_MESSAGE(
+ current_deposition_algo != CurrentDepositionAlgo::Vay,
+ "algo.current_deposition=vay not implemented with psatd.J_in_time=linear");
}
for (int dir = 0; dir < AMREX_SPACEDIM; dir++)
@@ -2334,6 +2341,7 @@ void WarpX::AllocLevelSpectralSolver (amrex::Vector<std::unique_ptr<SpectralSolv
fft_periodic_single_box,
update_with_rho,
fft_do_time_averaging,
+ psatd_solution_type,
J_in_time,
rho_in_time,
do_dive_cleaning,