ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/trunk/src/rnemd/RNEMD.cpp
Revision: 2026
Committed: Wed Oct 22 12:23:59 2014 UTC (10 years, 6 months ago) by gezelter
File size: 78086 byte(s)
Log Message:
Starting to add support for UniformGradient. 
Changed Vector3d input type to a more general std::vector<RealType> input.  This change alters RNEMD and UniformField inputs.

File Contents

# User Rev Content
1 gezelter 1329 /*
2     * Copyright (c) 2005 The University of Notre Dame. All Rights Reserved.
3     *
4     * The University of Notre Dame grants you ("Licensee") a
5     * non-exclusive, royalty free, license to use, modify and
6     * redistribute this software in source and binary code form, provided
7     * that the following conditions are met:
8     *
9 gezelter 1390 * 1. Redistributions of source code must retain the above copyright
10 gezelter 1329 * notice, this list of conditions and the following disclaimer.
11     *
12 gezelter 1390 * 2. Redistributions in binary form must reproduce the above copyright
13 gezelter 1329 * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the
15     * distribution.
16     *
17     * This software is provided "AS IS," without a warranty of any
18     * kind. All express or implied conditions, representations and
19     * warranties, including any implied warranty of merchantability,
20     * fitness for a particular purpose or non-infringement, are hereby
21     * excluded. The University of Notre Dame and its licensors shall not
22     * be liable for any damages suffered by licensee as a result of
23     * using, modifying or distributing the software or its
24     * derivatives. In no event will the University of Notre Dame or its
25     * licensors be liable for any lost revenue, profit or data, or for
26     * direct, indirect, special, consequential, incidental or punitive
27     * damages, however caused and regardless of the theory of liability,
28     * arising out of the use of or inability to use software, even if the
29     * University of Notre Dame has been advised of the possibility of
30     * such damages.
31 gezelter 1390 *
32     * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
33     * research, please cite the appropriate papers when you publish your
34     * work. Good starting points are:
35     *
36     * [1] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
37     * [2] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
38 gezelter 1879 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
39 gezelter 1722 * [4] Vardeman & Gezelter, in progress (2009).
40 gezelter 1329 */
41 gezelter 1938 #ifdef IS_MPI
42     #include <mpi.h>
43     #endif
44 gezelter 1329
45 skuang 1368 #include <cmath>
46 gezelter 1879 #include <sstream>
47     #include <string>
48    
49 gezelter 1731 #include "rnemd/RNEMD.hpp"
50 gezelter 1332 #include "math/Vector3.hpp"
51 gezelter 1722 #include "math/Vector.hpp"
52 gezelter 1329 #include "math/SquareMatrix3.hpp"
53 skuang 1368 #include "math/Polynomial.hpp"
54 gezelter 1329 #include "primitives/Molecule.hpp"
55     #include "primitives/StuntDouble.hpp"
56 gezelter 1390 #include "utils/PhysicalConstants.hpp"
57 gezelter 1332 #include "utils/Tuple.hpp"
58 gezelter 1879 #include "brains/Thermo.hpp"
59     #include "math/ConvexHull.hpp"
60 gezelter 1329
61 gezelter 1789 #ifdef _MSC_VER
62     #define isnan(x) _isnan((x))
63     #define isinf(x) (!_finite(x) && !_isnan(x))
64     #endif
65    
66 gezelter 1350 #define HONKING_LARGE_VALUE 1.0e10
67 gezelter 1329
68 gezelter 1629 using namespace std;
69 gezelter 1390 namespace OpenMD {
70 gezelter 1329
71 gezelter 1629 RNEMD::RNEMD(SimInfo* info) : info_(info), evaluator_(info), seleMan_(info),
72 gezelter 1879 evaluatorA_(info), seleManA_(info),
73     commonA_(info), evaluatorB_(info),
74     seleManB_(info), commonB_(info),
75     hasData_(false), hasDividingArea_(false),
76 gezelter 1629 usePeriodicBoundaryConditions_(info->getSimParams()->getUsePeriodicBoundaryConditions()) {
77 skuang 1368
78 gezelter 1773 trialCount_ = 0;
79 skuang 1368 failTrialCount_ = 0;
80     failRootCount_ = 0;
81    
82 gezelter 1879 Globals* simParams = info->getSimParams();
83 gezelter 1731 RNEMDParameters* rnemdParams = simParams->getRNEMDParameters();
84 skuang 1330
85 gezelter 1776 doRNEMD_ = rnemdParams->getUseRNEMD();
86     if (!doRNEMD_) return;
87    
88 gezelter 1773 stringToMethod_["Swap"] = rnemdSwap;
89     stringToMethod_["NIVS"] = rnemdNIVS;
90     stringToMethod_["VSS"] = rnemdVSS;
91 skuang 1330
92 gezelter 1773 stringToFluxType_["KE"] = rnemdKE;
93     stringToFluxType_["Px"] = rnemdPx;
94     stringToFluxType_["Py"] = rnemdPy;
95     stringToFluxType_["Pz"] = rnemdPz;
96 gezelter 1777 stringToFluxType_["Pvector"] = rnemdPvector;
97 gezelter 1879 stringToFluxType_["Lx"] = rnemdLx;
98     stringToFluxType_["Ly"] = rnemdLy;
99     stringToFluxType_["Lz"] = rnemdLz;
100     stringToFluxType_["Lvector"] = rnemdLvector;
101 gezelter 1773 stringToFluxType_["KE+Px"] = rnemdKePx;
102     stringToFluxType_["KE+Py"] = rnemdKePy;
103     stringToFluxType_["KE+Pvector"] = rnemdKePvector;
104 gezelter 1879 stringToFluxType_["KE+Lx"] = rnemdKeLx;
105     stringToFluxType_["KE+Ly"] = rnemdKeLy;
106     stringToFluxType_["KE+Lz"] = rnemdKeLz;
107     stringToFluxType_["KE+Lvector"] = rnemdKeLvector;
108 gezelter 1773
109 jmarr 1728 runTime_ = simParams->getRunTime();
110     statusTime_ = simParams->getStatusTime();
111    
112 gezelter 1773 const string methStr = rnemdParams->getMethod();
113     bool hasFluxType = rnemdParams->haveFluxType();
114    
115 gezelter 1879 rnemdObjectSelection_ = rnemdParams->getObjectSelection();
116    
117 gezelter 1773 string fluxStr;
118     if (hasFluxType) {
119     fluxStr = rnemdParams->getFluxType();
120     } else {
121     sprintf(painCave.errMsg,
122     "RNEMD: No fluxType was set in the md file. This parameter,\n"
123     "\twhich must be one of the following values:\n"
124 gezelter 1879 "\tKE, Px, Py, Pz, Pvector, Lx, Ly, Lz, Lvector,\n"
125     "\tKE+Px, KE+Py, KE+Pvector, KE+Lx, KE+Ly, KE+Lz, KE+Lvector\n"
126 gezelter 1777 "\tmust be set to use RNEMD\n");
127 gezelter 1773 painCave.isFatal = 1;
128     painCave.severity = OPENMD_ERROR;
129     simError();
130     }
131    
132     bool hasKineticFlux = rnemdParams->haveKineticFlux();
133     bool hasMomentumFlux = rnemdParams->haveMomentumFlux();
134     bool hasMomentumFluxVector = rnemdParams->haveMomentumFluxVector();
135 gezelter 1879 bool hasAngularMomentumFlux = rnemdParams->haveAngularMomentumFlux();
136     bool hasAngularMomentumFluxVector = rnemdParams->haveAngularMomentumFluxVector();
137     hasSelectionA_ = rnemdParams->haveSelectionA();
138     hasSelectionB_ = rnemdParams->haveSelectionB();
139 gezelter 1773 bool hasSlabWidth = rnemdParams->haveSlabWidth();
140     bool hasSlabACenter = rnemdParams->haveSlabACenter();
141     bool hasSlabBCenter = rnemdParams->haveSlabBCenter();
142 gezelter 1879 bool hasSphereARadius = rnemdParams->haveSphereARadius();
143     hasSphereBRadius_ = rnemdParams->haveSphereBRadius();
144     bool hasCoordinateOrigin = rnemdParams->haveCoordinateOrigin();
145 gezelter 1773 bool hasOutputFileName = rnemdParams->haveOutputFileName();
146     bool hasOutputFields = rnemdParams->haveOutputFields();
147    
148     map<string, RNEMDMethod>::iterator i;
149     i = stringToMethod_.find(methStr);
150     if (i != stringToMethod_.end())
151     rnemdMethod_ = i->second;
152     else {
153     sprintf(painCave.errMsg,
154     "RNEMD: The current method,\n"
155     "\t\t%s is not one of the recognized\n"
156     "\texchange methods: Swap, NIVS, or VSS\n",
157     methStr.c_str());
158     painCave.isFatal = 1;
159     painCave.severity = OPENMD_ERROR;
160     simError();
161     }
162    
163     map<string, RNEMDFluxType>::iterator j;
164     j = stringToFluxType_.find(fluxStr);
165     if (j != stringToFluxType_.end())
166     rnemdFluxType_ = j->second;
167     else {
168     sprintf(painCave.errMsg,
169     "RNEMD: The current fluxType,\n"
170     "\t\t%s\n"
171     "\tis not one of the recognized flux types.\n",
172     fluxStr.c_str());
173     painCave.isFatal = 1;
174     painCave.severity = OPENMD_ERROR;
175     simError();
176     }
177    
178     bool methodFluxMismatch = false;
179     bool hasCorrectFlux = false;
180     switch(rnemdMethod_) {
181     case rnemdSwap:
182     switch (rnemdFluxType_) {
183     case rnemdKE:
184     hasCorrectFlux = hasKineticFlux;
185     break;
186     case rnemdPx:
187     case rnemdPy:
188     case rnemdPz:
189     hasCorrectFlux = hasMomentumFlux;
190     break;
191     default :
192     methodFluxMismatch = true;
193     break;
194     }
195     break;
196     case rnemdNIVS:
197     switch (rnemdFluxType_) {
198     case rnemdKE:
199     case rnemdRotKE:
200     case rnemdFullKE:
201     hasCorrectFlux = hasKineticFlux;
202     break;
203     case rnemdPx:
204     case rnemdPy:
205     case rnemdPz:
206     hasCorrectFlux = hasMomentumFlux;
207     break;
208     case rnemdKePx:
209     case rnemdKePy:
210     hasCorrectFlux = hasMomentumFlux && hasKineticFlux;
211     break;
212     default:
213     methodFluxMismatch = true;
214     break;
215     }
216     break;
217     case rnemdVSS:
218     switch (rnemdFluxType_) {
219     case rnemdKE:
220     case rnemdRotKE:
221     case rnemdFullKE:
222     hasCorrectFlux = hasKineticFlux;
223     break;
224     case rnemdPx:
225     case rnemdPy:
226     case rnemdPz:
227     hasCorrectFlux = hasMomentumFlux;
228     break;
229 gezelter 1879 case rnemdLx:
230     case rnemdLy:
231     case rnemdLz:
232     hasCorrectFlux = hasAngularMomentumFlux;
233     break;
234 gezelter 1773 case rnemdPvector:
235     hasCorrectFlux = hasMomentumFluxVector;
236 gezelter 1777 break;
237 gezelter 1879 case rnemdLvector:
238     hasCorrectFlux = hasAngularMomentumFluxVector;
239     break;
240 gezelter 1773 case rnemdKePx:
241     case rnemdKePy:
242     hasCorrectFlux = hasMomentumFlux && hasKineticFlux;
243     break;
244 gezelter 1879 case rnemdKeLx:
245     case rnemdKeLy:
246     case rnemdKeLz:
247     hasCorrectFlux = hasAngularMomentumFlux && hasKineticFlux;
248     break;
249 gezelter 1773 case rnemdKePvector:
250     hasCorrectFlux = hasMomentumFluxVector && hasKineticFlux;
251     break;
252 gezelter 1879 case rnemdKeLvector:
253     hasCorrectFlux = hasAngularMomentumFluxVector && hasKineticFlux;
254     break;
255 gezelter 1773 default:
256     methodFluxMismatch = true;
257     break;
258     }
259     default:
260     break;
261     }
262    
263     if (methodFluxMismatch) {
264     sprintf(painCave.errMsg,
265     "RNEMD: The current method,\n"
266     "\t\t%s\n"
267     "\tcannot be used with the current flux type, %s\n",
268     methStr.c_str(), fluxStr.c_str());
269     painCave.isFatal = 1;
270     painCave.severity = OPENMD_ERROR;
271     simError();
272     }
273     if (!hasCorrectFlux) {
274     sprintf(painCave.errMsg,
275 gezelter 1777 "RNEMD: The current method, %s, and flux type, %s,\n"
276 gezelter 1773 "\tdid not have the correct flux value specified. Options\n"
277 gezelter 1879 "\tinclude: kineticFlux, momentumFlux, angularMomentumFlux,\n"
278     "\tmomentumFluxVector, and angularMomentumFluxVector.\n",
279 gezelter 1773 methStr.c_str(), fluxStr.c_str());
280     painCave.isFatal = 1;
281     painCave.severity = OPENMD_ERROR;
282     simError();
283     }
284    
285     if (hasKineticFlux) {
286 gezelter 1777 // convert the kcal / mol / Angstroms^2 / fs values in the md file
287     // into amu / fs^3:
288     kineticFlux_ = rnemdParams->getKineticFlux()
289     * PhysicalConstants::energyConvert;
290 gezelter 1773 } else {
291     kineticFlux_ = 0.0;
292     }
293     if (hasMomentumFluxVector) {
294 gezelter 2026 std::vector<RealType> mf = rnemdParams->getMomentumFluxVector();
295     if (mf.size() != 3) {
296     sprintf(painCave.errMsg,
297     "RNEMD: Incorrect number of parameters specified for momentumFluxVector.\n"
298     "\tthere should be 3 parameters, but %lu were specified.\n",
299     mf.size());
300     painCave.isFatal = 1;
301     simError();
302     }
303     momentumFluxVector_.x() = mf[0];
304     momentumFluxVector_.y() = mf[1];
305     momentumFluxVector_.z() = mf[2];
306 gezelter 1773 } else {
307     momentumFluxVector_ = V3Zero;
308     if (hasMomentumFlux) {
309     RealType momentumFlux = rnemdParams->getMomentumFlux();
310     switch (rnemdFluxType_) {
311     case rnemdPx:
312     momentumFluxVector_.x() = momentumFlux;
313     break;
314     case rnemdPy:
315     momentumFluxVector_.y() = momentumFlux;
316     break;
317     case rnemdPz:
318     momentumFluxVector_.z() = momentumFlux;
319     break;
320     case rnemdKePx:
321     momentumFluxVector_.x() = momentumFlux;
322     break;
323     case rnemdKePy:
324     momentumFluxVector_.y() = momentumFlux;
325     break;
326     default:
327     break;
328     }
329 gezelter 1879 }
330     if (hasAngularMomentumFluxVector) {
331 gezelter 2026 std::vector<RealType> amf = rnemdParams->getAngularMomentumFluxVector();
332     if (amf.size() != 3) {
333     sprintf(painCave.errMsg,
334     "RNEMD: Incorrect number of parameters specified for angularMomentumFluxVector.\n"
335     "\tthere should be 3 parameters, but %lu were specified.\n",
336     amf.size());
337     painCave.isFatal = 1;
338     simError();
339     }
340     angularMomentumFluxVector_.x() = amf[0];
341     angularMomentumFluxVector_.y() = amf[1];
342     angularMomentumFluxVector_.z() = amf[2];
343 gezelter 1879 } else {
344     angularMomentumFluxVector_ = V3Zero;
345     if (hasAngularMomentumFlux) {
346     RealType angularMomentumFlux = rnemdParams->getAngularMomentumFlux();
347     switch (rnemdFluxType_) {
348     case rnemdLx:
349     angularMomentumFluxVector_.x() = angularMomentumFlux;
350     break;
351     case rnemdLy:
352     angularMomentumFluxVector_.y() = angularMomentumFlux;
353     break;
354     case rnemdLz:
355     angularMomentumFluxVector_.z() = angularMomentumFlux;
356     break;
357     case rnemdKeLx:
358     angularMomentumFluxVector_.x() = angularMomentumFlux;
359     break;
360     case rnemdKeLy:
361     angularMomentumFluxVector_.y() = angularMomentumFlux;
362     break;
363     case rnemdKeLz:
364     angularMomentumFluxVector_.z() = angularMomentumFlux;
365     break;
366     default:
367     break;
368     }
369     }
370     }
371 gezelter 1773
372 gezelter 1879 if (hasCoordinateOrigin) {
373 gezelter 2026 std::vector<RealType> co = rnemdParams->getCoordinateOrigin();
374     if (co.size() != 3) {
375     sprintf(painCave.errMsg,
376     "RNEMD: Incorrect number of parameters specified for coordinateOrigin.\n"
377     "\tthere should be 3 parameters, but %lu were specified.\n",
378     co.size());
379     painCave.isFatal = 1;
380     simError();
381     }
382     coordinateOrigin_.x() = co[0];
383     coordinateOrigin_.y() = co[1];
384     coordinateOrigin_.z() = co[2];
385 gezelter 1879 } else {
386     coordinateOrigin_ = V3Zero;
387     }
388 skuang 1341
389 gezelter 1879 // do some sanity checking
390 gezelter 1801
391 gezelter 1879 int selectionCount = seleMan_.getSelectionCount();
392 skuang 1341
393 gezelter 1879 int nIntegrable = info->getNGlobalIntegrableObjects();
394 skuang 1330
395 gezelter 1879 if (selectionCount > nIntegrable) {
396     sprintf(painCave.errMsg,
397     "RNEMD: The current objectSelection,\n"
398     "\t\t%s\n"
399     "\thas resulted in %d selected objects. However,\n"
400     "\tthe total number of integrable objects in the system\n"
401     "\tis only %d. This is almost certainly not what you want\n"
402     "\tto do. A likely cause of this is forgetting the _RB_0\n"
403     "\tselector in the selection script!\n",
404     rnemdObjectSelection_.c_str(),
405     selectionCount, nIntegrable);
406     painCave.isFatal = 0;
407     painCave.severity = OPENMD_WARNING;
408     simError();
409     }
410 gezelter 1774
411 gezelter 1879 areaAccumulator_ = new Accumulator();
412 skuang 1330
413 gezelter 1879 nBins_ = rnemdParams->getOutputBins();
414     binWidth_ = rnemdParams->getOutputBinWidth();
415 skuang 1368
416 gezelter 1879 data_.resize(RNEMD::ENDINDEX);
417     OutputData z;
418     z.units = "Angstroms";
419     z.title = "Z";
420     z.dataType = "RealType";
421     z.accumulator.reserve(nBins_);
422     for (int i = 0; i < nBins_; i++)
423     z.accumulator.push_back( new Accumulator() );
424     data_[Z] = z;
425     outputMap_["Z"] = Z;
426 gezelter 1722
427 gezelter 1879 OutputData r;
428     r.units = "Angstroms";
429     r.title = "R";
430     r.dataType = "RealType";
431     r.accumulator.reserve(nBins_);
432     for (int i = 0; i < nBins_; i++)
433     r.accumulator.push_back( new Accumulator() );
434     data_[R] = r;
435     outputMap_["R"] = R;
436 skuang 1368
437 gezelter 1879 OutputData temperature;
438     temperature.units = "K";
439     temperature.title = "Temperature";
440     temperature.dataType = "RealType";
441     temperature.accumulator.reserve(nBins_);
442     for (int i = 0; i < nBins_; i++)
443     temperature.accumulator.push_back( new Accumulator() );
444     data_[TEMPERATURE] = temperature;
445     outputMap_["TEMPERATURE"] = TEMPERATURE;
446 skuang 1368
447 gezelter 1879 OutputData velocity;
448     velocity.units = "angstroms/fs";
449     velocity.title = "Velocity";
450     velocity.dataType = "Vector3d";
451     velocity.accumulator.reserve(nBins_);
452     for (int i = 0; i < nBins_; i++)
453     velocity.accumulator.push_back( new VectorAccumulator() );
454     data_[VELOCITY] = velocity;
455     outputMap_["VELOCITY"] = VELOCITY;
456    
457     OutputData angularVelocity;
458     angularVelocity.units = "angstroms^2/fs";
459     angularVelocity.title = "AngularVelocity";
460 gezelter 1941 angularVelocity.dataType = "Vector3d";
461 gezelter 1879 angularVelocity.accumulator.reserve(nBins_);
462     for (int i = 0; i < nBins_; i++)
463 gezelter 1941 angularVelocity.accumulator.push_back( new VectorAccumulator() );
464 gezelter 1879 data_[ANGULARVELOCITY] = angularVelocity;
465     outputMap_["ANGULARVELOCITY"] = ANGULARVELOCITY;
466    
467     OutputData density;
468     density.units = "g cm^-3";
469     density.title = "Density";
470     density.dataType = "RealType";
471     density.accumulator.reserve(nBins_);
472     for (int i = 0; i < nBins_; i++)
473     density.accumulator.push_back( new Accumulator() );
474     data_[DENSITY] = density;
475     outputMap_["DENSITY"] = DENSITY;
476    
477     if (hasOutputFields) {
478     parseOutputFileFormat(rnemdParams->getOutputFields());
479     } else {
480     if (usePeriodicBoundaryConditions_)
481     outputMask_.set(Z);
482     else
483     outputMask_.set(R);
484     switch (rnemdFluxType_) {
485     case rnemdKE:
486     case rnemdRotKE:
487     case rnemdFullKE:
488     outputMask_.set(TEMPERATURE);
489     break;
490     case rnemdPx:
491     case rnemdPy:
492     outputMask_.set(VELOCITY);
493     break;
494     case rnemdPz:
495     case rnemdPvector:
496     outputMask_.set(VELOCITY);
497     outputMask_.set(DENSITY);
498     break;
499     case rnemdLx:
500     case rnemdLy:
501     case rnemdLz:
502     case rnemdLvector:
503     outputMask_.set(ANGULARVELOCITY);
504     break;
505     case rnemdKeLx:
506     case rnemdKeLy:
507     case rnemdKeLz:
508     case rnemdKeLvector:
509     outputMask_.set(TEMPERATURE);
510     outputMask_.set(ANGULARVELOCITY);
511     break;
512     case rnemdKePx:
513     case rnemdKePy:
514     outputMask_.set(TEMPERATURE);
515     outputMask_.set(VELOCITY);
516     break;
517     case rnemdKePvector:
518     outputMask_.set(TEMPERATURE);
519     outputMask_.set(VELOCITY);
520     outputMask_.set(DENSITY);
521     break;
522     default:
523     break;
524     }
525 gezelter 1629 }
526 gezelter 1773
527 gezelter 1879 if (hasOutputFileName) {
528     rnemdFileName_ = rnemdParams->getOutputFileName();
529     } else {
530     rnemdFileName_ = getPrefix(info->getFinalConfigFileName()) + ".rnemd";
531     }
532 gezelter 1722
533 gezelter 1879 exchangeTime_ = rnemdParams->getExchangeTime();
534 skuang 1338
535 gezelter 1879 Snapshot* currentSnap_ = info->getSnapshotManager()->getCurrentSnapshot();
536     // total exchange sums are zeroed out at the beginning:
537 skuang 1368
538 gezelter 1879 kineticExchange_ = 0.0;
539     momentumExchange_ = V3Zero;
540     angularMomentumExchange_ = V3Zero;
541 gezelter 1773
542 gezelter 1879 std::ostringstream selectionAstream;
543     std::ostringstream selectionBstream;
544    
545     if (hasSelectionA_) {
546     selectionA_ = rnemdParams->getSelectionA();
547     } else {
548     if (usePeriodicBoundaryConditions_) {
549     Mat3x3d hmat = currentSnap_->getHmat();
550    
551     if (hasSlabWidth)
552     slabWidth_ = rnemdParams->getSlabWidth();
553     else
554     slabWidth_ = hmat(2,2) / 10.0;
555    
556     if (hasSlabACenter)
557     slabACenter_ = rnemdParams->getSlabACenter();
558     else
559     slabACenter_ = 0.0;
560    
561     selectionAstream << "select wrappedz > "
562     << slabACenter_ - 0.5*slabWidth_
563     << " && wrappedz < "
564     << slabACenter_ + 0.5*slabWidth_;
565     selectionA_ = selectionAstream.str();
566     } else {
567     if (hasSphereARadius)
568     sphereARadius_ = rnemdParams->getSphereARadius();
569     else {
570     // use an initial guess to the size of the inner slab to be 1/10 the
571     // radius of an approximately spherical hull:
572     Thermo thermo(info);
573     RealType hVol = thermo.getHullVolume();
574     sphereARadius_ = 0.1 * pow((3.0 * hVol / (4.0 * M_PI)), 1.0/3.0);
575     }
576     selectionAstream << "select r < " << sphereARadius_;
577     selectionA_ = selectionAstream.str();
578     }
579     }
580    
581     if (hasSelectionB_) {
582     selectionB_ = rnemdParams->getSelectionB();
583 gezelter 1903
584 gezelter 1879 } else {
585     if (usePeriodicBoundaryConditions_) {
586     Mat3x3d hmat = currentSnap_->getHmat();
587    
588     if (hasSlabWidth)
589     slabWidth_ = rnemdParams->getSlabWidth();
590     else
591     slabWidth_ = hmat(2,2) / 10.0;
592    
593     if (hasSlabBCenter)
594     slabBCenter_ = rnemdParams->getSlabBCenter();
595     else
596     slabBCenter_ = hmat(2,2) / 2.0;
597    
598     selectionBstream << "select wrappedz > "
599     << slabBCenter_ - 0.5*slabWidth_
600     << " && wrappedz < "
601     << slabBCenter_ + 0.5*slabWidth_;
602     selectionB_ = selectionBstream.str();
603     } else {
604     if (hasSphereBRadius_) {
605     sphereBRadius_ = rnemdParams->getSphereBRadius();
606     selectionBstream << "select r > " << sphereBRadius_;
607     selectionB_ = selectionBstream.str();
608     } else {
609     selectionB_ = "select hull";
610 gezelter 1903 BisHull_ = true;
611 gezelter 1879 hasSelectionB_ = true;
612     }
613     }
614     }
615     }
616 gezelter 1773
617 gezelter 1879 // object evaluator:
618     evaluator_.loadScriptString(rnemdObjectSelection_);
619     seleMan_.setSelectionSet(evaluator_.evaluate());
620     evaluatorA_.loadScriptString(selectionA_);
621     evaluatorB_.loadScriptString(selectionB_);
622     seleManA_.setSelectionSet(evaluatorA_.evaluate());
623     seleManB_.setSelectionSet(evaluatorB_.evaluate());
624     commonA_ = seleManA_ & seleMan_;
625     commonB_ = seleManB_ & seleMan_;
626     }
627 gezelter 1773
628    
629 gezelter 1329 RNEMD::~RNEMD() {
630 gezelter 1776 if (!doRNEMD_) return;
631 skuang 1368 #ifdef IS_MPI
632     if (worldRank == 0) {
633     #endif
634 gezelter 1722
635 gezelter 1773 writeOutputFile();
636    
637     rnemdFile_.close();
638 jmarr 1728
639 skuang 1368 #ifdef IS_MPI
640     }
641     #endif
642 gezelter 1879
643     // delete all of the objects we created:
644     delete areaAccumulator_;
645     data_.clear();
646 gezelter 1329 }
647 gezelter 1773
648 gezelter 1879 void RNEMD::doSwap(SelectionManager& smanA, SelectionManager& smanB) {
649     if (!doRNEMD_) return;
650     int selei;
651     int selej;
652 skuang 1330
653 gezelter 1332 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
654     Mat3x3d hmat = currentSnap_->getHmat();
655    
656 gezelter 1331 StuntDouble* sd;
657    
658 skuang 1338 RealType min_val;
659 gezelter 1971 int min_found = 0;
660 skuang 1338 StuntDouble* min_sd;
661    
662     RealType max_val;
663 gezelter 1971 int max_found = 0;
664 skuang 1338 StuntDouble* max_sd;
665    
666 gezelter 1879 for (sd = seleManA_.beginSelected(selei); sd != NULL;
667     sd = seleManA_.nextSelected(selei)) {
668 gezelter 1332
669 gezelter 1331 Vector3d pos = sd->getPos();
670 gezelter 1879
671 gezelter 1332 // wrap the stuntdouble's position back into the box:
672 gezelter 1879
673 gezelter 1331 if (usePeriodicBoundaryConditions_)
674 gezelter 1332 currentSnap_->wrapVector(pos);
675 gezelter 1879
676     RealType mass = sd->getMass();
677     Vector3d vel = sd->getVel();
678     RealType value;
679    
680     switch(rnemdFluxType_) {
681     case rnemdKE :
682 gezelter 1332
683 gezelter 1879 value = mass * vel.lengthSquare();
684    
685     if (sd->isDirectional()) {
686     Vector3d angMom = sd->getJ();
687     Mat3x3d I = sd->getI();
688 gezelter 1332
689 gezelter 1879 if (sd->isLinear()) {
690     int i = sd->linearAxis();
691     int j = (i + 1) % 3;
692     int k = (i + 2) % 3;
693     value += angMom[j] * angMom[j] / I(j, j) +
694     angMom[k] * angMom[k] / I(k, k);
695     } else {
696     value += angMom[0]*angMom[0]/I(0, 0)
697     + angMom[1]*angMom[1]/I(1, 1)
698     + angMom[2]*angMom[2]/I(2, 2);
699     }
700     } //angular momenta exchange enabled
701     value *= 0.5;
702     break;
703     case rnemdPx :
704     value = mass * vel[0];
705     break;
706     case rnemdPy :
707     value = mass * vel[1];
708     break;
709     case rnemdPz :
710     value = mass * vel[2];
711     break;
712     default :
713     break;
714     }
715     if (!max_found) {
716     max_val = value;
717     max_sd = sd;
718 gezelter 1971 max_found = 1;
719 gezelter 1879 } else {
720     if (max_val < value) {
721     max_val = value;
722     max_sd = sd;
723 gezelter 1332 }
724 gezelter 1879 }
725     }
726 gezelter 1332
727 gezelter 1879 for (sd = seleManB_.beginSelected(selej); sd != NULL;
728     sd = seleManB_.nextSelected(selej)) {
729    
730     Vector3d pos = sd->getPos();
731    
732     // wrap the stuntdouble's position back into the box:
733    
734     if (usePeriodicBoundaryConditions_)
735     currentSnap_->wrapVector(pos);
736    
737     RealType mass = sd->getMass();
738     Vector3d vel = sd->getVel();
739     RealType value;
740    
741     switch(rnemdFluxType_) {
742     case rnemdKE :
743    
744     value = mass * vel.lengthSquare();
745    
746     if (sd->isDirectional()) {
747     Vector3d angMom = sd->getJ();
748     Mat3x3d I = sd->getI();
749    
750     if (sd->isLinear()) {
751     int i = sd->linearAxis();
752     int j = (i + 1) % 3;
753     int k = (i + 2) % 3;
754     value += angMom[j] * angMom[j] / I(j, j) +
755     angMom[k] * angMom[k] / I(k, k);
756     } else {
757     value += angMom[0]*angMom[0]/I(0, 0)
758     + angMom[1]*angMom[1]/I(1, 1)
759     + angMom[2]*angMom[2]/I(2, 2);
760     }
761     } //angular momenta exchange enabled
762     value *= 0.5;
763     break;
764     case rnemdPx :
765     value = mass * vel[0];
766     break;
767     case rnemdPy :
768     value = mass * vel[1];
769     break;
770     case rnemdPz :
771     value = mass * vel[2];
772     break;
773     default :
774     break;
775 gezelter 1332 }
776 gezelter 1879
777     if (!min_found) {
778     min_val = value;
779     min_sd = sd;
780 gezelter 1971 min_found = 1;
781 gezelter 1879 } else {
782     if (min_val > value) {
783     min_val = value;
784     min_sd = sd;
785     }
786     }
787 gezelter 1331 }
788 gezelter 1773
789 gezelter 1793 #ifdef IS_MPI
790 gezelter 1969 int worldRank;
791     MPI_Comm_rank( MPI_COMM_WORLD, &worldRank);
792    
793     int my_min_found = min_found;
794     int my_max_found = max_found;
795 gezelter 1350
796     // Even if we didn't find a minimum, did someone else?
797 gezelter 1969 MPI_Allreduce(&my_min_found, &min_found, 1, MPI_INT, MPI_LOR,
798     MPI_COMM_WORLD);
799 gezelter 1350 // Even if we didn't find a maximum, did someone else?
800 gezelter 1969 MPI_Allreduce(&my_max_found, &max_found, 1, MPI_INT, MPI_LOR,
801     MPI_COMM_WORLD);
802 gezelter 1722 #endif
803    
804     if (max_found && min_found) {
805    
806     #ifdef IS_MPI
807     struct {
808     RealType val;
809     int rank;
810     } max_vals, min_vals;
811 jmarr 1728
812 gezelter 1722 if (my_min_found) {
813 gezelter 1350 min_vals.val = min_val;
814 gezelter 1722 } else {
815 gezelter 1350 min_vals.val = HONKING_LARGE_VALUE;
816 gezelter 1722 }
817 gezelter 1350 min_vals.rank = worldRank;
818    
819     // Who had the minimum?
820 gezelter 1969 MPI_Allreduce(&min_vals, &min_vals,
821     1, MPI_REALTYPE_INT, MPI_MINLOC, MPI_COMM_WORLD);
822 gezelter 1350 min_val = min_vals.val;
823    
824 gezelter 1722 if (my_max_found) {
825 gezelter 1350 max_vals.val = max_val;
826 gezelter 1722 } else {
827 gezelter 1350 max_vals.val = -HONKING_LARGE_VALUE;
828 gezelter 1722 }
829 gezelter 1350 max_vals.rank = worldRank;
830    
831     // Who had the maximum?
832 gezelter 1969 MPI_Allreduce(&max_vals, &max_vals,
833     1, MPI_REALTYPE_INT, MPI_MAXLOC, MPI_COMM_WORLD);
834 gezelter 1350 max_val = max_vals.val;
835     #endif
836 gezelter 1722
837 gezelter 1629 if (min_val < max_val) {
838 gezelter 1722
839 gezelter 1350 #ifdef IS_MPI
840     if (max_vals.rank == worldRank && min_vals.rank == worldRank) {
841     // I have both maximum and minimum, so proceed like a single
842     // processor version:
843     #endif
844 gezelter 1722
845 gezelter 1350 Vector3d min_vel = min_sd->getVel();
846     Vector3d max_vel = max_sd->getVel();
847     RealType temp_vel;
848    
849 gezelter 1773 switch(rnemdFluxType_) {
850     case rnemdKE :
851 gezelter 1350 min_sd->setVel(max_vel);
852     max_sd->setVel(min_vel);
853 gezelter 1722 if (min_sd->isDirectional() && max_sd->isDirectional()) {
854 gezelter 1350 Vector3d min_angMom = min_sd->getJ();
855     Vector3d max_angMom = max_sd->getJ();
856     min_sd->setJ(max_angMom);
857     max_sd->setJ(min_angMom);
858 gezelter 1722 }//angular momenta exchange enabled
859     //assumes same rigid body identity
860 gezelter 1350 break;
861     case rnemdPx :
862     temp_vel = min_vel.x();
863     min_vel.x() = max_vel.x();
864     max_vel.x() = temp_vel;
865     min_sd->setVel(min_vel);
866     max_sd->setVel(max_vel);
867     break;
868     case rnemdPy :
869     temp_vel = min_vel.y();
870     min_vel.y() = max_vel.y();
871     max_vel.y() = temp_vel;
872     min_sd->setVel(min_vel);
873     max_sd->setVel(max_vel);
874     break;
875     case rnemdPz :
876     temp_vel = min_vel.z();
877     min_vel.z() = max_vel.z();
878     max_vel.z() = temp_vel;
879     min_sd->setVel(min_vel);
880     max_sd->setVel(max_vel);
881     break;
882     default :
883     break;
884     }
885 gezelter 1722
886 gezelter 1350 #ifdef IS_MPI
887     // the rest of the cases only apply in parallel simulations:
888     } else if (max_vals.rank == worldRank) {
889     // I had the max, but not the minimum
890    
891     Vector3d min_vel;
892     Vector3d max_vel = max_sd->getVel();
893 gezelter 1980 MPI_Status status;
894 skuang 1341
895 gezelter 1350 // point-to-point swap of the velocity vector
896 gezelter 1969 MPI_Sendrecv(max_vel.getArrayPointer(), 3, MPI_REALTYPE,
897     min_vals.rank, 0,
898     min_vel.getArrayPointer(), 3, MPI_REALTYPE,
899 gezelter 1980 min_vals.rank, 0, MPI_COMM_WORLD, &status);
900 gezelter 1350
901 gezelter 1773 switch(rnemdFluxType_) {
902     case rnemdKE :
903 gezelter 1350 max_sd->setVel(min_vel);
904 gezelter 1722 //angular momenta exchange enabled
905 gezelter 1350 if (max_sd->isDirectional()) {
906     Vector3d min_angMom;
907     Vector3d max_angMom = max_sd->getJ();
908 gezelter 1629
909 gezelter 1350 // point-to-point swap of the angular momentum vector
910 gezelter 1969 MPI_Sendrecv(max_angMom.getArrayPointer(), 3,
911     MPI_REALTYPE, min_vals.rank, 1,
912     min_angMom.getArrayPointer(), 3,
913     MPI_REALTYPE, min_vals.rank, 1,
914 gezelter 1980 MPI_COMM_WORLD, &status);
915 gezelter 1629
916 gezelter 1350 max_sd->setJ(min_angMom);
917 gezelter 1722 }
918 gezelter 1350 break;
919     case rnemdPx :
920     max_vel.x() = min_vel.x();
921     max_sd->setVel(max_vel);
922     break;
923     case rnemdPy :
924     max_vel.y() = min_vel.y();
925     max_sd->setVel(max_vel);
926     break;
927     case rnemdPz :
928     max_vel.z() = min_vel.z();
929     max_sd->setVel(max_vel);
930     break;
931     default :
932     break;
933 skuang 1341 }
934 gezelter 1350 } else if (min_vals.rank == worldRank) {
935     // I had the minimum but not the maximum:
936    
937     Vector3d max_vel;
938     Vector3d min_vel = min_sd->getVel();
939 gezelter 1980 MPI_Status status;
940 gezelter 1350
941     // point-to-point swap of the velocity vector
942 gezelter 1969 MPI_Sendrecv(min_vel.getArrayPointer(), 3, MPI_REALTYPE,
943     max_vals.rank, 0,
944     max_vel.getArrayPointer(), 3, MPI_REALTYPE,
945 gezelter 1980 max_vals.rank, 0, MPI_COMM_WORLD, &status);
946 gezelter 1350
947 gezelter 1773 switch(rnemdFluxType_) {
948     case rnemdKE :
949 gezelter 1350 min_sd->setVel(max_vel);
950 gezelter 1722 //angular momenta exchange enabled
951 gezelter 1350 if (min_sd->isDirectional()) {
952     Vector3d min_angMom = min_sd->getJ();
953     Vector3d max_angMom;
954 gezelter 1629
955 gezelter 1350 // point-to-point swap of the angular momentum vector
956 gezelter 1969 MPI_Sendrecv(min_angMom.getArrayPointer(), 3,
957     MPI_REALTYPE, max_vals.rank, 1,
958     max_angMom.getArrayPointer(), 3,
959     MPI_REALTYPE, max_vals.rank, 1,
960 gezelter 1980 MPI_COMM_WORLD, &status);
961 gezelter 1629
962 gezelter 1350 min_sd->setJ(max_angMom);
963     }
964     break;
965     case rnemdPx :
966     min_vel.x() = max_vel.x();
967     min_sd->setVel(min_vel);
968     break;
969     case rnemdPy :
970     min_vel.y() = max_vel.y();
971     min_sd->setVel(min_vel);
972     break;
973     case rnemdPz :
974     min_vel.z() = max_vel.z();
975     min_sd->setVel(min_vel);
976     break;
977     default :
978     break;
979     }
980     }
981     #endif
982 gezelter 1773
983     switch(rnemdFluxType_) {
984     case rnemdKE:
985     kineticExchange_ += max_val - min_val;
986     break;
987     case rnemdPx:
988     momentumExchange_.x() += max_val - min_val;
989     break;
990     case rnemdPy:
991     momentumExchange_.y() += max_val - min_val;
992     break;
993     case rnemdPz:
994     momentumExchange_.z() += max_val - min_val;
995     break;
996     default:
997     break;
998     }
999 gezelter 1629 } else {
1000     sprintf(painCave.errMsg,
1001 gezelter 1773 "RNEMD::doSwap exchange NOT performed because min_val > max_val\n");
1002 gezelter 1629 painCave.isFatal = 0;
1003     painCave.severity = OPENMD_INFO;
1004     simError();
1005 skuang 1368 failTrialCount_++;
1006 skuang 1338 }
1007     } else {
1008 gezelter 1629 sprintf(painCave.errMsg,
1009 gezelter 1773 "RNEMD::doSwap exchange NOT performed because selected object\n"
1010     "\twas not present in at least one of the two slabs.\n");
1011 gezelter 1629 painCave.isFatal = 0;
1012     painCave.severity = OPENMD_INFO;
1013     simError();
1014 skuang 1368 failTrialCount_++;
1015 gezelter 1773 }
1016 skuang 1338 }
1017 gezelter 1350
1018 gezelter 1879 void RNEMD::doNIVS(SelectionManager& smanA, SelectionManager& smanB) {
1019 gezelter 1776 if (!doRNEMD_) return;
1020 gezelter 1879 int selei;
1021     int selej;
1022    
1023 skuang 1338 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1024 gezelter 1879 RealType time = currentSnap_->getTime();
1025 skuang 1338 Mat3x3d hmat = currentSnap_->getHmat();
1026    
1027     StuntDouble* sd;
1028    
1029 gezelter 1629 vector<StuntDouble*> hotBin, coldBin;
1030 gezelter 1350
1031 skuang 1368 RealType Phx = 0.0;
1032     RealType Phy = 0.0;
1033     RealType Phz = 0.0;
1034     RealType Khx = 0.0;
1035     RealType Khy = 0.0;
1036     RealType Khz = 0.0;
1037 gezelter 1722 RealType Khw = 0.0;
1038 skuang 1368 RealType Pcx = 0.0;
1039     RealType Pcy = 0.0;
1040     RealType Pcz = 0.0;
1041     RealType Kcx = 0.0;
1042     RealType Kcy = 0.0;
1043     RealType Kcz = 0.0;
1044 gezelter 1722 RealType Kcw = 0.0;
1045 skuang 1368
1046 gezelter 1879 for (sd = smanA.beginSelected(selei); sd != NULL;
1047     sd = smanA.nextSelected(selei)) {
1048 skuang 1368
1049     Vector3d pos = sd->getPos();
1050 gezelter 1879
1051 skuang 1368 // wrap the stuntdouble's position back into the box:
1052 gezelter 1879
1053 skuang 1368 if (usePeriodicBoundaryConditions_)
1054     currentSnap_->wrapVector(pos);
1055 gezelter 1879
1056    
1057     RealType mass = sd->getMass();
1058     Vector3d vel = sd->getVel();
1059    
1060     hotBin.push_back(sd);
1061     Phx += mass * vel.x();
1062     Phy += mass * vel.y();
1063     Phz += mass * vel.z();
1064     Khx += mass * vel.x() * vel.x();
1065     Khy += mass * vel.y() * vel.y();
1066     Khz += mass * vel.z() * vel.z();
1067     if (sd->isDirectional()) {
1068     Vector3d angMom = sd->getJ();
1069     Mat3x3d I = sd->getI();
1070     if (sd->isLinear()) {
1071     int i = sd->linearAxis();
1072     int j = (i + 1) % 3;
1073     int k = (i + 2) % 3;
1074     Khw += angMom[j] * angMom[j] / I(j, j) +
1075     angMom[k] * angMom[k] / I(k, k);
1076     } else {
1077     Khw += angMom[0]*angMom[0]/I(0, 0)
1078     + angMom[1]*angMom[1]/I(1, 1)
1079     + angMom[2]*angMom[2]/I(2, 2);
1080     }
1081     }
1082     }
1083     for (sd = smanB.beginSelected(selej); sd != NULL;
1084     sd = smanB.nextSelected(selej)) {
1085     Vector3d pos = sd->getPos();
1086    
1087     // wrap the stuntdouble's position back into the box:
1088    
1089     if (usePeriodicBoundaryConditions_)
1090     currentSnap_->wrapVector(pos);
1091    
1092     RealType mass = sd->getMass();
1093     Vector3d vel = sd->getVel();
1094 skuang 1368
1095 gezelter 1879 coldBin.push_back(sd);
1096     Pcx += mass * vel.x();
1097     Pcy += mass * vel.y();
1098     Pcz += mass * vel.z();
1099     Kcx += mass * vel.x() * vel.x();
1100     Kcy += mass * vel.y() * vel.y();
1101     Kcz += mass * vel.z() * vel.z();
1102     if (sd->isDirectional()) {
1103     Vector3d angMom = sd->getJ();
1104     Mat3x3d I = sd->getI();
1105     if (sd->isLinear()) {
1106     int i = sd->linearAxis();
1107     int j = (i + 1) % 3;
1108     int k = (i + 2) % 3;
1109     Kcw += angMom[j] * angMom[j] / I(j, j) +
1110     angMom[k] * angMom[k] / I(k, k);
1111     } else {
1112     Kcw += angMom[0]*angMom[0]/I(0, 0)
1113     + angMom[1]*angMom[1]/I(1, 1)
1114     + angMom[2]*angMom[2]/I(2, 2);
1115     }
1116 skuang 1368 }
1117     }
1118 gezelter 1722
1119 skuang 1368 Khx *= 0.5;
1120     Khy *= 0.5;
1121     Khz *= 0.5;
1122 gezelter 1722 Khw *= 0.5;
1123 skuang 1368 Kcx *= 0.5;
1124     Kcy *= 0.5;
1125     Kcz *= 0.5;
1126 gezelter 1722 Kcw *= 0.5;
1127 skuang 1368
1128     #ifdef IS_MPI
1129 gezelter 1969 MPI_Allreduce(MPI_IN_PLACE, &Phx, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1130     MPI_Allreduce(MPI_IN_PLACE, &Phy, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1131     MPI_Allreduce(MPI_IN_PLACE, &Phz, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1132     MPI_Allreduce(MPI_IN_PLACE, &Pcx, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1133     MPI_Allreduce(MPI_IN_PLACE, &Pcy, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1134     MPI_Allreduce(MPI_IN_PLACE, &Pcz, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1135 skuang 1368
1136 gezelter 1969 MPI_Allreduce(MPI_IN_PLACE, &Khx, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1137     MPI_Allreduce(MPI_IN_PLACE, &Khy, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1138     MPI_Allreduce(MPI_IN_PLACE, &Khz, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1139     MPI_Allreduce(MPI_IN_PLACE, &Khw, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1140 gezelter 1722
1141 gezelter 1969 MPI_Allreduce(MPI_IN_PLACE, &Kcx, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1142     MPI_Allreduce(MPI_IN_PLACE, &Kcy, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1143     MPI_Allreduce(MPI_IN_PLACE, &Kcz, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1144     MPI_Allreduce(MPI_IN_PLACE, &Kcw, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1145 skuang 1368 #endif
1146    
1147 gezelter 1722 //solve coldBin coeff's first
1148 skuang 1368 RealType px = Pcx / Phx;
1149     RealType py = Pcy / Phy;
1150     RealType pz = Pcz / Phz;
1151 gezelter 1722 RealType c, x, y, z;
1152     bool successfulScale = false;
1153 gezelter 1773 if ((rnemdFluxType_ == rnemdFullKE) ||
1154     (rnemdFluxType_ == rnemdRotKE)) {
1155 gezelter 1722 //may need sanity check Khw & Kcw > 0
1156 skuang 1368
1157 gezelter 1773 if (rnemdFluxType_ == rnemdFullKE) {
1158     c = 1.0 - kineticTarget_ / (Kcx + Kcy + Kcz + Kcw);
1159 gezelter 1722 } else {
1160 gezelter 1773 c = 1.0 - kineticTarget_ / Kcw;
1161 gezelter 1722 }
1162 skuang 1368
1163 gezelter 1722 if ((c > 0.81) && (c < 1.21)) {//restrict scaling coefficients
1164     c = sqrt(c);
1165 gezelter 1801
1166 gezelter 1722 RealType w = 0.0;
1167 gezelter 1773 if (rnemdFluxType_ == rnemdFullKE) {
1168 gezelter 1722 x = 1.0 + px * (1.0 - c);
1169     y = 1.0 + py * (1.0 - c);
1170     z = 1.0 + pz * (1.0 - c);
1171     /* more complicated way
1172     w = 1.0 + (Kcw - Kcw * c * c - (c * c * (Kcx + Kcy + Kcz
1173     + Khx * px * px + Khy * py * py + Khz * pz * pz)
1174     - 2.0 * c * (Khx * px * (1.0 + px) + Khy * py * (1.0 + py)
1175     + Khz * pz * (1.0 + pz)) + Khx * px * (2.0 + px)
1176     + Khy * py * (2.0 + py) + Khz * pz * (2.0 + pz)
1177     - Kcx - Kcy - Kcz)) / Khw; the following is simpler
1178     */
1179     if ((fabs(x - 1.0) < 0.1) && (fabs(y - 1.0) < 0.1) &&
1180     (fabs(z - 1.0) < 0.1)) {
1181 gezelter 1773 w = 1.0 + (kineticTarget_
1182     + Khx * (1.0 - x * x) + Khy * (1.0 - y * y)
1183 gezelter 1722 + Khz * (1.0 - z * z)) / Khw;
1184     }//no need to calculate w if x, y or z is out of range
1185     } else {
1186 gezelter 1773 w = 1.0 + kineticTarget_ / Khw;
1187 gezelter 1722 }
1188     if ((w > 0.81) && (w < 1.21)) {//restrict scaling coefficients
1189     //if w is in the right range, so should be x, y, z.
1190     vector<StuntDouble*>::iterator sdi;
1191     Vector3d vel;
1192 gezelter 1879 for (sdi = coldBin.begin(); sdi != coldBin.end(); ++sdi) {
1193 gezelter 1773 if (rnemdFluxType_ == rnemdFullKE) {
1194 gezelter 1722 vel = (*sdi)->getVel() * c;
1195     (*sdi)->setVel(vel);
1196     }
1197     if ((*sdi)->isDirectional()) {
1198     Vector3d angMom = (*sdi)->getJ() * c;
1199     (*sdi)->setJ(angMom);
1200     }
1201     }
1202     w = sqrt(w);
1203 gezelter 1879 for (sdi = hotBin.begin(); sdi != hotBin.end(); ++sdi) {
1204 gezelter 1773 if (rnemdFluxType_ == rnemdFullKE) {
1205 gezelter 1722 vel = (*sdi)->getVel();
1206     vel.x() *= x;
1207     vel.y() *= y;
1208     vel.z() *= z;
1209     (*sdi)->setVel(vel);
1210     }
1211     if ((*sdi)->isDirectional()) {
1212     Vector3d angMom = (*sdi)->getJ() * w;
1213     (*sdi)->setJ(angMom);
1214     }
1215     }
1216     successfulScale = true;
1217 gezelter 1773 kineticExchange_ += kineticTarget_;
1218 gezelter 1722 }
1219 skuang 1368 }
1220 gezelter 1722 } else {
1221     RealType a000, a110, c0, a001, a111, b01, b11, c1;
1222 gezelter 1773 switch(rnemdFluxType_) {
1223     case rnemdKE :
1224 gezelter 1722 /* used hotBin coeff's & only scale x & y dimensions
1225     RealType px = Phx / Pcx;
1226     RealType py = Phy / Pcy;
1227     a110 = Khy;
1228 gezelter 1773 c0 = - Khx - Khy - kineticTarget_;
1229 gezelter 1722 a000 = Khx;
1230     a111 = Kcy * py * py;
1231     b11 = -2.0 * Kcy * py * (1.0 + py);
1232 gezelter 1773 c1 = Kcy * py * (2.0 + py) + Kcx * px * ( 2.0 + px) + kineticTarget_;
1233 gezelter 1722 b01 = -2.0 * Kcx * px * (1.0 + px);
1234     a001 = Kcx * px * px;
1235     */
1236     //scale all three dimensions, let c_x = c_y
1237     a000 = Kcx + Kcy;
1238     a110 = Kcz;
1239 gezelter 1773 c0 = kineticTarget_ - Kcx - Kcy - Kcz;
1240 gezelter 1722 a001 = Khx * px * px + Khy * py * py;
1241     a111 = Khz * pz * pz;
1242     b01 = -2.0 * (Khx * px * (1.0 + px) + Khy * py * (1.0 + py));
1243     b11 = -2.0 * Khz * pz * (1.0 + pz);
1244     c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
1245 gezelter 1773 + Khz * pz * (2.0 + pz) - kineticTarget_;
1246 gezelter 1722 break;
1247 gezelter 1773 case rnemdPx :
1248     c = 1 - momentumTarget_.x() / Pcx;
1249 gezelter 1722 a000 = Kcy;
1250     a110 = Kcz;
1251     c0 = Kcx * c * c - Kcx - Kcy - Kcz;
1252     a001 = py * py * Khy;
1253     a111 = pz * pz * Khz;
1254     b01 = -2.0 * Khy * py * (1.0 + py);
1255     b11 = -2.0 * Khz * pz * (1.0 + pz);
1256     c1 = Khy * py * (2.0 + py) + Khz * pz * (2.0 + pz)
1257     + Khx * (fastpow(c * px - px - 1.0, 2) - 1.0);
1258     break;
1259 gezelter 1773 case rnemdPy :
1260     c = 1 - momentumTarget_.y() / Pcy;
1261 gezelter 1722 a000 = Kcx;
1262     a110 = Kcz;
1263     c0 = Kcy * c * c - Kcx - Kcy - Kcz;
1264     a001 = px * px * Khx;
1265     a111 = pz * pz * Khz;
1266     b01 = -2.0 * Khx * px * (1.0 + px);
1267     b11 = -2.0 * Khz * pz * (1.0 + pz);
1268     c1 = Khx * px * (2.0 + px) + Khz * pz * (2.0 + pz)
1269     + Khy * (fastpow(c * py - py - 1.0, 2) - 1.0);
1270     break;
1271 gezelter 1773 case rnemdPz ://we don't really do this, do we?
1272     c = 1 - momentumTarget_.z() / Pcz;
1273 gezelter 1722 a000 = Kcx;
1274     a110 = Kcy;
1275     c0 = Kcz * c * c - Kcx - Kcy - Kcz;
1276     a001 = px * px * Khx;
1277     a111 = py * py * Khy;
1278     b01 = -2.0 * Khx * px * (1.0 + px);
1279     b11 = -2.0 * Khy * py * (1.0 + py);
1280     c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
1281     + Khz * (fastpow(c * pz - pz - 1.0, 2) - 1.0);
1282     break;
1283     default :
1284     break;
1285 skuang 1368 }
1286 gezelter 1722
1287     RealType v1 = a000 * a111 - a001 * a110;
1288     RealType v2 = a000 * b01;
1289     RealType v3 = a000 * b11;
1290     RealType v4 = a000 * c1 - a001 * c0;
1291     RealType v8 = a110 * b01;
1292     RealType v10 = - b01 * c0;
1293    
1294     RealType u0 = v2 * v10 - v4 * v4;
1295     RealType u1 = -2.0 * v3 * v4;
1296     RealType u2 = -v2 * v8 - v3 * v3 - 2.0 * v1 * v4;
1297     RealType u3 = -2.0 * v1 * v3;
1298     RealType u4 = - v1 * v1;
1299     //rescale coefficients
1300     RealType maxAbs = fabs(u0);
1301     if (maxAbs < fabs(u1)) maxAbs = fabs(u1);
1302     if (maxAbs < fabs(u2)) maxAbs = fabs(u2);
1303     if (maxAbs < fabs(u3)) maxAbs = fabs(u3);
1304     if (maxAbs < fabs(u4)) maxAbs = fabs(u4);
1305     u0 /= maxAbs;
1306     u1 /= maxAbs;
1307     u2 /= maxAbs;
1308     u3 /= maxAbs;
1309     u4 /= maxAbs;
1310     //max_element(start, end) is also available.
1311     Polynomial<RealType> poly; //same as DoublePolynomial poly;
1312     poly.setCoefficient(4, u4);
1313     poly.setCoefficient(3, u3);
1314     poly.setCoefficient(2, u2);
1315     poly.setCoefficient(1, u1);
1316     poly.setCoefficient(0, u0);
1317     vector<RealType> realRoots = poly.FindRealRoots();
1318    
1319     vector<RealType>::iterator ri;
1320     RealType r1, r2, alpha0;
1321     vector<pair<RealType,RealType> > rps;
1322 gezelter 1879 for (ri = realRoots.begin(); ri !=realRoots.end(); ++ri) {
1323 gezelter 1722 r2 = *ri;
1324     //check if FindRealRoots() give the right answer
1325     if ( fabs(u0 + r2 * (u1 + r2 * (u2 + r2 * (u3 + r2 * u4)))) > 1e-6 ) {
1326     sprintf(painCave.errMsg,
1327     "RNEMD Warning: polynomial solve seems to have an error!");
1328     painCave.isFatal = 0;
1329     simError();
1330     failRootCount_++;
1331     }
1332     //might not be useful w/o rescaling coefficients
1333     alpha0 = -c0 - a110 * r2 * r2;
1334     if (alpha0 >= 0.0) {
1335     r1 = sqrt(alpha0 / a000);
1336     if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111))
1337     < 1e-6)
1338     { rps.push_back(make_pair(r1, r2)); }
1339     if (r1 > 1e-6) { //r1 non-negative
1340     r1 = -r1;
1341     if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111))
1342     < 1e-6)
1343     { rps.push_back(make_pair(r1, r2)); }
1344     }
1345     }
1346 skuang 1368 }
1347 gezelter 1722 // Consider combining together the solving pair part w/ the searching
1348     // best solution part so that we don't need the pairs vector
1349     if (!rps.empty()) {
1350     RealType smallestDiff = HONKING_LARGE_VALUE;
1351     RealType diff;
1352     pair<RealType,RealType> bestPair = make_pair(1.0, 1.0);
1353     vector<pair<RealType,RealType> >::iterator rpi;
1354 gezelter 1879 for (rpi = rps.begin(); rpi != rps.end(); ++rpi) {
1355 gezelter 1722 r1 = (*rpi).first;
1356     r2 = (*rpi).second;
1357 gezelter 1773 switch(rnemdFluxType_) {
1358     case rnemdKE :
1359 gezelter 1722 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1360     + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2)
1361     + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
1362     break;
1363 gezelter 1773 case rnemdPx :
1364 gezelter 1722 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1365     + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
1366     break;
1367 gezelter 1773 case rnemdPy :
1368 gezelter 1722 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1369     + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2);
1370     break;
1371 gezelter 1773 case rnemdPz :
1372 gezelter 1722 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1373     + fastpow(r1 * r1 / r2 / r2 - Kcy/Kcx, 2);
1374     default :
1375     break;
1376     }
1377     if (diff < smallestDiff) {
1378     smallestDiff = diff;
1379     bestPair = *rpi;
1380     }
1381     }
1382 skuang 1368 #ifdef IS_MPI
1383 gezelter 1722 if (worldRank == 0) {
1384 skuang 1368 #endif
1385 gezelter 1773 // sprintf(painCave.errMsg,
1386     // "RNEMD: roots r1= %lf\tr2 = %lf\n",
1387     // bestPair.first, bestPair.second);
1388     // painCave.isFatal = 0;
1389     // painCave.severity = OPENMD_INFO;
1390     // simError();
1391 skuang 1368 #ifdef IS_MPI
1392 gezelter 1722 }
1393 skuang 1368 #endif
1394 gezelter 1722
1395 gezelter 1773 switch(rnemdFluxType_) {
1396     case rnemdKE :
1397 gezelter 1722 x = bestPair.first;
1398     y = bestPair.first;
1399     z = bestPair.second;
1400     break;
1401 gezelter 1773 case rnemdPx :
1402 gezelter 1722 x = c;
1403     y = bestPair.first;
1404     z = bestPair.second;
1405     break;
1406 gezelter 1773 case rnemdPy :
1407 gezelter 1722 x = bestPair.first;
1408     y = c;
1409     z = bestPair.second;
1410     break;
1411 gezelter 1773 case rnemdPz :
1412 gezelter 1722 x = bestPair.first;
1413     y = bestPair.second;
1414     z = c;
1415     break;
1416     default :
1417     break;
1418     }
1419     vector<StuntDouble*>::iterator sdi;
1420     Vector3d vel;
1421 gezelter 1879 for (sdi = coldBin.begin(); sdi != coldBin.end(); ++sdi) {
1422 gezelter 1722 vel = (*sdi)->getVel();
1423     vel.x() *= x;
1424     vel.y() *= y;
1425     vel.z() *= z;
1426     (*sdi)->setVel(vel);
1427     }
1428     //convert to hotBin coefficient
1429     x = 1.0 + px * (1.0 - x);
1430     y = 1.0 + py * (1.0 - y);
1431     z = 1.0 + pz * (1.0 - z);
1432 gezelter 1879 for (sdi = hotBin.begin(); sdi != hotBin.end(); ++sdi) {
1433 gezelter 1722 vel = (*sdi)->getVel();
1434     vel.x() *= x;
1435     vel.y() *= y;
1436     vel.z() *= z;
1437     (*sdi)->setVel(vel);
1438     }
1439     successfulScale = true;
1440 gezelter 1773 switch(rnemdFluxType_) {
1441     case rnemdKE :
1442     kineticExchange_ += kineticTarget_;
1443     break;
1444     case rnemdPx :
1445     case rnemdPy :
1446     case rnemdPz :
1447     momentumExchange_ += momentumTarget_;
1448     break;
1449     default :
1450     break;
1451     }
1452 gezelter 1629 }
1453 gezelter 1722 }
1454     if (successfulScale != true) {
1455     sprintf(painCave.errMsg,
1456 gezelter 1773 "RNEMD::doNIVS exchange NOT performed - roots that solve\n"
1457     "\tthe constraint equations may not exist or there may be\n"
1458     "\tno selected objects in one or both slabs.\n");
1459 gezelter 1722 painCave.isFatal = 0;
1460     painCave.severity = OPENMD_INFO;
1461     simError();
1462     failTrialCount_++;
1463     }
1464     }
1465 gezelter 1879
1466     void RNEMD::doVSS(SelectionManager& smanA, SelectionManager& smanB) {
1467     if (!doRNEMD_) return;
1468     int selei;
1469     int selej;
1470 gezelter 1722
1471     Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1472 jmarr 1728 RealType time = currentSnap_->getTime();
1473 gezelter 1722 Mat3x3d hmat = currentSnap_->getHmat();
1474    
1475     StuntDouble* sd;
1476    
1477     vector<StuntDouble*> hotBin, coldBin;
1478    
1479     Vector3d Ph(V3Zero);
1480 gezelter 1879 Vector3d Lh(V3Zero);
1481 gezelter 1722 RealType Mh = 0.0;
1482 gezelter 1879 Mat3x3d Ih(0.0);
1483 gezelter 1722 RealType Kh = 0.0;
1484     Vector3d Pc(V3Zero);
1485 gezelter 1879 Vector3d Lc(V3Zero);
1486 gezelter 1722 RealType Mc = 0.0;
1487 gezelter 1879 Mat3x3d Ic(0.0);
1488 gezelter 1722 RealType Kc = 0.0;
1489 gezelter 1879
1490     // Constraints can be on only the linear or angular momentum, but
1491     // not both. Usually, the user will specify which they want, but
1492     // in case they don't, the use of periodic boundaries should make
1493     // the choice for us.
1494     bool doLinearPart = false;
1495     bool doAngularPart = false;
1496    
1497     switch (rnemdFluxType_) {
1498     case rnemdPx:
1499     case rnemdPy:
1500     case rnemdPz:
1501     case rnemdPvector:
1502     case rnemdKePx:
1503     case rnemdKePy:
1504     case rnemdKePvector:
1505     doLinearPart = true;
1506     break;
1507     case rnemdLx:
1508     case rnemdLy:
1509     case rnemdLz:
1510     case rnemdLvector:
1511     case rnemdKeLx:
1512     case rnemdKeLy:
1513     case rnemdKeLz:
1514     case rnemdKeLvector:
1515     doAngularPart = true;
1516     break;
1517     case rnemdKE:
1518     case rnemdRotKE:
1519     case rnemdFullKE:
1520     default:
1521     if (usePeriodicBoundaryConditions_)
1522     doLinearPart = true;
1523     else
1524     doAngularPart = true;
1525     break;
1526     }
1527 jmarr 1728
1528 gezelter 1879 for (sd = smanA.beginSelected(selei); sd != NULL;
1529     sd = smanA.nextSelected(selei)) {
1530 gezelter 1722
1531     Vector3d pos = sd->getPos();
1532    
1533     // wrap the stuntdouble's position back into the box:
1534 gezelter 1879
1535     if (usePeriodicBoundaryConditions_)
1536     currentSnap_->wrapVector(pos);
1537    
1538     RealType mass = sd->getMass();
1539     Vector3d vel = sd->getVel();
1540     Vector3d rPos = sd->getPos() - coordinateOrigin_;
1541     RealType r2;
1542    
1543     hotBin.push_back(sd);
1544     Ph += mass * vel;
1545     Mh += mass;
1546     Kh += mass * vel.lengthSquare();
1547     Lh += mass * cross(rPos, vel);
1548     Ih -= outProduct(rPos, rPos) * mass;
1549     r2 = rPos.lengthSquare();
1550     Ih(0, 0) += mass * r2;
1551     Ih(1, 1) += mass * r2;
1552     Ih(2, 2) += mass * r2;
1553    
1554     if (rnemdFluxType_ == rnemdFullKE) {
1555     if (sd->isDirectional()) {
1556     Vector3d angMom = sd->getJ();
1557     Mat3x3d I = sd->getI();
1558     if (sd->isLinear()) {
1559     int i = sd->linearAxis();
1560     int j = (i + 1) % 3;
1561     int k = (i + 2) % 3;
1562     Kh += angMom[j] * angMom[j] / I(j, j) +
1563     angMom[k] * angMom[k] / I(k, k);
1564     } else {
1565     Kh += angMom[0] * angMom[0] / I(0, 0) +
1566     angMom[1] * angMom[1] / I(1, 1) +
1567     angMom[2] * angMom[2] / I(2, 2);
1568     }
1569     }
1570     }
1571     }
1572     for (sd = smanB.beginSelected(selej); sd != NULL;
1573     sd = smanB.nextSelected(selej)) {
1574 gezelter 1722
1575 gezelter 1879 Vector3d pos = sd->getPos();
1576    
1577     // wrap the stuntdouble's position back into the box:
1578    
1579 gezelter 1722 if (usePeriodicBoundaryConditions_)
1580     currentSnap_->wrapVector(pos);
1581 gezelter 1879
1582     RealType mass = sd->getMass();
1583     Vector3d vel = sd->getVel();
1584     Vector3d rPos = sd->getPos() - coordinateOrigin_;
1585     RealType r2;
1586 gezelter 1722
1587 gezelter 1879 coldBin.push_back(sd);
1588     Pc += mass * vel;
1589     Mc += mass;
1590     Kc += mass * vel.lengthSquare();
1591     Lc += mass * cross(rPos, vel);
1592     Ic -= outProduct(rPos, rPos) * mass;
1593     r2 = rPos.lengthSquare();
1594     Ic(0, 0) += mass * r2;
1595     Ic(1, 1) += mass * r2;
1596     Ic(2, 2) += mass * r2;
1597 gezelter 1773
1598 gezelter 1879 if (rnemdFluxType_ == rnemdFullKE) {
1599     if (sd->isDirectional()) {
1600     Vector3d angMom = sd->getJ();
1601     Mat3x3d I = sd->getI();
1602     if (sd->isLinear()) {
1603     int i = sd->linearAxis();
1604     int j = (i + 1) % 3;
1605     int k = (i + 2) % 3;
1606     Kc += angMom[j] * angMom[j] / I(j, j) +
1607     angMom[k] * angMom[k] / I(k, k);
1608     } else {
1609     Kc += angMom[0] * angMom[0] / I(0, 0) +
1610     angMom[1] * angMom[1] / I(1, 1) +
1611     angMom[2] * angMom[2] / I(2, 2);
1612     }
1613     }
1614 skuang 1368 }
1615 gezelter 1722 }
1616    
1617     Kh *= 0.5;
1618     Kc *= 0.5;
1619 jmarr 1728
1620 gezelter 1722 #ifdef IS_MPI
1621 gezelter 1969 MPI_Allreduce(MPI_IN_PLACE, &Ph[0], 3, MPI_REALTYPE, MPI_SUM,
1622     MPI_COMM_WORLD);
1623     MPI_Allreduce(MPI_IN_PLACE, &Pc[0], 3, MPI_REALTYPE, MPI_SUM,
1624     MPI_COMM_WORLD);
1625     MPI_Allreduce(MPI_IN_PLACE, &Lh[0], 3, MPI_REALTYPE, MPI_SUM,
1626     MPI_COMM_WORLD);
1627     MPI_Allreduce(MPI_IN_PLACE, &Lc[0], 3, MPI_REALTYPE, MPI_SUM,
1628     MPI_COMM_WORLD);
1629     MPI_Allreduce(MPI_IN_PLACE, &Mh, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1630     MPI_Allreduce(MPI_IN_PLACE, &Kh, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1631     MPI_Allreduce(MPI_IN_PLACE, &Mc, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1632     MPI_Allreduce(MPI_IN_PLACE, &Kc, 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1633     MPI_Allreduce(MPI_IN_PLACE, Ih.getArrayPointer(), 9,
1634     MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1635     MPI_Allreduce(MPI_IN_PLACE, Ic.getArrayPointer(), 9,
1636     MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
1637 gezelter 1722 #endif
1638 gezelter 1879
1639 gezelter 1722
1640 gezelter 1879 Vector3d ac, acrec, bc, bcrec;
1641     Vector3d ah, ahrec, bh, bhrec;
1642    
1643 gezelter 1722 bool successfulExchange = false;
1644     if ((Mh > 0.0) && (Mc > 0.0)) {//both slabs are not empty
1645     Vector3d vc = Pc / Mc;
1646 gezelter 1879 ac = -momentumTarget_ / Mc + vc;
1647     acrec = -momentumTarget_ / Mc;
1648    
1649     // We now need the inverse of the inertia tensor to calculate the
1650     // angular velocity of the cold slab;
1651     Mat3x3d Ici = Ic.inverse();
1652     Vector3d omegac = Ici * Lc;
1653     bc = -(Ici * angularMomentumTarget_) + omegac;
1654     bcrec = bc - omegac;
1655    
1656     RealType cNumerator = Kc - kineticTarget_;
1657     if (doLinearPart)
1658     cNumerator -= 0.5 * Mc * ac.lengthSquare();
1659    
1660     if (doAngularPart)
1661     cNumerator -= 0.5 * ( dot(bc, Ic * bc));
1662    
1663 gezelter 1722 if (cNumerator > 0.0) {
1664 gezelter 1879
1665     RealType cDenominator = Kc;
1666    
1667     if (doLinearPart)
1668     cDenominator -= 0.5 * Mc * vc.lengthSquare();
1669    
1670     if (doAngularPart)
1671     cDenominator -= 0.5*(dot(omegac, Ic * omegac));
1672    
1673 gezelter 1722 if (cDenominator > 0.0) {
1674     RealType c = sqrt(cNumerator / cDenominator);
1675     if ((c > 0.9) && (c < 1.1)) {//restrict scaling coefficients
1676 gezelter 1879
1677 gezelter 1722 Vector3d vh = Ph / Mh;
1678 gezelter 1879 ah = momentumTarget_ / Mh + vh;
1679     ahrec = momentumTarget_ / Mh;
1680    
1681     // We now need the inverse of the inertia tensor to
1682     // calculate the angular velocity of the hot slab;
1683     Mat3x3d Ihi = Ih.inverse();
1684     Vector3d omegah = Ihi * Lh;
1685     bh = (Ihi * angularMomentumTarget_) + omegah;
1686     bhrec = bh - omegah;
1687    
1688     RealType hNumerator = Kh + kineticTarget_;
1689     if (doLinearPart)
1690     hNumerator -= 0.5 * Mh * ah.lengthSquare();
1691    
1692     if (doAngularPart)
1693     hNumerator -= 0.5 * ( dot(bh, Ih * bh));
1694    
1695     if (hNumerator > 0.0) {
1696    
1697     RealType hDenominator = Kh;
1698     if (doLinearPart)
1699     hDenominator -= 0.5 * Mh * vh.lengthSquare();
1700     if (doAngularPart)
1701     hDenominator -= 0.5*(dot(omegah, Ih * omegah));
1702    
1703 gezelter 1722 if (hDenominator > 0.0) {
1704     RealType h = sqrt(hNumerator / hDenominator);
1705     if ((h > 0.9) && (h < 1.1)) {
1706 gezelter 1879
1707 gezelter 1722 vector<StuntDouble*>::iterator sdi;
1708     Vector3d vel;
1709 gezelter 1879 Vector3d rPos;
1710    
1711     for (sdi = coldBin.begin(); sdi != coldBin.end(); ++sdi) {
1712 gezelter 1722 //vel = (*sdi)->getVel();
1713 gezelter 1879 rPos = (*sdi)->getPos() - coordinateOrigin_;
1714     if (doLinearPart)
1715     vel = ((*sdi)->getVel() - vc) * c + ac;
1716     if (doAngularPart)
1717     vel = ((*sdi)->getVel() - cross(omegac, rPos)) * c + cross(bc, rPos);
1718    
1719 gezelter 1722 (*sdi)->setVel(vel);
1720 gezelter 1773 if (rnemdFluxType_ == rnemdFullKE) {
1721 gezelter 1722 if ((*sdi)->isDirectional()) {
1722     Vector3d angMom = (*sdi)->getJ() * c;
1723     (*sdi)->setJ(angMom);
1724     }
1725     }
1726     }
1727 gezelter 1879 for (sdi = hotBin.begin(); sdi != hotBin.end(); ++sdi) {
1728 gezelter 1722 //vel = (*sdi)->getVel();
1729 gezelter 1879 rPos = (*sdi)->getPos() - coordinateOrigin_;
1730     if (doLinearPart)
1731     vel = ((*sdi)->getVel() - vh) * h + ah;
1732     if (doAngularPart)
1733     vel = ((*sdi)->getVel() - cross(omegah, rPos)) * h + cross(bh, rPos);
1734    
1735 gezelter 1722 (*sdi)->setVel(vel);
1736 gezelter 1773 if (rnemdFluxType_ == rnemdFullKE) {
1737 gezelter 1722 if ((*sdi)->isDirectional()) {
1738     Vector3d angMom = (*sdi)->getJ() * h;
1739     (*sdi)->setJ(angMom);
1740     }
1741     }
1742     }
1743     successfulExchange = true;
1744 gezelter 1773 kineticExchange_ += kineticTarget_;
1745     momentumExchange_ += momentumTarget_;
1746 gezelter 1879 angularMomentumExchange_ += angularMomentumTarget_;
1747 gezelter 1722 }
1748     }
1749     }
1750     }
1751     }
1752 skuang 1368 }
1753 gezelter 1722 }
1754     if (successfulExchange != true) {
1755 gezelter 1773 sprintf(painCave.errMsg,
1756     "RNEMD::doVSS exchange NOT performed - roots that solve\n"
1757     "\tthe constraint equations may not exist or there may be\n"
1758     "\tno selected objects in one or both slabs.\n");
1759     painCave.isFatal = 0;
1760     painCave.severity = OPENMD_INFO;
1761     simError();
1762 skuang 1368 failTrialCount_++;
1763     }
1764     }
1765    
1766 gezelter 1879 RealType RNEMD::getDividingArea() {
1767    
1768     if (hasDividingArea_) return dividingArea_;
1769    
1770     RealType areaA, areaB;
1771     Snapshot* snap = info_->getSnapshotManager()->getCurrentSnapshot();
1772    
1773     if (hasSelectionA_) {
1774 gezelter 1903
1775     if (evaluatorA_.hasSurfaceArea())
1776     areaA = evaluatorA_.getSurfaceArea();
1777     else {
1778    
1779     cerr << "selection A did not have surface area, recomputing\n";
1780     int isd;
1781     StuntDouble* sd;
1782     vector<StuntDouble*> aSites;
1783     seleManA_.setSelectionSet(evaluatorA_.evaluate());
1784     for (sd = seleManA_.beginSelected(isd); sd != NULL;
1785     sd = seleManA_.nextSelected(isd)) {
1786     aSites.push_back(sd);
1787     }
1788 gezelter 1879 #if defined(HAVE_QHULL)
1789 gezelter 1903 ConvexHull* surfaceMeshA = new ConvexHull();
1790     surfaceMeshA->computeHull(aSites);
1791 gezelter 2026 cerr << "flag1\n";
1792 gezelter 1903 areaA = surfaceMeshA->getArea();
1793 gezelter 2026 cerr << "Flag2 " << areaA << "\n";
1794 gezelter 1903 delete surfaceMeshA;
1795 gezelter 1879 #else
1796 gezelter 1903 sprintf( painCave.errMsg,
1797 gezelter 1879 "RNEMD::getDividingArea : Hull calculation is not possible\n"
1798 gezelter 1903 "\twithout libqhull. Please rebuild OpenMD with qhull enabled.");
1799     painCave.severity = OPENMD_ERROR;
1800     painCave.isFatal = 1;
1801     simError();
1802 gezelter 1879 #endif
1803 gezelter 1903 }
1804 gezelter 1879
1805     } else {
1806     if (usePeriodicBoundaryConditions_) {
1807     // in periodic boundaries, the surface area is twice the x-y
1808     // area of the current box:
1809     areaA = 2.0 * snap->getXYarea();
1810     } else {
1811     // in non-periodic simulations, without explicitly setting
1812     // selections, the sphere radius sets the surface area of the
1813     // dividing surface:
1814     areaA = 4.0 * M_PI * pow(sphereARadius_, 2);
1815     }
1816     }
1817    
1818     if (hasSelectionB_) {
1819 gezelter 1903 if (evaluatorB_.hasSurfaceArea())
1820     areaB = evaluatorB_.getSurfaceArea();
1821     else {
1822     cerr << "selection B did not have surface area, recomputing\n";
1823 gezelter 1879
1824 gezelter 1903 int isd;
1825     StuntDouble* sd;
1826     vector<StuntDouble*> bSites;
1827     seleManB_.setSelectionSet(evaluatorB_.evaluate());
1828     for (sd = seleManB_.beginSelected(isd); sd != NULL;
1829     sd = seleManB_.nextSelected(isd)) {
1830     bSites.push_back(sd);
1831     }
1832    
1833 gezelter 1879 #if defined(HAVE_QHULL)
1834 gezelter 1903 ConvexHull* surfaceMeshB = new ConvexHull();
1835     surfaceMeshB->computeHull(bSites);
1836     areaB = surfaceMeshB->getArea();
1837     delete surfaceMeshB;
1838 gezelter 1879 #else
1839 gezelter 1903 sprintf( painCave.errMsg,
1840     "RNEMD::getDividingArea : Hull calculation is not possible\n"
1841     "\twithout libqhull. Please rebuild OpenMD with qhull enabled.");
1842     painCave.severity = OPENMD_ERROR;
1843     painCave.isFatal = 1;
1844     simError();
1845 gezelter 1879 #endif
1846 gezelter 1903 }
1847    
1848 gezelter 1879 } else {
1849     if (usePeriodicBoundaryConditions_) {
1850     // in periodic boundaries, the surface area is twice the x-y
1851     // area of the current box:
1852     areaB = 2.0 * snap->getXYarea();
1853     } else {
1854     // in non-periodic simulations, without explicitly setting
1855     // selections, but if a sphereBradius has been set, just use that:
1856     areaB = 4.0 * M_PI * pow(sphereBRadius_, 2);
1857     }
1858     }
1859 gezelter 1903
1860 gezelter 1879 dividingArea_ = min(areaA, areaB);
1861     hasDividingArea_ = true;
1862     return dividingArea_;
1863     }
1864    
1865 skuang 1368 void RNEMD::doRNEMD() {
1866 gezelter 1776 if (!doRNEMD_) return;
1867 gezelter 1773 trialCount_++;
1868 gezelter 1879
1869     // object evaluator:
1870     evaluator_.loadScriptString(rnemdObjectSelection_);
1871     seleMan_.setSelectionSet(evaluator_.evaluate());
1872    
1873     evaluatorA_.loadScriptString(selectionA_);
1874     evaluatorB_.loadScriptString(selectionB_);
1875    
1876     seleManA_.setSelectionSet(evaluatorA_.evaluate());
1877     seleManB_.setSelectionSet(evaluatorB_.evaluate());
1878    
1879     commonA_ = seleManA_ & seleMan_;
1880     commonB_ = seleManB_ & seleMan_;
1881    
1882     // Target exchange quantities (in each exchange) = dividingArea * dt * flux
1883     // dt = exchange time interval
1884     // flux = target flux
1885     // dividingArea = smallest dividing surface between the two regions
1886    
1887     hasDividingArea_ = false;
1888     RealType area = getDividingArea();
1889    
1890     kineticTarget_ = kineticFlux_ * exchangeTime_ * area;
1891     momentumTarget_ = momentumFluxVector_ * exchangeTime_ * area;
1892     angularMomentumTarget_ = angularMomentumFluxVector_ * exchangeTime_ * area;
1893    
1894 gezelter 1773 switch(rnemdMethod_) {
1895     case rnemdSwap:
1896 gezelter 1879 doSwap(commonA_, commonB_);
1897 skuang 1368 break;
1898 gezelter 1773 case rnemdNIVS:
1899 gezelter 1879 doNIVS(commonA_, commonB_);
1900 gezelter 1722 break;
1901 gezelter 1773 case rnemdVSS:
1902 gezelter 1879 doVSS(commonA_, commonB_);
1903 gezelter 1773 break;
1904     case rnemdUnkownMethod:
1905 skuang 1368 default :
1906     break;
1907     }
1908     }
1909    
1910     void RNEMD::collectData() {
1911 gezelter 1776 if (!doRNEMD_) return;
1912 skuang 1368 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1913 gezelter 1879
1914     // collectData can be called more frequently than the doRNEMD, so use the
1915     // computed area from the last exchange time:
1916     RealType area = getDividingArea();
1917     areaAccumulator_->add(area);
1918 skuang 1368 Mat3x3d hmat = currentSnap_->getHmat();
1919 gezelter 1940 Vector3d u = angularMomentumFluxVector_;
1920     u.normalize();
1921    
1922 skuang 1368 seleMan_.setSelectionSet(evaluator_.evaluate());
1923    
1924 gezelter 1801 int selei(0);
1925 skuang 1368 StuntDouble* sd;
1926 gezelter 1879 int binNo;
1927 gezelter 1941 RealType mass;
1928     Vector3d vel;
1929     Vector3d rPos;
1930     RealType KE;
1931     Vector3d L;
1932     Mat3x3d I;
1933     RealType r2;
1934 skuang 1368
1935 gezelter 1773 vector<RealType> binMass(nBins_, 0.0);
1936 gezelter 1941 vector<Vector3d> binP(nBins_, V3Zero);
1937 gezelter 1940 vector<RealType> binOmega(nBins_, 0.0);
1938 gezelter 1941 vector<Vector3d> binL(nBins_, V3Zero);
1939     vector<Mat3x3d> binI(nBins_);
1940 gezelter 1773 vector<RealType> binKE(nBins_, 0.0);
1941     vector<int> binDOF(nBins_, 0);
1942     vector<int> binCount(nBins_, 0);
1943 jmarr 1728
1944 gezelter 1629 // alternative approach, track all molecules instead of only those
1945     // selected for scaling/swapping:
1946     /*
1947 gezelter 1879 SimInfo::MoleculeIterator miter;
1948     vector<StuntDouble*>::iterator iiter;
1949     Molecule* mol;
1950     StuntDouble* sd;
1951     for (mol = info_->beginMolecule(miter); mol != NULL;
1952 jmarr 1728 mol = info_->nextMolecule(miter))
1953 gezelter 1769 sd is essentially sd
1954 gezelter 1879 for (sd = mol->beginIntegrableObject(iiter);
1955     sd != NULL;
1956     sd = mol->nextIntegrableObject(iiter))
1957 gezelter 1629 */
1958 gezelter 1801
1959 skuang 1368 for (sd = seleMan_.beginSelected(selei); sd != NULL;
1960 gezelter 1793 sd = seleMan_.nextSelected(selei)) {
1961 gezelter 1801
1962 skuang 1338 Vector3d pos = sd->getPos();
1963    
1964     // wrap the stuntdouble's position back into the box:
1965    
1966 gezelter 1879 if (usePeriodicBoundaryConditions_) {
1967 skuang 1338 currentSnap_->wrapVector(pos);
1968 gezelter 1879 // which bin is this stuntdouble in?
1969     // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
1970     // Shift molecules by half a box to have bins start at 0
1971     // The modulo operator is used to wrap the case when we are
1972     // beyond the end of the bins back to the beginning.
1973     binNo = int(nBins_ * (pos.z() / hmat(2,2) + 0.5)) % nBins_;
1974     } else {
1975     Vector3d rPos = pos - coordinateOrigin_;
1976     binNo = int(rPos.length() / binWidth_);
1977     }
1978 gezelter 1773
1979 gezelter 1941 mass = sd->getMass();
1980     vel = sd->getVel();
1981     rPos = sd->getPos() - coordinateOrigin_;
1982 gezelter 1946 KE = 0.5 * mass * vel.lengthSquare();
1983 gezelter 1941 L = mass * cross(rPos, vel);
1984     I = outProduct(rPos, rPos) * mass;
1985     r2 = rPos.lengthSquare();
1986     I(0, 0) += mass * r2;
1987     I(1, 1) += mass * r2;
1988     I(2, 2) += mass * r2;
1989 gezelter 1940
1990     // Project the relative position onto a plane perpendicular to
1991     // the angularMomentumFluxVector:
1992 gezelter 1941 // Vector3d rProj = rPos - dot(rPos, u) * u;
1993 gezelter 1940 // Project the velocity onto a plane perpendicular to the
1994     // angularMomentumFluxVector:
1995 gezelter 1941 // Vector3d vProj = vel - dot(vel, u) * u;
1996 gezelter 1940 // Compute angular velocity vector (should be nearly parallel to
1997     // angularMomentumFluxVector
1998 gezelter 1941 // Vector3d aVel = cross(rProj, vProj);
1999    
2000 gezelter 1879 if (binNo >= 0 && binNo < nBins_) {
2001     binCount[binNo]++;
2002     binMass[binNo] += mass;
2003 gezelter 1941 binP[binNo] += mass*vel;
2004     binKE[binNo] += KE;
2005     binI[binNo] += I;
2006     binL[binNo] += L;
2007 gezelter 1879 binDOF[binNo] += 3;
2008    
2009     if (sd->isDirectional()) {
2010     Vector3d angMom = sd->getJ();
2011 gezelter 1941 Mat3x3d Ia = sd->getI();
2012 gezelter 1879 if (sd->isLinear()) {
2013     int i = sd->linearAxis();
2014     int j = (i + 1) % 3;
2015     int k = (i + 2) % 3;
2016 gezelter 1941 binKE[binNo] += 0.5 * (angMom[j] * angMom[j] / Ia(j, j) +
2017     angMom[k] * angMom[k] / Ia(k, k));
2018 gezelter 1879 binDOF[binNo] += 2;
2019     } else {
2020 gezelter 1941 binKE[binNo] += 0.5 * (angMom[0] * angMom[0] / Ia(0, 0) +
2021     angMom[1] * angMom[1] / Ia(1, 1) +
2022     angMom[2] * angMom[2] / Ia(2, 2));
2023 gezelter 1879 binDOF[binNo] += 3;
2024     }
2025 gezelter 1773 }
2026 gezelter 1722 }
2027 gezelter 1773 }
2028    
2029     #ifdef IS_MPI
2030 gezelter 1941
2031     for (int i = 0; i < nBins_; i++) {
2032 gezelter 1969
2033     MPI_Allreduce(MPI_IN_PLACE, &binCount[i],
2034     1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
2035     MPI_Allreduce(MPI_IN_PLACE, &binMass[i],
2036     1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
2037 gezelter 1971 MPI_Allreduce(MPI_IN_PLACE, binP[i].getArrayPointer(),
2038 gezelter 1969 3, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
2039 gezelter 1971 MPI_Allreduce(MPI_IN_PLACE, binL[i].getArrayPointer(),
2040 gezelter 1969 3, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
2041 gezelter 1971 MPI_Allreduce(MPI_IN_PLACE, binI[i].getArrayPointer(),
2042 gezelter 1969 9, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
2043     MPI_Allreduce(MPI_IN_PLACE, &binKE[i],
2044     1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
2045     MPI_Allreduce(MPI_IN_PLACE, &binDOF[i],
2046     1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
2047     //MPI_Allreduce(MPI_IN_PLACE, &binOmega[i],
2048     // 1, MPI_REALTYPE, MPI_SUM, MPI_COMM_WORLD);
2049 gezelter 1941 }
2050    
2051 gezelter 1773 #endif
2052    
2053 gezelter 1941 Vector3d omega;
2054 gezelter 1773 RealType den;
2055     RealType temp;
2056     RealType z;
2057 gezelter 1879 RealType r;
2058 gezelter 1773 for (int i = 0; i < nBins_; i++) {
2059 gezelter 1879 if (usePeriodicBoundaryConditions_) {
2060     z = (((RealType)i + 0.5) / (RealType)nBins_) * hmat(2,2);
2061     den = binMass[i] * nBins_ * PhysicalConstants::densityConvert
2062     / currentSnap_->getVolume() ;
2063     } else {
2064     r = (((RealType)i + 0.5) * binWidth_);
2065     RealType rinner = (RealType)i * binWidth_;
2066     RealType router = (RealType)(i+1) * binWidth_;
2067     den = binMass[i] * 3.0 * PhysicalConstants::densityConvert
2068     / (4.0 * M_PI * (pow(router,3) - pow(rinner,3)));
2069     }
2070 gezelter 1941 vel = binP[i] / binMass[i];
2071 gezelter 1777
2072 gezelter 1941 omega = binI[i].inverse() * binL[i];
2073    
2074     // omega = binOmega[i] / binCount[i];
2075    
2076 gezelter 1804 if (binCount[i] > 0) {
2077     // only add values if there are things to add
2078     temp = 2.0 * binKE[i] / (binDOF[i] * PhysicalConstants::kb *
2079     PhysicalConstants::energyConvert);
2080    
2081     for (unsigned int j = 0; j < outputMask_.size(); ++j) {
2082     if(outputMask_[j]) {
2083     switch(j) {
2084     case Z:
2085     dynamic_cast<Accumulator *>(data_[j].accumulator[i])->add(z);
2086     break;
2087 gezelter 1879 case R:
2088     dynamic_cast<Accumulator *>(data_[j].accumulator[i])->add(r);
2089     break;
2090 gezelter 1804 case TEMPERATURE:
2091     dynamic_cast<Accumulator *>(data_[j].accumulator[i])->add(temp);
2092     break;
2093     case VELOCITY:
2094     dynamic_cast<VectorAccumulator *>(data_[j].accumulator[i])->add(vel);
2095     break;
2096 gezelter 1879 case ANGULARVELOCITY:
2097 gezelter 1941 dynamic_cast<VectorAccumulator *>(data_[j].accumulator[i])->add(omega);
2098 gezelter 1879 break;
2099 gezelter 1804 case DENSITY:
2100     dynamic_cast<Accumulator *>(data_[j].accumulator[i])->add(den);
2101     break;
2102     }
2103 gezelter 1773 }
2104     }
2105 gezelter 1629 }
2106 skuang 1338 }
2107 gezelter 1879 hasData_ = true;
2108 skuang 1368 }
2109    
2110     void RNEMD::getStarted() {
2111 gezelter 1776 if (!doRNEMD_) return;
2112 gezelter 1879 hasDividingArea_ = false;
2113 gezelter 1629 collectData();
2114 gezelter 1773 writeOutputFile();
2115 skuang 1368 }
2116    
2117 gezelter 1773 void RNEMD::parseOutputFileFormat(const std::string& format) {
2118 gezelter 1776 if (!doRNEMD_) return;
2119 gezelter 1773 StringTokenizer tokenizer(format, " ,;|\t\n\r");
2120    
2121     while(tokenizer.hasMoreTokens()) {
2122     std::string token(tokenizer.nextToken());
2123     toUpper(token);
2124     OutputMapType::iterator i = outputMap_.find(token);
2125     if (i != outputMap_.end()) {
2126     outputMask_.set(i->second);
2127     } else {
2128     sprintf( painCave.errMsg,
2129     "RNEMD::parseOutputFileFormat: %s is not a recognized\n"
2130     "\toutputFileFormat keyword.\n", token.c_str() );
2131     painCave.isFatal = 0;
2132     painCave.severity = OPENMD_ERROR;
2133     simError();
2134     }
2135     }
2136     }
2137    
2138     void RNEMD::writeOutputFile() {
2139 gezelter 1776 if (!doRNEMD_) return;
2140 gezelter 1879 if (!hasData_) return;
2141 gezelter 1773
2142 gezelter 1350 #ifdef IS_MPI
2143     // If we're the root node, should we print out the results
2144 gezelter 1969 int worldRank;
2145     MPI_Comm_rank( MPI_COMM_WORLD, &worldRank);
2146    
2147 gezelter 1350 if (worldRank == 0) {
2148     #endif
2149 gezelter 1773 rnemdFile_.open(rnemdFileName_.c_str(), std::ios::out | std::ios::trunc );
2150    
2151     if( !rnemdFile_ ){
2152     sprintf( painCave.errMsg,
2153     "Could not open \"%s\" for RNEMD output.\n",
2154     rnemdFileName_.c_str());
2155     painCave.isFatal = 1;
2156     simError();
2157     }
2158 gezelter 1722
2159 gezelter 1773 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
2160    
2161     RealType time = currentSnap_->getTime();
2162 gezelter 1774 RealType avgArea;
2163     areaAccumulator_->getAverage(avgArea);
2164    
2165 gezelter 1879 RealType Jz(0.0);
2166     Vector3d JzP(V3Zero);
2167     Vector3d JzL(V3Zero);
2168     if (time >= info_->getSimParams()->getDt()) {
2169     Jz = kineticExchange_ / (time * avgArea)
2170     / PhysicalConstants::energyConvert;
2171     JzP = momentumExchange_ / (time * avgArea);
2172     JzL = angularMomentumExchange_ / (time * avgArea);
2173     }
2174    
2175 gezelter 1773 rnemdFile_ << "#######################################################\n";
2176     rnemdFile_ << "# RNEMD {\n";
2177    
2178     map<string, RNEMDMethod>::iterator mi;
2179     for(mi = stringToMethod_.begin(); mi != stringToMethod_.end(); ++mi) {
2180     if ( (*mi).second == rnemdMethod_)
2181 gezelter 1774 rnemdFile_ << "# exchangeMethod = \"" << (*mi).first << "\";\n";
2182 skuang 1368 }
2183 gezelter 1773 map<string, RNEMDFluxType>::iterator fi;
2184     for(fi = stringToFluxType_.begin(); fi != stringToFluxType_.end(); ++fi) {
2185     if ( (*fi).second == rnemdFluxType_)
2186 gezelter 1774 rnemdFile_ << "# fluxType = \"" << (*fi).first << "\";\n";
2187 gezelter 1722 }
2188 gezelter 1773
2189 gezelter 1775 rnemdFile_ << "# exchangeTime = " << exchangeTime_ << ";\n";
2190 gezelter 1773
2191     rnemdFile_ << "# objectSelection = \""
2192 gezelter 1774 << rnemdObjectSelection_ << "\";\n";
2193 gezelter 1879 rnemdFile_ << "# selectionA = \"" << selectionA_ << "\";\n";
2194     rnemdFile_ << "# selectionB = \"" << selectionB_ << "\";\n";
2195 gezelter 1773 rnemdFile_ << "# }\n";
2196     rnemdFile_ << "#######################################################\n";
2197 gezelter 1774 rnemdFile_ << "# RNEMD report:\n";
2198 gezelter 1879 rnemdFile_ << "# running time = " << time << " fs\n";
2199     rnemdFile_ << "# Target flux:\n";
2200     rnemdFile_ << "# kinetic = "
2201 gezelter 1777 << kineticFlux_ / PhysicalConstants::energyConvert
2202     << " (kcal/mol/A^2/fs)\n";
2203 gezelter 1879 rnemdFile_ << "# momentum = " << momentumFluxVector_
2204 gezelter 1777 << " (amu/A/fs^2)\n";
2205 gezelter 1879 rnemdFile_ << "# angular momentum = " << angularMomentumFluxVector_
2206     << " (amu/A^2/fs^2)\n";
2207     rnemdFile_ << "# Target one-time exchanges:\n";
2208     rnemdFile_ << "# kinetic = "
2209 gezelter 1777 << kineticTarget_ / PhysicalConstants::energyConvert
2210     << " (kcal/mol)\n";
2211 gezelter 1879 rnemdFile_ << "# momentum = " << momentumTarget_
2212 gezelter 1777 << " (amu*A/fs)\n";
2213 gezelter 1879 rnemdFile_ << "# angular momentum = " << angularMomentumTarget_
2214     << " (amu*A^2/fs)\n";
2215     rnemdFile_ << "# Actual exchange totals:\n";
2216     rnemdFile_ << "# kinetic = "
2217 gezelter 1777 << kineticExchange_ / PhysicalConstants::energyConvert
2218     << " (kcal/mol)\n";
2219 gezelter 1879 rnemdFile_ << "# momentum = " << momentumExchange_
2220 gezelter 1777 << " (amu*A/fs)\n";
2221 gezelter 1879 rnemdFile_ << "# angular momentum = " << angularMomentumExchange_
2222     << " (amu*A^2/fs)\n";
2223     rnemdFile_ << "# Actual flux:\n";
2224     rnemdFile_ << "# kinetic = " << Jz
2225 gezelter 1777 << " (kcal/mol/A^2/fs)\n";
2226 gezelter 1879 rnemdFile_ << "# momentum = " << JzP
2227 gezelter 1777 << " (amu/A/fs^2)\n";
2228 gezelter 1879 rnemdFile_ << "# angular momentum = " << JzL
2229     << " (amu/A^2/fs^2)\n";
2230     rnemdFile_ << "# Exchange statistics:\n";
2231     rnemdFile_ << "# attempted = " << trialCount_ << "\n";
2232     rnemdFile_ << "# failed = " << failTrialCount_ << "\n";
2233 gezelter 1773 if (rnemdMethod_ == rnemdNIVS) {
2234 gezelter 1879 rnemdFile_ << "# NIVS root-check errors = "
2235 gezelter 1774 << failRootCount_ << "\n";
2236 gezelter 1722 }
2237 gezelter 1773 rnemdFile_ << "#######################################################\n";
2238    
2239    
2240    
2241     //write title
2242     rnemdFile_ << "#";
2243     for (unsigned int i = 0; i < outputMask_.size(); ++i) {
2244     if (outputMask_[i]) {
2245     rnemdFile_ << "\t" << data_[i].title <<
2246     "(" << data_[i].units << ")";
2247 gezelter 1777 // add some extra tabs for column alignment
2248     if (data_[i].dataType == "Vector3d") rnemdFile_ << "\t\t";
2249 skuang 1368 }
2250 gezelter 1773 }
2251     rnemdFile_ << std::endl;
2252    
2253     rnemdFile_.precision(8);
2254    
2255 gezelter 1789 for (int j = 0; j < nBins_; j++) {
2256 gezelter 1773
2257     for (unsigned int i = 0; i < outputMask_.size(); ++i) {
2258     if (outputMask_[i]) {
2259     if (data_[i].dataType == "RealType")
2260     writeReal(i,j);
2261 gezelter 1879 else if (data_[i].dataType == "Vector3d")
2262 gezelter 1773 writeVector(i,j);
2263     else {
2264     sprintf( painCave.errMsg,
2265     "RNEMD found an unknown data type for: %s ",
2266     data_[i].title.c_str());
2267     painCave.isFatal = 1;
2268     simError();
2269     }
2270     }
2271 skuang 1368 }
2272 gezelter 1773 rnemdFile_ << std::endl;
2273    
2274     }
2275 gezelter 1774
2276     rnemdFile_ << "#######################################################\n";
2277 gezelter 1979 rnemdFile_ << "# 95% confidence intervals in those quantities follow:\n";
2278 gezelter 1774 rnemdFile_ << "#######################################################\n";
2279    
2280    
2281 gezelter 1789 for (int j = 0; j < nBins_; j++) {
2282 gezelter 1774 rnemdFile_ << "#";
2283     for (unsigned int i = 0; i < outputMask_.size(); ++i) {
2284     if (outputMask_[i]) {
2285     if (data_[i].dataType == "RealType")
2286 gezelter 1979 writeRealErrorBars(i,j);
2287 gezelter 1774 else if (data_[i].dataType == "Vector3d")
2288 gezelter 1979 writeVectorErrorBars(i,j);
2289 gezelter 1774 else {
2290     sprintf( painCave.errMsg,
2291     "RNEMD found an unknown data type for: %s ",
2292     data_[i].title.c_str());
2293     painCave.isFatal = 1;
2294     simError();
2295     }
2296     }
2297     }
2298     rnemdFile_ << std::endl;
2299    
2300     }
2301 gezelter 1773
2302     rnemdFile_.flush();
2303     rnemdFile_.close();
2304    
2305 gezelter 1350 #ifdef IS_MPI
2306 gezelter 1396 }
2307 gezelter 1350 #endif
2308 jmarr 1728
2309 gezelter 1334 }
2310 gezelter 1773
2311     void RNEMD::writeReal(int index, unsigned int bin) {
2312 gezelter 1776 if (!doRNEMD_) return;
2313 gezelter 1773 assert(index >=0 && index < ENDINDEX);
2314 gezelter 1879 assert(int(bin) < nBins_);
2315 gezelter 1773 RealType s;
2316 gezelter 1879 int count;
2317 gezelter 1773
2318 gezelter 1879 count = data_[index].accumulator[bin]->count();
2319     if (count == 0) return;
2320    
2321 gezelter 1791 dynamic_cast<Accumulator *>(data_[index].accumulator[bin])->getAverage(s);
2322 gezelter 1773
2323     if (! isinf(s) && ! isnan(s)) {
2324     rnemdFile_ << "\t" << s;
2325     } else{
2326     sprintf( painCave.errMsg,
2327 gezelter 1879 "RNEMD detected a numerical error writing: %s for bin %u",
2328 gezelter 1773 data_[index].title.c_str(), bin);
2329     painCave.isFatal = 1;
2330     simError();
2331     }
2332     }
2333    
2334     void RNEMD::writeVector(int index, unsigned int bin) {
2335 gezelter 1776 if (!doRNEMD_) return;
2336 gezelter 1773 assert(index >=0 && index < ENDINDEX);
2337 gezelter 1879 assert(int(bin) < nBins_);
2338 gezelter 1773 Vector3d s;
2339 gezelter 1879 int count;
2340    
2341     count = data_[index].accumulator[bin]->count();
2342    
2343     if (count == 0) return;
2344    
2345 gezelter 1773 dynamic_cast<VectorAccumulator*>(data_[index].accumulator[bin])->getAverage(s);
2346     if (isinf(s[0]) || isnan(s[0]) ||
2347     isinf(s[1]) || isnan(s[1]) ||
2348     isinf(s[2]) || isnan(s[2]) ) {
2349     sprintf( painCave.errMsg,
2350 gezelter 1879 "RNEMD detected a numerical error writing: %s for bin %u",
2351 gezelter 1773 data_[index].title.c_str(), bin);
2352     painCave.isFatal = 1;
2353     simError();
2354     } else {
2355     rnemdFile_ << "\t" << s[0] << "\t" << s[1] << "\t" << s[2];
2356     }
2357     }
2358 gezelter 1774
2359 gezelter 1979 void RNEMD::writeRealErrorBars(int index, unsigned int bin) {
2360 gezelter 1776 if (!doRNEMD_) return;
2361 gezelter 1774 assert(index >=0 && index < ENDINDEX);
2362 gezelter 1879 assert(int(bin) < nBins_);
2363 gezelter 1774 RealType s;
2364 gezelter 1879 int count;
2365 gezelter 1774
2366 gezelter 1879 count = data_[index].accumulator[bin]->count();
2367     if (count == 0) return;
2368    
2369 gezelter 1979 dynamic_cast<Accumulator *>(data_[index].accumulator[bin])->get95percentConfidenceInterval(s);
2370 gezelter 1774
2371     if (! isinf(s) && ! isnan(s)) {
2372     rnemdFile_ << "\t" << s;
2373     } else{
2374     sprintf( painCave.errMsg,
2375 gezelter 1879 "RNEMD detected a numerical error writing: %s std. dev. for bin %u",
2376 gezelter 1774 data_[index].title.c_str(), bin);
2377     painCave.isFatal = 1;
2378     simError();
2379     }
2380     }
2381    
2382 gezelter 1979 void RNEMD::writeVectorErrorBars(int index, unsigned int bin) {
2383 gezelter 1776 if (!doRNEMD_) return;
2384 gezelter 1774 assert(index >=0 && index < ENDINDEX);
2385 gezelter 1879 assert(int(bin) < nBins_);
2386 gezelter 1774 Vector3d s;
2387 gezelter 1879 int count;
2388    
2389     count = data_[index].accumulator[bin]->count();
2390     if (count == 0) return;
2391    
2392 gezelter 1979 dynamic_cast<VectorAccumulator*>(data_[index].accumulator[bin])->get95percentConfidenceInterval(s);
2393 gezelter 1774 if (isinf(s[0]) || isnan(s[0]) ||
2394     isinf(s[1]) || isnan(s[1]) ||
2395     isinf(s[2]) || isnan(s[2]) ) {
2396     sprintf( painCave.errMsg,
2397 gezelter 1879 "RNEMD detected a numerical error writing: %s std. dev. for bin %u",
2398 gezelter 1774 data_[index].title.c_str(), bin);
2399     painCave.isFatal = 1;
2400     simError();
2401     } else {
2402     rnemdFile_ << "\t" << s[0] << "\t" << s[1] << "\t" << s[2];
2403     }
2404     }
2405 skuang 1338 }
2406 gezelter 1722

Properties

Name Value
svn:keywords Author Id Revision Date