faunus
group.h
1 #pragma once
2 #include "core.h"
3 #include "particle.h"
4 #include "molecule.h"
5 #include "units.h"
6 
7 namespace Faunus {
8 
9 template <typename T> void inline swap_to_back(T first, T last, T end)
10 {
11  while (end-- > last) {
12  std::iter_swap(first++, end);
13  }
14 }
15 
16 template <class T> struct IterRange : std::pair<T, T>
17 {
18  using std::pair<T, T>::pair;
19 
20  T& begin() { return this->first; }
21 
22  T& end() { return this->second; }
23 
24  [[nodiscard]] const T& begin() const { return this->first; }
25 
26  [[nodiscard]] const T& end() const { return this->second; }
27 
28  [[nodiscard]] size_t size() const { return std::distance(this->first, this->second); }
29 
30  void resize(size_t n)
31  {
32  end() += n - size();
33  assert(size() == n);
34  }
35 
36  [[nodiscard]] bool empty() const { return this->first == this->second; }
37 
38  void clear()
39  {
40  this->second = this->first;
41  assert(empty());
42  }
43 
44  [[nodiscard]] std::pair<int, int> to_index(T reference) const
45  {
46  return {std::distance(reference, begin()), std::distance(reference, end() - 1)};
47  }
48 };
49 
60 template <class T> class ElasticRange : public IterRange<typename std::vector<T>::iterator>
61 {
62  public:
63  using Titer = typename std::vector<T>::iterator;
64  using const_iterator = typename std::vector<T>::const_iterator;
65 
66  private:
67  Titer _trueend;
68 
69  public:
71  using base::begin;
72  using base::end;
73  using base::size;
74 
75  ElasticRange(Titer begin, Titer end);
76  virtual ~ElasticRange() = default;
77  [[nodiscard]] size_t capacity() const;
78  [[nodiscard]] auto inactive() const;
79  void
80  deactivate(Titer first,
81  Titer last);
82  void activate(Titer first, Titer last);
83  Titer& trueend();
84  [[nodiscard]] const Titer& trueend() const;
85  void relocate(const_iterator oldorigin,
86  Titer neworigin);
87  [[nodiscard]] [[nodiscard]] virtual bool isFull() const;
89  [[maybe_unused]] [[nodiscard]] auto numInactive() const;
90 
93 
94  [[maybe_unused]] [[nodiscard]] inline bool
95  resizeIsPossible(int number_to_insert_or_delete) const
96  {
97  auto new_size = static_cast<int>(size()) + number_to_insert_or_delete;
98  return (new_size >= 0 && new_size <= capacity());
99  }
100 
101  inline auto all()
102  {
103  return std::ranges::subrange(begin(), trueend());
104  }
105 
106  [[nodiscard]] inline auto all() const
107  {
108  return std::ranges::subrange(begin(), trueend());
109  }
110 };
111 
112 template <class T> bool ElasticRange<T>::isFull() const
113 {
114  return end() == trueend();
115 }
116 
117 template <class T>
118 ElasticRange<T>::ElasticRange(ElasticRange::Titer begin, ElasticRange::Titer end)
119  : base({begin, end})
120  , _trueend(end)
121 {
122 }
123 
124 template <class T> size_t ElasticRange<T>::capacity() const
125 {
126  return std::distance(begin(), _trueend);
127 }
128 
129 template <class T> auto ElasticRange<T>::inactive() const
130 {
131  return base({end(), _trueend});
132 }
133 
134 template <class T>
135 void ElasticRange<T>::deactivate(ElasticRange::Titer first, ElasticRange::Titer last)
136 {
137  size_t n = std::distance(first, last);
138  assert(first >= begin() && last <= end());
139  std::rotate(begin(), last, end());
140  end() -= n;
141  assert(size() + inactive().size() == capacity());
142 }
143 
144 template <class T>
145 void ElasticRange<T>::activate(ElasticRange::Titer first, ElasticRange::Titer last)
146 {
147  size_t n = std::distance(first, last);
148  std::rotate(end(), first, _trueend);
149  end() += n;
150  assert(size() + inactive().size() == capacity());
151 }
152 
153 template <class T> typename ElasticRange<T>::Titer& ElasticRange<T>::trueend()
154 {
155  return _trueend;
156 }
157 
158 template <class T> const typename ElasticRange<T>::Titer& ElasticRange<T>::trueend() const
159 {
160  return _trueend;
161 }
162 
163 template <class T>
164 void ElasticRange<T>::relocate(ElasticRange::const_iterator oldorigin,
165  ElasticRange::Titer neworigin)
166 {
167  begin() = neworigin + std::distance(oldorigin, const_iterator(begin()));
168  end() = neworigin + std::distance(oldorigin, const_iterator(end()));
169  trueend() = neworigin + std::distance(oldorigin, const_iterator(trueend()));
170 }
171 
172 template <class T> [[maybe_unused]] auto ElasticRange<T>::numInactive() const
173 {
174  return inactive().size();
175 }
176 
177 class Group : public ElasticRange<Particle>
178 {
179  public:
180  ~Group() override = default;
182  using iter = typename base::Titer;
183  int id = -1;
184  int conformation_id = 0;
185  Point mass_center = {0.0, 0.0, 0.0};
186 
187  [[nodiscard]] inline bool isAtomic() const
188  {
189  return traits().atomic;
190  }
191 
192  [[nodiscard]] inline bool isMolecular() const
193  {
194  return !traits().atomic;
195  }
196 
197  [[nodiscard]] bool isFull() const override;
198 
199  std::optional<std::reference_wrapper<Point>>
200  massCenter();
201  [[nodiscard]] std::optional<std::reference_wrapper<const Point>>
202  massCenter() const;
203 
205  enum Selectors : unsigned int
206  {
207  ANY = (1U << 1U),
208  ACTIVE = (1U << 2U),
209  INACTIVE = (1U << 3U),
210  NEUTRAL = (1U << 4U),
211  ATOMIC = (1U << 5U),
212  MOLECULAR = (1U << 6U),
213  FULL = (1U << 7U)
214  };
215 
224 #pragma clang diagnostic push
225 #pragma clang diagnostic ignored "-Wc++11-narrowing"
226 
227  template <unsigned int mask> [[nodiscard]] bool match() const
228  {
229  static_assert(mask >= ANY && mask <= FULL);
230  if constexpr (mask & ANY) {
231  static_assert(mask == ANY, "don't mix ANY with other flags");
232  return true;
233  }
234  if constexpr (mask & ACTIVE) {
235  static_assert(!(mask & INACTIVE), "don't mix ACTIVE and INACTIVE");
236  if (empty()) {
237  return false;
238  }
239  }
240  else if constexpr (mask & INACTIVE) {
241  if (!empty()) {
242  return false;
243  }
244  }
245  if constexpr (mask & FULL) {
246  if (end() != trueend()) {
247  return false;
248  }
249  }
250  if constexpr (mask & ATOMIC) {
251  static_assert(!(mask & MOLECULAR), "don't mix ATOMIC and MOLECULAR");
252  if (isMolecular()) {
253  return false;
254  }
255  }
256  else if constexpr (mask & MOLECULAR) {
257  if (isAtomic()) {
258  return false;
259  }
260  }
261  if constexpr (mask & NEUTRAL) {
262  auto _end = (mask & INACTIVE) ? trueend() : end();
263  auto _charge = std::accumulate(begin(), _end, 0.0, [](auto sum, const auto& particle) {
264  return sum + particle.charge;
265  });
266  if (std::fabs(_charge) > pc::epsilon_dbl) {
267  return false;
268  }
269  }
270  return true;
271  }
272 
273 #pragma clang diagnostic pop
274 
275  [[nodiscard]] inline const MoleculeData& traits() const
276  {
277  assert(id >= 0 && id < Faunus::molecules.size());
278  return Faunus::molecules[id];
279  }
280 
281  Group(Group& other);
282  Group(const Group& other);
283  Group(MoleculeData::index_type molid, iter begin, iter end);
284  Group& operator=(const Group& other);
285  Group& shallowCopy(const Group& other);
286  [[nodiscard]] bool contains(const Particle& particle,
287  bool include_inactive = false) const;
288  [[nodiscard]] double mass() const;
289 
290  auto positions()
291  {
292  return std::ranges::subrange(begin(), end()) |
293  std::views::transform([&](Particle& particle) -> Point& { return particle.pos; });
294  }
295 
296  [[nodiscard]] auto positions() const
297  {
298  return std::ranges::subrange(begin(), end()) |
299  std::views::transform(
300  [&](const Particle& particle) -> const Point& { return particle.pos; });
301  }
302 
303  [[nodiscard]] AtomData::index_type getParticleIndex(const Particle& particle,
304  bool include_inactive = false)
305  const;
306 
307  [[nodiscard]] auto findAtomID(AtomData::index_type atomid) const
308  {
309  return *this |
310  std::views::filter([atomid](auto& particle) { return (particle.id == atomid); });
311  }
312 
319  inline auto& operator[](size_t index) { return *(begin() + index); }
320 
321  inline const auto& operator[](size_t index) const { return *(begin() + index); }
322 
323  Particle& at(size_t index);
324  [[nodiscard]] const Particle& at(size_t index) const;
325 
331  template <std::integral Tint = size_t> auto operator[](std::vector<Tint>& indices)
332  {
333 #ifndef NDEBUG
334  if (not indices.empty()) {
335  assert(*std::max_element(indices.begin(), indices.end()) < size());
336  }
337 #endif
338  return indices |
339  std::views::transform([this](auto i) -> Particle& { return *(begin() + i); });
340  }
341 
349  template <typename TdistanceFunc> void unwrap(const TdistanceFunc& vector_distance)
350  {
351  if (isMolecular()) {
352  for (auto& particle : *this) {
353  particle.pos = mass_center + vector_distance(particle.pos, mass_center);
354  }
355  }
356  }
357 
358  [[maybe_unused]] void
359  wrap(Geometry::BoundaryFunction boundary);
360 
361  void translate(
362  const Point& displacement, Geometry::BoundaryFunction boundary = [](Point&) {
363  });
364 
365  void rotate(const Eigen::Quaterniond& quaternion,
367  boundary);
368 
369  void updateMassCenter(Geometry::BoundaryFunction boundary,
370  const Point& approximate_mass_center);
371 
372  void updateMassCenter(Geometry::BoundaryFunction boundary);
373 
374 };
375 
376 void to_json(json& j, const Group& group);
377 void from_json(const json& j, Group& group);
378 
380 template <unsigned int mask> std::function<bool(const Group&)> getGroupFilter()
381 {
382  return [](const Group& group) { return group.match<mask>(); };
383 }
384 
386 template <typename T>
387 concept RequireGroups =
388  std::ranges::range<T> && std::is_convertible_v<std::ranges::range_value_t<T>, Group>;
389 
390 } // namespace Faunus
auto inactive() const
Range of inactive elements.
Definition: group.h:129
nlohmann::json json
JSON object.
Definition: json_support.h:10
Eigen::Vector3d Point
3D vector used for positions, velocities, forces etc.
Definition: coordinates.h:7
Point pos
Particle position vector.
Definition: particle.h:227
void relocate(const_iterator oldorigin, Titer neworigin)
Shift all iterators to new underlying container; useful when resizing vectors.
Definition: group.h:164
double T
floating point size
Definition: units.h:73
auto operator[](std::vector< Tint > &indices)
Reference to subset of given indices, where 0 is the start of the group.
Definition: group.h:331
auto findAtomID(AtomData::index_type atomid) const
Range of all (active) elements with matching particle id.
Definition: group.h:307
auto all() const
Active and inactive elements.
Definition: group.h:106
void unwrap(const TdistanceFunc &vector_distance)
Remove PBC for molecular groups w.
Definition: group.h:349
auto & operator[](size_t index)
Returns i&#39;th element in group.
Definition: group.h:319
void activate(Titer first, Titer last)
Activate previously deactivated elements.
Definition: group.h:145
Turns a pair of iterators into an elastic range.
Definition: group.h:60
void deactivate(Titer first, Titer last)
Deactivate particles by moving to end, reducing the effective size.
Definition: group.h:135
void swap_to_back(T first, T last, T end)
Move range [first:last] to [end] by swapping elements.
Definition: group.h:9
auto numInactive() const
Number of inactive elements.
Definition: group.h:172
Turns a pair of iterators into a range.
Definition: group.h:16
Selectors
Selections to filter groups using getSelectionFilter()
Definition: group.h:205
int id
Particle id/type.
Definition: particle.h:225
std::function< void(Point &)> BoundaryFunction
Function to apply PBC to a position.
Definition: core.h:30
General properties for molecules.
Definition: molecule.h:211
bool isAtomic() const
Is it an atomic group?
Definition: group.h:187
Particle class for storing positions, id, and other properties.
Definition: particle.h:220
Cell list class templates.
Definition: actions.cpp:11
End of Group class.
Definition: group.h:177
concept RequireGroups
Concept for a range of groups.
Definition: group.h:387
std::vector< MoleculeData > molecules
List of molecule types.
Definition: molecule.cpp:22
auto all()
Active and inactive elements.
Definition: group.h:101
bool isMolecular() const
is it a molecular group?
Definition: group.h:192
std::pair< int, int > to_index(T reference) const
Returns particle index pair relative to given reference.
Definition: group.h:44
const MoleculeData & traits() const
Convenient access to molecule properties.
Definition: group.h:275
bool match() const
Determines if given Selectors bitmask matches group.
Definition: group.h:227
std::function< bool(const Group &)> getGroupFilter()
Get lambda function matching given enum Select mask.
Definition: group.h:380
auto positions()
Range of positions of active particles.
Definition: group.h:290
auto positions() const
Range of positions of active particles.
Definition: group.h:296