SSAGES  0.1
A MetaDynamics Package
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Groups Pages
RouseModeCV.h
1 
21 #pragma once
22 
23 #include "CollectiveVariable.h"
24 #include "Validator/ObjectRequirement.h"
25 #include "Drivers/DriverException.h"
26 #include "Snapshot.h"
27 #include "schema.h"
28 
29 namespace SSAGES
30 {
32 
40  {
41  private:
42  std::vector<Label> groups_; // vector of groups of indices to define the particle groups
43  std::vector<double> massg_; // vector of the total mass for each particle group
44  int N_; // number of Rouse beads in polymer chain
45  int p_; // index of mode of interest as CV
46  Vector3 xp_; // 3d vector for containing vectorial rouse amplitude
47  std::vector<Vector3> r_; // vector of coordinate positions for each bead
48 
49  public:
51 
55  RouseModeCV(const std::vector<Label>& groups, int p) :
56  groups_(groups), p_(p), N_( groups_.size())
57  { massg_.resize( groups_.size(),0.0 ); }
58 
60 
64  void setMasses(const std::vector<Label>& groups, const Snapshot& snapshot ) {
65  // Compute mass of each group and store to massg_
66  double massi; Label listi;
67  for (size_t i = 0; i < N_; ++i) {
68  listi = groups[i]; // MW: can this be used directly in Total Mass
69  Label idi;
70  snapshot.GetLocalIndices(listi, &idi);
71  massg_[i] = snapshot.TotalMass(idi);
72  }
73  }
74 
76 
79  void Initialize(const Snapshot& snapshot) override
80  {
81  using std::to_string;
82 
83  // Check for valid p_
84  if (p_ > groups_.size())
85  throw std::invalid_argument(
86  "RouseModeCV: Expected to find p to be less than " +
87  to_string(groups_.size()) +" but found p = " +
88  to_string(p_)
89  );
90  // Check for valid groups
91  for (size_t j = 0; j < groups_.size(); ++j) {
92  auto nj = groups_[j].size();
93  // Make sure atom IDs in the group are somewhere
94  std::vector<int> found(nj,0);
95  for (size_t i = 0; i <nj; ++i) {
96  if(snapshot.GetLocalIndex(groups_[j][i]) != -1)
97  found[i] = 1;
98  }
99 
100  MPI_Allreduce(MPI_IN_PLACE, found.data(), nj, MPI_INT, MPI_SUM, snapshot.GetCommunicator());
101  unsigned njtot = std::accumulate(found.begin(), found.end(), 0, std::plus<int>());
102 
103  if(njtot != nj)
104  throw std::invalid_argument(
105  "RouseModeCV: Expected to find " +
106  to_string(nj) +
107  " atoms in group " + to_string(j) +", but only found " +
108  to_string(njtot) + "."
109  );
110 
111  }
112  // Set the masses of each particle group in massg_
113  this->setMasses( groups_, snapshot);
114  }
115 
117 
120  void Evaluate(const Snapshot& snapshot) override
121  {
122 
123  // Get data from snapshot.
124  auto ntot = snapshot.GetNumAtoms(); // total number of atoms
125  const auto& masses = snapshot.GetMasses(); // mass of each atom
126 
127  // Initialize working variables
128  double ppi_n = p_ * M_PI / N_; // constant
129  xp_.fill(0.0); // vectorial Rouse mode
130  r_.resize(N_); // position vector for beads in Rouse chain (unwrapped)
131  grad_.resize(ntot, Vector3{0,0,0}); // gradient set to 0.0 for all atoms
132  std::fill(grad_.begin(), grad_.end(), Vector3{0,0,0});
133 
134  // Iterate over all N_ atom groups and compute the center of mass for each
135  std::vector<Vector3> rcom; // vector of COM positions
136  for (size_t i = 0; i < N_; ++i) {
137  Label idi; // list of indices
138  snapshot.GetLocalIndices(groups_[i], &idi);
139  rcom.push_back(snapshot.CenterOfMass(idi,massg_[i])); // center of mass for group
140  }
141 
142  // Now compute differences vectors between the neighboring beads
143  // accumulate displacements to reconstruct unwrapped polymer chain
144  // for simplicity, we consider the first bead to be the reference position
145  // in all snapshots
146  r_[0] = rcom[0];
147  for (size_t i = 1; i< N_; ++i) {
148  Vector3 dri = snapshot.ApplyMinimumImage(rcom[i] - rcom[i-1]);
149  r_[i] = r_[i-1] + dri; // r_i = r_{i-1} + (r_i - r_{i-1})
150  }
151 
152  // Determine the value of the Rouse coordinate
153  // Xp(t) = 1/sqrt(N) * sum_{i=1}^{N} ri, p = 0
154  // Xp(t) = sqrt(2/N) * sum_{i=1}^{N} ri * cos[p*pi/N*(i-0.5)], p = 1,...,N-1
155  // Note: this solution is valid for homogeneous friction
156  xp_.fill(0.0);
157  for (size_t i = 0; i<N_; ++i) {
158  xp_ += r_[i]*cos ( ppi_n * (i+0.5) );
159  }
160  xp_ /= sqrt(N_);
161  if ( p_ != 0 ) xp_ *= sqrt(2.0) ;
162 
163  // Compute Rouse vector norm as the CV
164  // CV = sqrt(Xp*Xp), Xp = (Xp1,Xp2,Xp3)
165  val_ = xp_.norm();
166 
167  // Now perform gradient operation
168  // dCV/dxjd = (Xpd/CV)*(c/N)**0.5*sum_i=1^N cos[p*pi(i-0.5)/N] mj/Mi *delta_j({i})
169  // delta_j({i}) = 1, if j in {i}, 0 otherwise
170  Vector3 gradpcon = xp_ / sqrt(N_) / val_;
171  if ( p_ != 0) gradpcon *= sqrt(2.0); // (Xpd/CV)*(c/N)**0.5
172  for (size_t i = 0; i < N_; ++i) {
173  Label idi; // list of indices
174  snapshot.GetLocalIndices(groups_[i], &idi);
175  // go over each atom in the group and add to its gradient
176  // Note: performance tradeoff here. All gradient elements have a common factor of
177  // Xpd/CV*sqrt(c/N) = prefactor, with c = 2 if p != 0
178  // this could be factored out, but if ntot >> number of atoms in groups
179  // then it won't be worth it to post multiply all gradient terms...
180  // Could also go over loop again after to do the multiplication, but
181  // that is troublesome if atom ids appear in multiple groups for some reason
182  double cosval = cos(ppi_n*(i+0.5)) / massg_[i]; // cos[p*pi(i-0.5)/N] / Mi
183  for (auto& id : idi) {
184  grad_[id] += gradpcon* cosval * masses[id];
185  }
186  }
187 
188  }
189 
190  static RouseModeCV* Build(const Json::Value& json, const std::string& path)
191  {
192  Json::ObjectRequirement validator;
193  Json::Value schema;
194  Json::Reader reader;
195 
196  reader.parse(JsonSchema::RouseModeCV, schema);
197  validator.Parse(schema, path);
198 
199  // Validate inputs.
200  validator.Validate(json, path);
201  if(validator.HasErrors())
202  throw BuildException(validator.GetErrors());
203 
204  std::vector<Label> groups;
205  for (auto& group : json["groups"])
206  {
207  groups.push_back({});
208  for(auto& id : group)
209  groups.back().push_back(id.asInt());
210  }
211 
212  auto mode = json.get("mode",0).asInt();
213  return new RouseModeCV( groups, mode);
214  }
215  };
216 }
std::vector< int > Label
List of integers.
Definition: types.h:48
bool HasErrors()
Check if errors have occured.
Definition: Requirement.h:86
unsigned GetNumAtoms() const
Get number of atoms in this snapshot.
Definition: Snapshot.h:200
void Evaluate(const Snapshot &snapshot) override
Evaluate the CV.
Definition: RouseModeCV.h:120
double TotalMass(const Label &indices) const
Compute the total mass of a group of particles based on index.
Definition: Snapshot.h:451
Collective variable is a Rouse mode for a polymer chain comprised of N particle groups.
Definition: RouseModeCV.h:39
Class containing a snapshot of the current simulation in time.
Definition: Snapshot.h:43
virtual void Parse(Value json, const std::string &path) override
Parse JSON value to generate Requirement(s).
int GetLocalIndex(int id) const
Gets the local atom index corresponding to an atom ID.
Definition: Snapshot.h:555
RouseModeCV(const std::vector< Label > &groups, int p)
Basic Constructor for Rouse Mode CV.
Definition: RouseModeCV.h:55
std::vector< Vector3 > grad_
Gradient vector dCv/dxi.
const mxx::comm & GetCommunicator() const
Get communicator for walker.
Definition: Snapshot.h:184
void GetLocalIndices(const Label &ids, Label *indices) const
Definition: Snapshot.h:573
Exception to be thrown when building the Driver fails.
std::vector< std::string > GetErrors()
Get list of error messages.
Definition: Requirement.h:92
Vector3 CenterOfMass(const Label &indices) const
Definition: Snapshot.h:466
const std::vector< double > & GetMasses() const
Const access to the particle masses.
Definition: Snapshot.h:378
Requirements on an object.
void Initialize(const Snapshot &snapshot) override
Initialize necessary variables.
Definition: RouseModeCV.h:79
void setMasses(const std::vector< Label > &groups, const Snapshot &snapshot)
Helper function to determine masses of each group.
Definition: RouseModeCV.h:64
Eigen::Vector3d Vector3
Three-dimensional vector.
Definition: types.h:33
void ApplyMinimumImage(Vector3 *v) const
Apply minimum image to a vector.
Definition: Snapshot.h:418
double val_
Current value of CV.
Abstract class for a collective variable.
virtual void Validate(const Value &json, const std::string &path) override
Validate JSON value.