Simpatico  v1.10
CfbDoubleRebridgeMove.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 "CfbDoubleRebridgeMove.h"
9 #include <mcMd/mcSimulation/McSystem.h>
10 #include <mcMd/simulation/Simulation.h>
11 #ifndef SIMP_NOPAIR
12 #include <mcMd/potentials/pair/McPairPotential.h>
13 #endif
14 #include <mcMd/chemistry/Molecule.h>
15 #include <mcMd/chemistry/Bond.h>
16 #include <mcMd/chemistry/Atom.h>
17 
18 #include <simp/species/Linear.h>
19 #include <simp/boundary/Boundary.h>
20 
21 #include <util/global.h>
22 
23 namespace McMd
24 {
25 
26  using namespace Util;
27  using namespace Simp;
28 
29  /*
30  * Constructor
31  */
33  CfbRebridgeBase(system),
34  speciesId_(-1),
35  nRegrow_(-1),
36  bridgeLength_(0)
37  { setClassName("CfbDoubleRebridgeMove"); }
38 
39  /*
40  * Read parameters speciesId, nRegrow, and nTrial
41  */
42  void CfbDoubleRebridgeMove::readParameters(std::istream& in)
43  {
44  // Read parameters
45  readProbability(in);
46  read<int>(in, "speciesId", speciesId_);
47  read<int>(in, "nRegrow", nRegrow_);
48  read<double>(in, "bridgeLength", bridgeLength_);
49 
50  // Read parameters hold by RebridgeBase
52 
53  // Validate
54  Linear* chainPtr;
55  chainPtr = dynamic_cast<Linear*>(&(simulation().species(speciesId_)));
56  if (!chainPtr) {
57  UTIL_THROW("Not a Linear species");
58  }
59 
60  // Initialize tables for spring constants and normalizations.
61  setup();
62 
63  // Allocate array to store old positions
64  iOldPos_.allocate(nRegrow_);
65  jOldPos_.allocate(nRegrow_);
66  }
67 
68  /*
69  * Load state from archive.
70  */
72  {
73  // Read parameters
75  loadParameter<int>(ar, "speciesId", speciesId_);
76  loadParameter<int>(ar, "nRegrow", nRegrow_);
77  loadParameter<double>(ar, "bridgeLength", bridgeLength_);
79 
80  // Validate
81  Linear* chainPtr;
82  chainPtr = dynamic_cast<Linear*>(&(simulation().species(speciesId_)));
83  if (!chainPtr) {
84  UTIL_THROW("Species is not a subclass of Linear");
85  }
86 
87  // Initialize tables for spring constants and normalizations.
88  setup();
89 
90  // Allocate arrays to store old positions
91  iOldPos_.allocate(nRegrow_);
92  jOldPos_.allocate(nRegrow_);
93  }
94 
95  /*
96  * Save state to archive.
97  */
99  {
100  McMove::save(ar);
101  ar & speciesId_;
102  ar & nRegrow_;
103  ar & bridgeLength_;
105  }
106 
107 
108  /*
109  * Generate, attempt and accept or reject a Monte Carlo move.
110  *
111  * A complete move involve the following stepts:
112  *
113  * 1) choose a molecule-i randomly;
114  * 2) find molecule-j of the same type as i, and monomer pairs satisfying
115  * the distance criterion exist;
116  * 3) Delete the two rebridging monomers; first molecule-i, then -j.
117  * 4) Rebuild molecule-j, then -i. (in the JCP paper, the order is chosen
118  * at random.)
119  *
120  */
122  {
123  bool found, accept;
124  int iMol, jMol, sign, beginId, nEnd, i;
125  Molecule *iPtr; // pointer to i-th molecule
126  Molecule *jPtr; // pointer to j-th molecule
127  int *bonds; // bond types of a consequtive blocks of atoms
128  Atom *thisPtr; // pointer to the current end atom
129  Atom *tempPtr; // pointer used for swap atom positions
130  double rosenbluth, rosen_r, rosen_f;
131  double energy, energy_r, energy_f;
132  double po2n, pn2o;
133  Vector swapPos;
134 
136 
137  // Choose a random direction
138  if (random().uniform(0.0, 1.0) > 0.5)
139  sign = +1;
140  else
141  sign = -1;
142 
143  // Search for a pair of candidate sites and calculate probability
144  found = forwardScan(sign, iMol, jMol, beginId, po2n);
145  if (!found) return found;
146 
147  iPtr = &(system().molecule(speciesId_, iMol));
148  jPtr = &(system().molecule(speciesId_, jMol));
149 
150  // Save positions for atoms to be regrown
151  thisPtr = &(iPtr->atom(beginId));
152  tempPtr = &(jPtr->atom(beginId));
153  for (i = 0; i < nRegrow_; ++i) {
154  iOldPos_[i] = thisPtr->position();
155  jOldPos_[i] = tempPtr->position();
156 
157  thisPtr += sign;
158  tempPtr += sign;
159  }
160 
161  // Prepare for the rebridge move
162  accept = false;
163 
164  bonds = new int[nRegrow_ + 1];
165  if (sign == +1) {
166  for (i = 0; i < nRegrow_ + 1; ++i)
167  bonds[i] = iPtr->bond(beginId - 1 + nRegrow_ - i).typeId();
168  } else {
169  for (i = 0; i < nRegrow_ + 1; ++i)
170  bonds[i] = iPtr->bond(beginId - nRegrow_ + i).typeId();
171  }
172 
173  // Deleting atoms: first i-th molecule, then j-th
174  rosen_r = 1.0;
175  energy_r = 0.0;
176 
177  thisPtr = &(iPtr->atom(beginId + (nRegrow_-1)*sign));
178  deleteSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy);
179  rosen_r *= rosenbluth;
180  energy_r += energy;
181 
182  thisPtr = &(jPtr->atom(beginId + (nRegrow_-1)*sign));
183  deleteSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy);
184  rosen_r *= rosenbluth;
185  energy_r += energy;
186 
187  // Swap the atom positions of the dangling end
188  if (sign == +1)
189  nEnd = iPtr->nAtom() - beginId - nRegrow_;
190  else
191  nEnd = beginId + 1 - nRegrow_;
192 
193  thisPtr = &(iPtr->atom(beginId + nRegrow_*sign));
194  tempPtr = &(jPtr->atom(beginId + nRegrow_*sign));
195  for (i = 0; i < nEnd; ++i) {
196  swapPos = thisPtr->position();
197  //system().moveAtom(*thisPtr, tempPtr->position());
198  thisPtr->position() = tempPtr->position();
199  #ifndef SIMP_NOPAIR
200  system().pairPotential().updateAtomCell(*thisPtr);
201  #endif
202  //system().moveAtom(*tempPtr, swapPos);
203  tempPtr->position() = swapPos;
204  #ifndef SIMP_NOPAIR
205  system().pairPotential().updateAtomCell(*tempPtr);
206  #endif
207 
208  thisPtr += sign;
209  tempPtr += sign;
210  }
211 
212  // Regrow atoms: first j-th molecule, then i-th
213  rosen_f = 1.0;
214  energy_f = 0.0;
215 
216  thisPtr = &(jPtr->atom(beginId));
217  addSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy);
218  rosen_f *= rosenbluth;
219  energy_f += energy;
220 
221  thisPtr = &(iPtr->atom(beginId));
222  addSequence(nRegrow_, sign, thisPtr, bonds, rosenbluth, energy);
223  rosen_f *= rosenbluth;
224  energy_f += energy;
225 
226  // Reverse scan
227  found = reverseScan(sign, iMol, jMol, beginId - sign, pn2o);
228 
229  // Decide whether to accept or reject
230  if (found)
231  accept = random().metropolis(rosen_f * pn2o / rosen_r / po2n);
232  else
233  accept = false;
234 
235  if (accept) {
236 
237  // Increment counter for accepted moves of this class.
239 
240  } else {
241 
242  // If the move is rejected, restore nRegrow_ positions
243  thisPtr = &(iPtr->atom(beginId));
244  tempPtr = &(jPtr->atom(beginId));
245  for (i = 0; i < nRegrow_; ++i) {
246  //system().moveAtom(*thisPtr, iOldPos_[i]);
247  thisPtr->position() = iOldPos_[i];
248  #ifndef SIMP_NOPAIR
249  system().pairPotential().updateAtomCell(*thisPtr);
250  #endif
251  //system().moveAtom(*tempPtr, jOldPos_[i]);
252  tempPtr->position() = jOldPos_[i];
253  #ifndef SIMP_NOPAIR
254  system().pairPotential().updateAtomCell(*tempPtr);
255  #endif
256 
257  thisPtr += sign;
258  tempPtr += sign;
259  }
260 
261  // Restore atom positions at the dangling end
262  thisPtr = &(iPtr->atom(beginId + nRegrow_*sign));
263  tempPtr = &(jPtr->atom(beginId + nRegrow_*sign));
264  for (i = 0; i < nEnd; ++i) {
265  swapPos = thisPtr->position();
266  //system().moveAtom(*thisPtr, tempPtr->position());
267  thisPtr->position() = tempPtr->position();
268  #ifndef SIMP_NOPAIR
269  system().pairPotential().updateAtomCell(*thisPtr);
270  #endif
271  //system().moveAtom(*tempPtr, swapPos);
272  tempPtr->position() = swapPos;
273  #ifndef SIMP_NOPAIR
274  system().pairPotential().updateAtomCell(*tempPtr);
275  #endif
276 
277  thisPtr += sign;
278  tempPtr += sign;
279  }
280 
281  }
282 
283  // Release memory
284  delete [] bonds;
285 
286  return accept;
287  }
288 
289  /*
290  * Scanning chains to find all possible pairs of rebriding sites satisfying
291  * the distance criterion, then choose one randomly to commit the double
292  * rebridging move.
293  *
294  * probability = 1 / (number of pairs satisfying the distance criterion)
295  *
296  * rebriding criterion:
297  *
298  * distance(i1,j2) < bridgeLength
299  * && distance(i2,j1) < bridgeLength
300  *
301  * i1 i2
302  * -->------o-o-o---- i-chain
303  * \ /
304  * X
305  * / \
306  * -->------o-o-o---- j-chain
307  * j1 j2
308  *
309  *
310  */
311  bool CfbDoubleRebridgeMove::forwardScan(int sign, int &iMol,
312  int &jMol, int &beginId, double &prob)
313  {
314  Molecule *iPtr, *jPtr;
315  Vector iPos1, jPos1, iPos2, jPos2;
316  int nMol, nAtom, maxPair;
317  int signRegrow, nPairs, k, choice;
318  int *molBuf, *atomBuf;
319  double lengthSq, bridgeLengthSq;
320  bool found;
321 
322  // Number of molecules
323  nMol = system().nMolecule(speciesId_);
324 
325  // Randomly choose one molecule
326  iPtr = &(system().randomMolecule(speciesId_));
327  iMol = system().moleculeId(*iPtr);
328 
329  // Number of atoms per molecule
330  nAtom = iPtr->nAtom();
331 
332  // Require that chain length - 2 >= nRegrow_
333  if (nRegrow_ > nAtom - 2) {
334  UTIL_THROW("nRegrow_ >= chain length");
335  }
336 
337  // Allocate arrays holding candidate atom pairs
338  maxPair = (nMol - 1) * (nAtom - 1 - nRegrow_);
339  molBuf = new int[maxPair];
340  atomBuf = new int[maxPair];
341 
342  // Identify the direction of scaning
343  beginId = (sign == -1) ? (nAtom-1) : 0;
344 
345  // Auxiliary variables
346  signRegrow = sign * (nRegrow_ + 1);
347  bridgeLengthSq = bridgeLength_ * bridgeLength_;
348 
349  // Nullify counters
350  nPairs = 0;
351  found = false;
352 
353  // Loop over j molecules to scan possible pairs
354  for (jMol = 0; jMol < nMol; ++jMol) {
355 
356  jPtr = &(system().molecule(speciesId_, jMol));
357 
358  if (jMol != iMol) {
359 
360  for (k = 0; k < nAtom - 1 - nRegrow_; ++k) {
361 
362  // Check if i1 to j2 bridging is possible
363  iPos1 = iPtr->atom(beginId + k*sign).position();
364  jPos2 = jPtr->atom(beginId + signRegrow + k*sign).position();
365  lengthSq = boundary().distanceSq(iPos1, jPos2);
366 
367  if (lengthSq < bridgeLengthSq) {
368  // Check if j2 to i1 bridging is possible
369  jPos1 = jPtr->atom(beginId + k*sign).position();
370  iPos2 = iPtr->atom(beginId + signRegrow + k*sign).position();
371  lengthSq = boundary().distanceSq(iPos2, jPos1);
372 
373  if (lengthSq < bridgeLengthSq) {
374  molBuf[nPairs] = jMol;
375  atomBuf[nPairs] = beginId + k*sign;
376  nPairs += 1;
377  }
378  }
379 
380  } // loop over atom positions
381  } // if jMol != iMol
382  } // loop over j molecules
383 
384  if (nPairs > 0) found = true;
385 
386  if (found) {
387  // iMol is not changed after the random selection
388  choice = random().uniformInt(0, nPairs);
389  jMol = molBuf[choice];
390  beginId = atomBuf[choice] + sign; // return the the active atom ID
391  prob = 1.0 / double(nPairs);
392  } else {
393  iMol = -1; // invalid value
394  jMol = -1; // invalid value
395  beginId = -1; // invalid value
396  prob = 0.0;
397  }
398 
399  // Deallocate memory and quit
400  delete [] molBuf;
401  delete [] atomBuf;
402  return found;
403 
404  }
405 
406  /*
407  * Scanning chains to find the probability of choosing the specific reverse
408  * move.
409  * probability = 1 / (number of pairs satisfying the distance criterion)
410  *
411  * This method is different than the forward one in two aspects:
412  * (1) It first check if the old configuration is one possible reverse
413  * move; and return "0" probability if not.
414  * (2) It does not store the indices of possible monomer pairs and simply
415  * count the number of all possible bridging sites.
416  */
417  bool CfbDoubleRebridgeMove::reverseScan(int sign, int iMol,
418  int jMol, int beginId, double &prob)
419  {
420  Molecule *iPtr, *jPtr;
421  Vector iPos1, jPos1, iPos2, jPos2;
422  int nMol, nAtom, j;
423  int signRegrow, nPairs, headId, k;
424  double lengthSq, bridgeLengthSq;
425  bool found;
426 
427  // Retrieve molecule pointers
428  iPtr = &(system().molecule(speciesId_, iMol));
429  jPtr = &(system().molecule(speciesId_, jMol));
430 
431  // Number of molecules
432  nMol = system().nMolecule(speciesId_);
433 
434  // Number of atoms per molecule
435  nAtom = iPtr->nAtom();
436 
437  // Auxiliary variables
438  signRegrow = sign * (nRegrow_ + 1);
439  bridgeLengthSq = bridgeLength_ * bridgeLength_;
440 
441  // Initialize returning variable
442  found = false;
443 
444  // Check if i1 to j2 bridging is possible
445  iPos1 = iPtr->atom(beginId).position();
446  jPos2 = jPtr->atom(beginId + signRegrow).position();
447  lengthSq = boundary().distanceSq(iPos1, jPos2);
448 
449  if (lengthSq < bridgeLengthSq) {
450  // Check if j2 to i1 bridging is possible
451  jPos1 = jPtr->atom(beginId).position();
452  iPos2 = iPtr->atom(beginId + signRegrow).position();
453  lengthSq = boundary().distanceSq(iPos2, jPos1);
454 
455  if (lengthSq < bridgeLengthSq) {
456  found = true;
457  } else {
458  prob = 0.0;
459  return found;
460  }
461  } else {
462  prob = 0.0;
463  return found;
464  }
465 
466  // Auxiliary variables
467  headId = (sign == -1) ? (nAtom-1) : 0;
468  iMol = system().moleculeId(*iPtr);
469 
470  // Nullify counters
471  nPairs = 0;
472 
473  // Loop over j molecules to scan possible pairs
474  for (j = 0; j < nMol; ++j) {
475 
476  jPtr = &(system().molecule(speciesId_, j));
477 
478  if (j != iMol) {
479 
480  for (k = 0; k < nAtom - 1 - nRegrow_; ++k) {
481 
482  // Check if i1 to j2 bridging is possible
483  iPos1 = iPtr->atom(headId + k*sign).position();
484  jPos2 = jPtr->atom(headId + signRegrow + k*sign).position();
485  lengthSq = boundary().distanceSq(iPos1, jPos2);
486 
487  if (lengthSq < bridgeLengthSq) {
488  // Check if j2 to j1 bridging is possible
489  jPos1 = jPtr->atom(headId + k*sign).position();
490  iPos2 = iPtr->atom(headId + signRegrow + k*sign).position();
491  lengthSq = boundary().distanceSq(iPos2, jPos1);
492 
493  if (lengthSq < bridgeLengthSq) nPairs += 1;
494  }
495 
496  } // loop over atom positions
497  } // if j != iMol
498  } // loop over j molecules
499 
500  // nPairs is always greater than or equal to 1
501  prob = 1.0 / double(nPairs);
502  return found;
503  }
504 
505 }
virtual void setup()
Initialize the arrays for preferential angle, effective spring constant and normalization factor...
Bond & bond(int localId)
Get a specific Bond in this Molecule by non-const reference.
A System for use in a Markov chain Monte Carlo simulation.
Definition: McSystem.h:52
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
A Vector is a Cartesian vector.
Definition: Vector.h:75
void incrementNAttempt()
Increment the number of attempted moves.
Definition: McMove.h:191
DArray< Vector > jOldPos_
Array of old positions of temporarily deleted atoms (jMol).
double distanceSq(const Vector &r1, const Vector &r2) const
Return square distance between positions r1 and r2.
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
Definition: McMove.cpp:58
virtual void readParameters(std::istream &in)
Read species type, nTrial, and parameters needed to evaluate the orientation bias.
virtual void readParameters(std::istream &in)
Read species to which displacement is applied.
int typeId() const
Get the typeId for this covalent group.
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
Definition: McMove.cpp:48
File containing preprocessor macros for error handling.
Classes used by all simpatico molecular simulations.
Base class configuration bias moves internal segment regrowth moves.
DArray< Vector > iOldPos_
Array of old positions of temporarily deleted atoms (iMol).
Saving / output archive for binary ostream.
Molecule & molecule(int speciesId, int moleculeId)
Get a specific Molecule in this System, by integer index.
Definition: System.h:1137
int nMolecule(int speciesId) const
Get the number of molecules of one Species in this System.
Definition: System.h:1128
void addSequence(int nActive, int sign, Atom *beginPtr, int *bonds, double &rosenbluth, double &energy)
Configuration bias algorithm for adding a consequtive sequence of atoms.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
McSystem & system()
Get parent McSystem.
Definition: SystemMove.h:82
Molecule & randomMolecule(int speciesId)
Get a random Molecule of a specified species in this System.
Definition: System.cpp:1200
void incrementNAccept()
Increment the number of accepted moves.
Definition: McMove.h:197
virtual void loadParameters(Serializable::IArchive &ar)
Load internal state from an archive.
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
A point particle within a Molecule.
Utility classes for scientific computation.
Definition: accumulators.mod:1
int speciesId_
Integer index for molecular species.
long uniformInt(long range1, long range2)
Return random long int x uniformly distributed in range1 <= x < range2.
Definition: Random.h:224
Random & random()
Get Random number generator of parent Simulation.
Definition: McMove.h:209
McPairPotential & pairPotential() const
Return the McPairPotential by reference.
Definition: McSystem.h:388
virtual void save(Serializable::OArchive &ar)
Save internal state to an archive.
CfbDoubleRebridgeMove(McSystem &system)
Constructor.
void deleteSequence(int nActive, int sign, Atom *endPtr, int *bonds, double &rosenbluth, double &energy)
Configuration bias algorithm for deleting a consequtive sequence of atoms.
Saving archive for binary istream.
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
void readProbability(std::istream &in)
Read the probability from file.
Definition: McMove.cpp:42
void setClassName(const char *className)
Set class name string.
const Atom & atom(int localId) const
Get a specific Atom in this Molecule.
double bridgeLength_
upper bound for trial lenght of a bridge.
bool metropolis(double ratio)
Metropolis algorithm for whether to accept a MC move.
Definition: Random.h:260
virtual bool move()
Generate and accept or reject configuration bias move.
Simulation & simulation()
Get parent Simulation object.
Definition: McMove.h:203
A physical molecule (a set of covalently bonded Atoms).
const Vector & position() const
Get the position Vector by const reference.
Species & species(int i)
Get a specific Species by reference.
void updateAtomCell(Atom &atom)
Update the cell list to reflect a new position.
A Species of linear polymers (abstract).
Definition: Linear.h:36
int nAtom() const
Get the number of Atoms in this Molecule.
int moleculeId(const Molecule &molecule) const
Get the index of a Molecule within its Species in this System.
Definition: System.cpp:1189
Boundary & boundary()
Get Boundary object of parent McSystem.
Definition: SystemMove.h:88
int nRegrow_
Number of particles at end to attempt to regrow.