SSAGES  0.1
A MetaDynamics Package
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Groups Pages
PairwiseCV.h
1 
21 #pragma once
22 
23 #include "CVs/CollectiveVariable.h"
24 #include "Validator/ObjectRequirement.h"
25 #include "Drivers/DriverException.h"
26 #include "Utility/PairwiseKernel.h"
27 #include "Snapshot.h"
28 #include "schema.h"
29 
30 namespace SSAGES
31 {
33 
41  {
42  private:
46 
47  public:
49 
56  PairwiseCV(const Label& group1, const Label& group2, PairwiseKernel* pk) :
57  group1_(group1), group2_(group2), pk_(pk)
58  {
59  }
60 
62 
65  void Initialize(const Snapshot& snapshot) override
66  {
67  using std::to_string;
68 
69  auto n1 = group1_.size(), n2 = group2_.size();
70 
71  // Make sure atom ID's are on at least one processor.
72  std::vector<int> found1(n1, 0), found2(n2, 0);
73  for(size_t i = 0; i < n1; ++i)
74  {
75  if(snapshot.GetLocalIndex(group1_[i]) != -1)
76  found1[i] = 1;
77  }
78 
79  for(size_t i = 0; i < n2; ++i)
80  {
81  if(snapshot.GetLocalIndex(group2_[i]) != -1)
82  found2[i] = 1;
83  }
84 
85  MPI_Allreduce(MPI_IN_PLACE, found1.data(), n1, MPI_INT, MPI_SUM, snapshot.GetCommunicator());
86  MPI_Allreduce(MPI_IN_PLACE, found2.data(), n2, MPI_INT, MPI_SUM, snapshot.GetCommunicator());
87 
88  unsigned ntot1 = std::accumulate(found1.begin(), found1.end(), 0, std::plus<int>());
89  unsigned ntot2 = std::accumulate(found2.begin(), found2.end(), 0, std::plus<int>());
90  if(ntot1 != n1)
91  throw BuildException({
92  "PairwiseCV: Expected to find " +
93  to_string(n1) +
94  " atoms in group 1, but only found " +
95  to_string(ntot1) + "."
96  });
97 
98  if(ntot2 != n2)
99  throw BuildException({
100  "PairwiseCV: Expected to find " +
101  to_string(n2) +
102  " atoms in group 2, but only found " +
103  to_string(ntot2) + "."
104  });
105  }
106 
108 
111  void Evaluate(const Snapshot& snapshot) override
112  {
113  // Get local atom indices.
114  std::vector<int> idx1, idx2;
115  snapshot.GetLocalIndices(group1_, &idx1);
116  snapshot.GetLocalIndices(group2_, &idx2);
117 
118  // Get data from snapshot.
119  auto n = snapshot.GetNumAtoms();
120  auto& atomids = snapshot.GetAtomIDs();
121  auto& positions = snapshot.GetPositions();
122  auto& comm = snapshot.GetCommunicator();
123 
124  // Initialize gradient.
125  std::fill(grad_.begin(), grad_.end(), Vector3{0,0,0});
126  grad_.resize(n, Vector3{0,0,0});
127  boxgrad_ = Matrix3::Zero();
128 
129  // Fill eigen matrix with coordinate data.
130  std::vector<double> pos1(3*idx1.size()), pos2(3*idx2.size());
131  std::vector<int> id1(idx1.size()), id2(idx2.size());
132  for(size_t i = 0; i < idx1.size(); ++i)
133  {
134  pos1[3*i+0] = positions[idx1[i]][0];
135  pos1[3*i+1] = positions[idx1[i]][1];
136  pos1[3*i+2] = positions[idx1[i]][2];
137 
138  id1[i] = atomids[idx1[i]];
139  }
140 
141  for(size_t i = 0; i < idx2.size(); ++i)
142  {
143  pos2[3*i+0] = positions[idx2[i]][0];
144  pos2[3*i+1] = positions[idx2[i]][1];
145  pos2[3*i+2] = positions[idx2[i]][2];
146 
147  id2[i] = atomids[idx2[i]];
148  }
149 
150  // Gather across all procs.
151  pos1 = mxx::allgatherv(pos1.data(), pos1.size(), comm);
152  pos2 = mxx::allgatherv(pos2.data(), pos2.size(), comm);
153  id1 = mxx::allgatherv(id1.data(), id1.size(), comm);
154  id2 = mxx::allgatherv(id2.data(), id2.size(), comm);
155 
156  // Create Eigen map for ease of use.
157  using Map = Eigen::Map<Eigen::Matrix<double, Eigen::Dynamic, 3, Eigen::RowMajor>>;
158  Map gpos1(pos1.data(), group1_.size(), 3), gpos2(pos2.data(), group2_.size(), 3);
159 
160  val_ = 0;
161  double df = 0.;
162  // Compute gradient and value.
163  for(size_t i = 0; i < group1_.size(); ++i)
164  {
165  auto t1 = id1[i];
166  const auto& pi = gpos1.row(i);
167  for(size_t j = 0; j < group2_.size(); ++j)
168  {
169  auto t2 = id2[j];
170  const auto& pj = gpos2.row(j);
171 
172  // Skip identical pairs.
173  if(t1 == t2)
174  continue;
175 
176  // Compute distance and pairwise function.
177  Vector3 rij = pi - pj;
178  snapshot.ApplyMinimumImage(&rij);
179  auto r = rij.norm();
180  val_ += pk_->Evaluate(r, df);
181 
182  // Get local indices and sum gradients.
183  auto lid1 = snapshot.GetLocalIndex(t1);
184  if(lid1 != -1)
185  grad_[lid1] += df*rij/r;
186 
187  auto lid2 = snapshot.GetLocalIndex(t2);
188  if(lid2 != -1)
189  grad_[lid2] -= df*rij/r;
190 
191  // Only sum box gradient on a single proc.
192  if(comm.rank() == 0)
193  boxgrad_ += df*rij/r*rij.transpose();
194  }
195  }
196  }
197 
198  static PairwiseCV* Build(const Json::Value& json, const std::string& path)
199  {
200  Json::ObjectRequirement validator;
201  Json::Value schema;
202  Json::Reader reader;
203 
204  reader.parse(JsonSchema::PairwiseCV, schema);
205  validator.Parse(schema, path);
206 
207  // Validate inputs.
208  validator.Validate(json, path);
209  if(validator.HasErrors())
210  throw BuildException(validator.GetErrors());
211 
212  std::vector<int> group1, group2;
213 
214  for(auto& s : json["group1"])
215  group1.push_back(s.asInt());
216 
217  for(auto& s : json["group2"])
218  group2.push_back(s.asInt());
219 
220  return new PairwiseCV(group1, group2, PairwiseKernel::Build(json["kernel"], path));
221  }
222 
223  ~PairwiseCV()
224  {
225  delete pk_;
226  /*
227  * deleting object of abstract class type ‘SSAGES::PairwiseKernel’
228  * which has non-virtual destructor will cause undefined behaviour
229  * [-Wdelete-non-virtual-dtor]
230  *
231  */
232  }
233  };
234 }
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
Class containing a snapshot of the current simulation in time.
Definition: Snapshot.h:43
Label group1_
IDs of the first group of atoms.
Definition: PairwiseCV.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
std::vector< Vector3 > grad_
Gradient vector dCv/dxi.
const mxx::comm & GetCommunicator() const
Get communicator for walker.
Definition: Snapshot.h:184
Map for histogram and coefficients.
Definition: BasisFunc.h:37
void GetLocalIndices(const Label &ids, Label *indices) const
Definition: Snapshot.h:573
Exception to be thrown when building the Driver fails.
virtual double Evaluate(double rij, double &df) const =0
Evaluate the pairwise kernel function.
const Label & GetAtomIDs() const
Access the atom IDs.
Definition: Snapshot.h:541
PairwiseCV(const Label &group1, const Label &group2, PairwiseKernel *pk)
Constructor.
Definition: PairwiseCV.h:56
std::vector< std::string > GetErrors()
Get list of error messages.
Definition: Requirement.h:92
void Initialize(const Snapshot &snapshot) override
Initialize necessary variables.
Definition: PairwiseCV.h:65
Requirements on an object.
Pairwise kernel base class.
void Evaluate(const Snapshot &snapshot) override
Evaluate the CV.
Definition: PairwiseCV.h:111
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.
Matrix3 boxgrad_
Gradient w.r.t box vectors dCv/dHij.
Generalized collective variable based on pairwise properties of atoms.
Definition: PairwiseCV.h:40
const std::vector< Vector3 > & GetPositions() const
Access the particle positions.
Definition: Snapshot.h:323
PairwiseKernel * pk_
Pairwise kernel function used for CV.
Definition: PairwiseCV.h:45
Label group2_
IDs of the second group of atoms.
Definition: PairwiseCV.h:44
virtual void Validate(const Value &json, const std::string &path) override
Validate JSON value.
static PairwiseKernel * Build(const Json::Value &json, const std::string &path)
Build PairwiseKernel from JSON value.