BioCMAMC-ST
move_kernel.hpp
1#ifndef __SIMULATION_MOVE_KERNEL_HPP__
2#define __SIMULATION_MOVE_KERNEL_HPP__
3
4#include "Kokkos_Macros.hpp"
5#include "common/common.hpp"
6#include <Kokkos_Assert.hpp>
7#include <Kokkos_Core.hpp>
8#include <Kokkos_Printf.hpp>
9#include <Kokkos_Random.hpp>
10#include <biocma_cst_config.hpp>
11#include <cassert>
12#include <decl/Kokkos_Declare_OPENMP.hpp>
13#include <mc/alias.hpp>
14#include <mc/domain.hpp>
15#include <mc/events.hpp>
16#include <mc/prng/prng.hpp>
17#include <mc/traits.hpp>
18#include <simulation/alias.hpp>
19#include <simulation/move_info.hpp>
20#include <simulation/probability_leaving.hpp>
21#include <simulation/probe.hpp>
22#include <utility>
23
25{
26 constexpr bool enable_leave = true;
27 constexpr bool disable_leave = false;
28 constexpr bool disable_move = false;
29 constexpr bool enable_move = true;
30
31 // KOKKOS_INLINE_FUNCTION std::size_t __find_next_compartment(
32 // const ConstNeighborsView<ComputeSpace>& neighbors,
33 // const CumulativeProbabilityView<ComputeSpace>& cumulative_probability,
34 // const std::size_t i_compartment,
35 // const double random_number)
36 // {
37 // const int max_neighbor = static_cast<int>(neighbors.extent(1));
38
39 // std::size_t next =
40 // neighbors(i_compartment, 0); // Default to the first neighbor
41
42 // // Iterate through the neighbors to find the appropriate next compartment
43 // for (int k_neighbor = 0; k_neighbor < max_neighbor - 1; ++k_neighbor)
44 // {
45
46 // // Get the cumulative probability range for the current neighbor
47 // const auto pi = cumulative_probability(i_compartment, k_neighbor);
48 // const auto pn = cumulative_probability(i_compartment, k_neighbor + 1);
49
50 // // Use of a Condition mask to avoid branching.
51 // next = (random_number <= pn && pi <= random_number)
52 // ? neighbors(i_compartment, k_neighbor + 1)
53 // : next;
54 // }
55
56 // return next; // Return the index of the chosen next compartment
57 // }
58
64 KOKKOS_INLINE_FUNCTION std::size_t __find_next_compartment(
65 const bool do_serch,
66 const ConstNeighborsView<ComputeSpace>& neighbors,
67 const CumulativeProbabilityView<ComputeSpace>& cumulative_probability,
68 const std::size_t i_compartment,
69 const double random_number)
70 {
71 const int mask_do_serch = static_cast<int>(do_serch);
72
73 const int max_neighbor = static_cast<int>(neighbors.extent(1));
74
75 int left = 0;
76 int right = mask_do_serch * (max_neighbor - 1);
77 while (left < right)
78 {
79 int mid = (left + right) >> 1; // NOLINT
80 const auto pm = cumulative_probability(i_compartment, mid);
81 const int mask = static_cast<int>(random_number > pm);
82 left = mask * (mid + 1) + (1 - mask) * left;
83 right = mask * right + (1 - mask) * mid;
84 }
85
86 const auto ret = i_compartment * (1 - mask_do_serch) +
87 neighbors(i_compartment, left) * mask_do_serch;
88 return ret;
89 }
90
91 // KOKKOS_INLINE_FUNCTION std::size_t __find_next_compartment(
92 // const bool do_serch,
93 // const ConstNeighborsView<ComputeSpace>& neighbors,
94 // const CumulativeProbabilityView<ComputeSpace>& cumulative_probability,
95 // const std::size_t i_compartment,
96 // const double random_number)
97 // {
98 // const int mask_do_serch = static_cast<int>(do_serch);
99
100 // const int max_neighbor =
101 // mask_do_serch * static_cast<int>(neighbors.extent(1));
102
103 // std::size_t next =
104 // i_compartment * (1 - mask_do_serch) +
105 // mask_do_serch *
106 // neighbors(i_compartment, 0); // Default to the first neighbor
107
108 // for (int k_neighbor = 0; k_neighbor < max_neighbor - 1; ++k_neighbor)
109 // {
110
111 // // Get the cumulative probability range for the current neighbor
112 // const auto pi = cumulative_probability(i_compartment, k_neighbor);
113 // const auto pn = cumulative_probability(i_compartment, k_neighbor + 1);
114
115 // const auto cond =
116 // static_cast<int>(random_number <= pn && pi <= random_number);
117
118 // // Use of a Condition mask to avoid branching.
119 // next = cond * neighbors(i_compartment, k_neighbor + 1) + cond * next;
120 // }
121
122 // return next;
123 // }
124
125 struct TagMove
126 {
127 };
128 struct TagLeave
129 {
130 };
131
133 {
134 MoveFunctor() = default;
136 MC::ParticleStatus _status,
138 MC::pool_type _random_pool,
139 MC::EventContainer _events,
141 MC::ParticleAges _ages,
142 MC::ParticleSamples _random)
143 : MoveFunctor(0,
144 std::move(p),
145 std::move(_status),
146 0,
147 std::move(m),
148 std::move(_random_pool),
149 std::move(_events),
150 std::move(_probes),
151 std::move(_ages),
152 std::move(_random),
153 false,
154 false) {};
155
156 MoveFunctor(double _d_t,
158 MC::ParticleStatus _status,
159 std::size_t n_p,
161 MC::pool_type _random_pool,
162 MC::EventContainer _events,
164 MC::ParticleAges _ages,
165 MC::ParticleSamples _random,
166 bool b_move,
167 bool b_leave)
168 : d_t(_d_t), positions(std::move(p)), n_particles(n_p),
169 move(std::move(m)), random_pool(_random_pool), // NOLINT
170 status(std::move(_status)), events(std::move(_events)),
171 probes(std::move(_probes)), ages(std::move(_ages)),
172 random(std::move(_random)), enable_move(b_move),
173 enable_leave(b_leave) {};
174
175 void update(const ComputeSpace& ex,
176 double _d_t,
177 std::size_t n_p,
178 MoveInfo<ComputeSpace>&& move_i,
179 MC::ParticlePositions _positions,
180 MC::ParticleStatus _status,
181 MC::ParticleAges _ages,
182 MC::ParticleSamples _random,
183 bool b_move,
184 bool b_leave)
185 {
186
187 this->d_t = _d_t;
188 this->n_particles = n_p;
189 this->enable_leave = b_leave;
190 this->enable_move = b_move;
191 this->move = std::move(move_i);
192 this->random = std::move(_random);
193
194 this->positions = std::move(_positions);
195 this->status = std::move(_status);
196 this->ages = std::move(_ages);
197
198 Kokkos::fill_random(ex, random, random_pool, 0., 1.);
199 }
200
201 KOKKOS_INLINE_FUNCTION void operator()(
202 TagMove _tag,
203 const Kokkos::TeamPolicy<ComputeSpace>::member_type& team_handle) const
204 {
205 (void)_tag;
206 GET_INDEX(n_particles);
207 if (status(idx) != MC::Status::Idle) [[unlikely]]
208 {
209 return;
210 }
211
212 handle_move(idx);
213 }
214
215 // KOKKOS_INLINE_FUNCTION void
216 // operator()(TagLeave _tag,
217 // const Kokkos::TeamPolicy<ComputeSpace>::member_type& team,
218 // std::size_t& local_dead_count) const
219 // {
220 // const auto work_stride = team.team_size() * team.league_size();
221 // const auto work_end = n_particles;
222
223 // std::size_t iwork =
224 // team.league_rank() * team.team_size() + team.team_rank();
225
226 // for (; iwork < work_end; iwork += work_stride)
227 // {
228 // ages(iwork, 0) += d_t;
229 // handle_exit(iwork, local_dead_count);
230 // }
231 // }
232 //
233 KOKKOS_INLINE_FUNCTION void operator()([[maybe_unused]] TagLeave _tag,
234 const std::size_t& idx,
235 std::size_t& local_dead_count) const
236 {
237
238 ages(idx, 0) += d_t;
239 handle_exit(idx, local_dead_count);
240 }
241
242 // KOKKOS_INLINE_FUNCTION void
243 // operator()(TagLeave _tag,
244 // const Kokkos::TeamPolicy<ComputeSpace>::member_type&
245 // team_handle, std::size_t& local_dead_count) const
246 // {
247 // (void)_tag;
248 // const std::size_t league_size = team_handle.league_size();
249 // const std::size_t league_rank = team_handle.league_rank();
250 // const std::size_t start_idx = league_rank * (n_particles /
251 // league_size); std::size_t end_idx = (league_rank + 1) * (n_particles /
252 // league_size);
253
254 // if (league_rank == (league_size - 1))
255 // {
256 // end_idx = n_particles;
257 // }
258 // Kokkos::parallel_for(
259 // Kokkos::TeamThreadRange(team_handle, start_idx, end_idx),
260 // [&](int idx)
261 // {
262 // ages(idx, 0) += d_t;
263 // handle_exit(idx, local_dead_count);
264 // });
265 // }
266
267 [[nodiscard]] bool need_launch() const
268 {
269 return enable_leave || enable_move;
270 }
271
272 KOKKOS_FUNCTION void handle_move(const std::size_t idx) const
273 {
274 // auto generator = random_pool.get_state();
275 // const float rng1 = generator.frand(0., 1.);
276 // const double rng2 = generator.drand(0., 1.);
277 // random_pool.free_state(generator);
278
279 const auto rng1 = static_cast<float>(random(idx, 0));
280 const auto rng2 = static_cast<float>(random(idx, 1));
281
282 const std::size_t i_current_compartment = positions(idx);
283
284 KOKKOS_ASSERT(i_current_compartment < move.liquid_volume.extent(0));
285
286 const bool mask_next =
288 move.liquid_volume(i_current_compartment),
289 move.diag_transition(i_current_compartment),
290 d_t);
291
292 positions(idx) = __find_next_compartment(mask_next,
293 move.neighbors,
294 move.cumulative_probability,
295 i_current_compartment,
296 rng2);
297
298 // positions(idx) =
299 // (mask_next) ? __find_next_compartment(move.neighbors,
300 // move.cumulative_probability,
301 // i_current_compartment,
302 // rng2)
303 // : i_current_compartment;
304
305 KOKKOS_ASSERT(positions(idx) < move.liquid_volume.extent(0));
306
307 if constexpr (AutoGenerated::FlagCompileTime::enable_event_counter)
308 {
309 if (mask_next)
310 {
311 events.wrap_incr<MC::EventType::Move>();
312 }
313 }
314 }
315
316 KOKKOS_INLINE_FUNCTION void
317 inner_handle_exit(const std::size_t i_flow,
318 const std::size_t idx,
319 std ::size_t& dead_count,
320 const double liquid_volume,
321 const std::size_t position) const
322 {
323 // const float random_number = random(idx, i);
324
325 // SAMPLE_RANDOM_VARIABLES(random_pool,
326 // const float random_number =
327 // _generator_state_.frand(0., 1.);)
328
329 // FIXME when move AND exit, take the same random number, is it really
330 // important ?
331 const auto random_number = static_cast<float>(random(idx, 0));
332 const auto& [index, flow] = move.leaving_flow(i_flow);
333
334 const bool is_leaving =
335 (position == index) &&
336 probability_leaving<void>(random_number, liquid_volume, flow, d_t);
337
338 const int leave_mask = static_cast<int>(is_leaving);
339
340 // If using probes
341 if constexpr (AutoGenerated::FlagCompileTime::use_probe)
342 {
343 // Execute probe set, but only actually do something if leaving
344
345 if (is_leaving)
346 {
347 probes.set(ages(idx, 0));
348 }
349
350 // if (is_leaving && !probes.set(probe_value))
351 // {
352 // Kokkos::printf("[Kernel]: PROBES OVERFLOW\r\n");
353 // }
354 }
355 if constexpr (AutoGenerated::FlagCompileTime::enable_event_counter)
356 {
357 // if (is_leaving)
358 // {
359 // events.incr<MC::EventType::Exit>();
360 // }
361 events.add<MC::EventType::Exit>(leave_mask);
362 }
363
364 dead_count += leave_mask;
365 ages(idx, 0) = leave_mask * 0 + (1 - leave_mask) * ages(idx, 0);
366 // status(idx) = is_leaving ? MC::Status::Exit : status(idx);
367 status(idx) = static_cast<MC::Status>(
368 static_cast<int>(MC::Status::Exit) * leave_mask +
369 (1 - leave_mask) * static_cast<int>(status(idx)));
370 }
371
372 KOKKOS_FORCEINLINE_FUNCTION void handle_exit(std::size_t idx,
373 std::size_t& dead_count) const
374 {
375 const auto position = positions(idx);
376 const std::size_t n_flow = move.leaving_flow.size();
377 const auto liquid_volume = move.liquid_volume(position);
378 for (std::size_t i_flow = 0LU; i_flow < n_flow; ++i_flow)
379 {
380 inner_handle_exit(i_flow, idx, dead_count, liquid_volume, position);
381 }
382 }
383
384 double d_t{};
386 std::size_t n_particles{};
393 // Kokkos::View<float**, Kokkos::LayoutLeft> random;
394
396
399 };
400} // namespace Simulation::KernelInline
401
402#endif
Kokkos::View< Status *, ComputeSpace > ParticleStatus
Definition alias.hpp:71
Kokkos::View< uint64_t *, ComputeSpace > ParticlePositions
Definition alias.hpp:70
@ Move
Move in domain.
Definition events.hpp:20
@ Exit
Remove particle from list due to move in domain.
Definition events.hpp:19
Status
Definition alias.hpp:57
@ Idle
Definition alias.hpp:58
@ Exit
Definition alias.hpp:60
ParticleAgesBase< ComputeSpace > ParticleAges
Definition alias.hpp:73
gen_pool_type< Kokkos::DefaultExecutionSpace > pool_type
Definition alias.hpp:38
Kokkos:: View< Kokkos::Experimental::half_t **, Kokkos::LayoutRight, ComputeSpace > ParticleSamples
Definition alias.hpp:75
Definition kernels.hpp:11
constexpr bool enable_leave
Definition move_kernel.hpp:26
constexpr bool enable_move
Definition move_kernel.hpp:29
constexpr bool disable_leave
Definition move_kernel.hpp:27
KOKKOS_INLINE_FUNCTION bool probability_leaving(float random_number, double volume, double flow, double dt)
Definition probability_leaving.hpp:21
KOKKOS_INLINE_FUNCTION bool probability_leaving< void >(float random_number, double volume, double flow, double dt)
Definition probability_leaving.hpp:33
KOKKOS_INLINE_FUNCTION std::size_t __find_next_compartment(const bool do_serch, const ConstNeighborsView< ComputeSpace > &neighbors, const CumulativeProbabilityView< ComputeSpace > &cumulative_probability, const std::size_t i_compartment, const double random_number)
probably overkill binary search to find next compartment
Definition move_kernel.hpp:64
constexpr bool disable_move
Definition move_kernel.hpp:28
Probes< AutoGenerated::probe_buffer_size > ProbeAutogeneratedBuffer
Definition probe.hpp:61
Kokkos::View< const double **, Kokkos::LayoutRight, Space, Kokkos::MemoryTraits< Kokkos::RandomAccess > > CumulativeProbabilityView
Definition alias.hpp:20
Use to count events that occurs during Monte-Carlo processing cycles.
Definition events.hpp:44
KOKKOS_FORCEINLINE_FUNCTION void handle_exit(std::size_t idx, std::size_t &dead_count) const
Definition move_kernel.hpp:372
KOKKOS_INLINE_FUNCTION void inner_handle_exit(const std::size_t i_flow, const std::size_t idx, std ::size_t &dead_count, const double liquid_volume, const std::size_t position) const
Definition move_kernel.hpp:317
bool enable_leave
Definition move_kernel.hpp:398
KOKKOS_INLINE_FUNCTION void operator()(TagLeave _tag, const std::size_t &idx, std::size_t &local_dead_count) const
Definition move_kernel.hpp:233
MoveFunctor(MC::ParticlePositions p, MC::ParticleStatus _status, MoveInfo< ComputeSpace > m, MC::pool_type _random_pool, MC::EventContainer _events, ProbeAutogeneratedBuffer _probes, MC::ParticleAges _ages, MC::ParticleSamples _random)
Definition move_kernel.hpp:135
MoveFunctor(double _d_t, MC::ParticlePositions p, MC::ParticleStatus _status, std::size_t n_p, MoveInfo< ComputeSpace > m, MC::pool_type _random_pool, MC::EventContainer _events, ProbeAutogeneratedBuffer _probes, MC::ParticleAges _ages, MC::ParticleSamples _random, bool b_move, bool b_leave)
Definition move_kernel.hpp:156
KOKKOS_FUNCTION void handle_move(const std::size_t idx) const
Definition move_kernel.hpp:272
void update(const ComputeSpace &ex, double _d_t, std::size_t n_p, MoveInfo< ComputeSpace > &&move_i, MC::ParticlePositions _positions, MC::ParticleStatus _status, MC::ParticleAges _ages, MC::ParticleSamples _random, bool b_move, bool b_leave)
Definition move_kernel.hpp:175
MC::ParticleSamples random
Definition move_kernel.hpp:395
bool need_launch() const
Definition move_kernel.hpp:267
MC::ParticlePositions positions
Definition move_kernel.hpp:385
double d_t
Definition move_kernel.hpp:384
std::size_t n_particles
Definition move_kernel.hpp:386
MoveInfo< ComputeSpace > move
Definition move_kernel.hpp:387
MC::EventContainer events
Definition move_kernel.hpp:390
ProbeAutogeneratedBuffer probes
Definition move_kernel.hpp:391
MC::ParticleStatus status
Definition move_kernel.hpp:389
bool enable_move
Definition move_kernel.hpp:397
MC::ParticleAges ages
Definition move_kernel.hpp:392
MC::pool_type random_pool
Definition move_kernel.hpp:388
KOKKOS_INLINE_FUNCTION void operator()(TagMove _tag, const Kokkos::TeamPolicy< ComputeSpace >::member_type &team_handle) const
Definition move_kernel.hpp:201
Definition move_info.hpp:19
Definition move_kernel.hpp:129
Definition move_kernel.hpp:126