From e4e3f3cf716d51caa73de8079f2727bab8b3b36f Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 2 Jul 2024 10:40:08 +0800 Subject: [PATCH 01/47] Adding new metric flux_surface and its tests --- src/global/enums.h | 16 +- src/metrics/flux_surface.h | 353 ++++++++++++++++++++++++++++++ src/metrics/tests/coord_trans.cpp | 10 + src/metrics/tests/fs.cpp | 184 ++++++++++++++++ src/metrics/tests/vec_trans.cpp | 10 + 5 files changed, 567 insertions(+), 6 deletions(-) create mode 100644 src/metrics/flux_surface.h create mode 100644 src/metrics/tests/fs.cpp diff --git a/src/global/enums.h b/src/global/enums.h index 2dc492dac..ba015d0b2 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -2,9 +2,9 @@ * @file enums.h * @brief Special enum variables describing the simulation * @implements - * - enum ntt::Coord // Cart, Sph, Qsph + * - enum ntt::Coord // Cart, Sph, Qsph, Fs * - enum ntt::Metric // Minkowski, Spherical, QSpherical, - * Kerr_Schild, QKerr_Schild, Kerr_Schild_0 + * Kerr_Schild, QKerr_Schild, Kerr_Schild_0, Flux_Surface * - enum ntt::SimEngine // SRPIC, GRPIC * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync @@ -134,12 +134,13 @@ namespace ntt { Cart = 1, Sph = 2, Qsph = 3, + Fs = 4, }; constexpr Coord(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { Cart, Sph, Qsph }; - static constexpr const char* lookup[] = { "cart", "sph", "qsph" }; + static constexpr type variants[] = { Cart, Sph, Qsph, Fs }; + static constexpr const char* lookup[] = { "cart", "sph", "qsph", "fs" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; @@ -154,16 +155,19 @@ namespace ntt { Kerr_Schild = 4, QKerr_Schild = 5, Kerr_Schild_0 = 6, + Flux_Surface = 7, }; constexpr Metric(uint8_t c) : enums_hidden::BaseEnum { c } {} static constexpr type variants[] = { Minkowski, Spherical, QSpherical, Kerr_Schild, - QKerr_Schild, Kerr_Schild_0 }; + QKerr_Schild, Kerr_Schild_0, + Flux_Surface }; static constexpr const char* lookup[] = { "minkowski", "spherical", "qspherical", "kerr_schild", - "qkerr_schild", "kerr_schild_0" }; + "qkerr_schild", "kerr_schild_0", + "flux_surface" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h new file mode 100644 index 000000000..719cdd36d --- /dev/null +++ b/src/metrics/flux_surface.h @@ -0,0 +1,353 @@ +/** + * @file metrics/flux_surface.h + * @brief metric along constant flux surfaces in force-free fields, based on totoised Boyer-Lindquist coordinates + * @implements + * - metric::FluxSurface<> : metric::MetricBase<> + * @namespaces: + * - metric:: + * !TODO + * None radial surfaces needs to be implemented (dpsi_dr != 0). + */ + +#ifndef METRICS_FLUX_SURFACE_H +#define METRICS_FLUX_SURFACE_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +#include "metrics/metric_base.h" + +#include +#include +#include + + +namespace metric { + + template + class FluxSurface : public MetricBase { + static_assert(D == Dim::_1D, "Only 1D flux_surface is available"); + + private: + // Spin parameter, in [0,1[ + // and horizon size in units of rg + // all physical extents are in units of rg + const real_t a, rg_, rh_, rh_m, psi0, theta0, Omega, pCur; + const real_t eta_max, eta_min; + const real_t d_eta, d_eta_inv; + + Inline auto Delta(const real_t& r) const -> real_t { + return SQR(r) - TWO * r + SQR(a); + } + + Inline auto Sigma(const real_t& r, const real_t& theta) const -> real_t { + return SQR(r) + SQR(a) * SQR(math::cos(theta)); + } + + Inline auto A(const real_t& r, const real_t& theta) const -> real_t { + return SQR(SQR(r) + SQR(a)) - SQR(a) * Delta(r) * SQR(math::sin(theta)); + } + + Inline auto omega(const real_t& r, const real_t& theta) const -> real_t { + return 2 * a * r / A(r, theta); + } + + Inline auto psi(const real_t& r, const real_t& theta) const -> real_t { + return psi0 * (1 - cos(theta)); + } + + Inline auto dpsi_dr(const real_t& r, const real_t& theta) const -> real_t { + return ZERO; + } + + Inline auto dpsi_dtheta(const real_t& r, const real_t& theta) const -> real_t { + return psi0 * math::sin(theta); + } + + Inline auto r2eta(const real_t& r) const -> real_t{ + return math::log((r - rh_) / (r - rh_m)) / (rh_ - rh_m); + } + + Inline auto eta2theta(const real_t& eta) const -> real_t{ + return theta0; + } + + Inline auto eta2r(const real_t& eta) const -> real_t{ + real_t exp = math::exp(eta * (rh_ - rh_m)); + return (rh_ - rh_m * exp) / (1 - exp); + } + + + + + public: + static constexpr const char* Label { "flux_surface" }; + static constexpr Dimension PrtlDim { D }; + static constexpr ntt::Coord::type CoordType { ntt::Coord::Fs }; + static constexpr ntt::Metric::type MetricType { ntt::Metric::Flux_Surface }; + using MetricBase::x1_min; + using MetricBase::x1_max; + using MetricBase::nx1; + using MetricBase::set_dxMin; + + FluxSurface(std::vector res, + boundaries_t ext, + const std::map& params) + : MetricBase { res, ext } + , a { params.at("a") } + , psi0 { params.at("psi0") } + , theta0 { params.at("theta0") } + , pCur { params.at("pCur") } + , rg_ { ONE } + , rh_ { ONE + math::sqrt(ONE - SQR(a)) } + , rh_m { ONE - math::sqrt(ONE - SQR(a)) } + , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh_)) } + , eta_min { r2eta(x1_min) } + , eta_max { r2eta(x1_max) } + , d_eta { (eta_max - eta_min) / nx1 } + , d_eta_inv { 1 / d_eta }{ + set_dxMin(find_dxMin()); + } + + ~FluxSurface() = default; + + [[nodiscard]] + Inline auto spin() const -> real_t { + return a; + } + + [[nodiscard]] + Inline auto rhorizon() const -> real_t { + return rh_; + } + + [[nodiscard]] + Inline auto rhorizon_minus() const -> real_t { + return rh_m; + } + + [[nodiscard]] + Inline auto rg() const -> real_t { + return rg_; + } + + + /** + * lapse function + * @param x coordinate array in code units + */ + Inline auto alpha(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return math::sqrt(Sigma(r_, theta_) * Delta(r_) / A(r_, theta_)); + } + + /** + * @brief Compute helper functions f0,f1,f2 in 1D-GRPIC + */ + Inline auto f2(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; + const real_t Delta_ { Delta(r_) }; + const real_t temp = SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_dr(r_, theta_)); + return Sigma(r_, theta_) * Delta_ * SQR(dpsi_dtheta_) / temp + + SQR(A(r_, theta_)* math::sin(theta_) * dpsi_dtheta_ * pCur / temp ) + / h_<3, 3>(xi); + } + + Inline auto f1(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; + return A(r_, theta_)* math::sin(theta_) * dpsi_dtheta_ * pCur * (Omega - omega(r_, theta_)) / + (SQR(dpsi_dtheta_) + Delta(r_) * SQR(dpsi_dr(r_, theta_))); + } + + Inline auto f0(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return h_<3, 3>(xi) * SQR(Omega - omega(r_, theta_)); + } + + /** + * minimum effective cell size for a given metric (in physical units) + */ + [[nodiscard]] + auto find_dxMin() const -> real_t override { + real_t min_dx { -ONE }; + for (int i { 0 }; i < nx1; ++i){ + real_t i_ { static_cast(i) + HALF }; + coord_t xi { i_ }; + real_t dx = ONE / math::sqrt(h<1, 1>(xi)); + if ((min_dx > dx) || (min_dx < 0.0)) { + min_dx = dx; + } + } + return min_dx; + } + + /** + * metric component with lower indices: h_ij + * @param x coordinate array in code units + */ + template + Inline auto h_(const coord_t& x) const -> real_t { + static_assert(i > 0 && i <= 3, "Invalid index i"); + static_assert(j > 0 && j <= 3, "Invalid index j"); + + const real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; + const real_t Sigma_ { Sigma(r_, theta_) }; + const real_t Delta_ { Delta(r_) }; + const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; + const real_t dpsi_r_ { dpsi_dr(r_, theta_) }; + if constexpr (i == 1 && j == 1) { + // h_11 + return SQR(d_eta) * Sigma_ * Delta_ * SQR( dpsi_dtheta_) / + (SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_r_)); + } else if constexpr (i == 2 && j == 2) { + // h_22 + return Sigma_ / (SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_r_)); + } else if constexpr (i == 3 && j == 3) { + // h_33 + return A(r_, theta_) * SQR(math::sin(theta_)) / Sigma_; + }else { + return ZERO; + } + } + + /** + * metric component with upper indices: h^ij + * @param x coordinate array in code units + */ + template + Inline auto h(const coord_t& x) const -> real_t { + static_assert(i > 0 && i <= 3, "Invalid index i"); + static_assert(j > 0 && j <= 3, "Invalid index j"); + + if constexpr (i == j) { + return ONE / h_(x); + }else { + return ZERO; + } + } + + /** + * sqrt(det(h_ij)) + * @param x coordinate array in code units + */ + Inline auto sqrt_det_h(const coord_t& x) const -> real_t { + return math::sqrt(h_<1, 1>(x) * h_<2, 2>(x) * h_<3, 3>(x)); + } + + /** + * coordinate conversions + */ + template + Inline void convert(const coord_t& x_in, coord_t& x_out) const { + static_assert(in != out, "Invalid coordinate conversion"); + static_assert((in != Crd::XYZ) && + (out != Crd::XYZ), + "Invalid coordinate conversion: XYZ not allowed in GR"); + if constexpr (in == Crd::Cd && (out == Crd::Sph || out == Crd::Ph)){ + // code -> sph/phys + x_out[0] = eta2r(x_in[0] * d_eta + eta_min); + }else if constexpr ((in == Crd::Sph || in == Crd::Ph) && out == Crd::Cd){ + //sph/phys -> code + x_out[0] = (r2eta(x_in[0]) - eta_min) / d_eta; + } + } + + + /** + * component wise vector transformations + */ + template + Inline auto transform(const coord_t& x, + const real_t& v_in) const -> real_t { + static_assert(in != out, "Invalid vector transformation"); + static_assert(in != Idx::XYZ && out != Idx::XYZ, + "Invalid vector transformation: XYZ not allowed in GR"); + static_assert(i > 0 && i <= 3, "Invalid index i"); + if constexpr ((in == Idx::T && out == Idx::Sph) || + (in == Idx::Sph && out == Idx::T)) { + // tetrad <-> sph + return v_in; + } else if constexpr ((in == Idx::T || in == Idx::Sph) && out == Idx::U) { + // tetrad/sph -> cntrv + return v_in / math::sqrt(h_(x)); + } else if constexpr (in == Idx::U && (out == Idx::T || out == Idx::Sph)) { + // cntrv -> tetrad/sph + return v_in * math::sqrt(h_(x)); + } else if constexpr ((in == Idx::T || in == Idx::Sph) && out == Idx::D) { + // tetrad/sph -> cov + return v_in / math::sqrt(h(x)); + } else if constexpr (in == Idx::D && (out == Idx::T || out == Idx::Sph)) { + // cov -> tetrad/sph + return v_in * math::sqrt(h(x)); + } else if constexpr (in == Idx::U && out == Idx::D) { + // cntrv -> cov + return v_in * h_(x); + } else if constexpr (in == Idx::D && out == Idx::U) { + // cov -> cntrv + return v_in * h(x); + } else if constexpr ((in == Idx::U && out == Idx::PU) || + (in == Idx::PD && out == Idx::D)) { + // cntrv -> phys cntrv || phys cov -> cov + if constexpr (i == 1){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + return v_in * Delta(r_) * d_eta ; + }else if constexpr (i == 2){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; + return v_in / dpsi_dtheta(r_, theta_); + }else{ + return v_in; + } + } else if constexpr ((in == Idx::PU && out == Idx::U) || + (in == Idx::D && out == Idx::PD)) { + // phys cntrv -> cntrv || cov -> phys cov + if constexpr (i == 1){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + return v_in * d_eta_inv / Delta(r_); + }else if constexpr (i == 2){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; + return v_in * dpsi_dtheta(r_, theta_); + }else{ + return v_in; + } + } else { + raise::KernelError(HERE, "Invalid transformation"); + } + } + + /** + * full vector transformations + */ + template + Inline void transform(const coord_t& xi, + const vec_t& v_in, + vec_t& v_out) const { + static_assert(in != out, "Invalid vector transformation"); + if constexpr (in != Idx::XYZ && out != Idx::XYZ) { + v_out[0] = transform<1, in, out>(xi, v_in[0]); + v_out[1] = transform<2, in, out>(xi, v_in[1]); + v_out[2] = transform<3, in, out>(xi, v_in[2]); + } else { + raise::KernelError(HERE, "Invalid vector transformation"); + } + } + + }; + + + +} + + +#endif // METRICS_FLUX_SURFACE_H diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 027b7677a..af0277740 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -182,6 +182,16 @@ auto main(int argc, char* argv[]) -> int { }; testMetric>(resks0, extks0, 150); + testMetric>( + { 128 }, + { { 2.0, 50.0 } }, + 10, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + } catch (std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/fs.cpp new file mode 100644 index 000000000..16d60fcd9 --- /dev/null +++ b/src/metrics/tests/fs.cpp @@ -0,0 +1,184 @@ +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" + +#include "metrics/flux_surface.h" + +#include +#include +#include +#include + +void errorIf(bool condition, const std::string& message) { + if (condition) { + throw std::runtime_error(message); + } +} + +inline static constexpr auto epsilon = std::numeric_limits::epsilon(); + +template +Inline auto equal(const vec_t& a, + const vec_t& b, + const char* msg, + const real_t acc = ONE) -> bool { + const auto eps = epsilon * acc; + for (unsigned short d = 0; d < D; ++d) { + if (not cmp::AlmostEqual(a[d], b[d], eps)) { + printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); + return false; + } + } + return true; +} + +Inline auto equal(const real_t& a, + const real_t& b, + const char* msg, + const real_t acc = ONE) -> bool { + const auto eps = epsilon * acc; + if (not cmp::AlmostEqual(a, b, eps)) { + printf("%.12e != %.12e %s\n", a, b, msg); + return false; + } + return true; +} + +template +Inline void unravel(std::size_t idx, + tuple_t& ijk, + const tuple_t& res) { + for (unsigned short d = 0; d < D; ++d) { + ijk[d] = idx % res[d]; + idx /= res[d]; + } +} + +template +void testMetric(const std::vector& res, + const boundaries_t& ext, + const real_t acc = ONE, + const std::map& params = {}) { + static_assert(M::Dim == 1, "Dim != 1"); + errorIf(res.size() != (std::size_t)(M::Dim), "res.size() != M.dim"); + errorIf(ext.size() != (std::size_t)(M::Dim), "ext.size() != M.dim"); + for (const auto& e : ext) { + errorIf(e.first >= e.second, "e.first >= e.second"); + } + + M metric(res, ext, params); + tuple_t res_tup; + std::size_t npts = 1; + for (auto d = 0; d < M::Dim; ++d) { + res_tup[d] = res[d]; + npts *= res[d]; + } + + unsigned long all_wrongs = 0; + const auto rg = metric.rg(); + const auto rh = metric.rhorizon(); + const auto a = metric.spin(); + const auto th = params.at("theta0"); + const auto psi0 = params.at("psi0"); + const auto pCur = params.at("pCur"); + const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); + Kokkos::parallel_reduce( + "h_ij/hij", + npts, + Lambda(index_t n, unsigned long& wrongs) { + tuple_t idx; + unravel(n, idx, res_tup); + coord_t x_Code { ZERO }; + coord_t x_Phys { ZERO }; + + for (unsigned short d = 0; d < M::Dim; ++d) { + x_Code[d] = (real_t)(idx[d]) + HALF; + } + + const auto h11 = metric.template h<1, 1>(x_Code); + const auto h22 = metric.template h<2, 2>(x_Code); + const auto h33 = metric.template h<3, 3>(x_Code); + const auto h_11 = metric.template h_<1, 1>(x_Code); + const auto h_22 = metric.template h_<2, 2>(x_Code); + const auto h_33 = metric.template h_<3, 3>(x_Code); + + metric.template convert(x_Code, x_Phys); + const auto r = x_Phys[0]; + + + const auto Sigma = SQR(r) + SQR(a * math::cos(th)); + const auto Delta = SQR(r) - TWO * rg * r + SQR(a); + const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th)) * Delta; + const auto dpsi_r = 0; + const auto dpsi_dtheta = psi0 * math::sin(th); + const auto omega = 2 * a * r / A ; + + const auto h_11_expect = Sigma / Delta; + const auto h_22_expect = Sigma ; + const auto h_33_expect = A * SQR(math::sin(th)) / Sigma; + const auto h11_expect = ONE / h_11_expect; + const auto h22_expect = ONE / h_22_expect; + const auto h33_expect = ONE / h_33_expect; + + const auto f0_expect = h_33_expect * SQR(Omega - omega); + const auto f1_expect = A * pCur * math::sin(th) * (Omega - omega) / dpsi_dtheta; + const auto f2_expect = Sigma * Delta + Sigma * A * SQR(pCur / dpsi_dtheta); + + const auto f0_predict = metric.f0(x_Code); + const auto f1_predict = metric.f1(x_Code); + const auto f2_predict = metric.f2(x_Code); + + + vec_t hij_temp { ZERO }, hij_predict { ZERO }; + metric.template transform(x_Code, { h11, h22, h33 }, hij_temp); + metric.template transform(x_Code, hij_temp, hij_predict); + + + vec_t h_ij_temp { ZERO }, h_ij_predict { ZERO }; + metric.template transform(x_Code, + { h_11, h_22, h_33 }, + h_ij_temp); + metric.template transform(x_Code, h_ij_temp, h_ij_predict); + + + vec_t hij_expect { h11_expect, h22_expect, h33_expect }; + vec_t h_ij_expect { h_11_expect, h_22_expect, h_33_expect }; + + wrongs += not equal(hij_expect, hij_predict, "hij", acc); + wrongs += not equal(f0_expect, f0_predict, "f0", acc); + wrongs += not equal(f1_expect, f1_predict, "f1", acc); + wrongs += not equal(f2_expect, f2_predict, "f2", acc); + + }, + all_wrongs); + + errorIf(all_wrongs != 0, + "wrong h_ij/hij for " + std::to_string(M::Dim) + "D " + + std::string(metric.Label) + " with " + std::to_string(all_wrongs) + + " errors"); +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + using namespace metric; + testMetric>( + { 128 }, + { { 2.0, 50.0 } }, + 10, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} diff --git a/src/metrics/tests/vec_trans.cpp b/src/metrics/tests/vec_trans.cpp index a249c1d41..659244462 100644 --- a/src/metrics/tests/vec_trans.cpp +++ b/src/metrics/tests/vec_trans.cpp @@ -236,6 +236,16 @@ auto main(int argc, char* argv[]) -> int { }; testMetric>(resks0, extks0, 10); + testMetric>( + { 128 }, + { { 2.0, 50.0 } }, + 10, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + } catch (std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); From 33a69b2e467921f0e3ff110d9f1fafa525972f07 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 2 Jul 2024 10:41:58 +0800 Subject: [PATCH 02/47] generate tests for flux_surface --- src/metrics/tests/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/metrics/tests/CMakeLists.txt b/src/metrics/tests/CMakeLists.txt index 117cb3295..fe917de0b 100644 --- a/src/metrics/tests/CMakeLists.txt +++ b/src/metrics/tests/CMakeLists.txt @@ -25,4 +25,5 @@ gen_test(vec_trans) gen_test(coord_trans) gen_test(sph-qsph) gen_test(ks-qks) -gen_test(sr-cart-sph) \ No newline at end of file +gen_test(sr-cart-sph) +gen_test(fs) \ No newline at end of file From 279c90b7a4c793a08ba5785ab6dc1126712591ec Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 2 Jul 2024 10:40:08 +0800 Subject: [PATCH 03/47] Adding new metric flux_surface and its tests --- src/global/enums.h | 16 +- src/metrics/flux_surface.h | 353 ++++++++++++++++++++++++++++++ src/metrics/tests/coord_trans.cpp | 10 + src/metrics/tests/fs.cpp | 184 ++++++++++++++++ src/metrics/tests/vec_trans.cpp | 10 + 5 files changed, 567 insertions(+), 6 deletions(-) create mode 100644 src/metrics/flux_surface.h create mode 100644 src/metrics/tests/fs.cpp diff --git a/src/global/enums.h b/src/global/enums.h index 2dc492dac..ba015d0b2 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -2,9 +2,9 @@ * @file enums.h * @brief Special enum variables describing the simulation * @implements - * - enum ntt::Coord // Cart, Sph, Qsph + * - enum ntt::Coord // Cart, Sph, Qsph, Fs * - enum ntt::Metric // Minkowski, Spherical, QSpherical, - * Kerr_Schild, QKerr_Schild, Kerr_Schild_0 + * Kerr_Schild, QKerr_Schild, Kerr_Schild_0, Flux_Surface * - enum ntt::SimEngine // SRPIC, GRPIC * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync @@ -134,12 +134,13 @@ namespace ntt { Cart = 1, Sph = 2, Qsph = 3, + Fs = 4, }; constexpr Coord(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { Cart, Sph, Qsph }; - static constexpr const char* lookup[] = { "cart", "sph", "qsph" }; + static constexpr type variants[] = { Cart, Sph, Qsph, Fs }; + static constexpr const char* lookup[] = { "cart", "sph", "qsph", "fs" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; @@ -154,16 +155,19 @@ namespace ntt { Kerr_Schild = 4, QKerr_Schild = 5, Kerr_Schild_0 = 6, + Flux_Surface = 7, }; constexpr Metric(uint8_t c) : enums_hidden::BaseEnum { c } {} static constexpr type variants[] = { Minkowski, Spherical, QSpherical, Kerr_Schild, - QKerr_Schild, Kerr_Schild_0 }; + QKerr_Schild, Kerr_Schild_0, + Flux_Surface }; static constexpr const char* lookup[] = { "minkowski", "spherical", "qspherical", "kerr_schild", - "qkerr_schild", "kerr_schild_0" }; + "qkerr_schild", "kerr_schild_0", + "flux_surface" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h new file mode 100644 index 000000000..719cdd36d --- /dev/null +++ b/src/metrics/flux_surface.h @@ -0,0 +1,353 @@ +/** + * @file metrics/flux_surface.h + * @brief metric along constant flux surfaces in force-free fields, based on totoised Boyer-Lindquist coordinates + * @implements + * - metric::FluxSurface<> : metric::MetricBase<> + * @namespaces: + * - metric:: + * !TODO + * None radial surfaces needs to be implemented (dpsi_dr != 0). + */ + +#ifndef METRICS_FLUX_SURFACE_H +#define METRICS_FLUX_SURFACE_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +#include "metrics/metric_base.h" + +#include +#include +#include + + +namespace metric { + + template + class FluxSurface : public MetricBase { + static_assert(D == Dim::_1D, "Only 1D flux_surface is available"); + + private: + // Spin parameter, in [0,1[ + // and horizon size in units of rg + // all physical extents are in units of rg + const real_t a, rg_, rh_, rh_m, psi0, theta0, Omega, pCur; + const real_t eta_max, eta_min; + const real_t d_eta, d_eta_inv; + + Inline auto Delta(const real_t& r) const -> real_t { + return SQR(r) - TWO * r + SQR(a); + } + + Inline auto Sigma(const real_t& r, const real_t& theta) const -> real_t { + return SQR(r) + SQR(a) * SQR(math::cos(theta)); + } + + Inline auto A(const real_t& r, const real_t& theta) const -> real_t { + return SQR(SQR(r) + SQR(a)) - SQR(a) * Delta(r) * SQR(math::sin(theta)); + } + + Inline auto omega(const real_t& r, const real_t& theta) const -> real_t { + return 2 * a * r / A(r, theta); + } + + Inline auto psi(const real_t& r, const real_t& theta) const -> real_t { + return psi0 * (1 - cos(theta)); + } + + Inline auto dpsi_dr(const real_t& r, const real_t& theta) const -> real_t { + return ZERO; + } + + Inline auto dpsi_dtheta(const real_t& r, const real_t& theta) const -> real_t { + return psi0 * math::sin(theta); + } + + Inline auto r2eta(const real_t& r) const -> real_t{ + return math::log((r - rh_) / (r - rh_m)) / (rh_ - rh_m); + } + + Inline auto eta2theta(const real_t& eta) const -> real_t{ + return theta0; + } + + Inline auto eta2r(const real_t& eta) const -> real_t{ + real_t exp = math::exp(eta * (rh_ - rh_m)); + return (rh_ - rh_m * exp) / (1 - exp); + } + + + + + public: + static constexpr const char* Label { "flux_surface" }; + static constexpr Dimension PrtlDim { D }; + static constexpr ntt::Coord::type CoordType { ntt::Coord::Fs }; + static constexpr ntt::Metric::type MetricType { ntt::Metric::Flux_Surface }; + using MetricBase::x1_min; + using MetricBase::x1_max; + using MetricBase::nx1; + using MetricBase::set_dxMin; + + FluxSurface(std::vector res, + boundaries_t ext, + const std::map& params) + : MetricBase { res, ext } + , a { params.at("a") } + , psi0 { params.at("psi0") } + , theta0 { params.at("theta0") } + , pCur { params.at("pCur") } + , rg_ { ONE } + , rh_ { ONE + math::sqrt(ONE - SQR(a)) } + , rh_m { ONE - math::sqrt(ONE - SQR(a)) } + , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh_)) } + , eta_min { r2eta(x1_min) } + , eta_max { r2eta(x1_max) } + , d_eta { (eta_max - eta_min) / nx1 } + , d_eta_inv { 1 / d_eta }{ + set_dxMin(find_dxMin()); + } + + ~FluxSurface() = default; + + [[nodiscard]] + Inline auto spin() const -> real_t { + return a; + } + + [[nodiscard]] + Inline auto rhorizon() const -> real_t { + return rh_; + } + + [[nodiscard]] + Inline auto rhorizon_minus() const -> real_t { + return rh_m; + } + + [[nodiscard]] + Inline auto rg() const -> real_t { + return rg_; + } + + + /** + * lapse function + * @param x coordinate array in code units + */ + Inline auto alpha(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return math::sqrt(Sigma(r_, theta_) * Delta(r_) / A(r_, theta_)); + } + + /** + * @brief Compute helper functions f0,f1,f2 in 1D-GRPIC + */ + Inline auto f2(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; + const real_t Delta_ { Delta(r_) }; + const real_t temp = SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_dr(r_, theta_)); + return Sigma(r_, theta_) * Delta_ * SQR(dpsi_dtheta_) / temp + + SQR(A(r_, theta_)* math::sin(theta_) * dpsi_dtheta_ * pCur / temp ) + / h_<3, 3>(xi); + } + + Inline auto f1(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; + return A(r_, theta_)* math::sin(theta_) * dpsi_dtheta_ * pCur * (Omega - omega(r_, theta_)) / + (SQR(dpsi_dtheta_) + Delta(r_) * SQR(dpsi_dr(r_, theta_))); + } + + Inline auto f0(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return h_<3, 3>(xi) * SQR(Omega - omega(r_, theta_)); + } + + /** + * minimum effective cell size for a given metric (in physical units) + */ + [[nodiscard]] + auto find_dxMin() const -> real_t override { + real_t min_dx { -ONE }; + for (int i { 0 }; i < nx1; ++i){ + real_t i_ { static_cast(i) + HALF }; + coord_t xi { i_ }; + real_t dx = ONE / math::sqrt(h<1, 1>(xi)); + if ((min_dx > dx) || (min_dx < 0.0)) { + min_dx = dx; + } + } + return min_dx; + } + + /** + * metric component with lower indices: h_ij + * @param x coordinate array in code units + */ + template + Inline auto h_(const coord_t& x) const -> real_t { + static_assert(i > 0 && i <= 3, "Invalid index i"); + static_assert(j > 0 && j <= 3, "Invalid index j"); + + const real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; + const real_t Sigma_ { Sigma(r_, theta_) }; + const real_t Delta_ { Delta(r_) }; + const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; + const real_t dpsi_r_ { dpsi_dr(r_, theta_) }; + if constexpr (i == 1 && j == 1) { + // h_11 + return SQR(d_eta) * Sigma_ * Delta_ * SQR( dpsi_dtheta_) / + (SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_r_)); + } else if constexpr (i == 2 && j == 2) { + // h_22 + return Sigma_ / (SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_r_)); + } else if constexpr (i == 3 && j == 3) { + // h_33 + return A(r_, theta_) * SQR(math::sin(theta_)) / Sigma_; + }else { + return ZERO; + } + } + + /** + * metric component with upper indices: h^ij + * @param x coordinate array in code units + */ + template + Inline auto h(const coord_t& x) const -> real_t { + static_assert(i > 0 && i <= 3, "Invalid index i"); + static_assert(j > 0 && j <= 3, "Invalid index j"); + + if constexpr (i == j) { + return ONE / h_(x); + }else { + return ZERO; + } + } + + /** + * sqrt(det(h_ij)) + * @param x coordinate array in code units + */ + Inline auto sqrt_det_h(const coord_t& x) const -> real_t { + return math::sqrt(h_<1, 1>(x) * h_<2, 2>(x) * h_<3, 3>(x)); + } + + /** + * coordinate conversions + */ + template + Inline void convert(const coord_t& x_in, coord_t& x_out) const { + static_assert(in != out, "Invalid coordinate conversion"); + static_assert((in != Crd::XYZ) && + (out != Crd::XYZ), + "Invalid coordinate conversion: XYZ not allowed in GR"); + if constexpr (in == Crd::Cd && (out == Crd::Sph || out == Crd::Ph)){ + // code -> sph/phys + x_out[0] = eta2r(x_in[0] * d_eta + eta_min); + }else if constexpr ((in == Crd::Sph || in == Crd::Ph) && out == Crd::Cd){ + //sph/phys -> code + x_out[0] = (r2eta(x_in[0]) - eta_min) / d_eta; + } + } + + + /** + * component wise vector transformations + */ + template + Inline auto transform(const coord_t& x, + const real_t& v_in) const -> real_t { + static_assert(in != out, "Invalid vector transformation"); + static_assert(in != Idx::XYZ && out != Idx::XYZ, + "Invalid vector transformation: XYZ not allowed in GR"); + static_assert(i > 0 && i <= 3, "Invalid index i"); + if constexpr ((in == Idx::T && out == Idx::Sph) || + (in == Idx::Sph && out == Idx::T)) { + // tetrad <-> sph + return v_in; + } else if constexpr ((in == Idx::T || in == Idx::Sph) && out == Idx::U) { + // tetrad/sph -> cntrv + return v_in / math::sqrt(h_(x)); + } else if constexpr (in == Idx::U && (out == Idx::T || out == Idx::Sph)) { + // cntrv -> tetrad/sph + return v_in * math::sqrt(h_(x)); + } else if constexpr ((in == Idx::T || in == Idx::Sph) && out == Idx::D) { + // tetrad/sph -> cov + return v_in / math::sqrt(h(x)); + } else if constexpr (in == Idx::D && (out == Idx::T || out == Idx::Sph)) { + // cov -> tetrad/sph + return v_in * math::sqrt(h(x)); + } else if constexpr (in == Idx::U && out == Idx::D) { + // cntrv -> cov + return v_in * h_(x); + } else if constexpr (in == Idx::D && out == Idx::U) { + // cov -> cntrv + return v_in * h(x); + } else if constexpr ((in == Idx::U && out == Idx::PU) || + (in == Idx::PD && out == Idx::D)) { + // cntrv -> phys cntrv || phys cov -> cov + if constexpr (i == 1){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + return v_in * Delta(r_) * d_eta ; + }else if constexpr (i == 2){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; + return v_in / dpsi_dtheta(r_, theta_); + }else{ + return v_in; + } + } else if constexpr ((in == Idx::PU && out == Idx::U) || + (in == Idx::D && out == Idx::PD)) { + // phys cntrv -> cntrv || cov -> phys cov + if constexpr (i == 1){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + return v_in * d_eta_inv / Delta(r_); + }else if constexpr (i == 2){ + real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; + return v_in * dpsi_dtheta(r_, theta_); + }else{ + return v_in; + } + } else { + raise::KernelError(HERE, "Invalid transformation"); + } + } + + /** + * full vector transformations + */ + template + Inline void transform(const coord_t& xi, + const vec_t& v_in, + vec_t& v_out) const { + static_assert(in != out, "Invalid vector transformation"); + if constexpr (in != Idx::XYZ && out != Idx::XYZ) { + v_out[0] = transform<1, in, out>(xi, v_in[0]); + v_out[1] = transform<2, in, out>(xi, v_in[1]); + v_out[2] = transform<3, in, out>(xi, v_in[2]); + } else { + raise::KernelError(HERE, "Invalid vector transformation"); + } + } + + }; + + + +} + + +#endif // METRICS_FLUX_SURFACE_H diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 027b7677a..af0277740 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -182,6 +182,16 @@ auto main(int argc, char* argv[]) -> int { }; testMetric>(resks0, extks0, 150); + testMetric>( + { 128 }, + { { 2.0, 50.0 } }, + 10, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + } catch (std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/fs.cpp new file mode 100644 index 000000000..16d60fcd9 --- /dev/null +++ b/src/metrics/tests/fs.cpp @@ -0,0 +1,184 @@ +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" + +#include "metrics/flux_surface.h" + +#include +#include +#include +#include + +void errorIf(bool condition, const std::string& message) { + if (condition) { + throw std::runtime_error(message); + } +} + +inline static constexpr auto epsilon = std::numeric_limits::epsilon(); + +template +Inline auto equal(const vec_t& a, + const vec_t& b, + const char* msg, + const real_t acc = ONE) -> bool { + const auto eps = epsilon * acc; + for (unsigned short d = 0; d < D; ++d) { + if (not cmp::AlmostEqual(a[d], b[d], eps)) { + printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); + return false; + } + } + return true; +} + +Inline auto equal(const real_t& a, + const real_t& b, + const char* msg, + const real_t acc = ONE) -> bool { + const auto eps = epsilon * acc; + if (not cmp::AlmostEqual(a, b, eps)) { + printf("%.12e != %.12e %s\n", a, b, msg); + return false; + } + return true; +} + +template +Inline void unravel(std::size_t idx, + tuple_t& ijk, + const tuple_t& res) { + for (unsigned short d = 0; d < D; ++d) { + ijk[d] = idx % res[d]; + idx /= res[d]; + } +} + +template +void testMetric(const std::vector& res, + const boundaries_t& ext, + const real_t acc = ONE, + const std::map& params = {}) { + static_assert(M::Dim == 1, "Dim != 1"); + errorIf(res.size() != (std::size_t)(M::Dim), "res.size() != M.dim"); + errorIf(ext.size() != (std::size_t)(M::Dim), "ext.size() != M.dim"); + for (const auto& e : ext) { + errorIf(e.first >= e.second, "e.first >= e.second"); + } + + M metric(res, ext, params); + tuple_t res_tup; + std::size_t npts = 1; + for (auto d = 0; d < M::Dim; ++d) { + res_tup[d] = res[d]; + npts *= res[d]; + } + + unsigned long all_wrongs = 0; + const auto rg = metric.rg(); + const auto rh = metric.rhorizon(); + const auto a = metric.spin(); + const auto th = params.at("theta0"); + const auto psi0 = params.at("psi0"); + const auto pCur = params.at("pCur"); + const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); + Kokkos::parallel_reduce( + "h_ij/hij", + npts, + Lambda(index_t n, unsigned long& wrongs) { + tuple_t idx; + unravel(n, idx, res_tup); + coord_t x_Code { ZERO }; + coord_t x_Phys { ZERO }; + + for (unsigned short d = 0; d < M::Dim; ++d) { + x_Code[d] = (real_t)(idx[d]) + HALF; + } + + const auto h11 = metric.template h<1, 1>(x_Code); + const auto h22 = metric.template h<2, 2>(x_Code); + const auto h33 = metric.template h<3, 3>(x_Code); + const auto h_11 = metric.template h_<1, 1>(x_Code); + const auto h_22 = metric.template h_<2, 2>(x_Code); + const auto h_33 = metric.template h_<3, 3>(x_Code); + + metric.template convert(x_Code, x_Phys); + const auto r = x_Phys[0]; + + + const auto Sigma = SQR(r) + SQR(a * math::cos(th)); + const auto Delta = SQR(r) - TWO * rg * r + SQR(a); + const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th)) * Delta; + const auto dpsi_r = 0; + const auto dpsi_dtheta = psi0 * math::sin(th); + const auto omega = 2 * a * r / A ; + + const auto h_11_expect = Sigma / Delta; + const auto h_22_expect = Sigma ; + const auto h_33_expect = A * SQR(math::sin(th)) / Sigma; + const auto h11_expect = ONE / h_11_expect; + const auto h22_expect = ONE / h_22_expect; + const auto h33_expect = ONE / h_33_expect; + + const auto f0_expect = h_33_expect * SQR(Omega - omega); + const auto f1_expect = A * pCur * math::sin(th) * (Omega - omega) / dpsi_dtheta; + const auto f2_expect = Sigma * Delta + Sigma * A * SQR(pCur / dpsi_dtheta); + + const auto f0_predict = metric.f0(x_Code); + const auto f1_predict = metric.f1(x_Code); + const auto f2_predict = metric.f2(x_Code); + + + vec_t hij_temp { ZERO }, hij_predict { ZERO }; + metric.template transform(x_Code, { h11, h22, h33 }, hij_temp); + metric.template transform(x_Code, hij_temp, hij_predict); + + + vec_t h_ij_temp { ZERO }, h_ij_predict { ZERO }; + metric.template transform(x_Code, + { h_11, h_22, h_33 }, + h_ij_temp); + metric.template transform(x_Code, h_ij_temp, h_ij_predict); + + + vec_t hij_expect { h11_expect, h22_expect, h33_expect }; + vec_t h_ij_expect { h_11_expect, h_22_expect, h_33_expect }; + + wrongs += not equal(hij_expect, hij_predict, "hij", acc); + wrongs += not equal(f0_expect, f0_predict, "f0", acc); + wrongs += not equal(f1_expect, f1_predict, "f1", acc); + wrongs += not equal(f2_expect, f2_predict, "f2", acc); + + }, + all_wrongs); + + errorIf(all_wrongs != 0, + "wrong h_ij/hij for " + std::to_string(M::Dim) + "D " + + std::string(metric.Label) + " with " + std::to_string(all_wrongs) + + " errors"); +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + using namespace metric; + testMetric>( + { 128 }, + { { 2.0, 50.0 } }, + 10, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} diff --git a/src/metrics/tests/vec_trans.cpp b/src/metrics/tests/vec_trans.cpp index a249c1d41..659244462 100644 --- a/src/metrics/tests/vec_trans.cpp +++ b/src/metrics/tests/vec_trans.cpp @@ -236,6 +236,16 @@ auto main(int argc, char* argv[]) -> int { }; testMetric>(resks0, extks0, 10); + testMetric>( + { 128 }, + { { 2.0, 50.0 } }, + 10, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + } catch (std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); From 6c37cb64c8695a1e1ef7bc614a8ab37863ed8cf1 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 2 Jul 2024 10:41:58 +0800 Subject: [PATCH 04/47] generate tests for flux_surface --- src/metrics/tests/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/metrics/tests/CMakeLists.txt b/src/metrics/tests/CMakeLists.txt index 117cb3295..fe917de0b 100644 --- a/src/metrics/tests/CMakeLists.txt +++ b/src/metrics/tests/CMakeLists.txt @@ -25,4 +25,5 @@ gen_test(vec_trans) gen_test(coord_trans) gen_test(sph-qsph) gen_test(ks-qks) -gen_test(sr-cart-sph) \ No newline at end of file +gen_test(sr-cart-sph) +gen_test(fs) \ No newline at end of file From bc6b981f3279d4546d6483272a8ccc43279dbd8f Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 2 Jul 2024 14:40:59 -0400 Subject: [PATCH 05/47] fluxsurf headers in tests --- src/metrics/tests/coord_trans.cpp | 17 ++++++++++------- src/metrics/tests/vec_trans.cpp | 15 +++++++++------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index af0277740..5cbe9dea1 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -3,6 +3,7 @@ #include "arch/kokkos_aliases.h" #include "utils/comparators.h" +#include "metrics/flux_surface.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" #include "metrics/minkowski.h" @@ -183,14 +184,16 @@ auto main(int argc, char* argv[]) -> int { testMetric>(resks0, extks0, 150); testMetric>( - { 128 }, + { + 128 + }, { { 2.0, 50.0 } }, 10, - { { "a", (real_t)0.95 } , - { "psi0", (real_t)1.0 } , - { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } , - { "pCur", (real_t)3.1 } }); + { { "a", (real_t)0.95 }, + { "psi0", (real_t)1.0 }, + { "theta0", (real_t)1.0 }, + { "Omega", (real_t)0.5 }, + { "pCur", (real_t)3.1 } }); } catch (std::exception& e) { std::cerr << e.what() << std::endl; @@ -199,4 +202,4 @@ auto main(int argc, char* argv[]) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} diff --git a/src/metrics/tests/vec_trans.cpp b/src/metrics/tests/vec_trans.cpp index 659244462..6442f24d0 100644 --- a/src/metrics/tests/vec_trans.cpp +++ b/src/metrics/tests/vec_trans.cpp @@ -3,6 +3,7 @@ #include "arch/kokkos_aliases.h" #include "utils/comparators.h" +#include "metrics/flux_surface.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" #include "metrics/minkowski.h" @@ -237,14 +238,16 @@ auto main(int argc, char* argv[]) -> int { testMetric>(resks0, extks0, 10); testMetric>( - { 128 }, + { + 128 + }, { { 2.0, 50.0 } }, 10, - { { "a", (real_t)0.95 } , - { "psi0", (real_t)1.0 } , - { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } , - { "pCur", (real_t)3.1 } }); + { { "a", (real_t)0.95 }, + { "psi0", (real_t)1.0 }, + { "theta0", (real_t)1.0 }, + { "Omega", (real_t)0.5 }, + { "pCur", (real_t)3.1 } }); } catch (std::exception& e) { std::cerr << e.what() << std::endl; From de6c8b5fd0d1ddb970c2782242585f37619c9ffe Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Wed, 3 Jul 2024 13:30:22 +0800 Subject: [PATCH 06/47] lower accurracy for fs test --- src/metrics/flux_surface.h | 2 +- src/metrics/tests/fs.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h index 719cdd36d..e1e8c1633 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/flux_surface.h @@ -52,7 +52,7 @@ namespace metric { } Inline auto omega(const real_t& r, const real_t& theta) const -> real_t { - return 2 * a * r / A(r, theta); + return TWO * a * r / A(r, theta); } Inline auto psi(const real_t& r, const real_t& theta) const -> real_t { diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/fs.cpp index 16d60fcd9..4300a8a0b 100644 --- a/src/metrics/tests/fs.cpp +++ b/src/metrics/tests/fs.cpp @@ -112,7 +112,7 @@ void testMetric(const std::vector& res, const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th)) * Delta; const auto dpsi_r = 0; const auto dpsi_dtheta = psi0 * math::sin(th); - const auto omega = 2 * a * r / A ; + const auto omega = TWO * a * r / A ; const auto h_11_expect = Sigma / Delta; const auto h_22_expect = Sigma ; @@ -168,7 +168,7 @@ auto main(int argc, char* argv[]) -> int { testMetric>( { 128 }, { { 2.0, 50.0 } }, - 10, + 30, { { "a", (real_t)0.95 } , { "psi0", (real_t)1.0 } , { "theta0", (real_t)1.0 } , From 907c4be5dbc774890d6b4e4ed84d83a65498ddfa Mon Sep 17 00:00:00 2001 From: StaticObserver <151660448+StaticObserver@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:34:08 +0800 Subject: [PATCH 07/47] Update flux_surface.h --- src/metrics/flux_surface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h index 719cdd36d..e1e8c1633 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/flux_surface.h @@ -52,7 +52,7 @@ namespace metric { } Inline auto omega(const real_t& r, const real_t& theta) const -> real_t { - return 2 * a * r / A(r, theta); + return TWO * a * r / A(r, theta); } Inline auto psi(const real_t& r, const real_t& theta) const -> real_t { From fb297cf4bf3abbe5bcc655ab11cfbac4fdde20d9 Mon Sep 17 00:00:00 2001 From: StaticObserver <151660448+StaticObserver@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:34:40 +0800 Subject: [PATCH 08/47] Update fs.cpp --- src/metrics/tests/fs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/fs.cpp index 16d60fcd9..4300a8a0b 100644 --- a/src/metrics/tests/fs.cpp +++ b/src/metrics/tests/fs.cpp @@ -112,7 +112,7 @@ void testMetric(const std::vector& res, const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th)) * Delta; const auto dpsi_r = 0; const auto dpsi_dtheta = psi0 * math::sin(th); - const auto omega = 2 * a * r / A ; + const auto omega = TWO * a * r / A ; const auto h_11_expect = Sigma / Delta; const auto h_22_expect = Sigma ; @@ -168,7 +168,7 @@ auto main(int argc, char* argv[]) -> int { testMetric>( { 128 }, { { 2.0, 50.0 } }, - 10, + 30, { { "a", (real_t)0.95 } , { "psi0", (real_t)1.0 } , { "theta0", (real_t)1.0 } , From 24c69088a84bd7974b7c9751deb8ae337e51bccc Mon Sep 17 00:00:00 2001 From: StaticObserver <151660448+StaticObserver@users.noreply.github.com> Date: Thu, 4 Jul 2024 15:54:18 +0800 Subject: [PATCH 09/47] Update flux_surface.h --- src/metrics/flux_surface.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h index e1e8c1633..a8f240937 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/flux_surface.h @@ -76,8 +76,9 @@ namespace metric { } Inline auto eta2r(const real_t& eta) const -> real_t{ - real_t exp = math::exp(eta * (rh_ - rh_m)); - return (rh_ - rh_m * exp) / (1 - exp); + real_t diff = TWO * math::sqrt(ONE - SQR(a)); + real_t exp_m1 = std::expm1(eta * diff); + return rh_m - diff / exp_m1; } From b7acda0ff2740c807793d8e4bdccb7e95384314d Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 5 Jul 2024 01:43:21 +0000 Subject: [PATCH 10/47] minor tweaks in flux_surf metric --- src/metrics/flux_surface.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h index a8f240937..827d62d5c 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/flux_surface.h @@ -76,9 +76,7 @@ namespace metric { } Inline auto eta2r(const real_t& eta) const -> real_t{ - real_t diff = TWO * math::sqrt(ONE - SQR(a)); - real_t exp_m1 = std::expm1(eta * diff); - return rh_m - diff / exp_m1; + return rh_m - TWO * math::sqrt(ONE - SQR(a)) / math::expm1(eta * TWO * math::sqrt(ONE - SQR(a))); } @@ -109,7 +107,7 @@ namespace metric { , eta_min { r2eta(x1_min) } , eta_max { r2eta(x1_max) } , d_eta { (eta_max - eta_min) / nx1 } - , d_eta_inv { 1 / d_eta }{ + , d_eta_inv { ONE / d_eta }{ set_dxMin(find_dxMin()); } From 68685996ac5f21b14f5b6dc9634450d431f304de Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 5 Jul 2024 01:45:04 +0000 Subject: [PATCH 11/47] reduced acc for fs test --- src/metrics/tests/coord_trans.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 5cbe9dea1..10fab89ae 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -188,7 +188,7 @@ auto main(int argc, char* argv[]) -> int { 128 }, { { 2.0, 50.0 } }, - 10, + 100, { { "a", (real_t)0.95 }, { "psi0", (real_t)1.0 }, { "theta0", (real_t)1.0 }, From 608147d3a1d5dc73d18bce27927c978cf20ba4e9 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 5 Jul 2024 02:12:39 +0000 Subject: [PATCH 12/47] slight fix in tests --- src/global/tests/enums.cpp | 3 ++- src/metrics/tests/coord_trans.cpp | 23 ++++++++++++----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 81e63d57a..65398bfe6 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -57,7 +57,8 @@ auto main() -> int { enum_str_t all_coords = { "cart", "sph", "qsph" }; enum_str_t all_metrics = { "minkowski", "spherical", "qspherical", - "kerr_schild", "qkerr_schild", "kerr_schild_0" }; + "kerr_schild", "qkerr_schild", "kerr_schild_0", + "flux_surface" }; enum_str_t all_simulation_engines = { "srpic", "grpic" }; enum_str_t all_particle_bcs = { "periodic", "absorb", "atmosphere", "custom", "reflect", "horizon", "axis", "sync" }; diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 10fab89ae..66e25fb77 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -183,17 +183,18 @@ auto main(int argc, char* argv[]) -> int { }; testMetric>(resks0, extks0, 150); - testMetric>( - { - 128 - }, - { { 2.0, 50.0 } }, - 100, - { { "a", (real_t)0.95 }, - { "psi0", (real_t)1.0 }, - { "theta0", (real_t)1.0 }, - { "Omega", (real_t)0.5 }, - { "pCur", (real_t)3.1 } }); + const auto resfs = std::vector { 128 }; + const auto extfs = boundaries_t { + {2.0, 50.0} + }; + const auto paramsfs = std::map { + { "a", (real_t)0.95}, + { "psi0", (real_t)1.0}, + {"theta0", (real_t)1.0}, + { "Omega", (real_t)0.5}, + { "pCur", (real_t)3.1} + }; + testMetric>(resfs, extfs, 500, paramsfs); } catch (std::exception& e) { std::cerr << e.what() << std::endl; From 642311939fb1df1b796c33ffb1b46db82bb8ef08 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 5 Jul 2024 02:26:22 +0000 Subject: [PATCH 13/47] enums test upd --- src/global/tests/enums.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 65398bfe6..da4ed9d0a 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -55,7 +55,7 @@ auto main() -> int { using enum_str_t = const std::vector; - enum_str_t all_coords = { "cart", "sph", "qsph" }; + enum_str_t all_coords = { "cart", "sph", "qsph", "fs" }; enum_str_t all_metrics = { "minkowski", "spherical", "qspherical", "kerr_schild", "qkerr_schild", "kerr_schild_0", "flux_surface" }; From 7800969a7f691ea508da55ae99f7f567dff657a6 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Mon, 8 Jul 2024 13:50:57 +0800 Subject: [PATCH 14/47] added 1DGRPIC particle pusher and tests --- src/kernels/particle_pusher_1D_gr.hpp | 376 ++++++++++++++++++++++++++ src/kernels/tests/ff_pusher.cpp | 239 ++++++++++++++++ src/metrics/flux_surface.h | 22 ++ 3 files changed, 637 insertions(+) create mode 100644 src/kernels/particle_pusher_1D_gr.hpp create mode 100644 src/kernels/tests/ff_pusher.cpp diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp new file mode 100644 index 000000000..e0356b899 --- /dev/null +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -0,0 +1,376 @@ +/** + * @file kernels/particle_pusher_1D_gr.h + * @brief Implementation of the particle pusher for 1D GR + * @implements + * - kernel::gr::Pusher_kernel_1D<> + * @namespaces: + * - kernel::gr:: + * @macros: + * - MPI_ENABLED +*/ + +#ifndef KERNELS_PARTICLE_PUSHER_1D_GR_HPP +#define KERNELS_PARTICLE_PUSHER_1D_GR_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_tags.h" +#endif + +/* -------------------------------------------------------------------------- */ +/* Local macros */ +/* -------------------------------------------------------------------------- */ +#define from_Xi_to_i(XI, I) \ + { I = static_cast((XI)); } + +#define from_Xi_to_i_di(XI, I, DI) \ + { \ + from_Xi_to_i((XI), (I)); \ + DI = static_cast((XI)) - static_cast(I); \ + } + +#define i_di_to_Xi(I, DI) static_cast((I)) + static_cast((DI)) + +#define DERIVATIVE(func, x) \ + ((func({ x + epsilon }) - func({ x - epsilon })) / \ + (TWO * epsilon)) + + +/* -------------------------------------------------------------------------- */ + +namespace kernel::gr { + using namespace ntt; + + struct Massive_t {}; + + struct Massless_t {}; + + /** + * @brief Algorithm for the Particle pusher + * @tparam M Metric + */ + template + class Pusher_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + static_assert(D == Dim::1D, "Only 1d available for this pusher"); + + const ndfield_t D; + array_t i1; + array_t i1_prev; + array_t dx1; + array_t dx1_prev; + array_t ux1, ux2, ux3; + array_t tag; + const M metric; + + const real_t coeff, dt; + const int ni1; + const real_t epsilon; + const int niter; + const int i1_absorb; + + bool is_absorb_i1min { false }, is_absorb_i1max { false }; + + public: + Pusher_kernel(const ndfield_t& Dfield, + const array_t& i1, + const array_t& i1_prev, + const array_t& dx1, + const array_t& dx1_prev, + const array_t& ux1, + const array_t& ux2, + const array_t& ux3, + const array_t& tag, + const M& metric, + const real_t& coeff, + const real_t& dt, + const int& n1i, + const real_t& epsilon, + const int& niter, + const real_t& Omega_, + const boundaries_t& boundaries) + : Dfield { Dfield } + , i1 { i1 } + , i1_prev { i1_prev } + , dx1 { dx1 } + , dx1_prev { dx1_prev } + , ux1 { ux1 } + , ux2 { ux2 } + , ux3 { ux3 } + , metric { metric } + , coeff { coeff } + , dt { dt } + , n1i { n1i } + , epsilon { epsilon } + , niter { niter } + , Omega_ { metric.Omega() } + , i1_absorb { static_cast(metric.template convert<1, Crd::Ph, Crd::Cd>( + metric.rhorizon())) - + 5 } { + + raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); + is_absorb_i1min = (boundaries[0].first == PrtlBC::ABSORB) || + (boundaries[0].first == PrtlBC::HORIZON); + is_absorb_i1max = (boundaries[0].second == PrtlBC::ABSORB) || + (boundaries[0].second == PrtlBC::HORIZON); + } + + /** + * @brief Main pusher subroutine for photon particles. + */ + Inline void operator()(Massless_t, index_t) const; + + /** + * @brief Main pusher subroutine for massive particles. + */ + Inline void operator()(Massive_t, index_t) const; + + /** + * @brief Iterative geodesic pusher substep for momentum only. + * @param xp particle coordinate. + * @param vp particle velocity. + * @param vp_upd updated particle velocity [return]. + */ + Inline void Pusher_kernel::ForceFreePush( const coord_t& xp, + const real_t& vp, + real_t& vp_upd) const; + + /** + * @brief Iterative geodesic pusher substep for coordinate only. + * @param xp particle coordinate. + * @param vp particle velocity. + * @param xp_upd updated particle coordinate [return]. + */ + Inline void Pusher_kernel::CoordinatePush(const coord_t& xp, + const real_t& vp, + const real_t& xp_upd) const; + + + /** + * @brief EM pusher substep. + * @param xp coordinate of the particle. + * @param vp covariant velocity of the particle. + * @param e0 electric field at the particle position. + * @param v_upd updated covarient velocity of the particle [return]. + */ + Inline void Pusher_kernel::EfieldHalfPush(const coord_t& xp, + const real_t& vp, + const real_t& e0, + real_t& vp_upd) const; + // Helper functions + + /** + * @brief First order Yee mesh field interpolation to particle position. + * @param p index of the particle. + * @param e interpolated e-field + */ + Inline void interpolateFields(index_t& p, + real_t& e,) const { + const int i { i1(p) + static_cast(N_GHOSTS) }; + const auto dx1_ { static_cast(dx1(p)) }; + real_t c1 = HALF * (Dfield(i, em::dx1) + Dfield(i - 1, em::dx1)); + real_t c2 = HALF * (Dfield(i, em::dx1) + Dfield(i + 1, em::dx1)); + e = c1 * (ONE - dx1_) + c2 * dx1_; + } + + /** + * @brief Compute controvariant component u^0 for massive particles. + */ + + Inline auto compute_u0(const real_t& v, + const coord_t& xi){ + return ONE / math::sqrt(SQR(metric.alpha(xi)) - + metric.f2(xi) * SQR(v) - TWO * metric.f1(xi) * v - metric.f0(xi)); + } + + Inline auto compute_u0(const coord_t& u_cov, + const coord_t& u_ccov, + const coord_t& xi){ + return math::sqrt((u_cov[0] * u_ccov[0] + u_cov[1] * u_ccov[1] + u_cov[2] * u_ccov[2]) / + (SQR(metric.alpha(xi)) + SQR(metric.beta(xi)))); + } + + // Extra + Inline void boundaryConditions(index_t&) const{ + if (i1(p) < i1_absorb && is_absorb_i1min) { + tag(p) = ParticleTag::dead; + } else if (i1(p) >= ni1 && is_absorb_i1max) { + tag(p) = ParticleTag::dead; + } + +#if defined(MPI_ENABLED) + tag(p) = mpi::SendTag(tag(p), i1(p) < 0, i1(p) >= ni1); +#endif + } + + }; + + + + /* -------------------------------------------------------------------------- */ + /* 1D Pushers */ + /* -------------------------------------------------------------------------- */ + + /** + * massive particle electric field pusher + */ + template + Inline void Pusher_kernel::EfieldHalfPush(const coord_t& xp, + const real_t& vp, + const real_t& e0, + real_t& vp_upd) const { + real_t pp { ZERO }; + real_t pp_upd { ZERO }; + + real_t COEFF { HALF * coeff * metric.alpha(xp) }; + + //calculate canonical momentum + real_t u0 { compute_u0(vp, xp) }; + pp = u0 * (metric.f2(xp) * vp + metric.f1(xp)); + + //calculate updated canonical momentum + pp_upd = pp + COEFF * e0; + + //calculate updated velocity + vp_upd = (pp_upd / u0 - metric.f1(xp)) / metric.f2(xp); + } + /** + * massive particle momentum pusher under force-free constraint + */ + template + Inline void Pusher_kernel::ForceFreePush( const coord_t& xp, + const real_t& vp, + real_t& vp_upd) const { + real_t vp_mid { ZERO }; + //canonical momentum of particles + real_t pp { ZERO }; + real_t pp_upd { ZERO }; + + vp_upd = vp; + + real_t u0 { compute_u0(vp, xp) }; + //calculate canonical momentum + pp = u0 * (metric.f2(xp) * vp + metric.f1(xp)); + pp_upd = pp ; + + for (auto i { 0 }; i < niter; ++i) { + // find midpoint values + vp_mid = HALF * (vp + vp_upd); + + u0 = compute_u0(vp_mid, xp); + + // find updated canonical momentum + pp_upd = pp + + dt * u0 * + (- metric.alpha(xp) * DERIVATIVE(metric.alpha, xp) + + HALF * (DERIVATIVE(metric.f2, xp) * SQR(vp_mid) + + TWO * DERIVATIVE(metric.f1, xp) * vp_mid + + DERIVATIVE(metric.f0, xp))); + + // find updated velocity + vp_upd = (pp_upd / u0 - metric.f1(xp)) / metric.f2(xp); + } + } + + /** + * coordinate pusher + */ + template + Inline void Pusher_kernel::CoordinatePush(const coord_t& xp, + const real_t& vp, + const coord_t& xp_upd) const { + xp_upd[0] = dt * vp + xp[0]; + } + + /* ------------------------- Massive particle pusher ------------------------ */ +template + Inline void Pusher_kernel::operator()(Massive_t, index_t p) const { + if (tag(p) != ParticleTag::alive) { + if (tag(p) != ParticleTag::dead) { + raise::KernelError(HERE, "Invalid particle tag in pusher"); + } + return; + } + // record previous coordinate + i1_prev(p) = i1(p); + dx1_prev(p) = dx1(p); + + coord_t xp { ZERO }; + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + + real_t Dp_contrv { ZERO }; + interpolateFields(p, Dp_contrv); + + real_t ep_controv { metric.alpha(xp) * metric.template transform<1, Idx::U, Idx::D>(xp, Dp_cntrv) }; + + vec_t up_cov { ZERO }; + vec_t up_ccov { ZERO }; + + up_cov[0] = ux1(p); + up_cov[1] = ux2(p); + up_cov[2] = ux3(p); + + metric.template transform(xp, up_cov, up_ccov); + + real_t vp { up_cov[0] / compute_u0(up_cov, up_ccov, xp) }; + + + /* -------------------------------- Leapfrog -------------------------------- */ + /* u_i(n - 1/2) -> u*_i(n) */ + real_t vp_upd { ZERO }; + EfieldHalfPush(xp, vp, ep_controv, vp_upd); + + /* u*_i(n) -> u**_i(n) */ + vp = vp_upd; + ForceFreePush(xp, vp, vp_upd); + /* u**_i(n) -> u_i(n + 1/2) */ + vp = vp_upd; + EfieldHalfPush(xp, vp, ep_controv, vp_upd); + + /* x^i(n) -> x^i(n + 1) */ + real_t xp_upd { ZERO }; + CoordinatePush(xp, vp_upd, xp_upd); + + /* update coordinate */ + int i1_; + prtldx_t dx1_; + from_Xi_to_i_di(xp_upd, i1_, dx1_); + i1(p) = i1_; + dx1(p) = dx1_; + + /* update velocity */ + real_t u0 { compute_u0(vp_upd, xp) }; + ux1(p) = vp_upd * u0; + ux3(p) = u0 * (metric.template h<3,3>(xp) * Omega_ + + metric.f1(xp) * vp_upd / (Omega_ + metric.beta3(xp))); + + + boundaryConditions(p); + } + + + + + + +} // namespace kernel::gr + + + + + +#undef DERIVATIVE + +#undef i_di_to_Xi +#undef from_Xi_to_i_di +#undef from_Xi_to_i + +#endif // KERNELS_PARTICLE_PUSHER_GR_1D_HPP + diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp new file mode 100644 index 000000000..781f47e5a --- /dev/null +++ b/src/kernels/tests/ff_pusher.cpp @@ -0,0 +1,239 @@ +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +#include "metrics/flux_surface.h" + +#include "kernels/particle_pusher_1D_gr.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace ntt; +using namespace metric; + +#define i_di_to_Xi(I, DI) static_cast((I)) + static_cast((DI)) + +#define DERIVATIVE(func, x) \ + ((func({ x + epsilon }) - func({ x - epsilon })) / \ + (TWO * epsilon)) + +inline static constexpr auto eps = std::numeric_limits::epsilon(); + +void errorIf(bool condition, const std::string& message) { + if (condition) { + throw std::runtime_error(message); + } +} + +template +void put_value(array_t& arr, T v, index_t p) { + auto h = Kokkos::create_mirror_view(arr); + Kokkos::deep_copy(h, arr); + h(p) = v; + Kokkos::deep_copy(arr, h); +} + +template +void testFFPusher(const std::vector& res, + const boundaries_t& ext, + const real_t acc, + const std::map& params = {}) { + static_assert(M::Dim == 1, "Only 1D is supported"); + errorIf(res.size() != M::Dim, "res.size() != M::Dim"); + + boundaries_t extent; + extent = ext; + + M metric { res, extent, params }; + + const int nx1 = res[0]; + + auto coeff = real_t { 1.0 }; + auto dt = real_t { 0.01 }; + + const auto range_ext = CreateRangePolicy( + { 0}, + { res[0] + 2 * N_GHOSTS }); + + auto efield = ndfield_t { "efield", + res[0] + 2 * N_GHOSTS}; + + Kokkos::parallel_for( + "init efield", + range_ext, + Lambda(index_t i1) { + emfield(i1, em::ex1) = 1.92; + }); + + + array_t i1 { "i1", 2 }; + array_t i1_prev { "i1_prev", 2 }; + array_t dx1 { "dx1", 2 }; + array_t dx1_prev { "dx1_prev", 2 }; + array_t ux1 { "ux1", 2 }; + array_t ux2 { "ux2", 2 }; + array_t ux3 { "ux3", 2 }; + array_t tag { "tag", 2 }; + + put_value(i1, 5, 0); + put_value(dx1, (prtldx_t)(0.15), 0); + put_value(ux1, ZERO, 0); + put_value(ux3, metric.Omega_(), 0); + put_value(tag, ParticleTag::alive, 0); + + put_value(i1, 5, 1); + put_value(dx1, (prtldx_t)(0.15), 1); + put_value(ux1, ZERO, 1); + put_value(ux3, metric.Omega_(), 1); + put_value(tag, ParticleTag::alive, 1); + + + // Particle boundaries + auto boundaries = boundaries_t {}; + boundaries = { + {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + }; + + + + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({ 0 }, { 1 }), + kernel::gr::Pusher_kernel>( + efield, + i1, + i1_prev, + dx1, + dx1_prev, + ux1, ux2, ux3, + tag, + metric, + coeff, dt, + nx1, + eps * 1e3, + 20, + boundaries)); + + + Kokkos::parallel_for( + "pusher", + 1, + kernel::gr::Pusher_kernel>( + efield, + i1, + i1_prev, + dx1, + dx1_prev, + ux1, ux2, ux3, + tag, + metric, + -coeff, dt, + nx1, + eps * 1e3, + 20, + boundaries)); + + auto epsilon = eps * 1e3; + + auto i1_ = Kokkos::create_mirror_view(i1); + Kokkos::deep_copy(i1_, i1); + auto i1_ prev_ = Kokkos::create_mirror_view(i1_prev); + Kokkos::deep_copy(i1_prev_, i1_prev); + auto dx1_ = Kokkos::create_mirror_view(dx1); + Kokkos::deep_copy(dx1_, dx1); + auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); + Kokkos::deep_copy(dx1_prev_, dx1_prev); + auto ux1_ = Kokkos::create_mirror_view(ux1); + Kokkos::deep_copy(ux1_, ux1); + auto ux2_ = Kokkos::create_mirror_view(ux2); + Kokkos::deep_copy(ux2_, ux2); + auto ux3_ = Kokkos::create_mirror_view(ux3); + Kokkos::deep_copy(ux3_, ux3); + + +//negative charge + coord_t xp { i_di_to_Xi(i1_(0), dx1_(0)) }; + coord_t xp_prev { i_di_to_Xi(i1_prev_(0), dx1_prev(0)) }; + coord_t u_d {ux1_(0), ux2_(0), ux3_(0)}; + coord_t u_u { ZERO }; + metric.template transform(xp, u_d, u_u); + + real_t u0 { math::sqrt((u_d[0] * u_u[0] + u_d[1] * u_u[1] + u_d[2] * u_u[2]) / + (SQR(metric.alpha(xp)) + SQR(metric.beta(xp)))) }; + real_t vp { u_p[0] / u0 }; + + real_t diff { u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - + dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) - + u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp) + + HALF * u0 * (DERIVATIVE(metric.f2, xp) * SQR(vp) + + TWO * DERIVATIVE(metric.f1, xp) * vp + + DERIVATIVE(metric.f0, xp))) }; + + if (not cmp::AlmostEqual(diff, ZERO, eps * acc)) { + printf("%.12e %s\n", diff, "Pusher test failed at negative charge."); + return false; + } + +//positive charge + coord_t xp { i_di_to_Xi(i1_(1), dx1_(1)) }; + coord_t xp_prev { i_di_to_Xi(i1_prev_(1), dx1_prev(1)) }; + coord_t u_d {ux1_(1), ux2_(1), ux3_(1)}; + coord_t u_u { ZERO }; + metric.template transform(xp, u_d, u_u); + + real_t u0 = math::sqrt((u_d[0] * u_u[0] + u_d[1] * u_u[1] + u_d[2] * u_u[2]) / + (SQR(metric.alpha(xp)) + SQR(metric.beta(xp)))) ; + real_t vp = u_p[0] / u0 ; + + real_t diff = u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - + dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) - + u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp) + + HALF * u0 * (DERIVATIVE(metric.f2, xp) * SQR(vp) + + TWO * DERIVATIVE(metric.f1, xp) * vp + + DERIVATIVE(metric.f0, xp))) ; + + if (not cmp::AlmostEqual(diff, ZERO, eps * acc)) { + printf("%.12e %s\n", diff, "Pusher test failed at positive charge."); + return false; + } + + + +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + testFFPusher>( + { 128 }, + { { 2.0, 50.0 } }, + 100, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} + +#undef DERIVATIVE +#undef i_di_to_Xi \ No newline at end of file diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h index e1e8c1633..e63e89bf6 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/flux_surface.h @@ -133,6 +133,11 @@ namespace metric { Inline auto rg() const -> real_t { return rg_; } + + [[nodiscard]] + Inline auto OmegaF() const -> real_t { + return Omega; + } /** @@ -145,6 +150,23 @@ namespace metric { return math::sqrt(Sigma(r_, theta_) * Delta(r_) / A(r_, theta_)); } + /** + * shift vector, only third covariant component is non-zero + * @param x coordinate array in code units + */ + + Inline auto beta(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return math::sqrt(h<3, 3>(xi)) * omega(r_, theta_); + } + + Inline auto bet3(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return -omega(r_, theta_); + } + /** * @brief Compute helper functions f0,f1,f2 in 1D-GRPIC */ From d61fb77d49c93e1d787d12f903f3e0808728a77c Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 9 Jul 2024 10:41:40 +0800 Subject: [PATCH 15/47] fix bugs in 1d grpic --- src/kernels/particle_pusher_1D_gr.hpp | 74 +++++++++++++-------------- src/kernels/tests/CMakeLists.txt | 1 + src/kernels/tests/ff_pusher.cpp | 54 +++++++++---------- src/metrics/flux_surface.h | 2 +- 4 files changed, 65 insertions(+), 66 deletions(-) diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index e0356b899..d85e119cc 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -59,9 +59,9 @@ namespace kernel::gr { class Pusher_kernel { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; - static_assert(D == Dim::1D, "Only 1d available for this pusher"); + static_assert(D == Dim::_1D, "Only 1d available for this pusher"); - const ndfield_t D; + const ndfield_t Dfield; array_t i1; array_t i1_prev; array_t dx1; @@ -91,11 +91,10 @@ namespace kernel::gr { const M& metric, const real_t& coeff, const real_t& dt, - const int& n1i, + const int& ni1, const real_t& epsilon, const int& niter, - const real_t& Omega_, - const boundaries_t& boundaries) + const boundaries_t& boundaries) : Dfield { Dfield } , i1 { i1 } , i1_prev { i1_prev } @@ -107,15 +106,12 @@ namespace kernel::gr { , metric { metric } , coeff { coeff } , dt { dt } - , n1i { n1i } + , ni1 { ni1 } , epsilon { epsilon } , niter { niter } - , Omega_ { metric.Omega() } - , i1_absorb { static_cast(metric.template convert<1, Crd::Ph, Crd::Cd>( - metric.rhorizon())) - - 5 } { + , i1_absorb { 2 } { - raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); + raise::ErrorIf(boundaries.size() < 1, "boundaries defined incorrectly", HERE); is_absorb_i1min = (boundaries[0].first == PrtlBC::ABSORB) || (boundaries[0].first == PrtlBC::HORIZON); is_absorb_i1max = (boundaries[0].second == PrtlBC::ABSORB) || @@ -125,12 +121,12 @@ namespace kernel::gr { /** * @brief Main pusher subroutine for photon particles. */ - Inline void operator()(Massless_t, index_t) const; + //Inline void operator()(Massless_t, index_t) const; /** * @brief Main pusher subroutine for massive particles. */ - Inline void operator()(Massive_t, index_t) const; + Inline void operator()(index_t) const; /** * @brief Iterative geodesic pusher substep for momentum only. @@ -138,7 +134,7 @@ namespace kernel::gr { * @param vp particle velocity. * @param vp_upd updated particle velocity [return]. */ - Inline void Pusher_kernel::ForceFreePush( const coord_t& xp, + Inline void ForceFreePush( const coord_t& xp, const real_t& vp, real_t& vp_upd) const; @@ -148,9 +144,9 @@ namespace kernel::gr { * @param vp particle velocity. * @param xp_upd updated particle coordinate [return]. */ - Inline void Pusher_kernel::CoordinatePush(const coord_t& xp, + Inline void CoordinatePush(const coord_t& xp, const real_t& vp, - const real_t& xp_upd) const; + coord_t& xp_upd) const; /** @@ -160,7 +156,7 @@ namespace kernel::gr { * @param e0 electric field at the particle position. * @param v_upd updated covarient velocity of the particle [return]. */ - Inline void Pusher_kernel::EfieldHalfPush(const coord_t& xp, + Inline void EfieldHalfPush(const coord_t& xp, const real_t& vp, const real_t& e0, real_t& vp_upd) const; @@ -172,7 +168,7 @@ namespace kernel::gr { * @param e interpolated e-field */ Inline void interpolateFields(index_t& p, - real_t& e,) const { + real_t& e) const { const int i { i1(p) + static_cast(N_GHOSTS) }; const auto dx1_ { static_cast(dx1(p)) }; real_t c1 = HALF * (Dfield(i, em::dx1) + Dfield(i - 1, em::dx1)); @@ -184,21 +180,21 @@ namespace kernel::gr { * @brief Compute controvariant component u^0 for massive particles. */ - Inline auto compute_u0(const real_t& v, - const coord_t& xi){ + Inline auto compute_u0_v(const real_t& v, + const coord_t& xi) const { return ONE / math::sqrt(SQR(metric.alpha(xi)) - metric.f2(xi) * SQR(v) - TWO * metric.f1(xi) * v - metric.f0(xi)); } - Inline auto compute_u0(const coord_t& u_cov, + Inline auto compute_u0_u(const coord_t& u_cov, const coord_t& u_ccov, - const coord_t& xi){ + const coord_t& xi) const { return math::sqrt((u_cov[0] * u_ccov[0] + u_cov[1] * u_ccov[1] + u_cov[2] * u_ccov[2]) / (SQR(metric.alpha(xi)) + SQR(metric.beta(xi)))); } // Extra - Inline void boundaryConditions(index_t&) const{ + Inline void boundaryConditions(index_t& p) const{ if (i1(p) < i1_absorb && is_absorb_i1min) { tag(p) = ParticleTag::dead; } else if (i1(p) >= ni1 && is_absorb_i1max) { @@ -232,7 +228,7 @@ namespace kernel::gr { real_t COEFF { HALF * coeff * metric.alpha(xp) }; //calculate canonical momentum - real_t u0 { compute_u0(vp, xp) }; + real_t u0 { compute_u0_v(vp, xp) }; pp = u0 * (metric.f2(xp) * vp + metric.f1(xp)); //calculate updated canonical momentum @@ -255,7 +251,7 @@ namespace kernel::gr { vp_upd = vp; - real_t u0 { compute_u0(vp, xp) }; + real_t u0 { compute_u0_v(vp, xp) }; //calculate canonical momentum pp = u0 * (metric.f2(xp) * vp + metric.f1(xp)); pp_upd = pp ; @@ -264,15 +260,15 @@ namespace kernel::gr { // find midpoint values vp_mid = HALF * (vp + vp_upd); - u0 = compute_u0(vp_mid, xp); + u0 = compute_u0_v(vp_mid, xp); // find updated canonical momentum pp_upd = pp + dt * u0 * - (- metric.alpha(xp) * DERIVATIVE(metric.alpha, xp) + - HALF * (DERIVATIVE(metric.f2, xp) * SQR(vp_mid) + - TWO * DERIVATIVE(metric.f1, xp) * vp_mid + - DERIVATIVE(metric.f0, xp))); + (- metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + + HALF * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp_mid) + + TWO * DERIVATIVE(metric.f1, xp[0]) * vp_mid + + DERIVATIVE(metric.f0, xp[0]))); // find updated velocity vp_upd = (pp_upd / u0 - metric.f1(xp)) / metric.f2(xp); @@ -285,13 +281,13 @@ namespace kernel::gr { template Inline void Pusher_kernel::CoordinatePush(const coord_t& xp, const real_t& vp, - const coord_t& xp_upd) const { + coord_t& xp_upd) const { xp_upd[0] = dt * vp + xp[0]; } /* ------------------------- Massive particle pusher ------------------------ */ template - Inline void Pusher_kernel::operator()(Massive_t, index_t p) const { + Inline void Pusher_kernel::operator()(index_t p) const { if (tag(p) != ParticleTag::alive) { if (tag(p) != ParticleTag::dead) { raise::KernelError(HERE, "Invalid particle tag in pusher"); @@ -308,7 +304,7 @@ template real_t Dp_contrv { ZERO }; interpolateFields(p, Dp_contrv); - real_t ep_controv { metric.alpha(xp) * metric.template transform<1, Idx::U, Idx::D>(xp, Dp_cntrv) }; + real_t ep_controv { metric.alpha(xp) * metric.template transform<1, Idx::U, Idx::D>(xp, Dp_contrv) }; vec_t up_cov { ZERO }; vec_t up_ccov { ZERO }; @@ -319,7 +315,7 @@ template metric.template transform(xp, up_cov, up_ccov); - real_t vp { up_cov[0] / compute_u0(up_cov, up_ccov, xp) }; + real_t vp { up_cov[0] / compute_u0_u(up_cov, up_ccov, xp) }; /* -------------------------------- Leapfrog -------------------------------- */ @@ -335,21 +331,21 @@ template EfieldHalfPush(xp, vp, ep_controv, vp_upd); /* x^i(n) -> x^i(n + 1) */ - real_t xp_upd { ZERO }; + coord_t xp_upd { ZERO }; CoordinatePush(xp, vp_upd, xp_upd); /* update coordinate */ int i1_; prtldx_t dx1_; - from_Xi_to_i_di(xp_upd, i1_, dx1_); + from_Xi_to_i_di(xp_upd[0], i1_, dx1_); i1(p) = i1_; dx1(p) = dx1_; /* update velocity */ - real_t u0 { compute_u0(vp_upd, xp) }; + real_t u0 { compute_u0_v(vp_upd, xp) }; ux1(p) = vp_upd * u0; - ux3(p) = u0 * (metric.template h<3,3>(xp) * Omega_ - + metric.f1(xp) * vp_upd / (Omega_ + metric.beta3(xp))); + ux3(p) = u0 * (metric.template h<3,3>(xp) * metric.OmegaF() + + metric.f1(xp) * vp_upd / (metric.OmegaF()+ metric.beta3(xp))); boundaryConditions(p); diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index e55dbc111..9556a2536 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -29,3 +29,4 @@ gen_test(fields_to_phys) gen_test(prtls_to_phys) gen_test(gca_pusher) gen_test(prtl_bc) +gen_test(ff_pusher) diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 781f47e5a..7026f322a 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -3,6 +3,7 @@ #include "arch/kokkos_aliases.h" #include "utils/numeric.h" +#include "utils/comparators.h" #include "metrics/flux_surface.h" @@ -54,6 +55,8 @@ void testFFPusher(const std::vector& res, extent = ext; M metric { res, extent, params }; + + const auto D = M::Dim; const int nx1 = res[0]; @@ -71,7 +74,7 @@ void testFFPusher(const std::vector& res, "init efield", range_ext, Lambda(index_t i1) { - emfield(i1, em::ex1) = 1.92; + efield(i1, em::ex1) = 1.92; }); @@ -87,13 +90,13 @@ void testFFPusher(const std::vector& res, put_value(i1, 5, 0); put_value(dx1, (prtldx_t)(0.15), 0); put_value(ux1, ZERO, 0); - put_value(ux3, metric.Omega_(), 0); + put_value(ux3, metric.OmegaF(), 0); put_value(tag, ParticleTag::alive, 0); put_value(i1, 5, 1); put_value(dx1, (prtldx_t)(0.15), 1); put_value(ux1, ZERO, 1); - put_value(ux3, metric.Omega_(), 1); + put_value(ux3, metric.OmegaF(), 1); put_value(tag, ParticleTag::alive, 1); @@ -146,7 +149,7 @@ void testFFPusher(const std::vector& res, auto i1_ = Kokkos::create_mirror_view(i1); Kokkos::deep_copy(i1_, i1); - auto i1_ prev_ = Kokkos::create_mirror_view(i1_prev); + auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); Kokkos::deep_copy(i1_prev_, i1_prev); auto dx1_ = Kokkos::create_mirror_view(dx1); Kokkos::deep_copy(dx1_, dx1); @@ -169,41 +172,40 @@ void testFFPusher(const std::vector& res, real_t u0 { math::sqrt((u_d[0] * u_u[0] + u_d[1] * u_u[1] + u_d[2] * u_u[2]) / (SQR(metric.alpha(xp)) + SQR(metric.beta(xp)))) }; - real_t vp { u_p[0] / u0 }; + real_t vp { u_u[0] / u0 }; real_t diff { u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - - dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) - - u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp) + - HALF * u0 * (DERIVATIVE(metric.f2, xp) * SQR(vp) + - TWO * DERIVATIVE(metric.f1, xp) * vp + - DERIVATIVE(metric.f0, xp))) }; + dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield(i1_(1), em::ex1) - + u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + + HALF * u0 * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp) + + TWO * DERIVATIVE(metric.f1, xp[0]) * vp + + DERIVATIVE(metric.f0, xp[0]))) }; if (not cmp::AlmostEqual(diff, ZERO, eps * acc)) { printf("%.12e %s\n", diff, "Pusher test failed at negative charge."); - return false; } //positive charge - coord_t xp { i_di_to_Xi(i1_(1), dx1_(1)) }; - coord_t xp_prev { i_di_to_Xi(i1_prev_(1), dx1_prev(1)) }; - coord_t u_d {ux1_(1), ux2_(1), ux3_(1)}; - coord_t u_u { ZERO }; + xp[0] = i_di_to_Xi(i1_(1), dx1_(1)); + xp_prev[0] = i_di_to_Xi(i1_prev_(1), dx1_prev(1)); + u_d[0] = ux1_(1); + u_d[1] = ux2_(1); + u_d[2] = ux3_(1); metric.template transform(xp, u_d, u_u); - real_t u0 = math::sqrt((u_d[0] * u_u[0] + u_d[1] * u_u[1] + u_d[2] * u_u[2]) / + u0 = math::sqrt((u_d[0] * u_u[0] + u_d[1] * u_u[1] + u_d[2] * u_u[2]) / (SQR(metric.alpha(xp)) + SQR(metric.beta(xp)))) ; - real_t vp = u_p[0] / u0 ; - - real_t diff = u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - - dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) - - u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp) + - HALF * u0 * (DERIVATIVE(metric.f2, xp) * SQR(vp) + - TWO * DERIVATIVE(metric.f1, xp) * vp + - DERIVATIVE(metric.f0, xp))) ; + vp = u_u[0] / u0 ; + + diff = u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - + dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield(i1_(1), em::ex1) - + u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + + HALF * u0 * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp) + + TWO * DERIVATIVE(metric.f1, xp[0]) * vp + + DERIVATIVE(metric.f0, xp[0]))) ; if (not cmp::AlmostEqual(diff, ZERO, eps * acc)) { printf("%.12e %s\n", diff, "Pusher test failed at positive charge."); - return false; } @@ -216,7 +218,7 @@ auto main(int argc, char* argv[]) -> int { try { using namespace ntt; - testFFPusher>( + testFFPusher>( { 128 }, { { 2.0, 50.0 } }, 100, diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h index d5de199da..83d90c0ff 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/flux_surface.h @@ -160,7 +160,7 @@ namespace metric { return math::sqrt(h<3, 3>(xi)) * omega(r_, theta_); } - Inline auto bet3(const coord_t& xi) const -> real_t { + Inline auto beta3(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; return -omega(r_, theta_); From b32bca09ddba2b310232605d87f2d045f6492f26 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Wed, 10 Jul 2024 13:37:30 +0800 Subject: [PATCH 16/47] fix bugs in 1d gr pusher --- src/kernels/particle_pusher_1D_gr.hpp | 13 ++++++----- src/kernels/tests/ff_pusher.cpp | 32 ++++++++++++++++----------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index d85e119cc..a402c23a4 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -103,6 +103,7 @@ namespace kernel::gr { , ux1 { ux1 } , ux2 { ux2 } , ux3 { ux3 } + , tag { tag } , metric { metric } , coeff { coeff } , dt { dt } @@ -116,6 +117,7 @@ namespace kernel::gr { (boundaries[0].first == PrtlBC::HORIZON); is_absorb_i1max = (boundaries[0].second == PrtlBC::ABSORB) || (boundaries[0].second == PrtlBC::HORIZON); + } /** @@ -186,11 +188,12 @@ namespace kernel::gr { metric.f2(xi) * SQR(v) - TWO * metric.f1(xi) * v - metric.f0(xi)); } - Inline auto compute_u0_u(const coord_t& u_cov, - const coord_t& u_ccov, + Inline auto compute_u0_u(const coord_t& u_ccov, const coord_t& xi) const { - return math::sqrt((u_cov[0] * u_ccov[0] + u_cov[1] * u_ccov[1] + u_cov[2] * u_ccov[2]) / - (SQR(metric.alpha(xi)) + SQR(metric.beta(xi)))); + return (u_ccov[2] - + u_ccov[0] * metric.f1(xi) / + (metric.template h<3, 3>(xi) * (metric.OmegaF() + metric.beta3(xi))) + ) / metric.OmegaF(); } // Extra @@ -315,7 +318,7 @@ template metric.template transform(xp, up_cov, up_ccov); - real_t vp { up_cov[0] / compute_u0_u(up_cov, up_ccov, xp) }; + real_t vp { up_ccov[0] / compute_u0_u(up_ccov, xp) }; /* -------------------------------- Leapfrog -------------------------------- */ diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 7026f322a..a4a2afff0 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -56,7 +56,7 @@ void testFFPusher(const std::vector& res, M metric { res, extent, params }; - const auto D = M::Dim; + static constexpr auto D = M::Dim; const int nx1 = res[0]; @@ -161,25 +161,29 @@ void testFFPusher(const std::vector& res, Kokkos::deep_copy(ux2_, ux2); auto ux3_ = Kokkos::create_mirror_view(ux3); Kokkos::deep_copy(ux3_, ux3); + auto efield_ = Kokkos::create_mirror_view(efield(i1(1), em::ex1)); + Kokkos::deep_copy(efield_, efield(i1(1), em::ex1)); //negative charge coord_t xp { i_di_to_Xi(i1_(0), dx1_(0)) }; - coord_t xp_prev { i_di_to_Xi(i1_prev_(0), dx1_prev(0)) }; - coord_t u_d {ux1_(0), ux2_(0), ux3_(0)}; - coord_t u_u { ZERO }; + coord_t xp_prev { i_di_to_Xi(i1_prev_(0), dx1_prev_(0)) }; + vec_t u_d {ux1_(0), ux2_(0), ux3_(0)}; + vec_t u_u { ZERO }; metric.template transform(xp, u_d, u_u); - real_t u0 { math::sqrt((u_d[0] * u_u[0] + u_d[1] * u_u[1] + u_d[2] * u_u[2]) / - (SQR(metric.alpha(xp)) + SQR(metric.beta(xp)))) }; + real_t u0 { (u_u[2] - + u_u[0] * metric.f1(xi) / + (metric.template h<3, 3>(xi) * (metric.OmegaF() + metric.beta3(xi))) + ) / metric.OmegaF()}; real_t vp { u_u[0] / u0 }; - real_t diff { u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - - dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield(i1_(1), em::ex1) - + real_t diff { u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) / + (dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield_ - u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + HALF * u0 * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp) + TWO * DERIVATIVE(metric.f1, xp[0]) * vp + - DERIVATIVE(metric.f0, xp[0]))) }; + DERIVATIVE(metric.f0, xp[0])))) }; if (not cmp::AlmostEqual(diff, ZERO, eps * acc)) { printf("%.12e %s\n", diff, "Pusher test failed at negative charge."); @@ -187,18 +191,20 @@ void testFFPusher(const std::vector& res, //positive charge xp[0] = i_di_to_Xi(i1_(1), dx1_(1)); - xp_prev[0] = i_di_to_Xi(i1_prev_(1), dx1_prev(1)); + xp_prev[0] = i_di_to_Xi(i1_prev_(1), dx1_prev_(1)); u_d[0] = ux1_(1); u_d[1] = ux2_(1); u_d[2] = ux3_(1); metric.template transform(xp, u_d, u_u); - u0 = math::sqrt((u_d[0] * u_u[0] + u_d[1] * u_u[1] + u_d[2] * u_u[2]) / - (SQR(metric.alpha(xp)) + SQR(metric.beta(xp)))) ; + u0 = (u_u[2] - + u_u[0] * metric.f1(xi) / + (metric.template h<3, 3>(xi) * (metric.OmegaF() + metric.beta3(xi))) + ) / metric.OmegaF() ; vp = u_u[0] / u0 ; diff = u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - - dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield(i1_(1), em::ex1) - + dt * (-coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield_ - u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + HALF * u0 * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp) + TWO * DERIVATIVE(metric.f1, xp[0]) * vp + From 072a1f7b779c857340d3bc7222dc20d7435f0959 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Wed, 10 Jul 2024 13:43:42 +0800 Subject: [PATCH 17/47] bug fix --- src/kernels/tests/ff_pusher.cpp | 38 ++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index a4a2afff0..7b887c585 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -178,15 +178,17 @@ void testFFPusher(const std::vector& res, ) / metric.OmegaF()}; real_t vp { u_u[0] / u0 }; - real_t diff { u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) / - (dt * (coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield_ - - u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + - HALF * u0 * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp) + - TWO * DERIVATIVE(metric.f1, xp[0]) * vp + - DERIVATIVE(metric.f0, xp[0])))) }; - - if (not cmp::AlmostEqual(diff, ZERO, eps * acc)) { - printf("%.12e %s\n", diff, "Pusher test failed at negative charge."); + real_t left { u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) }; + real_t right { dt * (coeff * metric.alpha(xp_prev) * metric.template h_<1, 1>(xp_prev) * 1.92 - + u0 * metric.alpha(xp_prev) * DERIVATIVE(metric.alpha, xp_prev[0]) + + HALF * u0 * (DERIVATIVE(metric.f2, xp_prev[0]) * SQR(vp) + + TWO * DERIVATIVE(metric.f1, xp_prev[0]) * vp + + DERIVATIVE(metric.f0, xp_prev[0]))) }; + real_t ratio { left / right }; + + if (not cmp::AlmostEqual(ratio, ONE, eps * acc)) { + printf("%.12e != 1\n", ratio); + throw std::runtime_error("Pusher fails at negative charge."); } //positive charge @@ -203,15 +205,17 @@ void testFFPusher(const std::vector& res, ) / metric.OmegaF() ; vp = u_u[0] / u0 ; - diff = u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - - dt * (-coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * efield_ - - u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + - HALF * u0 * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp) + + left = u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)); + right = dt * (-coeff * metric.alpha(xp) * metric.template h_<1, 1>(xp) * 1.92 - + u0 * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + + HALF * u0 * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp) + TWO * DERIVATIVE(metric.f1, xp[0]) * vp + - DERIVATIVE(metric.f0, xp[0]))) ; - - if (not cmp::AlmostEqual(diff, ZERO, eps * acc)) { - printf("%.12e %s\n", diff, "Pusher test failed at positive charge."); + DERIVATIVE(metric.f0, xp[0]))); + ratio = left / right; + + if (not cmp::AlmostEqual(ratio, ONE, eps * acc)) { + printf("%.12e != 1\n", ratio); + throw std::runtime_error("Pusher fails at positive charge."); } From dbead023517fbff96a3b8158b1202118b9635cf0 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Wed, 10 Jul 2024 15:33:48 -0400 Subject: [PATCH 18/47] Turbulence testing. --- src/framework/domain/domain.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/framework/domain/domain.h b/src/framework/domain/domain.h index 397907fef..3ecb8597f 100644 --- a/src/framework/domain/domain.h +++ b/src/framework/domain/domain.h @@ -107,6 +107,7 @@ namespace ntt { void set_mpi_rank(int rank) { m_mpi_rank = rank; + random_pool = random_number_pool_t { constant::RandomSeed + rank }; } #endif // MPI_ENABLED From f6ae1992bd7998edc8890b5cee569214c2e994c5 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 12 Jul 2024 10:10:22 +0800 Subject: [PATCH 19/47] fix bugs at ff_pusher --- src/kernels/particle_pusher_1D_gr.hpp | 2 +- src/kernels/tests/ff_pusher.cpp | 23 ++++++++++++----------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index a402c23a4..5672b3ee3 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -347,7 +347,7 @@ template /* update velocity */ real_t u0 { compute_u0_v(vp_upd, xp) }; ux1(p) = vp_upd * u0; - ux3(p) = u0 * (metric.template h<3,3>(xp) * metric.OmegaF() + ux3(p) = u0 * (metric.template h_<3,3>(xp) * metric.OmegaF() + metric.f1(xp) * vp_upd / (metric.OmegaF()+ metric.beta3(xp))); diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 7b887c585..115ed6c12 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -173,9 +173,8 @@ void testFFPusher(const std::vector& res, metric.template transform(xp, u_d, u_u); real_t u0 { (u_u[2] - - u_u[0] * metric.f1(xi) / - (metric.template h<3, 3>(xi) * (metric.OmegaF() + metric.beta3(xi))) - ) / metric.OmegaF()}; + u_u[0] * metric.f1(xi) * metric.template h<3, 3>(xi) / (metric.OmegaF() + metric.beta3(xi)) + ) / metric.OmegaF() }; real_t vp { u_u[0] / u0 }; real_t left { u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) }; @@ -186,9 +185,10 @@ void testFFPusher(const std::vector& res, DERIVATIVE(metric.f0, xp_prev[0]))) }; real_t ratio { left / right }; + unsigned int wrong { 0 }; if (not cmp::AlmostEqual(ratio, ONE, eps * acc)) { - printf("%.12e != 1\n", ratio); - throw std::runtime_error("Pusher fails at negative charge."); + printf("%.12e != 1 at negative charge\n", ratio); + ++wrong; } //positive charge @@ -200,9 +200,8 @@ void testFFPusher(const std::vector& res, metric.template transform(xp, u_d, u_u); u0 = (u_u[2] - - u_u[0] * metric.f1(xi) / - (metric.template h<3, 3>(xi) * (metric.OmegaF() + metric.beta3(xi))) - ) / metric.OmegaF() ; + u_u[0] * metric.f1(xi) * metric.template h<3, 3>(xi) / (metric.OmegaF() + metric.beta3(xi)) + ) / metric.OmegaF() ; vp = u_u[0] / u0 ; left = u0 * (metric.f2(xp) * vp + metric.f1(xp)) - (metric.f2(xp_prev) * vp + metric.f1(xp_prev)); @@ -214,11 +213,13 @@ void testFFPusher(const std::vector& res, ratio = left / right; if (not cmp::AlmostEqual(ratio, ONE, eps * acc)) { - printf("%.12e != 1\n", ratio); - throw std::runtime_error("Pusher fails at positive charge."); + printf("%.12e != 1 at positive charge\n", ratio); + ++wrong; } - + if (not wrong){ + throw std::runtime_error("ff_usher failed."); + } } From 6eb32443c315f5b337d70aa01a3e7e51f287d04d Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Mon, 22 Jul 2024 21:36:54 +0800 Subject: [PATCH 20/47] update tests of force free pusher --- src/kernels/particle_pusher_1D_gr.hpp | 358 ++++++++++++++++++++++++++ src/kernels/tests/ff_pusher.cpp | 203 +++++++++++++++ src/metrics/flux_surface.h | 98 +++---- src/metrics/tests/fs.cpp | 14 +- 4 files changed, 626 insertions(+), 47 deletions(-) create mode 100644 src/kernels/particle_pusher_1D_gr.hpp create mode 100644 src/kernels/tests/ff_pusher.cpp diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp new file mode 100644 index 000000000..65ef50958 --- /dev/null +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -0,0 +1,358 @@ +/** + * @file kernels/particle_pusher_1D_gr.h + * @brief Implementation of the particle pusher for 1D GR + * @implements + * - kernel::gr::Pusher_kernel_1D<> + * @namespaces: + * - kernel::gr:: + * @macros: + * - MPI_ENABLED +*/ + +#ifndef KERNELS_PARTICLE_PUSHER_1D_GR_HPP +#define KERNELS_PARTICLE_PUSHER_1D_GR_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_tags.h" +#endif + +/* -------------------------------------------------------------------------- */ +/* Local macros */ +/* -------------------------------------------------------------------------- */ +#define from_Xi_to_i(XI, I) \ + { I = static_cast((XI)); } + +#define from_Xi_to_i_di(XI, I, DI) \ + { \ + from_Xi_to_i((XI), (I)); \ + DI = static_cast((XI)) - static_cast(I); \ + } + +#define i_di_to_Xi(I, DI) static_cast((I)) + static_cast((DI)) + +#define DERIVATIVE(func, x) \ + ((func({ x + epsilon }) - func({ x - epsilon })) / \ + (TWO * epsilon)) + + +/* -------------------------------------------------------------------------- */ + +namespace kernel::gr { + using namespace ntt; + + struct Massive_t {}; + + struct Massless_t {}; + + /** + * @brief Algorithm for the Particle pusher + * @tparam M Metric + */ + template + class Pusher_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + static_assert(D == Dim::_1D, "Only 1d available for this pusher"); + + const ndfield_t Dfield; + array_t i1; + array_t i1_prev; + array_t dx1; + array_t dx1_prev; + array_t ux1, ux2, ux3; + array_t tag; + const M metric; + + const real_t coeff, dt; + const int ni1; + const real_t epsilon; + const int niter; + const int i1_absorb; + + bool is_absorb_i1min { false }, is_absorb_i1max { false }; + + public: + Pusher_kernel(const ndfield_t& Dfield, + const array_t& i1, + const array_t& i1_prev, + const array_t& dx1, + const array_t& dx1_prev, + const array_t& ux1, + const array_t& tag, + const M& metric, + const real_t& coeff, + const real_t& dt, + const int& ni1, + const real_t& epsilon, + const int& niter, + const boundaries_t& boundaries) + : Dfield { Dfield } + , i1 { i1 } + , i1_prev { i1_prev } + , dx1 { dx1 } + , dx1_prev { dx1_prev } + , ux1 { ux1 } + , tag { tag } + , metric { metric } + , coeff { coeff } + , dt { dt } + , ni1 { ni1 } + , epsilon { epsilon } + , niter { niter } + , i1_absorb { 2 } { + + raise::ErrorIf(boundaries.size() < 1, "boundaries defined incorrectly", HERE); + is_absorb_i1min = (boundaries[0].first == PrtlBC::ABSORB) || + (boundaries[0].first == PrtlBC::HORIZON); + is_absorb_i1max = (boundaries[0].second == PrtlBC::ABSORB) || + (boundaries[0].second == PrtlBC::HORIZON); + + } + + /** + * @brief Main pusher subroutine for photon particles. + */ + //Inline void operator()(Massless_t, index_t) const; + + /** + * @brief Main pusher subroutine for massive particles. + */ + Inline void operator()(index_t) const; + + /** + * @brief Iterative geodesic pusher substep for momentum only. + * @param xp particle coordinate. + * @param vp particle velocity. + * @param vp_upd updated particle velocity [return]. + */ + Inline void ForceFreePush( const coord_t& xp, + const real_t& vp, + real_t& vp_upd) const; + + /** + * @brief Iterative geodesic pusher substep for coordinate only. + * @param xp particle coordinate. + * @param vp particle velocity. + * @param xp_upd updated particle coordinate [return]. + */ + Inline void CoordinatePush(const coord_t& xp, + const real_t& vp, + coord_t& xp_upd) const; + + + /** + * @brief EM pusher substep. + * @param xp coordinate of the particle. + * @param vp covariant velocity of the particle. + * @param e0 electric field at the particle position. + * @param v_upd updated covarient velocity of the particle [return]. + */ + Inline void EfieldHalfPush(const coord_t& xp, + const real_t& vp, + const real_t& e0, + real_t& vp_upd) const; + // Helper functions + + /** + * @brief First order Yee mesh field interpolation to particle position. + * @param p index of the particle. + * @param e interpolated e-field + */ + Inline void interpolateFields(index_t& p, + real_t& e) const { + const int i { i1(p) + static_cast(N_GHOSTS) }; + const auto dx1_ { static_cast(dx1(p)) }; + real_t c1 = HALF * (Dfield(i, em::dx1) + Dfield(i - 1, em::dx1)); + real_t c2 = HALF * (Dfield(i, em::dx1) + Dfield(i + 1, em::dx1)); + e = c1 * (ONE - dx1_) + c2 * dx1_; + } + + /** + * @brief Compute controvariant component u^0 for massive particles. + */ + + Inline auto compute_u0(const real_t& v, + const coord_t& xi) const { + return ONE / math::sqrt(SQR(metric.alpha(xi)) - + metric.f2(xi) * SQR(v) - TWO * metric.f1(xi) * v - metric.f0(xi)); + } + + // Inline auto compute_u0_u(const coord_t& u_ccov, + // const coord_t& xi) const { + // return (u_ccov[2] - + // u_ccov[0] * metric.f1(xi) * metric.template h<3, 3>(xi) / (metric.OmegaF() + metric.beta3(xi)) + // ) / metric.OmegaF(); + // } + + // Extra + Inline void boundaryConditions(index_t& p) const{ + if (i1(p) < i1_absorb && is_absorb_i1min) { + tag(p) = ParticleTag::dead; + } else if (i1(p) >= ni1 && is_absorb_i1max) { + tag(p) = ParticleTag::dead; + } + +#if defined(MPI_ENABLED) + tag(p) = mpi::SendTag(tag(p), i1(p) < 0, i1(p) >= ni1); +#endif + } + + }; + + + + /* -------------------------------------------------------------------------- */ + /* 1D Pushers */ + /* -------------------------------------------------------------------------- */ + + /** + * massive particle electric field pusher + */ + template + Inline void Pusher_kernel::EfieldHalfPush(const coord_t& xp, + const real_t& vp, + const real_t& e0, + real_t& vp_upd) const { + real_t pp { ZERO }; + real_t pp_upd { ZERO }; + + real_t COEFF { HALF * coeff }; + + //calculate canonical momentum + real_t u0 { compute_u0(vp, xp) }; + pp = u0 * (metric.f2(xp) * vp + metric.f1(xp)); + + //calculate updated canonical momentum + pp_upd = pp + COEFF * e0; + + //calculate updated velocity + vp_upd = (pp_upd / u0 - metric.f1(xp)) / metric.f2(xp); + } + /** + * massive particle momentum pusher under force-free constraint + */ + template + Inline void Pusher_kernel::ForceFreePush( const coord_t& xp, + const real_t& vp, + real_t& vp_upd) const { + real_t vp_mid { ZERO }; + //canonical momentum of particles + real_t pp { ZERO }; + real_t pp_upd { ZERO }; + + vp_upd = vp; + + real_t u0 { compute_u0(vp, xp) }; + //calculate canonical momentum + pp = u0 * (metric.f2(xp) * vp + metric.f1(xp)); + pp_upd = pp ; + + for (auto i { 0 }; i < niter; ++i) { + // find midpoint values + vp_mid = HALF * (vp + vp_upd); + + u0 = compute_u0(vp_mid, xp); + + // find updated canonical momentum + pp_upd = pp + + dt * u0 * + (- metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + + HALF * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp_mid) + + TWO * DERIVATIVE(metric.f1, xp[0]) * vp_mid + + DERIVATIVE(metric.f0, xp[0]))); + + // find updated velocity + vp_upd = (pp_upd / u0 - metric.f1(xp)) / metric.f2(xp); + } + } + + /** + * coordinate pusher + */ + template + Inline void Pusher_kernel::CoordinatePush(const coord_t& xp, + const real_t& vp, + coord_t& xp_upd) const { + xp_upd[0] = dt * vp + xp[0]; + } + + /* ------------------------- Massive particle pusher ------------------------ */ +template + Inline void Pusher_kernel::operator()(index_t p) const { + if (tag(p) != ParticleTag::alive) { + if (tag(p) != ParticleTag::dead) { + raise::KernelError(HERE, "Invalid particle tag in pusher"); + } + return; + } + // record previous coordinate + i1_prev(p) = i1(p); + dx1_prev(p) = dx1(p); + + coord_t xp { ZERO }; + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + + real_t Dp_contrv { ZERO }; + interpolateFields(p, Dp_contrv); + + real_t ep_controv { metric.alpha(xp) * metric.template transform<1, Idx::U, Idx::D>(xp, Dp_contrv) }; + + real_t vp { ux1(p) }; + + + /* -------------------------------- Leapfrog -------------------------------- */ + /* u_i(n - 1/2) -> u*_i(n) */ + real_t vp_upd { ZERO }; + EfieldHalfPush(xp, vp, ep_controv, vp_upd); + + /* u*_i(n) -> u**_i(n) */ + vp = vp_upd; + ForceFreePush(xp, vp, vp_upd); + /* u**_i(n) -> u_i(n + 1/2) */ + vp = vp_upd; + EfieldHalfPush(xp, vp, ep_controv, vp_upd); + + /* x^i(n) -> x^i(n + 1) */ + coord_t xp_upd { ZERO }; + CoordinatePush(xp, vp_upd, xp_upd); + + /* update coordinate */ + int i1_; + prtldx_t dx1_; + from_Xi_to_i_di(xp_upd[0], i1_, dx1_); + i1(p) = i1_; + dx1(p) = dx1_; + + /* update velocity */ + ux1(p) = vp_upd; + + + boundaryConditions(p); + } + + + + + + +} // namespace kernel::gr + + + + + +#undef DERIVATIVE + +#undef i_di_to_Xi +#undef from_Xi_to_i_di +#undef from_Xi_to_i + +#endif // KERNELS_PARTICLE_PUSHER_GR_1D_HPP + diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp new file mode 100644 index 000000000..a4a6194d6 --- /dev/null +++ b/src/kernels/tests/ff_pusher.cpp @@ -0,0 +1,203 @@ +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" +#include "utils/comparators.h" + +#include "metrics/flux_surface.h" + +#include "kernels/particle_pusher_1D_gr.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace ntt; +using namespace metric; + +#define i_di_to_Xi(I, DI) static_cast((I)) + static_cast((DI)) + +#define DERIVATIVE(func, x) \ + ((func({ x + epsilon }) - func({ x - epsilon })) / \ + (TWO * epsilon)) + +inline static constexpr auto eps = std::numeric_limits::epsilon(); + +void errorIf(bool condition, const std::string& message) { + if (condition) { + throw std::runtime_error(message); + } +} + +template +void put_value(array_t& arr, T v, index_t p) { + auto h = Kokkos::create_mirror_view(arr); + Kokkos::deep_copy(h, arr); + h(p) = v; + Kokkos::deep_copy(arr, h); +} + +template +void testFFPusher(const std::vector& res, + const boundaries_t& ext, + const real_t acc, + const std::map& params = {}) { + static_assert(M::Dim == 1, "Only 1D is supported"); + errorIf(res.size() != M::Dim, "res.size() != M::Dim"); + + boundaries_t extent; + extent = ext; + + M metric { res, extent, params }; + + static constexpr auto D = M::Dim; + + const int nx1 = res[0]; + + auto coeff = real_t { 1.0 }; + auto dt = real_t { 0.01 }; + + const auto range_ext = CreateRangePolicy( + { 0}, + { res[0] + 2 * N_GHOSTS }); + + auto efield = ndfield_t { "efield", + res[0] + 2 * N_GHOSTS}; + + Kokkos::parallel_for( + "init efield", + range_ext, + Lambda(index_t i1) { + efield(i1, em::ex1) = ZERO; + }); + + + array_t i1 { "i1", 2 }; + array_t i1_prev { "i1_prev", 2 }; + array_t dx1 { "dx1", 2 }; + array_t dx1_prev { "dx1_prev", 2 }; + array_t ux1 { "ux1", 2 }; + array_t tag { "tag", 2 }; + + + put_value(i1, 50, 0); + put_value(dx1, (prtldx_t)(0.15), 0); + put_value(ux1, ZERO, 0); + put_value(tag, ParticleTag::alive, 0); + + put_value(i1, 50, 1); + put_value(dx1, (prtldx_t)(0.15), 1); + put_value(ux1, ZERO, 1); + put_value(tag, ParticleTag::alive, 1); + + + // Particle boundaries + auto boundaries = boundaries_t {}; + boundaries = { + {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + }; + + + + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({ 0 }, { 1 }), + kernel::gr::Pusher_kernel>( + efield, + i1, + i1_prev, + dx1, + dx1_prev, + ux1, + tag, + metric, + coeff, dt, + nx1, + 1e-5, + 30, + boundaries)); + + + + auto i1_ = Kokkos::create_mirror_view(i1); + Kokkos::deep_copy(i1_, i1); + auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); + Kokkos::deep_copy(i1_prev_, i1_prev); + auto dx1_ = Kokkos::create_mirror_view(dx1); + Kokkos::deep_copy(dx1_, dx1); + auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); + Kokkos::deep_copy(dx1_prev_, dx1_prev); + auto ux1_ = Kokkos::create_mirror_view(ux1); + Kokkos::deep_copy(ux1_, ux1); + + + +//negative charge + coord_t xp_prev { i_di_to_Xi(i1_prev_(0), dx1_prev_(0)) }; + //coord_t xp_prev { 50.15 }; + real_t u0_prev { ONE / math::sqrt(SQR(metric.alpha(xp_prev)) - metric.f0(xp_prev)) }; + + real_t epsilon { 1e-5 }; + + real_t vp { ux1_(0) }; + real_t vmid { HALF * vp }; + real_t u0_mid { ONE / math::sqrt(SQR(metric.alpha(xp_prev)) - + metric.f2(xp_prev) * SQR(vmid) - TWO * metric.f1(xp_prev) * vmid - metric.f0(xp_prev)) }; + + + real_t left { u0_mid * (metric.f2(xp_prev) * vp + metric.f1(xp_prev)) - u0_prev * metric.f1(xp_prev) }; + real_t right { dt * (coeff * metric.alpha(xp_prev) * metric.template h_<1, 1>(xp_prev) * ZERO + + u0_mid * (-metric.alpha(xp_prev) * DERIVATIVE(metric.alpha, xp_prev[0]) + + HALF * (DERIVATIVE(metric.f2, xp_prev[0]) * SQR(vmid) + + TWO * DERIVATIVE(metric.f1, xp_prev[0]) * vmid + + DERIVATIVE(metric.f0, xp_prev[0])))) }; + real_t ratio { left / right }; + + printf("vp = %.12e\n", vp); + + unsigned int wrong { 0 }; + + if (not cmp::AlmostEqual(ratio, ONE, eps * acc)) { + printf("%.12e != 1; %.12e != %.12e at negative charge\n", ratio, left, right); + ++wrong; + } + + if (wrong){ + throw std::runtime_error("ff_usher failed."); + } + +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + testFFPusher>( + { 128 }, + { { 2.0, 50.0 } }, + 1000, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} + +#undef DERIVATIVE +#undef i_di_to_Xi diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h index e1e8c1633..4c031094e 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/flux_surface.h @@ -59,9 +59,6 @@ namespace metric { return psi0 * (1 - cos(theta)); } - Inline auto dpsi_dr(const real_t& r, const real_t& theta) const -> real_t { - return ZERO; - } Inline auto dpsi_dtheta(const real_t& r, const real_t& theta) const -> real_t { return psi0 * math::sin(theta); @@ -76,8 +73,7 @@ namespace metric { } Inline auto eta2r(const real_t& eta) const -> real_t{ - real_t exp = math::exp(eta * (rh_ - rh_m)); - return (rh_ - rh_m * exp) / (1 - exp); + return rh_m - TWO * math::sqrt(ONE - SQR(a)) / math::expm1(eta * TWO * math::sqrt(ONE - SQR(a))); } @@ -108,7 +104,7 @@ namespace metric { , eta_min { r2eta(x1_min) } , eta_max { r2eta(x1_max) } , d_eta { (eta_max - eta_min) / nx1 } - , d_eta_inv { 1 / d_eta }{ + , d_eta_inv { ONE / d_eta }{ set_dxMin(find_dxMin()); } @@ -133,6 +129,11 @@ namespace metric { Inline auto rg() const -> real_t { return rg_; } + + [[nodiscard]] + Inline auto OmegaF() const -> real_t { + return Omega; + } /** @@ -145,32 +146,38 @@ namespace metric { return math::sqrt(Sigma(r_, theta_) * Delta(r_) / A(r_, theta_)); } + /** + * shift vector, only third covariant component is non-zero + * @param x coordinate array in code units + */ + + Inline auto beta(const coord_t& xi) const -> real_t { + return math::sqrt(h<3, 3>(xi)) * omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min) ); + } + + Inline auto beta3(const coord_t& xi) const -> real_t { + return -omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min)); + } + /** * @brief Compute helper functions f0,f1,f2 in 1D-GRPIC */ Inline auto f2(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; - const real_t Delta_ { Delta(r_) }; - const real_t temp = SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_dr(r_, theta_)); - return Sigma(r_, theta_) * Delta_ * SQR(dpsi_dtheta_) / temp + - SQR(A(r_, theta_)* math::sin(theta_) * dpsi_dtheta_ * pCur / temp ) - / h_<3, 3>(xi); + return SQR(d_eta) * Sigma(r_, theta_) * (Delta(r_) + + A(r_, theta_) * SQR(pCur / dpsi_dtheta(r_, theta_) ) + ); } Inline auto f1(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; - return A(r_, theta_)* math::sin(theta_) * dpsi_dtheta_ * pCur * (Omega - omega(r_, theta_)) / - (SQR(dpsi_dtheta_) + Delta(r_) * SQR(dpsi_dr(r_, theta_))); + return d_eta * A(r_, theta_)* math::sin(theta_) * pCur * (Omega + beta3(xi)) / dpsi_dtheta(r_, theta_); } Inline auto f0(const coord_t& xi) const -> real_t { - const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - return h_<3, 3>(xi) * SQR(Omega - omega(r_, theta_)); + return h_<3, 3>(xi) * SQR(Omega + beta3(xi)); } /** @@ -203,15 +210,12 @@ namespace metric { const real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; const real_t Sigma_ { Sigma(r_, theta_) }; const real_t Delta_ { Delta(r_) }; - const real_t dpsi_dtheta_ { dpsi_dtheta(r_, theta_) }; - const real_t dpsi_r_ { dpsi_dr(r_, theta_) }; if constexpr (i == 1 && j == 1) { // h_11 - return SQR(d_eta) * Sigma_ * Delta_ * SQR( dpsi_dtheta_) / - (SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_r_)); + return SQR(d_eta) * Sigma_ * Delta_; } else if constexpr (i == 2 && j == 2) { // h_22 - return Sigma_ / (SQR(dpsi_dtheta_) + Delta_ * SQR(dpsi_r_)); + return Sigma_ / SQR(dpsi_dtheta(r_, theta_) ) ; } else if constexpr (i == 3 && j == 3) { // h_33 return A(r_, theta_) * SQR(math::sin(theta_)) / Sigma_; @@ -277,18 +281,28 @@ namespace metric { (in == Idx::Sph && out == Idx::T)) { // tetrad <-> sph return v_in; - } else if constexpr ((in == Idx::T || in == Idx::Sph) && out == Idx::U) { - // tetrad/sph -> cntrv - return v_in / math::sqrt(h_(x)); - } else if constexpr (in == Idx::U && (out == Idx::T || out == Idx::Sph)) { - // cntrv -> tetrad/sph - return v_in * math::sqrt(h_(x)); - } else if constexpr ((in == Idx::T || in == Idx::Sph) && out == Idx::D) { - // tetrad/sph -> cov - return v_in / math::sqrt(h(x)); - } else if constexpr (in == Idx::D && (out == Idx::T || out == Idx::Sph)) { - // cov -> tetrad/sph - return v_in * math::sqrt(h(x)); + } else if constexpr (((in == Idx::T || in == Idx::Sph) && out == Idx::U) || + (in == Idx::D && (out == Idx::T || out == Idx::Sph))){ + // tetrad/sph -> cntrv ; cov -> tetrad/sph + if constexpr (i == 1){ + return v_in / math::sqrt(h_(x)) / Delta(eta2r(x[0] * d_eta + eta_min)); + }else if constexpr (i == 2){ + return v_in / math::sqrt(h_(x)) * + dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + }else{ + return v_in / math::sqrt(h_(x)); + } + } else if constexpr ((in == Idx::U && (out == Idx::T || out == Idx::Sph)) || + ((in == Idx::T || in == Idx::Sph) && out == Idx::D)){ + // cntrv -> tetrad/sph ; tetrad/sph -> cov + if constexpr (i == 1){ + return v_in * math::sqrt(h_(x)) * Delta(eta2r(x[0] * d_eta + eta_min)); + }else if constexpr (i == 2){ + return v_in * math::sqrt(h_(x)) / + dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + }else{ + return v_in * math::sqrt(h_(x)); + } } else if constexpr (in == Idx::U && out == Idx::D) { // cntrv -> cov return v_in * h_(x); @@ -299,12 +313,9 @@ namespace metric { (in == Idx::PD && out == Idx::D)) { // cntrv -> phys cntrv || phys cov -> cov if constexpr (i == 1){ - real_t r_ { eta2r(x[0] * d_eta + eta_min) }; - return v_in * Delta(r_) * d_eta ; + return v_in * Delta(eta2r(x[0] * d_eta + eta_min)) * d_eta ; }else if constexpr (i == 2){ - real_t r_ { eta2r(x[0] * d_eta + eta_min) }; - real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; - return v_in / dpsi_dtheta(r_, theta_); + return v_in / dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min) ); }else{ return v_in; } @@ -312,12 +323,9 @@ namespace metric { (in == Idx::D && out == Idx::PD)) { // phys cntrv -> cntrv || cov -> phys cov if constexpr (i == 1){ - real_t r_ { eta2r(x[0] * d_eta + eta_min) }; - return v_in * d_eta_inv / Delta(r_); + return v_in * d_eta_inv / Delta(eta2r(x[0] * d_eta + eta_min)); }else if constexpr (i == 2){ - real_t r_ { eta2r(x[0] * d_eta + eta_min) }; - real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; - return v_in * dpsi_dtheta(r_, theta_); + return v_in * dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); }else{ return v_in; } diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/fs.cpp index 4300a8a0b..9f905d380 100644 --- a/src/metrics/tests/fs.cpp +++ b/src/metrics/tests/fs.cpp @@ -74,6 +74,10 @@ void testMetric(const std::vector& res, res_tup[d] = res[d]; npts *= res[d]; } + + const auto x_min = ext[0].first; + const auto x_max = ext[0].second; + unsigned long all_wrongs = 0; const auto rg = metric.rg(); @@ -83,6 +87,12 @@ void testMetric(const std::vector& res, const auto psi0 = params.at("psi0"); const auto pCur = params.at("pCur"); const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); + const auto rh_m = rh - TWO * math::sqrt(ONE - SQR(a)); + + const auto eta_min = math::log((x_min - rh) / (x_min - rh_m)) / (rh - rh_m); + const auto eta_max = math::log((x_max - rh) / (x_max - rh_m)) / (rh - rh_m); + const auto d_eta = (eta_max - eta_min) / ((real_t)res[0]); + Kokkos::parallel_reduce( "h_ij/hij", npts, @@ -122,8 +132,8 @@ void testMetric(const std::vector& res, const auto h33_expect = ONE / h_33_expect; const auto f0_expect = h_33_expect * SQR(Omega - omega); - const auto f1_expect = A * pCur * math::sin(th) * (Omega - omega) / dpsi_dtheta; - const auto f2_expect = Sigma * Delta + Sigma * A * SQR(pCur / dpsi_dtheta); + const auto f1_expect = d_eta * A * pCur * math::sin(th) * (Omega - omega) / dpsi_dtheta; + const auto f2_expect = SQR(d_eta) * Sigma * (Delta + A * SQR(pCur / dpsi_dtheta)); const auto f0_predict = metric.f0(x_Code); const auto f1_predict = metric.f1(x_Code); From a0f62f50cc747ace3229e7f5082c3ebdbc5bad4b Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 26 Jul 2024 10:54:38 +0800 Subject: [PATCH 21/47] 1d grpic --- src/kernels/particle_pusher_1D_gr.hpp | 310 ++++++++++++++++++++++ src/kernels/tests/ff_pusher.cpp | 292 +++++++++++++++++++++ src/metrics/flux_surface.h | 360 ++++++++++++++++++++++++++ src/metrics/tests/fs.cpp | 187 +++++++++++++ 4 files changed, 1149 insertions(+) create mode 100644 src/kernels/particle_pusher_1D_gr.hpp create mode 100644 src/kernels/tests/ff_pusher.cpp create mode 100644 src/metrics/flux_surface.h create mode 100644 src/metrics/tests/fs.cpp diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp new file mode 100644 index 000000000..08400070d --- /dev/null +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -0,0 +1,310 @@ +/** + * @file kernels/particle_pusher_1D_gr.h + * @brief Implementation of the particle pusher for 1D GR + * @implements + * - kernel::gr::Pusher_kernel_1D<> + * @namespaces: + * - kernel::gr:: + * @macros: + * - MPI_ENABLED +*/ + +#ifndef KERNELS_PARTICLE_PUSHER_1D_GR_HPP +#define KERNELS_PARTICLE_PUSHER_1D_GR_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_tags.h" +#endif + +/* -------------------------------------------------------------------------- */ +/* Local macros */ +/* -------------------------------------------------------------------------- */ +#define from_Xi_to_i(XI, I) \ + { I = static_cast((XI)); } + +#define from_Xi_to_i_di(XI, I, DI) \ + { \ + from_Xi_to_i((XI), (I)); \ + DI = static_cast((XI)) - static_cast(I); \ + } + +#define i_di_to_Xi(I, DI) static_cast((I)) + static_cast((DI)) + +#define DERIVATIVE(func, x) \ + ((func({ x + epsilon }) - func({ x - epsilon })) / \ + (TWO * epsilon)) + + +/* -------------------------------------------------------------------------- */ + +namespace kernel::gr { + using namespace ntt; + + struct Massive_t {}; + + struct Massless_t {}; + + /** + * @brief Algorithm for the Particle pusher + * @tparam M Metric + */ + template + class Pusher_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + static_assert(D == Dim::_1D, "Only 1d available for this pusher"); + + const ndfield_t Dfield; + array_t i1; + array_t i1_prev; + array_t dx1; + array_t dx1_prev; + array_t ux1; + array_t tag; + const M metric; + + const real_t coeff, dt; + const int ni1; + const real_t epsilon; + const int niter; + const int i1_absorb; + + + bool is_absorb_i1min { false }, is_absorb_i1max { false }; + + public: + Pusher_kernel(const ndfield_t& Dfield, + const array_t& i1, + const array_t& i1_prev, + const array_t& dx1, + const array_t& dx1_prev, + const array_t& ux1, + const array_t& tag, + const M& metric, + const real_t& coeff, + const real_t& dt, + const int& ni1, + const real_t& epsilon, + const int& niter, + const boundaries_t& boundaries) + : Dfield { Dfield } + , i1 { i1 } + , i1_prev { i1_prev } + , dx1 { dx1 } + , dx1_prev { dx1_prev } + , ux1 { ux1 } + , tag { tag } + , metric { metric } + , coeff { coeff } + , dt { dt } + , ni1 { ni1 } + , epsilon { epsilon } + , niter { niter } + , i1_absorb { 2 } { + + raise::ErrorIf(boundaries.size() < 1, "boundaries defined incorrectly", HERE); + is_absorb_i1min = (boundaries[0].first == PrtlBC::ABSORB) || + (boundaries[0].first == PrtlBC::HORIZON); + is_absorb_i1max = (boundaries[0].second == PrtlBC::ABSORB) || + (boundaries[0].second == PrtlBC::HORIZON); + + } + + /** + * @brief Main pusher subroutine for photon particles. + */ + //Inline void operator()(Massless_t, index_t) const; + + /** + * @brief Main pusher subroutine for massive particles. + */ + Inline void operator()(index_t) const; + + /** + * @brief Iterative geodesic pusher substep for momentum only. + * @param xp particle coordinate. + * @param vp particle velocity. + * @param vp_upd updated particle velocity [return]. + */ + Inline void ForceFreePush( const coord_t& xp, + const real_t& vp, + const real_t& ex, + real_t& vp_upd) const; + + /** + * @brief Iterative geodesic pusher substep for coordinate only. + * @param xp particle coordinate. + * @param vp particle velocity. + * @param xp_upd updated particle coordinate [return]. + */ + Inline void CoordinatePush(const coord_t& xp, + const real_t& vp, + coord_t& xp_upd) const; + + // Helper functions + + /** + * @brief First order Yee mesh field interpolation to particle position. + * @param p index of the particle. + * @param e interpolated e-field + */ + Inline void interpolateFields(index_t& p, + real_t& e) const { + const int i { i1(p) + static_cast(N_GHOSTS) }; + const auto dx1_ { static_cast(dx1(p)) }; + real_t c1 = HALF * (Dfield(i, em::dx1) + Dfield(i - 1, em::dx1)); + real_t c2 = HALF * (Dfield(i, em::dx1) + Dfield(i + 1, em::dx1)); + e = c1 * (ONE - dx1_) + c2 * dx1_; + } + + /** + * @brief Compute controvariant component u^0 for massive particles. + */ + + Inline auto compute_u0_inv(const real_t& v, + const coord_t& xi) const -> real_t{ + return math::sqrt(math::abs(SQR(metric.alpha(xi)) - + metric.f2(xi) * SQR(v) - TWO * metric.f1(xi) * v - metric.f0(xi))) ; + } + + + // Extra + Inline void boundaryConditions(index_t& p) const{ + if (i1(p) < i1_absorb && is_absorb_i1min) { + tag(p) = ParticleTag::dead; + } else if (i1(p) >= ni1 && is_absorb_i1max) { + tag(p) = ParticleTag::dead; + } + +#if defined(MPI_ENABLED) + tag(p) = mpi::SendTag(tag(p), i1(p) < 0, i1(p) >= ni1); +#endif + } + + }; + + + + /* -------------------------------------------------------------------------- */ + /* 1D Pushers */ + /* -------------------------------------------------------------------------- */ + + /** + * massive particle momentum pusher under force-free constraint + */ + template + Inline void Pusher_kernel::ForceFreePush( const coord_t& xp, + const real_t& vp, + const real_t& ex, + real_t& vp_upd) const { + + + real_t vp_mid { vp }; + + vp_upd = vp; + + real_t weight = 0.5; + + //printf("Iteration starts.\n"); + for (auto i { 0 }; i < niter; ++i) { + // find midpoint values + vp_mid = 0.5 * (vp + vp_upd); + // find updated velociity + vp_upd = compute_u0_inv(vp_rlx, xp) * vp / compute_u0_inv(vp, xp) + + (( compute_u0_inv(vp_rlx,xp) / compute_u0_inv(vp, xp) - ONE) * metric.f1(xp) + + dt * (coeff * ex * compute_u0_inv(vp_rlx, xp) + + (-metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + + HALF * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp_rlx) + + TWO * DERIVATIVE(metric.f1, xp[0]) * vp_rlx + + DERIVATIVE(metric.f0, xp[0])) + ) + ) + ) / metric.f2(xp); + } + } + + /** + * coordinate pusher + */ + template + Inline void Pusher_kernel::CoordinatePush(const coord_t& xp, + const real_t& vp, + coord_t& xp_upd) const { + xp_upd[0] = dt * vp + xp[0]; + } + + /* ------------------------- Massive particle pusher ------------------------ */ +template + Inline void Pusher_kernel::operator()(index_t p) const { + if (tag(p) != ParticleTag::alive) { + if (tag(p) != ParticleTag::dead) { + raise::KernelError(HERE, "Invalid particle tag in pusher"); + } + return; + } + // record previous coordinate + i1_prev(p) = i1(p); + dx1_prev(p) = dx1(p); + + coord_t xp { ZERO }; + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + + real_t Dp_cntrv { ZERO }; + interpolateFields(p, Dp_cntrv); + + real_t ep_cntrv { metric.alpha(xp) * metric.template transform<1, Idx::U, Idx::D>(xp, Dp_cntrv) }; + + real_t vp { ux1(p) }; + + + /* -------------------------------- Leapfrog -------------------------------- */ + /* u_i(n - 1/2) -> u_i(n + 1/2) */ + real_t vp_upd { ZERO }; + + ForceFreePush(xp, vp, ep_cntrv, vp_upd); + + + /* x^i(n) -> x^i(n + 1) */ + coord_t xp_upd { ZERO }; + CoordinatePush(xp, vp_upd, xp_upd); + + /* update coordinate */ + int i1_; + prtldx_t dx1_; + from_Xi_to_i_di(xp_upd[0], i1_, dx1_); + i1(p) = i1_; + dx1(p) = dx1_; + + /* update velocity */ + ux1(p) = vp_upd; + + + boundaryConditions(p); + } + + + + + + +} // namespace kernel::gr + + + + + +#undef DERIVATIVE + +#undef i_di_to_Xi +#undef from_Xi_to_i_di +#undef from_Xi_to_i + +#endif // KERNELS_PARTICLE_PUSHER_GR_1D_HPP + diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp new file mode 100644 index 000000000..5da755fb0 --- /dev/null +++ b/src/kernels/tests/ff_pusher.cpp @@ -0,0 +1,292 @@ +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" +#include "utils/comparators.h" + +#include "metrics/flux_surface.h" + +#include "kernels/particle_pusher_1D_gr.hpp" + +#include +#include + +#include +#include +#include +#include +#include + +using namespace ntt; +using namespace metric; + +#define i_di_to_Xi(I, DI) static_cast((I)) + static_cast((DI)) + +#define from_Xi_to_i(XI, I) \ + { I = static_cast((XI)); } + +#define from_Xi_to_i_di(XI, I, DI) \ + { \ + from_Xi_to_i((XI), (I)); \ + DI = static_cast((XI)) - static_cast(I); \ + } + + +#define DERIVATIVE(func, x) \ + ((func({ x + epsilon }) - func({ x - epsilon })) / \ + (TWO * epsilon)) + +inline static constexpr auto epsilon = std::numeric_limits::epsilon(); + + +Inline auto equal(const real_t& a, + const real_t& b, + const char* msg, + const real_t acc = ONE) -> bool { + const auto eps = math::sqrt(epsilon) * acc; + if (not cmp::AlmostEqual(a, b, eps)) { + printf("%.12e != %.12e %s\n", a, b, msg); + return false; + } + return true; +} + + +void errorIf(bool condition, const std::string& message) { + if (condition) { + throw std::runtime_error(message); + } +} + +template +void put_value(array_t& arr, T v, index_t p) { + auto h = Kokkos::create_mirror_view(arr); + Kokkos::deep_copy(h, arr); + h(p) = v; + Kokkos::deep_copy(arr, h); +} + +template +void testFFPusher(const std::vector& res, + const boundaries_t& ext, + const real_t acc, + const std::map& params = {}) { + static_assert(M::Dim == 1, "Only 1D is supported"); + errorIf(res.size() != M::Dim, "res.size() != M::Dim"); + + boundaries_t extent; + extent = ext; + + M metric { res, extent, params }; + + static constexpr auto D = M::Dim; + + const int nx1 = res[0]; + + const real_t d_eta_inv { nx1 / (metric.r2eta(extent[0].second) - metric.r2eta(extent[0].first)) }; + + const auto coeff { d_eta_inv }; + const auto dt = real_t { 0.001 }; + + const auto range_ext = CreateRangePolicy( + { 0 }, + { res[0] + 2 * N_GHOSTS }); + + auto efield = ndfield_t { "efield", + res[0] + 2 * N_GHOSTS}; + + + array_t i1 { "i1", 30 }; + array_t i1_prev { "i1_prev", 30 }; + array_t dx1 { "dx1", 30 }; + array_t dx1_prev { "dx1_prev", 30 }; + array_t ux1 { "ux1", 30 }; + array_t tag { "tag", 30 }; + + const auto sep = real_t { 0.1 * res[0] }; + real_t x1i { ZERO }; + int ii { 0 }; + prtldx_t dx1i { ZERO }; + + + // Particle boundaries + auto boundaries = boundaries_t {}; + boundaries = { + {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + }; + + // No efield + + Kokkos::parallel_for( + "init efield", + range_ext, + Lambda(index_t i1) { + efield(i1, em::ex1) = ZERO; + }); + + for (size_t n { 0 }; n < 30; n++){ + x1i = ZERO + (n % 10) * sep; + from_Xi_to_i_di(x1i, ii, dx1i) + put_value(i1, ii, n); + put_value(dx1, dx1i, n); + put_value(ux1, -metric.f1({ x1i }) / metric.f2({ x1i }), n); + put_value(tag, ParticleTag::alive, n); + } + + + // Without electric field + + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({ 0 }, { 10 }), + kernel::gr::Pusher_kernel>( + efield, + i1, + i1_prev, + dx1, + dx1_prev, + ux1, + tag, + metric, + -coeff, dt, + nx1, + 1e-5, + 30, + boundaries)); + + // With electric field + // positive charge + + Kokkos::parallel_for( + "init efield", + range_ext, + Lambda(index_t i1) { + efield(i1, em::ex1) = 99.0; + }); + + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({ 10 }, { 20 }), + kernel::gr::Pusher_kernel>( + efield, + i1, + i1_prev, + dx1, + dx1_prev, + ux1, + tag, + metric, + coeff, dt, + nx1, + 1e-5, + 30, + boundaries)); + //negative charge + + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({ 20 }, { 30 }), + kernel::gr::Pusher_kernel>( + efield, + i1, + i1_prev, + dx1, + dx1_prev, + ux1, + tag, + metric, + -coeff, dt, + nx1, + 1e-5, + 30, + boundaries)); + + auto i1_ = Kokkos::create_mirror_view(i1); + Kokkos::deep_copy(i1_, i1); + auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); + Kokkos::deep_copy(i1_prev_, i1_prev); + auto dx1_ = Kokkos::create_mirror_view(dx1); + Kokkos::deep_copy(dx1_, dx1); + auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); + Kokkos::deep_copy(dx1_prev_, dx1_prev); + auto ux1_ = Kokkos::create_mirror_view(ux1); + Kokkos::deep_copy(ux1_, ux1); + + + + real_t vp_exp[10] { -0.128080544611002, -0.222571219885845, -0.301212251198582, + -0.358235366733387, -0.387383121052459, -0.382799931574759, + -0.340833052985762, -0.263140267573464, -0.161128753912851, + -0.0604347402410836 }; + real_t vp_e_p_exp[10] { -0.122286881108314, -0.215534929107648, -0.292701135574140, + -0.348028532252193, -0.375337709663405, -0.368984471614021, + -0.325765909536170, -0.248149662916807, -0.148698026244964, + -0.0538237879835971 }; + real_t vp_e_n_exp[10] { -0.133874207868050, -0.229607510251248, -0.309723366124719, + -0.368442200032320, -0.399428530458386, -0.396615388297603, + -0.355900191451829, -0.278130865433766, -0.173559474415594, + -0.0670456885818427 }; + + unsigned int wrongs { 0 }; + + for (size_t n { 0 }; n < 10; ++n){ + wrongs += !equal(ux1_(n), vp_exp[n], "no efield", acc); + } + + for (size_t n { 0 }; n < 10; ++n){ + wrongs += !equal(ux1_(n + 10), vp_e_p_exp[n], "positive charge", acc); + } + + for (size_t n { 0 }; n < 10; ++n){ + wrongs += !equal(ux1_(n + 20), vp_e_n_exp[n], "negative charge", acc); + } + + if (wrongs){ + throw std::runtime_error("ff_usher failed."); + } + + + //with electric field, positive charge +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + testFFPusher>( + { 128 }, + { { 2.0, 50.0 } }, + 5, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + + testFFPusher>( + { 512 }, + { { 2.0, 50.0 } }, + 5, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} + +#undef DERIVATIVE +#undef i_di_to_Xi +#undef from_Xi_to_i_di +#undef from_Xi_to_i diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h new file mode 100644 index 000000000..d87d81474 --- /dev/null +++ b/src/metrics/flux_surface.h @@ -0,0 +1,360 @@ +/** + * @file metrics/flux_surface.h + * @brief metric along constant flux surfaces in force-free fields, based on totoised Boyer-Lindquist coordinates + * @implements + * - metric::FluxSurface<> : metric::MetricBase<> + * @namespaces: + * - metric:: + * !TODO + * None radial surfaces needs to be implemented (dpsi_dr != 0). + */ + +#ifndef METRICS_FLUX_SURFACE_H +#define METRICS_FLUX_SURFACE_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +#include "metrics/metric_base.h" + +#include +#include +#include + + +namespace metric { + + template + class FluxSurface : public MetricBase { + static_assert(D == Dim::_1D, "Only 1D flux_surface is available"); + + private: + // Spin parameter, in [0,1[ + // and horizon size in units of rg + // all physical extents are in units of rg + const real_t a, rg_, rh_, rh_m, psi0, theta0, Omega, pCur; + const real_t eta_max, eta_min; + const real_t d_eta, d_eta_inv; + + Inline auto Delta(const real_t& r) const -> real_t { + return SQR(r) - TWO * r + SQR(a); + } + + Inline auto Sigma(const real_t& r, const real_t& theta) const -> real_t { + return SQR(r) + SQR(a) * SQR(math::cos(theta)); + } + + Inline auto A(const real_t& r, const real_t& theta) const -> real_t { + return SQR(SQR(r) + SQR(a)) - SQR(a) * Delta(r) * SQR(math::sin(theta)); + } + + Inline auto omega(const real_t& r, const real_t& theta) const -> real_t { + return TWO * a * r / A(r, theta); + } + + Inline auto psi(const real_t& r, const real_t& theta) const -> real_t { + return psi0 * (1 - cos(theta)); + } + + + Inline auto dpsi_dtheta(const real_t& r, const real_t& theta) const -> real_t { + return psi0 * math::sin(theta); + } + + + + + public: + static constexpr const char* Label { "flux_surface" }; + static constexpr Dimension PrtlDim { D }; + static constexpr ntt::Coord::type CoordType { ntt::Coord::Fs }; + static constexpr ntt::Metric::type MetricType { ntt::Metric::Flux_Surface }; + using MetricBase::x1_min; + using MetricBase::x1_max; + using MetricBase::nx1; + using MetricBase::set_dxMin; + + FluxSurface(std::vector res, + boundaries_t ext, + const std::map& params) + : MetricBase { res, ext } + , a { params.at("a") } + , psi0 { params.at("psi0") } + , theta0 { params.at("theta0") } + , pCur { params.at("pCur") } + , rg_ { ONE } + , rh_ { ONE + math::sqrt(ONE - SQR(a)) } + , rh_m { ONE - math::sqrt(ONE - SQR(a)) } + , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh_)) } + , eta_min { r2eta(x1_min) } + , eta_max { r2eta(x1_max) } + , d_eta { (eta_max - eta_min) / nx1 } + , d_eta_inv { ONE / d_eta }{ + set_dxMin(find_dxMin()); + } + + ~FluxSurface() = default; + + [[nodiscard]] + Inline auto spin() const -> real_t { + return a; + } + + [[nodiscard]] + Inline auto rhorizon() const -> real_t { + return rh_; + } + + [[nodiscard]] + Inline auto rhorizon_minus() const -> real_t { + return rh_m; + } + + [[nodiscard]] + Inline auto rg() const -> real_t { + return rg_; + } + + [[nodiscard]] + Inline auto OmegaF() const -> real_t { + return Omega; + } + + + /** + * lapse function + * @param x coordinate array in code units + */ + Inline auto alpha(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return math::sqrt(Sigma(r_, theta_) * Delta(r_) / A(r_, theta_)); + } + + /** + * shift vector, only third covariant component is non-zero + * @param x coordinate array in code units + */ + + Inline auto beta(const coord_t& xi) const -> real_t { + return math::sqrt(h<3, 3>(xi)) * omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min) ); + } + + Inline auto beta3(const coord_t& xi) const -> real_t { + return -omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min)); + } + + /** + * @brief Compute helper functions f0,f1,f2 in 1D-GRPIC + */ + Inline auto f2(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return SQR(d_eta) * Sigma(r_, theta_) * (Delta(r_) + + A(r_, theta_) * SQR(pCur / dpsi_dtheta(r_, theta_) ) + ); + } + + Inline auto f1(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; + return d_eta * A(r_, theta_)* math::sin(theta_) * pCur * (Omega + beta3(xi)) / dpsi_dtheta(r_, theta_); + } + + Inline auto f0(const coord_t& xi) const -> real_t { + return h_<3, 3>(xi) * SQR(Omega + beta3(xi)); + } + + /** + * minimum effective cell size for a given metric (in physical units) + */ + [[nodiscard]] + auto find_dxMin() const -> real_t override { + real_t min_dx { -ONE }; + for (int i { 0 }; i < nx1; ++i){ + real_t i_ { static_cast(i) + HALF }; + coord_t xi { i_ }; + real_t dx = ONE / math::sqrt(h<1, 1>(xi)); + if ((min_dx > dx) || (min_dx < 0.0)) { + min_dx = dx; + } + } + return min_dx; + } + + /** + * metric component with lower indices: h_ij + * @param x coordinate array in code units + */ + template + Inline auto h_(const coord_t& x) const -> real_t { + static_assert(i > 0 && i <= 3, "Invalid index i"); + static_assert(j > 0 && j <= 3, "Invalid index j"); + + const real_t r_ { eta2r(x[0] * d_eta + eta_min) }; + const real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; + const real_t Sigma_ { Sigma(r_, theta_) }; + const real_t Delta_ { Delta(r_) }; + if constexpr (i == 1 && j == 1) { + // h_11 + return SQR(d_eta) * Sigma_ * Delta_; + } else if constexpr (i == 2 && j == 2) { + // h_22 + return Sigma_ / SQR(dpsi_dtheta(r_, theta_) ) ; + } else if constexpr (i == 3 && j == 3) { + // h_33 + return A(r_, theta_) * SQR(math::sin(theta_)) / Sigma_; + }else { + return ZERO; + } + } + + /** + * metric component with upper indices: h^ij + * @param x coordinate array in code units + */ + template + Inline auto h(const coord_t& x) const -> real_t { + static_assert(i > 0 && i <= 3, "Invalid index i"); + static_assert(j > 0 && j <= 3, "Invalid index j"); + + if constexpr (i == j) { + return ONE / h_(x); + }else { + return ZERO; + } + } + + /** + * sqrt(det(h_ij)) + * @param x coordinate array in code units + */ + Inline auto sqrt_det_h(const coord_t& x) const -> real_t { + return math::sqrt(h_<1, 1>(x) * h_<2, 2>(x) * h_<3, 3>(x)); + } + + /** + * coordinate conversions + */ + template + Inline void convert(const coord_t& x_in, coord_t& x_out) const { + static_assert(in != out, "Invalid coordinate conversion"); + static_assert((in != Crd::XYZ) && + (out != Crd::XYZ), + "Invalid coordinate conversion: XYZ not allowed in GR"); + if constexpr (in == Crd::Cd && (out == Crd::Sph || out == Crd::Ph)){ + // code -> sph/phys + x_out[0] = eta2r(x_in[0] * d_eta + eta_min); + }else if constexpr ((in == Crd::Sph || in == Crd::Ph) && out == Crd::Cd){ + //sph/phys -> code + x_out[0] = (r2eta(x_in[0]) - eta_min) / d_eta; + } + } + + + /** + * component wise vector transformations + */ + template + Inline auto transform(const coord_t& x, + const real_t& v_in) const -> real_t { + static_assert(in != out, "Invalid vector transformation"); + static_assert(in != Idx::XYZ && out != Idx::XYZ, + "Invalid vector transformation: XYZ not allowed in GR"); + static_assert(i > 0 && i <= 3, "Invalid index i"); + if constexpr ((in == Idx::T && out == Idx::Sph) || + (in == Idx::Sph && out == Idx::T)) { + // tetrad <-> sph + return v_in; + } else if constexpr (((in == Idx::T || in == Idx::Sph) && out == Idx::U) || + (in == Idx::D && (out == Idx::T || out == Idx::Sph))){ + // tetrad/sph -> cntrv ; cov -> tetrad/sph + if constexpr (i == 1){ + return v_in / math::sqrt(h_(x)) / Delta(eta2r(x[0] * d_eta + eta_min)); + }else if constexpr (i == 2){ + return v_in / math::sqrt(h_(x)) * + dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + }else{ + return v_in / math::sqrt(h_(x)); + } + } else if constexpr ((in == Idx::U && (out == Idx::T || out == Idx::Sph)) || + ((in == Idx::T || in == Idx::Sph) && out == Idx::D)){ + // cntrv -> tetrad/sph ; tetrad/sph -> cov + if constexpr (i == 1){ + return v_in * math::sqrt(h_(x)) * Delta(eta2r(x[0] * d_eta + eta_min)); + }else if constexpr (i == 2){ + return v_in * math::sqrt(h_(x)) / + dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + }else{ + return v_in * math::sqrt(h_(x)); + } + } else if constexpr (in == Idx::U && out == Idx::D) { + // cntrv -> cov + return v_in * h_(x); + } else if constexpr (in == Idx::D && out == Idx::U) { + // cov -> cntrv + return v_in * h(x); + } else if constexpr ((in == Idx::U && out == Idx::PU) || + (in == Idx::PD && out == Idx::D)) { + // cntrv -> phys cntrv || phys cov -> cov + if constexpr (i == 1){ + return v_in * Delta(eta2r(x[0] * d_eta + eta_min)) * d_eta ; + }else if constexpr (i == 2){ + return v_in / dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min) ); + }else{ + return v_in; + } + } else if constexpr ((in == Idx::PU && out == Idx::U) || + (in == Idx::D && out == Idx::PD)) { + // phys cntrv -> cntrv || cov -> phys cov + if constexpr (i == 1){ + return v_in * d_eta_inv / Delta(eta2r(x[0] * d_eta + eta_min)); + }else if constexpr (i == 2){ + return v_in * dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + }else{ + return v_in; + } + } else { + raise::KernelError(HERE, "Invalid transformation"); + } + } + + /** + * full vector transformations + */ + template + Inline void transform(const coord_t& xi, + const vec_t& v_in, + vec_t& v_out) const { + static_assert(in != out, "Invalid vector transformation"); + if constexpr (in != Idx::XYZ && out != Idx::XYZ) { + v_out[0] = transform<1, in, out>(xi, v_in[0]); + v_out[1] = transform<2, in, out>(xi, v_in[1]); + v_out[2] = transform<3, in, out>(xi, v_in[2]); + } else { + raise::KernelError(HERE, "Invalid vector transformation"); + } + } + + Inline auto r2eta(const real_t& r) const -> real_t{ + return math::log((r - rh_) / (r - rh_m)) / (rh_ - rh_m); + } + + Inline auto eta2theta(const real_t& eta) const -> real_t{ + return theta0; + } + + Inline auto eta2r(const real_t& eta) const -> real_t{ + return rh_m - TWO * math::sqrt(ONE - SQR(a)) / math::expm1(eta * TWO * math::sqrt(ONE - SQR(a))); + } + }; + + + +} + + +#endif // METRICS_FLUX_SURFACE_H diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/fs.cpp new file mode 100644 index 000000000..0299b2b42 --- /dev/null +++ b/src/metrics/tests/fs.cpp @@ -0,0 +1,187 @@ +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" + +#include "metrics/flux_surface.h" + +#include +#include +#include +#include + +void errorIf(bool condition, const std::string& message) { + if (condition) { + throw std::runtime_error(message); + } +} + +inline static constexpr auto epsilon = std::numeric_limits::epsilon(); + +template +Inline auto equal(const vec_t& a, + const vec_t& b, + const char* msg, + const real_t acc = ONE) -> bool { + const auto eps = epsilon * acc; + for (unsigned short d = 0; d < D; ++d) { + if (not cmp::AlmostEqual(a[d], b[d], eps)) { + printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); + return false; + } + } + return true; +} + +Inline auto equal(const real_t& a, + const real_t& b, + const char* msg, + const real_t acc = ONE) -> bool { + const auto eps = epsilon * acc; + if (not cmp::AlmostEqual(a, b, eps)) { + printf("%.12e != %.12e %s\n", a, b, msg); + return false; + } + return true; +} + +template +Inline void unravel(std::size_t idx, + tuple_t& ijk, + const tuple_t& res) { + for (unsigned short d = 0; d < D; ++d) { + ijk[d] = idx % res[d]; + idx /= res[d]; + } +} + +template +void testMetric(const std::vector& res, + const boundaries_t& ext, + const real_t acc = ONE, + const std::map& params = {}) { + static_assert(M::Dim == 1, "Dim != 1"); + errorIf(res.size() != (std::size_t)(M::Dim), "res.size() != M.dim"); + errorIf(ext.size() != (std::size_t)(M::Dim), "ext.size() != M.dim"); + for (const auto& e : ext) { + errorIf(e.first >= e.second, "e.first >= e.second"); + } + + M metric(res, ext, params); + tuple_t res_tup; + std::size_t npts = 1; + for (auto d = 0; d < M::Dim; ++d) { + res_tup[d] = res[d]; + npts *= res[d]; + } + + const auto x_min = ext[0].first; + const auto x_max = ext[0].second; + + + unsigned long all_wrongs = 0; + const auto rg = metric.rg(); + const auto rh = metric.rhorizon(); + const auto a = metric.spin(); + const auto th = params.at("theta0"); + const auto psi0 = params.at("psi0"); + const auto pCur = params.at("pCur"); + const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); + const auto rh_m = rh - TWO * math::sqrt(ONE - SQR(a)); + + const auto eta_min = math::log((x_min - rh) / (x_min - rh_m)) / (rh - rh_m); + const auto eta_max = math::log((x_max - rh) / (x_max - rh_m)) / (rh - rh_m); + const auto d_eta = (eta_max - eta_min) / ((real_t)res[0]); + + Kokkos::parallel_reduce( + "h_ij/hij", + npts, + Lambda(index_t n, unsigned long& wrongs) { + tuple_t idx; + unravel(n, idx, res_tup); + coord_t x_Code { ZERO }; + coord_t x_Phys { ZERO }; + + for (unsigned short d = 0; d < M::Dim; ++d) { + x_Code[d] = (real_t)(idx[d]) + HALF; + } + + const auto h11 = metric.template h<1, 1>(x_Code); + const auto h22 = metric.template h<2, 2>(x_Code); + const auto h33 = metric.template h<3, 3>(x_Code); + const auto h_11 = metric.template h_<1, 1>(x_Code); + const auto h_22 = metric.template h_<2, 2>(x_Code); + const auto h_33 = metric.template h_<3, 3>(x_Code); + + metric.template convert(x_Code, x_Phys); + const auto r = x_Phys[0]; + + + const auto Sigma = SQR(r) + SQR(a * math::cos(th)); + const auto Delta = SQR(r) - TWO * rg * r + SQR(a); + const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th)) * Delta; + const auto dpsi_r = 0; + const auto dpsi_dtheta = psi0 * math::sin(th); + const auto omega = TWO * a * r / A ; + + const auto h_11_expect = Sigma / Delta; + const auto h_22_expect = Sigma ; + const auto h_33_expect = A * SQR(math::sin(th)) / Sigma; + const auto h11_expect = ONE / h_11_expect; + const auto h22_expect = ONE / h_22_expect; + const auto h33_expect = ONE / h_33_expect; + + const auto f0_expect = h_33_expect * SQR(Omega - omega); + const auto f1_expect = d_eta * A * pCur * math::sin(th) * (Omega - omega) / dpsi_dtheta; + const auto f2_expect = SQR(d_eta) * Sigma * (Delta + A * SQR(pCur / dpsi_dtheta)); + + const auto f0_predict = metric.f0(x_Code); + const auto f1_predict = metric.f1(x_Code); + const auto f2_predict = metric.f2(x_Code); + + + vec_t hij_temp { ZERO }, hij_predict { ZERO }; + metric.template transform(x_Code, { h11, h22, h33 }, hij_temp); + metric.template transform(x_Code, hij_temp, hij_predict); + + + + vec_t hij_expect { h11_expect, h22_expect, h33_expect }; + + wrongs += not equal(hij_expect, hij_predict, "hij", acc); + wrongs += not equal(f0_expect, f0_predict, "f0", acc); + wrongs += not equal(f1_expect, f1_predict, "f1", acc); + wrongs += not equal(f2_expect, f2_predict, "f2", acc); + + }, + all_wrongs); + + errorIf(all_wrongs != 0, + "wrong h_ij/hij for " + std::to_string(M::Dim) + "D " + + std::string(metric.Label) + " with " + std::to_string(all_wrongs) + + " errors"); +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + using namespace metric; + testMetric>( + { 128 }, + { { 2.0, 50.0 } }, + 30, + { { "a", (real_t)0.95 } , + { "psi0", (real_t)1.0 } , + { "theta0", (real_t)1.0 } , + { "Omega", (real_t)0.5 } , + { "pCur", (real_t)3.1 } }); + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} From c6ef138973cc17479c440e53759c7227b3e7ce93 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 26 Jul 2024 11:35:50 +0800 Subject: [PATCH 22/47] minor edit --- src/global/enums.h | 16 ++++++++++------ src/kernels/tests/CMakeLists.txt | 1 + src/metrics/tests/CMakeLists.txt | 3 ++- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/global/enums.h b/src/global/enums.h index 2dc492dac..1cb8129a6 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -2,9 +2,10 @@ * @file enums.h * @brief Special enum variables describing the simulation * @implements - * - enum ntt::Coord // Cart, Sph, Qsph + * - enum ntt::Coord // Cart, Sph, Qsph, Fs * - enum ntt::Metric // Minkowski, Spherical, QSpherical, - * Kerr_Schild, QKerr_Schild, Kerr_Schild_0 + * Kerr_Schild, QKerr_Schild, Kerr_Schild_0, + * Flux_Surface * - enum ntt::SimEngine // SRPIC, GRPIC * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync @@ -138,8 +139,8 @@ namespace ntt { constexpr Coord(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { Cart, Sph, Qsph }; - static constexpr const char* lookup[] = { "cart", "sph", "qsph" }; + static constexpr type variants[] = { Cart, Sph, Qsph, Fs}; + static constexpr const char* lookup[] = { "cart", "sph", "qsph", "fs" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; @@ -154,16 +155,19 @@ namespace ntt { Kerr_Schild = 4, QKerr_Schild = 5, Kerr_Schild_0 = 6, + Flux_Surface = 7, }; constexpr Metric(uint8_t c) : enums_hidden::BaseEnum { c } {} static constexpr type variants[] = { Minkowski, Spherical, QSpherical, Kerr_Schild, - QKerr_Schild, Kerr_Schild_0 }; + QKerr_Schild, Kerr_Schild_0, + Flux_Surface }; static constexpr const char* lookup[] = { "minkowski", "spherical", "qspherical", "kerr_schild", - "qkerr_schild", "kerr_schild_0" }; + "qkerr_schild", "kerr_schild_0", + "flux_surface" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index e55dbc111..9556a2536 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -29,3 +29,4 @@ gen_test(fields_to_phys) gen_test(prtls_to_phys) gen_test(gca_pusher) gen_test(prtl_bc) +gen_test(ff_pusher) diff --git a/src/metrics/tests/CMakeLists.txt b/src/metrics/tests/CMakeLists.txt index 117cb3295..fe917de0b 100644 --- a/src/metrics/tests/CMakeLists.txt +++ b/src/metrics/tests/CMakeLists.txt @@ -25,4 +25,5 @@ gen_test(vec_trans) gen_test(coord_trans) gen_test(sph-qsph) gen_test(ks-qks) -gen_test(sr-cart-sph) \ No newline at end of file +gen_test(sr-cart-sph) +gen_test(fs) \ No newline at end of file From bf5e3688f624dd0a97c0215839fa2c206a58b75d Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 26 Jul 2024 14:16:11 +0800 Subject: [PATCH 23/47] fix errors in ff_pusher test --- src/kernels/tests/ff_pusher.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 5da755fb0..d6c4154eb 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -215,31 +215,31 @@ void testFFPusher(const std::vector& res, - real_t vp_exp[10] { -0.128080544611002, -0.222571219885845, -0.301212251198582, - -0.358235366733387, -0.387383121052459, -0.382799931574759, - -0.340833052985762, -0.263140267573464, -0.161128753912851, - -0.0604347402410836 }; - real_t vp_e_p_exp[10] { -0.122286881108314, -0.215534929107648, -0.292701135574140, - -0.348028532252193, -0.375337709663405, -0.368984471614021, - -0.325765909536170, -0.248149662916807, -0.148698026244964, - -0.0538237879835971 }; - real_t vp_e_n_exp[10] { -0.133874207868050, -0.229607510251248, -0.309723366124719, - -0.368442200032320, -0.399428530458386, -0.396615388297603, - -0.355900191451829, -0.278130865433766, -0.173559474415594, - -0.0670456885818427 }; + real_t vp_exp[10] { -0.00101477428313248, -0.00176341809594538, -0.00238648615376442, + -0.00283827679351036, -0.00306921265956161, -0.00303290033101228, + -0.00270039933123280, -0.00208484416740382, -0.00127661321429062, + -0.000478820732615589 }; + real_t vp_e_p_exp[10] { -0.000968871443278805, -0.00170766999655962, -0.00231905310776449, + -0.00275740867122713, -0.00297377760543621, -0.00292344129084046, + -0.00258102327970717, -0.00196607452803054, -0.00117812532296952, + -0.000426442564188143 }; + real_t vp_e_n_exp[10] { -0.00106067712103997, -0.00181916619206061, -0.00245391919423174, + -0.00291914490642661, -0.00316464769797483, -0.00314235934553045, + -0.00281977534327427, -0.00220361375292999, -0.00137510104884271, + -0.000531198870011043 }; unsigned int wrongs { 0 }; for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(ux1_(n), vp_exp[n], "no efield", acc); + wrongs += !equal(ux1_(n), vp_exp[n] * d_eta_inv, "no efield", acc); } for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(ux1_(n + 10), vp_e_p_exp[n], "positive charge", acc); + wrongs += !equal(ux1_(n + 10), vp_e_p_exp[n] * d_eta_inv, "positive charge", acc); } for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(ux1_(n + 20), vp_e_n_exp[n], "negative charge", acc); + wrongs += !equal(ux1_(n + 20), vp_e_n_exp[n] * d_eta_inv, "negative charge", acc); } if (wrongs){ From d108c55f02e5f6187c870fa472b8b1d87dff2947 Mon Sep 17 00:00:00 2001 From: Yangyang Cai <151660448+StaticObserver@users.noreply.github.com> Date: Fri, 2 Aug 2024 21:57:33 +0800 Subject: [PATCH 24/47] Update metadomain.cpp --- src/framework/domain/metadomain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 86a9420fd..584bfa551 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -375,7 +375,7 @@ namespace ntt { template void Metadomain::metricCompatibilityCheck() const { const auto dx_min = g_mesh.metric.dxMin(); - auto dx_min_from_domains = INFINITY; + auto dx_min_from_domains = std::numeric_limits::infinity(); for (unsigned int idx { 0 }; idx < g_ndomains; ++idx) { const auto& current_domain = g_subdomains[idx]; const auto current_dx_min = current_domain.mesh.metric.dxMin(); From 15d81763f61119aca092be43e0dbb4f4b17791b3 Mon Sep 17 00:00:00 2001 From: Yangyang Cai <151660448+StaticObserver@users.noreply.github.com> Date: Sun, 4 Aug 2024 10:04:51 +0800 Subject: [PATCH 25/47] Update enums.h --- src/global/enums.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/global/enums.h b/src/global/enums.h index 1cb8129a6..23a5bf43b 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -135,6 +135,7 @@ namespace ntt { Cart = 1, Sph = 2, Qsph = 3, + Fs = 4, }; constexpr Coord(uint8_t c) : enums_hidden::BaseEnum { c } {} From 04134b5387315673b7846e2ecac6554347cc7237 Mon Sep 17 00:00:00 2001 From: Yangyang Cai <151660448+StaticObserver@users.noreply.github.com> Date: Sun, 4 Aug 2024 10:07:20 +0800 Subject: [PATCH 26/47] Update particle_pusher_1D_gr.hpp --- src/kernels/particle_pusher_1D_gr.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index 08400070d..c0b7d27a6 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -217,12 +217,12 @@ namespace kernel::gr { // find midpoint values vp_mid = 0.5 * (vp + vp_upd); // find updated velociity - vp_upd = compute_u0_inv(vp_rlx, xp) * vp / compute_u0_inv(vp, xp) + - (( compute_u0_inv(vp_rlx,xp) / compute_u0_inv(vp, xp) - ONE) * metric.f1(xp) + - dt * (coeff * ex * compute_u0_inv(vp_rlx, xp) + + vp_upd = compute_u0_inv(vp_mid, xp) * vp / compute_u0_inv(vp, xp) + + (( compute_u0_inv(vp_mid, xp) / compute_u0_inv(vp, xp) - ONE) * metric.f1(xp) + + dt * (coeff * ex * compute_u0_inv(vp_mid, xp) + (-metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + - HALF * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp_rlx) + - TWO * DERIVATIVE(metric.f1, xp[0]) * vp_rlx + + HALF * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp_mid) + + TWO * DERIVATIVE(metric.f1, xp[0]) * vp_mid + DERIVATIVE(metric.f0, xp[0])) ) ) From 293550a5c47f2af1db3c0ee69d7a7c34d75208e7 Mon Sep 17 00:00:00 2001 From: Yangyang Cai <151660448+StaticObserver@users.noreply.github.com> Date: Sun, 4 Aug 2024 10:18:10 +0800 Subject: [PATCH 27/47] Update enums.cpp --- src/global/tests/enums.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 81e63d57a..ad6233ea8 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -55,9 +55,9 @@ auto main() -> int { using enum_str_t = const std::vector; - enum_str_t all_coords = { "cart", "sph", "qsph" }; + enum_str_t all_coords = { "cart", "sph", "qsph", "fs" }; enum_str_t all_metrics = { "minkowski", "spherical", "qspherical", - "kerr_schild", "qkerr_schild", "kerr_schild_0" }; + "kerr_schild", "qkerr_schild", "kerr_schild_0", "flux_surface" }; enum_str_t all_simulation_engines = { "srpic", "grpic" }; enum_str_t all_particle_bcs = { "periodic", "absorb", "atmosphere", "custom", "reflect", "horizon", "axis", "sync" }; From a117c3ac7902e812cf951121da8f22cfe1633396 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Wed, 21 Aug 2024 13:14:51 +0800 Subject: [PATCH 28/47] step_forward() for 1d grpic --- src/engines/grpic.hpp | 147 +++++++++++++++++++++++++++++++++++++- src/global/enums.h | 13 ++-- src/kernels/ampere_gr.hpp | 46 ++++++++++++ 3 files changed, 198 insertions(+), 8 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 148c1c5c5..fd779f0d5 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -13,12 +13,32 @@ #define ENGINES_GRPIC_GRPIC_H #include "enums.h" +#include "global.h" +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/log.h" +#include "utils/numeric.h" #include "utils/timer.h" +#include "archetypes/particle_injector.h" #include "framework/domain/domain.h" +#include "framework/parameters.h" #include "engines/engine.hpp" +#include "kernels/ampere_gr.hpp" +#include "kernels/currents_deposit.hpp" +#include "kernels/digital_filter.hpp" +#include "kernels/fields_bcs.hpp" +#include "kernels/particle_moments.hpp" +#include "kernels/particle_pusher_1D_gr.hpp" +#include "pgen.hpp" + +#include +#include + +#include +#include namespace ntt { @@ -27,6 +47,8 @@ namespace ntt { using Engine::m_params; using Engine::m_metadomain; + auto constexpr D { M::Dim }; + public: static constexpr auto S { SimEngine::SRPIC }; @@ -35,8 +57,129 @@ namespace ntt { ~GRPICEngine() = default; - void step_forward(timer::Timers&, Domain&) override {} - }; + void step_forward(timer::Timers&, Domain&) override { + static_assert(D == Dim::1D, "GRPIC only supports 1D simulations"); + const auto fieldsolver_enabled = m_params.template get( + "algorithms.toggles.fieldsolver"); + const auto deposit_enabled = m_params.template get( + "algorithms.toggles.deposit"); + const auto sort_interval = m_params.template get( + "particles.sort_interval"); + + if (step == 0) { + // communicate fields and apply BCs on the first timestep + m_metadomain.CommunicateFields(dom, Comm::E); + FieldBoundaries(dom, BC::E); + ParticleInjector(dom); + } + + { + timers.start("ParticlePusher"); + ParticlePush(dom); + timers.stop("ParticlePusher"); + + if (deposit_enabled) { + timers.start("CurrentDeposit"); + Kokkos::deep_copy(dom.fields.cur, ZERO); + CurrentsDeposit(dom); + timers.stop("CurrentDeposit"); + + timers.start("Communications"); + m_metadomain.SynchronizeFields(dom, Comm::J); + m_metadomain.CommunicateFields(dom, Comm::J); + timers.stop("Communications"); + + timers.start("CurrentFiltering"); + CurrentsFilter(dom); + timers.stop("CurrentFiltering"); + } + + timers.start("Communications"); + if ((sort_interval > 0) and (step % sort_interval == 0)) { + m_metadomain.CommunicateParticles(dom, &timers); + } + timers.stop("Communications"); + } + + if (fieldsolver_enabled) { + + if (deposit_enabled) { + timers.start("FieldSolver"); + CurrentsAmpere(dom); + timers.stop("FieldSolver"); + } + + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::E | Comm::J); + timers.stop("Communications"); + + timers.start("FieldBoundaries"); + FieldBoundaries(dom, BC::E); + timers.stop("FieldBoundaries"); + } + + { + timers.start("Injector"); + ParticleInjector(dom); + timers.stop("Injector"); + } + } + + void FieldBoundaries(domain_t& domain, BCTags tags) {} + + void ParticleInjector(domain_t& domain, InjTags tags = Inj::None) {} + + void ParticlePush(domain_t& domain) { + for (auto& species : domain.species) { + species.set_unsorted(); + logger::Checkpoint( + fmt::format("Launching particle pusher kernel for %d [%s] : %lu", + species.index(), + species.label().c_str(), + species.npart()), + HERE); + if (species.npart() == 0) { + continue; + } + const auto q_ovr_m = species.mass() > ZERO + ? species.charge() / species.mass() + : ZERO; + // coeff = q / m (dt / 2) omegaB0 + const auto coeff = q_ovr_m * HALF * dt * + m_params.template get("scales.omegaB0"); + PrtlPusher::type pusher; + if (species.pusher() == PrtlPusher::FORCEFREE) { + pusher = PrtlPusher::FORCEFREE; + } else { + raise::Fatal("Invalid particle pusher", HERE); + } + // clang-format off + Kokkos::parallel_for( + "ParticlePusher", + species.rangeActiveParticles(), + kernel::gr::Pusher_kernel>( + efield, + i1, + i1_prev, + dx1, + dx1_prev, + ux1, + tag, + metric, + coeff, dt, + nx1, + 1e-5, + 15, + boundaries)); + } + } + + void CurrentsDeposit(domain_t& domain) {} + + void CurrentsFilter(domain_t& domain) {} + + void CurrentsAmpere(domain_t& domain) {} +}; } // namespace ntt diff --git a/src/global/enums.h b/src/global/enums.h index 1cb8129a6..ff733b436 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -243,18 +243,19 @@ namespace ntt { static constexpr const char* label = "prtl_pusher"; enum type : uint8_t { - INVALID = 0, - BORIS = 1, - VAY = 2, - PHOTON = 3, - NONE = 4, + INVALID = 0, + BORIS = 1, + VAY = 2, + PHOTON = 3, + FORCEFREE = 4 + NONE = 5, }; constexpr PrtlPusher(uint8_t c) : enums_hidden::BaseEnum { c } {} static constexpr type variants[] = { BORIS, VAY, PHOTON, NONE }; - static constexpr const char* lookup[] = { "boris", "vay", "photon", "none" }; + static constexpr const char* lookup[] = { "boris", "vay", "photon", "forcefree", "none"}; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 5af0fa4ef..7a74c610d 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -182,6 +182,52 @@ namespace kernel::gr { } }; + /** + * @brief Ampere's law for only 1D-GRPIC. + */ + template + class Ampere_kernel_1D { + static constexpr auto D = M::Dim; + + ndfield_t Df; + const ndfield_t J; + const ndfield_t J_ff; + const M metric; + const real_t coeff; + + + public: + /** + * @brief Constructor. + * @param mblock Meshblock. + */ + Ampere_kernel_1D(const ndfield_t & Df, + const ndfield_t& J, + const ndfield_t J_ff, + const M& metric, + real_t coeff) + : Df { Df } + , J { J } + , metric { metric } + , coeff { coeff } { + } + + Inline void operator()(index_t i1) const { + if constexpr (D == Dim::_1D) { + const real_t i1_ { COORD(i1) }; + + const real_t inv_sqrt_detH { ONE / metric.sqrt_det_h(i1_ + HALF) }; + + Df(i1, em::dx1) += (J(i1, cur::jx1) - J_ff(i1, cur::jx1)) * coeff * inv_sqrt_detH; + } else { + raise::KernelError( + HERE, + "CurrentsAmpere_kernel: 1D implementation called for D != 1"); + } + } + }; + + } // namespace kernel::gr #endif // KERNELS_AMPERE_GR_HPP From cc62f7c56d9622532cd87e90ee02b1a91baecf66 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 30 Aug 2024 21:12:21 +0800 Subject: [PATCH 29/47] 1d grpic engine update --- src/engines/grpic.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 148c1c5c5..f55d48701 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -28,7 +28,7 @@ namespace ntt { using Engine::m_metadomain; public: - static constexpr auto S { SimEngine::SRPIC }; + static constexpr auto S { SimEngine::GRPIC }; GRPICEngine(SimulationParams& params) : Engine { params } {} @@ -40,4 +40,8 @@ namespace ntt { } // namespace ntt + + + + #endif // ENGINES_GRPIC_GRPIC_H From 5c3376bdb6f27a9855c3fa343c450d291485fc1c Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 6 Sep 2024 09:43:21 +0800 Subject: [PATCH 30/47] updated grpic.hpp --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index fd779f0d5..5ed3d9b4e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -50,7 +50,7 @@ namespace ntt { auto constexpr D { M::Dim }; public: - static constexpr auto S { SimEngine::SRPIC }; + static constexpr auto S { SimEngine::GRPIC }; GRPICEngine(SimulationParams& params) : Engine { params } {} From 71420257280f4df1a3d8a87355b2de6d958b7c00 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Wed, 25 Sep 2024 14:45:19 +0800 Subject: [PATCH 31/47] engine updated --- src/engines/grpic.hpp | 73 +++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 5ed3d9b4e..7a6f47cba 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -58,27 +58,22 @@ namespace ntt { ~GRPICEngine() = default; void step_forward(timer::Timers&, Domain&) override { - static_assert(D == Dim::1D, "GRPIC only supports 1D simulations"); - const auto fieldsolver_enabled = m_params.template get( - "algorithms.toggles.fieldsolver"); - const auto deposit_enabled = m_params.template get( - "algorithms.toggles.deposit"); - const auto sort_interval = m_params.template get( - "particles.sort_interval"); - - if (step == 0) { - // communicate fields and apply BCs on the first timestep - m_metadomain.CommunicateFields(dom, Comm::E); - FieldBoundaries(dom, BC::E); - ParticleInjector(dom); - } + static_assert(D == Dim::1D, "GRPIC now only supports 1D simulations"); + const auto sort_interval = m_params.template get( + "particles.sort_interval"); + + if (step == 0) { + // communicate fields and apply BCs on the first timestep + m_metadomain.CommunicateFields(dom, Comm::E); + FieldBoundaries(dom, BC::E); + ParticleInjector(dom); + } - { - timers.start("ParticlePusher"); - ParticlePush(dom); - timers.stop("ParticlePusher"); + { + timers.start("ParticlePusher"); + ParticlePush(dom); + timers.stop("ParticlePusher"); - if (deposit_enabled) { timers.start("CurrentDeposit"); Kokkos::deep_copy(dom.fields.cur, ZERO); CurrentsDeposit(dom); @@ -92,37 +87,33 @@ namespace ntt { timers.start("CurrentFiltering"); CurrentsFilter(dom); timers.stop("CurrentFiltering"); - } - timers.start("Communications"); - if ((sort_interval > 0) and (step % sort_interval == 0)) { - m_metadomain.CommunicateParticles(dom, &timers); + timers.start("Communications"); + if ((sort_interval > 0) and (step % sort_interval == 0)) { + m_metadomain.CommunicateParticles(dom, &timers); + } + timers.stop("Communications"); } - timers.stop("Communications"); - } - - if (fieldsolver_enabled) { - if (deposit_enabled) { + { timers.start("FieldSolver"); CurrentsAmpere(dom); timers.stop("FieldSolver"); - } - timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::E | Comm::J); - timers.stop("Communications"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::E | Comm::J); + timers.stop("Communications"); - timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::E); - timers.stop("FieldBoundaries"); - } + timers.start("FieldBoundaries"); + FieldBoundaries(dom, BC::E); + timers.stop("FieldBoundaries"); + } - { - timers.start("Injector"); - ParticleInjector(dom); - timers.stop("Injector"); - } + { + timers.start("Injector"); + ParticleInjector(dom); + timers.stop("Injector"); + } } void FieldBoundaries(domain_t& domain, BCTags tags) {} From 76db7e4dbb1a383bf67c7d2e5c792234f09d9be8 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Thu, 10 Oct 2024 21:36:03 +0800 Subject: [PATCH 32/47] change flux_surface to boyer_lindq_tp and update; updated 1d grpic pusher --- src/global/enums.h | 13 +-- src/kernels/particle_pusher_1D_gr.hpp | 62 ++++++------- src/kernels/tests/ff_pusher.cpp | 26 +++--- .../{flux_surface.h => boyer_lindq_tp.h} | 92 ++++++++----------- 4 files changed, 89 insertions(+), 104 deletions(-) rename src/metrics/{flux_surface.h => boyer_lindq_tp.h} (77%) diff --git a/src/global/enums.h b/src/global/enums.h index ff733b436..9520d47df 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -135,12 +135,13 @@ namespace ntt { Cart = 1, Sph = 2, Qsph = 3, + Bltp = 4, }; constexpr Coord(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { Cart, Sph, Qsph, Fs}; - static constexpr const char* lookup[] = { "cart", "sph", "qsph", "fs" }; + static constexpr type variants[] = { Cart, Sph, Qsph, Bltp}; + static constexpr const char* lookup[] = { "cart", "sph", "qsph", "bltp" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; @@ -155,7 +156,7 @@ namespace ntt { Kerr_Schild = 4, QKerr_Schild = 5, Kerr_Schild_0 = 6, - Flux_Surface = 7, + BoyerLindqTP = 7, }; constexpr Metric(uint8_t c) : enums_hidden::BaseEnum { c } {} @@ -163,11 +164,11 @@ namespace ntt { static constexpr type variants[] = { Minkowski, Spherical, QSpherical, Kerr_Schild, QKerr_Schild, Kerr_Schild_0, - Flux_Surface }; + BoyerLindqTP }; static constexpr const char* lookup[] = { "minkowski", "spherical", "qspherical", "kerr_schild", "qkerr_schild", "kerr_schild_0", - "flux_surface" }; + "boyer_lindq_tp" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; @@ -247,7 +248,7 @@ namespace ntt { BORIS = 1, VAY = 2, PHOTON = 3, - FORCEFREE = 4 + FORCEFREE = 4, NONE = 5, }; diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index 08400070d..077973442 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -66,7 +66,7 @@ namespace kernel::gr { array_t i1_prev; array_t dx1; array_t dx1_prev; - array_t ux1; + array_t px1; array_t tag; const M metric; @@ -85,7 +85,7 @@ namespace kernel::gr { const array_t& i1_prev, const array_t& dx1, const array_t& dx1_prev, - const array_t& ux1, + const array_t& px1, const array_t& tag, const M& metric, const real_t& coeff, @@ -99,7 +99,7 @@ namespace kernel::gr { , i1_prev { i1_prev } , dx1 { dx1 } , dx1_prev { dx1_prev } - , ux1 { ux1 } + , px1 { px1 } , tag { tag } , metric { metric } , coeff { coeff } @@ -134,9 +134,9 @@ namespace kernel::gr { * @param vp_upd updated particle velocity [return]. */ Inline void ForceFreePush( const coord_t& xp, - const real_t& vp, + const real_t& pp, const real_t& ex, - real_t& vp_upd) const; + real_t& pp_upd) const; /** * @brief Iterative geodesic pusher substep for coordinate only. @@ -168,10 +168,10 @@ namespace kernel::gr { * @brief Compute controvariant component u^0 for massive particles. */ - Inline auto compute_u0_inv(const real_t& v, + Inline auto compute_u0(const real_t& pxi, const coord_t& xi) const -> real_t{ - return math::sqrt(math::abs(SQR(metric.alpha(xi)) - - metric.f2(xi) * SQR(v) - TWO * metric.f1(xi) * v - metric.f0(xi))) ; + return math::sqrt((SQR(pxi) + metric.f2(xi)) / + (metric.f2(xi) * (SQR(metric.alpha(xi)) - metric.f1(xi)) + SQR(metric.f1(xi)))); } @@ -201,32 +201,30 @@ namespace kernel::gr { */ template Inline void Pusher_kernel::ForceFreePush( const coord_t& xp, - const real_t& vp, - const real_t& ex, - real_t& vp_upd) const { + const real_t& pp, + const real_t& ex, + real_t& pp_upd) const { - real_t vp_mid { vp }; + real_t pp_mid { pp }; + pp_upd = pp; - vp_upd = vp; - real_t weight = 0.5; - //printf("Iteration starts.\n"); for (auto i { 0 }; i < niter; ++i) { // find midpoint values - vp_mid = 0.5 * (vp + vp_upd); - // find updated velociity - vp_upd = compute_u0_inv(vp_rlx, xp) * vp / compute_u0_inv(vp, xp) + - (( compute_u0_inv(vp_rlx,xp) / compute_u0_inv(vp, xp) - ONE) * metric.f1(xp) + - dt * (coeff * ex * compute_u0_inv(vp_rlx, xp) + - (-metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + - HALF * (DERIVATIVE(metric.f2, xp[0]) * SQR(vp_rlx) + - TWO * DERIVATIVE(metric.f1, xp[0]) * vp_rlx + - DERIVATIVE(metric.f0, xp[0])) - ) - ) - ) / metric.f2(xp); + pp_mid = 0.5 * (pp + pp_upd); + + // find updated momentum + pp_upd = pp + + dt * (ex + + HALF * compute_u0(pp_mid, xp) * + (-DERIVATIVE(metric.alpha, xp[0]) + + DERIVATIVE(metirc.f2, xp[0]) * SQR((pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp)) + + TWO * DERIVATIVE(metric.f1, xp[0]) * (pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp) + + DERIVATIVE(metric.f0, xp[0]) + ) + ); } } @@ -261,19 +259,19 @@ template real_t ep_cntrv { metric.alpha(xp) * metric.template transform<1, Idx::U, Idx::D>(xp, Dp_cntrv) }; - real_t vp { ux1(p) }; + real_t pp { ux1(p) }; /* -------------------------------- Leapfrog -------------------------------- */ /* u_i(n - 1/2) -> u_i(n + 1/2) */ - real_t vp_upd { ZERO }; + real_t pp_upd { ZERO }; - ForceFreePush(xp, vp, ep_cntrv, vp_upd); + ForceFreePush(xp, pp, ep_cntrv, pp_upd); /* x^i(n) -> x^i(n + 1) */ coord_t xp_upd { ZERO }; - CoordinatePush(xp, vp_upd, xp_upd); + CoordinatePush(xp, (pp_upd / compute_u0(pp_upd, xp) - metric.f1(xp)) / metric.f2(xp), xp_upd); /* update coordinate */ int i1_; @@ -283,7 +281,7 @@ template dx1(p) = dx1_; /* update velocity */ - ux1(p) = vp_upd; + ux1(p) = pp_upd; boundaryConditions(p); diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index d6c4154eb..38f86e3fb 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -101,7 +101,7 @@ void testFFPusher(const std::vector& res, array_t i1_prev { "i1_prev", 30 }; array_t dx1 { "dx1", 30 }; array_t dx1_prev { "dx1_prev", 30 }; - array_t ux1 { "ux1", 30 }; + array_t px1 { "px1", 30 }; array_t tag { "tag", 30 }; const auto sep = real_t { 0.1 * res[0] }; @@ -130,7 +130,7 @@ void testFFPusher(const std::vector& res, from_Xi_to_i_di(x1i, ii, dx1i) put_value(i1, ii, n); put_value(dx1, dx1i, n); - put_value(ux1, -metric.f1({ x1i }) / metric.f2({ x1i }), n); + put_value(px1, ZERO, n); put_value(tag, ParticleTag::alive, n); } @@ -146,7 +146,7 @@ void testFFPusher(const std::vector& res, i1_prev, dx1, dx1_prev, - ux1, + px1, tag, metric, -coeff, dt, @@ -174,7 +174,7 @@ void testFFPusher(const std::vector& res, i1_prev, dx1, dx1_prev, - ux1, + px1, tag, metric, coeff, dt, @@ -193,7 +193,7 @@ void testFFPusher(const std::vector& res, i1_prev, dx1, dx1_prev, - ux1, + px1, tag, metric, -coeff, dt, @@ -210,20 +210,20 @@ void testFFPusher(const std::vector& res, Kokkos::deep_copy(dx1_, dx1); auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); Kokkos::deep_copy(dx1_prev_, dx1_prev); - auto ux1_ = Kokkos::create_mirror_view(ux1); - Kokkos::deep_copy(ux1_, ux1); + auto px1_ = Kokkos::create_mirror_view(px1); + Kokkos::deep_copy(px1_, px1); - real_t vp_exp[10] { -0.00101477428313248, -0.00176341809594538, -0.00238648615376442, + real_t pp_exp[10] { -0.00101477428313248, -0.00176341809594538, -0.00238648615376442, -0.00283827679351036, -0.00306921265956161, -0.00303290033101228, -0.00270039933123280, -0.00208484416740382, -0.00127661321429062, -0.000478820732615589 }; - real_t vp_e_p_exp[10] { -0.000968871443278805, -0.00170766999655962, -0.00231905310776449, + real_t pp_e_p_exp[10] { -0.000968871443278805, -0.00170766999655962, -0.00231905310776449, -0.00275740867122713, -0.00297377760543621, -0.00292344129084046, -0.00258102327970717, -0.00196607452803054, -0.00117812532296952, -0.000426442564188143 }; - real_t vp_e_n_exp[10] { -0.00106067712103997, -0.00181916619206061, -0.00245391919423174, + real_t pp_e_n_exp[10] { -0.00106067712103997, -0.00181916619206061, -0.00245391919423174, -0.00291914490642661, -0.00316464769797483, -0.00314235934553045, -0.00281977534327427, -0.00220361375292999, -0.00137510104884271, -0.000531198870011043 }; @@ -231,15 +231,15 @@ void testFFPusher(const std::vector& res, unsigned int wrongs { 0 }; for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(ux1_(n), vp_exp[n] * d_eta_inv, "no efield", acc); + wrongs += !equal(px1_(n), pp_exp[n] * d_eta_inv, "no efield", acc); } for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(ux1_(n + 10), vp_e_p_exp[n] * d_eta_inv, "positive charge", acc); + wrongs += !equal(px1_(n + 10), pp_e_p_exp[n] * d_eta_inv, "positive charge", acc); } for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(ux1_(n + 20), vp_e_n_exp[n] * d_eta_inv, "negative charge", acc); + wrongs += !equal(px1_(n + 20), pp_e_n_exp[n] * d_eta_inv, "negative charge", acc); } if (wrongs){ diff --git a/src/metrics/flux_surface.h b/src/metrics/boyer_lindq_tp.h similarity index 77% rename from src/metrics/flux_surface.h rename to src/metrics/boyer_lindq_tp.h index d87d81474..3d73e06f4 100644 --- a/src/metrics/flux_surface.h +++ b/src/metrics/boyer_lindq_tp.h @@ -1,16 +1,16 @@ /** - * @file metrics/flux_surface.h - * @brief metric along constant flux surfaces in force-free fields, based on totoised Boyer-Lindquist coordinates + * @file metrics/boyer_lindq_tp.h + * @brief metric along constant flux surfaces in force-free fields, based on totoised Boyer-Lindquist-psi coordinates * @implements - * - metric::FluxSurface<> : metric::MetricBase<> + * - metric::BoyerLindqTP<> : metric::MetricBase<> * @namespaces: * - metric:: * !TODO * None radial surfaces needs to be implemented (dpsi_dr != 0). */ -#ifndef METRICS_FLUX_SURFACE_H -#define METRICS_FLUX_SURFACE_H +#ifndef METRICS_BOYER_LINDQ_TP_H +#define METRICS_BOYER_LINDQ_TP_H #include "enums.h" #include "global.h" @@ -28,14 +28,15 @@ namespace metric { template - class FluxSurface : public MetricBase { - static_assert(D == Dim::_1D, "Only 1D flux_surface is available"); + class BoyerLindqTP : public MetricBase { + static_assert(D == Dim::_1D, "Only 1D boyer_lindq_tp is available"); private: // Spin parameter, in [0,1[ // and horizon size in units of rg // all physical extents are in units of rg - const real_t a, rg_, rh_, rh_m, psi0, theta0, Omega, pCur; + const real_t a, rg_, psi0, th0; + const real_t rh_, rh_m, psi, bt, Omega, dpsi_dth, dbt_dth; const real_t eta_max, eta_min; const real_t d_eta, d_eta_inv; @@ -43,52 +44,47 @@ namespace metric { return SQR(r) - TWO * r + SQR(a); } - Inline auto Sigma(const real_t& r, const real_t& theta) const -> real_t { - return SQR(r) + SQR(a) * SQR(math::cos(theta)); + Inline auto Sigma(const real_t& r) const -> real_t { + return SQR(r) + SQR(a) * SQR(math::cos(th0)); } - Inline auto A(const real_t& r, const real_t& theta) const -> real_t { - return SQR(SQR(r) + SQR(a)) - SQR(a) * Delta(r) * SQR(math::sin(theta)); + Inline auto A(const real_t& r) const -> real_t { + return SQR(SQR(r) + SQR(a)) - SQR(a) * Delta(r) * SQR(math::sin(th0)); } - Inline auto omega(const real_t& r, const real_t& theta) const -> real_t { - return TWO * a * r / A(r, theta); - } - - Inline auto psi(const real_t& r, const real_t& theta) const -> real_t { - return psi0 * (1 - cos(theta)); - } - - - Inline auto dpsi_dtheta(const real_t& r, const real_t& theta) const -> real_t { - return psi0 * math::sin(theta); + Inline auto omega(const real_t& r) const -> real_t { + return TWO * a * r / A(r, th0); } public: - static constexpr const char* Label { "flux_surface" }; + static constexpr const char* Label { "boyer_lindq_tp" }; static constexpr Dimension PrtlDim { D }; - static constexpr ntt::Coord::type CoordType { ntt::Coord::Fs }; - static constexpr ntt::Metric::type MetricType { ntt::Metric::Flux_Surface }; + static constexpr ntt::Coord::type CoordType { ntt::Coord::Bltp }; + static constexpr ntt::Metric::type MetricType { ntt::Metric::BoyerLindqTP }; using MetricBase::x1_min; using MetricBase::x1_max; using MetricBase::nx1; using MetricBase::set_dxMin; - FluxSurface(std::vector res, + BoyerLindqTP(std::vector res, boundaries_t ext, const std::map& params) : MetricBase { res, ext } , a { params.at("a") } , psi0 { params.at("psi0") } - , theta0 { params.at("theta0") } - , pCur { params.at("pCur") } + , th0 { params.at("theta0") } + , bt { params.at("BT") } , rg_ { ONE } , rh_ { ONE + math::sqrt(ONE - SQR(a)) } , rh_m { ONE - math::sqrt(ONE - SQR(a)) } + , psi { psi0 * (1 - math::cos(th0)) } + , bt { -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / Sigma(rh_) } , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh_)) } + , dpsi_dth { -psi0 * math::sin(th0) } + , dbt_dth { -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) / SQR(Sigma(rh_)) } , eta_min { r2eta(x1_min) } , eta_max { r2eta(x1_max) } , d_eta { (eta_max - eta_min) / nx1 } @@ -130,8 +126,7 @@ namespace metric { */ Inline auto alpha(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - return math::sqrt(Sigma(r_, theta_) * Delta(r_) / A(r_, theta_)); + return math::sqrt(Sigma(r) * Delta(r_) / A(r_)); } /** @@ -140,11 +135,11 @@ namespace metric { */ Inline auto beta(const coord_t& xi) const -> real_t { - return math::sqrt(h<3, 3>(xi)) * omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min) ); + return math::sqrt(h<3, 3>(xi)) * omega(eta2r(xi[0] * d_eta + eta_min)); } Inline auto beta3(const coord_t& xi) const -> real_t { - return -omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min)); + return -omega(eta2r(xi[0] * d_eta + eta_min)); } /** @@ -152,16 +147,14 @@ namespace metric { */ Inline auto f2(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - return SQR(d_eta) * Sigma(r_, theta_) * (Delta(r_) + - A(r_, theta_) * SQR(pCur / dpsi_dtheta(r_, theta_) ) + return SQR(d_eta) * Sigma(r_) * (Delta(r_) + + A(r_) * SQR(bt / dpsi_dth ) ); } Inline auto f1(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - return d_eta * A(r_, theta_)* math::sin(theta_) * pCur * (Omega + beta3(xi)) / dpsi_dtheta(r_, theta_); + return d_eta * A(r_)* math::sin(th0) * bt * (Omega + beta3(xi)) / dpsi_dth; } Inline auto f0(const coord_t& xi) const -> real_t { @@ -195,18 +188,15 @@ namespace metric { static_assert(j > 0 && j <= 3, "Invalid index j"); const real_t r_ { eta2r(x[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; - const real_t Sigma_ { Sigma(r_, theta_) }; - const real_t Delta_ { Delta(r_) }; if constexpr (i == 1 && j == 1) { // h_11 - return SQR(d_eta) * Sigma_ * Delta_; + return SQR(d_eta) * Sigma(r_) * Delta(r_); } else if constexpr (i == 2 && j == 2) { // h_22 - return Sigma_ / SQR(dpsi_dtheta(r_, theta_) ) ; + return Sigma(r_) / SQR(dpsi_dth) ; } else if constexpr (i == 3 && j == 3) { // h_33 - return A(r_, theta_) * SQR(math::sin(theta_)) / Sigma_; + return A(r_) * SQR(math::sin(th0)) / Sigma(r_); }else { return ZERO; } @@ -276,7 +266,7 @@ namespace metric { return v_in / math::sqrt(h_(x)) / Delta(eta2r(x[0] * d_eta + eta_min)); }else if constexpr (i == 2){ return v_in / math::sqrt(h_(x)) * - dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + dpsi_dth; }else{ return v_in / math::sqrt(h_(x)); } @@ -287,7 +277,7 @@ namespace metric { return v_in * math::sqrt(h_(x)) * Delta(eta2r(x[0] * d_eta + eta_min)); }else if constexpr (i == 2){ return v_in * math::sqrt(h_(x)) / - dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + dpsi_dth; }else{ return v_in * math::sqrt(h_(x)); } @@ -303,7 +293,7 @@ namespace metric { if constexpr (i == 1){ return v_in * Delta(eta2r(x[0] * d_eta + eta_min)) * d_eta ; }else if constexpr (i == 2){ - return v_in / dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min) ); + return v_in / dpsi_dth; }else{ return v_in; } @@ -313,7 +303,7 @@ namespace metric { if constexpr (i == 1){ return v_in * d_eta_inv / Delta(eta2r(x[0] * d_eta + eta_min)); }else if constexpr (i == 2){ - return v_in * dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); + return v_in * dpsi_dth; }else{ return v_in; } @@ -343,10 +333,6 @@ namespace metric { return math::log((r - rh_) / (r - rh_m)) / (rh_ - rh_m); } - Inline auto eta2theta(const real_t& eta) const -> real_t{ - return theta0; - } - Inline auto eta2r(const real_t& eta) const -> real_t{ return rh_m - TWO * math::sqrt(ONE - SQR(a)) / math::expm1(eta * TWO * math::sqrt(ONE - SQR(a))); } @@ -357,4 +343,4 @@ namespace metric { } -#endif // METRICS_FLUX_SURFACE_H +#endif // METRICS_BOYER_LINDQ_TP_H From 5a8b64a500d860023dabc461ae1488d0c1e9b207 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 11 Oct 2024 10:33:00 +0800 Subject: [PATCH 33/47] updated bltp metric and its tests --- src/metrics/boyer_lindq_tp.h | 9 +++------ src/metrics/tests/{fs.cpp => bltp.cpp} | 25 ++++++++++++------------- 2 files changed, 15 insertions(+), 19 deletions(-) rename src/metrics/tests/{fs.cpp => bltp.cpp} (89%) diff --git a/src/metrics/boyer_lindq_tp.h b/src/metrics/boyer_lindq_tp.h index 3d73e06f4..bc931bde1 100644 --- a/src/metrics/boyer_lindq_tp.h +++ b/src/metrics/boyer_lindq_tp.h @@ -76,7 +76,6 @@ namespace metric { , a { params.at("a") } , psi0 { params.at("psi0") } , th0 { params.at("theta0") } - , bt { params.at("BT") } , rg_ { ONE } , rh_ { ONE + math::sqrt(ONE - SQR(a)) } , rh_m { ONE - math::sqrt(ONE - SQR(a)) } @@ -126,7 +125,7 @@ namespace metric { */ Inline auto alpha(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - return math::sqrt(Sigma(r) * Delta(r_) / A(r_)); + return math::sqrt(Sigma(r_) * Delta(r_) / A(r_)); } /** @@ -147,14 +146,12 @@ namespace metric { */ Inline auto f2(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - return SQR(d_eta) * Sigma(r_) * (Delta(r_) + - A(r_) * SQR(bt / dpsi_dth ) - ); + return SQR(d_eta) * Sigma(r_) * (Delta(r_) + A(r_) * SQR(bt / dpsi_dth )); } Inline auto f1(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - return d_eta * A(r_)* math::sin(th0) * bt * (Omega + beta3(xi)) / dpsi_dth; + return d_eta * A(r_) * bt * (Omega + beta3(xi)) / psi0; } Inline auto f0(const coord_t& xi) const -> real_t { diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/bltp.cpp similarity index 89% rename from src/metrics/tests/fs.cpp rename to src/metrics/tests/bltp.cpp index 0299b2b42..557ba8186 100644 --- a/src/metrics/tests/fs.cpp +++ b/src/metrics/tests/bltp.cpp @@ -3,7 +3,7 @@ #include "arch/kokkos_aliases.h" #include "utils/comparators.h" -#include "metrics/flux_surface.h" +#include "metrics/boyer_lindq_tp.h" #include #include @@ -83,10 +83,12 @@ void testMetric(const std::vector& res, const auto rg = metric.rg(); const auto rh = metric.rhorizon(); const auto a = metric.spin(); - const auto th = params.at("theta0"); + const auto th0 = params.at("theta0"); const auto psi0 = params.at("psi0"); - const auto pCur = params.at("pCur"); + const auto bt = -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / Sigma(rh_); const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); + const auto dpsi_dth = -psi0 * math::sin(th0); + const auto dbt_dth = -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) / SQR(Sigma(rh_)); const auto rh_m = rh - TWO * math::sqrt(ONE - SQR(a)); const auto eta_min = math::log((x_min - rh) / (x_min - rh_m)) / (rh - rh_m); @@ -117,23 +119,21 @@ void testMetric(const std::vector& res, const auto r = x_Phys[0]; - const auto Sigma = SQR(r) + SQR(a * math::cos(th)); + const auto Sigma = SQR(r) + SQR(a * math::cos(th0)); const auto Delta = SQR(r) - TWO * rg * r + SQR(a); - const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th)) * Delta; - const auto dpsi_r = 0; - const auto dpsi_dtheta = psi0 * math::sin(th); + const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th0)) * Delta; const auto omega = TWO * a * r / A ; const auto h_11_expect = Sigma / Delta; const auto h_22_expect = Sigma ; - const auto h_33_expect = A * SQR(math::sin(th)) / Sigma; + const auto h_33_expect = A * SQR(math::sin(th0)) / Sigma; const auto h11_expect = ONE / h_11_expect; const auto h22_expect = ONE / h_22_expect; const auto h33_expect = ONE / h_33_expect; const auto f0_expect = h_33_expect * SQR(Omega - omega); - const auto f1_expect = d_eta * A * pCur * math::sin(th) * (Omega - omega) / dpsi_dtheta; - const auto f2_expect = SQR(d_eta) * Sigma * (Delta + A * SQR(pCur / dpsi_dtheta)); + const auto f1_expect = d_eta * A * bt * (Omega - omega) / psi0; + const auto f2_expect = SQR(d_eta) * Sigma * (Delta + A * SQR(bt / dpsi_dth)); const auto f0_predict = metric.f0(x_Code); const auto f1_predict = metric.f1(x_Code); @@ -170,13 +170,12 @@ auto main(int argc, char* argv[]) -> int { using namespace metric; testMetric>( { 128 }, - { { 2.0, 50.0 } }, + { { 2.0, 20.0 } }, 30, { { "a", (real_t)0.95 } , { "psi0", (real_t)1.0 } , { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } , - { "pCur", (real_t)3.1 } }); + { "Omega", (real_t)0.5 }}); } catch (std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); From de38b911a895c5aa39d9b2057fb45efb7f68a204 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 11 Oct 2024 15:23:39 +0800 Subject: [PATCH 34/47] fix errors --- src/kernels/particle_pusher_1D_gr.hpp | 6 +++--- src/kernels/tests/ff_pusher.cpp | 24 +++++++++++------------- src/metrics/boyer_lindq_tp.h | 12 +++++++----- src/metrics/tests/bltp.cpp | 6 +++--- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index 077973442..fcd7307fe 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -220,7 +220,7 @@ namespace kernel::gr { dt * (ex + HALF * compute_u0(pp_mid, xp) * (-DERIVATIVE(metric.alpha, xp[0]) + - DERIVATIVE(metirc.f2, xp[0]) * SQR((pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp)) + + DERIVATIVE(metric.f2, xp[0]) * SQR((pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp)) + TWO * DERIVATIVE(metric.f1, xp[0]) * (pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp) + DERIVATIVE(metric.f0, xp[0]) ) @@ -259,7 +259,7 @@ template real_t ep_cntrv { metric.alpha(xp) * metric.template transform<1, Idx::U, Idx::D>(xp, Dp_cntrv) }; - real_t pp { ux1(p) }; + real_t pp { px1(p) }; /* -------------------------------- Leapfrog -------------------------------- */ @@ -281,7 +281,7 @@ template dx1(p) = dx1_; /* update velocity */ - ux1(p) = pp_upd; + px1(p) = pp_upd; boundaryConditions(p); diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 38f86e3fb..a1f8ae74c 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -5,7 +5,7 @@ #include "utils/numeric.h" #include "utils/comparators.h" -#include "metrics/flux_surface.h" +#include "metrics/boyer_lindq_tp.h" #include "kernels/particle_pusher_1D_gr.hpp" @@ -104,7 +104,7 @@ void testFFPusher(const std::vector& res, array_t px1 { "px1", 30 }; array_t tag { "tag", 30 }; - const auto sep = real_t { 0.1 * res[0] }; + const auto sep = { static_cast(0.1 * res[0]) }; real_t x1i { ZERO }; int ii { 0 }; prtldx_t dx1i { ZERO }; @@ -140,7 +140,7 @@ void testFFPusher(const std::vector& res, Kokkos::parallel_for( "pusher", CreateRangePolicy({ 0 }, { 10 }), - kernel::gr::Pusher_kernel>( + kernel::gr::Pusher_kernel>( efield, i1, i1_prev, @@ -168,7 +168,7 @@ void testFFPusher(const std::vector& res, Kokkos::parallel_for( "pusher", CreateRangePolicy({ 10 }, { 20 }), - kernel::gr::Pusher_kernel>( + kernel::gr::Pusher_kernel>( efield, i1, i1_prev, @@ -187,7 +187,7 @@ void testFFPusher(const std::vector& res, Kokkos::parallel_for( "pusher", CreateRangePolicy({ 20 }, { 30 }), - kernel::gr::Pusher_kernel>( + kernel::gr::Pusher_kernel>( efield, i1, i1_prev, @@ -256,25 +256,23 @@ auto main(int argc, char* argv[]) -> int { try { using namespace ntt; - testFFPusher>( + testFFPusher>( { 128 }, - { { 2.0, 50.0 } }, + { { 2.0, 20.0 } }, 5, { { "a", (real_t)0.95 } , { "psi0", (real_t)1.0 } , { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } , - { "pCur", (real_t)3.1 } }); + { "Omega", (real_t)0.5 } }); - testFFPusher>( + testFFPusher>( { 512 }, - { { 2.0, 50.0 } }, + { { 2.0, 20.0 } }, 5, { { "a", (real_t)0.95 } , { "psi0", (real_t)1.0 } , { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } , - { "pCur", (real_t)3.1 } }); + { "Omega", (real_t)0.5 } }); } catch (std::exception& e) { diff --git a/src/metrics/boyer_lindq_tp.h b/src/metrics/boyer_lindq_tp.h index bc931bde1..1beaf9f64 100644 --- a/src/metrics/boyer_lindq_tp.h +++ b/src/metrics/boyer_lindq_tp.h @@ -53,7 +53,7 @@ namespace metric { } Inline auto omega(const real_t& r) const -> real_t { - return TWO * a * r / A(r, th0); + return TWO * a * r / A(r); } @@ -82,8 +82,8 @@ namespace metric { , psi { psi0 * (1 - math::cos(th0)) } , bt { -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / Sigma(rh_) } , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh_)) } - , dpsi_dth { -psi0 * math::sin(th0) } - , dbt_dth { -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) / SQR(Sigma(rh_)) } + , dpsi_dth { psi0 * math::sin(th0) } + , dbt_dth { -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh_) * math::cos(TWO * th0)) / SQR(Sigma(rh_)) } , eta_min { r2eta(x1_min) } , eta_max { r2eta(x1_max) } , d_eta { (eta_max - eta_min) / nx1 } @@ -91,7 +91,7 @@ namespace metric { set_dxMin(find_dxMin()); } - ~FluxSurface() = default; + ~BoyerLindqTP() = default; [[nodiscard]] Inline auto spin() const -> real_t { @@ -146,7 +146,9 @@ namespace metric { */ Inline auto f2(const coord_t& xi) const -> real_t { const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - return SQR(d_eta) * Sigma(r_) * (Delta(r_) + A(r_) * SQR(bt / dpsi_dth )); + return SQR(d_eta) * Sigma(r_) * (Delta(r_) + + A(r_) * SQR(bt / dpsi_dth ) + ); } Inline auto f1(const coord_t& xi) const -> real_t { diff --git a/src/metrics/tests/bltp.cpp b/src/metrics/tests/bltp.cpp index 557ba8186..3527663dd 100644 --- a/src/metrics/tests/bltp.cpp +++ b/src/metrics/tests/bltp.cpp @@ -85,10 +85,10 @@ void testMetric(const std::vector& res, const auto a = metric.spin(); const auto th0 = params.at("theta0"); const auto psi0 = params.at("psi0"); - const auto bt = -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / Sigma(rh_); + const auto bt = -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / (SQR(rh) + SQR(a * math::cos(th0))); const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); const auto dpsi_dth = -psi0 * math::sin(th0); - const auto dbt_dth = -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) / SQR(Sigma(rh_)); + const auto dbt_dth = -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) / SQR(SQR(rh) + SQR(a * math::cos(th0))); const auto rh_m = rh - TWO * math::sqrt(ONE - SQR(a)); const auto eta_min = math::log((x_min - rh) / (x_min - rh_m)) / (rh - rh_m); @@ -168,7 +168,7 @@ auto main(int argc, char* argv[]) -> int { try { using namespace ntt; using namespace metric; - testMetric>( + testMetric>( { 128 }, { { 2.0, 20.0 } }, 30, From 4321b01d7506d8fc6c299203524eeb157bb8d961 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 11 Oct 2024 17:30:10 +0800 Subject: [PATCH 35/47] fix errors --- src/kernels/particle_pusher_1D_gr.hpp | 4 ++-- src/kernels/tests/ff_pusher.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index fcd7307fe..7d1d673bf 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -171,7 +171,7 @@ namespace kernel::gr { Inline auto compute_u0(const real_t& pxi, const coord_t& xi) const -> real_t{ return math::sqrt((SQR(pxi) + metric.f2(xi)) / - (metric.f2(xi) * (SQR(metric.alpha(xi)) - metric.f1(xi)) + SQR(metric.f1(xi)))); + (metric.f2(xi) * (SQR(metric.alpha(xi)) - metric.f0(xi)) + SQR(metric.f1(xi)))); } @@ -219,7 +219,7 @@ namespace kernel::gr { pp_upd = pp + dt * (ex + HALF * compute_u0(pp_mid, xp) * - (-DERIVATIVE(metric.alpha, xp[0]) + + (-TWO * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + DERIVATIVE(metric.f2, xp[0]) * SQR((pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp)) + TWO * DERIVATIVE(metric.f1, xp[0]) * (pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp) + DERIVATIVE(metric.f0, xp[0]) diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index a1f8ae74c..0e82f625d 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -44,7 +44,7 @@ Inline auto equal(const real_t& a, const real_t& b, const char* msg, const real_t acc = ONE) -> bool { - const auto eps = math::sqrt(epsilon) * acc; + const auto eps = 1e-5 * acc; if (not cmp::AlmostEqual(a, b, eps)) { printf("%.12e != %.12e %s\n", a, b, msg); return false; From 0aa6f329842fb1c4384d7de4ae9ccaed3ab80d1e Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Sat, 12 Oct 2024 11:58:32 +0800 Subject: [PATCH 36/47] little amends --- src/engines/grpic.hpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 7a6f47cba..27143081a 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -64,8 +64,7 @@ namespace ntt { if (step == 0) { // communicate fields and apply BCs on the first timestep - m_metadomain.CommunicateFields(dom, Comm::E); - FieldBoundaries(dom, BC::E); + m_metadomain.CommunicateFields(dom, Comm::D); ParticleInjector(dom); } @@ -101,12 +100,9 @@ namespace ntt { timers.stop("FieldSolver"); timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::E | Comm::J); + m_metadomain.CommunicateFields(dom, Comm::D | Comm::J); timers.stop("Communications"); - timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::E); - timers.stop("FieldBoundaries"); } { @@ -116,8 +112,6 @@ namespace ntt { } } - void FieldBoundaries(domain_t& domain, BCTags tags) {} - void ParticleInjector(domain_t& domain, InjTags tags = Inj::None) {} void ParticlePush(domain_t& domain) { @@ -154,7 +148,7 @@ namespace ntt { i1_prev, dx1, dx1_prev, - ux1, + px1, tag, metric, coeff, dt, From 615a4b14e31eaea2d27b6b5706e52fc0f14c7656 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Mon, 14 Oct 2024 16:25:10 +0800 Subject: [PATCH 37/47] fix bugs --- src/kernels/particle_pusher_1D_gr.hpp | 3 +-- src/kernels/tests/ff_pusher.cpp | 38 +++++++++++++-------------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/kernels/particle_pusher_1D_gr.hpp b/src/kernels/particle_pusher_1D_gr.hpp index 7d1d673bf..ceb1c9fb3 100644 --- a/src/kernels/particle_pusher_1D_gr.hpp +++ b/src/kernels/particle_pusher_1D_gr.hpp @@ -139,7 +139,6 @@ namespace kernel::gr { real_t& pp_upd) const; /** - * @brief Iterative geodesic pusher substep for coordinate only. * @param xp particle coordinate. * @param vp particle velocity. * @param xp_upd updated particle coordinate [return]. @@ -217,7 +216,7 @@ namespace kernel::gr { // find updated momentum pp_upd = pp + - dt * (ex + + dt * (coeff * ex + HALF * compute_u0(pp_mid, xp) * (-TWO * metric.alpha(xp) * DERIVATIVE(metric.alpha, xp[0]) + DERIVATIVE(metric.f2, xp[0]) * SQR((pp_mid / compute_u0(pp_mid, xp) - metric.f1(xp)) / metric.f2(xp)) + diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 0e82f625d..7cbb69351 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -44,7 +44,7 @@ Inline auto equal(const real_t& a, const real_t& b, const char* msg, const real_t acc = ONE) -> bool { - const auto eps = 1e-5 * acc; + const auto eps = math::sqrt(epsilon) * acc; if (not cmp::AlmostEqual(a, b, eps)) { printf("%.12e != %.12e %s\n", a, b, msg); return false; @@ -151,7 +151,7 @@ void testFFPusher(const std::vector& res, metric, -coeff, dt, nx1, - 1e-5, + 1e-2, 30, boundaries)); @@ -179,7 +179,7 @@ void testFFPusher(const std::vector& res, metric, coeff, dt, nx1, - 1e-5, + 1e-2, 30, boundaries)); //negative charge @@ -198,7 +198,7 @@ void testFFPusher(const std::vector& res, metric, -coeff, dt, nx1, - 1e-5, + 1e-2, 30, boundaries)); @@ -215,31 +215,31 @@ void testFFPusher(const std::vector& res, - real_t pp_exp[10] { -0.00101477428313248, -0.00176341809594538, -0.00238648615376442, - -0.00283827679351036, -0.00306921265956161, -0.00303290033101228, - -0.00270039933123280, -0.00208484416740382, -0.00127661321429062, - -0.000478820732615589 }; - real_t pp_e_p_exp[10] { -0.000968871443278805, -0.00170766999655962, -0.00231905310776449, - -0.00275740867122713, -0.00297377760543621, -0.00292344129084046, - -0.00258102327970717, -0.00196607452803054, -0.00117812532296952, - -0.000426442564188143 }; - real_t pp_e_n_exp[10] { -0.00106067712103997, -0.00181916619206061, -0.00245391919423174, - -0.00291914490642661, -0.00316464769797483, -0.00314235934553045, - -0.00281977534327427, -0.00220361375292999, -0.00137510104884271, - -0.000531198870011043 }; + real_t pp_exp[10] { 1.00552757803207, 1.00905004166760, 1.01264731982748, + 1.01622119133582, 1.01961904791731, 1.02260412478936, + 1.02480734477237, 1.02564651052812, 1.02418169991879, + 1.01916798198126}; + real_t pp_e_p_exp[10] { 1.12420507263443, 1.18040523823437, 1.27055279565053, + 1.42520265982451, 1.71347897729332, 2.31132787710123, + 3.74396948272974, 7.98290677490210, 25.6627981723171, + 170.710945349036}; + real_t pp_e_n_exp[10] { 0.886850044532529, 0.837694736928196, 0.754741504814654, + 0.607238475100313, 0.325753270778111, -0.266166995807237, + -1.67869862572720, -5.82318047383146, -23.1877218243589, + -166.709733472388}; unsigned int wrongs { 0 }; for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(px1_(n), pp_exp[n] * d_eta_inv, "no efield", acc); + wrongs += !equal(px1_(n), pp_exp[n], "no efield", acc); } for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(px1_(n + 10), pp_e_p_exp[n] * d_eta_inv, "positive charge", acc); + wrongs += !equal(px1_(n + 10), pp_e_p_exp[n], "positive charge", acc); } for (size_t n { 0 }; n < 10; ++n){ - wrongs += !equal(px1_(n + 20), pp_e_n_exp[n] * d_eta_inv, "negative charge", acc); + wrongs += !equal(px1_(n + 20), pp_e_n_exp[n], "negative charge", acc); } if (wrongs){ From 603b764892b5ece732a48fd6693d412df8ae243f Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Mon, 14 Oct 2024 16:46:44 +0800 Subject: [PATCH 38/47] fix bug in ff_pusher --- src/kernels/tests/ff_pusher.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 7cbb69351..084eae284 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -87,7 +87,7 @@ void testFFPusher(const std::vector& res, const real_t d_eta_inv { nx1 / (metric.r2eta(extent[0].second) - metric.r2eta(extent[0].first)) }; const auto coeff { d_eta_inv }; - const auto dt = real_t { 0.001 }; + const auto dt = real_t { 0.1 }; const auto range_ext = CreateRangePolicy( { 0 }, @@ -264,15 +264,6 @@ auto main(int argc, char* argv[]) -> int { { "psi0", (real_t)1.0 } , { "theta0", (real_t)1.0 } , { "Omega", (real_t)0.5 } }); - - testFFPusher>( - { 512 }, - { { 2.0, 20.0 } }, - 5, - { { "a", (real_t)0.95 } , - { "psi0", (real_t)1.0 } , - { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } }); } catch (std::exception& e) { From 0aa85b787ffe883926bb847c00bdea12f89c86fb Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 15 Oct 2024 14:40:02 +0800 Subject: [PATCH 39/47] add force-free terms in bltp metric; update tests for bltp metric --- src/metrics/boyer_lindq_tp.h | 45 +++++++++----- src/metrics/tests/bltp.cpp | 99 +++++++++++++++++-------------- src/metrics/tests/coord_trans.cpp | 10 ++++ src/metrics/tests/vec_trans.cpp | 10 ++++ 4 files changed, 107 insertions(+), 57 deletions(-) diff --git a/src/metrics/boyer_lindq_tp.h b/src/metrics/boyer_lindq_tp.h index 1beaf9f64..d857d2313 100644 --- a/src/metrics/boyer_lindq_tp.h +++ b/src/metrics/boyer_lindq_tp.h @@ -35,8 +35,8 @@ namespace metric { // Spin parameter, in [0,1[ // and horizon size in units of rg // all physical extents are in units of rg - const real_t a, rg_, psi0, th0; - const real_t rh_, rh_m, psi, bt, Omega, dpsi_dth, dbt_dth; + const real_t a, rg, psi0, th0; + const real_t rh, rh_m, psi, bt, Omega, dpsi_dth, dbt_dth; const real_t eta_max, eta_min; const real_t d_eta, d_eta_inv; @@ -76,14 +76,14 @@ namespace metric { , a { params.at("a") } , psi0 { params.at("psi0") } , th0 { params.at("theta0") } - , rg_ { ONE } - , rh_ { ONE + math::sqrt(ONE - SQR(a)) } + , rg { ONE } + , rh { ONE + math::sqrt(ONE - SQR(a)) } , rh_m { ONE - math::sqrt(ONE - SQR(a)) } , psi { psi0 * (1 - math::cos(th0)) } - , bt { -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / Sigma(rh_) } - , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh_)) } + , bt { -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / Sigma(rh) } + , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh)) } , dpsi_dth { psi0 * math::sin(th0) } - , dbt_dth { -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh_) * math::cos(TWO * th0)) / SQR(Sigma(rh_)) } + , dbt_dth { -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) / SQR(Sigma(rh)) } , eta_min { r2eta(x1_min) } , eta_max { r2eta(x1_max) } , d_eta { (eta_max - eta_min) / nx1 } @@ -100,7 +100,7 @@ namespace metric { [[nodiscard]] Inline auto rhorizon() const -> real_t { - return rh_; + return rh; } [[nodiscard]] @@ -110,7 +110,7 @@ namespace metric { [[nodiscard]] Inline auto rg() const -> real_t { - return rg_; + return rg; } [[nodiscard]] @@ -160,6 +160,25 @@ namespace metric { return h_<3, 3>(xi) * SQR(Omega + beta3(xi)); } + /** + * @brief force-free charge densities and currents + */ + + Inline auto rho_ff(const coord_t& xi) const -> real_t { + const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; + return psi0 / sqrt_det_h(xi) * math::sin(TWO * th0) * + ((omega(r_) - Omega) * (ONE + SQR(a * math::sin(th0)) / Sigma(r_)) / SQR(alpha(xi)) + + SQR(a * math::sin(th0)) * Omega / Sigma(r_)); + } + + Inline auto J_ff() const -> real_t { + return -d_eta_inv * HALF * psi0 * a * + (ONE - TWO * SQR(rh * math::sin(th0)) / Sigma(rh)) + / Sigma(rh); + } + + + /** * minimum effective cell size for a given metric (in physical units) */ @@ -264,8 +283,7 @@ namespace metric { if constexpr (i == 1){ return v_in / math::sqrt(h_(x)) / Delta(eta2r(x[0] * d_eta + eta_min)); }else if constexpr (i == 2){ - return v_in / math::sqrt(h_(x)) * - dpsi_dth; + return v_in / math::sqrt(h_(x)) * dpsi_dth; }else{ return v_in / math::sqrt(h_(x)); } @@ -275,8 +293,7 @@ namespace metric { if constexpr (i == 1){ return v_in * math::sqrt(h_(x)) * Delta(eta2r(x[0] * d_eta + eta_min)); }else if constexpr (i == 2){ - return v_in * math::sqrt(h_(x)) / - dpsi_dth; + return v_in * math::sqrt(h_(x)) / dpsi_dth; }else{ return v_in * math::sqrt(h_(x)); } @@ -329,7 +346,7 @@ namespace metric { } Inline auto r2eta(const real_t& r) const -> real_t{ - return math::log((r - rh_) / (r - rh_m)) / (rh_ - rh_m); + return math::log((r - rh) / (r - rh_m)) / (rh - rh_m); } Inline auto eta2r(const real_t& eta) const -> real_t{ diff --git a/src/metrics/tests/bltp.cpp b/src/metrics/tests/bltp.cpp index 3527663dd..a6e59e9e4 100644 --- a/src/metrics/tests/bltp.cpp +++ b/src/metrics/tests/bltp.cpp @@ -69,31 +69,32 @@ void testMetric(const std::vector& res, M metric(res, ext, params); tuple_t res_tup; - std::size_t npts = 1; + std::size_t npts { 1 }; for (auto d = 0; d < M::Dim; ++d) { res_tup[d] = res[d]; npts *= res[d]; } - const auto x_min = ext[0].first; - const auto x_max = ext[0].second; - - - unsigned long all_wrongs = 0; - const auto rg = metric.rg(); - const auto rh = metric.rhorizon(); - const auto a = metric.spin(); - const auto th0 = params.at("theta0"); - const auto psi0 = params.at("psi0"); - const auto bt = -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / (SQR(rh) + SQR(a * math::cos(th0))); - const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); - const auto dpsi_dth = -psi0 * math::sin(th0); - const auto dbt_dth = -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) / SQR(SQR(rh) + SQR(a * math::cos(th0))); - const auto rh_m = rh - TWO * math::sqrt(ONE - SQR(a)); - - const auto eta_min = math::log((x_min - rh) / (x_min - rh_m)) / (rh - rh_m); - const auto eta_max = math::log((x_max - rh) / (x_max - rh_m)) / (rh - rh_m); - const auto d_eta = (eta_max - eta_min) / ((real_t)res[0]); + const auto x_min { ext[0].first }; + const auto x_max { ext[0].second }; + + + unsigned long all_wrongs { 0 }; + const auto rg { metric.rg() }; + const auto rh { metric.rhorizon() }; + const auto a { metric.spin() }; + const auto th0 { params.at("theta0") }; + const auto psi0 { params.at("psi0") }; + const auto bt { -HALF * psi0 * a * math::sin(th0) * math::cos(th0) / + (SQR(rh) + SQR(a * math::cos(th0))) }; + const auto Omega { params.at("Omega") * a / (SQR(a) + SQR(rh)) }; + const auto dpsi_dth { -psi0 * math::sin(th0) }; + const auto dbt_dth { -HALF * psi0 * a * (SQR(a * math::cos(th0)) + SQR(rh) * math::cos(TWO * th0)) + / SQR(SQR(rh) + SQR(a * math::cos(th0))) }; + const auto rh_m { rh - TWO * math::sqrt(ONE - SQR(a)) }; + const auto eta_min { math::log((x_min - rh) / (x_min - rh_m)) / (rh - rh_m) }; + const auto eta_max { math::log((x_max - rh) / (x_max - rh_m)) / (rh - rh_m) }; + const auto d_eta { (eta_max - eta_min) / ((real_t)res[0]) }; Kokkos::parallel_reduce( "h_ij/hij", @@ -108,36 +109,41 @@ void testMetric(const std::vector& res, x_Code[d] = (real_t)(idx[d]) + HALF; } - const auto h11 = metric.template h<1, 1>(x_Code); - const auto h22 = metric.template h<2, 2>(x_Code); - const auto h33 = metric.template h<3, 3>(x_Code); - const auto h_11 = metric.template h_<1, 1>(x_Code); - const auto h_22 = metric.template h_<2, 2>(x_Code); - const auto h_33 = metric.template h_<3, 3>(x_Code); + const auto h11 { metric.template h<1, 1>(x_Code) }; + const auto h22 { metric.template h<2, 2>(x_Code) }; + const auto h33 { metric.template h<3, 3>(x_Code) }; + const auto h_11 { metric.template h_<1, 1>(x_Code) }; + const auto h_22 { metric.template h_<2, 2>(x_Code) }; + const auto h_33 { metric.template h_<3, 3>(x_Code) }; metric.template convert(x_Code, x_Phys); - const auto r = x_Phys[0]; + const auto r { x_Phys[0] }; - const auto Sigma = SQR(r) + SQR(a * math::cos(th0)); - const auto Delta = SQR(r) - TWO * rg * r + SQR(a); - const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th0)) * Delta; - const auto omega = TWO * a * r / A ; + const auto Sigma { SQR(r) + SQR(a * math::cos(th0)) }; + const auto Delta { SQR(r) - TWO * rg * r + SQR(a) }; + const auto A { SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th0)) * Delta }; + const auto omega { TWO * a * r / A }; - const auto h_11_expect = Sigma / Delta; - const auto h_22_expect = Sigma ; - const auto h_33_expect = A * SQR(math::sin(th0)) / Sigma; - const auto h11_expect = ONE / h_11_expect; - const auto h22_expect = ONE / h_22_expect; - const auto h33_expect = ONE / h_33_expect; + const auto h_11_expect { Sigma / Delta }; + const auto h_22_expect { Sigma }; + const auto h_33_expect { A * SQR(math::sin(th0)) / Sigma }; + const auto h11_expect { ONE / h_11_expect }; + const auto h22_expect { ONE / h_22_expect }; + const auto h33_expect { ONE / h_33_expect }; - const auto f0_expect = h_33_expect * SQR(Omega - omega); - const auto f1_expect = d_eta * A * bt * (Omega - omega) / psi0; - const auto f2_expect = SQR(d_eta) * Sigma * (Delta + A * SQR(bt / dpsi_dth)); + const auto f0_expect { h_33_expect * SQR(Omega - omega) }; + const auto f1_expect { d_eta * A * bt * (Omega - omega) / psi0 }; + const auto f2_expect { SQR(d_eta) * Sigma * (Delta + A * SQR(bt / dpsi_dth)) }; - const auto f0_predict = metric.f0(x_Code); - const auto f1_predict = metric.f1(x_Code); - const auto f2_predict = metric.f2(x_Code); + const auto f0_predict { metric.f0(x_Code) }; + const auto f1_predict { metric.f1(x_Code) }; + const auto f2_predict { metric.f2(x_Code) }; + + const auto rho_ff_expect { psi0 * math::sin(TWO * th0) / (d_eta * math::sqrt(h_11_expect * h_22_expect * h_33_expect)) + * ( A / (Sigma * Delta) * (omega - Omega) * (ONE + SQR(a * math::sin(th0)) / Sigma) + + SQR(a * math::sin(th0)) / Sigma * Omega) }; + const auto rho_ff_predict { metric.rho_ff(x_Code) }; vec_t hij_temp { ZERO }, hij_predict { ZERO }; @@ -156,6 +162,13 @@ void testMetric(const std::vector& res, }, all_wrongs); + const auto J_ff_expect { -HALF * psi0 * a / (SQR(rh) + SQR(a * math::cos(th0))) + * (ONE - TWO * SQR(rh * math::sin(th0)) / (SQR(rh) + SQR(a * math::cos(th0))) )}; + + const auto J_ff_predict { metric.J_ff() }; + + all_wrongs += not equal(J_ff_expect, J_ff_predict, "J_ff", acc); + errorIf(all_wrongs != 0, "wrong h_ij/hij for " + std::to_string(M::Dim) + "D " + std::string(metric.Label) + " with " + std::to_string(all_wrongs) + diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 027b7677a..33afbd37d 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -9,6 +9,7 @@ #include "metrics/qkerr_schild.h" #include "metrics/qspherical.h" #include "metrics/spherical.h" +#include "metrics/boyer_lindq_tp.h" #include #include @@ -182,6 +183,15 @@ auto main(int argc, char* argv[]) -> int { }; testMetric>(resks0, extks0, 150); + const auto psramsbltp = std::map { + {"a" , (real_t)0.95}, + {"psi0" , ONE}, + {"theta0", ONE}, + {"Omega" , HALF} + }; + + testMetric>({ 128 }, ext1dcart, 200, psramsbltp); + } catch (std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); diff --git a/src/metrics/tests/vec_trans.cpp b/src/metrics/tests/vec_trans.cpp index a249c1d41..0c17430b8 100644 --- a/src/metrics/tests/vec_trans.cpp +++ b/src/metrics/tests/vec_trans.cpp @@ -9,6 +9,7 @@ #include "metrics/qkerr_schild.h" #include "metrics/qspherical.h" #include "metrics/spherical.h" +#include "metrics/boyer_lindq_tp.h" #include #include @@ -236,6 +237,15 @@ auto main(int argc, char* argv[]) -> int { }; testMetric>(resks0, extks0, 10); + const auto psramsbltp = std::map { + {"a" , (real_t)0.95}, + {"psi0" , ONE}, + {"theta0", ONE}, + {"Omega" , HALF} + }; + + testMetric>({ 128 }, ext1dcart, 200, psramsbltp); + } catch (std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); From 9ed44442006cf041fb176718352ca16ce3939371 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 15 Oct 2024 15:05:31 +0800 Subject: [PATCH 40/47] fix little errors in metric bltp and its tests --- src/metrics/boyer_lindq_tp.h | 6 +++--- src/metrics/tests/bltp.cpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/metrics/boyer_lindq_tp.h b/src/metrics/boyer_lindq_tp.h index d857d2313..94c078516 100644 --- a/src/metrics/boyer_lindq_tp.h +++ b/src/metrics/boyer_lindq_tp.h @@ -35,7 +35,7 @@ namespace metric { // Spin parameter, in [0,1[ // and horizon size in units of rg // all physical extents are in units of rg - const real_t a, rg, psi0, th0; + const real_t a, rg_, psi0, th0; const real_t rh, rh_m, psi, bt, Omega, dpsi_dth, dbt_dth; const real_t eta_max, eta_min; const real_t d_eta, d_eta_inv; @@ -76,7 +76,7 @@ namespace metric { , a { params.at("a") } , psi0 { params.at("psi0") } , th0 { params.at("theta0") } - , rg { ONE } + , rg_ { ONE } , rh { ONE + math::sqrt(ONE - SQR(a)) } , rh_m { ONE - math::sqrt(ONE - SQR(a)) } , psi { psi0 * (1 - math::cos(th0)) } @@ -110,7 +110,7 @@ namespace metric { [[nodiscard]] Inline auto rg() const -> real_t { - return rg; + return rg_; } [[nodiscard]] diff --git a/src/metrics/tests/bltp.cpp b/src/metrics/tests/bltp.cpp index a6e59e9e4..b5d4326cd 100644 --- a/src/metrics/tests/bltp.cpp +++ b/src/metrics/tests/bltp.cpp @@ -162,7 +162,7 @@ void testMetric(const std::vector& res, }, all_wrongs); - const auto J_ff_expect { -HALF * psi0 * a / (SQR(rh) + SQR(a * math::cos(th0))) + const auto J_ff_expect { -HALF / d_eta * psi0 * a / (SQR(rh) + SQR(a * math::cos(th0))) * (ONE - TWO * SQR(rh * math::sin(th0)) / (SQR(rh) + SQR(a * math::cos(th0))) )}; const auto J_ff_predict { metric.J_ff() }; From 42c7df9195fe0ac070327e19881700621f026d9b Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Tue, 15 Oct 2024 16:50:07 +0800 Subject: [PATCH 41/47] adding grpic_1d.hpp; update ampere kernel for 1d grpic --- src/engines/grpic.hpp | 136 +---------------------- src/engines/grpic_1d.hpp | 222 ++++++++++++++++++++++++++++++++++++++ src/kernels/ampere_gr.hpp | 12 +-- 3 files changed, 231 insertions(+), 139 deletions(-) create mode 100644 src/engines/grpic_1d.hpp diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 27143081a..18082b42e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -4,7 +4,7 @@ * @implements * - ntt::GRPICEngine<> : ntt::Engine<> * @cpp: - * - srpic.cpp + * - grpic.cpp * @namespaces: * - ntt:: */ @@ -13,32 +13,12 @@ #define ENGINES_GRPIC_GRPIC_H #include "enums.h" -#include "global.h" -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/log.h" -#include "utils/numeric.h" #include "utils/timer.h" -#include "archetypes/particle_injector.h" #include "framework/domain/domain.h" -#include "framework/parameters.h" #include "engines/engine.hpp" -#include "kernels/ampere_gr.hpp" -#include "kernels/currents_deposit.hpp" -#include "kernels/digital_filter.hpp" -#include "kernels/fields_bcs.hpp" -#include "kernels/particle_moments.hpp" -#include "kernels/particle_pusher_1D_gr.hpp" -#include "pgen.hpp" - -#include -#include - -#include -#include namespace ntt { @@ -47,124 +27,16 @@ namespace ntt { using Engine::m_params; using Engine::m_metadomain; - auto constexpr D { M::Dim }; - public: - static constexpr auto S { SimEngine::GRPIC }; + static constexpr auto S { SimEngine::SRPIC }; GRPICEngine(SimulationParams& params) : Engine { params } {} ~GRPICEngine() = default; - void step_forward(timer::Timers&, Domain&) override { - static_assert(D == Dim::1D, "GRPIC now only supports 1D simulations"); - const auto sort_interval = m_params.template get( - "particles.sort_interval"); - - if (step == 0) { - // communicate fields and apply BCs on the first timestep - m_metadomain.CommunicateFields(dom, Comm::D); - ParticleInjector(dom); - } - - { - timers.start("ParticlePusher"); - ParticlePush(dom); - timers.stop("ParticlePusher"); - - timers.start("CurrentDeposit"); - Kokkos::deep_copy(dom.fields.cur, ZERO); - CurrentsDeposit(dom); - timers.stop("CurrentDeposit"); - - timers.start("Communications"); - m_metadomain.SynchronizeFields(dom, Comm::J); - m_metadomain.CommunicateFields(dom, Comm::J); - timers.stop("Communications"); - - timers.start("CurrentFiltering"); - CurrentsFilter(dom); - timers.stop("CurrentFiltering"); - - timers.start("Communications"); - if ((sort_interval > 0) and (step % sort_interval == 0)) { - m_metadomain.CommunicateParticles(dom, &timers); - } - timers.stop("Communications"); - } - - { - timers.start("FieldSolver"); - CurrentsAmpere(dom); - timers.stop("FieldSolver"); - - timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::D | Comm::J); - timers.stop("Communications"); - - } - - { - timers.start("Injector"); - ParticleInjector(dom); - timers.stop("Injector"); - } - } - - void ParticleInjector(domain_t& domain, InjTags tags = Inj::None) {} - - void ParticlePush(domain_t& domain) { - for (auto& species : domain.species) { - species.set_unsorted(); - logger::Checkpoint( - fmt::format("Launching particle pusher kernel for %d [%s] : %lu", - species.index(), - species.label().c_str(), - species.npart()), - HERE); - if (species.npart() == 0) { - continue; - } - const auto q_ovr_m = species.mass() > ZERO - ? species.charge() / species.mass() - : ZERO; - // coeff = q / m (dt / 2) omegaB0 - const auto coeff = q_ovr_m * HALF * dt * - m_params.template get("scales.omegaB0"); - PrtlPusher::type pusher; - if (species.pusher() == PrtlPusher::FORCEFREE) { - pusher = PrtlPusher::FORCEFREE; - } else { - raise::Fatal("Invalid particle pusher", HERE); - } - // clang-format off - Kokkos::parallel_for( - "ParticlePusher", - species.rangeActiveParticles(), - kernel::gr::Pusher_kernel>( - efield, - i1, - i1_prev, - dx1, - dx1_prev, - px1, - tag, - metric, - coeff, dt, - nx1, - 1e-5, - 15, - boundaries)); - } - } - - void CurrentsDeposit(domain_t& domain) {} - - void CurrentsFilter(domain_t& domain) {} - - void CurrentsAmpere(domain_t& domain) {} -}; + void step_forward(timer::Timers&, Domain&) override {} + }; } // namespace ntt diff --git a/src/engines/grpic_1d.hpp b/src/engines/grpic_1d.hpp new file mode 100644 index 000000000..c60440cf9 --- /dev/null +++ b/src/engines/grpic_1d.hpp @@ -0,0 +1,222 @@ +/** + * @file engines/grpic_1d.hpp + * @brief Simulation engien class which specialized on 1D GRPIC + * @implements + * - ntt::GRPICEngine_1D<> : ntt::Engine<> + * @cpp: + * - grpic_1d.cpp + * @namespaces: + * - ntt:: + */ + +#ifndef ENGINES_GRPIC_GRPIC_1D_H +#define ENGINES_GRPIC_GRPIC_1D_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/log.h" +#include "utils/numeric.h" +#include "utils/timer.h" + +#include "archetypes/particle_injector.h" +#include "framework/domain/domain.h" +#include "framework/parameters.h" + +#include "metrics/boyer_lindq_tp.h" + +#include "engines/engine.hpp" +#include "kernels/ampere_gr.hpp" +#include "kernels/currents_deposit.hpp" +#include "kernels/digital_filter.hpp" +#include "kernels/fields_bcs.hpp" +#include "kernels/particle_moments.hpp" +#include "kernels/particle_pusher_1D_gr.hpp" +#include "pgen.hpp" + +#include +#include + +#include +#include + +namespace ntt { + + template + class GRPICEngine_1D : public Engine { + using Engine::m_params; + using Engine::m_metadomain; + + auto constexpr D { M::Dim }; + + public: + static constexpr auto S { SimEngine::GRPIC }; + + GRPICEngine_1D(SimulationParams& params) + : Engine { params } {} + + ~GRPICEngine_1D() = default; + + void step_forward(timer::Timers&, Domain&) override { + static_assert(D == Dim::1D, "This is 1D GRPIC simulation engine"); + const auto sort_interval = m_params.template get( + "particles.sort_interval"); + + if (step == 0) { + m_metadomain.CommunicateFields(dom, Comm::D); + /** + * !CommunicateFields: Special version for 1D GRPIC needed + */ + ParticleInjector(dom); + } + + { + timers.start("ParticlePusher"); + ParticlePush(dom); + timers.stop("ParticlePusher"); + + timers.start("CurrentDeposit"); + Kokkos::deep_copy(dom.fields.cur, ZERO); + CurrentsDeposit(dom); + timers.stop("CurrentDeposit"); + + timers.start("Communications"); + m_metadomain.SynchronizeFields(dom, Comm::J); + /** + * !SynchronizeFields: Special version for 1D GRPIC needed + */ + m_metadomain.CommunicateFields(dom, Comm::J); + timers.stop("Communications"); + + timers.start("CurrentFiltering"); + CurrentsFilter(dom); + timers.stop("CurrentFiltering"); + + timers.start("Communications"); + if ((sort_interval > 0) and (step % sort_interval == 0)) { + m_metadomain.CommunicateParticles(dom, &timers); + } + timers.stop("Communications"); + } + + { + timers.start("FieldSolver"); + CurrentsAmpere(dom); + timers.stop("FieldSolver"); + + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::D | Comm::J); + timers.stop("Communications"); + + } + + { + timers.start("Injector"); + ParticleInjector(dom); + timers.stop("Injector"); + } + } + + void ParticlePush(domain_t& domain) { + for (auto& species : domain.species) { + species.set_unsorted(); + logger::Checkpoint( + fmt::format("Launching particle pusher kernel for %d [%s] : %lu", + species.index(), + species.label().c_str(), + species.npart()), + HERE); + if (species.npart() == 0) { + continue; + } + const auto q_ovr_m = species.mass() > ZERO + ? species.charge() / species.mass() + : ZERO; + // coeff = q / m (dt / 2) omegaB0 + const auto coeff = q_ovr_m * HALF * dt * + m_params.template get("scales.omegaB0"); + PrtlPusher::type pusher; + if (species.pusher() == PrtlPusher::FORCEFREE) { + pusher = PrtlPusher::FORCEFREE; + } else { + raise::Fatal("Invalid particle pusher", HERE); + } + // clang-format off + Kokkos::parallel_for( + "ParticlePusher", + species.rangeActiveParticles(), + kernel::gr::Pusher_kernel>( + domain.fields.em, + species.i1, + species.i1_prev, + species.dx1, + species.dx1_prev, + species.px1, + species.tag, + domain.mesh.metric, + coeff, dt, + domain.mesh.n_active(in::x1), + 1e-2, + 30, + domain.mesh.n_active(in::x1)); + } + } + + void CurrentsDeposit(domain_t& domain) { + auto scatter_cur = Kokkos::Experimental::create_scatter_view( + domain.fields.cur); + for (auto& species : domain.species) { + logger::Checkpoint( + fmt::format("Launching currents deposit kernel for %d [%s] : %lu %f", + species.index(), + species.label().c_str(), + species.npart(), + (double)species.charge()), + HERE); + if (species.npart() == 0 || cmp::AlmostZero(species.charge())) { + continue; + } + /** + * !DepositCurrents_kernel: Special version for 1D GRPIC needed + */ + Kokkos::parallel_for("CurrentsDeposit", + species.rangeActiveParticles(), + kernel::DepositCurrents_kernel( + scatter_cur, + species.i1, + species.i1_prev, + species.dx1, + species.dx1_prev, + species.px1, + species.weight, + species.tag, + domain.mesh.metric, + (real_t)(species.charge()), + dt)); + } + Kokkos::Experimental::contribute(domain.fields.cur, scatter_cur); + } + + void CurrentsAmpere(domain_t& domain) { + logger::Checkpoint("Launching Ampere kernel for adding currents", HERE); + const auto q0 = m_params.template get("scales.q0"); + const auto n0 = m_params.template get("scales.n0"); + const auto B0 = m_params.template get("scales.B0"); + const auto coeff = -dt * q0 * n0 / B0; + Kokkos::parallel_for( + "Ampere", + domain.mesh.rangeActiveCells(), + kernel::gr::CurrentsAmpere_kernel_1D(domain.fields.em, + domain.fields.cur, + domain.mesh.metric, + coeff)); + } + + +}; + +} // namespace ntt + +#endif // ENGINES_GRPIC_GRPIC_1D_H diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 7a74c610d..b3f857af6 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -191,7 +191,6 @@ namespace kernel::gr { ndfield_t Df; const ndfield_t J; - const ndfield_t J_ff; const M metric; const real_t coeff; @@ -201,11 +200,10 @@ namespace kernel::gr { * @brief Constructor. * @param mblock Meshblock. */ - Ampere_kernel_1D(const ndfield_t & Df, - const ndfield_t& J, - const ndfield_t J_ff, - const M& metric, - real_t coeff) + CurrentsAmpere_kernel_1D(ndfield_t & Df, + const ndfield_t& J, + const M& metric, + const real_t coeff) : Df { Df } , J { J } , metric { metric } @@ -218,7 +216,7 @@ namespace kernel::gr { const real_t inv_sqrt_detH { ONE / metric.sqrt_det_h(i1_ + HALF) }; - Df(i1, em::dx1) += (J(i1, cur::jx1) - J_ff(i1, cur::jx1)) * coeff * inv_sqrt_detH; + Df(i1, em::dx1) += (J(i1, cur::jx1) - metric.J_ff()) * coeff * inv_sqrt_detH; } else { raise::KernelError( HERE, From 88a67646e28ebf2bc47dbb52c35acdd99e450f87 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Wed, 16 Oct 2024 14:25:52 +0800 Subject: [PATCH 42/47] update grpic_1d.hpp --- src/engines/grpic_1d.hpp | 41 +++++++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/src/engines/grpic_1d.hpp b/src/engines/grpic_1d.hpp index c60440cf9..4dc2aa196 100644 --- a/src/engines/grpic_1d.hpp +++ b/src/engines/grpic_1d.hpp @@ -46,8 +46,24 @@ namespace ntt { template class GRPICEngine_1D : public Engine { - using Engine::m_params; - using Engine::m_metadomain; + + using base_t = Engine; + using pgen_t = user::PGen; + using domain_t = Domain; + // constexprs + using base_t::pgen_is_ok; + // contents + using base_t::m_metadomain; + using base_t::m_params; + using base_t::m_pgen; + // methods + using base_t::init; + // variables + using base_t::dt; + using base_t::max_steps; + using base_t::runtime; + using base_t::step; + using base_t::time; auto constexpr D { M::Dim }; @@ -55,12 +71,14 @@ namespace ntt { static constexpr auto S { SimEngine::GRPIC }; GRPICEngine_1D(SimulationParams& params) - : Engine { params } {} + : Engine { params } { + raise::ErrorIf(D != Dim::_1D, "GRPICEngine_1D only works in 1D", HERE); + raise::ErrorIf(M.Lable != "boyer_lindq_tp", "GRPICEngine_1D only works with BoyerLindqTP metric", HERE); + } ~GRPICEngine_1D() = default; void step_forward(timer::Timers&, Domain&) override { - static_assert(D == Dim::1D, "This is 1D GRPIC simulation engine"); const auto sort_interval = m_params.template get( "particles.sort_interval"); @@ -92,6 +110,9 @@ namespace ntt { timers.start("CurrentFiltering"); CurrentsFilter(dom); + /** + * !CurrentsFilter: Special version for 1D GRPIC needed + */ timers.stop("CurrentFiltering"); timers.start("Communications"); @@ -114,7 +135,7 @@ namespace ntt { { timers.start("Injector"); - ParticleInjector(dom); + DischargeInjector(dom); timers.stop("Injector"); } } @@ -134,8 +155,8 @@ namespace ntt { const auto q_ovr_m = species.mass() > ZERO ? species.charge() / species.mass() : ZERO; - // coeff = q / m (dt / 2) omegaB0 - const auto coeff = q_ovr_m * HALF * dt * + // coeff = q / m dt omegaB0 + const auto coeff = q_ovr_m * dt * m_params.template get("scales.omegaB0"); PrtlPusher::type pusher; if (species.pusher() == PrtlPusher::FORCEFREE) { @@ -160,7 +181,7 @@ namespace ntt { domain.mesh.n_active(in::x1), 1e-2, 30, - domain.mesh.n_active(in::x1)); + domain.mesh.n_active(in::x1))); } } @@ -178,6 +199,7 @@ namespace ntt { if (species.npart() == 0 || cmp::AlmostZero(species.charge())) { continue; } + // clang-format off /** * !DepositCurrents_kernel: Special version for 1D GRPIC needed */ @@ -205,6 +227,7 @@ namespace ntt { const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); const auto coeff = -dt * q0 * n0 / B0; + // clang-format off Kokkos::parallel_for( "Ampere", domain.mesh.rangeActiveCells(), @@ -215,7 +238,7 @@ namespace ntt { } -}; +}; // class GRPICEngine_1D } // namespace ntt From a6e9f89d263794688707ec226e4610f2b7349fa5 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 18 Oct 2024 14:06:39 +0800 Subject: [PATCH 43/47] adding file grpic_1d.cpp for 1DGRPIC engine --- src/engines/grpic_1d.hpp | 2 +- src/kernels/ampere_gr.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic_1d.hpp b/src/engines/grpic_1d.hpp index 4dc2aa196..04706aa12 100644 --- a/src/engines/grpic_1d.hpp +++ b/src/engines/grpic_1d.hpp @@ -85,7 +85,7 @@ namespace ntt { if (step == 0) { m_metadomain.CommunicateFields(dom, Comm::D); /** - * !CommunicateFields: Special version for 1D GRPIC needed + * !CommunicateFields, ParticleInjector: Special version for 1D GRPIC needed */ ParticleInjector(dom); } diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index b3f857af6..f026cf447 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -216,7 +216,7 @@ namespace kernel::gr { const real_t inv_sqrt_detH { ONE / metric.sqrt_det_h(i1_ + HALF) }; - Df(i1, em::dx1) += (J(i1, cur::jx1) - metric.J_ff()) * coeff * inv_sqrt_detH; + Df(i1, em::dx1) += (J(i1, cur::jx1) * inv_sqrt_detH - metric.J_ff()) * coeff ; } else { raise::KernelError( HERE, From 140598e027d5ac3741ca4c39b7ad523d0c168870 Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Fri, 18 Oct 2024 14:11:52 +0800 Subject: [PATCH 44/47] add 1d ampere kernel --- src/kernels/ampere_gr.hpp | 191 +++++++++++++++++++++++++++++++++++++- 1 file changed, 188 insertions(+), 3 deletions(-) diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index be3be17bc..0dd7bf906 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -182,8 +182,194 @@ namespace kernel::gr { } }; -<<<<<<< HEAD -======= +} // namespace kernel::gr + +#endif // KERNELS_AMPERE_GR_HPP + +/** + * @file kernels/ampere_gr.hpp + * @brief Algorithms for Ampere's law in GR + * @implements + * - kernel::gr::Ampere_kernel<> + * - kernel::gr::CurrentsAmpere_kernel<> + * @namespaces: + * - kernel::gr:: + * !TODO: + * - 3D implementation + */ + +#ifndef KERNELS_AMPERE_GR_HPP +#define KERNELS_AMPERE_GR_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/numeric.h" + +namespace kernel::gr { + using namespace ntt; + + /** + * @brief Algorithms for Ampere's law: + * @brief `d(Din)^i / dt = curl H_j`, `Dout += dt * d(Din)/dt`. + * @tparam M Metric. + */ + template + class Ampere_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + + const ndfield_t Din; + ndfield_t Dout; + const ndfield_t H; + const M metric; + const std::size_t i2max; + const real_t coeff; + bool is_axis_i2min { false }, is_axis_i2max { false }; + + public: + Ampere_kernel(const ndfield_t& Din, + const ndfield_t& Dout, + const ndfield_t& H, + const M& metric, + real_t coeff, + std::size_t ni2, + const boundaries_t& boundaries) + : Din { Din } + , Dout { Dout } + , H { H } + , metric { metric } + , i2max { ni2 + N_GHOSTS } + , coeff { coeff } { + if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { + raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); + raise::ErrorIf(boundaries[1].size() < 2, + "boundaries defined incorrectly", + HERE); + is_axis_i2min = (boundaries[1].first == FldsBC::AXIS); + is_axis_i2max = (boundaries[1].second == FldsBC::AXIS); + } + } + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + constexpr std::size_t i2min { N_GHOSTS }; + const real_t i1_ { COORD(i1) }; + const real_t i2_ { COORD(i2) }; + + const real_t inv_sqrt_detH_0pH { ONE / + metric.sqrt_det_h({ i1_, i2_ + HALF }) }; + + if ((i2 == i2min) && is_axis_i2min) { + // theta = 0 + const real_t inv_polar_area_pH { ONE / metric.polar_area(i1_ + HALF) }; + Dout(i1, i2, em::dx1) = Din(i1, i2, em::dx1) + + inv_polar_area_pH * coeff * H(i1, i2, em::hx3); + Dout(i1, i2, em::dx2) = Din(i1, i2, em::dx2) + + coeff * inv_sqrt_detH_0pH * + (H(i1 - 1, i2, em::hx3) - H(i1, i2, em::hx3)); + } else if ((i2 == i2max) && is_axis_i2max) { + // theta = pi + const real_t inv_polar_area_pH { ONE / metric.polar_area(i1_ + HALF) }; + Dout(i1, i2, em::dx1) = Din(i1, i2, em::dx1) - inv_polar_area_pH * coeff * + H(i1, i2 - 1, em::hx3); + } else { + const real_t inv_sqrt_detH_00 { ONE / metric.sqrt_det_h({ i1_, i2_ }) }; + const real_t inv_sqrt_detH_pH0 { ONE / metric.sqrt_det_h( + { i1_ + HALF, i2_ }) }; + Dout(i1, i2, em::dx1) = Din(i1, i2, em::dx1) + + coeff * inv_sqrt_detH_pH0 * + (H(i1, i2, em::hx3) - H(i1, i2 - 1, em::hx3)); + Dout(i1, i2, em::dx2) = Din(i1, i2, em::dx2) + + coeff * inv_sqrt_detH_0pH * + (H(i1 - 1, i2, em::hx3) - H(i1, i2, em::hx3)); + Dout(i1, i2, em::dx3) = Din(i1, i2, em::dx3) + + coeff * inv_sqrt_detH_00 * + ((H(i1, i2 - 1, em::hx1) - H(i1, i2, em::hx1)) + + (H(i1, i2, em::hx2) - H(i1 - 1, i2, em::hx2))); + } + } else { + raise::KernelError(HERE, "Ampere_kernel: 2D implementation called for D != 2"); + } + } + }; + + /** + * @brief Add the currents to the D field with the appropriate conversion. + */ + template + class CurrentsAmpere_kernel { + static constexpr auto D = M::Dim; + + ndfield_t Df; + const ndfield_t J; + const M metric; + const std::size_t i2max; + const real_t coeff; + bool is_axis_i2min { false }; + bool is_axis_i2max { false }; + + public: + /** + * @brief Constructor. + * @param mblock Meshblock. + */ + CurrentsAmpere_kernel(const ndfield_t& Df, + const ndfield_t& J, + const M& metric, + real_t coeff, + std::size_t ni2, + const boundaries_t& boundaries) + : Df { Df } + , J { J } + , metric { metric } + , i2max { ni2 + N_GHOSTS } + , coeff { coeff } { + if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { + raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); + is_axis_i2min = (boundaries[1].first == FldsBC::AXIS); + is_axis_i2max = (boundaries[1].second == FldsBC::AXIS); + } + } + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + constexpr std::size_t i2min { N_GHOSTS }; + const real_t i1_ { COORD(i1) }; + const real_t i2_ { COORD(i2) }; + + const real_t inv_sqrt_detH_0pH { ONE / + metric.sqrt_det_h({ i1_, i2_ + HALF }) }; + + if ((i2 == i2min) && is_axis_i2min) { + // theta = 0 (first active cell) + Df(i1, i2, em::dx1) += J(i1, i2, cur::jx1) * HALF * coeff / + metric.polar_area(i1_ + HALF); + Df(i1, i2, em::dx2) += J(i1, i2, cur::jx2) * coeff * inv_sqrt_detH_0pH; + } else if ((i2 == i2max) && is_axis_i2max) { + // theta = pi (first ghost cell from end) + Df(i1, i2, em::dx1) += J(i1, i2, cur::jx1) * HALF * coeff / + metric.polar_area(i1_ + HALF); + } else { + // 0 < theta < pi + const real_t inv_sqrt_detH_00 { ONE / metric.sqrt_det_h({ i1_, i2_ }) }; + const real_t inv_sqrt_detH_pH0 { ONE / metric.sqrt_det_h( + { i1_ + HALF, i2_ }) }; + + Df(i1, i2, em::dx1) += J(i1, i2, cur::jx1) * coeff * inv_sqrt_detH_pH0; + Df(i1, i2, em::dx2) += J(i1, i2, cur::jx2) * coeff * inv_sqrt_detH_0pH; + Df(i1, i2, em::dx3) += J(i1, i2, cur::jx3) * coeff * inv_sqrt_detH_00; + } + } else { + raise::KernelError( + HERE, + "CurrentsAmpere_kernel: 2D implementation called for D != 2"); + } + } + }; + /** * @brief Ampere's law for only 1D-GRPIC. */ @@ -228,7 +414,6 @@ namespace kernel::gr { }; ->>>>>>> 1d_grpic_dev } // namespace kernel::gr #endif // KERNELS_AMPERE_GR_HPP From 8f9760c1265a5fdfac0bce46aa1d8ba6563ba4ad Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 26 Dec 2024 13:51:47 -0500 Subject: [PATCH 45/47] Update enums.h --- src/global/enums.h | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/global/enums.h b/src/global/enums.h index b96d662ed..e2d846848 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -4,12 +4,7 @@ * @implements * - enum ntt::Coord // Cart, Sph, Qsph, Fs * - enum ntt::Metric // Minkowski, Spherical, QSpherical, -<<<<<<< HEAD - * Kerr_Schild, QKerr_Schild, Kerr_Schild_0, Flux_Surface -======= - * Kerr_Schild, QKerr_Schild, Kerr_Schild_0, - * Flux_Surface ->>>>>>> 29730e373f0d18a95ed75cb30ba6dd18f3ec0028 + * Kerr_Schild, QKerr_Schild, Kerr_Schild_0, BoyerLindqTP * - enum ntt::SimEngine // SRPIC, GRPIC * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync From fcfa3ca7dfa5df805aef3684dd18a44a6ab42cc6 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 26 Dec 2024 16:54:53 -0500 Subject: [PATCH 46/47] tests fail for metric & pusher tests WIP --- extern/Kokkos | 2 +- extern/adios2 | 2 +- extern/plog | 2 +- src/global/enums.h | 16 +- src/global/tests/enums.cpp | 11 +- src/kernels/tests/ff_pusher.cpp | 214 ++++++++---------- src/metrics/flux_surface.h | 361 ------------------------------ src/metrics/tests/CMakeLists.txt | 2 +- src/metrics/tests/coord_trans.cpp | 1 - src/metrics/tests/fs.cpp | 194 ---------------- src/metrics/tests/vec_trans.cpp | 1 - 11 files changed, 109 insertions(+), 697 deletions(-) delete mode 100644 src/metrics/flux_surface.h delete mode 100644 src/metrics/tests/fs.cpp diff --git a/extern/Kokkos b/extern/Kokkos index 5fc08a9a7..6f69d94a4 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit 5fc08a9a7da14d8530f8c7035d008ef63ddb4e5c +Subproject commit 6f69d94a4abb153a22848d897a816f1a2fe4e3e3 diff --git a/extern/adios2 b/extern/adios2 index a6e8314cc..f80ad829d 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit a6e8314cc3c0b28d496b44dcd4f15685013b887b +Subproject commit f80ad829d751241140c40923503e1888e27e22e1 diff --git a/extern/plog b/extern/plog index 85a871b13..96637a6e5 160000 --- a/extern/plog +++ b/extern/plog @@ -1 +1 @@ -Subproject commit 85a871b13be0bd1a9e0110744fa60cc9bd1e8380 +Subproject commit 96637a6e5e53f54e4e56d667d312c564d979ec0e diff --git a/src/global/enums.h b/src/global/enums.h index e2d846848..ff8a92a3f 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -139,7 +139,7 @@ namespace ntt { constexpr Coord(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { Cart, Sph, Qsph, Bltp}; + static constexpr type variants[] = { Cart, Sph, Qsph, Bltp }; static constexpr const char* lookup[] = { "cart", "sph", "qsph", "bltp" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; @@ -164,9 +164,9 @@ namespace ntt { QSpherical, Kerr_Schild, QKerr_Schild, Kerr_Schild_0, BoyerLindqTP }; - static constexpr const char* lookup[] = { "minkowski", "spherical", - "qspherical", "kerr_schild", - "qkerr_schild", "kerr_schild_0", + static constexpr const char* lookup[] = { "minkowski", "spherical", + "qspherical", "kerr_schild", + "qkerr_schild", "kerr_schild_0", "boyer_lindq_tp" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; @@ -254,8 +254,12 @@ namespace ntt { constexpr PrtlPusher(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { BORIS, VAY, PHOTON, NONE }; - static constexpr const char* lookup[] = { "boris", "vay", "photon", "forcefree", "none"}; + static constexpr type variants[] = { BORIS, VAY, PHOTON, FORCEFREE, NONE }; + static constexpr const char* lookup[] = { "boris", + "vay", + "photon", + "forcefree", + "none" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 44a6a1cab..941c15793 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -55,16 +55,17 @@ auto main() -> int { using enum_str_t = const std::vector; - enum_str_t all_coords = { "cart", "sph", "qsph", "fs" }; - enum_str_t all_metrics = { "minkowski", "spherical", "qspherical", - "kerr_schild", "qkerr_schild", "kerr_schild_0", "boyer_lindq_tp" }; + enum_str_t all_coords = { "cart", "sph", "qsph", "bltp" }; + enum_str_t all_metrics = { "minkowski", "spherical", "qspherical", + "kerr_schild", "qkerr_schild", "kerr_schild_0", + "boyer_lindq_tp" }; enum_str_t all_simulation_engines = { "srpic", "grpic" }; enum_str_t all_particle_bcs = { "periodic", "absorb", "atmosphere", "custom", "reflect", "horizon", "axis", "sync" }; enum_str_t all_fields_bcs = { "periodic", "absorb", "atmosphere", "custom", "horizon", "conductor", "axis", "sync" }; - enum_str_t all_particle_pushers = { "boris", "vay", "photon", "none" }; - enum_str_t all_coolings = { "synchrotron", "none" }; + enum_str_t all_particle_pushers = { "boris", "vay", "photon", "forcefree", "none" }; + enum_str_t all_coolings = { "synchrotron", "none" }; enum_str_t all_out_flds = { "e", "dive", "d", "divd", "b", "h", "j", "a", "t", "rho", diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index 084eae284..a6eb46002 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -2,8 +2,8 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/numeric.h" #include "utils/comparators.h" +#include "utils/numeric.h" #include "metrics/boyer_lindq_tp.h" @@ -24,7 +24,9 @@ using namespace metric; #define i_di_to_Xi(I, DI) static_cast((I)) + static_cast((DI)) #define from_Xi_to_i(XI, I) \ - { I = static_cast((XI)); } + { \ + I = static_cast((XI)); \ + } #define from_Xi_to_i_di(XI, I, DI) \ { \ @@ -32,18 +34,15 @@ using namespace metric; DI = static_cast((XI)) - static_cast(I); \ } - -#define DERIVATIVE(func, x) \ - ((func({ x + epsilon }) - func({ x - epsilon })) / \ - (TWO * epsilon)) +#define DERIVATIVE(func, x) \ + ((func({ x + epsilon }) - func({ x - epsilon })) / (TWO * epsilon)) inline static constexpr auto epsilon = std::numeric_limits::epsilon(); - Inline auto equal(const real_t& a, const real_t& b, - const char* msg, - const real_t acc = ONE) -> bool { + const char* msg, + const real_t acc = ONE) -> bool { const auto eps = math::sqrt(epsilon) * acc; if (not cmp::AlmostEqual(a, b, eps)) { printf("%.12e != %.12e %s\n", a, b, msg); @@ -52,7 +51,6 @@ Inline auto equal(const real_t& a, return true; } - void errorIf(bool condition, const std::string& message) { if (condition) { throw std::runtime_error(message); @@ -69,9 +67,9 @@ void put_value(array_t& arr, T v, index_t p) { template void testFFPusher(const std::vector& res, - const boundaries_t& ext, - const real_t acc, - const std::map& params = {}) { + const boundaries_t& ext, + const real_t acc, + const std::map& params = {}) { static_assert(M::Dim == 1, "Only 1D is supported"); errorIf(res.size() != M::Dim, "res.size() != M::Dim"); @@ -79,175 +77,140 @@ void testFFPusher(const std::vector& res, extent = ext; M metric { res, extent, params }; - + static constexpr auto D = M::Dim; const int nx1 = res[0]; - - const real_t d_eta_inv { nx1 / (metric.r2eta(extent[0].second) - metric.r2eta(extent[0].first)) }; + + const real_t d_eta_inv { nx1 / (metric.r2eta(extent[0].second) - + metric.r2eta(extent[0].first)) }; const auto coeff { d_eta_inv }; - const auto dt = real_t { 0.1 }; + const auto dt = real_t { 0.1 }; - const auto range_ext = CreateRangePolicy( - { 0 }, - { res[0] + 2 * N_GHOSTS }); + const auto range_ext = CreateRangePolicy({ 0 }, + { res[0] + 2 * N_GHOSTS }); - auto efield = ndfield_t { "efield", - res[0] + 2 * N_GHOSTS}; + auto efield = ndfield_t { "efield", res[0] + 2 * N_GHOSTS }; - array_t i1 { "i1", 30 }; array_t i1_prev { "i1_prev", 30 }; array_t dx1 { "dx1", 30 }; array_t dx1_prev { "dx1_prev", 30 }; array_t px1 { "px1", 30 }; array_t tag { "tag", 30 }; - - const auto sep = { static_cast(0.1 * res[0]) }; - real_t x1i { ZERO }; - int ii { 0 }; - prtldx_t dx1i { ZERO }; + const real_t sep = 0.1 * res[0]; + real_t x1i { ZERO }; + int ii { 0 }; + prtldx_t dx1i { ZERO }; // Particle boundaries auto boundaries = boundaries_t {}; boundaries = { - {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + { PrtlBC::PERIODIC, PrtlBC::PERIODIC } }; - // No efield - + // No efield + Kokkos::parallel_for( "init efield", range_ext, - Lambda(index_t i1) { - efield(i1, em::ex1) = ZERO; - }); + Lambda(index_t i1) { efield(i1, em::ex1) = ZERO; }); - for (size_t n { 0 }; n < 30; n++){ + for (size_t n { 0 }; n < 30; n++) { x1i = ZERO + (n % 10) * sep; - from_Xi_to_i_di(x1i, ii, dx1i) - put_value(i1, ii, n); + from_Xi_to_i_di(x1i, ii, dx1i) put_value(i1, ii, n); put_value(dx1, dx1i, n); put_value(px1, ZERO, n); put_value(tag, ParticleTag::alive, n); } - // Without electric field - Kokkos::parallel_for( + Kokkos::parallel_for( "pusher", CreateRangePolicy({ 0 }, { 10 }), - kernel::gr::Pusher_kernel>( - efield, - i1, - i1_prev, - dx1, - dx1_prev, - px1, - tag, - metric, - -coeff, dt, - nx1, - 1e-2, - 30, - boundaries)); - + // clang-format off + kernel::gr::Pusher_kernel>(efield, + i1, i1_prev, dx1, dx1_prev, px1, + tag, metric, -coeff, dt, nx1, + 1e-2, 30, boundaries)); + // clang-format on + // With electric field // positive charge - + Kokkos::parallel_for( "init efield", range_ext, - Lambda(index_t i1) { - efield(i1, em::ex1) = 99.0; - }); + Lambda(index_t i1) { efield(i1, em::ex1) = 99.0; }); - Kokkos::parallel_for( + Kokkos::parallel_for( "pusher", CreateRangePolicy({ 10 }, { 20 }), - kernel::gr::Pusher_kernel>( - efield, - i1, - i1_prev, - dx1, - dx1_prev, - px1, - tag, - metric, - coeff, dt, - nx1, - 1e-2, - 30, - boundaries)); - //negative charge + // clang-format off + kernel::gr::Pusher_kernel>(efield, + i1, i1_prev, dx1, dx1_prev, px1, + tag, metric, coeff, dt, nx1, + 1e-2, 30, boundaries)); + // clang-format on + // negative charge Kokkos::parallel_for( "pusher", CreateRangePolicy({ 20 }, { 30 }), - kernel::gr::Pusher_kernel>( - efield, - i1, - i1_prev, - dx1, - dx1_prev, - px1, - tag, - metric, - -coeff, dt, - nx1, - 1e-2, - 30, - boundaries)); - - auto i1_ = Kokkos::create_mirror_view(i1); + // clang-format off + kernel::gr::Pusher_kernel>(efield, + i1, i1_prev, dx1, dx1_prev, px1, + tag, metric, -coeff, dt, nx1, + 1e-2, 30, boundaries)); + // clang-format on + + auto i1_ = Kokkos::create_mirror_view(i1); Kokkos::deep_copy(i1_, i1); - auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); + auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); Kokkos::deep_copy(i1_prev_, i1_prev); - auto dx1_ = Kokkos::create_mirror_view(dx1); + auto dx1_ = Kokkos::create_mirror_view(dx1); Kokkos::deep_copy(dx1_, dx1); - auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); + auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); Kokkos::deep_copy(dx1_prev_, dx1_prev); - auto px1_ = Kokkos::create_mirror_view(px1); + auto px1_ = Kokkos::create_mirror_view(px1); Kokkos::deep_copy(px1_, px1); - - - real_t pp_exp[10] { 1.00552757803207, 1.00905004166760, 1.01264731982748, - 1.01622119133582, 1.01961904791731, 1.02260412478936, - 1.02480734477237, 1.02564651052812, 1.02418169991879, - 1.01916798198126}; - real_t pp_e_p_exp[10] { 1.12420507263443, 1.18040523823437, 1.27055279565053, - 1.42520265982451, 1.71347897729332, 2.31132787710123, - 3.74396948272974, 7.98290677490210, 25.6627981723171, - 170.710945349036}; - real_t pp_e_n_exp[10] { 0.886850044532529, 0.837694736928196, 0.754741504814654, - 0.607238475100313, 0.325753270778111, -0.266166995807237, - -1.67869862572720, -5.82318047383146, -23.1877218243589, - -166.709733472388}; + real_t pp_exp[10] { 1.00552757803207, 1.00905004166760, 1.01264731982748, + 1.01622119133582, 1.01961904791731, 1.02260412478936, + 1.02480734477237, 1.02564651052812, 1.02418169991879, + 1.01916798198126 }; + real_t pp_e_p_exp[10] { 1.12420507263443, 1.18040523823437, 1.27055279565053, + 1.42520265982451, 1.71347897729332, 2.31132787710123, + 3.74396948272974, 7.98290677490210, 25.6627981723171, + 170.710945349036 }; + real_t pp_e_n_exp[10] { 0.886850044532529, 0.837694736928196, + 0.754741504814654, 0.607238475100313, + 0.325753270778111, -0.266166995807237, + -1.67869862572720, -5.82318047383146, + -23.1877218243589, -166.709733472388 }; unsigned int wrongs { 0 }; - - for (size_t n { 0 }; n < 10; ++n){ + + for (size_t n { 0 }; n < 10; ++n) { wrongs += !equal(px1_(n), pp_exp[n], "no efield", acc); } - - for (size_t n { 0 }; n < 10; ++n){ + + for (size_t n { 0 }; n < 10; ++n) { wrongs += !equal(px1_(n + 10), pp_e_p_exp[n], "positive charge", acc); } - - for (size_t n { 0 }; n < 10; ++n){ + + for (size_t n { 0 }; n < 10; ++n) { wrongs += !equal(px1_(n + 20), pp_e_n_exp[n], "negative charge", acc); } - if (wrongs){ - throw std::runtime_error("ff_usher failed."); + if (wrongs) { + throw std::runtime_error("ff_usher failed."); } - - //with electric field, positive charge + // with electric field, positive charge } auto main(int argc, char* argv[]) -> int { @@ -257,14 +220,15 @@ auto main(int argc, char* argv[]) -> int { using namespace ntt; testFFPusher>( - { 128 }, + { + 128 + }, { { 2.0, 20.0 } }, - 5, - { { "a", (real_t)0.95 } , - { "psi0", (real_t)1.0 } , - { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } }); - + 5, + { { "a", (real_t)0.95 }, + { "psi0", (real_t)1.0 }, + { "theta0", (real_t)1.0 }, + { "Omega", (real_t)0.5 } }); } catch (std::exception& e) { std::cerr << e.what() << std::endl; diff --git a/src/metrics/flux_surface.h b/src/metrics/flux_surface.h deleted file mode 100644 index 4c031094e..000000000 --- a/src/metrics/flux_surface.h +++ /dev/null @@ -1,361 +0,0 @@ -/** - * @file metrics/flux_surface.h - * @brief metric along constant flux surfaces in force-free fields, based on totoised Boyer-Lindquist coordinates - * @implements - * - metric::FluxSurface<> : metric::MetricBase<> - * @namespaces: - * - metric:: - * !TODO - * None radial surfaces needs to be implemented (dpsi_dr != 0). - */ - -#ifndef METRICS_FLUX_SURFACE_H -#define METRICS_FLUX_SURFACE_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "utils/numeric.h" - -#include "metrics/metric_base.h" - -#include -#include -#include - - -namespace metric { - - template - class FluxSurface : public MetricBase { - static_assert(D == Dim::_1D, "Only 1D flux_surface is available"); - - private: - // Spin parameter, in [0,1[ - // and horizon size in units of rg - // all physical extents are in units of rg - const real_t a, rg_, rh_, rh_m, psi0, theta0, Omega, pCur; - const real_t eta_max, eta_min; - const real_t d_eta, d_eta_inv; - - Inline auto Delta(const real_t& r) const -> real_t { - return SQR(r) - TWO * r + SQR(a); - } - - Inline auto Sigma(const real_t& r, const real_t& theta) const -> real_t { - return SQR(r) + SQR(a) * SQR(math::cos(theta)); - } - - Inline auto A(const real_t& r, const real_t& theta) const -> real_t { - return SQR(SQR(r) + SQR(a)) - SQR(a) * Delta(r) * SQR(math::sin(theta)); - } - - Inline auto omega(const real_t& r, const real_t& theta) const -> real_t { - return TWO * a * r / A(r, theta); - } - - Inline auto psi(const real_t& r, const real_t& theta) const -> real_t { - return psi0 * (1 - cos(theta)); - } - - - Inline auto dpsi_dtheta(const real_t& r, const real_t& theta) const -> real_t { - return psi0 * math::sin(theta); - } - - Inline auto r2eta(const real_t& r) const -> real_t{ - return math::log((r - rh_) / (r - rh_m)) / (rh_ - rh_m); - } - - Inline auto eta2theta(const real_t& eta) const -> real_t{ - return theta0; - } - - Inline auto eta2r(const real_t& eta) const -> real_t{ - return rh_m - TWO * math::sqrt(ONE - SQR(a)) / math::expm1(eta * TWO * math::sqrt(ONE - SQR(a))); - } - - - - - public: - static constexpr const char* Label { "flux_surface" }; - static constexpr Dimension PrtlDim { D }; - static constexpr ntt::Coord::type CoordType { ntt::Coord::Fs }; - static constexpr ntt::Metric::type MetricType { ntt::Metric::Flux_Surface }; - using MetricBase::x1_min; - using MetricBase::x1_max; - using MetricBase::nx1; - using MetricBase::set_dxMin; - - FluxSurface(std::vector res, - boundaries_t ext, - const std::map& params) - : MetricBase { res, ext } - , a { params.at("a") } - , psi0 { params.at("psi0") } - , theta0 { params.at("theta0") } - , pCur { params.at("pCur") } - , rg_ { ONE } - , rh_ { ONE + math::sqrt(ONE - SQR(a)) } - , rh_m { ONE - math::sqrt(ONE - SQR(a)) } - , Omega { params.at("Omega") * a / (SQR(a) + SQR(rh_)) } - , eta_min { r2eta(x1_min) } - , eta_max { r2eta(x1_max) } - , d_eta { (eta_max - eta_min) / nx1 } - , d_eta_inv { ONE / d_eta }{ - set_dxMin(find_dxMin()); - } - - ~FluxSurface() = default; - - [[nodiscard]] - Inline auto spin() const -> real_t { - return a; - } - - [[nodiscard]] - Inline auto rhorizon() const -> real_t { - return rh_; - } - - [[nodiscard]] - Inline auto rhorizon_minus() const -> real_t { - return rh_m; - } - - [[nodiscard]] - Inline auto rg() const -> real_t { - return rg_; - } - - [[nodiscard]] - Inline auto OmegaF() const -> real_t { - return Omega; - } - - - /** - * lapse function - * @param x coordinate array in code units - */ - Inline auto alpha(const coord_t& xi) const -> real_t { - const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - return math::sqrt(Sigma(r_, theta_) * Delta(r_) / A(r_, theta_)); - } - - /** - * shift vector, only third covariant component is non-zero - * @param x coordinate array in code units - */ - - Inline auto beta(const coord_t& xi) const -> real_t { - return math::sqrt(h<3, 3>(xi)) * omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min) ); - } - - Inline auto beta3(const coord_t& xi) const -> real_t { - return -omega(eta2r(xi[0] * d_eta + eta_min) , eta2theta(xi[0] * d_eta + eta_min)); - } - - /** - * @brief Compute helper functions f0,f1,f2 in 1D-GRPIC - */ - Inline auto f2(const coord_t& xi) const -> real_t { - const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - return SQR(d_eta) * Sigma(r_, theta_) * (Delta(r_) + - A(r_, theta_) * SQR(pCur / dpsi_dtheta(r_, theta_) ) - ); - } - - Inline auto f1(const coord_t& xi) const -> real_t { - const real_t r_ { eta2r(xi[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(xi[0] * d_eta + eta_min) }; - return d_eta * A(r_, theta_)* math::sin(theta_) * pCur * (Omega + beta3(xi)) / dpsi_dtheta(r_, theta_); - } - - Inline auto f0(const coord_t& xi) const -> real_t { - return h_<3, 3>(xi) * SQR(Omega + beta3(xi)); - } - - /** - * minimum effective cell size for a given metric (in physical units) - */ - [[nodiscard]] - auto find_dxMin() const -> real_t override { - real_t min_dx { -ONE }; - for (int i { 0 }; i < nx1; ++i){ - real_t i_ { static_cast(i) + HALF }; - coord_t xi { i_ }; - real_t dx = ONE / math::sqrt(h<1, 1>(xi)); - if ((min_dx > dx) || (min_dx < 0.0)) { - min_dx = dx; - } - } - return min_dx; - } - - /** - * metric component with lower indices: h_ij - * @param x coordinate array in code units - */ - template - Inline auto h_(const coord_t& x) const -> real_t { - static_assert(i > 0 && i <= 3, "Invalid index i"); - static_assert(j > 0 && j <= 3, "Invalid index j"); - - const real_t r_ { eta2r(x[0] * d_eta + eta_min) }; - const real_t theta_ { eta2theta(x[0] * d_eta + eta_min) }; - const real_t Sigma_ { Sigma(r_, theta_) }; - const real_t Delta_ { Delta(r_) }; - if constexpr (i == 1 && j == 1) { - // h_11 - return SQR(d_eta) * Sigma_ * Delta_; - } else if constexpr (i == 2 && j == 2) { - // h_22 - return Sigma_ / SQR(dpsi_dtheta(r_, theta_) ) ; - } else if constexpr (i == 3 && j == 3) { - // h_33 - return A(r_, theta_) * SQR(math::sin(theta_)) / Sigma_; - }else { - return ZERO; - } - } - - /** - * metric component with upper indices: h^ij - * @param x coordinate array in code units - */ - template - Inline auto h(const coord_t& x) const -> real_t { - static_assert(i > 0 && i <= 3, "Invalid index i"); - static_assert(j > 0 && j <= 3, "Invalid index j"); - - if constexpr (i == j) { - return ONE / h_(x); - }else { - return ZERO; - } - } - - /** - * sqrt(det(h_ij)) - * @param x coordinate array in code units - */ - Inline auto sqrt_det_h(const coord_t& x) const -> real_t { - return math::sqrt(h_<1, 1>(x) * h_<2, 2>(x) * h_<3, 3>(x)); - } - - /** - * coordinate conversions - */ - template - Inline void convert(const coord_t& x_in, coord_t& x_out) const { - static_assert(in != out, "Invalid coordinate conversion"); - static_assert((in != Crd::XYZ) && - (out != Crd::XYZ), - "Invalid coordinate conversion: XYZ not allowed in GR"); - if constexpr (in == Crd::Cd && (out == Crd::Sph || out == Crd::Ph)){ - // code -> sph/phys - x_out[0] = eta2r(x_in[0] * d_eta + eta_min); - }else if constexpr ((in == Crd::Sph || in == Crd::Ph) && out == Crd::Cd){ - //sph/phys -> code - x_out[0] = (r2eta(x_in[0]) - eta_min) / d_eta; - } - } - - - /** - * component wise vector transformations - */ - template - Inline auto transform(const coord_t& x, - const real_t& v_in) const -> real_t { - static_assert(in != out, "Invalid vector transformation"); - static_assert(in != Idx::XYZ && out != Idx::XYZ, - "Invalid vector transformation: XYZ not allowed in GR"); - static_assert(i > 0 && i <= 3, "Invalid index i"); - if constexpr ((in == Idx::T && out == Idx::Sph) || - (in == Idx::Sph && out == Idx::T)) { - // tetrad <-> sph - return v_in; - } else if constexpr (((in == Idx::T || in == Idx::Sph) && out == Idx::U) || - (in == Idx::D && (out == Idx::T || out == Idx::Sph))){ - // tetrad/sph -> cntrv ; cov -> tetrad/sph - if constexpr (i == 1){ - return v_in / math::sqrt(h_(x)) / Delta(eta2r(x[0] * d_eta + eta_min)); - }else if constexpr (i == 2){ - return v_in / math::sqrt(h_(x)) * - dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); - }else{ - return v_in / math::sqrt(h_(x)); - } - } else if constexpr ((in == Idx::U && (out == Idx::T || out == Idx::Sph)) || - ((in == Idx::T || in == Idx::Sph) && out == Idx::D)){ - // cntrv -> tetrad/sph ; tetrad/sph -> cov - if constexpr (i == 1){ - return v_in * math::sqrt(h_(x)) * Delta(eta2r(x[0] * d_eta + eta_min)); - }else if constexpr (i == 2){ - return v_in * math::sqrt(h_(x)) / - dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); - }else{ - return v_in * math::sqrt(h_(x)); - } - } else if constexpr (in == Idx::U && out == Idx::D) { - // cntrv -> cov - return v_in * h_(x); - } else if constexpr (in == Idx::D && out == Idx::U) { - // cov -> cntrv - return v_in * h(x); - } else if constexpr ((in == Idx::U && out == Idx::PU) || - (in == Idx::PD && out == Idx::D)) { - // cntrv -> phys cntrv || phys cov -> cov - if constexpr (i == 1){ - return v_in * Delta(eta2r(x[0] * d_eta + eta_min)) * d_eta ; - }else if constexpr (i == 2){ - return v_in / dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min) ); - }else{ - return v_in; - } - } else if constexpr ((in == Idx::PU && out == Idx::U) || - (in == Idx::D && out == Idx::PD)) { - // phys cntrv -> cntrv || cov -> phys cov - if constexpr (i == 1){ - return v_in * d_eta_inv / Delta(eta2r(x[0] * d_eta + eta_min)); - }else if constexpr (i == 2){ - return v_in * dpsi_dtheta(eta2r(x[0] * d_eta + eta_min), eta2theta(x[0] * d_eta + eta_min)); - }else{ - return v_in; - } - } else { - raise::KernelError(HERE, "Invalid transformation"); - } - } - - /** - * full vector transformations - */ - template - Inline void transform(const coord_t& xi, - const vec_t& v_in, - vec_t& v_out) const { - static_assert(in != out, "Invalid vector transformation"); - if constexpr (in != Idx::XYZ && out != Idx::XYZ) { - v_out[0] = transform<1, in, out>(xi, v_in[0]); - v_out[1] = transform<2, in, out>(xi, v_in[1]); - v_out[2] = transform<3, in, out>(xi, v_in[2]); - } else { - raise::KernelError(HERE, "Invalid vector transformation"); - } - } - - }; - - - -} - - -#endif // METRICS_FLUX_SURFACE_H diff --git a/src/metrics/tests/CMakeLists.txt b/src/metrics/tests/CMakeLists.txt index c2e4c1ce8..410497e25 100644 --- a/src/metrics/tests/CMakeLists.txt +++ b/src/metrics/tests/CMakeLists.txt @@ -28,4 +28,4 @@ gen_test(coord_trans) gen_test(sph-qsph) gen_test(ks-qks) gen_test(sr-cart-sph) -gen_test(fs) +gen_test(bltp) diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 11c0f8d8a..f507063c1 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -3,7 +3,6 @@ #include "arch/kokkos_aliases.h" #include "utils/comparators.h" -#include "metrics/flux_surface.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" #include "metrics/minkowski.h" diff --git a/src/metrics/tests/fs.cpp b/src/metrics/tests/fs.cpp deleted file mode 100644 index 9f905d380..000000000 --- a/src/metrics/tests/fs.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "utils/comparators.h" - -#include "metrics/flux_surface.h" - -#include -#include -#include -#include - -void errorIf(bool condition, const std::string& message) { - if (condition) { - throw std::runtime_error(message); - } -} - -inline static constexpr auto epsilon = std::numeric_limits::epsilon(); - -template -Inline auto equal(const vec_t& a, - const vec_t& b, - const char* msg, - const real_t acc = ONE) -> bool { - const auto eps = epsilon * acc; - for (unsigned short d = 0; d < D; ++d) { - if (not cmp::AlmostEqual(a[d], b[d], eps)) { - printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); - return false; - } - } - return true; -} - -Inline auto equal(const real_t& a, - const real_t& b, - const char* msg, - const real_t acc = ONE) -> bool { - const auto eps = epsilon * acc; - if (not cmp::AlmostEqual(a, b, eps)) { - printf("%.12e != %.12e %s\n", a, b, msg); - return false; - } - return true; -} - -template -Inline void unravel(std::size_t idx, - tuple_t& ijk, - const tuple_t& res) { - for (unsigned short d = 0; d < D; ++d) { - ijk[d] = idx % res[d]; - idx /= res[d]; - } -} - -template -void testMetric(const std::vector& res, - const boundaries_t& ext, - const real_t acc = ONE, - const std::map& params = {}) { - static_assert(M::Dim == 1, "Dim != 1"); - errorIf(res.size() != (std::size_t)(M::Dim), "res.size() != M.dim"); - errorIf(ext.size() != (std::size_t)(M::Dim), "ext.size() != M.dim"); - for (const auto& e : ext) { - errorIf(e.first >= e.second, "e.first >= e.second"); - } - - M metric(res, ext, params); - tuple_t res_tup; - std::size_t npts = 1; - for (auto d = 0; d < M::Dim; ++d) { - res_tup[d] = res[d]; - npts *= res[d]; - } - - const auto x_min = ext[0].first; - const auto x_max = ext[0].second; - - - unsigned long all_wrongs = 0; - const auto rg = metric.rg(); - const auto rh = metric.rhorizon(); - const auto a = metric.spin(); - const auto th = params.at("theta0"); - const auto psi0 = params.at("psi0"); - const auto pCur = params.at("pCur"); - const auto Omega = params.at("Omega") * a / (SQR(a) + SQR(rh)); - const auto rh_m = rh - TWO * math::sqrt(ONE - SQR(a)); - - const auto eta_min = math::log((x_min - rh) / (x_min - rh_m)) / (rh - rh_m); - const auto eta_max = math::log((x_max - rh) / (x_max - rh_m)) / (rh - rh_m); - const auto d_eta = (eta_max - eta_min) / ((real_t)res[0]); - - Kokkos::parallel_reduce( - "h_ij/hij", - npts, - Lambda(index_t n, unsigned long& wrongs) { - tuple_t idx; - unravel(n, idx, res_tup); - coord_t x_Code { ZERO }; - coord_t x_Phys { ZERO }; - - for (unsigned short d = 0; d < M::Dim; ++d) { - x_Code[d] = (real_t)(idx[d]) + HALF; - } - - const auto h11 = metric.template h<1, 1>(x_Code); - const auto h22 = metric.template h<2, 2>(x_Code); - const auto h33 = metric.template h<3, 3>(x_Code); - const auto h_11 = metric.template h_<1, 1>(x_Code); - const auto h_22 = metric.template h_<2, 2>(x_Code); - const auto h_33 = metric.template h_<3, 3>(x_Code); - - metric.template convert(x_Code, x_Phys); - const auto r = x_Phys[0]; - - - const auto Sigma = SQR(r) + SQR(a * math::cos(th)); - const auto Delta = SQR(r) - TWO * rg * r + SQR(a); - const auto A = SQR(SQR(r) + SQR(a)) - SQR(a * math::sin(th)) * Delta; - const auto dpsi_r = 0; - const auto dpsi_dtheta = psi0 * math::sin(th); - const auto omega = TWO * a * r / A ; - - const auto h_11_expect = Sigma / Delta; - const auto h_22_expect = Sigma ; - const auto h_33_expect = A * SQR(math::sin(th)) / Sigma; - const auto h11_expect = ONE / h_11_expect; - const auto h22_expect = ONE / h_22_expect; - const auto h33_expect = ONE / h_33_expect; - - const auto f0_expect = h_33_expect * SQR(Omega - omega); - const auto f1_expect = d_eta * A * pCur * math::sin(th) * (Omega - omega) / dpsi_dtheta; - const auto f2_expect = SQR(d_eta) * Sigma * (Delta + A * SQR(pCur / dpsi_dtheta)); - - const auto f0_predict = metric.f0(x_Code); - const auto f1_predict = metric.f1(x_Code); - const auto f2_predict = metric.f2(x_Code); - - - vec_t hij_temp { ZERO }, hij_predict { ZERO }; - metric.template transform(x_Code, { h11, h22, h33 }, hij_temp); - metric.template transform(x_Code, hij_temp, hij_predict); - - - vec_t h_ij_temp { ZERO }, h_ij_predict { ZERO }; - metric.template transform(x_Code, - { h_11, h_22, h_33 }, - h_ij_temp); - metric.template transform(x_Code, h_ij_temp, h_ij_predict); - - - vec_t hij_expect { h11_expect, h22_expect, h33_expect }; - vec_t h_ij_expect { h_11_expect, h_22_expect, h_33_expect }; - - wrongs += not equal(hij_expect, hij_predict, "hij", acc); - wrongs += not equal(f0_expect, f0_predict, "f0", acc); - wrongs += not equal(f1_expect, f1_predict, "f1", acc); - wrongs += not equal(f2_expect, f2_predict, "f2", acc); - - }, - all_wrongs); - - errorIf(all_wrongs != 0, - "wrong h_ij/hij for " + std::to_string(M::Dim) + "D " + - std::string(metric.Label) + " with " + std::to_string(all_wrongs) + - " errors"); -} - -auto main(int argc, char* argv[]) -> int { - Kokkos::initialize(argc, argv); - - try { - using namespace ntt; - using namespace metric; - testMetric>( - { 128 }, - { { 2.0, 50.0 } }, - 30, - { { "a", (real_t)0.95 } , - { "psi0", (real_t)1.0 } , - { "theta0", (real_t)1.0 } , - { "Omega", (real_t)0.5 } , - { "pCur", (real_t)3.1 } }); - } catch (std::exception& e) { - std::cerr << e.what() << std::endl; - Kokkos::finalize(); - return 1; - } - Kokkos::finalize(); - return 0; -} diff --git a/src/metrics/tests/vec_trans.cpp b/src/metrics/tests/vec_trans.cpp index d3882574c..3561b731e 100644 --- a/src/metrics/tests/vec_trans.cpp +++ b/src/metrics/tests/vec_trans.cpp @@ -3,7 +3,6 @@ #include "arch/kokkos_aliases.h" #include "utils/comparators.h" -#include "metrics/flux_surface.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" #include "metrics/minkowski.h" From f1dcf3b786c643a442b11264fdea148909d2131e Mon Sep 17 00:00:00 2001 From: StaticObserver Date: Thu, 2 Jan 2025 12:45:39 +0800 Subject: [PATCH 47/47] fix vec_trans in bltp metric;fix erros in ff_pusher test --- src/kernels/tests/ff_pusher.cpp | 4 ++-- src/metrics/boyer_lindq_tp.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/tests/ff_pusher.cpp b/src/kernels/tests/ff_pusher.cpp index a6eb46002..185e2b0fd 100644 --- a/src/kernels/tests/ff_pusher.cpp +++ b/src/kernels/tests/ff_pusher.cpp @@ -122,7 +122,7 @@ void testFFPusher(const std::vector& res, x1i = ZERO + (n % 10) * sep; from_Xi_to_i_di(x1i, ii, dx1i) put_value(i1, ii, n); put_value(dx1, dx1i, n); - put_value(px1, ZERO, n); + put_value(px1, ONE, n); put_value(tag, ParticleTag::alive, n); } @@ -224,7 +224,7 @@ auto main(int argc, char* argv[]) -> int { 128 }, { { 2.0, 20.0 } }, - 5, + 100, { { "a", (real_t)0.95 }, { "psi0", (real_t)1.0 }, { "theta0", (real_t)1.0 }, diff --git a/src/metrics/boyer_lindq_tp.h b/src/metrics/boyer_lindq_tp.h index 94c078516..78c4880ee 100644 --- a/src/metrics/boyer_lindq_tp.h +++ b/src/metrics/boyer_lindq_tp.h @@ -281,9 +281,9 @@ namespace metric { (in == Idx::D && (out == Idx::T || out == Idx::Sph))){ // tetrad/sph -> cntrv ; cov -> tetrad/sph if constexpr (i == 1){ - return v_in / math::sqrt(h_(x)) / Delta(eta2r(x[0] * d_eta + eta_min)); + return v_in / math::sqrt(h_(x)); }else if constexpr (i == 2){ - return v_in / math::sqrt(h_(x)) * dpsi_dth; + return v_in / math::sqrt(h_(x)); }else{ return v_in / math::sqrt(h_(x)); } @@ -291,9 +291,9 @@ namespace metric { ((in == Idx::T || in == Idx::Sph) && out == Idx::D)){ // cntrv -> tetrad/sph ; tetrad/sph -> cov if constexpr (i == 1){ - return v_in * math::sqrt(h_(x)) * Delta(eta2r(x[0] * d_eta + eta_min)); + return v_in * math::sqrt(h_(x)); }else if constexpr (i == 2){ - return v_in * math::sqrt(h_(x)) / dpsi_dth; + return v_in * math::sqrt(h_(x)); }else{ return v_in * math::sqrt(h_(x)); }