diff --git a/src/archetypes/traits.h b/src/archetypes/traits.h index f453c7fc..a7004fbf 100644 --- a/src/archetypes/traits.h +++ b/src/archetypes/traits.h @@ -85,6 +85,14 @@ namespace arch { pgen.EmissionPolicy(time, sp, domain); }; + template + concept HasCustomPrtlBC = requires(const PG& pgen, + simtime_t time, + spidx_t sp, + D& domain) { + pgen.CustomParticleBoundary(time, sp, domain); + }; + template concept HasInitPrtls = requires(PG& pgen, D& domain) { { pgen.InitPrtls(domain) } -> std::same_as; diff --git a/src/engines/srpic/particle_pusher.h b/src/engines/srpic/particle_pusher.h index 47189e98..d0849c62 100644 --- a/src/engines/srpic/particle_pusher.h +++ b/src/engines/srpic/particle_pusher.h @@ -26,29 +26,39 @@ namespace ntt { namespace srpic { template - void CallPusher_WithExternalFieldFlag( - Domain& domain, - const SimulationParams& params, - const kernel::sr::PusherParams& pusher_params, - kernel::sr::PusherArrays& pusher_arrays, - EmissionTypeFlag emission_policy_flag, - const range_t& range, - const ndfield_t& EB, - const M& metric, - const PG& pgen, - const F& external_fields) { + void CallPusher(Domain& domain, + const SimulationParams& params, + const kernel::sr::PusherParams& pusher_params, + kernel::sr::PusherArrays& pusher_arrays, + EmissionTypeFlag emission_policy_flag, + const range_t& range, + const ndfield_t& EB, + const M& metric, + const PG& pgen, + const F& external_fields) { + auto get_custom_prtl_bc = [&]() { + if constexpr (arch::traits::pgen::HasCustomPrtlBC) { + return pgen.CustomParticleBoundary( + pusher_params.time, pusher_params.species_index, domain); + } else { + return kernel::sr::NoCustomPrtlBC_t {}; + } + }; + const auto custom_prtl_bc = get_custom_prtl_bc(); + if (emission_policy_flag == EmissionType::NONE) { const auto no_emission = kernel::NoEmissionPolicy_t {}; Kokkos::parallel_for( "ParticlePusher", range, - kernel::sr::Pusher_kernel( + kernel::sr::Pusher_kernel( pusher_params, pusher_arrays, EB, metric, external_fields, - no_emission)); + no_emission, + custom_prtl_bc)); } else if (emission_policy_flag == EmissionType::SYNCHROTRON) { const auto photon_species = params.get( "radiation.emission.synchrotron.photon_species"); @@ -78,13 +88,14 @@ namespace ntt { Kokkos::parallel_for( "ParticlePusher", range, - kernel::sr::Pusher_kernel( + kernel::sr::Pusher_kernel( pusher_params, pusher_arrays, EB, metric, external_fields, - emission_policy)); + emission_policy, + custom_prtl_bc)); const auto n_inj = emission_policy.numbers_injected(); raise::ErrorIf(n_inj.size() != 1, "Synchrotron emission should only inject one species", @@ -121,13 +132,14 @@ namespace ntt { Kokkos::parallel_for( "ParticlePusher", range, - kernel::sr::Pusher_kernel( + kernel::sr::Pusher_kernel( pusher_params, pusher_arrays, EB, metric, external_fields, - emission_policy)); + emission_policy, + custom_prtl_bc)); const auto n_inj = emission_policy.numbers_injected(); raise::ErrorIf(n_inj.size() != 1, "Compton emission should only inject one species", @@ -148,13 +160,14 @@ namespace ntt { Kokkos::parallel_for( "ParticlePusher", range, - kernel::sr::Pusher_kernel( + kernel::sr::Pusher_kernel( pusher_params, pusher_arrays, EB, metric, external_fields, - emission_policy)); + emission_policy, + custom_prtl_bc)); const auto emitted_species = emission_policy.emitted_species_indices(); const auto n_inj = emission_policy.numbers_injected(); raise::ErrorIf(emitted_species.size() != n_inj.size(), diff --git a/src/kernels/digital_filter.hpp b/src/kernels/digital_filter.hpp index 5ac60327..7f3e52f1 100644 --- a/src/kernels/digital_filter.hpp +++ b/src/kernels/digital_filter.hpp @@ -93,8 +93,8 @@ namespace kernel { ? (boundaries[2].second == FldsBC::CONDUCTOR) : false } , i1_max { size_[0] + N_GHOSTS } - , i2_max { (short)D > 1 ? (size_[1] + N_GHOSTS) : 0 } - , i3_max { (short)D > 2 ? (size_[2] + N_GHOSTS) : 0 } {} + , i2_max { (short)D > 1 ? (size_[(short)D > 1 ? 1 : 0] + N_GHOSTS) : 0 } + , i3_max { (short)D > 2 ? (size_[(short)D > 2 ? 2 : 0] + N_GHOSTS) : 0 } {} Inline void operator()(index_t i1) const { if constexpr ((D == Dim::_1D) && (C == Coord::Cart)) { diff --git a/src/kernels/particle_pusher_sr.hpp b/src/kernels/particle_pusher_sr.hpp index 6706842e..27b5d0a1 100644 --- a/src/kernels/particle_pusher_sr.hpp +++ b/src/kernels/particle_pusher_sr.hpp @@ -101,11 +101,17 @@ namespace kernel::sr { array_t tag; }; + template + struct NoCustomPrtlBC_t { + template + Inline void operator()(index_t, int, bool, const PusherKernel&) const {} + }; + /** * @tparam M Metric * @tparam F Additional force */ - template + template > requires metric::traits::HasD && metric::traits::HasTransformXYZ && metric::traits::HasConvertXYZ && metric::traits::HasTransform_i && metric::traits::HasConvert_i @@ -120,12 +126,13 @@ namespace kernel::sr { std::is_same>::value, "Invalid emission policy E for Pusher_kernel"); - private: const ParticlePusherFlags pusher_flags; const RadiativeDragFlags radiative_drag_flags; const randacc_ndfield_t EB; + public: + const spidx_t sp; array_t i1, i2, i3; array_t i1_prev, i2_prev, i3_prev; array_t dx1, dx2, dx3; @@ -135,13 +142,16 @@ namespace kernel::sr { array_t weight; array_t tag; const M metric; + const int ni1, ni2, ni3; + + private: const F external_fields; const E emission_policy; + const PBC custom_prtl_bc; const real_t coeff, dt; - const int ni1, ni2, ni3; bool is_absorb_i1min { false }, is_absorb_i1max { false }; bool is_absorb_i2min { false }, is_absorb_i2max { false }; bool is_absorb_i3min { false }, is_absorb_i3max { false }; @@ -151,6 +161,9 @@ namespace kernel::sr { bool is_reflect_i1min { false }, is_reflect_i1max { false }; bool is_reflect_i2min { false }, is_reflect_i2max { false }; bool is_reflect_i3min { false }, is_reflect_i3max { false }; + bool is_custom_i1min { false }, is_custom_i1max { false }; + bool is_custom_i2min { false }, is_custom_i2max { false }; + bool is_custom_i3min { false }, is_custom_i3max { false }; bool is_axis_i2min { false }, is_axis_i2max { false }; // gca parameters @@ -167,7 +180,8 @@ namespace kernel::sr { const randacc_ndfield_t& EB, const M& metric, const F& external_fields, - const E& emission_policy) + const E& emission_policy, + const PBC& custom_prtl_bc) : pusher_flags { pusher_params.pusher_flags } , radiative_drag_flags { pusher_params.radiative_drag_flags } , EB { EB } @@ -192,6 +206,8 @@ namespace kernel::sr { , metric { metric } , external_fields { external_fields } , emission_policy { emission_policy } + , custom_prtl_bc { custom_prtl_bc } + , time { pusher_params.time } , coeff { HALF * (pusher_params.charge / pusher_params.mass) * pusher_params.omegaB0 * pusher_params.dt } , dt { pusher_params.dt } @@ -252,6 +268,8 @@ namespace kernel::sr { is_periodic_i1max = (pusher_params.boundaries[0].second == PrtlBC::PERIODIC); is_reflect_i1min = (pusher_params.boundaries[0].first == PrtlBC::REFLECT); is_reflect_i1max = (pusher_params.boundaries[0].second == PrtlBC::REFLECT); + is_custom_i1min = (pusher_params.boundaries[0].first == PrtlBC::CUSTOM); + is_custom_i1max = (pusher_params.boundaries[0].second == PrtlBC::CUSTOM); if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { raise::ErrorIf(pusher_params.boundaries.size() < 2, "pusher_params.boundaries defined incorrectly", @@ -265,6 +283,8 @@ namespace kernel::sr { is_periodic_i2max = (pusher_params.boundaries[1].second == PrtlBC::PERIODIC); is_reflect_i2min = (pusher_params.boundaries[1].first == PrtlBC::REFLECT); is_reflect_i2max = (pusher_params.boundaries[1].second == PrtlBC::REFLECT); + is_custom_i2min = (pusher_params.boundaries[1].first == PrtlBC::CUSTOM); + is_custom_i2max = (pusher_params.boundaries[1].second == PrtlBC::CUSTOM); is_axis_i2min = (pusher_params.boundaries[1].first == PrtlBC::AXIS); is_axis_i2max = (pusher_params.boundaries[1].second == PrtlBC::AXIS); } @@ -281,6 +301,8 @@ namespace kernel::sr { is_periodic_i3max = (pusher_params.boundaries[2].second == PrtlBC::PERIODIC); is_reflect_i3min = (pusher_params.boundaries[2].first == PrtlBC::REFLECT); is_reflect_i3max = (pusher_params.boundaries[2].second == PrtlBC::REFLECT); + is_custom_i3min = (pusher_params.boundaries[2].first == PrtlBC::CUSTOM); + is_custom_i3max = (pusher_params.boundaries[2].second == PrtlBC::CUSTOM); } } @@ -1352,6 +1374,8 @@ namespace kernel::sr { i1(p) = 0; dx1(p) = ONE - dx1(p); invert_vel = true; + } else if (is_custom_i1min) { + custom_prtl_bc(p, 1, true, *this); } } else if (i1(p) >= ni1) { if (is_periodic_i1max) { @@ -1363,6 +1387,8 @@ namespace kernel::sr { i1(p) = ni1 - 1; dx1(p) = ONE - dx1(p); invert_vel = true; + } else if (is_custom_i1max) { + custom_prtl_bc(p, 1, false, *this); } } if (invert_vel) { @@ -1394,6 +1420,8 @@ namespace kernel::sr { i2(p) = 0; dx2(p) = ONE - dx2(p); invert_vel = true; + } else if (is_custom_i2min) { + custom_prtl_bc(p, 2, true, *this); } else if (is_axis_i2min) { i2(p) = 0; dx2(p) = ONE - dx2(p); @@ -1408,6 +1436,8 @@ namespace kernel::sr { i2(p) = ni2 - 1; dx2(p) = ONE - dx2(p); invert_vel = true; + } else if (is_custom_i2max) { + custom_prtl_bc(p, 2, false, *this); } else if (is_axis_i2max) { i2(p) = ni2 - 1; dx2(p) = ONE - dx2(p); @@ -1442,6 +1472,8 @@ namespace kernel::sr { i3(p) = 0; dx3(p) = ONE - dx3(p); invert_vel = true; + } else if (is_custom_i3min) { + custom_prtl_bc(p, 3, true, *this); } } else if (i3(p) >= ni3) { if (is_periodic_i3max) { @@ -1453,6 +1485,8 @@ namespace kernel::sr { i3(p) = ni3 - 1; dx3(p) = ONE - dx3(p); invert_vel = true; + } else if (is_custom_i3max) { + custom_prtl_bc(p, 3, false, *this); } } if (invert_vel) {