ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/rnemd/RNEMD.cpp
Revision: 1773
Committed: Tue Aug 7 18:26:40 2012 UTC (12 years, 8 months ago) by gezelter
File size: 53421 byte(s)
Log Message:
Adding new RNEMD options and output file format

File Contents

# Content
1 /*
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 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * 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 *
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 * [3] Sun, Lin & Gezelter, J. Chem. Phys. 128, 24107 (2008).
39 * [4] Vardeman & Gezelter, in progress (2009).
40 */
41
42 #include <cmath>
43 #include "rnemd/RNEMD.hpp"
44 #include "math/Vector3.hpp"
45 #include "math/Vector.hpp"
46 #include "math/SquareMatrix3.hpp"
47 #include "math/Polynomial.hpp"
48 #include "primitives/Molecule.hpp"
49 #include "primitives/StuntDouble.hpp"
50 #include "utils/PhysicalConstants.hpp"
51 #include "utils/Tuple.hpp"
52 #ifdef IS_MPI
53 #include <mpi.h>
54 #endif
55
56 #define HONKING_LARGE_VALUE 1.0e10
57
58 using namespace std;
59 namespace OpenMD {
60
61 RNEMD::RNEMD(SimInfo* info) : info_(info), evaluator_(info), seleMan_(info),
62 usePeriodicBoundaryConditions_(info->getSimParams()->getUsePeriodicBoundaryConditions()) {
63
64 trialCount_ = 0;
65 failTrialCount_ = 0;
66 failRootCount_ = 0;
67
68 int seedValue;
69 Globals * simParams = info->getSimParams();
70 RNEMDParameters* rnemdParams = simParams->getRNEMDParameters();
71
72 stringToMethod_["Swap"] = rnemdSwap;
73 stringToMethod_["NIVS"] = rnemdNIVS;
74 stringToMethod_["VSS"] = rnemdVSS;
75
76 stringToFluxType_["KE"] = rnemdKE;
77 stringToFluxType_["Px"] = rnemdPx;
78 stringToFluxType_["Py"] = rnemdPy;
79 stringToFluxType_["Pz"] = rnemdPz;
80 stringToFluxType_["KE+Px"] = rnemdKePx;
81 stringToFluxType_["KE+Py"] = rnemdKePy;
82 stringToFluxType_["KE+Pvector"] = rnemdKePvector;
83
84 runTime_ = simParams->getRunTime();
85 statusTime_ = simParams->getStatusTime();
86
87 rnemdObjectSelection_ = rnemdParams->getObjectSelection();
88 evaluator_.loadScriptString(rnemdObjectSelection_);
89 seleMan_.setSelectionSet(evaluator_.evaluate());
90
91 const string methStr = rnemdParams->getMethod();
92 bool hasFluxType = rnemdParams->haveFluxType();
93
94 string fluxStr;
95 if (hasFluxType) {
96 fluxStr = rnemdParams->getFluxType();
97 } else {
98 sprintf(painCave.errMsg,
99 "RNEMD: No fluxType was set in the md file. This parameter,\n"
100 "\twhich must be one of the following values:\n"
101 "\tKE, Px, Py, Pz, KE+Px, KE+Py, KE+Pvector, must be set to\n"
102 "\tuse RNEMD\n");
103 painCave.isFatal = 1;
104 painCave.severity = OPENMD_ERROR;
105 simError();
106 }
107
108 bool hasKineticFlux = rnemdParams->haveKineticFlux();
109 bool hasMomentumFlux = rnemdParams->haveMomentumFlux();
110 bool hasMomentumFluxVector = rnemdParams->haveMomentumFluxVector();
111 bool hasSlabWidth = rnemdParams->haveSlabWidth();
112 bool hasSlabACenter = rnemdParams->haveSlabACenter();
113 bool hasSlabBCenter = rnemdParams->haveSlabBCenter();
114 bool hasOutputFileName = rnemdParams->haveOutputFileName();
115 bool hasOutputFields = rnemdParams->haveOutputFields();
116
117 map<string, RNEMDMethod>::iterator i;
118 i = stringToMethod_.find(methStr);
119 if (i != stringToMethod_.end())
120 rnemdMethod_ = i->second;
121 else {
122 sprintf(painCave.errMsg,
123 "RNEMD: The current method,\n"
124 "\t\t%s is not one of the recognized\n"
125 "\texchange methods: Swap, NIVS, or VSS\n",
126 methStr.c_str());
127 painCave.isFatal = 1;
128 painCave.severity = OPENMD_ERROR;
129 simError();
130 }
131
132 map<string, RNEMDFluxType>::iterator j;
133 j = stringToFluxType_.find(fluxStr);
134 if (j != stringToFluxType_.end())
135 rnemdFluxType_ = j->second;
136 else {
137 sprintf(painCave.errMsg,
138 "RNEMD: The current fluxType,\n"
139 "\t\t%s\n"
140 "\tis not one of the recognized flux types.\n",
141 fluxStr.c_str());
142 painCave.isFatal = 1;
143 painCave.severity = OPENMD_ERROR;
144 simError();
145 }
146
147 bool methodFluxMismatch = false;
148 bool hasCorrectFlux = false;
149 switch(rnemdMethod_) {
150 case rnemdSwap:
151 switch (rnemdFluxType_) {
152 case rnemdKE:
153 hasCorrectFlux = hasKineticFlux;
154 break;
155 case rnemdPx:
156 case rnemdPy:
157 case rnemdPz:
158 hasCorrectFlux = hasMomentumFlux;
159 break;
160 default :
161 methodFluxMismatch = true;
162 break;
163 }
164 break;
165 case rnemdNIVS:
166 switch (rnemdFluxType_) {
167 case rnemdKE:
168 case rnemdRotKE:
169 case rnemdFullKE:
170 hasCorrectFlux = hasKineticFlux;
171 break;
172 case rnemdPx:
173 case rnemdPy:
174 case rnemdPz:
175 hasCorrectFlux = hasMomentumFlux;
176 break;
177 case rnemdKePx:
178 case rnemdKePy:
179 hasCorrectFlux = hasMomentumFlux && hasKineticFlux;
180 break;
181 default:
182 methodFluxMismatch = true;
183 break;
184 }
185 break;
186 case rnemdVSS:
187 switch (rnemdFluxType_) {
188 case rnemdKE:
189 case rnemdRotKE:
190 case rnemdFullKE:
191 hasCorrectFlux = hasKineticFlux;
192 break;
193 case rnemdPx:
194 case rnemdPy:
195 case rnemdPz:
196 hasCorrectFlux = hasMomentumFlux;
197 break;
198 case rnemdPvector:
199 hasCorrectFlux = hasMomentumFluxVector;
200 case rnemdKePx:
201 case rnemdKePy:
202 hasCorrectFlux = hasMomentumFlux && hasKineticFlux;
203 break;
204 case rnemdKePvector:
205 hasCorrectFlux = hasMomentumFluxVector && hasKineticFlux;
206 break;
207 default:
208 methodFluxMismatch = true;
209 break;
210 }
211 default:
212 break;
213 }
214
215 if (methodFluxMismatch) {
216 sprintf(painCave.errMsg,
217 "RNEMD: The current method,\n"
218 "\t\t%s\n"
219 "\tcannot be used with the current flux type, %s\n",
220 methStr.c_str(), fluxStr.c_str());
221 painCave.isFatal = 1;
222 painCave.severity = OPENMD_ERROR;
223 simError();
224 }
225 if (!hasCorrectFlux) {
226 sprintf(painCave.errMsg,
227 "RNEMD: The current method,\n"
228 "\t%s, and flux type %s\n"
229 "\tdid not have the correct flux value specified. Options\n"
230 "\tinclude: kineticFlux, momentumFlux, and momentumFluxVector\n",
231 methStr.c_str(), fluxStr.c_str());
232 painCave.isFatal = 1;
233 painCave.severity = OPENMD_ERROR;
234 simError();
235 }
236
237 if (hasKineticFlux) {
238 kineticFlux_ = rnemdParams->getKineticFlux();
239 } else {
240 kineticFlux_ = 0.0;
241 }
242 if (hasMomentumFluxVector) {
243 momentumFluxVector_ = rnemdParams->getMomentumFluxVector();
244 } else {
245 momentumFluxVector_ = V3Zero;
246 if (hasMomentumFlux) {
247 RealType momentumFlux = rnemdParams->getMomentumFlux();
248 switch (rnemdFluxType_) {
249 case rnemdPx:
250 momentumFluxVector_.x() = momentumFlux;
251 break;
252 case rnemdPy:
253 momentumFluxVector_.y() = momentumFlux;
254 break;
255 case rnemdPz:
256 momentumFluxVector_.z() = momentumFlux;
257 break;
258 case rnemdKePx:
259 momentumFluxVector_.x() = momentumFlux;
260 break;
261 case rnemdKePy:
262 momentumFluxVector_.y() = momentumFlux;
263 break;
264 default:
265 break;
266 }
267 }
268 }
269
270 // do some sanity checking
271
272 int selectionCount = seleMan_.getSelectionCount();
273 int nIntegrable = info->getNGlobalIntegrableObjects();
274
275 if (selectionCount > nIntegrable) {
276 sprintf(painCave.errMsg,
277 "RNEMD: The current objectSelection,\n"
278 "\t\t%s\n"
279 "\thas resulted in %d selected objects. However,\n"
280 "\tthe total number of integrable objects in the system\n"
281 "\tis only %d. This is almost certainly not what you want\n"
282 "\tto do. A likely cause of this is forgetting the _RB_0\n"
283 "\tselector in the selection script!\n",
284 rnemdObjectSelection_.c_str(),
285 selectionCount, nIntegrable);
286 painCave.isFatal = 0;
287 painCave.severity = OPENMD_WARNING;
288 simError();
289 }
290
291 nBins_ = rnemdParams->getOutputBins();
292
293 data_.resize(RNEMD::ENDINDEX);
294 OutputData z;
295 z.units = "Angstroms";
296 z.title = "Z";
297 z.dataType = "RealType";
298 z.accumulator.reserve(nBins_);
299 for (unsigned int i = 0; i < nBins_; i++)
300 z.accumulator.push_back( new Accumulator() );
301 data_[Z] = z;
302 outputMap_["Z"] = Z;
303
304 OutputData temperature;
305 temperature.units = "K";
306 temperature.title = "Temperature";
307 temperature.dataType = "RealType";
308 temperature.accumulator.reserve(nBins_);
309 for (unsigned int i = 0; i < nBins_; i++)
310 temperature.accumulator.push_back( new Accumulator() );
311 data_[TEMPERATURE] = temperature;
312 outputMap_["TEMPERATURE"] = TEMPERATURE;
313
314 OutputData velocity;
315 velocity.units = "amu/fs";
316 velocity.title = "Velocity";
317 velocity.dataType = "Vector3d";
318 velocity.accumulator.reserve(nBins_);
319 for (unsigned int i = 0; i < nBins_; i++)
320 velocity.accumulator.push_back( new VectorAccumulator() );
321 data_[VELOCITY] = velocity;
322 outputMap_["VELOCITY"] = VELOCITY;
323
324 OutputData density;
325 density.units = "g cm^-3";
326 density.title = "Density";
327 density.dataType = "RealType";
328 density.accumulator.reserve(nBins_);
329 for (unsigned int i = 0; i < nBins_; i++)
330 density.accumulator.push_back( new Accumulator() );
331 data_[DENSITY] = density;
332 outputMap_["DENSITY"] = DENSITY;
333
334 if (hasOutputFields) {
335 parseOutputFileFormat(rnemdParams->getOutputFields());
336 } else {
337 outputMask_.set(Z);
338 switch (rnemdFluxType_) {
339 case rnemdKE:
340 case rnemdRotKE:
341 case rnemdFullKE:
342 outputMask_.set(TEMPERATURE);
343 break;
344 case rnemdPx:
345 case rnemdPy:
346 outputMask_.set(VELOCITY);
347 break;
348 case rnemdPz:
349 case rnemdPvector:
350 outputMask_.set(VELOCITY);
351 outputMask_.set(DENSITY);
352 break;
353 case rnemdKePx:
354 case rnemdKePy:
355 outputMask_.set(TEMPERATURE);
356 outputMask_.set(VELOCITY);
357 break;
358 case rnemdKePvector:
359 outputMask_.set(TEMPERATURE);
360 outputMask_.set(VELOCITY);
361 outputMask_.set(DENSITY);
362 break;
363 default:
364 break;
365 }
366 }
367
368 if (hasOutputFileName) {
369 rnemdFileName_ = rnemdParams->getOutputFileName();
370 } else {
371 rnemdFileName_ = getPrefix(info->getFinalConfigFileName()) + ".rnemd";
372 }
373
374 exchangeTime_ = rnemdParams->getExchangeTime();
375
376 Snapshot* currentSnap_ = info->getSnapshotManager()->getCurrentSnapshot();
377 Mat3x3d hmat = currentSnap_->getHmat();
378
379 // Target exchange quantities (in each exchange) = 2 Lx Ly dt flux
380 // Lx, Ly = box dimensions in x & y
381 // dt = exchange time interval
382 // flux = target flux
383
384 kineticTarget_ = 2.0*kineticFlux_*exchangeTime_*hmat(0,0)*hmat(1,1);
385 momentumTarget_ = 2.0*momentumFluxVector_*exchangeTime_*hmat(0,0)*hmat(1,1);
386
387 // total exchange sums are zeroed out at the beginning:
388
389 kineticExchange_ = 0.0;
390 momentumExchange_ = V3Zero;
391
392 if (hasSlabWidth)
393 slabWidth_ = rnemdParams->getSlabWidth();
394 else
395 slabWidth_ = hmat(2,2) / 10.0;
396
397 if (hasSlabACenter)
398 slabACenter_ = rnemdParams->getSlabACenter();
399 else
400 slabACenter_ = 0.0;
401
402 if (hasSlabBCenter)
403 slabBCenter_ = rnemdParams->getSlabBCenter();
404 else
405 slabBCenter_ = hmat(2,2) / 2.0;
406
407 }
408
409 RNEMD::~RNEMD() {
410
411 #ifdef IS_MPI
412 if (worldRank == 0) {
413 #endif
414
415 writeOutputFile();
416
417 rnemdFile_.close();
418
419 #ifdef IS_MPI
420 }
421 #endif
422 }
423
424 bool RNEMD::inSlabA(Vector3d pos) {
425 return (abs(pos.z() - slabACenter_) < 0.5*slabWidth_);
426 }
427 bool RNEMD::inSlabB(Vector3d pos) {
428 return (abs(pos.z() - slabBCenter_) < 0.5*slabWidth_);
429 }
430
431 void RNEMD::doSwap() {
432
433 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
434 Mat3x3d hmat = currentSnap_->getHmat();
435
436 seleMan_.setSelectionSet(evaluator_.evaluate());
437
438 int selei;
439 StuntDouble* sd;
440 int idx;
441
442 RealType min_val;
443 bool min_found = false;
444 StuntDouble* min_sd;
445
446 RealType max_val;
447 bool max_found = false;
448 StuntDouble* max_sd;
449
450 for (sd = seleMan_.beginSelected(selei); sd != NULL;
451 sd = seleMan_.nextSelected(selei)) {
452
453 idx = sd->getLocalIndex();
454
455 Vector3d pos = sd->getPos();
456
457 // wrap the stuntdouble's position back into the box:
458
459 if (usePeriodicBoundaryConditions_)
460 currentSnap_->wrapVector(pos);
461 bool inA = inSlabA(pos);
462 bool inB = inSlabB(pos);
463
464 if (inA || inB) {
465
466 RealType mass = sd->getMass();
467 Vector3d vel = sd->getVel();
468 RealType value;
469
470 switch(rnemdFluxType_) {
471 case rnemdKE :
472
473 value = mass * vel.lengthSquare();
474
475 if (sd->isDirectional()) {
476 Vector3d angMom = sd->getJ();
477 Mat3x3d I = sd->getI();
478
479 if (sd->isLinear()) {
480 int i = sd->linearAxis();
481 int j = (i + 1) % 3;
482 int k = (i + 2) % 3;
483 value += angMom[j] * angMom[j] / I(j, j) +
484 angMom[k] * angMom[k] / I(k, k);
485 } else {
486 value += angMom[0]*angMom[0]/I(0, 0)
487 + angMom[1]*angMom[1]/I(1, 1)
488 + angMom[2]*angMom[2]/I(2, 2);
489 }
490 } //angular momenta exchange enabled
491 //energyConvert temporarily disabled
492 //make kineticExchange_ comparable between swap & scale
493 //value = value * 0.5 / PhysicalConstants::energyConvert;
494 value *= 0.5;
495 break;
496 case rnemdPx :
497 value = mass * vel[0];
498 break;
499 case rnemdPy :
500 value = mass * vel[1];
501 break;
502 case rnemdPz :
503 value = mass * vel[2];
504 break;
505 default :
506 break;
507 }
508
509 if (inA == 0) {
510 if (!min_found) {
511 min_val = value;
512 min_sd = sd;
513 min_found = true;
514 } else {
515 if (min_val > value) {
516 min_val = value;
517 min_sd = sd;
518 }
519 }
520 } else {
521 if (!max_found) {
522 max_val = value;
523 max_sd = sd;
524 max_found = true;
525 } else {
526 if (max_val < value) {
527 max_val = value;
528 max_sd = sd;
529 }
530 }
531 }
532 }
533 }
534
535 #ifdef IS_MPI
536 int nProc, worldRank;
537
538 nProc = MPI::COMM_WORLD.Get_size();
539 worldRank = MPI::COMM_WORLD.Get_rank();
540
541 bool my_min_found = min_found;
542 bool my_max_found = max_found;
543
544 // Even if we didn't find a minimum, did someone else?
545 MPI::COMM_WORLD.Allreduce(&my_min_found, &min_found, 1, MPI::BOOL, MPI::LOR);
546 // Even if we didn't find a maximum, did someone else?
547 MPI::COMM_WORLD.Allreduce(&my_max_found, &max_found, 1, MPI::BOOL, MPI::LOR);
548 #endif
549
550 if (max_found && min_found) {
551
552 #ifdef IS_MPI
553 struct {
554 RealType val;
555 int rank;
556 } max_vals, min_vals;
557
558 if (my_min_found) {
559 min_vals.val = min_val;
560 } else {
561 min_vals.val = HONKING_LARGE_VALUE;
562 }
563 min_vals.rank = worldRank;
564
565 // Who had the minimum?
566 MPI::COMM_WORLD.Allreduce(&min_vals, &min_vals,
567 1, MPI::REALTYPE_INT, MPI::MINLOC);
568 min_val = min_vals.val;
569
570 if (my_max_found) {
571 max_vals.val = max_val;
572 } else {
573 max_vals.val = -HONKING_LARGE_VALUE;
574 }
575 max_vals.rank = worldRank;
576
577 // Who had the maximum?
578 MPI::COMM_WORLD.Allreduce(&max_vals, &max_vals,
579 1, MPI::REALTYPE_INT, MPI::MAXLOC);
580 max_val = max_vals.val;
581 #endif
582
583 if (min_val < max_val) {
584
585 #ifdef IS_MPI
586 if (max_vals.rank == worldRank && min_vals.rank == worldRank) {
587 // I have both maximum and minimum, so proceed like a single
588 // processor version:
589 #endif
590
591 Vector3d min_vel = min_sd->getVel();
592 Vector3d max_vel = max_sd->getVel();
593 RealType temp_vel;
594
595 switch(rnemdFluxType_) {
596 case rnemdKE :
597 min_sd->setVel(max_vel);
598 max_sd->setVel(min_vel);
599 if (min_sd->isDirectional() && max_sd->isDirectional()) {
600 Vector3d min_angMom = min_sd->getJ();
601 Vector3d max_angMom = max_sd->getJ();
602 min_sd->setJ(max_angMom);
603 max_sd->setJ(min_angMom);
604 }//angular momenta exchange enabled
605 //assumes same rigid body identity
606 break;
607 case rnemdPx :
608 temp_vel = min_vel.x();
609 min_vel.x() = max_vel.x();
610 max_vel.x() = temp_vel;
611 min_sd->setVel(min_vel);
612 max_sd->setVel(max_vel);
613 break;
614 case rnemdPy :
615 temp_vel = min_vel.y();
616 min_vel.y() = max_vel.y();
617 max_vel.y() = temp_vel;
618 min_sd->setVel(min_vel);
619 max_sd->setVel(max_vel);
620 break;
621 case rnemdPz :
622 temp_vel = min_vel.z();
623 min_vel.z() = max_vel.z();
624 max_vel.z() = temp_vel;
625 min_sd->setVel(min_vel);
626 max_sd->setVel(max_vel);
627 break;
628 default :
629 break;
630 }
631
632 #ifdef IS_MPI
633 // the rest of the cases only apply in parallel simulations:
634 } else if (max_vals.rank == worldRank) {
635 // I had the max, but not the minimum
636
637 Vector3d min_vel;
638 Vector3d max_vel = max_sd->getVel();
639 MPI::Status status;
640
641 // point-to-point swap of the velocity vector
642 MPI::COMM_WORLD.Sendrecv(max_vel.getArrayPointer(), 3, MPI::REALTYPE,
643 min_vals.rank, 0,
644 min_vel.getArrayPointer(), 3, MPI::REALTYPE,
645 min_vals.rank, 0, status);
646
647 switch(rnemdFluxType_) {
648 case rnemdKE :
649 max_sd->setVel(min_vel);
650 //angular momenta exchange enabled
651 if (max_sd->isDirectional()) {
652 Vector3d min_angMom;
653 Vector3d max_angMom = max_sd->getJ();
654
655 // point-to-point swap of the angular momentum vector
656 MPI::COMM_WORLD.Sendrecv(max_angMom.getArrayPointer(), 3,
657 MPI::REALTYPE, min_vals.rank, 1,
658 min_angMom.getArrayPointer(), 3,
659 MPI::REALTYPE, min_vals.rank, 1,
660 status);
661
662 max_sd->setJ(min_angMom);
663 }
664 break;
665 case rnemdPx :
666 max_vel.x() = min_vel.x();
667 max_sd->setVel(max_vel);
668 break;
669 case rnemdPy :
670 max_vel.y() = min_vel.y();
671 max_sd->setVel(max_vel);
672 break;
673 case rnemdPz :
674 max_vel.z() = min_vel.z();
675 max_sd->setVel(max_vel);
676 break;
677 default :
678 break;
679 }
680 } else if (min_vals.rank == worldRank) {
681 // I had the minimum but not the maximum:
682
683 Vector3d max_vel;
684 Vector3d min_vel = min_sd->getVel();
685 MPI::Status status;
686
687 // point-to-point swap of the velocity vector
688 MPI::COMM_WORLD.Sendrecv(min_vel.getArrayPointer(), 3, MPI::REALTYPE,
689 max_vals.rank, 0,
690 max_vel.getArrayPointer(), 3, MPI::REALTYPE,
691 max_vals.rank, 0, status);
692
693 switch(rnemdFluxType_) {
694 case rnemdKE :
695 min_sd->setVel(max_vel);
696 //angular momenta exchange enabled
697 if (min_sd->isDirectional()) {
698 Vector3d min_angMom = min_sd->getJ();
699 Vector3d max_angMom;
700
701 // point-to-point swap of the angular momentum vector
702 MPI::COMM_WORLD.Sendrecv(min_angMom.getArrayPointer(), 3,
703 MPI::REALTYPE, max_vals.rank, 1,
704 max_angMom.getArrayPointer(), 3,
705 MPI::REALTYPE, max_vals.rank, 1,
706 status);
707
708 min_sd->setJ(max_angMom);
709 }
710 break;
711 case rnemdPx :
712 min_vel.x() = max_vel.x();
713 min_sd->setVel(min_vel);
714 break;
715 case rnemdPy :
716 min_vel.y() = max_vel.y();
717 min_sd->setVel(min_vel);
718 break;
719 case rnemdPz :
720 min_vel.z() = max_vel.z();
721 min_sd->setVel(min_vel);
722 break;
723 default :
724 break;
725 }
726 }
727 #endif
728
729 switch(rnemdFluxType_) {
730 case rnemdKE:
731 cerr << "KE\n";
732 kineticExchange_ += max_val - min_val;
733 break;
734 case rnemdPx:
735 momentumExchange_.x() += max_val - min_val;
736 break;
737 case rnemdPy:
738 momentumExchange_.y() += max_val - min_val;
739 break;
740 case rnemdPz:
741 momentumExchange_.z() += max_val - min_val;
742 break;
743 default:
744 cerr << "default\n";
745 break;
746 }
747 } else {
748 sprintf(painCave.errMsg,
749 "RNEMD::doSwap exchange NOT performed because min_val > max_val\n");
750 painCave.isFatal = 0;
751 painCave.severity = OPENMD_INFO;
752 simError();
753 failTrialCount_++;
754 }
755 } else {
756 sprintf(painCave.errMsg,
757 "RNEMD::doSwap exchange NOT performed because selected object\n"
758 "\twas not present in at least one of the two slabs.\n");
759 painCave.isFatal = 0;
760 painCave.severity = OPENMD_INFO;
761 simError();
762 failTrialCount_++;
763 }
764 }
765
766 void RNEMD::doNIVS() {
767
768 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
769 Mat3x3d hmat = currentSnap_->getHmat();
770
771 seleMan_.setSelectionSet(evaluator_.evaluate());
772
773 int selei;
774 StuntDouble* sd;
775 int idx;
776
777 vector<StuntDouble*> hotBin, coldBin;
778
779 RealType Phx = 0.0;
780 RealType Phy = 0.0;
781 RealType Phz = 0.0;
782 RealType Khx = 0.0;
783 RealType Khy = 0.0;
784 RealType Khz = 0.0;
785 RealType Khw = 0.0;
786 RealType Pcx = 0.0;
787 RealType Pcy = 0.0;
788 RealType Pcz = 0.0;
789 RealType Kcx = 0.0;
790 RealType Kcy = 0.0;
791 RealType Kcz = 0.0;
792 RealType Kcw = 0.0;
793
794 for (sd = seleMan_.beginSelected(selei); sd != NULL;
795 sd = seleMan_.nextSelected(selei)) {
796
797 idx = sd->getLocalIndex();
798
799 Vector3d pos = sd->getPos();
800
801 // wrap the stuntdouble's position back into the box:
802
803 if (usePeriodicBoundaryConditions_)
804 currentSnap_->wrapVector(pos);
805
806 // which bin is this stuntdouble in?
807 bool inA = inSlabA(pos);
808 bool inB = inSlabB(pos);
809
810 if (inA || inB) {
811
812 RealType mass = sd->getMass();
813 Vector3d vel = sd->getVel();
814
815 if (inA) {
816 hotBin.push_back(sd);
817 Phx += mass * vel.x();
818 Phy += mass * vel.y();
819 Phz += mass * vel.z();
820 Khx += mass * vel.x() * vel.x();
821 Khy += mass * vel.y() * vel.y();
822 Khz += mass * vel.z() * vel.z();
823 if (sd->isDirectional()) {
824 Vector3d angMom = sd->getJ();
825 Mat3x3d I = sd->getI();
826 if (sd->isLinear()) {
827 int i = sd->linearAxis();
828 int j = (i + 1) % 3;
829 int k = (i + 2) % 3;
830 Khw += angMom[j] * angMom[j] / I(j, j) +
831 angMom[k] * angMom[k] / I(k, k);
832 } else {
833 Khw += angMom[0]*angMom[0]/I(0, 0)
834 + angMom[1]*angMom[1]/I(1, 1)
835 + angMom[2]*angMom[2]/I(2, 2);
836 }
837 }
838 } else {
839 coldBin.push_back(sd);
840 Pcx += mass * vel.x();
841 Pcy += mass * vel.y();
842 Pcz += mass * vel.z();
843 Kcx += mass * vel.x() * vel.x();
844 Kcy += mass * vel.y() * vel.y();
845 Kcz += mass * vel.z() * vel.z();
846 if (sd->isDirectional()) {
847 Vector3d angMom = sd->getJ();
848 Mat3x3d I = sd->getI();
849 if (sd->isLinear()) {
850 int i = sd->linearAxis();
851 int j = (i + 1) % 3;
852 int k = (i + 2) % 3;
853 Kcw += angMom[j] * angMom[j] / I(j, j) +
854 angMom[k] * angMom[k] / I(k, k);
855 } else {
856 Kcw += angMom[0]*angMom[0]/I(0, 0)
857 + angMom[1]*angMom[1]/I(1, 1)
858 + angMom[2]*angMom[2]/I(2, 2);
859 }
860 }
861 }
862 }
863 }
864
865 Khx *= 0.5;
866 Khy *= 0.5;
867 Khz *= 0.5;
868 Khw *= 0.5;
869 Kcx *= 0.5;
870 Kcy *= 0.5;
871 Kcz *= 0.5;
872 Kcw *= 0.5;
873
874 #ifdef IS_MPI
875 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phx, 1, MPI::REALTYPE, MPI::SUM);
876 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phy, 1, MPI::REALTYPE, MPI::SUM);
877 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phz, 1, MPI::REALTYPE, MPI::SUM);
878 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcx, 1, MPI::REALTYPE, MPI::SUM);
879 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcy, 1, MPI::REALTYPE, MPI::SUM);
880 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcz, 1, MPI::REALTYPE, MPI::SUM);
881
882 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khx, 1, MPI::REALTYPE, MPI::SUM);
883 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khy, 1, MPI::REALTYPE, MPI::SUM);
884 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khz, 1, MPI::REALTYPE, MPI::SUM);
885 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khw, 1, MPI::REALTYPE, MPI::SUM);
886
887 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcx, 1, MPI::REALTYPE, MPI::SUM);
888 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcy, 1, MPI::REALTYPE, MPI::SUM);
889 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcz, 1, MPI::REALTYPE, MPI::SUM);
890 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcw, 1, MPI::REALTYPE, MPI::SUM);
891 #endif
892
893 //solve coldBin coeff's first
894 RealType px = Pcx / Phx;
895 RealType py = Pcy / Phy;
896 RealType pz = Pcz / Phz;
897 RealType c, x, y, z;
898 bool successfulScale = false;
899 if ((rnemdFluxType_ == rnemdFullKE) ||
900 (rnemdFluxType_ == rnemdRotKE)) {
901 //may need sanity check Khw & Kcw > 0
902
903 if (rnemdFluxType_ == rnemdFullKE) {
904 c = 1.0 - kineticTarget_ / (Kcx + Kcy + Kcz + Kcw);
905 } else {
906 c = 1.0 - kineticTarget_ / Kcw;
907 }
908
909 if ((c > 0.81) && (c < 1.21)) {//restrict scaling coefficients
910 c = sqrt(c);
911 //std::cerr << "cold slab scaling coefficient: " << c << endl;
912 //now convert to hotBin coefficient
913 RealType w = 0.0;
914 if (rnemdFluxType_ == rnemdFullKE) {
915 x = 1.0 + px * (1.0 - c);
916 y = 1.0 + py * (1.0 - c);
917 z = 1.0 + pz * (1.0 - c);
918 /* more complicated way
919 w = 1.0 + (Kcw - Kcw * c * c - (c * c * (Kcx + Kcy + Kcz
920 + Khx * px * px + Khy * py * py + Khz * pz * pz)
921 - 2.0 * c * (Khx * px * (1.0 + px) + Khy * py * (1.0 + py)
922 + Khz * pz * (1.0 + pz)) + Khx * px * (2.0 + px)
923 + Khy * py * (2.0 + py) + Khz * pz * (2.0 + pz)
924 - Kcx - Kcy - Kcz)) / Khw; the following is simpler
925 */
926 if ((fabs(x - 1.0) < 0.1) && (fabs(y - 1.0) < 0.1) &&
927 (fabs(z - 1.0) < 0.1)) {
928 w = 1.0 + (kineticTarget_
929 + Khx * (1.0 - x * x) + Khy * (1.0 - y * y)
930 + Khz * (1.0 - z * z)) / Khw;
931 }//no need to calculate w if x, y or z is out of range
932 } else {
933 w = 1.0 + kineticTarget_ / Khw;
934 }
935 if ((w > 0.81) && (w < 1.21)) {//restrict scaling coefficients
936 //if w is in the right range, so should be x, y, z.
937 vector<StuntDouble*>::iterator sdi;
938 Vector3d vel;
939 for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) {
940 if (rnemdFluxType_ == rnemdFullKE) {
941 vel = (*sdi)->getVel() * c;
942 (*sdi)->setVel(vel);
943 }
944 if ((*sdi)->isDirectional()) {
945 Vector3d angMom = (*sdi)->getJ() * c;
946 (*sdi)->setJ(angMom);
947 }
948 }
949 w = sqrt(w);
950 // std::cerr << "xh= " << x << "\tyh= " << y << "\tzh= " << z
951 // << "\twh= " << w << endl;
952 for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) {
953 if (rnemdFluxType_ == rnemdFullKE) {
954 vel = (*sdi)->getVel();
955 vel.x() *= x;
956 vel.y() *= y;
957 vel.z() *= z;
958 (*sdi)->setVel(vel);
959 }
960 if ((*sdi)->isDirectional()) {
961 Vector3d angMom = (*sdi)->getJ() * w;
962 (*sdi)->setJ(angMom);
963 }
964 }
965 successfulScale = true;
966 kineticExchange_ += kineticTarget_;
967 }
968 }
969 } else {
970 RealType a000, a110, c0, a001, a111, b01, b11, c1;
971 switch(rnemdFluxType_) {
972 case rnemdKE :
973 /* used hotBin coeff's & only scale x & y dimensions
974 RealType px = Phx / Pcx;
975 RealType py = Phy / Pcy;
976 a110 = Khy;
977 c0 = - Khx - Khy - kineticTarget_;
978 a000 = Khx;
979 a111 = Kcy * py * py;
980 b11 = -2.0 * Kcy * py * (1.0 + py);
981 c1 = Kcy * py * (2.0 + py) + Kcx * px * ( 2.0 + px) + kineticTarget_;
982 b01 = -2.0 * Kcx * px * (1.0 + px);
983 a001 = Kcx * px * px;
984 */
985 //scale all three dimensions, let c_x = c_y
986 a000 = Kcx + Kcy;
987 a110 = Kcz;
988 c0 = kineticTarget_ - Kcx - Kcy - Kcz;
989 a001 = Khx * px * px + Khy * py * py;
990 a111 = Khz * pz * pz;
991 b01 = -2.0 * (Khx * px * (1.0 + px) + Khy * py * (1.0 + py));
992 b11 = -2.0 * Khz * pz * (1.0 + pz);
993 c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
994 + Khz * pz * (2.0 + pz) - kineticTarget_;
995 break;
996 case rnemdPx :
997 c = 1 - momentumTarget_.x() / Pcx;
998 a000 = Kcy;
999 a110 = Kcz;
1000 c0 = Kcx * c * c - Kcx - Kcy - Kcz;
1001 a001 = py * py * Khy;
1002 a111 = pz * pz * Khz;
1003 b01 = -2.0 * Khy * py * (1.0 + py);
1004 b11 = -2.0 * Khz * pz * (1.0 + pz);
1005 c1 = Khy * py * (2.0 + py) + Khz * pz * (2.0 + pz)
1006 + Khx * (fastpow(c * px - px - 1.0, 2) - 1.0);
1007 break;
1008 case rnemdPy :
1009 c = 1 - momentumTarget_.y() / Pcy;
1010 a000 = Kcx;
1011 a110 = Kcz;
1012 c0 = Kcy * c * c - Kcx - Kcy - Kcz;
1013 a001 = px * px * Khx;
1014 a111 = pz * pz * Khz;
1015 b01 = -2.0 * Khx * px * (1.0 + px);
1016 b11 = -2.0 * Khz * pz * (1.0 + pz);
1017 c1 = Khx * px * (2.0 + px) + Khz * pz * (2.0 + pz)
1018 + Khy * (fastpow(c * py - py - 1.0, 2) - 1.0);
1019 break;
1020 case rnemdPz ://we don't really do this, do we?
1021 c = 1 - momentumTarget_.z() / Pcz;
1022 a000 = Kcx;
1023 a110 = Kcy;
1024 c0 = Kcz * c * c - Kcx - Kcy - Kcz;
1025 a001 = px * px * Khx;
1026 a111 = py * py * Khy;
1027 b01 = -2.0 * Khx * px * (1.0 + px);
1028 b11 = -2.0 * Khy * py * (1.0 + py);
1029 c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
1030 + Khz * (fastpow(c * pz - pz - 1.0, 2) - 1.0);
1031 break;
1032 default :
1033 break;
1034 }
1035
1036 RealType v1 = a000 * a111 - a001 * a110;
1037 RealType v2 = a000 * b01;
1038 RealType v3 = a000 * b11;
1039 RealType v4 = a000 * c1 - a001 * c0;
1040 RealType v8 = a110 * b01;
1041 RealType v10 = - b01 * c0;
1042
1043 RealType u0 = v2 * v10 - v4 * v4;
1044 RealType u1 = -2.0 * v3 * v4;
1045 RealType u2 = -v2 * v8 - v3 * v3 - 2.0 * v1 * v4;
1046 RealType u3 = -2.0 * v1 * v3;
1047 RealType u4 = - v1 * v1;
1048 //rescale coefficients
1049 RealType maxAbs = fabs(u0);
1050 if (maxAbs < fabs(u1)) maxAbs = fabs(u1);
1051 if (maxAbs < fabs(u2)) maxAbs = fabs(u2);
1052 if (maxAbs < fabs(u3)) maxAbs = fabs(u3);
1053 if (maxAbs < fabs(u4)) maxAbs = fabs(u4);
1054 u0 /= maxAbs;
1055 u1 /= maxAbs;
1056 u2 /= maxAbs;
1057 u3 /= maxAbs;
1058 u4 /= maxAbs;
1059 //max_element(start, end) is also available.
1060 Polynomial<RealType> poly; //same as DoublePolynomial poly;
1061 poly.setCoefficient(4, u4);
1062 poly.setCoefficient(3, u3);
1063 poly.setCoefficient(2, u2);
1064 poly.setCoefficient(1, u1);
1065 poly.setCoefficient(0, u0);
1066 vector<RealType> realRoots = poly.FindRealRoots();
1067
1068 vector<RealType>::iterator ri;
1069 RealType r1, r2, alpha0;
1070 vector<pair<RealType,RealType> > rps;
1071 for (ri = realRoots.begin(); ri !=realRoots.end(); ri++) {
1072 r2 = *ri;
1073 //check if FindRealRoots() give the right answer
1074 if ( fabs(u0 + r2 * (u1 + r2 * (u2 + r2 * (u3 + r2 * u4)))) > 1e-6 ) {
1075 sprintf(painCave.errMsg,
1076 "RNEMD Warning: polynomial solve seems to have an error!");
1077 painCave.isFatal = 0;
1078 simError();
1079 failRootCount_++;
1080 }
1081 //might not be useful w/o rescaling coefficients
1082 alpha0 = -c0 - a110 * r2 * r2;
1083 if (alpha0 >= 0.0) {
1084 r1 = sqrt(alpha0 / a000);
1085 if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111))
1086 < 1e-6)
1087 { rps.push_back(make_pair(r1, r2)); }
1088 if (r1 > 1e-6) { //r1 non-negative
1089 r1 = -r1;
1090 if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111))
1091 < 1e-6)
1092 { rps.push_back(make_pair(r1, r2)); }
1093 }
1094 }
1095 }
1096 // Consider combining together the solving pair part w/ the searching
1097 // best solution part so that we don't need the pairs vector
1098 if (!rps.empty()) {
1099 RealType smallestDiff = HONKING_LARGE_VALUE;
1100 RealType diff;
1101 pair<RealType,RealType> bestPair = make_pair(1.0, 1.0);
1102 vector<pair<RealType,RealType> >::iterator rpi;
1103 for (rpi = rps.begin(); rpi != rps.end(); rpi++) {
1104 r1 = (*rpi).first;
1105 r2 = (*rpi).second;
1106 switch(rnemdFluxType_) {
1107 case rnemdKE :
1108 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1109 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2)
1110 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
1111 break;
1112 case rnemdPx :
1113 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1114 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
1115 break;
1116 case rnemdPy :
1117 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1118 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2);
1119 break;
1120 case rnemdPz :
1121 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1122 + fastpow(r1 * r1 / r2 / r2 - Kcy/Kcx, 2);
1123 default :
1124 break;
1125 }
1126 if (diff < smallestDiff) {
1127 smallestDiff = diff;
1128 bestPair = *rpi;
1129 }
1130 }
1131 #ifdef IS_MPI
1132 if (worldRank == 0) {
1133 #endif
1134 // sprintf(painCave.errMsg,
1135 // "RNEMD: roots r1= %lf\tr2 = %lf\n",
1136 // bestPair.first, bestPair.second);
1137 // painCave.isFatal = 0;
1138 // painCave.severity = OPENMD_INFO;
1139 // simError();
1140 #ifdef IS_MPI
1141 }
1142 #endif
1143
1144 switch(rnemdFluxType_) {
1145 case rnemdKE :
1146 x = bestPair.first;
1147 y = bestPair.first;
1148 z = bestPair.second;
1149 break;
1150 case rnemdPx :
1151 x = c;
1152 y = bestPair.first;
1153 z = bestPair.second;
1154 break;
1155 case rnemdPy :
1156 x = bestPair.first;
1157 y = c;
1158 z = bestPair.second;
1159 break;
1160 case rnemdPz :
1161 x = bestPair.first;
1162 y = bestPair.second;
1163 z = c;
1164 break;
1165 default :
1166 break;
1167 }
1168 vector<StuntDouble*>::iterator sdi;
1169 Vector3d vel;
1170 for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) {
1171 vel = (*sdi)->getVel();
1172 vel.x() *= x;
1173 vel.y() *= y;
1174 vel.z() *= z;
1175 (*sdi)->setVel(vel);
1176 }
1177 //convert to hotBin coefficient
1178 x = 1.0 + px * (1.0 - x);
1179 y = 1.0 + py * (1.0 - y);
1180 z = 1.0 + pz * (1.0 - z);
1181 for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) {
1182 vel = (*sdi)->getVel();
1183 vel.x() *= x;
1184 vel.y() *= y;
1185 vel.z() *= z;
1186 (*sdi)->setVel(vel);
1187 }
1188 successfulScale = true;
1189 switch(rnemdFluxType_) {
1190 case rnemdKE :
1191 kineticExchange_ += kineticTarget_;
1192 break;
1193 case rnemdPx :
1194 case rnemdPy :
1195 case rnemdPz :
1196 momentumExchange_ += momentumTarget_;
1197 break;
1198 default :
1199 break;
1200 }
1201 }
1202 }
1203 if (successfulScale != true) {
1204 sprintf(painCave.errMsg,
1205 "RNEMD::doNIVS exchange NOT performed - roots that solve\n"
1206 "\tthe constraint equations may not exist or there may be\n"
1207 "\tno selected objects in one or both slabs.\n");
1208 painCave.isFatal = 0;
1209 painCave.severity = OPENMD_INFO;
1210 simError();
1211 failTrialCount_++;
1212 }
1213 }
1214
1215 void RNEMD::doVSS() {
1216
1217 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1218 RealType time = currentSnap_->getTime();
1219 Mat3x3d hmat = currentSnap_->getHmat();
1220
1221 seleMan_.setSelectionSet(evaluator_.evaluate());
1222
1223 int selei;
1224 StuntDouble* sd;
1225 int idx;
1226
1227 vector<StuntDouble*> hotBin, coldBin;
1228
1229 Vector3d Ph(V3Zero);
1230 RealType Mh = 0.0;
1231 RealType Kh = 0.0;
1232 Vector3d Pc(V3Zero);
1233 RealType Mc = 0.0;
1234 RealType Kc = 0.0;
1235
1236
1237 for (sd = seleMan_.beginSelected(selei); sd != NULL;
1238 sd = seleMan_.nextSelected(selei)) {
1239
1240 idx = sd->getLocalIndex();
1241
1242 Vector3d pos = sd->getPos();
1243
1244 // wrap the stuntdouble's position back into the box:
1245
1246 if (usePeriodicBoundaryConditions_)
1247 currentSnap_->wrapVector(pos);
1248
1249 // which bin is this stuntdouble in?
1250 bool inA = inSlabA(pos);
1251 bool inB = inSlabB(pos);
1252
1253 if (inA || inB) {
1254
1255 RealType mass = sd->getMass();
1256 Vector3d vel = sd->getVel();
1257
1258 if (inA) {
1259 hotBin.push_back(sd);
1260 //std::cerr << "before, velocity = " << vel << endl;
1261 Ph += mass * vel;
1262 //std::cerr << "after, velocity = " << vel << endl;
1263 Mh += mass;
1264 Kh += mass * vel.lengthSquare();
1265 if (rnemdFluxType_ == rnemdFullKE) {
1266 if (sd->isDirectional()) {
1267 Vector3d angMom = sd->getJ();
1268 Mat3x3d I = sd->getI();
1269 if (sd->isLinear()) {
1270 int i = sd->linearAxis();
1271 int j = (i + 1) % 3;
1272 int k = (i + 2) % 3;
1273 Kh += angMom[j] * angMom[j] / I(j, j) +
1274 angMom[k] * angMom[k] / I(k, k);
1275 } else {
1276 Kh += angMom[0] * angMom[0] / I(0, 0) +
1277 angMom[1] * angMom[1] / I(1, 1) +
1278 angMom[2] * angMom[2] / I(2, 2);
1279 }
1280 }
1281 }
1282 } else { //midBin_
1283 coldBin.push_back(sd);
1284 Pc += mass * vel;
1285 Mc += mass;
1286 Kc += mass * vel.lengthSquare();
1287 if (rnemdFluxType_ == rnemdFullKE) {
1288 if (sd->isDirectional()) {
1289 Vector3d angMom = sd->getJ();
1290 Mat3x3d I = sd->getI();
1291 if (sd->isLinear()) {
1292 int i = sd->linearAxis();
1293 int j = (i + 1) % 3;
1294 int k = (i + 2) % 3;
1295 Kc += angMom[j] * angMom[j] / I(j, j) +
1296 angMom[k] * angMom[k] / I(k, k);
1297 } else {
1298 Kc += angMom[0] * angMom[0] / I(0, 0) +
1299 angMom[1] * angMom[1] / I(1, 1) +
1300 angMom[2] * angMom[2] / I(2, 2);
1301 }
1302 }
1303 }
1304 }
1305 }
1306 }
1307
1308 Kh *= 0.5;
1309 Kc *= 0.5;
1310
1311 // std::cerr << "Mh= " << Mh << "\tKh= " << Kh << "\tMc= " << Mc
1312 // << "\tKc= " << Kc << endl;
1313 // std::cerr << "Ph= " << Ph << "\tPc= " << Pc << endl;
1314
1315 #ifdef IS_MPI
1316 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Ph[0], 3, MPI::REALTYPE, MPI::SUM);
1317 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pc[0], 3, MPI::REALTYPE, MPI::SUM);
1318 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Mh, 1, MPI::REALTYPE, MPI::SUM);
1319 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kh, 1, MPI::REALTYPE, MPI::SUM);
1320 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Mc, 1, MPI::REALTYPE, MPI::SUM);
1321 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kc, 1, MPI::REALTYPE, MPI::SUM);
1322 #endif
1323
1324 bool successfulExchange = false;
1325 if ((Mh > 0.0) && (Mc > 0.0)) {//both slabs are not empty
1326 Vector3d vc = Pc / Mc;
1327 Vector3d ac = -momentumTarget_ / Mc + vc;
1328 Vector3d acrec = -momentumTarget_ / Mc;
1329 RealType cNumerator = Kc - kineticTarget_ - 0.5 * Mc * ac.lengthSquare();
1330 if (cNumerator > 0.0) {
1331 RealType cDenominator = Kc - 0.5 * Mc * vc.lengthSquare();
1332 if (cDenominator > 0.0) {
1333 RealType c = sqrt(cNumerator / cDenominator);
1334 if ((c > 0.9) && (c < 1.1)) {//restrict scaling coefficients
1335 Vector3d vh = Ph / Mh;
1336 Vector3d ah = momentumTarget_ / Mh + vh;
1337 Vector3d ahrec = momentumTarget_ / Mh;
1338 RealType hNumerator = Kh + kineticTarget_
1339 - 0.5 * Mh * ah.lengthSquare();
1340 if (hNumerator > 0.0) {
1341 RealType hDenominator = Kh - 0.5 * Mh * vh.lengthSquare();
1342 if (hDenominator > 0.0) {
1343 RealType h = sqrt(hNumerator / hDenominator);
1344 if ((h > 0.9) && (h < 1.1)) {
1345 // std::cerr << "cold slab scaling coefficient: " << c << "\n";
1346 // std::cerr << "hot slab scaling coefficient: " << h << "\n";
1347 vector<StuntDouble*>::iterator sdi;
1348 Vector3d vel;
1349 for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) {
1350 //vel = (*sdi)->getVel();
1351 vel = ((*sdi)->getVel() - vc) * c + ac;
1352 (*sdi)->setVel(vel);
1353 if (rnemdFluxType_ == rnemdFullKE) {
1354 if ((*sdi)->isDirectional()) {
1355 Vector3d angMom = (*sdi)->getJ() * c;
1356 (*sdi)->setJ(angMom);
1357 }
1358 }
1359 }
1360 for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) {
1361 //vel = (*sdi)->getVel();
1362 vel = ((*sdi)->getVel() - vh) * h + ah;
1363 (*sdi)->setVel(vel);
1364 if (rnemdFluxType_ == rnemdFullKE) {
1365 if ((*sdi)->isDirectional()) {
1366 Vector3d angMom = (*sdi)->getJ() * h;
1367 (*sdi)->setJ(angMom);
1368 }
1369 }
1370 }
1371 successfulExchange = true;
1372 kineticExchange_ += kineticTarget_;
1373 momentumExchange_ += momentumTarget_;
1374 }
1375 }
1376 }
1377 }
1378 }
1379 }
1380 }
1381 if (successfulExchange != true) {
1382 sprintf(painCave.errMsg,
1383 "RNEMD::doVSS exchange NOT performed - roots that solve\n"
1384 "\tthe constraint equations may not exist or there may be\n"
1385 "\tno selected objects in one or both slabs.\n");
1386 painCave.isFatal = 0;
1387 painCave.severity = OPENMD_INFO;
1388 simError();
1389 failTrialCount_++;
1390 }
1391 }
1392
1393 void RNEMD::doRNEMD() {
1394
1395 trialCount_++;
1396 switch(rnemdMethod_) {
1397 case rnemdSwap:
1398 doSwap();
1399 break;
1400 case rnemdNIVS:
1401 doNIVS();
1402 break;
1403 case rnemdVSS:
1404 doVSS();
1405 break;
1406 case rnemdUnkownMethod:
1407 default :
1408 break;
1409 }
1410 }
1411
1412 void RNEMD::collectData() {
1413
1414 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1415 Mat3x3d hmat = currentSnap_->getHmat();
1416
1417 seleMan_.setSelectionSet(evaluator_.evaluate());
1418
1419 int selei;
1420 StuntDouble* sd;
1421 int idx;
1422
1423 vector<RealType> binMass(nBins_, 0.0);
1424 vector<RealType> binPx(nBins_, 0.0);
1425 vector<RealType> binPy(nBins_, 0.0);
1426 vector<RealType> binPz(nBins_, 0.0);
1427 vector<RealType> binKE(nBins_, 0.0);
1428 vector<int> binDOF(nBins_, 0);
1429 vector<int> binCount(nBins_, 0);
1430
1431 // alternative approach, track all molecules instead of only those
1432 // selected for scaling/swapping:
1433 /*
1434 SimInfo::MoleculeIterator miter;
1435 vector<StuntDouble*>::iterator iiter;
1436 Molecule* mol;
1437 StuntDouble* sd;
1438 for (mol = info_->beginMolecule(miter); mol != NULL;
1439 mol = info_->nextMolecule(miter))
1440 sd is essentially sd
1441 for (sd = mol->beginIntegrableObject(iiter);
1442 sd != NULL;
1443 sd = mol->nextIntegrableObject(iiter))
1444 */
1445 for (sd = seleMan_.beginSelected(selei); sd != NULL;
1446 sd = seleMan_.nextSelected(selei)) {
1447
1448 idx = sd->getLocalIndex();
1449
1450 Vector3d pos = sd->getPos();
1451
1452 // wrap the stuntdouble's position back into the box:
1453
1454 if (usePeriodicBoundaryConditions_)
1455 currentSnap_->wrapVector(pos);
1456
1457 // which bin is this stuntdouble in?
1458 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
1459 // Shift molecules by half a box to have bins start at 0
1460 // The modulo operator is used to wrap the case when we are
1461 // beyond the end of the bins back to the beginning.
1462 int binNo = int(nBins_ * (pos.z() / hmat(2,2) + 0.5)) % nBins_;
1463
1464 RealType mass = sd->getMass();
1465 Vector3d vel = sd->getVel();
1466
1467 binCount[binNo]++;
1468 binMass[binNo] += mass;
1469 binPx[binNo] += mass*vel.x();
1470 binPy[binNo] += mass*vel.y();
1471 binPz[binNo] += mass*vel.z();
1472 binKE[binNo] += 0.5 * (mass * vel.lengthSquare());
1473 binDOF[binNo] += 3;
1474
1475 if (sd->isDirectional()) {
1476 Vector3d angMom = sd->getJ();
1477 Mat3x3d I = sd->getI();
1478 if (sd->isLinear()) {
1479 int i = sd->linearAxis();
1480 int j = (i + 1) % 3;
1481 int k = (i + 2) % 3;
1482 binKE[binNo] += 0.5 * (angMom[j] * angMom[j] / I(j, j) +
1483 angMom[k] * angMom[k] / I(k, k));
1484 binDOF[binNo] += 2;
1485 } else {
1486 binKE[binNo] += 0.5 * (angMom[0] * angMom[0] / I(0, 0) +
1487 angMom[1] * angMom[1] / I(1, 1) +
1488 angMom[2] * angMom[2] / I(2, 2));
1489 binDOF[binNo] += 3;
1490 }
1491 }
1492 }
1493
1494
1495 #ifdef IS_MPI
1496 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &binCount[0],
1497 nBins_, MPI::INT, MPI::SUM);
1498 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &binMass[0],
1499 nBins_, MPI::REALTYPE, MPI::SUM);
1500 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &binPx[0],
1501 nBins_, MPI::REALTYPE, MPI::SUM);
1502 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &binPy[0],
1503 nBins_, MPI::REALTYPE, MPI::SUM);
1504 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &binPz[0],
1505 nBins_, MPI::REALTYPE, MPI::SUM);
1506 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &binKE[0],
1507 nBins_, MPI::REALTYPE, MPI::SUM);
1508 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &binDOF[0],
1509 nBins_, MPI::INT, MPI::SUM);
1510 #endif
1511
1512 Vector3d vel;
1513 RealType den;
1514 RealType temp;
1515 RealType z;
1516 for (int i = 0; i < nBins_; i++) {
1517 z = (((RealType)i + 0.5) / (RealType)nBins_) * hmat(2,2);
1518 vel.x() = binPx[i] / binMass[i];
1519 vel.y() = binPy[i] / binMass[i];
1520 vel.z() = binPz[i] / binMass[i];
1521 den = binCount[i] * nBins_ / (hmat(0,0) * hmat(1,1) * hmat(2,2));
1522 temp = 2.0 * binKE[i] / (binDOF[i] * PhysicalConstants::kb *
1523 PhysicalConstants::energyConvert);
1524
1525 for (unsigned int j = 0; j < outputMask_.size(); ++j) {
1526 if(outputMask_[j]) {
1527 switch(j) {
1528 case Z:
1529 (data_[j].accumulator[i])->add(z);
1530 break;
1531 case TEMPERATURE:
1532 data_[j].accumulator[i]->add(temp);
1533 break;
1534 case VELOCITY:
1535 dynamic_cast<VectorAccumulator *>(data_[j].accumulator[i])->add(vel);
1536 break;
1537 case DENSITY:
1538 data_[j].accumulator[i]->add(den);
1539 break;
1540 }
1541 }
1542 }
1543 }
1544 }
1545
1546 void RNEMD::getStarted() {
1547 collectData();
1548 writeOutputFile();
1549 }
1550
1551 void RNEMD::parseOutputFileFormat(const std::string& format) {
1552 StringTokenizer tokenizer(format, " ,;|\t\n\r");
1553
1554 while(tokenizer.hasMoreTokens()) {
1555 std::string token(tokenizer.nextToken());
1556 toUpper(token);
1557 OutputMapType::iterator i = outputMap_.find(token);
1558 if (i != outputMap_.end()) {
1559 outputMask_.set(i->second);
1560 } else {
1561 sprintf( painCave.errMsg,
1562 "RNEMD::parseOutputFileFormat: %s is not a recognized\n"
1563 "\toutputFileFormat keyword.\n", token.c_str() );
1564 painCave.isFatal = 0;
1565 painCave.severity = OPENMD_ERROR;
1566 simError();
1567 }
1568 }
1569 }
1570
1571 void RNEMD::writeOutputFile() {
1572
1573 #ifdef IS_MPI
1574 // If we're the root node, should we print out the results
1575 int worldRank = MPI::COMM_WORLD.Get_rank();
1576 if (worldRank == 0) {
1577 #endif
1578 rnemdFile_.open(rnemdFileName_.c_str(), std::ios::out | std::ios::trunc );
1579
1580 if( !rnemdFile_ ){
1581 sprintf( painCave.errMsg,
1582 "Could not open \"%s\" for RNEMD output.\n",
1583 rnemdFileName_.c_str());
1584 painCave.isFatal = 1;
1585 simError();
1586 }
1587
1588 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1589
1590 RealType time = currentSnap_->getTime();
1591
1592
1593 rnemdFile_ << "#######################################################\n";
1594 rnemdFile_ << "# RNEMD {\n";
1595
1596 map<string, RNEMDMethod>::iterator mi;
1597 for(mi = stringToMethod_.begin(); mi != stringToMethod_.end(); ++mi) {
1598 if ( (*mi).second == rnemdMethod_)
1599 rnemdFile_ << "# exchangeMethod = " << (*mi).first << "\n";
1600 }
1601 map<string, RNEMDFluxType>::iterator fi;
1602 for(fi = stringToFluxType_.begin(); fi != stringToFluxType_.end(); ++fi) {
1603 if ( (*fi).second == rnemdFluxType_)
1604 rnemdFile_ << "# fluxType = " << (*fi).first << "\n";
1605 }
1606
1607 rnemdFile_ << "# exchangeTime = " << exchangeTime_ << " fs\n";
1608
1609 rnemdFile_ << "# objectSelection = \""
1610 << rnemdObjectSelection_ << "\"\n";
1611 rnemdFile_ << "# slabWidth = " << slabWidth_ << " angstroms\n";
1612 rnemdFile_ << "# slabAcenter = " << slabACenter_ << " angstroms\n";
1613 rnemdFile_ << "# slabBcenter = " << slabBCenter_ << " angstroms\n";
1614 rnemdFile_ << "# }\n";
1615 rnemdFile_ << "#######################################################\n";
1616
1617 rnemdFile_ << "# running time = " << time << " fs\n";
1618 rnemdFile_ << "# target kinetic flux = " << kineticFlux_ << "\n";
1619 rnemdFile_ << "# target momentum flux = " << momentumFluxVector_ << "\n";
1620
1621 rnemdFile_ << "# target one-time kinetic exchange = " << kineticTarget_
1622 << "\n";
1623 rnemdFile_ << "# target one-time momentum exchange = " << momentumTarget_
1624 << "\n";
1625
1626 rnemdFile_ << "# actual kinetic exchange = " << kineticExchange_ << "\n";
1627 rnemdFile_ << "# actual momentum exchange = " << momentumExchange_
1628 << "\n";
1629
1630 rnemdFile_ << "# attempted exchanges: " << trialCount_ << "\n";
1631 rnemdFile_ << "# failed exchanges: " << failTrialCount_ << "\n";
1632
1633
1634 if (rnemdMethod_ == rnemdNIVS) {
1635 rnemdFile_ << "# NIVS root-check warnings: " << failRootCount_ << "\n";
1636 }
1637
1638 rnemdFile_ << "#######################################################\n";
1639
1640
1641
1642 //write title
1643 rnemdFile_ << "#";
1644 for (unsigned int i = 0; i < outputMask_.size(); ++i) {
1645 if (outputMask_[i]) {
1646 rnemdFile_ << "\t" << data_[i].title <<
1647 "(" << data_[i].units << ")";
1648 }
1649 }
1650 rnemdFile_ << std::endl;
1651
1652 rnemdFile_.precision(8);
1653
1654 for (unsigned int j = 0; j < nBins_; j++) {
1655
1656 for (unsigned int i = 0; i < outputMask_.size(); ++i) {
1657 if (outputMask_[i]) {
1658 if (data_[i].dataType == "RealType")
1659 writeReal(i,j);
1660 else if (data_[i].dataType == "Vector3d")
1661 writeVector(i,j);
1662 else {
1663 sprintf( painCave.errMsg,
1664 "RNEMD found an unknown data type for: %s ",
1665 data_[i].title.c_str());
1666 painCave.isFatal = 1;
1667 simError();
1668 }
1669 }
1670 }
1671 rnemdFile_ << std::endl;
1672
1673 }
1674
1675 rnemdFile_.flush();
1676 rnemdFile_.close();
1677
1678 #ifdef IS_MPI
1679 }
1680 #endif
1681
1682 }
1683
1684 void RNEMD::writeReal(int index, unsigned int bin) {
1685 assert(index >=0 && index < ENDINDEX);
1686 assert(bin >=0 && bin < nBins_);
1687 RealType s;
1688
1689 data_[index].accumulator[bin]->getAverage(s);
1690
1691 if (! isinf(s) && ! isnan(s)) {
1692 rnemdFile_ << "\t" << s;
1693 } else{
1694 sprintf( painCave.errMsg,
1695 "RNEMD detected a numerical error writing: %s for bin %d",
1696 data_[index].title.c_str(), bin);
1697 painCave.isFatal = 1;
1698 simError();
1699 }
1700 }
1701
1702 void RNEMD::writeVector(int index, unsigned int bin) {
1703 assert(index >=0 && index < ENDINDEX);
1704 assert(bin >=0 && bin < nBins_);
1705 Vector3d s;
1706 dynamic_cast<VectorAccumulator*>(data_[index].accumulator[bin])->getAverage(s);
1707 if (isinf(s[0]) || isnan(s[0]) ||
1708 isinf(s[1]) || isnan(s[1]) ||
1709 isinf(s[2]) || isnan(s[2]) ) {
1710 sprintf( painCave.errMsg,
1711 "RNEMD detected a numerical error writing: %s for bin %d",
1712 data_[index].title.c_str(), bin);
1713 painCave.isFatal = 1;
1714 simError();
1715 } else {
1716 rnemdFile_ << "\t" << s[0] << "\t" << s[1] << "\t" << s[2];
1717 }
1718 }
1719 }
1720

Properties

Name Value
svn:keywords Author Id Revision Date