SPHinXsys  alpha version
particle_sorting.h
Go to the documentation of this file.
1 /* -------------------------------------------------------------------------*
2  * SPHinXsys *
3  * --------------------------------------------------------------------------*
4  * SPHinXsys (pronunciation: s'finksis) is an acronym from Smoothed Particle *
5  * Hydrodynamics for industrial compleX systems. It provides C++ APIs for *
6  * physical accurate simulation and aims to model coupled industrial dynamic *
7  * systems including fluid, solid, multi-body dynamics and beyond with SPH *
8  * (smoothed particle hydrodynamics), a meshless computational method using *
9  * particle discretization. *
10  * *
11  * SPHinXsys is partially funded by German Research Foundation *
12  * (Deutsche Forschungsgemeinschaft) DFG HU1527/6-1, HU1527/10-1 *
13  * and HU1527/12-1. *
14  * *
15  * Portions copyright (c) 2017-2020 Technical University of Munich and *
16  * the authors' affiliations. *
17  * *
18  * Licensed under the Apache License, Version 2.0 (the "License"); you may *
19  * not use this file except in compliance with the License. You may obtain a *
20  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
21  * *
22  * --------------------------------------------------------------------------*/
23 
30 #ifndef PARTICLE_SORTING_H
31 #define PARTICLE_SORTING_H
32 
33 #include "base_data_package.h"
34 #include "sph_data_containers.h"
35 #include "base_particles.h"
36 
38 namespace tbb
39 {
40  namespace interafce9
41  {
42  namespace internal
43  {
44 
45 #ifdef TBB_2021_2_0
46  using tbb::detail::no_assign;
47 #else
48  using tbb::internal::no_assign;
49 #endif
50 
52  template <typename RandomAccessIterator, typename Compare, typename SwapType>
53  class QuickSortParticleRange : private no_assign
54  {
55 
56  inline size_t median_of_three(const RandomAccessIterator &array, size_t l, size_t m, size_t r) const
57  {
58  return comp_(array[l], array[m]) ? (comp_(array[m], array[r]) ? m : (comp_(array[l], array[r]) ? r : l))
59  : (comp_(array[r], array[m]) ? m : (comp_(array[r], array[l]) ? r : l));
60  }
61 
62  inline size_t PseudoMedianOfNine(const RandomAccessIterator &array, const QuickSortParticleRange &range) const
63  {
64  size_t offset = range.size_ / 8u;
65  return median_of_three(array,
66  median_of_three(array, 0, offset, offset * 2),
67  median_of_three(array, offset * 3, offset * 4, offset * 5),
68  median_of_three(array, offset * 6, offset * 7, range.size_ - 1));
69  }
70 
71  size_t splitRange(QuickSortParticleRange &range)
72  {
73  RandomAccessIterator array = range.begin_;
74  RandomAccessIterator key0 = range.begin_;
75  size_t m = PseudoMedianOfNine(array, range);
76  if (m)
77  swap_sortable_particle_data_(array, array + m);
78 
79  size_t i = 0;
80  size_t j = range.size_;
81  // Partition interval [i+1,j-1] with key *key0.
82  for (;;)
83  {
84  __TBB_ASSERT(i < j, nullptr);
85  // Loop must terminate since array[l]==*key0.
86  do
87  {
88  --j;
89  __TBB_ASSERT(i <= j, "bad ordering relation?");
90  } while (comp_(*key0, array[j]));
91  do
92  {
93  __TBB_ASSERT(i <= j, nullptr);
94  if (i == j)
95  goto quick_sort_particle_partition;
96  ++i;
97  } while (comp_(array[i], *key0));
98  if (i == j)
99  goto quick_sort_particle_partition;
100  swap_sortable_particle_data_(array + i, array + j);
101  }
102  quick_sort_particle_partition:
103  // Put the partition key were it belongs
104  swap_sortable_particle_data_(array + j, key0);
105  // array[l..j) is less or equal to key.
106  // array(j..r) is greater or equal to key.
107  // array[j] is equal to key
108  i = j + 1;
109  size_t new_range_size = range.size_ - i;
110  range.size_ = j;
111  return new_range_size;
112  }
113 
114  public:
115  static const size_t grainsize_ = 500;
116  const Compare &comp_;
117  SwapType &swap_sortable_particle_data_;
118  size_t size_;
119  RandomAccessIterator begin_;
120 
121  QuickSortParticleRange(RandomAccessIterator begin,
122  size_t size, const Compare &compare, SwapType &swap_particle_data)
123  : comp_(compare), swap_sortable_particle_data_(swap_particle_data),
124  size_(size), begin_(begin) {}
125 
126  bool empty() const { return size_ == 0; }
127  bool is_divisible() const { return size_ >= grainsize_; }
128 
130  : comp_(range.comp_), swap_sortable_particle_data_(range.swap_sortable_particle_data_), size_(splitRange(range))
131  // +1 accounts for the pivot element, which is at its correct place
132  // already and, therefore, is not included into subranges.
133  ,
134  begin_(range.begin_ + range.size_ + 1)
135  {
136  }
137  };
138 
139  /*
140  Description : QuickSort in Iterator format
141  Link : https://stackoverflow.com/a/54976413/3547485
142  Ref : http://www.cs.fsu.edu/~lacher/courses/COP4531/lectures/sorts/slide09.html
143  */
144  template <typename RandomAccessIterator, typename Compare, typename SwapType>
145  RandomAccessIterator Partition(RandomAccessIterator first, RandomAccessIterator last, Compare &compare, SwapType &swap_particle_data)
146  {
147  auto pivot = std::prev(last, 1);
148  auto i = first;
149  for (auto j = first; j != pivot; ++j)
150  {
151  // bool format
152  if (compare(*j, *pivot))
153  {
154  swap_particle_data(i++, j);
155  }
156  }
157  swap_particle_data(i, pivot);
158  return i;
159  }
160 
161  template <typename RandomAccessIterator, typename Compare, typename SwapType>
162  void SerialQuickSort(RandomAccessIterator first, RandomAccessIterator last, Compare &compare, SwapType &swap_particle_data)
163  {
164  if (std::distance(first, last) > 1)
165  {
166  RandomAccessIterator bound = Partition(first, last, compare, swap_particle_data);
167  SerialQuickSort(first, bound, compare, swap_particle_data);
168  SerialQuickSort(bound + 1, last, compare, swap_particle_data);
169  }
170  }
171 
172  /*
173  Description : Insertsort in Iterator format
174  Link : http://www.codecodex.com/wiki/Insertion_sort
175  */
176 
177  template <typename RandomAccessIterator, typename Compare, typename SwapType>
178  void InsertionSort(RandomAccessIterator First, RandomAccessIterator Last, Compare &compare, SwapType &swap_particle_data)
179  {
180  RandomAccessIterator min = First;
181  for (RandomAccessIterator i = First + 1; i < Last; ++i)
182  if (compare(*i, *min))
183  min = i;
184 
185  swap_particle_data(First, min);
186  while (++First < Last)
187  for (RandomAccessIterator j = First; compare(*j, *(j - 1)); --j)
188  swap_particle_data((j - 1), j);
189  }
190 
192  template <typename RandomAccessIterator, typename Compare, typename SwapType>
194  {
195  void operator()(const QuickSortParticleRange<RandomAccessIterator, Compare, SwapType> &range) const
196  {
197  SerialQuickSort(range.begin_, range.begin_ + range.size_, range.comp_, range.swap_sortable_particle_data_);
198  }
199  };
200 
201  }
202  }
203 }
204 
205 namespace SPH
206 {
207 
208  class RealBody;
209  class BaseCellLinkedList;
210 
211  template <typename VariableType>
213  {
214  void operator()(ParticleData &particle_data, size_t index_a, size_t index_b) const
215  {
216  constexpr int type_index = DataTypeIndex<VariableType>::value;
217 
218  StdVec<StdLargeVec<VariableType> *> variables = std::get<type_index>(particle_data);
219  for (size_t i = 0; i != variables.size(); ++i)
220  {
221  StdLargeVec<VariableType> &variable = *variables[i];
222  std::swap(variable[index_a], variable[index_b]);
223  }
224  };
225  };
226 
232  {
233  bool operator()(const size_t &x, const size_t &y) const
234  {
235  return x < y;
236  };
237  };
238 
244  {
245  protected:
246  StdLargeVec<size_t> &sequence_;
247  StdLargeVec<size_t> &unsorted_id_;
248  ParticleData &sortable_data_;
249  DataAssembleOperation<swapParticleDataValue> swap_particle_data_value_;
250 
251  public:
252  explicit SwapSortableParticleData(BaseParticles *base_particles);
254 
258  void operator()(size_t *a, size_t *b);
259  };
260 
266  {
267  private:
268  UniquePtrKeeper<SwapSortableParticleData> swap_particle_ptr_keeper_;
271  quick_sort_particle_range_ptr_keeper_;
272 
273  protected:
274  BaseParticles *base_particles_;
275 
278  CompareParticleSequence compare_;
280  size_t *, CompareParticleSequence, SwapSortableParticleData> *quick_sort_particle_range_;
283  quick_sort_particle_body_;
284 
285  public:
286  // the construction is before particles
287  explicit ParticleSorting(RealBody *real_body);
288  virtual ~ParticleSorting(){};
289 
290  void assignBaseParticles(BaseParticles *base_particles);
292  virtual void sortingParticleData(size_t *begin, size_t size);
294  virtual void updateSortedId();
295  };
296 }
297 #endif // PARTICLE_SORTING_H
Particles with essential (geometric and kinematic) data. There are three types of particles, all par...
Definition: base_particles.h:81
swap sortable particle data according to a sequence
Definition: particle_sorting.h:243
virtual void sortingParticleData(size_t *begin, size_t size)
Definition: particle_sorting.cpp:34
virtual void updateSortedId()
Definition: particle_sorting.cpp:42
GeneralDataAssemble< StdLargeVec > ParticleData
Definition: sph_data_containers.h:59
Definition: base_data_package.h:46
void operator()(size_t *a, size_t *b)
Definition: particle_sorting.cpp:20
Definition: particle_sorting.h:53
A wrapper to provide an ownership for a new derived object which previous often generated by new a ra...
Definition: ownership.h:90
The class for sorting particle according a given sequence.
Definition: particle_sorting.h:265
Definition: particle_sorting.h:193
SwapSortableParticleData * swap_sortable_particle_data_
Definition: particle_sorting.h:277
This is the base class of SPH particles. The basic data of the particles is saved in separated large ...
Set up of basic data structure.
Definition: particle_sorting.h:38
Definition: base_data_type.h:320
compare the sequence of two particles
Definition: particle_sorting.h:231
Derived body with inner particle configuration or inner interactions. After construction, the particle and material must be specified.
Definition: base_body.h:182
Definition: particle_sorting.h:212
Definition: solid_body_supplementary.cpp:9