SSAGES  0.9.3
Software Suite for Advanced General Ensemble Simulations
RMSDCV.h
1 
22 #pragma once
23 
24 #include "CVs/CollectiveVariable.h"
25 #include "Validator/ObjectRequirement.h"
26 #include "Drivers/DriverException.h"
27 #include "Snapshot.h"
28 #include "schema.h"
29 #include "Utility/ReadFile.h"
30 #include <array>
31 #include <Eigen/Dense>
32 #include <Eigen/Eigenvalues>
33 
34 namespace SSAGES
35 {
37 
42  class RMSDCV : public CollectiveVariable
43  {
44  private:
47 
49  std::string xyzfile_;
50 
52  std::vector<Vector3> refcoord_;
53 
56 
57  public:
59 
68  RMSDCV(const Label& atomids, std::string xyzfile, bool use_range = false) :
69  atomids_(atomids), xyzfile_(xyzfile)
70  {
71  if(use_range)
72  {
73  if(atomids.size() != 2)
74  {
75  throw BuildException({
76  "RMSDCV: With use_range, expected 2 atoms, but found " +
77  std::to_string(atomids.size()) + "."
78  });
79  }
80 
81  atomids_.clear();
82  if(atomids[0] >= atomids[1])
83  {
84  throw BuildException({
85  "RMSDCV: Atom range must be strictly increasing."
86  });
87  }
88  for(int i = atomids[0]; i <= atomids[1]; ++i)
89  {
90  atomids_.push_back(i);
91  }
92  }
93  }
94 
96 
99  void Initialize(const Snapshot& snapshot) override
100  {
101  const auto& masses = snapshot.GetMasses();
102  auto n = atomids_.size();
103 
104  // Make sure atom IDs are on at least one processor.
105  std::vector<int> found(n, 0);
106  for(size_t i = 0; i < n; ++i)
107  {
108  if(snapshot.GetLocalIndex(atomids_[i]) != -1) found[i] = 1;
109  }
110 
111  MPI_Allreduce(MPI_IN_PLACE, found.data(), n, MPI_INT, MPI_SUM, snapshot.GetCommunicator());
112  unsigned ntot = std::accumulate(found.begin(), found.end(), 0, std::plus<int>());
113  if(ntot != n)
114  {
115  throw BuildException({
116  "RMSDCV: Expected to find " + std::to_string(n) +
117  " atoms, but only found " + std::to_string(ntot) + "."
118  });
119  }
120 
121  Label idx;
122  snapshot.GetLocalIndices(atomids_, &idx);
123 
124  std::vector<std::array<double,4>> xyzinfo = ReadFile::ReadXYZ(xyzfile_);
125 
126  refcoord_.resize(snapshot.GetNumAtoms(), Vector3{0,0,0});
127 
128  // Loop through atom positions
129  for(size_t i = 0; i < xyzinfo.size(); ++i)
130  {
131  int id = snapshot.GetLocalIndex(xyzinfo[i][0]);
132  if(id == -1) continue; // Atom not found
133  for(size_t j = 0; j < atomids_.size(); ++j)
134  {
135  if(atomids_[j] == xyzinfo[i][0])
136  {
137  refcoord_[id][0] = xyzinfo[i][1];
138  refcoord_[id][1] = xyzinfo[i][2];
139  refcoord_[id][2] = xyzinfo[i][3];
140  }
141  }
142  }
143 
144  Vector3 mass_pos_prod_ref = Vector3::Zero();
145  double total_mass = 0;
146 
147  for(auto& i : idx)
148  {
149  mass_pos_prod_ref += masses[i]*refcoord_[i];
150  total_mass += masses[i];
151  }
152  MPI_Allreduce(MPI_IN_PLACE, mass_pos_prod_ref.data(), mass_pos_prod_ref.size(), MPI_DOUBLE, MPI_SUM, snapshot.GetCommunicator());
153  MPI_Allreduce(MPI_IN_PLACE, &total_mass, 1, MPI_DOUBLE, MPI_SUM, snapshot.GetCommunicator());
154 
155  COMref_ = mass_pos_prod_ref/total_mass;
156  }
157 
159 
162  void Evaluate(const Snapshot& snapshot) override
163  {
164  // Get local atom indices.
165  Label idx;
166  snapshot.GetLocalIndices(atomids_, &idx);
167 
168  // Get data from snapshot.
169  const auto& masses = snapshot.GetMasses();
170  const auto& pos = snapshot.GetPositions();
171  double masstot = snapshot.TotalMass(idx);
172 
173  // Initialize gradient.
174  std::fill(grad_.begin(), grad_.end(), Vector3{0,0,0});
175  grad_.resize(snapshot.GetNumAtoms(), Vector3{0,0,0});
176 
177  // Calculate center of mass
178  Vector3 COM_ = snapshot.CenterOfMass(idx);
179 
180  // Build correlation matrix
181  Matrix3 R = Matrix3::Zero();
182 
183  Vector3 diff, diff_ref;
184  double part_RMSD = 0;
185 
186  for(auto& i : idx)
187  {
188  diff = snapshot.ApplyMinimumImage(pos[i] - COM_);
189  diff_ref = refcoord_[i] - COMref_; // Reference has no "box" or minimum image
190 
191  R.noalias() += masses[i]*diff*diff_ref.transpose();
192 
193  part_RMSD += masses[i]*(diff.squaredNorm() + diff_ref.squaredNorm());
194  }
195  MPI_Allreduce(MPI_IN_PLACE, R.data(), R.size(), MPI_DOUBLE, MPI_SUM, snapshot.GetCommunicator());
196  MPI_Allreduce(MPI_IN_PLACE, &part_RMSD, 1, MPI_DOUBLE, MPI_SUM, snapshot.GetCommunicator());
197  R /= masstot;
198  part_RMSD /= masstot;
199 
200  Eigen::Matrix4d F;
201  F(0,0) = R(0,0) + R(1,1) + R(2,2);
202  F(1,0) = R(1,2) - R(2,1);
203  F(2,0) = R(2,0) - R(0,2);
204  F(3,0) = R(0,1) - R(1,0);
205 
206  F(0,1) = F(1,0);
207  F(1,1) = R(0,0) - R(1,1) - R(2,2);
208  F(2,1) = R(0,1) + R(1,0);
209  F(3,1) = R(0,2) + R(2,0);
210 
211  F(0,2) = F(2,0);
212  F(1,2) = F(2,1);
213  F(2,2) = -R(0,0) + R(1,1) - R(2,2);
214  F(3,2) = R(1,2) + R(2,1);
215 
216  F(0,3) = F(3,0);
217  F(1,3) = F(3,1);
218  F(2,3) = F(3,2);
219  F(3,3) = -R(0,0) - R(1,1) + R(2,2);
220 
221  //Find eigenvalues
222  Eigen::SelfAdjointEigenSolver<Eigen::Matrix4d> es(F);
223  auto max_lambda = es.eigenvalues().real()[3];
224 
225  // Calculate RMSD
226  val_ = sqrt(part_RMSD - (2*max_lambda));
227 
228  // If RMSD is zero, we have nothing to do.
229  if(val_ == 0) return;
230 
231  // Calculate gradient
232  auto ev = es.eigenvectors().real().col(3);
233  auto q = Eigen::Quaterniond(ev(0),ev(1),ev(2),ev(3));
234  Matrix3 RotMatrix = q.toRotationMatrix();
235 
236  for(auto& i : idx)
237  {
238  auto rotref = RotMatrix.transpose()*(refcoord_[i] - COMref_);
239  grad_[i] = masses[i]/masstot*(1-masses[i]/masstot)*(snapshot.ApplyMinimumImage(pos[i] - COM_) - rotref)/val_;
240  }
241  }
242 
244  static RMSDCV* Build(const Json::Value& json, const std::string& path)
245  {
246  Json::ObjectRequirement validator;
247  Json::Value schema;
248  Json::CharReaderBuilder rbuilder;
249  Json::CharReader* reader = rbuilder.newCharReader();
250 
251  reader->parse(JsonSchema::RMSDCV.c_str(),
252  JsonSchema::RMSDCV.c_str() + JsonSchema::RMSDCV.size(),
253  &schema, NULL);
254  validator.Parse(schema, path);
255 
256  //Validate inputs
257  validator.Validate(json, path);
258  if(validator.HasErrors())
259  throw BuildException(validator.GetErrors());
260 
261  std::vector<int> atom_ids;
262  for(auto& s : json["atom_ids"])
263  atom_ids.push_back(s.asInt());
264  auto reference = json["reference"].asString();
265  auto use_range = json.get("use_range",false).asBool();
266 
267  return new RMSDCV(atom_ids, reference, use_range);
268  }
269  };
270 }
Requirements on an object.
virtual void Parse(Value json, const std::string &path) override
Parse JSON value to generate Requirement(s).
virtual void Validate(const Value &json, const std::string &path) override
Validate JSON value.
std::vector< std::string > GetErrors()
Get list of error messages.
Definition: Requirement.h:92
bool HasErrors()
Check if errors have occured.
Definition: Requirement.h:86
Exception to be thrown when building the Driver fails.
Abstract class for a collective variable.
std::vector< Vector3 > grad_
Gradient vector dCv/dxi.
double val_
Current value of CV.
Collective variable to calculate root mean square displacement.
Definition: RMSDCV.h:43
std::string xyzfile_
Name of model structure.
Definition: RMSDCV.h:49
void Initialize(const Snapshot &snapshot) override
Initialize necessary variables.
Definition: RMSDCV.h:99
Label atomids_
IDs of the atoms used for RMSD calculation.
Definition: RMSDCV.h:46
RMSDCV(const Label &atomids, std::string xyzfile, bool use_range=false)
Constructor.
Definition: RMSDCV.h:68
static RMSDCV * Build(const Json::Value &json, const std::string &path)
Set up collective variable.
Definition: RMSDCV.h:244
std::vector< Vector3 > refcoord_
Store reference structure coordinates.
Definition: RMSDCV.h:52
Vector3 COMref_
Center of mass of reference.
Definition: RMSDCV.h:55
void Evaluate(const Snapshot &snapshot) override
Evaluate the CV.
Definition: RMSDCV.h:162
static std::vector< std::array< double, 4 > > ReadXYZ(std::string FileName)
Read xyz file.
Definition: ReadFile.h:66
Class containing a snapshot of the current simulation in time.
Definition: Snapshot.h:48
unsigned GetNumAtoms() const
Get number of atoms in this snapshot.
Definition: Snapshot.h:202
void GetLocalIndices(const Label &ids, Label *indices) const
Definition: Snapshot.h:537
const mxx::comm & GetCommunicator() const
Get communicator for walker.
Definition: Snapshot.h:186
int GetLocalIndex(int id) const
Gets the local atom index corresponding to an atom ID.
Definition: Snapshot.h:519
double TotalMass(const Label &indices) const
Compute the total mass of a group of particles based on index.
Definition: Snapshot.h:423
const std::vector< Vector3 > & GetPositions() const
Access the particle positions.
Definition: Snapshot.h:325
const std::vector< double > & GetMasses() const
Const access to the particle masses.
Definition: Snapshot.h:367
Vector3 CenterOfMass(const Label &indices, bool mass_weight=true) const
Compute center of mass of a group of atoms based on index.
Definition: Snapshot.h:442
void ApplyMinimumImage(Vector3 *v) const
Apply minimum image to a vector.
Definition: Snapshot.h:390
Eigen::Matrix3d Matrix3
3x3 matrix.
Definition: types.h:42
Eigen::Vector3d Vector3
Three-dimensional vector.
Definition: types.h:33
std::vector< int > Label
List of integers.
Definition: types.h:48