diff --git a/CMakeLists.txt b/CMakeLists.txt index e3c580020..ab9895792 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(PROJECT_NAME entity) project( ${PROJECT_NAME} - VERSION 1.4.2 + VERSION 1.4.3 LANGUAGES CXX C) add_compile_options("-D ENTITY_VERSION=\"${PROJECT_VERSION}\"") set(hash_cmd "git diff --quiet src/ && echo $(git rev-parse HEAD) ") diff --git a/src/kernels/pushers/sr_policies.h b/src/kernels/pushers/sr_policies.h index b247b27b7..efcef1c78 100644 --- a/src/kernels/pushers/sr_policies.h +++ b/src/kernels/pushers/sr_policies.h @@ -102,6 +102,62 @@ namespace kernel::sr { } } + // The optional-method dispatch below is split into these free function + // templates on purpose. `if constexpr` whose condition depends only on a + // template parameter captured from an *enclosing* scope is not reliably + // discarded inside a generic lambda: several compilers (nvcc, intel, ...) + // still parse/instantiate the dead branch, which fails when the pgen does + // not define the optional method. Making the predicate a template parameter + // of a regular function template guarantees the dead branch is discarded. + + template + void DispatchEmissionPolicy(const PGen& pgen, + DOM& domain, + const PusherContext& pusher_ctx, + Next&& next) { + if constexpr (HasEP) { + next(pgen.EmissionPolicy(pusher_ctx.time, pusher_ctx.species_index, domain)); + } else { + raise::Error("Custom emission policy flag is set but problem " + "generator does not define an emission policy", + HERE); + } + } + + template + void DispatchCustomPrtlUpdate(const PGen& pgen, + DOM& domain, + const PusherContext& pusher_ctx, + Next&& next) { + if constexpr (HasCPU) { + next(pgen.CustomParticleUpdate(pusher_ctx.time, + pusher_ctx.species_index, + domain)); + } else { + next(::traits::custom_prtl_update::NoPolicy_t {}); + } + } + + template + void DispatchExternalFields(const PGen& pgen, + DOM& domain, + const PusherContext& pusher_ctx, + Next&& next) { + if constexpr (HasEF) { + const auto [apply_extfields, external_fields] = pgen.ExternalFields( + pusher_ctx.time, + pusher_ctx.species_index, + domain); + if (apply_extfields) { + next(external_fields); + } else { + next(::traits::extfields::NoPolicy_t {}); + } + } else { + next(::traits::extfields::NoPolicy_t {}); + } + } + template void MakePusherPolicy(const PGen& pgen, DOM& domain, @@ -110,6 +166,10 @@ namespace kernel::sr { ntt::EmissionTypeFlag emission_type, bool atm, F&& callback) { + constexpr bool has_emission = ::traits::pgen::HasEmissionPolicy; + constexpr bool has_cpu = ::traits::pgen::HasCustomPrtlUpdate; + constexpr bool has_extfields = ::traits::pgen::HasExternalFields; + auto with_emission = [&](auto next) { switch (emission_type) { case ntt::EmissionType::SYNCHROTRON: @@ -125,15 +185,7 @@ namespace kernel::sr { pusher_ctx)); break; case ntt::EmissionType::CUSTOM: - if constexpr (::traits::pgen::HasEmissionPolicy) { - next(pgen.EmissionPolicy(pusher_ctx.time, - pusher_ctx.species_index, - domain)); - } else { - raise::Error("Custom emission policy flag is set but problem " - "generator does not define an emission policy", - HERE); - } + DispatchEmissionPolicy(pgen, domain, pusher_ctx, next); break; case ntt::EmissionType::NONE: default: @@ -143,29 +195,11 @@ namespace kernel::sr { }; auto with_custom_prtl_upd = [&](auto next) { - if constexpr (::traits::pgen::HasCustomPrtlUpdate) { - next(pgen.CustomParticleUpdate(pusher_ctx.time, - pusher_ctx.species_index, - domain)); - } else { - next(::traits::custom_prtl_update::NoPolicy_t {}); - } + DispatchCustomPrtlUpdate(pgen, domain, pusher_ctx, next); }; auto with_ext_fields = [&](auto next) { - if constexpr (::traits::pgen::HasExternalFields) { - const auto [apply_extfields, external_fields] = pgen.ExternalFields( - pusher_ctx.time, - pusher_ctx.species_index, - domain); - if (apply_extfields) { - next(external_fields); - } else { - next(::traits::extfields::NoPolicy_t {}); - } - } else { - next(::traits::extfields::NoPolicy_t {}); - } + DispatchExternalFields(pgen, domain, pusher_ctx, next); }; with_emission([&](auto ep) {