aboutsummaryrefslogtreecommitdiff
path: root/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/GalileanAlgorithm.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/FieldSolver/SpectralSolver/SpectralAlgorithms/GalileanAlgorithm.cpp')
-rw-r--r--Source/FieldSolver/SpectralSolver/SpectralAlgorithms/GalileanAlgorithm.cpp258
1 files changed, 184 insertions, 74 deletions
diff --git a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/GalileanAlgorithm.cpp b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/GalileanAlgorithm.cpp
index 0757d17cd..ea5aa7ec0 100644
--- a/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/GalileanAlgorithm.cpp
+++ b/Source/FieldSolver/SpectralSolver/SpectralAlgorithms/GalileanAlgorithm.cpp
@@ -18,6 +18,16 @@ GalileanAlgorithm::GalileanAlgorithm(const SpectralKSpace& spectral_kspace,
const bool update_with_rho)
// Initialize members of base class
: SpectralBaseAlgorithm(spectral_kspace, dm, norder_x, norder_y, norder_z, nodal),
+ // Initialize the centered finite-order modified k vectors: these are computed
+ // always with the assumption of centered grids (argument nodal = true),
+ // for both nodal and staggered simulations
+ modified_kx_vec_centered(spectral_kspace.getModifiedKComponent(dm,0,norder_x,true)),
+#if (AMREX_SPACEDIM==3)
+ modified_ky_vec_centered(spectral_kspace.getModifiedKComponent(dm,1,norder_y,true)),
+ modified_kz_vec_centered(spectral_kspace.getModifiedKComponent(dm,2,norder_z,true)),
+#else
+ modified_kz_vec_centered(spectral_kspace.getModifiedKComponent(dm,1,norder_z,true)),
+#endif
m_v_galilean(v_galilean),
m_dt(dt),
m_update_with_rho(update_with_rho)
@@ -91,8 +101,8 @@ GalileanAlgorithm::pushSpectralFields (SpectralFieldData& f) const
const Real ky = modified_ky_arr[j];
const Real kz = modified_kz_arr[k];
#else
- constexpr Real ky = 0;
- const Real kz = modified_kz_arr[j];
+ constexpr Real ky = 0._rt;
+ const Real kz = modified_kz_arr[j];
#endif
// Physical constant c**2 and imaginary unit
constexpr Real c2 = PhysConst::c*PhysConst::c;
@@ -168,11 +178,14 @@ void GalileanAlgorithm::InitializeSpectralCoefficients (const SpectralKSpace& sp
const Box& bx = ba[mfi];
// Extract pointers for the k vectors
- const Real* modified_kx = modified_kx_vec[mfi].dataPtr();
+ const Real* kx = modified_kx_vec[mfi].dataPtr();
+ const Real* kx_c = modified_kx_vec_centered[mfi].dataPtr();
#if (AMREX_SPACEDIM==3)
- const Real* modified_ky = modified_ky_vec[mfi].dataPtr();
+ const Real* ky = modified_ky_vec[mfi].dataPtr();
+ const Real* ky_c = modified_ky_vec_centered[mfi].dataPtr();
#endif
- const Real* modified_kz = modified_kz_vec[mfi].dataPtr();
+ const Real* kz = modified_kz_vec[mfi].dataPtr();
+ const Real* kz_c = modified_kz_vec_centered[mfi].dataPtr();
// Extract arrays for the coefficients
Array4<Real> C = C_coef[mfi].array();
@@ -194,13 +207,22 @@ void GalileanAlgorithm::InitializeSpectralCoefficients (const SpectralKSpace& sp
ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept
{
// Calculate norm of vector
- const Real k_norm = std::sqrt(
- std::pow(modified_kx[i], 2) +
+ const Real knorm = std::sqrt(
+ std::pow(kx[i], 2) +
#if (AMREX_SPACEDIM==3)
- std::pow(modified_ky[j], 2) +
- std::pow(modified_kz[k], 2));
+ std::pow(ky[j], 2) +
+ std::pow(kz[k], 2));
#else
- std::pow(modified_kz[j], 2));
+ std::pow(kz[j], 2));
+#endif
+ // Calculate norm of vector
+ const Real knorm_c = std::sqrt(
+ std::pow(kx_c[i], 2) +
+#if (AMREX_SPACEDIM==3)
+ std::pow(ky_c[j], 2) +
+ std::pow(kz_c[k], 2));
+#else
+ std::pow(kz_c[j], 2));
#endif
// Physical constants c, c**2, and epsilon_0, and imaginary unit
constexpr Real c = PhysConst::c;
@@ -213,142 +235,222 @@ void GalileanAlgorithm::InitializeSpectralCoefficients (const SpectralKSpace& sp
const Real dt3 = dt * dt2;
Complex X2_old, X3_old;
- // Calculate dot product of k vector with Galilean velocity
- const Real kv = modified_kx[i]*vx +
+ // Calculate dot product of k vector with Galilean velocity:
+ // this has to be computed always with the centered finite-order modified k
+ // vectors, in order to work correctly for both nodal and staggered simulations
+ const Real kv = kx_c[i]*vx +
#if (AMREX_SPACEDIM==3)
- modified_ky[j]*vy + modified_kz[k]*vz;
+ ky_c[j]*vy + kz_c[k]*vz;
#else
- modified_kz[j]*vz;
+ kz_c[j]*vz;
#endif
// The coefficients in the following refer to the ones given in equations
// (12a)-(12d) of (Lehe et al, PRE 94, 2016), used to update B and E
// (equations (11a) and (11b) of the same reference, respectively)
- if (k_norm != 0.) {
+ if (knorm != 0. && knorm_c != 0.) {
// Auxiliary coefficients
- const Real k2 = k_norm * k_norm;
- const Real ck = c * k_norm;
- const Real ckdt = ck * dt;
- const Complex tmp1 = amrex::exp( I * ckdt); // limit of T2 for nu = 1
- const Complex tmp2 = amrex::exp(- I * ckdt); // limit of T2 for nu = -1
+ const Real om = c * knorm;
+ const Real om2 = om * om;
+ const Real om3 = om * om2;
+ const Real om_c = c * knorm_c;
+ const Real om2_c = om_c * om_c;
+ const Real om3_c = om_c * om2_c;
+ const Complex tmp1 = amrex::exp( I * om * dt);
+ const Complex tmp2 = amrex::exp(- I * om * dt);
// See equation (12a)
- C (i,j,k) = std::cos(ckdt);
- S_ck(i,j,k) = std::sin(ckdt) / ck;
+ C (i,j,k) = std::cos(om * dt);
+ S_ck(i,j,k) = std::sin(om * dt) / om;
// See equation (12b)
- const Real nu = kv / ck;
- const Complex theta = amrex::exp( I * 0.5_rt * kv * dt);
- const Complex theta_star = amrex::exp(- I * 0.5_rt * kv * dt);
+ const Real nu = kv / om_c;
+ const Complex theta = amrex::exp( I * nu * om_c * dt * 0.5_rt);
+ const Complex theta_star = amrex::exp(- I * nu * om_c * dt * 0.5_rt);
// This is exp(i*(k \dot v_gal)*dt)
T2(i,j,k) = theta * theta;
- if ( (nu != 1.) && (nu != 0.) ) {
+ if ( (nu != om/om_c) && (nu != -om/om_c) && (nu != 0.) ) {
// x1 is the coefficient chi_1 in equation (12c)
- Complex x1 = 1._rt / (1._rt - nu*nu)
- * (theta_star - C(i,j,k) * theta + I * kv * S_ck(i,j,k) * theta);
+ Complex x1 = om2_c / (om2 - nu * nu * om2_c)
+ * (theta_star - theta * C(i,j,k) + I * nu * om_c * theta * S_ck(i,j,k));
// X1 multiplies i*(k \times J) in the update equation for B
- X1(i,j,k) = theta * x1 / (ep0 * c2 * k2);
+ X1(i,j,k) = theta * x1 / (ep0 * om2_c);
if (update_with_rho) {
// X2 multiplies rho_new in the update equation for E
// X3 multiplies rho_old in the update equation for E
- X2(i,j,k) = (x1 - theta * (1._rt - C(i,j,k))) / (theta_star - theta) / (ep0 * k2);
- X3(i,j,k) = (x1 - theta_star * (1._rt - C(i,j,k))) / (theta_star - theta) / (ep0 * k2);
+ X2(i,j,k) = c2 * (x1 * om2 - theta * (1._rt - C(i,j,k)) * om2_c)
+ / (theta_star - theta) / (ep0 * om2_c * om2);
+ X3(i,j,k) = c2 * (x1 * om2 - theta_star * (1._rt - C(i,j,k)) * om2_c)
+ / (theta_star - theta) / (ep0 * om2_c * om2);
} else {
// X2_old is the coefficient chi_2 in equation (12d)
// X3_old is the coefficient chi_3 in equation (12d)
// X2 multiplies (k \dot E) in the update equation for E
// X3 multiplies (k \dot J) in the update equation for E
- X2_old = (x1 - theta * (1._rt - C(i,j,k))) / (theta_star - theta);
- X3_old = (x1 - theta_star * (1._rt - C(i,j,k))) / (theta_star - theta);
- X2(i,j,k) = T2(i,j,k) * (X2_old - X3_old) / k2;
- X3(i,j,k) = I * X2_old * (T2(i,j,k) - 1._rt) / (ep0 * k2 * kv);
+ X2_old = (x1 * om2 - theta * (1._rt - C(i,j,k)) * om2_c)
+ / (theta_star - theta);
+ X3_old = (x1 * om2 - theta_star * (1._rt - C(i,j,k)) * om2_c)
+ / (theta_star - theta);
+ X2(i,j,k) = c2 * T2(i,j,k) * (X2_old - X3_old)
+ / (om2_c * om2);
+ X3(i,j,k) = I * c2 * X2_old * (T2(i,j,k) - 1._rt)
+ / (ep0 * nu * om3_c * om2);
}
// X4 multiplies J in the update equation for E
- X4(i,j,k) = I * kv * X1(i,j,k) - T2(i,j,k) * S_ck(i,j,k) / ep0;
+ X4(i,j,k) = I * nu * om_c * X1(i,j,k) - T2(i,j,k) * S_ck(i,j,k) / ep0;
}
// Limits for nu = 0
if (nu == 0.) {
// X1 multiplies i*(k \times J) in the update equation for B
- X1(i,j,k) = (1._rt - C(i,j,k)) / (ep0 * c2 * k2);
+ X1(i,j,k) = (1._rt - C(i,j,k)) / (ep0 * om2);
if (update_with_rho) {
// X2 multiplies rho_new in the update equation for E
// X3 multiplies rho_old in the update equation for E
- X2(i,j,k) = (1._rt - S_ck(i,j,k) / dt) / (ep0 * k2);
- X3(i,j,k) = (C(i,j,k) - S_ck(i,j,k) / dt) / (ep0 * k2);
+ X2(i,j,k) = c2 * (1._rt - S_ck(i,j,k) / dt) / (ep0 * om2);
+ X3(i,j,k) = c2 * (C(i,j,k) - S_ck(i,j,k) / dt) / (ep0 * om2);
} else {
// X2 multiplies (k \dot E) in the update equation for E
// X3 multiplies (k \dot J) in the update equation for E
- X2(i,j,k) = (1._rt - C(i,j,k)) / k2;
- X3(i,j,k) = (S_ck(i,j,k) / dt - 1._rt) * dt / (ep0 * k2);
+ X2(i,j,k) = c2 * (1._rt - C(i,j,k)) / om2;
+ X3(i,j,k) = c2 * (S_ck(i,j,k) / dt - 1._rt) * dt / (ep0 * om2);
}
// Coefficient multiplying J in update equation for E
X4(i,j,k) = - S_ck(i,j,k) / ep0;
}
- // Limits for nu = 1
- if (nu == 1.) {
+ // Limits for nu = omega/omega_c
+ if (nu == om/om_c) {
// X1 multiplies i*(k \times J) in the update equation for B
- X1(i,j,k) = (1._rt - tmp1 * tmp1 + 2._rt * I * ckdt) / (4._rt * ep0 * c2 * k2);
+ X1(i,j,k) = (1._rt - tmp1 * tmp1 + 2._rt * I * om * dt) / (4._rt * ep0 * om2);
if (update_with_rho) {
// X2 multiplies rho_new in the update equation for E
// X3 multiplies rho_old in the update equation for E
- X2(i,j,k) = (- 3._rt + 4._rt * tmp1 - tmp1 * tmp1 - 2._rt * I * ckdt)
- / (4._rt * ep0 * k2 * (tmp1 - 1._rt));
- X3(i,j,k) = (3._rt - 2._rt / tmp1 - 2._rt * tmp1 + tmp1 * tmp1 - 2._rt * I * ckdt)
- / (4._rt * ep0 * k2 * (tmp1 - 1._rt));
+ X2(i,j,k) = c2 * (- 3._rt + 4._rt * tmp1 - tmp1 * tmp1 - 2._rt * I * om * dt)
+ / (4._rt * ep0 * om2 * (tmp1 - 1._rt));
+ X3(i,j,k) = c2 * (3._rt - 2._rt * tmp2 - 2._rt * tmp1 + tmp1 * tmp1 - 2._rt * I * om * dt)
+ / (4._rt * ep0 * om2 * (tmp1 - 1._rt));
} else {
// X2 multiplies (k \dot E) in the update equation for E
// X3 multiplies (k \dot J) in the update equation for E
- X2(i,j,k) = (1._rt - C(i,j,k)) * tmp1 / k2;
- X3(i,j,k) = (2._rt * ckdt - I * tmp1 * tmp1 + 4._rt * I * tmp1 - 3._rt * I)
- / (4._rt * ep0 * ck * k2);
+ X2(i,j,k) = c2 * (1._rt - C(i,j,k)) * tmp1 / om2;
+ X3(i,j,k) = c2 * (2._rt * om * dt - I * tmp1 * tmp1 + 4._rt * I * tmp1 - 3._rt * I)
+ / (4._rt * ep0 * om3);
}
// Coefficient multiplying J in update equation for E
- X4(i,j,k) = (- I + I * tmp1 * tmp1 - 2._rt * ckdt) / (4._rt * ep0 * ck);
+ X4(i,j,k) = (- I + I * tmp1 * tmp1 - 2._rt * om * dt) / (4._rt * ep0 * om);
}
- // Limits for nu = -1
- if (nu == -1.) {
+ // Limits for nu = -omega/omega_c
+ if (nu == -om/om_c) {
// X1 multiplies i*(k \times J) in the update equation for B
- X1(i,j,k) = (1._rt - tmp2 * tmp2 - 2._rt * I * ckdt) / (4._rt * ep0 * c2 * k2);
+ X1(i,j,k) = (1._rt - tmp2 * tmp2 - 2._rt * I * om * dt) / (4._rt * ep0 * om2);
if (update_with_rho) {
// X2 multiplies rho_new in the update equation for E
// X3 multiplies rho_old in the update equation for E
- X2(i,j,k) = (- 4._rt + 3._rt * tmp1 + tmp2 - 2._rt * I * ckdt * tmp1)
- / (4._rt * ep0 * k2 * (tmp1 - 1._rt));
- X3(i,j,k) = (2._rt - tmp2 - 3._rt * tmp1 + 2._rt * tmp1 * tmp1 - 2._rt * I * ckdt * tmp1)
- / (4._rt * ep0 * k2 * (tmp1 - 1._rt));
+ X2(i,j,k) = c2 * (- 4._rt + 3._rt * tmp1 + tmp2 - 2._rt * I * om * dt * tmp1)
+ / (4._rt * ep0 * om2 * (tmp1 - 1._rt));
+ X3(i,j,k) = c2 * (2._rt - tmp2 - 3._rt * tmp1 + 2._rt * tmp1 * tmp1 - 2._rt * I * om * dt * tmp1)
+ / (4._rt * ep0 * om2 * (tmp1 - 1._rt));
} else {
// X2 multiplies (k \dot E) in the update equation for E
// X3 multiplies (k \dot J) in the update equation for E
- X2(i,j,k) = (1._rt - C(i,j,k)) * tmp2 / k2;
- X3(i,j,k) = (2._rt * ckdt + I * tmp2 * tmp2 - 4._rt * I * tmp2 + 3._rt * I)
- / (4._rt * ep0 * ck * k2);
+ X2(i,j,k) = c2 * (1._rt - C(i,j,k)) * tmp2 / om2;
+ X3(i,j,k) = c2 * (2._rt * om * dt + I * tmp2 * tmp2 - 4._rt * I * tmp2 + 3._rt * I)
+ / (4._rt * ep0 * om3);
}
// Coefficient multiplying J in update equation for E
- X4(i,j,k) = (I - I * tmp2 * tmp2 - 2._rt * ckdt) / (4._rt * ep0 * ck);
+ X4(i,j,k) = (I - I * tmp2 * tmp2 - 2._rt * om * dt) / (4._rt * ep0 * om);
+ }
+ }
+
+ // Limits for omega_c = 0 only
+ else if (knorm != 0. && knorm_c == 0.) {
+
+ const Real om = c * knorm;
+ const Real om2 = om * om;
+
+ C (i,j,k) = std::cos(om * dt);
+ S_ck(i,j,k) = std::sin(om * dt) / om;
+ T2(i,j,k) = 1._rt;
+
+ // X1 multiplies i*(k \times J) in the update equation for B
+ X1(i,j,k) = (1._rt - C(i,j,k)) / (ep0 * om2);
+
+ if (update_with_rho) {
+ // X2 multiplies rho_new in the update equation for E
+ // X3 multiplies rho_old in the update equation for E
+ X2(i,j,k) = c2 * (1._rt - S_ck(i,j,k) / dt) / (ep0 * om2);
+ X3(i,j,k) = c2 * (C(i,j,k) - S_ck(i,j,k) / dt) / (ep0 * om2);
+ } else {
+ // X2 multiplies (k \dot E) in the update equation for E
+ // X3 multiplies (k \dot J) in the update equation for E
+ X2(i,j,k) = c2 * (1._rt - C(i,j,k)) / om2;
+ X3(i,j,k) = c2 * (S_ck(i,j,k) / dt - 1._rt) * dt / (ep0 * om2);
}
+
+ // Coefficient multiplying J in update equation for E
+ X4(i,j,k) = - S_ck(i,j,k) / ep0;
+
+ }
+
+ // Limits for omega = 0 only
+ else if (knorm == 0. && knorm_c != 0.) {
+
+ const Real om_c = c * knorm_c;
+ const Real om2_c = om_c * om_c;
+ const Real om3_c = om_c * om2_c;
+ const Real nu = kv / om_c;
+ const Complex theta = amrex::exp(I * nu * om_c * dt * 0.5_rt);
+
+ C(i,j,k) = 1._rt;
+ S_ck(i,j,k) = dt;
+ T2(i,j,k) = theta * theta;
+
+ // X1 multiplies i*(k \times J) in the update equation for B
+ X1(i,j,k) = (-1._rt + T2(i,j,k) - I * nu * om_c * dt * T2(i,j,k))
+ / (ep0 * nu * nu * om2_c);
+
+ if (update_with_rho) {
+ // X2 multiplies rho_new in the update equation for E
+ // X3 multiplies rho_old in the update equation for E
+ X2(i,j,k) = c2 * (1._rt - T2(i,j,k) + I * nu * om_c * dt * T2(i,j,k)
+ + 0.5_rt * nu * nu * om2_c * dt * dt * T2(i,j,k))
+ / (ep0 * nu * nu * om2_c * (T2(i,j,k) - 1._rt));
+ X3(i,j,k) = c2 * (1._rt - T2(i,j,k) + I * nu * om_c * dt * T2(i,j,k)
+ + 0.5_rt * nu * nu * om2_c * dt * dt)
+ / (ep0 * nu * nu * om2_c * (T2(i,j,k) - 1._rt));
+ } else {
+ // X2 multiplies (k \dot E) in the update equation for E
+ // X3 multiplies (k \dot J) in the update equation for E
+ X2(i,j,k) = c2 * dt * dt * T2(i,j,k) * 0.5_rt;
+ X3(i,j,k) = c2 * (2._rt * I - 2._rt * nu * om_c * dt * T2(i,j,k)
+ + I * nu * nu * om2_c * dt * dt * T2(i,j,k))
+ / (2._rt * ep0 * nu * nu * nu * om3_c);
+ }
+
+ // Coefficient multiplying J in update equation for E
+ X4(i,j,k) = I * (T2(i,j,k) - 1._rt) / (ep0 * nu * om_c);
}
- // Limits for k = 0
- else {
+ // Limits for omega = 0 and omega_c = 0
+ else if (knorm == 0. && knorm_c == 0.) {
// Limits of cos(c*k*dt) and sin(c*k*dt)/(c*k)
C(i,j,k) = 1._rt;
@@ -404,11 +506,14 @@ GalileanAlgorithm::CurrentCorrection (SpectralFieldData& field_data,
amrex::Array4<Complex> fields = field_data.fields[mfi].array();
// Extract pointers for the k vectors
- const amrex::Real* const modified_kx_arr = modified_kx_vec[mfi].dataPtr();
+ const amrex::Real* const modified_kx_arr = modified_kx_vec[mfi].dataPtr();
+ const amrex::Real* const modified_kx_arr_c = modified_kx_vec_centered[mfi].dataPtr();
#if (AMREX_SPACEDIM==3)
- const amrex::Real* const modified_ky_arr = modified_ky_vec[mfi].dataPtr();
+ const amrex::Real* const modified_ky_arr = modified_ky_vec[mfi].dataPtr();
+ const amrex::Real* const modified_ky_arr_c = modified_ky_vec_centered[mfi].dataPtr();
#endif
- const amrex::Real* const modified_kz_arr = modified_kz_vec[mfi].dataPtr();
+ const amrex::Real* const modified_kz_arr = modified_kz_vec[mfi].dataPtr();
+ const amrex::Real* const modified_kz_arr_c = modified_kz_vec_centered[mfi].dataPtr();
// Local copy of member variables before GPU loop
const amrex::Real dt = m_dt;
@@ -429,13 +534,18 @@ GalileanAlgorithm::CurrentCorrection (SpectralFieldData& field_data,
const Complex rho_new = fields(i,j,k,Idx::rho_new);
// k vector values, and coefficients
- const amrex::Real kx = modified_kx_arr[i];
+ const amrex::Real kx = modified_kx_arr[i];
+ const amrex::Real kx_c = modified_kx_arr_c[i];
#if (AMREX_SPACEDIM==3)
- const amrex::Real ky = modified_ky_arr[j];
- const amrex::Real kz = modified_kz_arr[k];
+ const amrex::Real ky = modified_ky_arr[j];
+ const amrex::Real kz = modified_kz_arr[k];
+ const amrex::Real ky_c = modified_ky_arr_c[j];
+ const amrex::Real kz_c = modified_kz_arr_c[k];
#else
- constexpr amrex::Real ky = 0._rt;
- const amrex::Real kz = modified_kz_arr[j];
+ constexpr amrex::Real ky = 0._rt;
+ const amrex::Real kz = modified_kz_arr[j];
+ constexpr amrex::Real ky_c = 0._rt;
+ const amrex::Real kz_c = modified_kz_arr_c[j];
#endif
constexpr Complex I = Complex{0._rt,1._rt};
@@ -445,7 +555,7 @@ GalileanAlgorithm::CurrentCorrection (SpectralFieldData& field_data,
if (k_norm != 0._rt)
{
const Complex k_dot_J = kx * Jx + ky * Jy + kz * Jz;
- const amrex::Real k_dot_vg = kx * vgx + ky * vgy + kz * vgz;
+ const amrex::Real k_dot_vg = kx_c * vgx + ky_c * vgy + kz_c * vgz;
if ( k_dot_vg != 0._rt ) {