faunus
move.h
1 #pragma once
2 
3 #include "average.h"
4 #include "mpicontroller.h"
5 #include "space.h"
6 #include "io.h"
7 #include "smart_montecarlo.h"
8 #include "aux/timers.h"
9 #include "aux/sparsehistogram.h"
10 #include <range/v3/view/filter.hpp>
11 #include <range/v3/view/iota.hpp>
12 #include <range/v3/view/transform.hpp>
13 #include <range/v3/view/indirect.hpp>
14 
15 namespace Faunus {
16 
17 namespace Speciation {
18 class GroupDeActivator;
19 }
20 
21 namespace Energy {
22 class Hamiltonian;
23 }
24 
25 namespace move {
26 
27 class MoveCollection;
28 
38 class Move
39 {
40  private:
41  virtual void _move(Change& change) = 0;
42  virtual void _accept(Change& change);
43  virtual void _reject(Change& change);
44  virtual void _to_json(json& j) const = 0;
45  virtual void _from_json(const json& j) = 0;
48 
49  friend MoveCollection;
50  unsigned long number_of_accepted_moves = 0;
51  unsigned long number_of_rejected_moves = 0;
52  unsigned int sweep_interval = 1;
53  const std::string cite;
54 
55  protected:
56  const std::string name;
58  int repeat = 1;
59  unsigned long number_of_attempted_moves = 0;
60 
61  public:
62  static Random slump;
63 
64  void from_json(const json& j);
65  void to_json(json& j) const;
66  void move(Change& change);
67  void accept(Change& change);
68  void reject(Change& change);
69  void setRepeat(int repeat);
70  virtual double bias(Change& change, double old_energy,
71  double new_energy);
72  Move(Space& spc, std::string_view name, std::string_view cite);
73  inline virtual ~Move() = default;
74  [[nodiscard]] bool isStochastic() const;
75  [[nodiscard]] const std::string& getName() const;
76 };
77 
78 void from_json(const json&, Move&);
79 void to_json(json&, const Move&);
80 
87 class ReplayMove : public Move
88 {
89  std::unique_ptr<XTCReader> reader = nullptr;
90  TrajectoryFrame frame;
91  bool end_of_trajectory = false;
92  // FIXME resolve always accept / always reject on the Faunus level
93  const double force_accept =
94  -1e12;
95 
96  void _move(Change& change) override;
97  void _to_json(json&) const override;
98  void _from_json(const json&) override;
99  double bias(Change&, double, double) override;
100 
101  protected:
102  using Move::spc;
103  ReplayMove(Space& spc, const std::string& name, const std::string& cite);
104 
105  public:
106  explicit ReplayMove(Space& spc);
107 };
108 
112 class [[maybe_unused]] AtomicSwapCharge : public Move
113 {
114  int molid = -1;
115  double pKa, pH;
116  Average<double> msqd; // mean squared displacement
117  double _sqd, _bias; // squared displament
118  std::string molname; // name of molecule to operate on
119  Change::GroupChange cdata;
120 
121  void _to_json(json&) const override;
122  void _from_json(const json&) override;
123  typename ParticleVector::iterator randomAtom();
124  void _move(Change& change) override;
125  double bias(Change&, double,
126  double) override;
127  void _accept(Change&) override;
128  void _reject(Change&) override;
129 
130  protected:
131  using Move::spc;
132  AtomicSwapCharge(Space& spc, const std::string& name, const std::string& cite);
133 
134  public:
135  explicit AtomicSwapCharge(Space& spc);
136 };
137 
142 {
143  ParticleVector::const_iterator latest_particle;
144  const Energy::Hamiltonian& hamiltonian;
145  std::map<int, SparseHistogram<>>
146  energy_histogram;
147  double energy_resolution = 0.0;
148  double latest_displacement_squared;
149  double default_dp = 0.0;
150  double default_dprot = 0.0;
151  void sampleEnergyHistogram();
152  void saveHistograms();
153  void checkMassCenter(
154  Space::GroupType& group) const;
155  void
156  groupToDisk(const Space::GroupType& group) const;
157 
158  protected:
159  int molid = -1;
160  Point directions = {1, 1, 1};
162  std::string molecule_name;
164 
165  void _to_json(json&) const override;
166  void _from_json(const json&) override;
167  ParticleVector::iterator randomAtom();
168 
169  virtual void translateParticle(ParticleVector::iterator, double);
170  void _move(Change&) override;
171  void _accept(Change&) override;
172  void _reject(Change&) override;
173 
174  AtomicTranslateRotate(Space& spc, const Energy::Hamiltonian& hamiltonian,
175  const std::string& name, const std::string& cite);
176 
177  public:
178  AtomicTranslateRotate(Space& spc, const Energy::Hamiltonian& hamiltonian);
179  ~AtomicTranslateRotate() override;
180 };
181 
186 /*
187 template<typename Tspace>
188  class Atomic2dTranslateRotate : public AtomicTranslateRotate {
189  protected:
190  typedef AtomicTranslateRotate base;
191  using base::spc;
192 
193  void translateParticle(Space::Tpvec::iterator p, double dp) override {
194  auto &g = spc.groups[base::cdata.index];
195  Point oldpos = p->pos;
196 
197  Point rtp = xyz2rtp(p->pos); // Get the spherical coordinates of the particle
198  double slump_theta = dp * (base::slump() - 0.5); // Get random theta-move
199  double slump_phi = dp * (base::slump() - 0.5); // Get random phi-move
200 
201  double scalefactor_theta = spc.geo.getRadius() * sin(rtp.z()); // Scale-factor for
202 theta double scalefactor_phi = spc.geo.getRadius(); // Scale-factor for phi
203 
204  Point theta_dir = Point(-sin(rtp.y()), cos(rtp.y()), 0); // Unit-vector in
205 theta-direction Point phi_dir = Point(cos(rtp.y()) * cos(rtp.z()), sin(rtp.y()) * cos(rtp.z()),
206  -sin(rtp.z())); // Unit-vector in phi-direction
207  Point xyz = oldpos + scalefactor_theta * theta_dir * slump_theta +
208  scalefactor_phi * phi_dir * slump_phi; // New position
209  p->pos = spc.geo.getRadius() * xyz / xyz.norm(); // Convert to cartesian
210 coordinates
211 
212  spc.geo.boundary(p->pos);
213  base::_sqd = spc.geo.sqdist(oldpos, p->pos); // squared displacement
214  if (not g.atomic) { // recalc mass-center for non-molecular
215 groups g.cm = Geometry::massCenter(g.begin(), g.end(), spc.geo.getBoundaryFunc(), -g.cm);
216 
217 #ifndef NDEBUG
218  Point cmbak = g.cm; // backup mass center
219  g.translate(-cmbak, spc.geo.getBoundaryFunc()); // translate to {0,0,0}
220  double should_be_zero = spc.geo.sqdist({0, 0, 0}, Geometry::massCenter(g.begin(),
221 g.end())); if (should_be_zero > 1e-6) throw std::runtime_error("atomic move too large"); else
222 g.translate(cmbak, spc.geo.getBoundaryFunc()); #endif
223  }
224  }
225 
226  public:
227  Atomic2dTranslateRotate(Tspace &spc, std::string name, std::string cite) : base(spc,
228 name, cite) {} explicit Atomic2dTranslateRotate(Tspace &spc) : Atomic2dTranslateRotate(spc,
229 "transrot 2d", "") {}
230  };*/
231 
235 class TranslateRotate : public Move
236 {
237  protected:
238  using OptionalGroup = std::optional<std::reference_wrapper<Space::GroupType>>;
239  int molid = -1;
240  void _to_json(json& j) const override;
241  TranslateRotate(Space& spc, std::string name, std::string cite);
242 
243  private:
244  Average<double> mean_squared_displacement;
245  Average<double> mean_squared_rotation_angle;
246 
247  double latest_displacement_squared = 0.0;
248  double latest_rotation_angle_squared = 0.0;
249  double translational_displacement = 0.0;
250  double rotational_displacement = 0.0;
251  Point translational_direction = {1, 1, 1};
252  Point fixed_rotation_axis = {0, 0, 0};
253 
254  virtual OptionalGroup findRandomMolecule();
255  double translateMolecule(Space::GroupType& group);
256  double rotateMolecule(Space::GroupType& group);
257  void checkMassCenter(const Space::GroupType& group) const; // sanity check of move
258 
259  void _from_json(const json& j) override;
260  void _move(Change& change) override;
261  void _accept(Change&) override;
262  void _reject(Change&) override;
263 
264  public:
265  explicit TranslateRotate(Space& spc);
266 };
267 
278 {
279  private:
281  void _to_json(json& j) const override;
282  OptionalGroup findRandomMolecule() override;
283  double bias(Change& change, double old_energy, double new_energy) override;
284 
285  public:
286  SmarterTranslateRotate(Space& spc, const json& j);
287 };
288 
302 class ConformationSwap : public Move
303 {
304  public:
305  enum class CopyPolicy
306  {
307  ALL,
308  POSITIONS,
309  CHARGES,
310  PATCHES,
311  INVALID
312  };
313  private:
314  CopyPolicy copy_policy;
315  RandomInserter inserter;
316  int molid = -1;
317  void copyConformation(ParticleVector& source_particle,
318  ParticleVector::iterator destination) const;
319  void _to_json(json& j) const override;
320  void _from_json(const json& j) override;
321  void _move(Change& change) override;
322  void setRepeat();
323  void checkConformationSize() const;
324  void checkMassCenterDrift(const Point& old_mass_center,
325  const ParticleVector& particles);
326  void registerChanges(Change& change,
327  const Space::GroupType& group) const;
328  ConformationSwap(Space& spc, const std::string& name, const std::string& cite);
329 
330  public:
331  explicit ConformationSwap(Space& spc);
332 }; // end of conformation swap move
333 
334 NLOHMANN_JSON_SERIALIZE_ENUM(ConformationSwap::CopyPolicy,
335  {{ConformationSwap::CopyPolicy::INVALID, nullptr},
336  {ConformationSwap::CopyPolicy::ALL, "all"},
337  {ConformationSwap::CopyPolicy::PATCHES, "patches"},
338  {ConformationSwap::CopyPolicy::POSITIONS, "positions"},
339  {ConformationSwap::CopyPolicy::CHARGES, "charges"}})
340 
341 class VolumeMove : public Move
342 {
343  protected:
344  Geometry::VolumeMethod volume_scaling_method = Geometry::VolumeMethod::ISOTROPIC;
345  double logarithmic_volume_displacement_factor = 0.0;
346  double old_volume = 0.0;
347  double new_volume = 0.0;
348  void _move(Change& change) override;
349  void _from_json(const json& j) override;
350 
351  private:
352  Average<double> mean_volume;
353  Average<double> mean_square_volume_change;
354 
355  virtual void setNewVolume();
356  void _to_json(json& j) const override;
357  void _accept(Change& change) override;
358  void _reject(Change& change) override;
359 
360  public:
361  VolumeMove(Space& spc, std::string_view name);
362  explicit VolumeMove(Space& spc);
363 }; // end of VolumeMove
364 
368 class ChargeMove : public Move
369 {
370  private:
371  Average<double> mean_squared_charge_displacement;
372  Change::GroupChange group_change;
373 
374  void _move(Change& change) override;
375  void _accept(Change&) override;
376  void _reject(Change&) override;
377  void _from_json(const json& j) override;
378  [[nodiscard]] virtual double getChargeDisplacement(const Particle& particle) const;
379  ChargeMove(Space& spc, std::string_view name, std::string_view cite);
380 
381  protected:
382  double max_charge_displacement = 0.0;
383  double charge_displacement = 0.0;
384  ParticleVector::size_type particle_index;
385  void _to_json(json& j) const override;
386 
387  public:
388  explicit ChargeMove(Space& spc);
389 };
390 
398 {
399  private:
400  Average<double> mean_bias;
401  void _to_json(json& j) const override;
402  [[nodiscard]] double getChargeDisplacement(const Particle& particle) const override;
403  double bias(Change& change, double old_energy, double new_energy) override;
404 
405  public:
406  explicit QuadraticChargeMove(Space& spc);
407 };
408 
412 class ChargeTransfer : public Move
413 {
414  private:
415  Average<double> msqd; // mean squared displacement
416  double dq = 0, deltaq = 0;
417 
418  struct moldata
419  {
420  double charges = 0;
421  double moves = 0;
422  size_t numOfAtoms = 0;
423  int id = 0;
424  std::string molname;
425  std::vector<double> min, max;
426  std::vector<double> molrange;
427  std::vector<double> ratio;
428  std::vector<double> changeQ;
429  Change::GroupChange cdata;
430  };
431 
432  moldata mol1, mol2;
433 
434  double sumTemp = 0;
435  int i = 0;
436 
437  void _to_json(json& j) const override;
438  void _from_json(const json& j) override;
439  void _move(Change& change) override;
440  void _accept(Change&) override;
441  void _reject(Change&) override;
442 
443  protected:
444  using Move::spc;
445  ChargeTransfer(Space& spc, const std::string& name, const std::string& cite);
446 
447  public:
448  explicit ChargeTransfer(Space& spc);
449 };
450 
456 class QuadrantJump : public Move
457 {
458  private:
459  int molid = -1;
460  Point dir = {1, 1, 1};
461  std::vector<size_t> index;
462  double _sqd; // squared displacement
463  Average<double> msqd; // mean squared displacement
464 
465  void _to_json(json& j) const override;
466  void _from_json(const json& j) override;
467  void _move(Change& change) override;
468 
469  void _accept(Change&) override { msqd += _sqd; }
470 
471  void _reject(Change&) override { msqd += 0; }
472 
473  protected:
474  using Move::spc;
475  QuadrantJump(Space& spc, const std::string& name, const std::string& cite);
476 
477  public:
478  explicit QuadrantJump(Space& spc);
479 };
480 
481 #ifdef ENABLE_MPI
482 
492 class GibbsEnsembleHelper
493 {
494  public:
495  using VectorOfMolIds = std::vector<MoleculeData::index_type>;
496  const MPI::Controller& mpi;
497  int partner_rank = -1;
498  double total_volume = 0;
499  int total_num_particles = 0;
500  VectorOfMolIds molids;
501  std::pair<int, int>
502  currentNumParticles(const Space& spc) const;
503  std::pair<double, double>
504  currentVolumes(const Space& spc) const;
505  double exchange(double value) const;
506  GibbsEnsembleHelper(const Space& spc, const MPI::Controller& mpi, const VectorOfMolIds& molids);
507 };
508 
512 class GibbsVolumeMove : public VolumeMove
513 {
514  private:
515  MPI::Controller& mpi;
516  std::unique_ptr<GibbsEnsembleHelper> gibbs;
517  bool direct_volume_displacement =
518  true;
519  void setNewVolume() override;
520  void _from_json(const json& j) override;
521  bool volumeTooExtreme() const;
522 
523  protected:
524  void _move(Change& change) override;
525 
526  public:
527  GibbsVolumeMove(Space& spc, MPI::Controller& mpi);
528  double bias(Change& change, double old_energy, double new_energy) override;
529 };
530 
537 class GibbsMatterMove : public Move
538 {
539  private:
540  bool insert;
541  MoleculeData::index_type molid;
542  MPI::Controller& mpi;
543  std::unique_ptr<GibbsEnsembleHelper> gibbs;
544  std::unique_ptr<Speciation::GroupDeActivator> molecule_bouncer;
545  void _from_json(const json& j) override;
546  void _to_json(json& j) const override;
547 
548  protected:
549  void _move(Change& change) override;
550 
551  public:
552  GibbsMatterMove(Space& spc, MPI::Controller& mpi);
553  double bias(Change& change, double old_energy, double new_energy) override;
554 };
555 
567 class ParallelTempering : public Move
568 {
569  private:
570  const MPI::Controller& mpi;
571  MPI::ExchangeParticles exchange_particles;
572  std::unique_ptr<MPI::Partner> partner;
573  Geometry::VolumeMethod volume_scaling_method =
574  Geometry::VolumeMethod::ISOTROPIC;
575  std::map<MPI::Partner::PartnerPair, Average<double>> acceptance_map;
576 
577  Random slump; // static instance of Random (shared for all in ParallelTempering)
578  void _to_json(json& j) const override;
579  void _from_json(const json& j) override;
580  void _move(Change& change) override;
581  void _accept(Change& change) override;
582  void _reject(Change& change) override;
583  double bias(Change& change, double uold,
584  double unew) override;
585  double exchangeEnergy(double energy_change);
586  void exchangeState(Change& change);
587  void exchangeGroupSizes(Space::GroupVector& groups, int partner_rank);
588 
589  std::string filename;
590  std::unique_ptr<std::ostream> stream;
591  std::optional<int> exchange;
592  void writeToFileStream() const;
593 
594  public:
595  explicit ParallelTempering(Space& spc, const MPI::Controller& mpi);
596 };
597 
598 #endif
599 
606 [[maybe_unused]] std::unique_ptr<Move> createMove(const std::string& name, const json& properties,
607  Space& spc, Energy::Hamiltonian& hamiltonian);
608 
614 {
615  private:
616  unsigned int number_of_moves_per_sweep;
618  std::vector<double> repeats;
619  std::discrete_distribution<unsigned int> distribution;
620  using move_iterator = decltype(moves.vec)::iterator;
621  move_iterator sample();
622 
623  public:
624  MoveCollection(const json& list_of_moves, Space& spc, Energy::Hamiltonian& hamiltonian,
625  Space& old_spc);
626  void addMove(std::shared_ptr<Move>&& move);
627  [[maybe_unused]] [[nodiscard]] const BasePointerVector<Move>&
628  getMoves() const;
629  friend void to_json(json& j, const MoveCollection& propagator);
630 
641  {
642  auto is_valid_and_stochastic = [&](auto move) {
643  return move < moves.end() && (*move)->isStochastic();
644  };
645  using namespace ranges::cpp20;
646  return views::iota(0U, number_of_moves_per_sweep) |
647  views::transform([&]([[maybe_unused]] auto count) { return sample(); }) |
648  views::filter(is_valid_and_stochastic) |
649  ranges::views::indirect; // dereference iterator
650  }
651 
665  auto constantIntervalMoves(const unsigned int sweep_number = 1)
666  {
667  auto is_static_and_time_to_sample = [&, sweep_number](const auto& move) {
668  return (!move->isStochastic()) && (sweep_number % move->sweep_interval == 0);
669  };
670  return moves | std::views::filter(is_static_and_time_to_sample);
671  }
672 };
673 
674 void to_json(json& j, const MoveCollection& propagator);
675 
676 } // namespace move
677 } // namespace Faunus
nlohmann::json json
JSON object.
Definition: json_support.h:10
Move that will swap conformation of a molecule.
Definition: move.h:302
Eigen::Vector3d Point
3D vector used for positions, velocities, forces etc.
Definition: coordinates.h:7
Simple data structure to store a trajectory frame in native Faunus format.
Definition: io.h:563
const std::string name
Name of move.
Definition: move.h:56
Random number generator.
Definition: random.h:34
Replay simulation from a trajectory.
Definition: move.h:87
Class storing a list of MC moves with their probability weights and randomly selecting one...
Definition: move.h:613
auto repeatedStochasticMoves()
Generates a range of repeated, randomized move pointers guaranteed to be valid.
Definition: move.h:640
Base class for all moves (MC, Langevin, ...)
Definition: move.h:38
Translate and rotate individual atoms.
Definition: move.h:141
Average< double > mean_square_displacement
mean squared displacement
Definition: move.h:161
Translate and rotate an atom on a 2D hypersphere-surface.
Definition: move.h:235
As ChargeMove but performs displacements in squared charge.
Definition: move.h:397
Swap the charge of a single atom.
Definition: move.h:112
Transfers charge between two molecules.
Definition: move.h:412
std::vector< Particle > ParticleVector
Storage type for collections of particles.
Definition: particle.h:253
Change::GroupChange cdata
Data for change object.
Definition: move.h:163
Properties of changed groups.
Definition: space.h:40
Particle class for storing positions, id, and other properties.
Definition: particle.h:220
Cell list class templates.
Definition: actions.cpp:11
Space & spc
Space to operate on.
Definition: move.h:57
std::string molecule_name
name of molecule to operate on
Definition: move.h:162
End of Group class.
Definition: group.h:177
Displaces charge on a single atom.
Definition: move.h:368
Aggregate and sum energy terms.
Definition: energy.h:1954
Smart Monte Carlo version of molecular translation and rotation.
Definition: move.h:277
NLOHMANN_JSON_SERIALIZE_ENUM(SpheroCylinderData::PatchType, {{SpheroCylinderData::PatchType::Invalid, nullptr}, {SpheroCylinderData::PatchType::Full, "full"}, {SpheroCylinderData::PatchType::Capped, "capped"}, {SpheroCylinderData::PatchType::None, "none"}}) class AtomData
General properties for atoms.
Definition: atomdata.h:61
Specify changes made to a system.
Definition: space.h:29
static Random slump
Shared for all moves.
Definition: move.h:62
std::vector< value_type > vec
Vector of shared pointers to base class.
Definition: auxiliary.h:240
Placeholder for atoms and molecules.
Definition: space.h:92
Helper class for storing vectors of base pointers.
Definition: auxiliary.h:237
QuadrantJump translates a molecule to another quadrant considering as the origin the center of the bo...
Definition: move.h:456
Inserts molecules into random positions in the container.
Definition: molecule.h:47
auto constantIntervalMoves(const unsigned int sweep_number=1)
Range of moves excluded from the sample() algorithm above due to ZERO weight.
Definition: move.h:665
Helper class for constructing smart monte carlo moves.
Definition: smart_montecarlo.h:149
VolumeMethod
Various methods of volume scaling,.
Definition: geometry.h:52