Simpatico  v1.10
McMuExchange.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 "McMuExchange.h" // class header
9 
10 #include <mcMd/mcSimulation/McSystem.h>
11 #include <mcMd/potentials/pair/McPairPotential.h>
12 #include <mcMd/neighbor/CellList.h>
13 #include <mcMd/chemistry/Molecule.h>
14 #include <mcMd/chemistry/Atom.h>
15 
16 #include <simp/species/Species.h>
17 #include <simp/ensembles/EnergyEnsemble.h>
18 #include <simp/boundary/Boundary.h>
19 
20 #include <util/archives/Serializable_includes.h>
21 #include <util/space/Vector.h>
22 #include <util/misc/FileMaster.h>
23 #include <util/global.h>
24 
25 #include <math.h>
26 
27 namespace McMd
28 {
29 
30  using namespace Util;
31  using namespace Simp;
32 
33  /*
34  * Constructor.
35  */
37  : SystemAnalyzer<McSystem>(system),
38  simulationPtr_(&system.simulation()),
39  boundaryPtr_(&system.boundary()),
40  outputFile_(),
41  accumulators_(),
42  newTypeIds_(),
43  isAtomFlipped_(),
44  flipAtomIds_(),
45  speciesId_(-1),
46  nAtom_(-1),
47  isInitialized_(false)
48  {
49  setClassName("McMuExchange");
50  }
51 
52  /*
53  * Read parameters and initialize.
54  */
55  void McMuExchange::readParameters(std::istream& in)
56  {
57 
58  readInterval(in);
60  read<int>(in, "speciesId", speciesId_);
61  if (speciesId_ < 0) {
62  UTIL_THROW("Negative speciesId");
63  }
64  if (speciesId_ >= system().simulation().nSpecies()) {
65  UTIL_THROW("speciesId >= nSpecies");
66  }
67  Species* speciesPtr;
68  speciesPtr = &(system().simulation().species(speciesId_));
69  nAtom_ = speciesPtr->nAtom();
70  newTypeIds_.allocate(nAtom_);
71  readDArray<int>(in, "newTypeIds", newTypeIds_, nAtom_);
72 
73  flipAtomIds_.allocate(nAtom_);
74  isAtomFlipped_.allocate(nAtom_);
75  for (int i = 0; i < nAtom_; ++i) {
76  if (newTypeIds_[i] != speciesPtr->atomTypeId(i)) {
77  flipAtomIds_.append(i);
78  isAtomFlipped_[i] = 1;
79  } else {
80  isAtomFlipped_[i] = 0;
81  }
82  }
83  accumulators_.allocate(speciesPtr->capacity());
84 
85  isInitialized_ = true;
86  }
87 
88  /*
89  * Clear accumulators.
90  */
92  {
93  nMolecule_ = system().nMolecule(speciesId_);
94  if (nMolecule_ > accumulators_.capacity()) {
95  UTIL_THROW("nMolecule > capacity");
96  }
97  if (nMolecule_ <= 0) {
98  UTIL_THROW("nMolecule <= 0");
99  }
100  for (int iMol = 0; iMol < nMolecule_; ++iMol) {
101  accumulators_[iMol].clear();
102  }
103  }
104 
105  /*
106  * Evaluate change in energy, add Boltzmann factor to accumulator.
107  */
108  void McMuExchange::sample(long iStep)
109  {
110  if (isAtInterval(iStep)) {
111 
112  // Preconditions
113  if (!system().energyEnsemble().isIsothermal()) {
114  UTIL_THROW("EnergyEnsemble is not isothermal");
115  }
116  if (nMolecule_ != system().nMolecule(speciesId_)) {
117  UTIL_THROW("nMolecule has changed since setup");
118  }
119 
120  McPairPotential& potential = system().pairPotential();
121  const CellList& cellList = potential.cellList();
122  System::MoleculeIterator molIter;
123  Atom* ptr0 = 0; // Pointer to first atom in molecule
124  Atom* ptr1 = 0; // Pointer to flipped atom
125  Atom* ptr2 = 0; // Pointer to neighboring atom
126  Mask* maskPtr = 0; // Mask of flipped atom
127  double rsq, dE, beta, boltzmann;
128  int j, k, nNeighbor, nFlip;
129  int i1, i2, id1, id2, t1, t2, t1New, iMol;
130  beta = system().energyEnsemble().beta();
131  nFlip = flipAtomIds_.size();
132 
133  // Loop over molecules in species
134  iMol = 0;
135  system().begin(speciesId_, molIter);
136  for ( ; molIter.notEnd(); ++molIter) {
137  dE = 0.0;
138  ptr0 = &molIter->atom(0);
139 
140  // Loop over flipped atoms
141  for (j = 0; j < nFlip; ++j) {
142  i1 = flipAtomIds_[j];
143  t1New = newTypeIds_[i1];
144  ptr1 = &molIter->atom(i1);
145  id1 = ptr1->id();
146  t1 = ptr1->typeId();
147  maskPtr = &(ptr1->mask());
148 
149  // Loop over neighboring atoms
150  cellList.getNeighbors(ptr1->position(), neighbors_);
151  nNeighbor = neighbors_.size();
152  for (k = 0; k < nNeighbor; ++k) {
153  ptr2 = neighbors_[k];
154  id2 = ptr2->id();
155 
156  // Check if atoms are identical
157  if (id2 != id1) {
158 
159  // Check if pair is masked
160  if (!maskPtr->isMasked(*ptr2)) {
161 
162  rsq = boundary().distanceSq(ptr1->position(),
163  ptr2->position());
164  t2 = ptr2->typeId();
165  if (&(ptr1->molecule()) != &(ptr2->molecule())) {
166  // Intermolecular atom pair
167  dE -= potential.energy(rsq, t1, t2);
168  dE += potential.energy(rsq, t1New, t2);
169  } else {
170  // Intramolecular atom pair
171  if (id2 > id1) {
172  dE -= potential.energy(rsq, t1, t2);
173  i2 = (int)(ptr2 - ptr0);
174  t2 = newTypeIds_[i2];
175  dE += potential.energy(rsq, t1New, t2);
176  } else {
177  i2 = (int)(ptr2 - ptr0);
178  if (!isAtomFlipped_[i2]) {
179  dE -= potential.energy(rsq, t1, t2);
180  t2 = newTypeIds_[i2];
181  dE += potential.energy(rsq, t1New, t2);
182  }
183  }
184  }
185  }
186 
187  }
188  } // end loop over neighbors
189  } // end loop over flipped atoms
190 
191  boltzmann = exp(-beta*dE);
192  accumulators_[iMol].sample(boltzmann);
193  ++iMol;
194  } // end loop over molecules
195  }
196  }
197 
198  /*
199  * Output results to file after simulation is completed.
200  */
202  {
203 
204  fileMaster().openOutputFile(outputFileName(".prm"), outputFile_);
205  writeParam(outputFile_);
206  outputFile_.close();
207 
208  double ave, err;
209  double sumAve = 0.0;
210  double sumAveSq = 0.0;
211  double sumErrSq = 0.0;
212  for (int iMol=0; iMol < nMolecule_; ++iMol) {
213  ave = accumulators_[iMol].average();
214  err = accumulators_[iMol].blockingError();
215  sumAve += ave;
216  sumAveSq += ave*ave;
217  sumErrSq += err*err;
218  }
219  double rMol = double(nMolecule_);
220  ave = sumAve/rMol;
221  err = sqrt(sumErrSq/rMol);
222  double dev = sqrt((sumAveSq/rMol) - ave*ave);
223 
224  fileMaster().openOutputFile(outputFileName(".ave"), outputFile_);
225  outputFile_ << "Average = " << ave << " +- "
226  << dev/sqrt(rMol) << std::endl;
227  outputFile_ << "Error via molecule variance = "
228  << dev/sqrt(rMol) << std::endl;
229  outputFile_ << "Error via time series analysis = "
230  << err/sqrt(rMol) << std::endl;
231  outputFile_ << std::endl;
232  //for (int iMol=0; iMol < nMolecule_; ++iMol) {
233  // accumulators_[iMol].output(outputFile_);
234  //}
235  outputFile_.close();
236  }
237 
238  /*
239  * Save state to binary file archive.
240  */
242  {
243  if (!isInitialized_) {
244  UTIL_THROW("McMuExchange object not initialized");
245  }
246  ar << interval_;
247  ar << outputFileName_;
248  ar << speciesId_;
249  ar << nAtom_;
250  ar << newTypeIds_;
251  ar << nMolecule_;
252  for (int i = 0; i < nMolecule_; ++i) {
253  ar << accumulators_[i];
254  }
255  }
256 
257  /*
258  * Load state from a binary file archive.
259  */
261  {
262  loadInterval(ar);
263  loadOutputFileName(ar);
264  loadParameter(ar, "speciesId", speciesId_);
265  ar >> nAtom_;
266  Species* speciesPtr;
267  speciesPtr = &(system().simulation().species(speciesId_));
268  if (nAtom_ != speciesPtr->nAtom()) {
269  UTIL_THROW("Inconsistent values of nAtom on loading");
270  }
271  newTypeIds_.allocate(nAtom_);
272  loadDArray(ar, "newTypeIds", newTypeIds_, nAtom_);
273 
274  flipAtomIds_.allocate(nAtom_);
275  isAtomFlipped_.allocate(nAtom_);
276  for (int i = 0; i < nAtom_; ++i) {
277  if (newTypeIds_[i] != speciesPtr->atomTypeId(i)) {
278  flipAtomIds_.append(i);
279  isAtomFlipped_[i] = 1;
280  } else {
281  isAtomFlipped_[i] = 0;
282  }
283  }
284  accumulators_.allocate(speciesPtr->capacity());
285 
286  ar >> nMolecule_;
287  for (int i = 0; i < nMolecule_; ++i) {
288  ar >> accumulators_[i];
289  }
290  isInitialized_ = true;
291  }
292 
293 }
int size() const
Return logical size of this array (i.e., number of elements).
Definition: DSArray.h:388
Molecule & molecule() const
Get the parent Molecule by reference.
A System for use in a Markov chain Monte Carlo simulation.
Definition: McSystem.h:52
virtual void readParameters(std::istream &in)
Read parameters and initialize.
virtual double energy(double rsq, int iAtomType, int jAtomType) const =0
Return pair energy for a single pair.
void getNeighbors(const Vector &pos, NeighborArray &neighbors) const
Fill a NeighborArray with pointers to atoms near a specified position.
void begin(int speciesId, MoleculeIterator &iterator)
Initialize an iterator for molecules of one species in this System.
Definition: System.h:1147
int nAtom() const
Get number of atoms per molecule for this Species.
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 void save(Serializable::OArchive &ar)
Save state to binary file archive.
McMuExchange(McSystem &system)
Constructor.
void append(const Data &data)
Append data to the end of the array.
Definition: DSArray.h:345
virtual void loadParameters(Serializable::IArchive &ar)
Load state from a binary file archive.
Set of Atoms for which pair interactions with a target Atom are "masked".
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
A PairPotential for MC simulations (abstract).
EnergyEnsemble & energyEnsemble() const
Get the EnergyEnsemble by reference.
Definition: System.h:1095
Mask & mask()
Get the associated Mask by reference.
McSystem & system()
Return reference to parent system.
File containing preprocessor macros for error handling.
Classes used by all simpatico molecular simulations.
void readOutputFileName(std::istream &in)
Read outputFileName from file.
Saving / output archive for binary ostream.
long interval_
Number of simulation steps between subsequent actions.
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
double beta() const
Return the inverse temperature.
DArrayParam< Type > & loadDArray(Serializable::IArchive &ar, const char *label, DArray< Type > &array, int n, bool isRequired)
Add an load a DArray < Type > array parameter.
#define UTIL_THROW(msg)
Macro for throwing an Exception, reporting function, file and line number.
Definition: global.h:51
void allocate(int capacity)
Allocates the underlying C array.
Definition: DSArray.h:247
Simulation & simulation() const
Get the parent Simulation by reference.
Definition: System.h:1055
int typeId() const
Get type index for this Atom.
virtual void writeParam(std::ostream &out)
Write all parameters to an output stream.
void readInterval(std::istream &in)
Read interval from file, with error checking.
A point particle within a Molecule.
bool notEnd() const
Is the current pointer not at the end of the PArray?
Utility classes for scientific computation.
Definition: accumulators.mod:1
virtual void sample(long iStep)
Evaluate energy per particle, and add to ensemble.
std::string outputFileName_
Base name of output file(s).
int id() const
Get global index for this Atom within the Simulation.
int atomTypeId(int iAtom) const
Get atom type index for a specific atom, by local atom index.
ScalarParam< Type > & loadParameter(Serializable::IArchive &ar, const char *label, Type &value, bool isRequired)
Add and load a new ScalarParam < Type > object.
Forward iterator for a PArray.
Definition: ArraySet.h:19
virtual void setup()
Clear accumulators.
Template for Analyzer associated with one System.
McPairPotential & pairPotential() const
Return the McPairPotential by reference.
Definition: McSystem.h:388
A cell list for Atom objects in a periodic system boundary.
Saving archive for binary istream.
Single-processor Monte Carlo (MC) and molecular dynamics (MD).
void setClassName(const char *className)
Set class name string.
int capacity() const
Maximum allowed number of molecules for this Species.
FileMaster & fileMaster()
Get the FileMaster by reference.
void loadInterval(Serializable::IArchive &ar)
Load interval from archive, with error checking.
bool isAtInterval(long counter) const
Return true iff counter is a multiple of the interval.
const std::string & outputFileName() const
Return outputFileName string.
void allocate(int capacity)
Allocate the underlying C array.
Definition: DArray.h:191
void loadOutputFileName(Serializable::IArchive &ar)
Load output file name from archive.
const Vector & position() const
Get the position Vector by const reference.
A Species represents a set of chemically similar molecules.
Species & species(int i)
Get a specific Species by reference.
int size() const
Return logical size of this array (i.e., number of elements).
Definition: FSArray.h:207
virtual void output()
Output results at end of simulation.