faunus
space.h
1 #pragma once
2 #include "core.h"
3 #include "geometry.h"
4 #include "group.h"
5 #include "molecule.h"
6 #include <range/v3/view/join.hpp>
7 #include <range/v3/view/filter.hpp>
8 #include <range/v3/range/conversion.hpp>
9 
10 namespace Faunus {
11 
29 struct Change
30 {
31  using index_type = std::size_t;
32  bool everything = false;
33  bool volume_change = false;
34  bool matter_change = false;
36  true;
38 
40  struct GroupChange
41  {
42  index_type group_index;
43  bool dNatomic = false;
44  bool dNswap = false;
45  bool internal = false;
46  bool all =
47  false;
48  std::vector<index_type>
50 
51  bool
52  operator<(const GroupChange& other) const;
53  void sort();
54  };
55 
56  std::vector<GroupChange> groups;
57 
58  [[nodiscard]] std::optional<std::pair<index_type, index_type>> singleParticleChange() const;
59 
61  [[nodiscard]] inline auto touchedGroupIndex() const
62  {
63  return std::views::transform(groups, &GroupChange::group_index);
64  }
65 
67  [[maybe_unused]] [[nodiscard]] std::vector<index_type>
68  touchedParticleIndex(const std::vector<Group>&) const;
69 
70  void clear();
71  [[nodiscard]] bool empty() const;
72  explicit operator bool() const;
73  void sanityCheck(
74  const std::vector<Group>& group_vector) const;
75 } __attribute__((aligned(32)));
76 
77 void to_json(json& j, const Change::GroupChange& group_change);
78 void to_json(json& j, const Change& change);
79 
92 class Space
93 {
94  public:
96  using GroupType = Group;
97  using GroupVector = std::vector<GroupType>;
98  using GroupRefVector = std::vector<std::reference_wrapper<Group>>;
99  using ConstGroupRefVector = std::vector<std::reference_wrapper<const Group>>;
100  using ScaleVolumeTrigger = std::function<void(Space&, double, double)>;
101  using ChangeTrigger = std::function<void(Space&, const Change&)>;
102  using SyncTrigger = std::function<void(Space&, const Space&, const Change&)>;
103 
104  private:
113  std::map<MoleculeData::index_type, std::size_t> implicit_reservoir;
114 
115  std::vector<ChangeTrigger> changeTriggers;
116  std::vector<SyncTrigger>
117  onSyncTriggers;
118 
119  public:
121  GroupVector groups;
123  std::vector<ScaleVolumeTrigger>
125 
126  [[nodiscard]] const std::map<MoleculeData::index_type, std::size_t>&
127  getImplicitReservoir() const;
128  std::map<MoleculeData::index_type, std::size_t>& getImplicitReservoir();
129 
131  enum class Selection
132  {
133  ALL,
134  ACTIVE,
135  INACTIVE,
136  ALL_NEUTRAL,
137  ACTIVE_NEUTRAL,
138  INACTIVE_NEUTRAL
139  };
140 
141  void clear();
142  GroupType& addGroup(MoleculeData::index_type molid,
143  const ParticleVector& particles);
144  GroupVector::iterator findGroupContaining(
145  const Particle& particle,
146  bool include_inactive = false);
147  GroupVector::iterator
148  findGroupContaining(AtomData::index_type atom_index);
149  [[nodiscard]] size_t
150  numParticles(Selection selection = Selection::ACTIVE) const;
151 
152  Point
153  scaleVolume(double new_volume,
154  Geometry::VolumeMethod method =
155  Geometry::VolumeMethod::ISOTROPIC);
156 
157  GroupVector::iterator
158  randomMolecule(MoleculeData::index_type molid, Random& rand,
159  Selection selection = Selection::ACTIVE);
160 
161  json info();
162 
163  [[nodiscard]] std::size_t
164  getGroupIndex(const GroupType& group) const;
165  [[nodiscard]] std::size_t
166  getFirstParticleIndex(const GroupType& group) const;
167  [[nodiscard]] std::size_t getFirstActiveParticleIndex(
168  const GroupType& group) const;
169 
193  template <std::forward_iterator iterator,
194  class copy_operation = std::function<void(const Particle&, Particle&)>>
196  const iterator begin, const iterator end, ParticleVector::iterator destination,
197  copy_operation copy_function = [](const Particle& src, Particle& dst) { dst = src; })
198  {
199 
200  const auto size = std::distance(begin, end); // number of affected particles
201 
202  assert(destination >= particles.begin() && destination < particles.end());
203  assert(size <= std::distance(destination, particles.end()));
204 
205  auto affected_groups =
206  groups | std::views::filter([=](auto& group) {
207  return (group.begin() < destination + size) && (group.end() > destination);
208  }); // filtered group with affected groups only. Note we copy in org. `destination`
209 
210  // copy data from source range (this modifies `destination`)
211  std::for_each(begin, end,
212  [&](const auto& source) { copy_function(source, *destination++); });
213 
214  std::ranges::for_each(affected_groups, [&](Group& group) {
215  group.updateMassCenter(geometry.getBoundaryFunc(), group.begin()->pos);
216  });
217  }
218 
231  void updateInternalState(const Change& change);
232 
234  [[nodiscard]] auto positions() const
235  {
236  return std::views::transform(particles,
237  [](auto& particle) -> const Point& { return particle.pos; });
238  }
239 
241  auto positions() { return std::views::transform(particles, &Particle::pos); }
242 
243  static std::function<bool(const GroupType&)> getGroupFilter(MoleculeData::index_type molid,
244  const Selection& selection)
245  {
246  auto is_active = [](const GroupType& group) { return group.size() == group.capacity(); };
247 
248  auto is_neutral = [](RequireParticleIterator auto begin, RequireParticleIterator auto end) {
249  auto charge = std::accumulate(
250  begin, end, 0.0, [](auto sum, auto& particle) { return sum + particle.charge; });
251  return (fabs(charge) < 1e-6);
252  };
253 
254  std::function<bool(const GroupType&)> f;
255 
256  switch (selection) {
257  case (Selection::ALL):
258  f = []([[maybe_unused]] auto& group) { return true; };
259  break;
260  case (Selection::INACTIVE):
261  f = [=](auto& group) { return !is_active(group); };
262  break;
263  case (Selection::ACTIVE):
264  f = [=](auto& group) { return is_active(group); };
265  break;
266  case (Selection::ALL_NEUTRAL):
267  f = [=](auto& group) { return is_neutral(group.begin(), group.trueend()); };
268  break;
269  case (Selection::INACTIVE_NEUTRAL):
270  f = [=](auto& group) {
271  return !is_active(group) && is_neutral(group.begin(), group.trueend());
272  };
273  break;
274  case (Selection::ACTIVE_NEUTRAL):
275  f = [=](auto& group) {
276  return is_active(group) && is_neutral(group.begin(), group.end());
277  };
278  break;
279  }
280  return [f, molid](auto& group) { return group.id == molid && f(group); };
281  }
282 
289  auto findMolecules(MoleculeData::index_type molid, Selection selection = Selection::ACTIVE)
290  {
291  auto group_filter = getGroupFilter(molid, selection);
292  return groups | ranges::cpp20::views::filter(group_filter);
293  }
294 
295  [[nodiscard]] auto findMolecules(MoleculeData::index_type molid,
296  Selection selection = Selection::ACTIVE) const
297  {
298  auto group_filter = getGroupFilter(molid, selection);
299  return groups | ranges::cpp20::views::filter(group_filter);
300  }
301 
303  {
304  return groups | ranges::cpp20::views::join;
305  }
306 
307  [[nodiscard]] auto activeParticles() const
308  {
309  return groups | ranges::cpp20::views::join;
310  }
311 
317  template <std::integral index_type = int>
318  auto toIndices(const RequireParticles auto& particle_range) const
319  {
320  auto to_index = [&](auto& particle) {
321  const auto index = std::addressof(particle) - std::addressof(particles.at(0));
322  if (index < 0 || index >= particles.size()) {
323  throw std::out_of_range("particle range outside Space");
324  }
325  return static_cast<index_type>(index);
326  };
327  return particle_range | std::views::transform(to_index) | ranges::to_vector;
328  }
329 
335  auto findAtoms(AtomData::index_type atomid)
336  {
337  return activeParticles() | std::views::filter([atomid](const Particle& particle) {
338  return particle.id == atomid;
339  });
340  }
341 
347  [[nodiscard]] auto findAtoms(AtomData::index_type atomid) const
348  {
349  return activeParticles() | std::views::filter([atomid](const Particle& particle) {
350  return particle.id == atomid;
351  });
352  }
353 
354  [[nodiscard]] size_t countAtoms(AtomData::index_type atomid) const;
355 
362  template <unsigned int mask> auto numMolecules(MoleculeData::index_type molid) const
363  {
364  auto filter = [&](const GroupType& group) {
365  return (group.id == molid) ? group.template match<mask>() : false;
366  };
367  return std::count_if(groups.begin(), groups.end(), filter);
368  }
369 
370  void sync(const Space& other,
371  const Change& change);
372 
373 }; // end of space
374 
375 void to_json(json& j, const Space& spc);
376 void from_json(const json& j, Space& spc);
377 
391 {
392  private:
393  static void insertAtomicGroups(MoleculeData& moldata, Space& spc, size_t num_molecules,
394  size_t num_inactive_molecules);
395 
396  static void insertMolecularGroups(MoleculeData& moldata, Space& spc, size_t num_molecules,
397  size_t num_inactive);
398 
399  static void setPositionsForTrailingGroups(Space& spc, size_t num_molecules,
400  const Faunus::ParticleVector&, const Point&);
401 
402  static void insertImplicitGroups(const MoleculeData& moldata, Space& spc, size_t num_molecules);
403 
405  static size_t getNumberOfMolecules(const json& j, double volume,
406  const std::string& molecule_name);
407 
409  static size_t getNumberOfInactiveMolecules(const json& j, size_t number_of_molecules);
410 
412  static ParticleVector getExternalPositions(const json& j, const std::string& molname);
413 
415  static void insertItem(const std::string& molname, const json& properties, Space& spc);
416 
417  static void reserveMemory(const json& j, Space& spc);
418 
419  public:
420  static void insertMolecules(const json& j, Space& spc);
421 }; // end of insertMolecules class
422 
423 namespace SpaceFactory {
424 
425 void makeNaCl(Space& space, size_t num_particles,
426  const Geometry::Chameleon& geometry);
427 void makeWater(Space& space, size_t num_particles,
428  const Geometry::Chameleon& geometry);
429 
430 } // namespace SpaceFactory
431 
432 } // namespace Faunus
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
void updateMassCenter(Geometry::BoundaryFunction boundary, const Point &approximate_mass_center)
Calculates mass center.
Definition: group.cpp:135
auto toIndices(const RequireParticles auto &particle_range) const
Get vector of indices of given range of particles.
Definition: space.h:318
BoundaryFunction getBoundaryFunc() const
Lambda for applying boundary conditions on a point.
Definition: geometry.h:121
auto positions()
Mutable iterable range of all particle positions.
Definition: space.h:241
Point pos
Particle position vector.
Definition: particle.h:227
Random number generator.
Definition: random.h:34
Insert molecules into space.
Definition: space.h:390
Geometry class for spheres, cylinders, cuboids, hexagonal prism, truncated octahedron, slits.
Definition: geometry.h:342
bool moved_to_moved_interactions
If several groups are moved, should they interact with each other?
Definition: space.h:35
auto numMolecules(MoleculeData::index_type molid) const
Count number of molecules matching criteria.
Definition: space.h:362
void sanityCheck(const std::vector< Group > &group_vector) const
Sanity check on contained object data.
Definition: space.cpp:64
std::vector< GroupChange > groups
Touched groups by index in group vector.
Definition: space.h:56
void sort()
Sort group indices.
Definition: space.cpp:17
auto touchedGroupIndex() const
List of moved groups (index)
Definition: space.h:61
concept RequireParticles
Concept for a range of particles.
Definition: particle.h:257
static std::function< bool(const GroupType &)> getGroupFilter(MoleculeData::index_type molid, const Selection &selection)
Definition: space.h:243
auto findAtoms(AtomData::index_type atomid) const
Find active atoms of type atomid (complexity: order N)
Definition: space.h:347
bool everything
Everything has changed (particles, groups, volume)
Definition: space.h:32
std::vector< index_type > relative_atom_indices
A subset of particles changed (sorted; empty if all=true)
Definition: space.h:49
bool dNswap
The number of atoms has changed as a result of a swap move.
Definition: space.h:44
bool all
All particles in the group have changed (leave relative_atom_indices empty)
Definition: space.h:46
auto positions() const
Iterable range of all particle positions.
Definition: space.h:234
void updateParticles(const iterator begin, const iterator end, ParticleVector::iterator destination, copy_operation copy_function=[](const Particle &src, Particle &dst) { dst=src;})
Update particles in Space from a source range.
Definition: space.h:195
std::vector< Particle > ParticleVector
Storage type for collections of particles.
Definition: particle.h:253
int id
Particle id/type.
Definition: particle.h:225
General properties for molecules.
Definition: molecule.h:211
auto activeParticles()
Range with all active particles.
Definition: space.h:302
void clear()
Clear all change data.
Definition: space.cpp:22
GeometryType geometry
Container geometry (boundaries, shape, volume)
Definition: space.h:122
Properties of changed groups.
Definition: space.h:40
Particle class for storing positions, id, and other properties.
Definition: particle.h:220
auto activeParticles() const
Range with all active particles.
Definition: space.h:307
index_type group_index
Touched group index.
Definition: space.h:42
bool operator<(const GroupChange &other) const
Comparison operator based on group_index
Definition: space.cpp:12
Cell list class templates.
Definition: actions.cpp:11
bool volume_change
The volume has changed.
Definition: space.h:33
auto findMolecules(MoleculeData::index_type molid, Selection selection=Selection::ACTIVE)
Finds all groups of type molid (complexity: order N)
Definition: space.h:289
End of Group class.
Definition: group.h:177
std::optional< std::pair< index_type, index_type > > singleParticleChange() const
Determines if the change reflects a single particle change.
Definition: space.cpp:90
bool empty() const
Check if change object is empty.
Definition: space.cpp:28
ParticleVector particles
All particles are stored here!
Definition: space.h:120
Specify changes made to a system.
Definition: space.h:29
bool disable_translational_entropy
Force exclusion of translational entropy.
Definition: space.h:37
bool matter_change
The number of atomic or molecular species has changed.
Definition: space.h:34
Placeholder for atoms and molecules.
Definition: space.h:92
std::vector< index_type > touchedParticleIndex(const std::vector< Group > &) const
List of changed atom index relative to first particle in system.
Definition: space.cpp:39
auto findAtoms(AtomData::index_type atomid)
Find active atoms of type atomid (complexity: order N)
Definition: space.h:335
GroupVector groups
All groups are stored here (i.e. molecules)
Definition: space.h:121
std::vector< ScaleVolumeTrigger > scaleVolumeTriggers
Functions triggered whenever the volume is scaled.
Definition: space.h:124
std::function< bool(const Group &)> getGroupFilter()
Get lambda function matching given enum Select mask.
Definition: group.h:380
bool dNatomic
The number of atomic molecules has changed.
Definition: space.h:43
VolumeMethod
Various methods of volume scaling,.
Definition: geometry.h:52