Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add Dan Barnes' effective potential (semi-implicit) Poisson solver #5079

Open
wants to merge 33 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
7020e9c
WIP implementation of the Darwin ES solver
roelof-groenewald Dec 12, 2023
ac4bb0f
add picmi flag to use Darwin solver
roelof-groenewald Mar 22, 2024
df0dc3e
slowly progressing
roelof-groenewald Apr 13, 2024
115bc69
make C_SI a runtime parameter
roelof-groenewald Apr 15, 2024
8549b50
use new sigma support in MLEBNodeLaplacian
roelof-groenewald Jun 9, 2024
c29a612
appropriately name new semi-implicit solver
roelof-groenewald Jul 23, 2024
c0aac03
use AMReX to calculate E-field directly
roelof-groenewald Jul 23, 2024
4ad7112
add example script
roelof-groenewald Jul 30, 2024
5e9b96f
fix clang-tidy issues
roelof-groenewald Aug 4, 2024
21a2a70
more CI fixes
roelof-groenewald Aug 5, 2024
56b40df
change definition of C_SI to match Aleph
roelof-groenewald Aug 5, 2024
6f29954
reset benchmark values
roelof-groenewald Aug 5, 2024
8188839
update documentation
roelof-groenewald Aug 6, 2024
75d4226
also reset fields for SI now that #5104 is merged
roelof-groenewald Aug 8, 2024
6e702a5
use `amrex::MLNodeLaplacian` if EB support is OFF
roelof-groenewald Aug 14, 2024
fd0bfbc
update license statement
roelof-groenewald Aug 18, 2024
e9d2470
Merge branch 'development' into quik
roelof-groenewald Aug 21, 2024
e0b4838
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 21, 2024
31ce2d8
Merge remote-tracking branch 'upstream/development' into quik
roelof-groenewald Sep 29, 2024
cb6a5ca
minor cleanup
roelof-groenewald Sep 29, 2024
b23d3c6
overload compute phi function in semi-implicit Poisson solver
roelof-groenewald Sep 30, 2024
3063ad8
update documentation based on review comments
roelof-groenewald Oct 23, 2024
3c756a9
Merge branch 'development' into quik
roelof-groenewald Oct 23, 2024
7f5f366
update `SemiImplicitPoissonSolver.H` to not rely on compile time sett…
roelof-groenewald Oct 23, 2024
7af8650
replace unavoidable dependence on macros
roelof-groenewald Oct 23, 2024
ed8618b
set `AMReX_LINEAR_SOLVERS_INCFLO` to ON
roelof-groenewald Oct 23, 2024
e41234e
update CI test to use adiabatic expansion benchmark from https://doi.…
roelof-groenewald Oct 24, 2024
03cf3cc
use EB in CI test
roelof-groenewald Oct 24, 2024
06d281a
update CI checksum values to Azure values
roelof-groenewald Oct 24, 2024
fbfcdaa
rename "semi-implicit ES" to "effective potential ES"
roelof-groenewald Nov 4, 2024
aed9360
Fix missed name updates
roelof-groenewald Nov 4, 2024
025699f
Merge remote-tracking branch 'upstream/development' into quik
roelof-groenewald Nov 14, 2024
b440053
Merge branch 'quik' of github.com:roelof-groenewald/WarpX into quik
roelof-groenewald Nov 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Docs/source/refs.bib
Original file line number Diff line number Diff line change
Expand Up @@ -479,3 +479,15 @@ @article{VayFELB2009
doi = {10.1063/1.3080930},
url = {https://doi.org/10.1063/1.3080930},
}

@article{Barnes2021,
title = {Improved C1 shape functions for simplex meshes},
author = {D.C. Barnes},
journal = {Journal of Computational Physics},
volume = {424},
pages = {109852},
year = {2021},
issn = {0021-9991},
doi = {https://doi.org/10.1016/j.jcp.2020.109852},
url = {https://www.sciencedirect.com/science/article/pii/S0021999120306264},
}
17 changes: 17 additions & 0 deletions Docs/source/usage/parameters.rst
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,23 @@ Overall simulation parameters
\boldsymbol{\nabla}^2 \phi = - \rho/\epsilon_0 \qquad \boldsymbol{E} = - \boldsymbol{\nabla}\phi \\
\boldsymbol{\nabla}^2 \boldsymbol{A} = - \mu_0 \boldsymbol{j} \qquad \boldsymbol{B} = \boldsymbol{\nabla}\times\boldsymbol{A}

* ``labframe-effective-potential``: Poisson's equation is solved with a modified dielectric function
(resulting in an "effective potential") to create a semi-implicit scheme which is robust to the
numerical instability seen in explicit electrostatic PIC when :math:`\Delta t \omega_{pe} > 2`.
If this option is used the additional parameter ``warpx.effective_potential_factor`` can also be
specified to set the value of :math:`C_{EP}` (default 4). The method is stable for :math:`C_{EP} \geq 1`
regardless of :math:`\Delta t`, however, the larger :math:`C_{EP}` is set, the lower the numerical plasma
frequency will be and therefore care must be taken to not set it so high that the plasma mode
hybridizes with other modes of interest.
Details of the method can be found in Appendix A of :cite:t:`param-Barnes2021` (note that in that paper
the method is referred to as "semi-implicit electrostatic" but here it has been renamed to "effective potential"
to avoid confusion with the semi-implicit method of Chen et al.).
In short, the code solves:

.. math::

\boldsymbol{\nabla}\cdot\left(1+\frac{C_{EP}}{4}\sum_{s \in \text{species}}(\omega_{ps}\Delta t)^2 \right)\boldsymbol{\nabla} \phi = - \rho/\epsilon_0 \qquad \boldsymbol{E} = - \boldsymbol{\nabla}\phi

* ``relativistic``: Poisson's equation is solved **for each species**
in their respective rest frame. The corresponding field
is mapped back to the simulation frame and will produce both E and B
Expand Down
1 change: 1 addition & 0 deletions Examples/Tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ add_subdirectory(restart)
add_subdirectory(restart_eb)
add_subdirectory(rigid_injection)
add_subdirectory(scraping)
add_subdirectory(effective_potential_electrostatic)
add_subdirectory(silver_mueller)
add_subdirectory(single_particle)
add_subdirectory(space_charge_initialization)
Expand Down
12 changes: 12 additions & 0 deletions Examples/Tests/effective_potential_electrostatic/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Add tests (alphabetical order) ##############################################
#

add_warpx_test(
test_3d_effective_potential_electrostatic_picmi # name
3 # dims
2 # nprocs
inputs_test_3d_effective_potential_electrostatic_picmi.py # inputs
analysis.py # analysis
diags/field_diag/ # output
OFF # dependency
)
81 changes: 81 additions & 0 deletions Examples/Tests/effective_potential_electrostatic/analysis.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python3

import os
import sys

import dill
import matplotlib.pyplot as plt
import numpy as np
from openpmd_viewer import OpenPMDTimeSeries
from scipy.interpolate import RegularGridInterpolator

from pywarpx import picmi

constants = picmi.constants

# load simulation parameters
with open("sim_parameters.dpkl", "rb") as f:
sim = dill.load(f)

# characteristic expansion time
tau = sim.sigma_0 * np.sqrt(sim.M / (constants.kb * (sim.T_e + sim.T_i)))


def get_analytic_density(r, t):
expansion_factor = 1.0 + t**2 / tau**2
T = sim.T_e / expansion_factor
sigma = sim.sigma_0 * np.sqrt(expansion_factor)
return sim.n_plasma * (T / sim.T_e) ** 1.5 * np.exp(-(r**2) / (2.0 * sigma**2))


def get_radial_function(field, info):
"""Helper function to transform Cartesian data to polar data and average
over theta and phi."""
r_grid = np.linspace(0, np.max(info.z) - 1e-3, 30)
theta_grid = np.linspace(0, 2 * np.pi, 40, endpoint=False)
phi_grid = np.linspace(0, np.pi, 20)

r, t, p = np.meshgrid(r_grid, theta_grid, phi_grid, indexing="ij")
x_sp = r * np.sin(p) * np.cos(t)
y_sp = r * np.sin(p) * np.sin(t)
z_sp = r * np.cos(p)

interp = RegularGridInterpolator((info.x, info.y, info.z), field)
field_sp = interp((x_sp, y_sp, z_sp))
return r_grid, np.mean(field_sp, axis=(1, 2))


diag_dir = "diags/field_diag"
ts = OpenPMDTimeSeries(diag_dir, check_all_files=True)

rms_errors = np.zeros(len(ts.iterations))

for ii, it in enumerate(ts.iterations):
rho_e, info = ts.get_field(field="rho_electrons", iteration=it)
r_grid, n_e = get_radial_function(-rho_e / constants.q_e, info)

n_e_analytic = get_analytic_density(r_grid, ts.t[ii])
rms_errors[ii] = (
np.sqrt(np.mean(np.sum((n_e - n_e_analytic) ** 2))) / n_e_analytic[0]
)

plt.plot(r_grid, n_e_analytic, "k--", alpha=0.6)
plt.plot(r_grid, n_e, label=f"t = {ts.t[ii]*1e6:.2f} $\mu$s")

print("RMS error (%) in density: ", rms_errors)
assert np.all(rms_errors < 0.05)

plt.ylabel("$n_e$ (m$^{-3}$)")
plt.xlabel("r (m)")
plt.grid()
plt.legend()
plt.show()

if len(sys.argv) > 1:
sys.path.insert(1, "../../../../warpx/Regression/Checksum/")
import checksumAPI

filename = sys.argv[1]

test_name = os.path.split(os.getcwd())[1]
checksumAPI.evaluate_checksum(test_name, filename, output_format="openpmd")
Loading
Loading