30
30
#include " ParticleDecomposition.hpp"
31
31
#include " ParticleList.hpp"
32
32
#include " ParticleRange.hpp"
33
+ #include " algorithm/link_cell.hpp"
33
34
#include " bond_error.hpp"
34
35
#include " ghosts.hpp"
35
36
36
37
#include < boost/algorithm/cxx11/any_of.hpp>
37
38
#include < boost/container/static_vector.hpp>
39
+ #include < boost/iterator/indirect_iterator.hpp>
38
40
#include < boost/range/algorithm/find_if.hpp>
39
41
#include < boost/range/algorithm/transform.hpp>
40
42
@@ -80,6 +82,32 @@ inline ParticleRange particles(Utils::Span<Cell *> cells) {
80
82
}
81
83
} // namespace Cells
82
84
85
+ /* *
86
+ * @brief Distance vector and length handed to pair kernels.
87
+ */
88
+ struct Distance {
89
+ explicit Distance (Utils::Vector3d const &vec21)
90
+ : vec21(vec21), dist2(vec21.norm2()) {}
91
+
92
+ Utils::Vector3d vec21;
93
+ double dist2;
94
+ };
95
+ namespace detail {
96
+ struct MinimalImageDistance {
97
+ const BoxGeometry box;
98
+
99
+ Distance operator ()(Particle const &p1, Particle const &p2) const {
100
+ return Distance (get_mi_vector (p1.r .p , p2.r .p , box));
101
+ }
102
+ };
103
+
104
+ struct EuclidianDistance {
105
+ Distance operator ()(Particle const &p1, Particle const &p2) const {
106
+ return Distance (p1.r .p - p2.r .p );
107
+ }
108
+ };
109
+ } // namespace detail
110
+
83
111
/* * Describes a cell structure / cell system. Contains information
84
112
* about the communication of cell contents (particles, ghosts, ...)
85
113
* between different nodes and the relation between particle
@@ -103,6 +131,9 @@ struct CellStructure {
103
131
public:
104
132
bool use_verlet_list = true ;
105
133
134
+ bool m_rebuild_verlet_list = true ;
135
+ std::vector<std::pair<Particle *, Particle *>> m_verlet_list;
136
+
106
137
/* *
107
138
* @brief Update local particle index.
108
139
*
@@ -212,11 +243,14 @@ struct CellStructure {
212
243
/* * Maximal pair range supported by current cell system. */
213
244
Utils::Vector3d max_range () const ;
214
245
215
- /* * Return the global local_cells */
246
+ private:
216
247
Utils::Span<Cell *> local_cells ();
248
+
249
+ public:
217
250
ParticleRange local_particles ();
218
251
ParticleRange ghost_particles ();
219
252
253
+ private:
220
254
/* * Cell system dependent function to find the right cell for a
221
255
* particle.
222
256
* \param p Particle.
@@ -225,6 +259,7 @@ struct CellStructure {
225
259
*/
226
260
Cell *particle_to_cell (const Particle &p);
227
261
262
+ public:
228
263
/* *
229
264
* @brief Add a particle.
230
265
*
@@ -293,7 +328,6 @@ struct CellStructure {
293
328
return assert (m_decomposition), *m_decomposition;
294
329
}
295
330
296
- private:
297
331
ParticleDecomposition &decomposition () {
298
332
return assert (m_decomposition), *m_decomposition;
299
333
}
@@ -327,6 +361,7 @@ struct CellStructure {
327
361
* Cells::DataPart
328
362
*/
329
363
void ghosts_update (unsigned data_parts);
364
+
330
365
/* *
331
366
* @brief Add forces from ghost particles to real particles.
332
367
*/
@@ -355,7 +390,6 @@ struct CellStructure {
355
390
return partners;
356
391
}
357
392
358
- public:
359
393
/* *
360
394
* @brief Execute kernel for every bond on particle.
361
395
* @tparam Handler Callable, which can be invoked with
@@ -387,9 +421,10 @@ struct CellStructure {
387
421
}
388
422
}
389
423
390
- private:
391
- /* * Go through ghost cells and remove the ghost entries from the
392
- local particle index. */
424
+ /* *
425
+ * @brief Go through ghost cells and remove the ghost entries from the
426
+ * local particle index.
427
+ */
393
428
void invalidate_ghosts () {
394
429
for (auto const &p : ghost_particles ()) {
395
430
if (get_local_particle (p.identity ()) == &p) {
@@ -443,11 +478,130 @@ struct CellStructure {
443
478
double range, BoxGeometry const &box,
444
479
LocalBox<double > const &local_geo);
445
480
481
+ public:
482
+ template <class BondKernel > void bond_loop (BondKernel const &bond_kernel) {
483
+ for (auto &p : local_particles ()) {
484
+ execute_bond_handler (p, bond_kernel);
485
+ }
486
+ }
487
+
488
+ private:
446
489
/* *
447
- * @brief Return true if minimum image convention is
448
- * needed for distance calculation. */
449
- bool minimum_image_distance () const {
450
- return m_decomposition->minimum_image_distance ();
490
+ * @brief Run link_cell algorithm for local cells.
491
+ *
492
+ * @tparam Kernel Needs to be callable with (Particle, Particle, Distance).
493
+ * @param kernel Pair kernel functor.
494
+ */
495
+ template <class Kernel > void link_cell (Kernel kernel) {
496
+ auto const maybe_box = decomposition ().minimum_image_distance ();
497
+ auto const first = boost::make_indirect_iterator (local_cells ().begin ());
498
+ auto const last = boost::make_indirect_iterator (local_cells ().end ());
499
+
500
+ if (maybe_box) {
501
+ Algorithm::link_cell (
502
+ first, last,
503
+ [&kernel, df = detail::MinimalImageDistance{*maybe_box}](
504
+ Particle &p1, Particle &p2) { kernel (p1, p2, df (p1, p2)); });
505
+ } else {
506
+ Algorithm::link_cell (
507
+ first, last,
508
+ [&kernel, df = detail::EuclidianDistance{}](
509
+ Particle &p1, Particle &p2) { kernel (p1, p2, df (p1, p2)); });
510
+ }
511
+ }
512
+
513
+ public:
514
+ /* * Non-bonded pair loop with potential use
515
+ * of verlet lists.
516
+ * @param pair_kernel Kernel to apply
517
+ */
518
+ template <class PairKernel > void non_bonded_loop (PairKernel pair_kernel) {
519
+ link_cell (pair_kernel);
520
+ }
521
+
522
+ /* * Non-bonded pair loop with potential use
523
+ * of verlet lists.
524
+ * @param pair_kernel Kernel to apply
525
+ * @param verlet_criterion Filter for verlet lists.
526
+ */
527
+ template <class PairKernel , class VerletCriterion >
528
+ void non_bonded_loop (PairKernel &&pair_kernel,
529
+ const VerletCriterion &verlet_criterion) {
530
+ /* In this case the verlet list update is attached to
531
+ * the pair kernel, and the verlet list is rebuilt as
532
+ * we go. */
533
+ if (use_verlet_list && m_rebuild_verlet_list) {
534
+ m_verlet_list.clear ();
535
+
536
+ link_cell ([&pair_kernel, &verlet_criterion,
537
+ this ](Particle &p1, Particle &p2, Distance const &d) {
538
+ if (verlet_criterion (p1, p2, d)) {
539
+ m_verlet_list.emplace_back (&p1, &p2);
540
+ pair_kernel (p1, p2, d);
541
+ }
542
+ });
543
+
544
+ m_rebuild_verlet_list = false ;
545
+ } else if (use_verlet_list && not m_rebuild_verlet_list) {
546
+ auto const maybe_box = decomposition ().minimum_image_distance ();
547
+ /* In this case the pair kernel is just run over the verlet list. */
548
+ if (maybe_box) {
549
+ auto const distance_function = detail::MinimalImageDistance{*maybe_box};
550
+ for (auto &pair : m_verlet_list) {
551
+ pair_kernel (*pair.first , *pair.second ,
552
+ distance_function (*pair.first , *pair.second ));
553
+ }
554
+ } else {
555
+ auto const distance_function = detail::EuclidianDistance{};
556
+ for (auto &pair : m_verlet_list) {
557
+ pair_kernel (*pair.first , *pair.second ,
558
+ distance_function (*pair.first , *pair.second ));
559
+ }
560
+ }
561
+ } else {
562
+ /* No verlet lists, just run the kernel with pairs from the cells. */
563
+ link_cell (pair_kernel);
564
+ }
565
+ }
566
+
567
+ private:
568
+ /* *
569
+ * @brief Check that particle index is commensurate with particles.
570
+ *
571
+ * For each local particles is checked that has a correct entry
572
+ * in the particles index, and that there are no excess (non-existing)
573
+ * particles in the index.
574
+ */
575
+ void check_particle_index ();
576
+
577
+ /* *
578
+ * @brief Check that particles are in the correct cell.
579
+ *
580
+ * This checks for all local particles that the result
581
+ * of particles_to_cell is the cell the particles is
582
+ * actually in, e.g. that the particles are sorted according
583
+ * to particles_to_cell.
584
+ */
585
+ void check_particle_sorting ();
586
+
587
+ public:
588
+ /* *
589
+ * @brief Find cell a particle is stored in.
590
+ *
591
+ * For local particles, this returns the cell they
592
+ * are stored in, otherwise nullptr is returned.
593
+ *
594
+ * @param p Particle to find cell for
595
+ * @return Cell for particle or nullptr.
596
+ */
597
+ Cell *find_current_cell (const Particle &p) {
598
+ assert (not get_resort_particles ());
599
+
600
+ if (p.l .ghost ) {
601
+ return nullptr ;
602
+ }
603
+
604
+ return particle_to_cell (p);
451
605
}
452
606
};
453
607
0 commit comments