Simpatico  v1.10
McNVTChemicalPotential.cpp
1 /*
2 * Simpatico - Simulation Package for Polymeric and Molecular Liquids
3 *
4 * Copyright 2010 - 2017, The Regents of the University of Minnesota
5 * Distributed under the terms of the GNU General Public License.
6 */
7 
8 #include "McNVTChemicalPotential.h" // class header
9 #include <util/misc/FileMaster.h>
10 #include <util/archives/Serializable_includes.h>
11 
12 #include <mcMd/mcSimulation/McSystem.h>
13 #include <mcMd/mcMoves/SystemMove.h>
15 
16 #include <simp/boundary/Boundary.h>
17 #include <simp/species/Species.h>
18 
19 #include <mcMd/chemistry/Molecule.h>
20 #include <mcMd/chemistry/Bond.h>
21 #include <mcMd/chemistry/Atom.h>
22 #include <util/space/Vector.h>
23 #include <util/space/Tensor.h>
24 #include <util/global.h>
25 
26 #include <math.h>
27 #include <cstdio>
28 
29 namespace McMd
30 {
31 
32  using namespace Util;
33  using namespace Simp;
34 
35  /*
36  * Constructor.
37  */
39  : SystemAnalyzer<McSystem>(system),
40  systemPtr_(&system),
41  simulationPtr_(&system.simulation()),
42  boundaryPtr_(&system.boundary()),
43  energyEnsemblePtr_(&system.energyEnsemble()),
44  randomPtr_(&system.simulation().random()),
45  outputFile_(),
46  accumulator_(),
47  nTrial_(-1),
48  nMoleculeTrial_(-1),
49  nSamplePerBlock_(1),
50  isInitialized_(false)
51  {}
52 
53 
54  /*
55  * Read parameters and initialize.
56  */
58  {
59 
60  readInterval(in);
62  read<int>(in,"nSamplePerBlock", nSamplePerBlock_);
63  read<int>(in, "nTrial", nTrial_);
64  read<int>(in, "nMoleculeTrial", nMoleculeTrial_);
65  read<int>(in, "speciesId", speciesId_);
66  accumulator_.setNSamplePerBlock(nSamplePerBlock_);
67 
68  read<double>(in, "Emin", Emin_);
69  read<double>(in, "Emax", Emax_);
70  read<double>(in, "EnBin", EnBin_);
71  Eaccumulator_.setParam(Emin_, Emax_, EnBin_);
72  Eaccumulator_.clear();
73  read<double>(in, "Ecmin", Ecmin_);
74  read<double>(in, "Ecmax", Ecmax_);
75  read<double>(in, "EcnBin", EcnBin_);
76  Ecaccumulator_.setParam(Ecmin_, Ecmax_, EcnBin_);
77  Ecaccumulator_.clear();
78  read<double>(in, "Emmin", Emmin_);
79  read<double>(in, "Emmax", Emmax_);
80  read<double>(in, "EmnBin", EmnBin_);
81  Emaccumulator_.setParam(Emmin_, Emmax_, EmnBin_);
82  Emaccumulator_.clear();
83  read<double>(in, "BRmin", BRmin_);
84  read<double>(in, "BRmax", BRmax_);
85  read<double>(in, "BRnBin", BRnBin_);
86  BRaccumulator_.setParam(BRmin_, BRmax_, BRnBin_);
87  BRaccumulator_.clear();
88 
89  // If nSamplePerBlock != 0, open an output file for block averages.
90  if (accumulator_.nSamplePerBlock()) {
91  fileMaster().openOutputFile(outputFileName(".dat"), outputFile_);
92  }
93 
94  if (nTrial_ <=0 || nTrial_ > MaxTrial_) {
95  UTIL_THROW("Invalid value input for nTrial");
96  }
97 
98  if (nMoleculeTrial_ <=0) {
99  UTIL_THROW("Invalid value input for nMoleculeTrial");
100  }
101 
102  if (speciesId_ <0 || speciesId_ >= system().simulation().nSpecies()) {
103  UTIL_THROW("Invalid value input for speciesId");
104  }
105 
106  isInitialized_ = true;
107 
108  }
109 
110  /*
111  * Clear accumulator.
112  */
114  { accumulator_.clear(); }
115 
116  /*
117  * Evaluate Rosenbluth weight, and add to accumulator.
118  */
120  {
121  if (isAtInterval(iStep)) {
122 
123  Molecule* molPtr;
124  Atom* endPtr, *pvt1Ptr;
125  Vector trialPos[MaxTrial_], bondVec, pvt1Pos;
126  #ifdef SIMP_ANGLE
127  double angle;
128  Atom* pvt2Ptr;
129  Vector pvt2Pos;
130  #endif
131  double beta, length;
132  // Rosenbluth factor and energy of inserted bonds at each stage.
133  double w = 0, de = 0;
134  // Total rosenbluth factor and energy of inserted polymer.
135  double rosenbluth = 1, energy = 0;
136  double trialProb[MaxTrial_], trialEnergy[MaxTrial_];
137  int iTrial;
138 
139  beta = energyEnsemble().beta();
140  molPtr = &(simulation().getMolecule(speciesId_));
141  system().addMolecule(*molPtr);
142 
143  // Main molecule inserting loop:
144  for (int i = 0; i < nMoleculeTrial_; i++) {
145 
146  // Inserting the first atom.
147  endPtr = &molPtr->atom(0);
148  for (iTrial = 0; iTrial < nTrial_; ++iTrial) {
149  // trialPos = pvtPos + bondVec
150  boundary().randomPosition(random(), trialPos[iTrial]);
151  boundary().shift(trialPos[iTrial]);
152 
153  #ifndef SIMP_NOPAIR
154  trialEnergy[iTrial] =
155  system().pairPotential().atomEnergy(*endPtr);
156  #else
157  trialEnergy[iTrial] = 0.0;
158  #endif
159 
160  #ifdef SIMP_EXTERNAL
161  trialEnergy[iTrial] +=
162  system().externalPotential().atomEnergy(*endPtr);
163  #endif
164 
165  trialProb[iTrial] = boltzmann(trialEnergy[iTrial]);
166  w += trialProb[iTrial];
167  }
168 
169  // Normalize trial probabilities
170  for (iTrial = 0; iTrial < nTrial_; ++iTrial) {
171  trialProb[iTrial] = trialProb[iTrial]/rosenbluth;
172  }
173 
174  // Choose trial position
175  iTrial = random().drawFrom(trialProb, nTrial_);
176 
177  // Calculate total energy for chosen trial
178  de = trialEnergy[iTrial];
179 
180  // Set position of new end atom to chosen trialPos Vector
181  endPtr->position() = trialPos[iTrial];
182 
183  #ifndef SIMP_NOPAIR
184  system().pairPotential().addAtom(*endPtr);
185  #endif
186 
187  rosenbluth *= w;
188  energy += de;
189 
190  // Inserting the second atom.
191  int bondTypeId = molPtr->bond(0).typeId();
192  length = system().bondPotential().randomBondLength(&random(),
193  beta,
194  bondTypeId);
195 
196  w = 0;
197  de = 0;
198 
199  pvt1Ptr = &molPtr->atom(0);
200  endPtr = &molPtr->atom(1);
201 
202  pvt1Pos = pvt1Ptr->position();
203 
204  for (iTrial = 0; iTrial < nTrial_; ++iTrial) {
205  // trialPos = pvtPos + bondVec
206  random().unitVector(bondVec);
207  bondVec *= length;
208  // trialPos = pvtPos + bondVec
209  trialPos[iTrial].add(pvt1Pos, bondVec);
210  boundary().shift(trialPos[iTrial]);
211  endPtr->position() = trialPos[iTrial];
212 
213  #ifndef SIMP_NOPAIR
214  trialEnergy[iTrial] =
215  system().pairPotential().atomEnergy(*endPtr);
216  #else
217  trialEnergy[iTrial] = 0.0;
218  #endif
219 
220  #ifdef SIMP_EXTERNAL
221  trialEnergy[iTrial] +=
222  system().externalPotential().atomEnergy(*endPtr);
223  #endif
224 
225  trialProb[iTrial] = boltzmann(trialEnergy[iTrial]);
226  w += trialProb[iTrial];
227  }
228 
229  // Normalize trial probabilities
230  for (iTrial = 0; iTrial < nTrial_; ++iTrial) {
231  trialProb[iTrial] = trialProb[iTrial]/rosenbluth;
232  }
233 
234  // Choose trial position
235  iTrial = random().drawFrom(trialProb, nTrial_);
236 
237  // Fetch nonbonded energy for chosen trial
238  de = trialEnergy[iTrial];
239 
240  // Add bond energy
241  de += system().bondPotential().energy(length*length, bondTypeId);
242 
243  // Set position of new end atom to chosen trialPos Vector
244  endPtr->position() = trialPos[iTrial];
245 
246  #ifndef SIMP_NOPAIR
247  system().pairPotential().addAtom(*endPtr);
248  #endif
249 
250  rosenbluth *= w;
251  energy += de;
252 
253  // Inserting the third atom.
254  bondTypeId = molPtr->bond(1).typeId();
255  length =
256  system().bondPotential().randomBondLength(&random(),
257  beta, bondTypeId);
258 
259  #ifdef SIMP_ANGLE
260  int angleTypeId = molPtr->angle(0).typeId();
261  angle =
262  system().anglePotential().randomAngle(&random(),
263  beta, angleTypeId);
264  pvt2Ptr = &molPtr->atom(0);
265  pvt2Pos = pvt2Ptr->position();
266  Vector n = pvt1Pos;
267  n -= pvt2Pos;
268  #endif
269 
270  w = 0;
271  de = 0;
272  pvt1Ptr = &molPtr->atom(1);
273  pvt1Pos = pvt1Ptr->position();
274  endPtr = &molPtr->atom(2);
275 
276  for (iTrial = 0; iTrial < nTrial_; ++iTrial) {
277  // trialPos = pvtPos + bondVec
278  #ifdef SIMP_ANGLE
279  if (system().hasAnglePotential()) {
280  uniformCone(length, angle, n, bondVec);
281  } else {
282  random().unitVector(bondVec);
283  bondVec *= length;
284  }
285  #else
286  random().unitVector(bondVec);
287  bondVec *= length;
288  #endif
289 
290  // trialPos = pvtPos + bondVec
291  trialPos[iTrial].add(pvt1Pos, bondVec);
292  boundary().shift(trialPos[iTrial]);
293  endPtr->position() = trialPos[iTrial];
294 
295  #ifndef SIMP_NOPAIR
296  trialEnergy[iTrial] =
297  system().pairPotential().atomEnergy(*endPtr);
298  #else
299  trialEnergy[iTrial] = 0.0;
300  #endif
301 
302  #ifdef SIMP_EXTERNAL
303  trialEnergy[iTrial] +=
304  system().externalPotential().atomEnergy(*endPtr);
305  #endif
306 
307  trialProb[iTrial] = boltzmann(trialEnergy[iTrial]);
308  w += trialProb[iTrial];
309  }
310  // Normalize trial probabilities
311  for (iTrial = 0; iTrial < nTrial_; ++iTrial) {
312  trialProb[iTrial] = trialProb[iTrial]/rosenbluth;
313  }
314 
315  // Choose trial position
316  iTrial = random().drawFrom(trialProb, nTrial_);
317 
318  // Get nonbonded energy for chosen trial
319  de = trialEnergy[iTrial];
320 
321  // Add bonded energies
322  de += system().bondPotential().energy(length*length, bondTypeId);
323  #ifdef SIMP_ANGLE
324  de += system().anglePotential().energy(cos(angle), angleTypeId);
325  #endif
326 
327  // Set position of new end atom to chosen trialPos Vector
328  endPtr->position() = trialPos[iTrial];
329 
330  #ifndef SIMP_NOPAIR
331  system().pairPotential().addAtom(*endPtr);
332  #endif
333 
334  rosenbluth *= w;
335  energy += de;
336 
337  for (int atomId = 3; atomId < molPtr->nAtom(); ++atomId) {
338  addEndAtom(molPtr, atomId, w, de);
339  rosenbluth *= w;
340  energy += de;
341  #ifndef SIMP_NOPAIR
342  system().pairPotential().addAtom(molPtr->atom(atomId));
343  #endif
344  }
345 
346  rosenbluth = rosenbluth / pow(nTrial_,molPtr->nAtom());
347  accumulator_.sample(rosenbluth, outputFile_);
348 
349  #ifndef SIMP_NOPAIR
350  for (int atomId = 0; atomId < molPtr->nAtom(); ++atomId) {
351  system().pairPotential().deleteAtom(molPtr->atom(atomId));
352  }
353  #endif
354  }
355 
356  system().removeMolecule(*molPtr);
357  simulation().returnMolecule(*molPtr);
358 
359  }
360  }
361 
362  /*
363  * Output results to file after simulation is completed.
364  */
366  {
367  // If outputFile_ was used to write block averages, close it.
368  if (accumulator_.nSamplePerBlock()) {
369  outputFile_.close();
370  }
371 
372  fileMaster().openOutputFile(outputFileName(".prm"), outputFile_);
373  writeParam(outputFile_);
374  outputFile_.close();
375 
376  fileMaster().openOutputFile(outputFileName(".ave"), outputFile_);
377  accumulator_.output(outputFile_);
378  outputFile_.close();
379 
380  fileMaster().openOutputFile(outputFileName(".e"), outputFile_);
381  Eaccumulator_.output(outputFile_);
382  outputFile_.close();
383 
384  fileMaster().openOutputFile(outputFileName(".ec"), outputFile_);
385  Ecaccumulator_.output(outputFile_);
386  outputFile_.close();
387 
388  fileMaster().openOutputFile(outputFileName(".emin"), outputFile_);
389  Emaccumulator_.output(outputFile_);
390  outputFile_.close();
391 
392  fileMaster().openOutputFile(outputFileName(".br"), outputFile_);
393  BRaccumulator_.output(outputFile_);
394  outputFile_.close();
395  }
396 
397  /*
398  * Save state to binary file archive.
399  */
401  { ar & *this; }
402 
403  /*
404  * Load state from a binary file archive.
405  */
407  { ar & *this; }
408 
409 
410  /*
411  * Configuration bias algorithm for adding one atom to a chain end.
412  */
413  void
414  McNVTChemicalPotential::addEndAtom(Molecule* molPtr,
415  int atomId, double &rosenbluth,
416  double &energy)
417  {
418  Atom* endPtr = &molPtr->atom(atomId);
419  Vector trialPos[MaxTrial_];
420  Vector bondVec;
421  Vector pvt1Pos = molPtr->atom(atomId-1).position();
422 
423  #ifdef SIMP_ANGLE
424  Vector pvt2Pos = molPtr->atom(atomId-2).position();
425  #endif
426 
427  #ifdef SIMP_DIHEDRAL
428  Vector pvt3Pos = molPtr->atom(atomId-3).position();
429  #endif
430 
431  double trialProb[MaxTrial_], trialEnergy[MaxTrial_];
432  double beta, length;
433  int bondTypeId = molPtr->bond(atomId - 1).typeId();
434 
435  #ifdef SIMP_ANGLE
436  double angle;
437  int angleTypeId = molPtr->angle(atomId - 2).typeId();
438  #endif
439 
440  int iTrial;
441  double eMin = 0;
442 
443  // Generate a random bond-length and bond-angle.
444  beta = energyEnsemble().beta();
445  length = system().bondPotential().randomBondLength(&random(), beta,
446  molPtr->bond(atomId-1).typeId());
447  #ifdef SIMP_ANGLE
448  Vector n = pvt1Pos;
449  n -= pvt2Pos;
450  angle = system().anglePotential().randomAngle(&random(), beta,
451  molPtr->angle(atomId-2).typeId());
452  #endif
453  #ifdef SIMP_DIHEDRAL
454  Vector dR1 = pvt3Pos;
455  Vector dR2 = pvt2Pos;
456  Vector dR3 = pvt1Pos;
457  dR1 -= pvt2Pos;
458  dR2 -= pvt1Pos;
459  dR3 -= endPtr->position();
460  #endif
461 
462  // Loop over nTrial trial positions:
463  rosenbluth = 0.0;
464  for (iTrial=0; iTrial < nTrial_; ++iTrial) {
465 
466  #ifdef SIMP_ANGLE
467  if (system().hasAnglePotential()) {
468  uniformCone(length, angle, n, bondVec);
469  } else {
470  random().unitVector(bondVec);
471  bondVec *= length;
472  }
473  #else
474  random().unitVector(bondVec);
475  bondVec *= length;
476  #endif
477 
478  trialPos[iTrial].add(pvt1Pos, bondVec);
479  boundary().shift(trialPos[iTrial]);
480  endPtr->position() = trialPos[iTrial];
481 
482  #ifndef SIMP_NOPAIR
483  trialEnergy[iTrial] = system().pairPotential().atomEnergy(*endPtr);
484  #else
485  trialEnergy[iTrial] = 0.0;
486  #endif
487 
488  #ifdef SIMP_DIHEDRAL
489  if (system().hasDihedralPotential()) {
490  trialEnergy[iTrial] +=
491  system().dihedralPotential().energy(dR1, dR2, dR3,
492  molPtr->dihedral(atomId-3).typeId());
493  }
494  #endif
495 
496  #ifdef SIMP_EXTERNAL
497  trialEnergy[iTrial] +=
498  system().externalPotential().atomEnergy(*endPtr);
499  #endif
500 
501  // Finding the Minimum of the trialEnergy vector
502  if (eMin > trialEnergy[iTrial])
503  eMin = trialEnergy[iTrial];
504  Eaccumulator_.sample(trialEnergy[iTrial]);
505 
506  trialProb[iTrial] = boltzmann(trialEnergy[iTrial]);
507  rosenbluth += trialProb[iTrial];
508  }
509 
510  Emaccumulator_.sample(eMin);
511  BRaccumulator_.sample(rosenbluth);
512  // Normalize trial probabilities
513  for (iTrial = 0; iTrial < nTrial_; ++iTrial) {
514  trialProb[iTrial] = trialProb[iTrial]/rosenbluth;
515  }
516 
517  // Choose trial position
518  iTrial = random().drawFrom(trialProb, nTrial_);
519 
520  // Calculate total energy for chosen trial.
521  energy = system().bondPotential().energy(length*length, bondTypeId);
522  #ifdef SIMP_ANGLE
523  energy += system().anglePotential().energy(cos(angle), angleTypeId);
524  #endif
525 
526  energy += trialEnergy[iTrial];
527  Ecaccumulator_.sample(energy);
528 
529  // Set position of new end atom to chosen value
530  endPtr->position() = trialPos[iTrial];
531  }
532 
533  /*
534  * Finding a vector which make an angle \theta with vector n and has length b.
535  */
536  void McNVTChemicalPotential::uniformCone(const double length,
537  const double angle,
538  const Vector n, Vector &p)
539  {
540  Vector v1;
541 
542  do {
543  random().unitVector(p);
544  v1.divide(n,n.abs());
545  v1.multiply(v1,p.projection(v1));
546  p -= v1;
547  } while (p.abs() > 1.0E-8);
548 
549  v1.divide(n,n.abs());
550  v1 *= length*cos(angle);
551  p /= p.abs();
552  p *= length*sin(angle);
553  p += (v1);
554  }
555 
556 }
virtual void readParameters(std::istream &in)
Read parameters and initialize.
Bond & bond(int localId)
Get a specific Bond in this Molecule by non-const reference.
void clear()
Clear all accumulators, set to empty initial state.
Definition: Average.cpp:42
A System for use in a Markov chain Monte Carlo simulation.
Definition: McSystem.h:52
A Vector is a Cartesian vector.
Definition: Vector.h:75
virtual double atomEnergy(const Atom &atom) const =0
Calculate the external energy for one Atom.
Vector & divide(const Vector &v, double s)
Divide vector v by scalar s.
Definition: Vector.h:700
Vector & add(const Vector &v1, const Vector &v2)
Add vectors v1 and v2.
Definition: Vector.h:657
Include this file to include all MC potential energy classes at once.
BondPotential & bondPotential() const
Return the BondPotential by reference.
Definition: McSystem.h:405
Dihedral & dihedral(int localId)
Get a specific Dihedral in this Molecule by reference.
void randomPosition(Random &random, Vector &r) const
Generate random position within the primary unit cell.
Vector & multiply(const Vector &v, double s)
Multiply a vector v by a scalar s.
Definition: Vector.h:686
void addAtom(Atom &atom)
Add an Atom to the CellList.
void openOutputFile(const std::string &filename, std::ofstream &out, std::ios_base::openmode mode=std::ios_base::out) const
Open an output file.
Definition: FileMaster.cpp:290
int typeId() const
Get the typeId for this covalent group.
virtual void save(Serializable::OArchive &ar)
Save state to binary file archive.
File containing preprocessor macros for error handling.
Classes used by all simpatico molecular simulations.
void readOutputFileName(std::istream &in)
Read outputFileName from file.
long drawFrom(double probability[], long size)
Choose one of several outcomes with a specified set of probabilities.
Definition: Random.h:237
Molecule & getMolecule(int speciesId)
Get a new molecule from a reservoir of unused Molecule objects.
virtual void output()
Output results at end of simulation.
void returnMolecule(Molecule &molecule)
Return a molecule to a reservoir of unused molecules.
Saving / output archive for binary ostream.
virtual double energy(const Vector &R1, const Vector &R2, const Vector &R3, int type) const =0
Returns potential energy for one dihedral.
double beta() const
Return the inverse temperature.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
virtual double randomAngle(Util::Random *random, double beta, int type) const =0
Return bond angle chosen from equilibrium distribution.
virtual void load(Serializable::IArchive &ar)
Load state from a binary file archive.
void addMolecule(Molecule &molecule)
Add a Molecule to this System.
Definition: System.cpp:1111
virtual void writeParam(std::ostream &out)
Write all parameters to an output stream.
ExternalPotential & externalPotential() const
Return ExternalPotential by reference.
Definition: McSystem.h:473
void readInterval(std::istream &in)
Read interval from file, with error checking.
A point particle within a Molecule.
Utility classes for scientific computation.
Definition: accumulators.mod:1
McNVTChemicalPotential(McSystem &system)
Constructor.
void sample(double value)
Sample a value.
void shift(Vector &r) const
Shift Cartesian Vector r to its primary image.
Template for Analyzer associated with one System.
void output(std::ostream &out) const
Output final statistical properties to file.
Definition: Average.cpp:178
void output(std::ostream &out)
Output the distribution to file.
McPairPotential & pairPotential() const
Return the McPairPotential by reference.
Definition: McSystem.h:388
virtual double energy(double cosTheta, int type) const =0
Returns potential energy for one angle.
virtual double energy(double rSq, int type) const =0
Returns potential energy for one bond.
void setNSamplePerBlock(int nSamplePerBlock)
Set nSamplePerBlock.
Definition: Average.cpp:63
virtual void clear()
Clear (i.e., zero) previously allocated histogram.
Saving archive for binary istream.
void sample(double value)
Add a sampled value to the ensemble.
Definition: Average.cpp:94
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
virtual void setup()
Clear accumulator.
double abs() const
Return absolute magnitude of this vector.
Definition: Vector.h:625
int nSamplePerBlock() const
Get number of samples per block average.
Definition: Average.h:220
const Atom & atom(int localId) const
Get a specific Atom in this Molecule.
FileMaster & fileMaster()
Get the FileMaster by reference.
bool isAtInterval(long counter) const
Return true iff counter is a multiple of the interval.
AnglePotential & anglePotential() const
Return AnglePotential by reference.
Definition: McSystem.h:422
const std::string & outputFileName() const
Return outputFileName string.
double projection(const Vector &p) const
Return projection of this vector along vector p.
Definition: Vector.h:641
void setParam(double min, double max, int nBin)
Set parameters and initialize.
A physical molecule (a set of covalently bonded Atoms).
void removeMolecule(Molecule &molecule)
Remove a specific molecule from this System.
Definition: System.cpp:1129
const Vector & position() const
Get the position Vector by const reference.
virtual double randomBondLength(Util::Random *random, double beta, int type) const =0
Return bond length chosen from equilibrium distribution.
Angle & angle(int localId)
Get a specific Angle in this Molecule by non-const reference.
void deleteAtom(Atom &atom)
Remove an Atom from the CellList.
virtual void sample(long iStep)
Evaluate energy per particle, and add to ensemble.
int nAtom() const
Get the number of Atoms in this Molecule.
virtual double atomEnergy(const Atom &atom) const =0
Calculate the nonbonded pair energy for one Atom.
void unitVector(Vector &v)
Generate unit vector with uniform probability over the unit sphere.
Definition: Random.cpp:122
DihedralPotential & dihedralPotential() const
Return the DihedralPotential by reference.
Definition: McSystem.h:439