@@ -284,6 +284,8 @@ namespace arch {
284284 ~NonUniformInjector () = default ;
285285 };
286286
287+
288+
287289 template <SimEngine::type S, class M , bool P, in O>
288290 struct AtmosphereInjector {
289291 struct TargetDensityProfile {
@@ -734,6 +736,112 @@ namespace arch {
734736 }
735737 }
736738
739+ namespace experimental {
740+ template <SimEngine::type S,
741+ class M ,
742+ template <SimEngine::type, class > class ED ,
743+ template <SimEngine::type, class > class SD1 ,
744+ template <SimEngine::type, class > class SD2 >
745+ struct Injector_with_weights {
746+ using energy_dist_t = ED<S, M>;
747+ using spatial_dist_t1 = SD1<S, M>;
748+ using spatial_dist_t2 = SD2<S, M>;
749+ static_assert (M::is_metric, " M must be a metric class" );
750+ static_assert (energy_dist_t ::is_energy_dist,
751+ " E must be an energy distribution class" );
752+ static_assert (spatial_dist_t1::is_spatial_dist,
753+ " SD must be a spatial distribution class" );
754+ static_assert (spatial_dist_t2::is_spatial_dist,
755+ " SD must be a spatial distribution class" );
756+ static constexpr bool is_nonuniform_injector { true };
757+ static constexpr Dimension D { M::Dim };
758+ static constexpr Coord C { M::CoordType };
759+
760+ const energy_dist_t energy_dist;
761+ const spatial_dist_t1 spatial_dist1;
762+ const spatial_dist_t2 spatial_dist2;
763+ const std::pair<spidx_t , spidx_t > species;
764+
765+ Injector_with_weights (const energy_dist_t & energy_dist,
766+ const spatial_dist_t1& spatial_dist1,
767+ const spatial_dist_t2& spatial_dist2,
768+ const std::pair<spidx_t , spidx_t >& species)
769+ : energy_dist { energy_dist }
770+ , spatial_dist1 { spatial_dist1 }
771+ , spatial_dist2 { spatial_dist2 }
772+ , species { species } {}
773+
774+ ~Injector_with_weights () = default ;
775+ }; // struct Injector_with_weights
776+
777+ template <SimEngine::type S, class M , class I >
778+ inline void InjectWithWeights (const SimulationParams& params,
779+ Domain<S, M>& domain,
780+ const I& injector,
781+ real_t number_density,
782+ const boundaries_t <real_t >& box = {}) {
783+ static_assert (M::is_metric, " M must be a metric class" );
784+ static_assert (I::is_nonuniform_injector,
785+ " I must be a nonuniform injector class" );
786+ raise::ErrorIf (
787+ not params.template get <bool >(" particles.use_weights" ),
788+ " Weights must be enabled for the injector" ,
789+ HERE);
790+ if (domain.species [injector.species .first - 1 ].charge () +
791+ domain.species [injector.species .second - 1 ].charge () !=
792+ 0 .0f ) {
793+ raise::Warning (" Total charge of the injected species is non-zero" , HERE);
794+ }
795+ {
796+ range_t <M::Dim> cell_range;
797+ if (box.size () == 0 ) {
798+ cell_range = domain.mesh .rangeActiveCells ();
799+ } else {
800+ raise::ErrorIf (box.size () != M::Dim,
801+ " Box must have the same dimension as the mesh" ,
802+ HERE);
803+ boundaries_t <bool > incl_ghosts;
804+ for (auto d = 0 ; d < M::Dim; ++d) {
805+ incl_ghosts.push_back ({ false , false });
806+ }
807+ const auto extent = domain.mesh .ExtentToRange (box, incl_ghosts);
808+ tuple_t <ncells_t , M::Dim> x_min { 0 }, x_max { 0 };
809+ for (auto d = 0 ; d < M::Dim; ++d) {
810+ x_min[d] = extent[d].first ;
811+ x_max[d] = extent[d].second ;
812+ }
813+ cell_range = CreateRangePolicy<M::Dim>(x_min, x_max);
814+ }
815+ const auto ppc = number_density *
816+ params.template get <real_t >(" particles.ppc0" ) * HALF;
817+ auto injector_kernel =
818+ kernel::experimental::Injector_with_weights_kernel<S, M, typename I::energy_dist_t , typename I::spatial_dist_t1, typename I::spatial_dist_t2>(
819+ ppc,
820+ injector.species .first ,
821+ injector.species .second ,
822+ domain.species [injector.species .first - 1 ],
823+ domain.species [injector.species .second - 1 ],
824+ domain.species [injector.species .first - 1 ].npart (),
825+ domain.species [injector.species .second - 1 ].npart (),
826+ domain.mesh .metric ,
827+ injector.energy_dist ,
828+ injector.spatial_dist1 ,
829+ injector.spatial_dist2 ,
830+ ONE / params.template get <real_t >(" scales.V0" ),
831+ domain.random_pool );
832+ Kokkos::parallel_for (" InjectWithWeights" ,
833+ cell_range,
834+ injector_kernel);
835+ const auto n_inj = injector_kernel.number_injected ();
836+ domain.species [injector.species .first - 1 ].set_npart (
837+ domain.species [injector.species .first - 1 ].npart () + n_inj);
838+ domain.species [injector.species .second - 1 ].set_npart (
839+ domain.species [injector.species .second - 1 ].npart () + n_inj);
840+ }
841+ } // function InjectWithWeights
842+
843+ } // namespace experimental
844+
737845} // namespace arch
738846
739847#endif // ARCHETYPES_PARTICLE_INJECTOR_H
0 commit comments