Path Integral Quantum Monte Carlo
pimc.cpp
Go to the documentation of this file.
1 
8 #include "pimc.h"
9 #include "path.h"
10 #include "lookuptable.h"
11 #include "move.h"
12 
13 // ---------------------------------------------------------------------------
14 // ---------------------------------------------------------------------------
15 // PATH INTEGRAL MONTE CARLO CLASS -------------------------------------------
16 // ---------------------------------------------------------------------------
17 // ---------------------------------------------------------------------------
18 
19 /**************************************************************************/
27 PathIntegralMonteCarlo::PathIntegralMonteCarlo (boost::ptr_vector<Path> &_pathPtrVec,
28  MTRand &_random, boost::ptr_vector<move_vector> &_movePtrVec,
29  boost::ptr_vector<estimator_vector> &_estimatorPtrVec,
30  const bool _startWithState,uint32 _binSize) :
31  random(_random),
32  binSize(_binSize),
33  Npaths(_pathPtrVec.size()),
34  pathPtrVec(_pathPtrVec),
35  path(pathPtrVec.front()),
36  movePtrVec(_movePtrVec),
37  move(movePtrVec.front()),
38  estimatorPtrVec(_estimatorPtrVec),
39  estimator(estimatorPtrVec.front())
40 {
41  /* Are we starting from a saved state? */
42  startWithState = _startWithState;
43 
44  /* Initialize stateStrings */
45  stateStrings.resize(Npaths);
46 
47  /* We keep simulating until we have stored a certain number of measurements */
48  numStoredBins = 0;
49 
50  /* Initialize the number of sweeps and updates per sweep*/
51  numSteps = 0;
52 
53  /* This is required in case we have zero particles in the simulation */
54  numUpdates = int(ceil(max(constants()->initialNumParticles(),1)*constants()->numTimeSlices() /
55  (1.0*constants()->Mbar())));
56  if (numUpdates < 100)
57  numUpdates = 100;
58 
59  /* Calculate the number of sweeps to make sure we touch every bead */
60  numImagTimeSweeps = int(ceil((1.0*constants()->numTimeSlices()/(1.0*constants()->Mbar()))));
61 
62  /* These counters are used in the equilibration process */
63  numConfig = 0;
64  numDiagonal = 0;
65  numCoMAttempted = 200;
66  prevNumCoMAttempted = 200;
67  numCoMAccepted = 0;
70  numNAttempted = 0;
71 
72  numStepsAttempted = 2000*numUpdates;
73  numMuAttempted = 2000*numUpdates;
74 
75  relaxmuMessage = false;
76  relaxC0Message = false;
77  equilMessage = false;
78  equilODMessage = false;
79 
80  /* The target diagonal fraction (hard coded) */
81  targetDiagFrac = 0.70;
82 
83  /* Do we need to shift C0 up or down? */
84  sgnDiagFrac = 0;
85  shiftC0 = 0.25;
86 
87  /* Have we found the desired C0 value for the diagonal fraction */
88  foundC0 = false;
89 
90  /* The target/initial number of particles */
92 
93  /* Number probability distribution used when relaxing chemical potential.
94  * We assume the maximum possible number is 2000 particles */
95  PN.resize(2000);
96  PN = 0;
97  foundmu = false;
98  muFactor = 1.0;
99  sgnAveN = 0;
100 
101  /* Used for optimization of μ search */
102  bestPN = 0;
103  bestmu = constants()->mu();
104  bestDiffAveN = 5000;
105 
106  /* Intialize the config number to zero */
107  configNumber = 0;
108 
109  /* Determine the cumulative attempt move probabilities, and the indices of
110  * various diagonal moves */
111  double cumDiagProb = 0.0;
112  double cumOffDiagProb = 0.0;
113  string moveName;
114 
115  for (auto movePtr = move.begin(); movePtr != move.end(); ++movePtr) {
116 
117  /* Get the namne of the move and check if it is the generic diagonal
118  * move */
119  moveName = movePtr->getName();
120  if ((moveName == "bisection") || (moveName == "staging"))
121  moveName = "diagonal";
122 
123  /* Accumulate the diagonal moves */
124  if ( (movePtr->operateOnConfig == DIAGONAL) || movePtr->operateOnConfig == ANY ) {
125  cumDiagProb += constants()->attemptProb(moveName);
126  attemptDiagProb.push_back(cumDiagProb);
127  }
128  else
129  attemptDiagProb.push_back(cumDiagProb);
130 
131  /* Accumulate the off-diagonal moves */
132  if ( (movePtr->operateOnConfig == OFFDIAGONAL) || movePtr->operateOnConfig == ANY) {
133  cumOffDiagProb += constants()->attemptProb(moveName);
134  attemptOffDiagProb.push_back(cumOffDiagProb);
135  }
136  else
137  attemptOffDiagProb.push_back(cumOffDiagProb);
138 
139  /* Find the indices of moves in case we need them */
140  moveIndex[moveName] = std::distance(move.begin(), movePtr);
141  }
142 
143  /* Make sure the move cumulative probability arrays add up to 1 */
144  attemptDiagProb.back() = 1.0 + EPS;
145  attemptOffDiagProb.back() = 1.0 + EPS;
146 
147  /* If we are restarting, or loading a state from disk, do so now. */
148  if (startWithState || constants()->restart())
149  loadState();
150 
151  /* Setup all the estimators for measurement i/o */
152  for (auto &&estPtr : estimatorPtrVec)
153  for (auto &est : estPtr)
154  est.prepare();
155 
156  /* Make a list of estimator names for the 0th estimator */
157  for (auto estimatorPtr = estimator.begin(); estimatorPtr != estimator.end(); ++estimatorPtr)
158  estimatorIndex[estimatorPtr->getName()] = std::distance(estimator.begin(), estimatorPtr);
159 }
160 
161 /**************************************************************************/
165  PN.free();
166 }
167 
168 /**************************************************************************/
171 string PathIntegralMonteCarlo::update(const double x, const int sweep, const int pathIdx=0) {
172 
173  success = false;
174  string moveName = "NONE";
175  int index;
176 
177  /* Determine the index of the move to be performed */
178  if (pathPtrVec[pathIdx].worm.isConfigDiagonal)
179  index = std::lower_bound(attemptDiagProb.begin(),attemptDiagProb.end(),x)
180  - attemptDiagProb.begin();
181  else
182  index = std::lower_bound(attemptOffDiagProb.begin(),attemptOffDiagProb.end(),x)
183  - attemptOffDiagProb.begin();
184 
185  /* Perform the move */
186  moveName = movePtrVec[pathIdx].at(index).getName();
187  success = movePtrVec[pathIdx].at(index).attemptMove();
188 
189  return moveName;
190 }
191 
192 
193 /**************************************************************************/
199 
200  for (int n = 0; n < constants()->initialNumParticles(); n++) {
201 
202  double x = random.rand();
203 
204  /* Here we do the diagonal pre-equilibration moves, and allow for
205  * optimization of simulation parameters */
206  if (x < constants()->attemptProb("center of mass")) {
207 
208  /* index for the center of mass */
209  int index = moveIndex["center of mass"];
210 
211  /* perform the CoM move */
212  for (auto & cmove : movePtrVec)
213  cmove.at(index).attemptMove();
214 
215  /* We check how many CoM moves we have tried. Every 200 moves, we see if we need
216  * to adjust comDelta, provided we are in the pre-equilibration diagonal state. */
217  if ( (move.at(index).getNumAttempted() > 0)
218  && (move.at(index).getNumAttempted() > prevNumCoMAttempted)
219  && (move.at(index).getNumAttempted() % numCoMAttempted == 0)
220  && (constants()->comDelta() < 0.5*blitz::min(path.boxPtr->side)) ) {
221 
222  numCoMAccepted = move.at(index).getNumAccepted() - numCoMAccepted;
223  double CoMRatio = 1.0*numCoMAccepted / numCoMAttempted;
224  if (CoMRatio < 0.2)
225  constants()->shiftCoMDelta(-0.6);
226  else if (CoMRatio < 0.3)
227  constants()->shiftCoMDelta(-0.4);
228  else if (CoMRatio < 0.4)
229  constants()->shiftCoMDelta(-0.2);
230  else if (CoMRatio > 0.6)
231  constants()->shiftCoMDelta(0.2);
232  else if (CoMRatio > 0.7)
233  constants()->shiftCoMDelta(0.4);
234  else if (CoMRatio > 0.8)
235  constants()->shiftCoMDelta(0.6);
236 
237  /* Reset the counters */
238  numCoMAccepted = move.at(index).getNumAccepted();
239  prevNumCoMAttempted = move.at(index).getNumAttempted();
240  } // CoM Delta Shift
241 
242  } // Center of mass move
243  /* Now try a displace move */
244  else if (x < constants()->attemptProb("center of mass") + constants()->attemptProb("displace")) {
245 
246  int index = moveIndex["displace"];
247  for (auto & cmove : movePtrVec)
248  cmove.at(index).attemptMove();
249 
250  /* We check how many displace moves we have tried. Every numDisplaceAttempted moves, we see if we need
251  * to adjust delta, provided we are in the pre-equilibration diagonal state. */
252  if ( (move.at(index).getNumAttempted() > 0)
253  && (move.at(index).getNumAttempted() % numDisplaceAttempted == 0) ) {
254 
255  numDisplaceAccepted = move.at(index).getNumAccepted() - numDisplaceAccepted;
256  double displaceRatio = 1.0*numDisplaceAccepted / numDisplaceAttempted;
257  if (displaceRatio < 0.2)
258  constants()->shiftDisplaceDelta(-0.6);
259  else if (displaceRatio < 0.3)
260  constants()->shiftDisplaceDelta(-0.4);
261  else if (displaceRatio < 0.4)
262  constants()->shiftDisplaceDelta(-0.2);
263  else if (displaceRatio > 0.6)
265  else if (displaceRatio > 0.7)
267  else if (displaceRatio > 0.8)
269 
270  //cout << "delta: " << constants()->delta() << " " << displaceRatio << endl;
271  /* Reset the counters */
272  numDisplaceAccepted = move.at(index).getNumAccepted();
273  }
274  } // displace move
275  else {
276  /* Attemp a diagonal path update*/
277  for (int sweep = 0; sweep < numImagTimeSweeps; sweep++){
278  for (auto &cmove : movePtrVec)
279  cmove.at(moveIndex["diagonal"]).attemptMove();
280  }
281  }
282 
283  } // initNumParticles
284 }
285 
286 /**************************************************************************/
293 
294  /* Print a message when starting the relaxation */
295  if (!relaxmuMessage) {
296  relaxmuMessage = true;
297  cout << format("[PIMCID: %s] - Relax Chemical Potential.") % constants()->id() << endl;
298  }
299 
300  double shiftmu = 1.0;
301  double mu;
302 
303  for (int n = 0; n < numUpdates; n++) {
304 
305  /* Generate random number and run through all moves */
306  double x = random.rand();
307  string mName;
308  for(uint32 p=0; p<Npaths; p++) {
309  mName = update(x,n,p);
310  }
311 
312  /* Relax the chemical potential to get a desired average number of
313  * particles */
314  int cN = round(1.0*path.worm.getNumBeadsOn()/constants()->numTimeSlices());
315  int curSize = PN.size();
316  if (cN >= curSize) {
317  PN.resizeAndPreserve(cN+1);
318  for (int n = curSize; n < cN; n++)
319  PN(n) = 0;
320  }
321 
322  PN(cN)++;
323  numNAttempted += 1;
324 
325  if ( (numNAttempted == numMuAttempted) && (N0 > 0) ) {
326 
327  /* Output the distribution to the terminal*/
328  cout << printHistogram();
329 
330  /* Compute the peak loation and average number of particles */
331  int peakN = blitz::maxIndex(PN)[0];
332  firstIndex i;
333  int aveN = round(blitz::sum(i*PN)/blitz::sum(PN));
334 
335  /* If we have shifted the peak to the desired value, exit */
336  if (peakN == N0) {
337  cout << format("Converged on μ = %8.5f\n\n") % constants()->mu();
338  return true;
339  }
340  else {
341  string method;
342 
343  /* We make sure the peak is in a window 10 particles away from
344  * the target. */
345  bool peakInWindow = ((peakN >= N0-5) && (peakN <= N0+5));
346 
347  if ((PN(N0) > 0) && (PN(N0+1) > 0) && (PN(N0-1) > 0) && peakInWindow) {
348  method = "Equal";
349  mu = constants()->mu() - 0.5*constants()->T()*log(1.0*PN(N0+1)/PN(N0-1));
350  }
351  else if ((PN(N0) > 0) && (PN(N0+1) > 0) && peakInWindow) {
352  method = "Down";
353  mu = constants()->mu() - constants()->T()*log(1.0*PN(N0+1)/PN(N0));
354  }
355  else if ((PN(N0) > 0) && (PN(N0-1) > 0) && peakInWindow) {
356  method = "Up";
357  mu = constants()->mu() - constants()->T()*log(1.0*PN(N0)/PN(N0-1));
358  }
359  else {
360  if (!inWindow) {
361  cout << "Reseting μ to previous best value." << endl;
362  mu = bestmu;
363  }
364  else {
365  if (peakN > N0) {
366  mu = constants()->mu() - shiftmu*muFactor;
367  method = "Down";
368  }
369  else {
370  mu = constants()->mu() + shiftmu*muFactor;
371  method = "Up";
372  }
373 
374  /* Determine if we need to alter the muFactor. */
375  int sgn = ((N0-aveN) > 0) - ((N0-aveN) < 0);
376  if (sgnAveN != 0) {
377  if (sgn == sgnAveN)
378  muFactor *= 1.618;
379  else
380  muFactor /= 1.61803399;
381  }
382  sgnAveN = sgn;
383  }
384  }
385 
386  cout << format("Shifting %5s:%10.2f%10.2f%10d%10d%10d") % method %
387  constants()->mu() % mu % PN(N0-1) % PN(N0) % PN(N0+1);
388 
389  constants()->setmu(mu);
390 
391  cout << format("%12d%12d%12d\n") % peakN % aveN % path.getTrueNumParticles();
392 
393  numNAttempted = 0;
394  PN = 0;
395 
396  } // haven't moved peak yet
397 
398  } // numNAttempted == numMuAttempted
399  } // numupdates
400 
401  return false;
402 }
403 
404 /**************************************************************************/
413 
414  /* Print a message when starting the relaxation */
415  if (!relaxC0Message) {
416  relaxC0Message = true;
417  cout << format("[PIMCID: %s] - Relax Worm Constant.\n") % constants()->id() << endl;
418  }
419 
420  for (int n = 0; n < numUpdates; n++) {
421 
422  /* Generate random number and run through all moves */
423  double x = random.rand();
424  string mName;
425  for(uint32 p=0; p<Npaths; p++) {
426  mName = update(x,n,p);
427  }
428 
429  /* We accumulate the number of diagonal configurations */
430  numConfig++;
431  if (path.worm.isConfigDiagonal)
432  ++numDiagonal;
433 
434  /* Every numStepsAttempted steps, we check the diagonal fraction and update the
435  * worm constant. */
436  if ( numConfig == numStepsAttempted) {
437 
438  double diagFrac = 1.0*numDiagonal / (1.0*numConfig);
439 
440  if ( (diagFrac > (targetDiagFrac-0.05)) && (diagFrac <= (targetDiagFrac+0.05)) ) {
441  cout << format("\nConverged on C0 = %8.5f\n\n") % constants()->C0();
442  /* for (int i = 0; i < diagFracVals.size(); i++) */
443  /* cout << format("%12.5f%12.5f\n") % C0Vals[i] % diagFracVals[i]; */
444  return true;
445  }
446  else {
447  cout << format("%4.2f\t%8.5f\t") % diagFrac % constants()->C0();
448 
449  /* Store the values of C0 and the diagonal fraciton */
450  C0Vals.push_back(constants()->C0());
451  diagFracVals.push_back(diagFrac);
452 
453  /* Perform an iterative linaer regression and suggest a new
454  * value */
455  constants()->setC0(linearRegressionC0());
456 
457  cout << format("%8.5f\t%5d\t%8.6f\n") % constants()->C0()
458  % path.getTrueNumParticles()
459  % (1.0*path.getTrueNumParticles()/path.boxPtr->volume);
460 
461  /* Reset the counters */
462  numDiagonal = 0;
463  numConfig = 0;
464 
465  } // Haven't converged yet
466 
467  } // numConfig == numStepsAttempted
468 
469  } // numUpdates
470 
471  return false;
472 }
473 
474 /**************************************************************************/
477 double PathIntegralMonteCarlo::linearRegressionC0() {
478 
479  auto num = diagFracVals.size();
480  double diagFrac = diagFracVals.back();
481 
482  if (num == 1) {
483 
484  sgnDiagFrac = ((targetDiagFrac-diagFrac) > 0) - ((targetDiagFrac-diagFrac) < 0);
485 
486  if (diagFrac < targetDiagFrac) {
487  /* double C0new = C0Vals.back() - shiftC0; */
488  /* return (C0new > 0.0) ? C0new : 1.0E-4; */
489  return 0.4*C0Vals.back();
490  }
491  else
492  return 1.6*C0Vals.back();
493  /* return C0Vals.back() + shiftC0; */
494  }
495  else {
496 
497  /* We first find the closest values to targetC0 */
498  /* double closestC0; */
499  /* double minDiff = 1000; */
500  /* for (int i = 0; i < num; i++) { */
501  /* double cDiff = abs(diagFracVals[i]-targetC0); */
502  /* if (cDiff < minDiff) { */
503  /* closestC0 = C0Vals[i]; */
504  /* minDiff = cDiff; */
505  /* } */
506  /* } */
507 
508  double sumX,sumY,sumX2,sumXY,sum1;
509 
510  sum1 = sumX = sumY = sumXY = sumX2 = 0.0;
511 
512  for (int i = 0; i < num; i++) {
513  sumX += C0Vals[i];
514  sumX2 += C0Vals[i]*C0Vals[i];
515  sumY += diagFracVals[i];
516  sumXY += C0Vals[i]*diagFracVals[i];
517  sum1 += 1.0;
518  }
519 
520  double denom = sum1*sumX2 - sumX*sumX;
521  double a0 = (sumY*sumX2 - sumX*sumXY)/denom;
522  double a1 = (sum1*sumXY - sumY*sumX)/denom;
523 
524  double C0guess = (targetDiagFrac-a0)/a1;
525 
526  if ((C0guess < 1E4) && ( C0guess > 1E-4) && (a1 < 0.0))
527  return C0guess;
528  else
529  {
530 
531  /* Determine if we need to alter the muFactor. */
532 
533  /* This is commented out for now, return to see if this can be
534  * improved. */
535  /* int sgn = ((targetDiagFrac-diagFrac) > 0) - ((targetDiagFrac-diagFrac) < 0); */
536  /* if (sgn == sgnDiagFrac) */
537  /* shiftC0 *= 1.618; */
538  /* else */
539  /* shiftC0 /= 1.61803399; */
540  /* sgnDiagFrac = sgn; */
541 
542  if (diagFrac < targetDiagFrac) {
543  /* double C0new = C0Vals.back() - shiftC0; */
544  /* return (C0new > 0.0) ? C0new : 1.0E-4; */
545  return (1.0/1.618)*C0Vals.back();
546  }
547  else
548  return 1.61803399*C0Vals.back();
549  /* return C0Vals.back() + shiftC0; */
550  }
551  }
552 }
553 
554 /**************************************************************************/
561 void PathIntegralMonteCarlo::equilStep(const uint32 iStep, const bool relaxC0, const bool relaxmu) {
562 
563  /* How far are we into the equilibration? */
564  double equilFrac = (1.0*iStep) / (1.0*constants()->numEqSteps());
565 
566  /* We begin by attempting to perform a purely diagonal equilibration */
567  if (equilFrac < 0.1 && !startWithState) {
568  if (iStep == 0) {
569  numRemainingSteps = constants()->numEqSteps()/10;
570  if (numRemainingSteps == 0)
571  numRemainingSteps = 1;
572  barStepSize = numRemainingSteps/44;
573  if (!barStepSize)
574  barStepSize = 1;
575  cout << "[" << std::flush;
576  numBars = 0;
577  }
579 
580  /* Output a progress bar */
581  if ((iStep > 0) && (iStep % barStepSize == 0) && (numBars < 44)) {
582  cout << "▇" << std::flush;
583  numBars++;
584  }
585 
586  if (iStep == numRemainingSteps-1) {
587  for (int nb = numBars; nb < 44; nb++)
588  cout << "▇" << std::flush;
589  cout << "] \t. Diagonal Pre-Equilibration." << endl << std::flush;
590  }
591 
592  }
593  else if ((equilFrac < 0.2) && (relaxmu || relaxC0)) {
594 
595  if (!equilODMessage) {
596  equilODMessage = true;
597  cout << "[";
598  numRemainingSteps = int(0.2*constants()->numEqSteps())-iStep;
599  barStepSize = numRemainingSteps/44;
600  if (!barStepSize)
601  barStepSize = 1;
602  numBars = 0;
603  }
604 
605  /* Output a progress bar */
606  if ((iStep % barStepSize == 0) && (numBars < 44)) {
607  cout << "▇" << std::flush;
608  numBars++;
609  }
610 
611  if (iStep == constants()->numEqSteps()/5-1) {
612  for (int nb = numBars; nb < 44; nb++)
613  cout << "▇" << std::flush;
614  cout << "] \t. Off-Diagonal Pre-Equilibration." << endl << std::flush;
615  }
616 
617  /* If we are performing any parameter relaxtion, we do some additional
618  * off-diagonal pre-equilibration */
619  for (int n = 0; n < numUpdates; n++) {
620 
621  /* Generate random number and run through all moves */
622  double x = random.rand();
623  string mName;
624  for(uint32 p=0;p<Npaths;p++){
625  mName = update(x,n,p);
626  }
627  }
628  }
629  else {
630  /* Perform possible parameter relaxation schemes */
631  if (relaxmu && !foundmu)
632  foundmu = equilStepRelaxmu();
633  else if (relaxC0 && !foundC0) {
634  foundC0 = equilStepRelaxC0();
635  }
636  /* Otherwise (or after converged) equilibrate */
637  else {
638  if (!equilMessage) {
639  equilMessage = true;
640  cout << format("[PIMCID: %s] - Equilibration Stage.") % constants()->id() << endl << "[";
641  numRemainingSteps = constants()->numEqSteps()-iStep;
642  barStepSize = numRemainingSteps/44;
643  if (!barStepSize)
644  barStepSize = 1;
645  numBars = 0;
646  }
647 
648  /* Output a progress bar */
649  if ((iStep % barStepSize == 0) && (numBars < 44)) {
650  cout << "▇" << std::flush;
651  numBars++;
652  }
653 
654  /* This is the regular equilibration portion after we have the desired
655  * value of C0 and μ. */
656  for (int n = 0; n < numUpdates; n++) {
657 
658  /* Generate random number and run through all moves */
659  double x = random.rand();
660  string mName;
661  for(uint32 p=0;p<Npaths;p++){
662  mName = update(x,n,p);
663  }
664  } // numUpdates
665  }
666 
667  } // equilfrac > 0.2
668 
669  /* Save a state every binsize equilibrium steps provided we are diagonal*/
670  if ( path.worm.isConfigDiagonal && (iStep > 0) && (iStep % binSize) == 0)
671  saveState();
672 
673  if ((iStep == constants()->numEqSteps()-1) && equilMessage){
674  for (int nb = numBars; nb < 44; nb++)
675  cout << "▇" << std::flush;
676  cout << "]" << endl;
677  }
678 }
679 
680 /**************************************************************************/
689 
690  string moveName;
691 
692  /* perform updates on each set of paths */
693  for (uint32 pIdx=0; pIdx<Npaths; pIdx++) {
694 
695  /* We run through all moves, making sure that we could have touched each bead at least once */
696  for (int n = 0; n < numUpdates ; n++) {
697  moveName = update(random.rand(),n,pIdx);
698  }
699 
700  /* Perform all measurements */
701  for (auto& est : estimatorPtrVec[pIdx])
702  est.sample();
703 
704  /* Every binSize measurements, we output averages to disk and record the
705  * state of the simulation on disk. */
706  if (estimatorPtrVec[pIdx].size() > 0){
707  if (estimatorPtrVec[pIdx].front().getNumAccumulated() >= binSize) {
708 
709  for (auto& est : estimatorPtrVec[pIdx]) {
710  /* cout << est.getNumAccumulated() << endl; */
711  if (est.getNumAccumulated() >= binSize)
712  est.output();
713  }
714  if(Npaths==1)
715  saveState();
716  if (pIdx == 0)
717  ++numStoredBins;
718  }
719  }
720  }
721 
723  if(estimatorPtrVec.size() > Npaths) {
724 
725  /* Multi-Path estimators are at the end of the estimator vectors */
726  for (auto& est : estimatorPtrVec.back())
727  est.sample();
728 
729  /* Every binSize measurements, we output averages to disk and record the
730  * state of the simulation on disk. */
731  if (estimatorPtrVec.back().front().getNumAccumulated() >= binSize) {
732 
733  for (auto& est : estimatorPtrVec.back())
734  if (est.getNumAccumulated() >= binSize)
735  est.output();
736 
737  /* Save to disk or store a state file */
738  saveState();
739 
740  if (estimator.size() == 0)
741  ++numStoredBins;
742  }
743  }
744 }
745 
746 /**************************************************************************/
753 
754  /* Output the acceptance data to the log file */
755  communicate()->file("log")->stream() << endl;
756  communicate()->file("log")->stream() << endl;
757 
758  communicate()->file("log")->stream() << "---------- Begin Acceptance Data ---------------" << endl;
759  communicate()->file("log")->stream() << endl;
760  communicate()->file("log")->stream() << format("%-29s\t:\t%7.5f\n") % "Total Rate"
761  % move.front().getTotAcceptanceRatio();
762  communicate()->file("log")->stream() << endl;
763 
764  /* Ouptut all the move acceptance information to disk */
765  string moveName;
766  for (auto &cmove : move){
767 
768  moveName = cmove.getName();
769 
770  /* We only output levels for those moves which have a variable size */
771  if (cmove.variableLength) {
772  for (int n = 0; n <= constants()->b(); n++) {
773  communicate()->file("log")->stream() << format("%-12s Level %-10d\t:\t%7.5f\t(%d/%d)\n")
774  % moveName % n % cmove.getAcceptanceRatioLevel(n)
775  % cmove.numAcceptedLevel(n) % cmove.numAttemptedLevel(n);
776  }
777  }
778  communicate()->file("log")->stream() << format("%-29s\t:\t%7.5f\t(%d/%d)\n") % moveName
779  % cmove.getAcceptanceRatio() % cmove.numAccepted % cmove.numAttempted;
780  communicate()->file("log")->stream() << endl;
781 
782  }
783  communicate()->file("log")->stream() << "---------- End Acceptance Data -----------------" << endl;
784 
785  communicate()->file("log")->stream() << endl;
786  communicate()->file("log")->stream() << endl;
787 
788  /* Output the estimator statistics to the log file */
789  communicate()->file("log")->stream() << "---------- Begin Estimator Data ----------------" << endl;
790  communicate()->file("log")->stream() << endl;
791  for (auto &cestimator : estimator) {
792  communicate()->file("log")->stream() << format("%-33s\t:\t%16d\t%16d\n") % cestimator.getName()
793  % cestimator.getNumSampled() % cestimator.getTotNumAccumulated();
794 
795  }
796  communicate()->file("log")->stream() << endl;
797  communicate()->file("log")->stream() << "---------- End Estimator Data ------------------" << endl;
798 }
799 
800 /**************************************************************************/
804 void PathIntegralMonteCarlo::saveState(const int finalSave) {
805 
806  stringstream stateStrStrm;
807 
808  /* We only update the string during the simulation */
809  if (!finalSave) {
810 
811  for(uint32 pIdx=0; pIdx<Npaths; pIdx++){
812 
813  stateStrStrm.str("");
814 
815  /* leftpack and update the lookup table arrays */
816  pathPtrVec[pIdx].leftPack();
817  pathPtrVec[pIdx].lookup.updateGrid(path);
818 
819  /* We First write the current total number of world lines */
820  stateStrStrm << pathPtrVec[pIdx].getNumParticles() << endl;
821 
822  /* Now write the total acceptance information for all moves */
823  stateStrStrm << format("%16d\t%16d\n")
824  % movePtrVec[pIdx].front().totAccepted % movePtrVec[pIdx].front().totAttempted;
825 
826  /* Now record the individual move acceptance information,
827  * first for the diagonal, then off-diagonal*/
828  for (const auto &cmove : movePtrVec[pIdx])
829  stateStrStrm << format("%16d\t%16d\n") % cmove.numAccepted % cmove.numAttempted;
830 
831  /* Output the estimator sampling information */
832  for (const auto &cestimator : estimatorPtrVec[pIdx])
833  stateStrStrm << format("%16d\t%16d\n") % cestimator.getTotNumAccumulated()
834  % cestimator.getNumSampled();
835 
836  /* Now we output the actual path and worldline data */
837  stateStrStrm << setprecision(16) << pathPtrVec[pIdx].beads << endl;
838  stateStrStrm << pathPtrVec[pIdx].nextLink << endl;
839  stateStrStrm << pathPtrVec[pIdx].prevLink << endl;
840 
841  /* Output the worm data */
842  stateStrStrm << pathPtrVec[pIdx].worm.beads << endl;
843 
844  /* Save the state of the random number generator */
845  uint32 randomState[random.SAVE];
846  random.save(randomState);
847  for (int i = 0; i < random.SAVE; i++)
848  stateStrStrm << randomState[i] << " ";
849  stateStrStrm << endl;
850 
851  /* store the state string */
852  stateStrings[pIdx] = stateStrStrm.str();
853 
854  } // for pidx
855  }
856 
857  /* Save the state file to disk */
858  string stateFileName;
859  if (constants()->saveStateFiles() || finalSave) {
860 
861  for(uint32 pIdx=0; pIdx<Npaths; pIdx++) {
862 
863  stateFileName = "state";
864  if(pIdx > 0)
865  stateFileName += str(format("%d") % (pIdx+1));
866 
867  /* Prepare the state file for writing */
868  communicate()->file(stateFileName.c_str())->reset();
869 
870  /* Write the stateString to disk */
871  communicate()->file(stateFileName.c_str())->stream() << stateStrings[pIdx];
872 
873  /* Rename and copy the file. */
874  communicate()->file(stateFileName.c_str())->rename();
875  }
876  }
877 }
878 
879 /**************************************************************************/
882 void PathIntegralMonteCarlo::loadClassicalState(Array <dVec,2> &tempBeads,
883  Array <unsigned int, 2> &tempWormBeads, int numWorldLines) {
884 
885  /* We go through each active worldline and create a new classical
886  * configuration */
887  int ptcl;
888  beadLocator beadIndex;
889 
890  for(uint32 pIdx=0; pIdx<Npaths; pIdx++){
891  ptcl = 0;
892  for (int n = 0; n < numWorldLines; n++) {
893  beadIndex = 0,n;
894 
895  /* Check if the bead is on */
896  if (tempWormBeads(beadIndex)) {
897 
898  /* Assign the classical configuration */
899  pathPtrVec[pIdx].beads(Range::all(),ptcl) = tempBeads(beadIndex);
900  pathPtrVec[pIdx].worm.beads(Range::all(),ptcl) = 1;
901  ptcl++;
902  }
903  }
904  }
905 }
906 
907 /**************************************************************************/
910 void PathIntegralMonteCarlo::loadQuantumState(Array <dVec,2> &tempBeads,
911  Array <beadLocator,2> &tempNextLink, Array <beadLocator,2> &tempPrevLink,
912  int numTimeSlices, int tempNumWorldLines) {
913 
914  /* Prevent double counting of worldlines */
915  Array <bool, 1> doBead(tempNumWorldLines);
916 
917  beadLocator startBead,beadIndex;
918  beadLocator newStartBead;
919  int ptcl;
920  int slice;
921 
922  for(uint32 pIdx=0; pIdx<Npaths; pIdx++) {
923 
924  newStartBead = 0,0;
925  ptcl = 0;
926  slice = 0;
927  doBead = true;
928 
929  /* Now we iterate through each worldline exactly once */
930  for (int n = 0; n < tempNumWorldLines; n++) {
931 
932  /* The initial bead to be moved */
933  startBead = 0,n;
934 
935  /* We make sure we don't try to touch the same worldline twice */
936  if (doBead(n)) {
937 
938  beadIndex = startBead;
939 
940  /* The world line length, we simply advance until we have looped back on
941  * ourselves. */
942  slice = 0;
943  newStartBead = slice,ptcl;
944  do {
945  /* We turn off any zero-slice beads we have touched */
946  if (beadIndex[0]==0)
947  doBead(beadIndex[1]) = false;
948 
949  pathPtrVec[pIdx].beads(slice % numTimeSlices,ptcl) = tempBeads(beadIndex);
950  pathPtrVec[pIdx].worm.beads(slice % numTimeSlices,ptcl) = 1;
951 
952  beadIndex = tempNextLink(beadIndex);
953  ++slice;
954 
955  /* Do a forward reconnection, provided we are not at the
956  * last bead */
957  if ( ((slice % numTimeSlices) == 0) && !all(beadIndex==startBead)) {
958  pathPtrVec[pIdx].nextLink(numTimeSlices-1,ptcl) = 0,ptcl+1;
959  pathPtrVec[pIdx].prevLink(0,ptcl+1) = numTimeSlices-1,ptcl;
960  ++ptcl;
961  }
962  } while (!all(beadIndex==startBead));
963 
964  /* Now we have to add the remaining beads and perform the final
965  * reconnection */
966  for (int tslice = (slice % numTimeSlices); tslice < numTimeSlices; tslice++) {
967  pathPtrVec[pIdx].beads(tslice,ptcl) = tempBeads(beadIndex);
968  pathPtrVec[pIdx].worm.beads(tslice,ptcl) = 1;
969  }
970  pathPtrVec[pIdx].nextLink(numTimeSlices-1,ptcl) = newStartBead;
971  pathPtrVec[pIdx].prevLink(newStartBead) = numTimeSlices-1,ptcl;
972  ++ptcl;
973 
974  } // doBead
975  } // n
976  } // pIdx
977 
978  /* Free local memory */
979  doBead.free();
980 
981 }
982 
983 /**************************************************************************/
986 void PathIntegralMonteCarlo::loadState() {
987 
988  string tempString;
989 
990  string fileInitStr = "init";
991 
992  for( uint32 pIdx=0; pIdx<Npaths; pIdx++){
993 
994  if(pIdx>0){
995  fileInitStr = str(format("init%d") % (pIdx+1));
996  }
997 
998  /* Reset the total acceptance information */
999  movePtrVec[pIdx].front().resetTotAccept();
1000 
1001  /* Reset all the individual move acceptance information */
1002  for (auto &cmove : movePtrVec[pIdx])
1003  cmove.resetAccept();
1004 
1005  /* Reset estimator sampling information */
1006  for (auto &cestimator : estimatorPtrVec[pIdx])
1007  cestimator.restart(0,0);
1008 
1009  /* We first read the former total number of world lines */
1010  int numWorldLines;
1011  int numTimeSlices = pathPtrVec[pIdx].numTimeSlices;
1012  communicate()->file(fileInitStr)->stream() >> numWorldLines;
1013 
1014  /* Now we skip through the input file until we find the beads matrix. This
1015  * is signalled by the appearance of an open bracket "(" */
1016  while (!communicate()->file(fileInitStr)->stream().eof()) {
1017  if (communicate()->file(fileInitStr)->stream().peek() != '(')
1018  getline (communicate()->file(fileInitStr)->stream(), tempString);
1019  else
1020  break;
1021  }
1022 
1023  /* Now we resize all path data members and read them from the init state file */
1024  pathPtrVec[pIdx].beads.resize(numTimeSlices,numWorldLines);
1025  pathPtrVec[pIdx].nextLink.resize(numTimeSlices,numWorldLines);
1026  pathPtrVec[pIdx].prevLink.resize(numTimeSlices,numWorldLines);
1027  pathPtrVec[pIdx].worm.beads.resize(numTimeSlices,numWorldLines);
1028 
1029  /* A temporary container for the beads array */
1030  Array <dVec,2> tempBeads;
1031 
1032  /* Get the worldline configuration */
1033  communicate()->file(fileInitStr)->stream() >> tempBeads;
1034 
1035  /* The temporary number of time slices */
1036  int tempNumTimeSlices = tempBeads.rows();
1037 
1038  if (tempNumTimeSlices == numTimeSlices) {
1039 
1040  /* Copy over the beads array */
1041  pathPtrVec[pIdx].beads = tempBeads;
1042 
1043  /* Get the link arrays */
1044  communicate()->file(fileInitStr)->stream() >> pathPtrVec[pIdx].nextLink;
1045  communicate()->file(fileInitStr)->stream() >> pathPtrVec[pIdx].prevLink;
1046 
1047  /* Repeat for the worm file */
1048  communicate()->file(fileInitStr)->stream() >> pathPtrVec[pIdx].worm.beads;
1049 
1050  } // locBeads.rows() == numTimeSlices
1051  else {
1052 
1053  /* Initialize the links */
1054  firstIndex i1;
1055  secondIndex i2;
1056  pathPtrVec[pIdx].prevLink[0] = i1-1;
1057  pathPtrVec[pIdx].prevLink[1] = i2;
1058  pathPtrVec[pIdx].nextLink[0] = i1+1;
1059  pathPtrVec[pIdx].nextLink[1] = i2;
1060 
1061  /* Here we implement the initial periodic boundary conditions in
1062  * imaginary time */
1063  pathPtrVec[pIdx].prevLink(0,Range::all())[0] = numTimeSlices-1;
1064  pathPtrVec[pIdx].nextLink(numTimeSlices-1,Range::all())[0] = 0;
1065 
1066  /* Reset the worm.beads array */
1067  pathPtrVec[pIdx].worm.beads = 0;
1068 
1069  /* Temporary containers for the links and worm beads */
1070  Array <beadLocator,2> tempNextLink;
1071  Array <beadLocator,2> tempPrevLink;
1072  Array <unsigned int,2> tempWormBeads;
1073 
1074  /* Get the link arrays and worm file */
1075  communicate()->file(fileInitStr)->stream() >> tempNextLink;
1076  communicate()->file(fileInitStr)->stream() >> tempPrevLink;
1077  communicate()->file(fileInitStr)->stream() >> tempWormBeads;
1078 
1079  /* Load a classical (all time slice positions equal) from the input
1080  * file */
1081  loadClassicalState(tempBeads,tempWormBeads, numWorldLines);
1082 
1083  /* Load a quantum initial state from a file */
1084  //if (tempNumTimeSlices < numTimeSlices) {
1085  // loadQuantumState(tempBeads,tempNextLink,tempPrevLink,
1086  // numTimeSlices,int(sum(tempWormBeads)/tempNumTimeSlices));
1087  //}
1088 
1089  /* Now we make sure all empty beads are unlinked */
1090  beadLocator beadIndex;
1091  for (int slice = 0; slice < numTimeSlices; slice++) {
1092  for (int ptcl = 0; ptcl < numWorldLines; ptcl++) {
1093  beadIndex = slice,ptcl;
1094  if (!pathPtrVec[pIdx].worm.beads(beadIndex)) {
1095  pathPtrVec[pIdx].nextLink(beadIndex) = XXX;
1096  pathPtrVec[pIdx].prevLink(beadIndex) = XXX;
1097  }
1098  }
1099  }
1100 
1101  /* Free local memory */
1102  tempPrevLink.free();
1103  tempNextLink.free();
1104  tempWormBeads.free();
1105 
1106  } // locBeads.rows() != numTimeSlices
1107 
1108  /* Load the state of the random number generator, only if we are restarting
1109  * the simulation */
1110  if (constants()->restart()) {
1111  uint32 randomState[random.SAVE];
1112  for (int i = 0; i < random.SAVE; i++)
1113  communicate()->file(fileInitStr)->stream() >> randomState[i];
1114  random.load(randomState);
1115  }
1116 
1117  /* Reset the number of on beads */
1118  pathPtrVec[pIdx].worm.resetNumBeadsOn();
1119 
1120  /* Go through all beads, and make sure they fit inside the simulation cell.
1121  * At the same time, determine how many active beads there are per slice */
1122  beadLocator beadIndex;
1123  pathPtrVec[pIdx].numBeadsAtSlice = 0;
1124  for (beadIndex[0] = 0; beadIndex[0] < numTimeSlices; ++beadIndex[0]) {
1125  for (beadIndex[1] = 0; beadIndex[1] < numWorldLines; ++beadIndex[1]) {
1126  pathPtrVec[pIdx].boxPtr->putInside(path(beadIndex));
1127  if (pathPtrVec[pIdx].worm.beadOn(beadIndex))
1128  ++pathPtrVec[pIdx].numBeadsAtSlice(beadIndex[0]);
1129  } // particles
1130  } // slices
1131 
1132  /* Reset the worm parameters */
1133  pathPtrVec[pIdx].worm.isConfigDiagonal = true;
1134  pathPtrVec[pIdx].worm.reset();
1135 
1136  /* Resize and update the lookup table arrays */
1137  pathPtrVec[pIdx].lookup.resizeList(numWorldLines);
1138  pathPtrVec[pIdx].lookup.updateGrid(path);
1139 
1140  /* Reset the broken/closed worldline vectors */
1141  pathPtrVec[pIdx].resetBrokenClosedVecs();
1142 
1143  /* Close the file */
1144  communicate()->file(fileInitStr)->close();
1145 
1146  /* Free up memory */
1147  tempBeads.free();
1148 
1149  }
1150 }
1151 
1152 /**************************************************************************/
1162 
1163  numParticles = path.getNumParticles();
1164  int numTimeSlices = path.numTimeSlices;
1165 
1166  configNumber++;
1167 
1168  /* We go through all beads, and find the start and end bead for each
1169  * worldline, adding them to an array */
1170  Array <beadLocator,1> startBead,endBead;
1171  startBead.resize(numParticles);
1172  endBead.resize(numParticles);
1173 
1174  /* We sort the output by the number of beads in a worldline */
1175  Array <int,1> wlLength(numParticles);
1176  wlLength = 0;
1177 
1178  /* This is the index-beadNumber mapping array */
1179  Array <int,2> beadNum(numTimeSlices,numParticles);
1180  beadNum = 0;
1181 
1182  int numWorldLines = 0;
1183 
1184  /* Get the list of beads that are active in the simulation */
1185  Array <bool,2> doBead(numTimeSlices,numParticles);
1186  doBead = cast<bool>(path.worm.getBeads());
1187 
1188  /* We go through each particle/worldline */
1189  int nwl = 0;
1190  int beadNumber = 0;
1191  for (int n = 0; n < numParticles; n++) {
1192 
1193  /* The initial bead to be moved */
1194  startBead(nwl) = 0,n;
1195 
1196  /* We make sure we don't try to touch the same worldline twice */
1197  if (doBead(startBead(nwl))) {
1198 
1199  /* Check to see if the start bead is on a worm. If it is, we start
1200  * at the worm tail and end at its head. */
1201  if (path.worm.foundBead(path,startBead(nwl))) {
1202  startBead(nwl) = path.worm.tail;
1203  endBead(nwl) = path.next(path.worm.head);
1204  }
1205  /* Otherwise, we loop around until we find the initial bead */
1206  else
1207  endBead(nwl) = startBead(nwl);
1208 
1209  /* Mark the beads as touched and increment the number of worldlines */
1210  beadLocator beadIndex;
1211  beadIndex = startBead(nwl);
1212  int length = 1;
1213  do {
1214  doBead(beadIndex) = false;
1215  beadNum(beadIndex) = beadNumber;
1216  beadNumber++;
1217  length++;
1218  beadIndex = path.next(beadIndex);
1219  } while (!all(beadIndex==endBead(nwl)));
1220 
1221  /* We label each trajectory by the number of particles it contains.
1222  * a worm is always given label 0 */
1223  if ((length % numTimeSlices) == 0)
1224  wlLength(nwl) = length/numTimeSlices;
1225  else
1226  wlLength(nwl) = 0;
1227 
1228  nwl++;
1229  } // doBead
1230 
1231  } // n
1232  numWorldLines = nwl;
1233 
1234  /* Output the PDB header */
1235  communicate()->file("wl")->stream() << format("REMARK [CONFIG %04d]\n") % configNumber;
1236 
1237  /* Output the unit cell information. It is always cubic. Everything is scaled by
1238  * an overall factor for better visualization. */
1239 
1240  double scale = 10.0;
1241  int i;
1242  communicate()->file("wl")->stream() << format("%-6s") % "CRYST1";
1243  for (i = 0; i < NDIM; i++)
1244  communicate()->file("wl")->stream() << format("%9.3f") % (scale*path.boxPtr->side[i]);
1245  while (i < 3) {
1246  communicate()->file("wl")->stream() << format("%9.3f") % 1.0;
1247  i++;
1248  }
1249  communicate()->file("wl")->stream() << format("%7.2f%7.2f%7.2f %-11s%4d\n") % 90.0 % 90.0 % 90.0 % "P 1" % 1;
1250 
1251  /* We output the atom block */
1252  beadLocator beadIndex;
1253  for (int n = 0; n < numWorldLines; n++) {
1254  beadIndex = startBead(n);
1255  do {
1256  /* We give the zero-time-slice bead a special name */
1257  if (beadIndex[0] == 0) {
1258  communicate()->file("wl")->stream() << format("%-6s%5d %-4s %03d %9s") % "ATOM"
1259  % beadNum(beadIndex) % "H0" % wlLength(n) % " ";
1260  }
1261  else {
1262  communicate()->file("wl")->stream() << format("%-6s%5d %-4s %03d %9s") % "ATOM"
1263  % beadNum(beadIndex) % "HE" % wlLength(n) % " ";
1264  }
1265 
1266  /* Output the coordinates in 3D */
1267  for (i = 0; i < NDIM; i++) {
1268  communicate()->file("wl")->stream() << format("%8.3f") % (scale*path(beadIndex)[i]);
1269  }
1270  while (i < 3) {
1271  communicate()->file("wl")->stream() << format("%8.3f") % 0.0;
1272  i++;
1273  }
1274  communicate()->file("wl")->stream() << format("%14s\n") % "HE";
1275 
1276  beadIndex = path.next(beadIndex);
1277  } while (!all(beadIndex==endBead(n)));
1278  }
1279  communicate()->file("wl")->stream() <<("TER\n");
1280 
1281  /* Now output the connect block */
1282  for (int n = 0; n < numWorldLines; n++) {
1283  beadIndex = startBead(n);
1284  do {
1285  communicate()->file("wl")->stream() << format("%-6s%5d") % "CONECT" % beadNum(beadIndex);
1286  beadLocator prevIndex,nextIndex;
1287  prevIndex = path.prev(beadIndex);
1288  nextIndex = path.next(beadIndex);
1289 
1290  /* We make sure that we don't connect beads linked by periodic bondary
1291  * conditions */
1292 
1293  /* Check the previous bead */
1294  if (path.worm.beadOn(prevIndex)) {
1295  dVec sep;
1296  sep = path(beadIndex) - path(prevIndex);
1297  if (dot(sep,sep) < path.boxPtr->rcut2)
1298  communicate()->file("wl")->stream() << format("%5d") % beadNum(prevIndex);
1299  }
1300 
1301  /* Now the next bead */
1302  if (path.worm.beadOn(nextIndex)) {
1303  dVec sep;
1304  sep = path(nextIndex) - path(beadIndex);
1305  if (dot(sep,sep) < path.boxPtr->rcut2)
1306  communicate()->file("wl")->stream() << format("%5d") % beadNum(nextIndex);
1307  }
1308  communicate()->file("wl")->stream() << endl;
1309 
1310  beadIndex = path.next(beadIndex);
1311  } while (!all(beadIndex==endBead(n)));
1312  }
1313  communicate()->file("wl")->stream() <<("END\n");
1314 
1315  /* Free up memory */
1316  startBead.free();
1317  endBead.free();
1318  wlLength.free();
1319  beadNum.free();
1320  doBead.free();
1321 }
1322 
1323 /**************************************************************************/
1327 void PathIntegralMonteCarlo::printWormState() {
1328 
1329  /* We make a list of all the beads contained in the worm */
1330  Array <beadLocator,1> wormBeads; // Used for debugging
1331  wormBeads.resize(path.worm.length+1);
1332  wormBeads = XXX;
1333 
1334  /* Output the worldline configuration */
1335  communicate()->file("debug")->stream() << " (" << path.getTrueNumParticles() << ")" << endl;
1336  communicate()->file("debug")->stream() << "head " << path.worm.head[0] << " " << path.worm.head[1]
1337  << " tail " << path.worm.tail[0] << " " << path.worm.tail[1]
1338  << " length " << path.worm.length
1339  << " gap " << path.worm.gap << endl;
1340 
1341  if (!path.worm.isConfigDiagonal) {
1342  beadLocator beadIndex;
1343  beadIndex = path.worm.tail;
1344  int n = 0;
1345  do {
1346  wormBeads(n) = beadIndex;
1347  beadIndex = path.next(beadIndex);
1348  ++n;
1349  } while(!all(beadIndex==path.next(path.worm.head)));
1350  }
1351 
1352  path.printWormConfig(wormBeads);
1353  path.printLinks<fstream>(communicate()->file("debug")->stream());
1354  wormBeads.free();
1355 }
1356 
1357 /**************************************************************************/
1362 
1363  string histogramDisplay = "\n";
1364 
1365  /* Setup the window of the histogram to be analyzed.*/
1366  int start,end,window;
1367  window = 5;
1368 
1369  start = N0-window;
1370  if (start < 0)
1371  start = 0;
1372  end = N0 + window;
1373 
1374  /* We make sure we haven't moved past the end of the probability
1375  * distribution array */
1376  if (end > PN.size()-1)
1377  end = PN.size()-1;
1378 
1379  double factor = 50.0/blitz::max(PN);
1380  int sumPN = 0;
1381  for (int n = start; n <= end; n++) {
1382  int numStars = int(PN(n)*factor);
1383  histogramDisplay += str(format("%03d|") % n);
1384  for (int i = 0; i < numStars; i++)
1385  histogramDisplay += "▇";
1386  histogramDisplay += "\n";
1387  sumPN += PN(n);
1388  }
1389  histogramDisplay += "\n";
1390 
1391  /* if (sumPN > bestPN) { */
1392  /* bestPN = sumPN; */
1393  /* bestmu = constants()->mu(); */
1394  /* cout << "setting mu" << endl; */
1395  /* } */
1396 
1397  firstIndex i;
1398  double aveN = (blitz::sum(i*PN)/blitz::sum(PN));
1399 
1400  double diffAveN = abs(N0-aveN);
1401 
1402  if (diffAveN < bestDiffAveN) {
1403  bestDiffAveN = diffAveN;
1404  bestmu = constants()->mu();
1405  }
1406 
1407  inWindow = (sumPN > 0);
1408  if (bestPN == 0)
1409  inWindow = true;
1410 
1411  return histogramDisplay;
1412 }
File * file(string type)
Get method returning file object.
Definition: communicator.h:85
void setmu(double _mu)
Set the value of the chemical potential.
Definition: constants.h:121
double T() const
Get temperature.
Definition: constants.h:41
double mu() const
Get chemical potential.
Definition: constants.h:43
void shiftCoMDelta(double frac)
Shift the CoM move size.
Definition: constants.h:129
void shiftDisplaceDelta(double frac)
Shift the displace move size.
Definition: constants.h:130
void setC0(double _C0)
Set the value of C0.
Definition: constants.h:127
string id()
Get simulation UUID.
Definition: constants.h:102
double C0() const
Get worm factor C0.
Definition: constants.h:49
int b()
Get bisection level.
Definition: constants.h:98
double comDelta() const
Get center of mass shift.
Definition: constants.h:53
uint32 numEqSteps()
Get the number of equilibration steps.
Definition: constants.h:103
int initialNumParticles()
Get initial number of particles.
Definition: constants.h:100
double volume
The volume of the container in A^3.
Definition: container.h:35
double rcut2
The smallest separation squared.
Definition: container.h:36
dVec side
The linear dimensions of the box.
Definition: container.h:31
void reset()
Reset a file.
void rename()
Rename a file.
void close()
Close the file.
void outputPDB()
Output the worldline configuration to disk using PDB , suitable for plotting using vmd.
Definition: pimc.cpp:1161
~PathIntegralMonteCarlo()
Destructor.
Definition: pimc.cpp:164
bool equilStepRelaxC0()
Relax the worm constant C0 until we have found the desired diagonal fraction.
Definition: pimc.cpp:412
bool equilStepRelaxmu()
Relax the chemical potential to find a target number of particles.
Definition: pimc.cpp:292
int prevNumCoMAttempted
Number of Center of Mass moves attempted.
Definition: pimc.h:68
int numDisplaceAttempted
Number of equil Displace moves.
Definition: pimc.h:70
int numDisplaceAccepted
Number of equil Displace moves accepted.
Definition: pimc.h:71
void saveState(const int finalSave=0)
Save the state of the simulation to disk, including all path, worm, move and estimator data.
Definition: pimc.cpp:804
int numConfig
Number of configurations;.
Definition: pimc.h:66
void equilStep(const uint32, const bool, const bool)
Equilibration.
Definition: pimc.cpp:561
void finalOutput()
Output simulation statistics to disk.
Definition: pimc.cpp:752
void step()
PIMC step.
Definition: pimc.cpp:688
string printHistogram()
Output a histogram to the terminal.
Definition: pimc.cpp:1361
int numStepsAttempted
Number of steps for relaxing C0.
Definition: pimc.h:74
PathIntegralMonteCarlo(boost::ptr_vector< Path > &, MTRand &, boost::ptr_vector< move_vector > &, boost::ptr_vector< estimator_vector > &, const bool, uint32 binSize=100)
Constructor.
Definition: pimc.cpp:27
int numCoMAttempted
Number of Center of Mass moves.
Definition: pimc.h:67
int numCoMAccepted
Number of equil CoM moves accepted.
Definition: pimc.h:69
int numNAttempted
The number of particle measurements.
Definition: pimc.h:73
void equilStepDiagonal()
Diagonal Equilibration.
Definition: pimc.cpp:198
int numDiagonal
Number of consecutive diagonal configs.
Definition: pimc.h:65
int numStoredBins
Number of stored estimators.
Definition: pimc.h:64
int numMuAttempted
Number of moves between mu adjustments.
Definition: pimc.h:72
int getNumParticles() const
Get the size of the worldline array.
Definition: path.h:51
void printWormConfig(Array< beadLocator, 1 > &)
Used when debugging worm configurations.
Definition: path.cpp:743
const int numTimeSlices
A local constant copy of the number of time slices.
Definition: path.h:37
void printLinks(Tstream &)
Output bead-link info, used for debugging.
Definition: path.h:250
beadLocator & next(int slice, int ptcl)
Move one link forward in imaginary time.
Definition: path.h:86
const Container * boxPtr
A constant reference to the container class.
Definition: path.h:43
Worm worm
Details on the worm.
Definition: path.h:44
beadLocator & prev(int slice, int ptcl)
Move one link backward in imaginary time.
Definition: path.h:95
int getTrueNumParticles() const
The number of active particles.
Definition: path.h:54
bool isConfigDiagonal
Stores the diagonality of the configuration.
Definition: worm.h:39
int gap
numTimeSlices - length
Definition: worm.h:38
beadLocator tail
The coordinates of the worm tail.
Definition: worm.h:32
beadLocator head
The coordinates of the worm head.
Definition: worm.h:31
int beadOn(int, int) const
Safely get a bead (int indexed)
Definition: worm.h:148
bool foundBead(const Path &, const beadLocator &)
Test to see if a supplied bead is located on a worm.
Definition: worm.cpp:124
int getNumBeadsOn() const
Return the number of active beads.
Definition: worm.h:88
const Array< unsigned int, 2 > & getBeads() const
Return the bead list.
Definition: worm.h:84
int length
The length of the worm.
Definition: worm.h:37
Ttype & max(Ttype &x, Ttype &y)
Maximum of two inputs.
Definition: common.h:146
#define NDIM
Number of spatial dimnsions.
Definition: common.h:71
unsigned long uint32
Unsigned integer type, at least 32 bits.
Definition: common.h:105
TinyVector< int, 2 > beadLocator
time-slice,bead-number world line index
Definition: common.h:117
#define EPS
A small number.
Definition: common.h:94
Ttype & min(Ttype &x, Ttype &y)
Minimum of two inputs.
Definition: common.h:142
TinyVector< double, NDIM > dVec
A NDIM-vector of type double.
Definition: common.h:111
#define XXX
Used to refer to a nonsense beadIndex.
Definition: common.h:98
Communicator * communicate()
Global public access to the communcator singleton.
Definition: communicator.h:121
ConstantParameters * constants()
Global public access to the constants.
Definition: constants.h:201
LookupTable class definition.
Move class definitions.
Path class definition.
PathIntegralMonteCarlo class definition.