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 <mc/alias.hpp>
13#include <mc/domain.hpp>
14#include <mc/events.hpp>
15#include <mc/prng/prng.hpp>
16#include <mc/traits.hpp>
17// #include <simulation/move_info.hpp>
18#include <simulation/probability_leaving.hpp>
19#include <simulation/probe.hpp>
20#include <utility>
21
23{
24 constexpr bool enable_leave = true;
25 constexpr bool disable_leave = false;
26 constexpr bool disable_move = false;
27 constexpr bool enable_move = true;
28
29 // KOKKOS_INLINE_FUNCTION std::size_t
30 // __find_next_compartment(
31 // const MC::NeighborsView<ComputeSpace, true>& neighbors,
32 // const MC::CumulativeProbabilityView<ComputeSpace, true>&
33 // 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 // next = (random_number < pn && pi < random_number)
55 // ? neighbors(i_compartment, k_neighbor + 1)
56 // : next;
57 // }
58
59 // return next; // Return the index of the chosen next compartment
60 // }
61
67 KOKKOS_INLINE_FUNCTION std::size_t
69 const bool do_serch,
72 cumulative_probability,
73 const std::size_t i_compartment,
74 const double random_number)
75 {
76 const int mask_do_serch = static_cast<int>(do_serch);
77 const int max_neighbor = static_cast<int>(neighbors.extent(1));
78
79 KOKKOS_ASSERT(max_neighbor >= 1);
80 KOKKOS_ASSERT(random_number <= 1. && random_number >= 0.);
81 KOKKOS_ASSERT(neighbors.extent(1) == cumulative_probability.extent(1));
82
83 // Do not use cumulative_probability(i_compartment, max_neighbor - 1)==1
84 // Bcause proba can be 0.999999999
85 KOKKOS_ASSERT(cumulative_probability(i_compartment, max_neighbor - 1)
86 >= random_number);
87
88 int left = 0;
89 int right = mask_do_serch * (max_neighbor - 1);
90 while (left < right)
91 {
92 const int mid = (left + right) >> 1; // NOLINT
93 const auto pm = cumulative_probability(i_compartment, mid);
94 const int mask = static_cast<int>(random_number > pm);
95 left = mask * (mid + 1) + (1 - mask) * left;
96 right = mask * right + (1 - mask) * mid;
97 }
98
99 const auto ret = i_compartment * (1 - mask_do_serch)
100 + neighbors(i_compartment, left) * mask_do_serch;
101 return ret;
102 }
103
104 struct TagMove
105 {
106 };
107 struct TagLeave
108 {
109 };
110
112 {
113 MoveFunctor() = default;
115 MC::ParticleStatus _status,
117 MC::pool_type _random_pool,
118 MC::EventContainer _events,
120 MC::ParticleAges _ages,
121 MC::ParticleSamples _random)
122 : MoveFunctor(0,
123 std::move(p),
124 std::move(_status),
125 0,
126 std::move(m),
127 std::move(_random_pool),
128 std::move(_events),
129 std::move(_probes),
130 std::move(_ages),
131 std::move(_random),
132 false,
133 false) {};
134
135 MoveFunctor(double _d_t,
137 MC::ParticleStatus _status,
138 std::size_t n_p,
140 MC::pool_type _random_pool,
141 MC::EventContainer _events,
143 MC::ParticleAges _ages,
144 MC::ParticleSamples _random,
145 bool b_move,
146 bool b_leave)
147 : d_t(_d_t), positions(std::move(p)), n_particles(n_p),
148 move(std::move(m)), random_pool(_random_pool), // NOLINT
149 status(std::move(_status)), events(std::move(_events)),
150 probes(std::move(_probes)), ages(std::move(_ages)),
151 random(std::move(_random)), enable_move(b_move),
152 enable_leave(b_leave) {};
153
154 void
155 update(const ComputeSpace& ex,
156 double _d_t,
157 std::size_t n_p,
159 MC::ParticlePositions _positions,
160 MC::ParticleStatus _status,
161 MC::ParticleAges _ages,
162 MC::ParticleSamples _random,
163 bool b_move,
164 bool b_leave)
165 {
166
167 this->d_t = _d_t;
168 this->n_particles = n_p;
169 this->enable_leave = b_leave;
170 this->enable_move = b_move;
171 this->move = std::move(move_i);
172 this->random = std::move(_random);
173
174 if (enable_move)
175 {
177 }
178 else
179 {
181 }
182
183 this->positions = std::move(_positions);
184 this->status = std::move(_status);
185 this->ages = std::move(_ages);
186
187 Kokkos::fill_random(ex, random, random_pool, 0., 1.);
188 }
189
190 KOKKOS_INLINE_FUNCTION void
192 TagMove /*tag*/,
193 const Kokkos::TeamPolicy<ComputeSpace>::member_type& team_handle) const
194 {
195 GET_INDEX(n_particles);
196 if (status(idx) != MC::Status::Idle) [[unlikely]]
197 {
198 return;
199 }
200
201 handle_move(idx);
202 }
203
204 KOKKOS_INLINE_FUNCTION void
205 operator()(TagMove /*tag*/, const std::size_t& idx) const
206 {
207
208 if (status(idx) != MC::Status::Idle) [[unlikely]]
209 {
210 return;
211 }
212
213 handle_move(idx);
214 }
215
216 // KOKKOS_INLINE_FUNCTION void
217 // operator()(TagLeave _tag,
218 // const Kokkos::TeamPolicy<ComputeSpace>::member_type& team,
219 // std::size_t& local_dead_count) const
220 // {
221 // const auto work_stride = team.team_size() * team.league_size();
222 // const auto work_end = n_particles;
223
224 // std::size_t iwork =
225 // team.league_rank() * team.team_size() + team.team_rank();
226
227 // for (; iwork < work_end; iwork += work_stride)
228 // {
229 // ages(iwork, 0) += d_t;
230 // handle_exit(iwork, local_dead_count);
231 // }
232 // }
233 //
234 KOKKOS_INLINE_FUNCTION void
235 operator()([[maybe_unused]] TagLeave _tag,
236 const std::size_t& idx,
237 std::size_t& local_dead_count) const
238 {
239 if (status(idx) != MC::Status::Idle) [[unlikely]]
240 {
241 return;
242 }
243
244 ages(idx, 0) += d_t;
245 handle_exit(idx, move.liquid_volume, local_dead_count);
246 }
247
248 // KOKKOS_INLINE_FUNCTION void
249 // operator()(TagLeave _tag,
250 // const Kokkos::TeamPolicy<ComputeSpace>::member_type&
251 // team_handle, std::size_t& local_dead_count) const
252 // {
253 // (void)_tag;
254 // const std::size_t league_size = team_handle.league_size();
255 // const std::size_t league_rank = team_handle.league_rank();
256 // const std::size_t start_idx = league_rank * (n_particles /
257 // league_size); std::size_t end_idx = (league_rank + 1) * (n_particles /
258 // league_size);
259
260 // if (league_rank == (league_size - 1))
261 // {
262 // end_idx = n_particles;
263 // }
264 // Kokkos::parallel_for(
265 // Kokkos::TeamThreadRange(team_handle, start_idx, end_idx),
266 // [&](int idx)
267 // {
268 // ages(idx, 0) += d_t;
269 // handle_exit(idx, local_dead_count);
270 // });
271 // }
272
273 [[nodiscard]] bool
275 {
276 return enable_leave || enable_move;
277 }
278
279 KOKKOS_FUNCTION void
280 handle_move(const std::size_t idx) const
281 {
282
283 const auto rng1 = static_cast<float>(random(idx, 0));
284 const auto rng2 = static_cast<float>(random(idx, 1));
285
286 KOKKOS_ASSERT(rng1 >= 0. && rng1 <= 1 && rng2 >= 0. && rng2 <= 1);
287
288 const std::size_t i_current_compartment = positions(idx);
289
290 KOKKOS_ASSERT(
291 i_current_compartment < move.liquid_volume.extent(0)
292 && "Particle position is incorect (greater than compartment number)");
293
294 const bool mask_next = probability_leaving<fast_tag>(
295 rng1,
296 move.liquid_volume(i_current_compartment),
297 move.diag_transition(i_current_compartment),
298 d_t);
299
300 positions(idx) = __find_next_compartment(mask_next,
301 move.neighbors,
302 move.cumulative_probability,
303 i_current_compartment,
304 rng2);
305
306 // positions(idx)
307 // = (mask_next) ? __find_next_compartment(move.neighbors,
308 // move.cumulative_probability,
309 // i_current_compartment,
310 // rng2)
311 // : i_current_compartment;
312
313 KOKKOS_ASSERT(
314 positions(idx) < move.liquid_volume.extent(0)
315 && " Position after move is greater than compartment number");
316
317 if constexpr (AutoGenerated::FlagCompileTime::enable_event_counter)
318 {
319 if (mask_next)
320 {
321 events.wrap_incr<MC::EventType::Move>();
322 }
323 }
324 }
325
326 // KOKKOS_INLINE_FUNCTION void
327 // inner_handle_exit(const std::size_t i_flow,
328 // const std::size_t idx,
329 // const double liquid_volume,
330 // const std::size_t position,
331 // const MC::LeavingFlowView<true>& leaving_flow,
332 // std ::size_t& dead_count) const
333 // {
334 // // FIXME : when move AND exit, take the same random number,
335 // // is it really important ?
336 // const auto random_number = static_cast<float>(random(idx, 2));
337 // const auto& [index, flow] = leaving_flow(i_flow);
338
339 // const bool is_leaving = (position == index)
340 // && probability_leaving<void>(
341 // random_number, liquid_volume, flow, d_t);
342
343 // const int leave_mask = static_cast<int>(is_leaving);
344
345 // // If using probes
346 // if constexpr (AutoGenerated::FlagCompileTime::use_probe)
347 // {
348 // // Execute probe set, but only actually do something if leaving
349 // if (is_leaving)
350 // {
351 // const auto _ = probes.set(ages(idx, 0));
352 // }
353 // }
354 // if constexpr (AutoGenerated::FlagCompileTime::enable_event_counter)
355 // {
356
357 // events.add<MC::EventType::Exit>(leave_mask);
358 // }
359
360 // dead_count += leave_mask;
361 // ages(idx, 0) = (1 - leave_mask) * ages(idx, 0) /*leave_mask * 0 + */;
362 // status(idx) = is_leaving ? MC::Status::Exit : status(idx);
363 // }
364
365 // KOKKOS_FORCEINLINE_FUNCTION void
366 // handle_exit(std::size_t idx,
367 // const MC::VolumeView<ComputeSpace, true>& liquid_volumes,
368 // std::size_t& dead_count) const
369 // {
370 // const auto position = positions(idx);
371 // const auto liquid_volume = liquid_volumes(position);
372 // const MC::LeavingFlowView<true>& leaving_flow = move.leaving_flow;
373 // const std::size_t n_flow = leaving_flow.size();
374 // for (std::size_t i_flow = 0LU; i_flow < n_flow; ++i_flow)
375 // {
376 // inner_handle_exit(
377 // i_flow, idx, liquid_volume, position, leaving_flow, dead_count);
378 // }
379 // }
380
381 // KOKKOS_FORCEINLINE_FUNCTION void
382 // handle_exit(std::size_t idx,
383 // const MC::VolumeView<ComputeSpace, true>& liquid_volumes,
384 // std::size_t& dead_count) const
385 // {
386 // const std::size_t position = positions(idx);
387 // const double liquid_volume = liquid_volumes(position);
388 // const MC::LeavingFlowView<true>& leaving_flow = move.leaving_flow;
389 // const std::size_t n_flow = leaving_flow.size();
390
391 // // Strategy: most of the time there is only one flow (0d reactor or
392 // // uniquement leaving point)
393 // // Then the first flow is out of the loop
394 // // For the first leaving flow use precomputed index_random_leave
395 // // If the particle position is correct probability to leave is high
396 // // then pregenerated only one number and get random on the fly in the
397 // // loop if needed
398
399 // // One improvement is to use rng1 as long as as the we do consume it
400 // // If first ok_p is false, rng1 is then not used
401 // // This needs a branch ?
402
403 // auto rng1 = static_cast<float>(random(idx, index_random_leave));
404
405 // const auto& [index, flow] = leaving_flow(0);
406 // const bool p
407 // = probability_leaving<precision_tag>(rng1, liquid_volume, flow,
408 // d_t);
409 // const bool ok_p = position == index;
410 // const int m = static_cast<int>(ok_p) * static_cast<int>(p);
411 // int leave_mask = m;
412
413 // for (std::size_t i_flow = 1; i_flow < n_flow; ++i_flow)
414 // {
415 // if (leave_mask != 0)
416 // {
417 // break;
418 // }
419 // const auto& [index, flow] = leaving_flow(i_flow);
420 // const bool ok_p = position == index;
421 // if (!ok_p)
422 // {
423 // continue;
424 // }
425
426 // // if (!ok_p || leave_mask != 0)
427 // // {
428 // // continue;
429 // // }
430 // auto gen = random_pool.get_state();
431 // rng1 = gen.frand(0, 1);
432 // random_pool.free_state(gen);
433
434 // const bool p = probability_leaving<precision_tag>(
435 // rng1, liquid_volume, flow, d_t);
436
437 // const int m = static_cast<int>(ok_p) * static_cast<int>(p);
438 // leave_mask |= m;
439 // }
440
441 // dead_count += leave_mask;
442
443 // // DO this betore age set to 0
444 // if constexpr (AutoGenerated::FlagCompileTime::use_probe)
445 // {
446 // // Execute probe set, but only actually do something if leaving
447 // if (leave_mask != 0)
448 // {
449 // // const auto _ = probes.template set<(ages(idx, 0));
450 // }
451 // }
452
453 // ages(idx, 0) *= (1 - leave_mask);
454
455 // // status(idx) = (leave_mask == 0) ? status(idx) : MC::Status::Exit;
456
457 // status(idx) = static_cast<MC::Status>(
458 // static_cast<int>(status(idx)) * (1 - leave_mask)
459 // + static_cast<int>(MC::Status::Exit) * leave_mask);
460
461 // if constexpr (AutoGenerated::FlagCompileTime::enable_event_counter)
462 // {
463 // events.add<MC::EventType::Exit>(leave_mask);
464 // }
465 // }
466
467 KOKKOS_FORCEINLINE_FUNCTION void
468 handle_exit(std::size_t idx,
469 const MC::VolumeView<ComputeSpace, true>& liquid_volumes,
470 std::size_t& dead_count) const
471 {
472
473 using mem_space = ComputeSpace::memory_space;
474
475 const std::size_t position = positions(idx);
476 const double liquid_volume = liquid_volumes(position);
477 const MC::LeavingFlowView<true>& leaving_flow = move.leaving_flow;
478 const std::size_t n_flow = leaving_flow.size();
479 const auto rng1 = static_cast<float>(random(idx, index_random_leave));
480
481 // Strategy:
482 // first find the value of leaving flow (0-> particle doesn´t leave)
483 // do-while +early break is ok as n_flow is likely <10
484 // second: calculate probability leaving, flow=0 => p=0 theres no need to
485 // check condition
486 std::size_t i_flow = 0;
487 double val_flow = 0.;
488
489 // do-while because n_flow is likely to be 1
490 do
491 {
492 const auto& [index, flow] = leaving_flow(i_flow++);
493 if (position == index)
494 {
495 val_flow = flow;
496 break;
497 }
498 } while (i_flow < n_flow);
499
500 int leave_mask = 0;
501 // Cases
502 // 0D: one flow and position always 0 then (val_flow != 0.) is always true
503 // 3D: only for few particles
504 //
505 if (val_flow != 0.)
506 {
507
509 rng1, liquid_volume, val_flow, d_t);
510
511 leave_mask = static_cast<int>(p);
512 // DO this betore age is reset to 0
513 // if (p)
514 // {
515 dead_count += leave_mask;
516 // }
517 if constexpr (AutoGenerated::FlagCompileTime::use_probe)
518 {
519 if (leave_mask != 0)
520 {
521 const auto _ = probes.set<mem_space>(ages(idx, 0));
522 }
523 }
524 if constexpr (AutoGenerated::FlagCompileTime::enable_event_counter)
525 {
526 events.add<MC::EventType::Exit>(leave_mask);
527 }
528 ages(idx, 0) *= (1 - leave_mask);
529 status(idx) = static_cast<MC::Status>(
530 static_cast<int>(status(idx)) * (1 - leave_mask)
531 + static_cast<int>(MC::Status::Exit) * leave_mask);
532 }
533 }
534
535 double d_t{};
537 std::size_t n_particles{};
544 // Kokkos::View<float**, Kokkos::LayoutLeft> random;
545
547
550 std::size_t index_random_leave{};
551 };
552} // namespace Simulation::KernelInline
553
554#endif
std::conditional_t< is_const, Kokkos::View< const std::size_t **, Kokkos::LayoutRight, ExecSpace, Kokkos::MemoryTraits< Kokkos::RandomAccess > >, Kokkos::View< std::size_t **, Kokkos::LayoutRight, ExecSpace > > NeighborsView
Definition alias.hpp:132
Kokkos::View< float **, Kokkos::LayoutRight, ComputeSpace > ParticleSamples
Definition alias.hpp:81
Kokkos::View< Status *, ComputeSpace > ParticleStatus
Definition alias.hpp:74
Kokkos::View< uint64_t *, ComputeSpace > ParticlePositions
Definition alias.hpp:73
@ 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:58
@ Idle
Definition alias.hpp:59
@ Exit
Definition alias.hpp:61
ParticleAgesBase< ComputeSpace > ParticleAges
Definition alias.hpp:76
std::conditional_t< is_const, Kokkos::View< const double *, ExecSpace, Kokkos::MemoryTraits< Kokkos::RandomAccess > >, Kokkos::View< double *, ExecSpace > > VolumeView
Definition alias.hpp:100
gen_pool_type< Kokkos::DefaultExecutionSpace > pool_type
Definition alias.hpp:39
std::conditional_t< is_const, Kokkos::View< const LeavingFlow *, Kokkos::SharedHostPinnedSpace >, Kokkos::View< LeavingFlow *, Kokkos::SharedHostPinnedSpace > > LeavingFlowView
Definition alias.hpp:117
std::conditional_t< is_const, Kokkos::View< const double **, Kokkos::LayoutRight, ExecSpace, Kokkos::MemoryTraits< Kokkos::RandomAccess > >, Kokkos::View< double **, Kokkos::LayoutRight, ExecSpace > > CumulativeProbabilityView
Definition alias.hpp:123
Definition kernels.hpp:12
constexpr bool enable_leave
Definition move_kernel.hpp:24
constexpr bool enable_move
Definition move_kernel.hpp:27
KOKKOS_INLINE_FUNCTION std::size_t __find_next_compartment(const bool do_serch, const MC::NeighborsView< ComputeSpace, true > &neighbors, const MC::CumulativeProbabilityView< ComputeSpace, true > &cumulative_probability, const std::size_t i_compartment, const double random_number)
probably overkill binary search to find next compartment
Definition move_kernel.hpp:68
constexpr bool disable_leave
Definition move_kernel.hpp:25
KOKKOS_INLINE_FUNCTION bool probability_leaving(float random_number, double volume, double flow, double dt)
Definition probability_leaving.hpp:18
KOKKOS_INLINE_FUNCTION bool probability_leaving< fast_tag >(float random_number, double volume, double flow, double dt)
Definition probability_leaving.hpp:35
constexpr bool disable_move
Definition move_kernel.hpp:26
Probes< AutoGenerated::probe_buffer_size > ProbeAutogeneratedBuffer
Definition probe.hpp:148
Structure to store information about domain needed during MC cycle data is likely to change between e...
Definition domain.hpp:27
Use to count events that occurs during Monte-Carlo processing cycles.
Definition events.hpp:45
KOKKOS_INLINE_FUNCTION void operator()(TagMove, const std::size_t &idx) const
Definition move_kernel.hpp:205
bool enable_leave
Definition move_kernel.hpp:549
KOKKOS_INLINE_FUNCTION void operator()(TagLeave _tag, const std::size_t &idx, std::size_t &local_dead_count) const
Definition move_kernel.hpp:235
KOKKOS_FUNCTION void handle_move(const std::size_t idx) const
Definition move_kernel.hpp:280
KOKKOS_INLINE_FUNCTION void operator()(TagMove, const Kokkos::TeamPolicy< ComputeSpace >::member_type &team_handle) const
Definition move_kernel.hpp:191
KOKKOS_FORCEINLINE_FUNCTION void handle_exit(std::size_t idx, const MC::VolumeView< ComputeSpace, true > &liquid_volumes, std::size_t &dead_count) const
Definition move_kernel.hpp:468
MC::ParticleSamples random
Definition move_kernel.hpp:546
MoveFunctor(MC::ParticlePositions p, MC::ParticleStatus _status, MC::DomainState< ComputeSpace > m, MC::pool_type _random_pool, MC::EventContainer _events, ProbeAutogeneratedBuffer _probes, MC::ParticleAges _ages, MC::ParticleSamples _random)
Definition move_kernel.hpp:114
bool need_launch() const
Definition move_kernel.hpp:274
MC::ParticlePositions positions
Definition move_kernel.hpp:536
double d_t
Definition move_kernel.hpp:535
MC::DomainState< ComputeSpace, true > move
Definition move_kernel.hpp:538
void update(const ComputeSpace &ex, double _d_t, std::size_t n_p, MC::DomainState< 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:155
std::size_t index_random_leave
Definition move_kernel.hpp:550
std::size_t n_particles
Definition move_kernel.hpp:537
MC::EventContainer events
Definition move_kernel.hpp:541
ProbeAutogeneratedBuffer probes
Definition move_kernel.hpp:542
MC::ParticleStatus status
Definition move_kernel.hpp:540
bool enable_move
Definition move_kernel.hpp:548
MC::ParticleAges ages
Definition move_kernel.hpp:543
MC::pool_type random_pool
Definition move_kernel.hpp:539
MoveFunctor(double _d_t, MC::ParticlePositions p, MC::ParticleStatus _status, std::size_t n_p, MC::DomainState< 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:135
Definition move_kernel.hpp:108
Definition move_kernel.hpp:105