Simpatico  v1.10
GcSliplinkMove.cpp
1 #ifndef GC_SLIPLINKMOVE_CPP
2 #define GC_SLIPLINKMOVE_CPP
3 
4 /*
5 * MolMcD - Monte Carlo and Molecular Dynamics Simulator for Molecular Liquids
6 *
7 * Copyright 2010 - 2014, The Regents of the University of Minnesota
8 * Distributed under the terms of the GNU General Public License.
9 */
10 
11 #include "GcSliplinkMove.h"
12 #include <util/misc/FileMaster.h>
13 #include <mcMd/simulation/Simulation.h>
14 #include <mcMd/links/LinkMaster.h>
15 #include <mcMd/mcSimulation/McSystem.h>
16 #include <mcMd/potentials/bond/BondPotential.h>
17 #include <mcMd/potentials/pair/McPairPotential.h>
18 #include <mcMd/chemistry/Molecule.h>
19 #include <mcMd/chemistry/Atom.h>
20 #include <simp/boundary/Boundary.h>
21 #include <util/space/Vector.h>
22 #include <util/global.h>
23 
24 #include <cstdlib>
25 
26 #define MCMD_LINK_CREATE
27 #define MCMD_LINK_SHUFFLE
28 
29 namespace McMd
30 {
31 
32  using namespace Util;
33  using namespace Simp;
34 
35  // Constructor
37  SystemMove(system),
38  cutoff_(0.0),
39  cutoffSq_(0.0),
40  fCreate_(0.0),
41  fNotCreate_(1.0),
42  mu_(0.0),
43  nTrial_(0),
44  speciesId_(0)
45  { setClassName("GcSliplinkMove"); }
46 
47  void GcSliplinkMove::readParameters(std::istream& in)
48  {
49  readProbability(in);
50  read<int>(in, "nTrial", nTrial_);
51  read<int>(in, "speciesId", speciesId_);
52  read<double>(in, "fCreate", fCreate_);
53  read<double>(in, "cutoff", cutoff_);
54  read<double>(in, "mu", mu_);
55 
56  cutoffSq_ = cutoff_*cutoff_;
57  fNotCreate_ = 1.0 - fCreate_;
58  }
59 
62  {
64  double rsq, oldEnergy, newEnergy;
65  double rnd, norm, energy, sum, pci, pdi, ratio;
66  double cdf[CellList::MaxNeighbor];
67  Molecule *mol0Ptr, *mol1Ptr;
68  Link *linkPtr;
69  Atom *atom0Ptr, *atom1Ptr;
70  int i, j, iAtom0, iAtom1, linkId, nLink, nNeighbor, n0, endId;
71  int idneighbors[CellList::MaxNeighbor];
72  bool allowed;
73 
74 
75  // Loop over attempted Markov moves
76  for (i=0; i < nTrial_; ++i) {
77 
78  nLink = system().linkMaster().nLink();
79 
81  if (random().uniform(0.0, 1.0) > fCreate_) { // Shuffle/destroy
82 
83  if (nLink > 0) {
84 
85  // Choose a link at random
86  linkId = random().uniformInt(0, nLink);
87  linkPtr = &(system().linkMaster().link(linkId));
88 
89  // Choose an end to be moved: atom0.
90  if (random().uniform(0.0, 1.0) < 0.5) {
91  endId = 0;
92  atom0Ptr = &(linkPtr->atom0());
93  atom1Ptr = &(linkPtr->atom1());
94  } else {
95  endId = 1;
96  atom0Ptr = &(linkPtr->atom1());
97  atom1Ptr = &(linkPtr->atom0());
98  }
99 
100  // Identify molecules and indices within molecules
101  mol0Ptr = &atom0Ptr->molecule();
102  iAtom0 = atom0Ptr->indexInMolecule();
103  mol1Ptr = &atom1Ptr->molecule();
104  iAtom1 = atom1Ptr->indexInMolecule();
105 
106  rsq = boundary().distanceSq(atom0Ptr->position(),
107  atom1Ptr->position());
108 
109  // If atom0 is not a chain end, attempt shuffle
110  if (iAtom0 != 0 && iAtom0 != mol0Ptr->nAtom() - 1) {
111 
112  #ifdef MCMD_LINK_SHUFFLE
113  // Calculate old link energy
114  oldEnergy = system().linkPotential()
115  .energy(rsq, linkPtr->typeId());
116 
117  // Shuffle atom0 index
118  if (random().uniform(0.0, 1.0) > 0.5) {
119  ++iAtom0;
120  } else {
121  --iAtom0;
122  }
123  atom0Ptr = &mol0Ptr->atom(iAtom0);
124 
125  // Check if proposed shuffle is allowed
126  allowed = true;
127  if (mol0Ptr == mol1Ptr) {
128  if (std::abs(iAtom0 - iAtom1) < 2) {
129  allowed = false;
130  }
131  }
132 
133  if (allowed) {
134 
135  // Calculate energy of new configuration
136  rsq = boundary().distanceSq(atom0Ptr->position(),
137  atom1Ptr->position());
138  newEnergy = system().linkPotential()
139  .energy(rsq, linkPtr->typeId());
140 
141  // Accept or reject shuffle
142  if (random().metropolis(boltzmann(newEnergy - oldEnergy))) {
143  system().linkMaster().reSetAtom(*linkPtr, *atom0Ptr, endId);
144  //system().linkMaster().reSetAtoms(*linkPtr,
145  // *atom0Ptr, *atom1Ptr);
146  incrementNAccept();
147  }
148 
149  }
150  #endif
151 
152  } else { // If atom0 is a chain end
153 
154  // Attempt shuffle away from end with 50% probability
155  if (random().uniform(0.0, 1.0) > 0.5) {
156 
157  #ifdef MCMD_LINK_SHUFFLE
158  // Calculate energy of old configuration.
159  oldEnergy = system().linkPotential()
160  .energy(rsq, linkPtr->typeId());
161 
162  // Move the atom away from the end
163  if (iAtom0 == 0) {
164  ++iAtom0;
165  } else {
166  assert(iAtom0 == mol0Ptr->nAtom()-1);
167  --iAtom0;
168  }
169  atom0Ptr = &mol0Ptr->atom(iAtom0);
170 
171  // Check if proposed shuffle is allowed
172  allowed = true;
173  if (mol0Ptr == mol1Ptr) {
174  if (std::abs(iAtom0 - iAtom1) < 2) {
175  allowed = false;
176  }
177  }
178 
179  if (allowed) {
180 
181  // Calculate new link energy
182  rsq = boundary().distanceSq(atom0Ptr->position(),
183  atom1Ptr->position());
184  newEnergy = system().linkPotential()
185  .energy(rsq, linkPtr->typeId());
186 
187  // Accept or reject shuffle
188  if (random().metropolis(boltzmann(newEnergy-oldEnergy))) {
189  system().linkMaster().reSetAtom(*linkPtr, *atom0Ptr, endId);
190  //system().linkMaster()
191  // .reSetAtoms(*linkPtr, *atom0Ptr, *atom1Ptr);
193  }
194 
195  }
196  #endif
197 
198  } else { // Attempt destroy with 50% probability
199 
200  #ifdef MCMD_LINK_CREATE
201  // If link length is within create/destroy cutoff
202  if (rsq <= cutoffSq_) {
203 
204  // Get array of neighbors
206  .getNeighbors(atom0Ptr->position(), neighbors_);
207  nNeighbor = neighbors_.size();
208 
209  // Loop over neighboring atoms
210  n0 = 0;
211  sum = 0;
212  for (j = 0; j < nNeighbor; ++j) {
213  atom1Ptr = neighbors_[j];
214 
215  // If atoms are not the same
216  if (atom0Ptr != atom1Ptr) {
217 
218  // If not a masked pair
219  if (!atom0Ptr->mask().isMasked(*atom1Ptr)) {
220 
221  rsq = boundary().distanceSq(atom0Ptr->position(),
222  atom1Ptr->position());
223 
224  // If r < cutoff, compute Boltzmann weight,
225  // and add to cumulative distribution cdf
226  if (rsq <= cutoffSq_) {
227  energy = system().linkPotential()
228  .energy(rsq, linkPtr->typeId());
229  sum = sum + boltzmann(energy);
230  cdf[n0] = sum;
231  idneighbors[n0] = j;
232  n0++;
233  }
234 
235  }
236  }
237  }
238 
239  // Accept or reject destruction
240  pci = 2.0 * system().nMolecule(speciesId_)
241  * boltzmann(-mu_) * cdf[n0-1] / fCreate_;
242  pdi = 4.0 * nLink / fNotCreate_;
243  ratio = pdi / pci;
244  if (random().metropolis(ratio)) {
245  system().linkMaster().removeLink(linkId);
247  }
248 
249  } // end if dRsq < cutoffSq
250  #endif
251 
252  } // end attempt destroy
253 
254  } // end if atom0 at end
255 
256  } // end if nLink > 0
257 
258  } else { // Attempt slip-link creation with probability fCreate_
259 
260  #ifdef MCMD_LINK_CREATE
261  // Choose a molecule at random
262  mol0Ptr = &(system().randomMolecule(speciesId_));
263 
264  // Choose either molecule end at random
265  if (random().uniform(0.0, 1.0) > 0.5) {
266  iAtom0 = 0;
267  } else {
268  iAtom0 = mol0Ptr->nAtom() - 1;
269  }
270  atom0Ptr = &mol0Ptr->atom(iAtom0);
271 
272  // Get array of neighbors
274  .getNeighbors(atom0Ptr->position(), neighbors_);
275  nNeighbor = neighbors_.size();
276 
277  // Loop over neighboring atoms
278  n0 = 0;
279  sum = 0;
280  for (j = 0; j < nNeighbor; ++j) {
281  atom1Ptr = neighbors_[j];
282 
283  // If atoms are not the same
284  if (atom0Ptr != atom1Ptr){
285 
286  // If not a masked pair
287  if (!atom0Ptr->mask().isMasked(*atom1Ptr)) {
288 
289  rsq = boundary().distanceSq(atom0Ptr->position(),
290  atom1Ptr->position());
291 
292  // If r < cutoff, compute Boltzmann weight for partner,
293  // and add to cumulative distribution cdf.
294  if (rsq <= cutoffSq_) {
295  energy = system().linkPotential().energy(rsq, 0);
296  sum = sum + boltzmann(energy);
297  cdf[n0] = sum;
298  idneighbors[n0] = j;
299  n0++;
300  }
301 
302  }
303  }
304  }
305 
306  // If at least 1 candidate has been found.
307  if (n0 > 0) {
308 
309  // Choose a partner with probability cdf[j]/cdf[n0-1]
310  j = 0;
311  rnd = random().uniform(0.0, 1.0);
312  norm = 1.0/cdf[n0-1];
313  while (rnd > cdf[j]*norm ){
314  j = j + 1;
315  }
316  atom1Ptr = neighbors_[idneighbors[j]];
317 
318  // Accept or reject creation
319  pci = 2.0 * system().nMolecule(speciesId_)
320  * boltzmann(-mu_) * cdf[n0-1] / fCreate_;
321  pdi = 4.0 * (nLink + 1.0) / fNotCreate_;
322  ratio = pci / pdi;
323  if (random().metropolis(ratio)) {
324  if (random().uniform(0.0, 1.0) > 0.5){
325  system().linkMaster().addLink(*atom0Ptr, *atom1Ptr, 0);
326  } else {
327  system().linkMaster().addLink(*atom1Ptr, *atom0Ptr, 0);
328  }
330  }
331 
332  } // end if (n0 > 0)
333  #endif
334 
335  } // end if (shuffle/destroy) else (create)
336 
337  } // foreach trial
338 
339  return true;
340  }
341 
342 }
343 
344 #ifdef MCMD_LINK_SHUFFLE
345 #undef MCMD_LINK_SHUFFLE
346 #endif
347 
348 #ifdef MCMD_LINK_CREATE
349 #undef MCMD_LINK_CREATE
350 #endif
351 
352 #endif
int nLink() const
Get the total number of active Links.
Definition: LinkMaster.h:261
Molecule & molecule() const
Get the parent Molecule by reference.
A System for use in a Markov chain Monte Carlo simulation.
Definition: McSystem.h:52
GcSliplinkMove(McSystem &system)
Constructor.
void removeLink(int id)
Remove a Link.
Definition: LinkMaster.cpp:77
void incrementNAttempt()
Increment the number of attempted moves.
Definition: McMove.h:191
static const int MaxNeighbor
Maximum possible number of neighboring atoms.
void getNeighbors(const Vector &pos, NeighborArray &neighbors) const
Fill a NeighborArray with pointers to atoms near a specified position.
double distanceSq(const Vector &r1, const Vector &r2) const
Return square distance between positions r1 and r2.
const CellList & cellList() const
Get the cellList by const reference.
virtual bool move()
Move slip-springs.
Mask & mask()
Get the associated Mask by reference.
File containing preprocessor macros for error handling.
Classes used by all simpatico molecular simulations.
double uniform()
Return a random floating point number x, uniformly distributed in the range 0 <= x < 1...
Definition: Random.h:203
double boltzmann(double energy)
Boltzmann weight associated with an energy difference.
Definition: SystemMove.h:100
bool isMasked(const Atom &atom) const
True if the atom is in the masked set for the target Atom.
int nMolecule(int speciesId) const
Get the number of molecules of one Species in this System.
Definition: System.h:1128
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
A point particle within a Molecule.
Utility classes for scientific computation.
Definition: accumulators.mod:1
An McMove that acts on one McSystem.
Definition: SystemMove.h:28
virtual void readParameters(std::istream &in)
Read cutoff and speciesId.
long uniformInt(long range1, long range2)
Return random long int x uniformly distributed in range1 <= x < range2.
Definition: Random.h:224
void reSetAtom(Link &link, Atom &atom, int endId)
Modify one atom attached to a link.
Definition: LinkMaster.cpp:160
Forward iterator for a PArray.
Definition: ArraySet.h:19
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 double energy(double rSq, int type) const =0
Returns potential energy for one bond.
BondPotential & linkPotential() const
Return the McLinkPotential by reference.
Definition: McSystem.h:493
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.
int indexInMolecule() const
Get local index for this Atom within the parent molecule;.
Link & link(int id) const
Return an active link by an internal set index.
Definition: LinkMaster.h:255
bool metropolis(double ratio)
Metropolis algorithm for whether to accept a MC move.
Definition: Random.h:260
A physical molecule (a set of covalently bonded Atoms).
const Vector & position() const
Get the position Vector by const reference.
void addLink(Atom &atom0, Atom &atom1, int typeId)
Add a link betwen two specific Atoms.
Definition: LinkMaster.cpp:39
int size() const
Return logical size of this array (i.e., number of elements).
Definition: FSArray.h:207
int nAtom() const
Get the number of Atoms in this Molecule.
Boundary & boundary()
Get Boundary object of parent McSystem.
Definition: SystemMove.h:88
LinkMaster & linkMaster() const
Get the LinkMaster by reference.
Definition: System.h:1074