ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/integrators/RNEMD.cpp
Revision: 1722
Committed: Thu May 24 14:23:40 2012 UTC (12 years, 11 months ago) by gezelter
File size: 49483 byte(s)
Log Message:
Merging Shenyu's RNEMD changes from openmd-1 into the development branch.

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 "integrators/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
53 #ifndef IS_MPI
54 #include "math/SeqRandNumGen.hpp"
55 #else
56 #include "math/ParallelRandNumGen.hpp"
57 #endif
58
59 #define HONKING_LARGE_VALUE 1.0e10
60
61 using namespace std;
62 namespace OpenMD {
63
64 RNEMD::RNEMD(SimInfo* info) : info_(info), evaluator_(info), seleMan_(info),
65 usePeriodicBoundaryConditions_(info->getSimParams()->getUsePeriodicBoundaryConditions()) {
66
67 failTrialCount_ = 0;
68 failRootCount_ = 0;
69
70 int seedValue;
71 Globals * simParams = info->getSimParams();
72
73 stringToEnumMap_["KineticSwap"] = rnemdKineticSwap;
74 stringToEnumMap_["KineticScale"] = rnemdKineticScale;
75 stringToEnumMap_["KineticScaleVAM"] = rnemdKineticScaleVAM;
76 stringToEnumMap_["KineticScaleAM"] = rnemdKineticScaleAM;
77 stringToEnumMap_["PxScale"] = rnemdPxScale;
78 stringToEnumMap_["PyScale"] = rnemdPyScale;
79 stringToEnumMap_["PzScale"] = rnemdPzScale;
80 stringToEnumMap_["Px"] = rnemdPx;
81 stringToEnumMap_["Py"] = rnemdPy;
82 stringToEnumMap_["Pz"] = rnemdPz;
83 stringToEnumMap_["ShiftScaleV"] = rnemdShiftScaleV;
84 stringToEnumMap_["ShiftScaleVAM"] = rnemdShiftScaleVAM;
85 stringToEnumMap_["Unknown"] = rnemdUnknown;
86
87 rnemdObjectSelection_ = simParams->getRNEMD_objectSelection();
88 evaluator_.loadScriptString(rnemdObjectSelection_);
89 seleMan_.setSelectionSet(evaluator_.evaluate());
90
91 // do some sanity checking
92
93 int selectionCount = seleMan_.getSelectionCount();
94 int nIntegrable = info->getNGlobalIntegrableObjects();
95
96 if (selectionCount > nIntegrable) {
97 sprintf(painCave.errMsg,
98 "RNEMD: The current RNEMD_objectSelection,\n"
99 "\t\t%s\n"
100 "\thas resulted in %d selected objects. However,\n"
101 "\tthe total number of integrable objects in the system\n"
102 "\tis only %d. This is almost certainly not what you want\n"
103 "\tto do. A likely cause of this is forgetting the _RB_0\n"
104 "\tselector in the selection script!\n",
105 rnemdObjectSelection_.c_str(),
106 selectionCount, nIntegrable);
107 painCave.isFatal = 0;
108 painCave.severity = OPENMD_WARNING;
109 simError();
110 }
111
112 const string st = simParams->getRNEMD_exchangeType();
113
114 map<string, RNEMDTypeEnum>::iterator i;
115 i = stringToEnumMap_.find(st);
116 rnemdType_ = (i == stringToEnumMap_.end()) ? RNEMD::rnemdUnknown : i->second;
117 if (rnemdType_ == rnemdUnknown) {
118 sprintf(painCave.errMsg,
119 "RNEMD: The current RNEMD_exchangeType,\n"
120 "\t\t%s\n"
121 "\tis not one of the recognized exchange types.\n",
122 st.c_str());
123 painCave.isFatal = 1;
124 painCave.severity = OPENMD_ERROR;
125 simError();
126 }
127
128 outputTemp_ = false;
129 if (simParams->haveRNEMD_outputTemperature()) {
130 outputTemp_ = simParams->getRNEMD_outputTemperature();
131 } else if ((rnemdType_ == rnemdKineticSwap) ||
132 (rnemdType_ == rnemdKineticScale) ||
133 (rnemdType_ == rnemdKineticScaleVAM) ||
134 (rnemdType_ == rnemdKineticScaleAM)) {
135 outputTemp_ = true;
136 }
137 outputVx_ = false;
138 if (simParams->haveRNEMD_outputVx()) {
139 outputVx_ = simParams->getRNEMD_outputVx();
140 } else if ((rnemdType_ == rnemdPx) || (rnemdType_ == rnemdPxScale)) {
141 outputVx_ = true;
142 }
143 outputVy_ = false;
144 if (simParams->haveRNEMD_outputVy()) {
145 outputVy_ = simParams->getRNEMD_outputVy();
146 } else if ((rnemdType_ == rnemdPy) || (rnemdType_ == rnemdPyScale)) {
147 outputVy_ = true;
148 }
149 output3DTemp_ = false;
150 if (simParams->haveRNEMD_outputXyzTemperature()) {
151 output3DTemp_ = simParams->getRNEMD_outputXyzTemperature();
152 }
153 outputRotTemp_ = false;
154 if (simParams->haveRNEMD_outputRotTemperature()) {
155 outputRotTemp_ = simParams->getRNEMD_outputRotTemperature();
156 }
157
158 #ifdef IS_MPI
159 if (worldRank == 0) {
160 #endif
161
162 //may have rnemdWriter separately
163 string rnemdFileName;
164
165 if (outputTemp_) {
166 rnemdFileName = "temperature.log";
167 tempLog_.open(rnemdFileName.c_str());
168 }
169 if (outputVx_) {
170 rnemdFileName = "velocityX.log";
171 vxzLog_.open(rnemdFileName.c_str());
172 }
173 if (outputVy_) {
174 rnemdFileName = "velocityY.log";
175 vyzLog_.open(rnemdFileName.c_str());
176 }
177
178 if (output3DTemp_) {
179 rnemdFileName = "temperatureX.log";
180 xTempLog_.open(rnemdFileName.c_str());
181 rnemdFileName = "temperatureY.log";
182 yTempLog_.open(rnemdFileName.c_str());
183 rnemdFileName = "temperatureZ.log";
184 zTempLog_.open(rnemdFileName.c_str());
185 }
186 if (outputRotTemp_) {
187 rnemdFileName = "temperatureR.log";
188 rotTempLog_.open(rnemdFileName.c_str());
189 }
190
191 #ifdef IS_MPI
192 }
193 #endif
194
195 set_RNEMD_exchange_time(simParams->getRNEMD_exchangeTime());
196 set_RNEMD_nBins(simParams->getRNEMD_nBins());
197 midBin_ = nBins_ / 2;
198 if (simParams->haveRNEMD_binShift()) {
199 if (simParams->getRNEMD_binShift()) {
200 zShift_ = 0.5 / (RealType)(nBins_);
201 } else {
202 zShift_ = 0.0;
203 }
204 } else {
205 zShift_ = 0.0;
206 }
207 //cerr << "I shift slabs by " << zShift_ << " Lz\n";
208 //shift slabs by half slab width, maybe useful in heterogeneous systems
209 //set to 0.0 if not using it; N/A in status output yet
210 if (simParams->haveRNEMD_logWidth()) {
211 set_RNEMD_logWidth(simParams->getRNEMD_logWidth());
212 /*arbitary rnemdLogWidth_, no checking;
213 if (rnemdLogWidth_ != nBins_ && rnemdLogWidth_ != midBin_ + 1) {
214 cerr << "WARNING! RNEMD_logWidth has abnormal value!\n";
215 cerr << "Automaically set back to default.\n";
216 rnemdLogWidth_ = nBins_;
217 }*/
218 } else {
219 set_RNEMD_logWidth(nBins_);
220 }
221 tempHist_.resize(rnemdLogWidth_, 0.0);
222 tempCount_.resize(rnemdLogWidth_, 0);
223 pxzHist_.resize(rnemdLogWidth_, 0.0);
224 //vxzCount_.resize(rnemdLogWidth_, 0);
225 pyzHist_.resize(rnemdLogWidth_, 0.0);
226 //vyzCount_.resize(rnemdLogWidth_, 0);
227
228 mHist_.resize(rnemdLogWidth_, 0.0);
229 xTempHist_.resize(rnemdLogWidth_, 0.0);
230 yTempHist_.resize(rnemdLogWidth_, 0.0);
231 zTempHist_.resize(rnemdLogWidth_, 0.0);
232 xyzTempCount_.resize(rnemdLogWidth_, 0);
233 rotTempHist_.resize(rnemdLogWidth_, 0.0);
234 rotTempCount_.resize(rnemdLogWidth_, 0);
235
236 set_RNEMD_exchange_total(0.0);
237 if (simParams->haveRNEMD_targetFlux()) {
238 set_RNEMD_target_flux(simParams->getRNEMD_targetFlux());
239 } else {
240 set_RNEMD_target_flux(0.0);
241 }
242 if (simParams->haveRNEMD_targetJzKE()) {
243 set_RNEMD_target_JzKE(simParams->getRNEMD_targetJzKE());
244 } else {
245 set_RNEMD_target_JzKE(0.0);
246 }
247 if (simParams->haveRNEMD_targetJzpx()) {
248 set_RNEMD_target_jzpx(simParams->getRNEMD_targetJzpx());
249 } else {
250 set_RNEMD_target_jzpx(0.0);
251 }
252 jzp_.x() = targetJzpx_;
253 njzp_.x() = -targetJzpx_;
254 if (simParams->haveRNEMD_targetJzpy()) {
255 set_RNEMD_target_jzpy(simParams->getRNEMD_targetJzpy());
256 } else {
257 set_RNEMD_target_jzpy(0.0);
258 }
259 jzp_.y() = targetJzpy_;
260 njzp_.y() = -targetJzpy_;
261 if (simParams->haveRNEMD_targetJzpz()) {
262 set_RNEMD_target_jzpz(simParams->getRNEMD_targetJzpz());
263 } else {
264 set_RNEMD_target_jzpz(0.0);
265 }
266 jzp_.z() = targetJzpz_;
267 njzp_.z() = -targetJzpz_;
268
269 #ifndef IS_MPI
270 if (simParams->haveSeed()) {
271 seedValue = simParams->getSeed();
272 randNumGen_ = new SeqRandNumGen(seedValue);
273 }else {
274 randNumGen_ = new SeqRandNumGen();
275 }
276 #else
277 if (simParams->haveSeed()) {
278 seedValue = simParams->getSeed();
279 randNumGen_ = new ParallelRandNumGen(seedValue);
280 }else {
281 randNumGen_ = new ParallelRandNumGen();
282 }
283 #endif
284 }
285
286 RNEMD::~RNEMD() {
287 delete randNumGen_;
288
289 #ifdef IS_MPI
290 if (worldRank == 0) {
291 #endif
292
293 sprintf(painCave.errMsg,
294 "RNEMD: total failed trials: %d\n",
295 failTrialCount_);
296 painCave.isFatal = 0;
297 painCave.severity = OPENMD_INFO;
298 simError();
299
300 if (outputTemp_) tempLog_.close();
301 if (outputVx_) vxzLog_.close();
302 if (outputVy_) vyzLog_.close();
303
304 if (rnemdType_ == rnemdKineticScale || rnemdType_ == rnemdPxScale ||
305 rnemdType_ == rnemdPyScale) {
306 sprintf(painCave.errMsg,
307 "RNEMD: total root-checking warnings: %d\n",
308 failRootCount_);
309 painCave.isFatal = 0;
310 painCave.severity = OPENMD_INFO;
311 simError();
312 }
313 if (output3DTemp_) {
314 xTempLog_.close();
315 yTempLog_.close();
316 zTempLog_.close();
317 }
318 if (outputRotTemp_) rotTempLog_.close();
319
320 #ifdef IS_MPI
321 }
322 #endif
323 }
324
325 void RNEMD::doSwap() {
326
327 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
328 Mat3x3d hmat = currentSnap_->getHmat();
329
330 seleMan_.setSelectionSet(evaluator_.evaluate());
331
332 int selei;
333 StuntDouble* sd;
334 int idx;
335
336 RealType min_val;
337 bool min_found = false;
338 StuntDouble* min_sd;
339
340 RealType max_val;
341 bool max_found = false;
342 StuntDouble* max_sd;
343
344 for (sd = seleMan_.beginSelected(selei); sd != NULL;
345 sd = seleMan_.nextSelected(selei)) {
346
347 idx = sd->getLocalIndex();
348
349 Vector3d pos = sd->getPos();
350
351 // wrap the stuntdouble's position back into the box:
352
353 if (usePeriodicBoundaryConditions_)
354 currentSnap_->wrapVector(pos);
355
356 // which bin is this stuntdouble in?
357 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
358
359 int binNo = int(nBins_ * (pos.z() / hmat(2,2) + zShift_ + 0.5)) % nBins_;
360
361
362 // if we're in bin 0 or the middleBin
363 if (binNo == 0 || binNo == midBin_) {
364
365 RealType mass = sd->getMass();
366 Vector3d vel = sd->getVel();
367 RealType value;
368
369 switch(rnemdType_) {
370 case rnemdKineticSwap :
371
372 value = mass * vel.lengthSquare();
373
374 if (sd->isDirectional()) {
375 Vector3d angMom = sd->getJ();
376 Mat3x3d I = sd->getI();
377
378 if (sd->isLinear()) {
379 int i = sd->linearAxis();
380 int j = (i + 1) % 3;
381 int k = (i + 2) % 3;
382 value += angMom[j] * angMom[j] / I(j, j) +
383 angMom[k] * angMom[k] / I(k, k);
384 } else {
385 value += angMom[0]*angMom[0]/I(0, 0)
386 + angMom[1]*angMom[1]/I(1, 1)
387 + angMom[2]*angMom[2]/I(2, 2);
388 }
389 } //angular momenta exchange enabled
390 //energyConvert temporarily disabled
391 //make exchangeSum_ comparable between swap & scale
392 //value = value * 0.5 / PhysicalConstants::energyConvert;
393 value *= 0.5;
394 break;
395 case rnemdPx :
396 value = mass * vel[0];
397 break;
398 case rnemdPy :
399 value = mass * vel[1];
400 break;
401 case rnemdPz :
402 value = mass * vel[2];
403 break;
404 default :
405 break;
406 }
407
408 if (binNo == 0) {
409 if (!min_found) {
410 min_val = value;
411 min_sd = sd;
412 min_found = true;
413 } else {
414 if (min_val > value) {
415 min_val = value;
416 min_sd = sd;
417 }
418 }
419 } else { //midBin_
420 if (!max_found) {
421 max_val = value;
422 max_sd = sd;
423 max_found = true;
424 } else {
425 if (max_val < value) {
426 max_val = value;
427 max_sd = sd;
428 }
429 }
430 }
431 }
432 }
433
434 #ifdef IS_MPI
435 int nProc, worldRank;
436
437 nProc = MPI::COMM_WORLD.Get_size();
438 worldRank = MPI::COMM_WORLD.Get_rank();
439
440 bool my_min_found = min_found;
441 bool my_max_found = max_found;
442
443 // Even if we didn't find a minimum, did someone else?
444 MPI::COMM_WORLD.Allreduce(&my_min_found, &min_found, 1, MPI::BOOL, MPI::LOR);
445 // Even if we didn't find a maximum, did someone else?
446 MPI::COMM_WORLD.Allreduce(&my_max_found, &max_found, 1, MPI::BOOL, MPI::LOR);
447 #endif
448
449 if (max_found && min_found) {
450
451 #ifdef IS_MPI
452 struct {
453 RealType val;
454 int rank;
455 } max_vals, min_vals;
456
457 if (my_min_found) {
458 min_vals.val = min_val;
459 } else {
460 min_vals.val = HONKING_LARGE_VALUE;
461 }
462 min_vals.rank = worldRank;
463
464 // Who had the minimum?
465 MPI::COMM_WORLD.Allreduce(&min_vals, &min_vals,
466 1, MPI::REALTYPE_INT, MPI::MINLOC);
467 min_val = min_vals.val;
468
469 if (my_max_found) {
470 max_vals.val = max_val;
471 } else {
472 max_vals.val = -HONKING_LARGE_VALUE;
473 }
474 max_vals.rank = worldRank;
475
476 // Who had the maximum?
477 MPI::COMM_WORLD.Allreduce(&max_vals, &max_vals,
478 1, MPI::REALTYPE_INT, MPI::MAXLOC);
479 max_val = max_vals.val;
480 #endif
481
482 if (min_val < max_val) {
483
484 #ifdef IS_MPI
485 if (max_vals.rank == worldRank && min_vals.rank == worldRank) {
486 // I have both maximum and minimum, so proceed like a single
487 // processor version:
488 #endif
489
490 Vector3d min_vel = min_sd->getVel();
491 Vector3d max_vel = max_sd->getVel();
492 RealType temp_vel;
493
494 switch(rnemdType_) {
495 case rnemdKineticSwap :
496 min_sd->setVel(max_vel);
497 max_sd->setVel(min_vel);
498 if (min_sd->isDirectional() && max_sd->isDirectional()) {
499 Vector3d min_angMom = min_sd->getJ();
500 Vector3d max_angMom = max_sd->getJ();
501 min_sd->setJ(max_angMom);
502 max_sd->setJ(min_angMom);
503 }//angular momenta exchange enabled
504 //assumes same rigid body identity
505 break;
506 case rnemdPx :
507 temp_vel = min_vel.x();
508 min_vel.x() = max_vel.x();
509 max_vel.x() = temp_vel;
510 min_sd->setVel(min_vel);
511 max_sd->setVel(max_vel);
512 break;
513 case rnemdPy :
514 temp_vel = min_vel.y();
515 min_vel.y() = max_vel.y();
516 max_vel.y() = temp_vel;
517 min_sd->setVel(min_vel);
518 max_sd->setVel(max_vel);
519 break;
520 case rnemdPz :
521 temp_vel = min_vel.z();
522 min_vel.z() = max_vel.z();
523 max_vel.z() = temp_vel;
524 min_sd->setVel(min_vel);
525 max_sd->setVel(max_vel);
526 break;
527 default :
528 break;
529 }
530
531 #ifdef IS_MPI
532 // the rest of the cases only apply in parallel simulations:
533 } else if (max_vals.rank == worldRank) {
534 // I had the max, but not the minimum
535
536 Vector3d min_vel;
537 Vector3d max_vel = max_sd->getVel();
538 MPI::Status status;
539
540 // point-to-point swap of the velocity vector
541 MPI::COMM_WORLD.Sendrecv(max_vel.getArrayPointer(), 3, MPI::REALTYPE,
542 min_vals.rank, 0,
543 min_vel.getArrayPointer(), 3, MPI::REALTYPE,
544 min_vals.rank, 0, status);
545
546 switch(rnemdType_) {
547 case rnemdKineticSwap :
548 max_sd->setVel(min_vel);
549 //angular momenta exchange enabled
550 if (max_sd->isDirectional()) {
551 Vector3d min_angMom;
552 Vector3d max_angMom = max_sd->getJ();
553
554 // point-to-point swap of the angular momentum vector
555 MPI::COMM_WORLD.Sendrecv(max_angMom.getArrayPointer(), 3,
556 MPI::REALTYPE, min_vals.rank, 1,
557 min_angMom.getArrayPointer(), 3,
558 MPI::REALTYPE, min_vals.rank, 1,
559 status);
560
561 max_sd->setJ(min_angMom);
562 }
563 break;
564 case rnemdPx :
565 max_vel.x() = min_vel.x();
566 max_sd->setVel(max_vel);
567 break;
568 case rnemdPy :
569 max_vel.y() = min_vel.y();
570 max_sd->setVel(max_vel);
571 break;
572 case rnemdPz :
573 max_vel.z() = min_vel.z();
574 max_sd->setVel(max_vel);
575 break;
576 default :
577 break;
578 }
579 } else if (min_vals.rank == worldRank) {
580 // I had the minimum but not the maximum:
581
582 Vector3d max_vel;
583 Vector3d min_vel = min_sd->getVel();
584 MPI::Status status;
585
586 // point-to-point swap of the velocity vector
587 MPI::COMM_WORLD.Sendrecv(min_vel.getArrayPointer(), 3, MPI::REALTYPE,
588 max_vals.rank, 0,
589 max_vel.getArrayPointer(), 3, MPI::REALTYPE,
590 max_vals.rank, 0, status);
591
592 switch(rnemdType_) {
593 case rnemdKineticSwap :
594 min_sd->setVel(max_vel);
595 //angular momenta exchange enabled
596 if (min_sd->isDirectional()) {
597 Vector3d min_angMom = min_sd->getJ();
598 Vector3d max_angMom;
599
600 // point-to-point swap of the angular momentum vector
601 MPI::COMM_WORLD.Sendrecv(min_angMom.getArrayPointer(), 3,
602 MPI::REALTYPE, max_vals.rank, 1,
603 max_angMom.getArrayPointer(), 3,
604 MPI::REALTYPE, max_vals.rank, 1,
605 status);
606
607 min_sd->setJ(max_angMom);
608 }
609 break;
610 case rnemdPx :
611 min_vel.x() = max_vel.x();
612 min_sd->setVel(min_vel);
613 break;
614 case rnemdPy :
615 min_vel.y() = max_vel.y();
616 min_sd->setVel(min_vel);
617 break;
618 case rnemdPz :
619 min_vel.z() = max_vel.z();
620 min_sd->setVel(min_vel);
621 break;
622 default :
623 break;
624 }
625 }
626 #endif
627 exchangeSum_ += max_val - min_val;
628 } else {
629 sprintf(painCave.errMsg,
630 "RNEMD: exchange NOT performed because min_val > max_val\n");
631 painCave.isFatal = 0;
632 painCave.severity = OPENMD_INFO;
633 simError();
634 failTrialCount_++;
635 }
636 } else {
637 sprintf(painCave.errMsg,
638 "RNEMD: exchange NOT performed because selected object\n"
639 "\tnot present in at least one of the two slabs.\n");
640 painCave.isFatal = 0;
641 painCave.severity = OPENMD_INFO;
642 simError();
643 failTrialCount_++;
644 }
645
646 }
647
648 void RNEMD::doScale() {
649
650 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
651 Mat3x3d hmat = currentSnap_->getHmat();
652
653 seleMan_.setSelectionSet(evaluator_.evaluate());
654
655 int selei;
656 StuntDouble* sd;
657 int idx;
658
659 vector<StuntDouble*> hotBin, coldBin;
660
661 RealType Phx = 0.0;
662 RealType Phy = 0.0;
663 RealType Phz = 0.0;
664 RealType Khx = 0.0;
665 RealType Khy = 0.0;
666 RealType Khz = 0.0;
667 RealType Khw = 0.0;
668 RealType Pcx = 0.0;
669 RealType Pcy = 0.0;
670 RealType Pcz = 0.0;
671 RealType Kcx = 0.0;
672 RealType Kcy = 0.0;
673 RealType Kcz = 0.0;
674 RealType Kcw = 0.0;
675
676 for (sd = seleMan_.beginSelected(selei); sd != NULL;
677 sd = seleMan_.nextSelected(selei)) {
678
679 idx = sd->getLocalIndex();
680
681 Vector3d pos = sd->getPos();
682
683 // wrap the stuntdouble's position back into the box:
684
685 if (usePeriodicBoundaryConditions_)
686 currentSnap_->wrapVector(pos);
687
688 // which bin is this stuntdouble in?
689 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
690
691 int binNo = int(nBins_ * (pos.z() / hmat(2,2) + zShift_ + 0.5)) % nBins_;
692
693 // if we're in bin 0 or the middleBin
694 if (binNo == 0 || binNo == midBin_) {
695
696 RealType mass = sd->getMass();
697 Vector3d vel = sd->getVel();
698
699 if (binNo == 0) {
700 hotBin.push_back(sd);
701 Phx += mass * vel.x();
702 Phy += mass * vel.y();
703 Phz += mass * vel.z();
704 Khx += mass * vel.x() * vel.x();
705 Khy += mass * vel.y() * vel.y();
706 Khz += mass * vel.z() * vel.z();
707 //if (rnemdType_ == rnemdKineticScaleVAM) {
708 if (sd->isDirectional()) {
709 Vector3d angMom = sd->getJ();
710 Mat3x3d I = sd->getI();
711 if (sd->isLinear()) {
712 int i = sd->linearAxis();
713 int j = (i + 1) % 3;
714 int k = (i + 2) % 3;
715 Khw += angMom[j] * angMom[j] / I(j, j) +
716 angMom[k] * angMom[k] / I(k, k);
717 } else {
718 Khw += angMom[0]*angMom[0]/I(0, 0)
719 + angMom[1]*angMom[1]/I(1, 1)
720 + angMom[2]*angMom[2]/I(2, 2);
721 }
722 }
723 //}
724 } else { //midBin_
725 coldBin.push_back(sd);
726 Pcx += mass * vel.x();
727 Pcy += mass * vel.y();
728 Pcz += mass * vel.z();
729 Kcx += mass * vel.x() * vel.x();
730 Kcy += mass * vel.y() * vel.y();
731 Kcz += mass * vel.z() * vel.z();
732 //if (rnemdType_ == rnemdKineticScaleVAM) {
733 if (sd->isDirectional()) {
734 Vector3d angMom = sd->getJ();
735 Mat3x3d I = sd->getI();
736 if (sd->isLinear()) {
737 int i = sd->linearAxis();
738 int j = (i + 1) % 3;
739 int k = (i + 2) % 3;
740 Kcw += angMom[j] * angMom[j] / I(j, j) +
741 angMom[k] * angMom[k] / I(k, k);
742 } else {
743 Kcw += angMom[0]*angMom[0]/I(0, 0)
744 + angMom[1]*angMom[1]/I(1, 1)
745 + angMom[2]*angMom[2]/I(2, 2);
746 }
747 }
748 //}
749 }
750 }
751 }
752
753 Khx *= 0.5;
754 Khy *= 0.5;
755 Khz *= 0.5;
756 Khw *= 0.5;
757 Kcx *= 0.5;
758 Kcy *= 0.5;
759 Kcz *= 0.5;
760 Kcw *= 0.5;
761
762 std::cerr << "Khx= " << Khx << "\tKhy= " << Khy << "\tKhz= " << Khz
763 << "\tKhw= " << Khw << "\tKcx= " << Kcx << "\tKcy= " << Kcy
764 << "\tKcz= " << Kcz << "\tKcw= " << Kcw << "\n";
765 std::cerr << "Phx= " << Phx << "\tPhy= " << Phy << "\tPhz= " << Phz
766 << "\tPcx= " << Pcx << "\tPcy= " << Pcy << "\tPcz= " <<Pcz<<"\n";
767
768 #ifdef IS_MPI
769 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phx, 1, MPI::REALTYPE, MPI::SUM);
770 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phy, 1, MPI::REALTYPE, MPI::SUM);
771 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phz, 1, MPI::REALTYPE, MPI::SUM);
772 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcx, 1, MPI::REALTYPE, MPI::SUM);
773 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcy, 1, MPI::REALTYPE, MPI::SUM);
774 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcz, 1, MPI::REALTYPE, MPI::SUM);
775
776 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khx, 1, MPI::REALTYPE, MPI::SUM);
777 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khy, 1, MPI::REALTYPE, MPI::SUM);
778 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khz, 1, MPI::REALTYPE, MPI::SUM);
779 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khw, 1, MPI::REALTYPE, MPI::SUM);
780
781 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcx, 1, MPI::REALTYPE, MPI::SUM);
782 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcy, 1, MPI::REALTYPE, MPI::SUM);
783 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcz, 1, MPI::REALTYPE, MPI::SUM);
784 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcw, 1, MPI::REALTYPE, MPI::SUM);
785 #endif
786
787 //solve coldBin coeff's first
788 RealType px = Pcx / Phx;
789 RealType py = Pcy / Phy;
790 RealType pz = Pcz / Phz;
791 RealType c, x, y, z;
792 bool successfulScale = false;
793 if ((rnemdType_ == rnemdKineticScaleVAM) ||
794 (rnemdType_ == rnemdKineticScaleAM)) {
795 //may need sanity check Khw & Kcw > 0
796
797 if (rnemdType_ == rnemdKineticScaleVAM) {
798 c = 1.0 - targetFlux_ / (Kcx + Kcy + Kcz + Kcw);
799 } else {
800 c = 1.0 - targetFlux_ / Kcw;
801 }
802
803 if ((c > 0.81) && (c < 1.21)) {//restrict scaling coefficients
804 c = sqrt(c);
805 std::cerr << "cold slab scaling coefficient: " << c << endl;
806 //now convert to hotBin coefficient
807 RealType w = 0.0;
808 if (rnemdType_ == rnemdKineticScaleVAM) {
809 x = 1.0 + px * (1.0 - c);
810 y = 1.0 + py * (1.0 - c);
811 z = 1.0 + pz * (1.0 - c);
812 /* more complicated way
813 w = 1.0 + (Kcw - Kcw * c * c - (c * c * (Kcx + Kcy + Kcz
814 + Khx * px * px + Khy * py * py + Khz * pz * pz)
815 - 2.0 * c * (Khx * px * (1.0 + px) + Khy * py * (1.0 + py)
816 + Khz * pz * (1.0 + pz)) + Khx * px * (2.0 + px)
817 + Khy * py * (2.0 + py) + Khz * pz * (2.0 + pz)
818 - Kcx - Kcy - Kcz)) / Khw; the following is simpler
819 */
820 if ((fabs(x - 1.0) < 0.1) && (fabs(y - 1.0) < 0.1) &&
821 (fabs(z - 1.0) < 0.1)) {
822 w = 1.0 + (targetFlux_ + Khx * (1.0 - x * x) + Khy * (1.0 - y * y)
823 + Khz * (1.0 - z * z)) / Khw;
824 }//no need to calculate w if x, y or z is out of range
825 } else {
826 w = 1.0 + targetFlux_ / Khw;
827 }
828 if ((w > 0.81) && (w < 1.21)) {//restrict scaling coefficients
829 //if w is in the right range, so should be x, y, z.
830 vector<StuntDouble*>::iterator sdi;
831 Vector3d vel;
832 for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) {
833 if (rnemdType_ == rnemdKineticScaleVAM) {
834 vel = (*sdi)->getVel() * c;
835 //vel.x() *= c;
836 //vel.y() *= c;
837 //vel.z() *= c;
838 (*sdi)->setVel(vel);
839 }
840 if ((*sdi)->isDirectional()) {
841 Vector3d angMom = (*sdi)->getJ() * c;
842 //angMom[0] *= c;
843 //angMom[1] *= c;
844 //angMom[2] *= c;
845 (*sdi)->setJ(angMom);
846 }
847 }
848 w = sqrt(w);
849 std::cerr << "xh= " << x << "\tyh= " << y << "\tzh= " << z
850 << "\twh= " << w << endl;
851 for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) {
852 if (rnemdType_ == rnemdKineticScaleVAM) {
853 vel = (*sdi)->getVel();
854 vel.x() *= x;
855 vel.y() *= y;
856 vel.z() *= z;
857 (*sdi)->setVel(vel);
858 }
859 if ((*sdi)->isDirectional()) {
860 Vector3d angMom = (*sdi)->getJ() * w;
861 //angMom[0] *= w;
862 //angMom[1] *= w;
863 //angMom[2] *= w;
864 (*sdi)->setJ(angMom);
865 }
866 }
867 successfulScale = true;
868 exchangeSum_ += targetFlux_;
869 }
870 }
871 } else {
872 RealType a000, a110, c0, a001, a111, b01, b11, c1;
873 switch(rnemdType_) {
874 case rnemdKineticScale :
875 /* used hotBin coeff's & only scale x & y dimensions
876 RealType px = Phx / Pcx;
877 RealType py = Phy / Pcy;
878 a110 = Khy;
879 c0 = - Khx - Khy - targetFlux_;
880 a000 = Khx;
881 a111 = Kcy * py * py;
882 b11 = -2.0 * Kcy * py * (1.0 + py);
883 c1 = Kcy * py * (2.0 + py) + Kcx * px * ( 2.0 + px) + targetFlux_;
884 b01 = -2.0 * Kcx * px * (1.0 + px);
885 a001 = Kcx * px * px;
886 */
887 //scale all three dimensions, let c_x = c_y
888 a000 = Kcx + Kcy;
889 a110 = Kcz;
890 c0 = targetFlux_ - Kcx - Kcy - Kcz;
891 a001 = Khx * px * px + Khy * py * py;
892 a111 = Khz * pz * pz;
893 b01 = -2.0 * (Khx * px * (1.0 + px) + Khy * py * (1.0 + py));
894 b11 = -2.0 * Khz * pz * (1.0 + pz);
895 c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
896 + Khz * pz * (2.0 + pz) - targetFlux_;
897 break;
898 case rnemdPxScale :
899 c = 1 - targetFlux_ / Pcx;
900 a000 = Kcy;
901 a110 = Kcz;
902 c0 = Kcx * c * c - Kcx - Kcy - Kcz;
903 a001 = py * py * Khy;
904 a111 = pz * pz * Khz;
905 b01 = -2.0 * Khy * py * (1.0 + py);
906 b11 = -2.0 * Khz * pz * (1.0 + pz);
907 c1 = Khy * py * (2.0 + py) + Khz * pz * (2.0 + pz)
908 + Khx * (fastpow(c * px - px - 1.0, 2) - 1.0);
909 break;
910 case rnemdPyScale :
911 c = 1 - targetFlux_ / Pcy;
912 a000 = Kcx;
913 a110 = Kcz;
914 c0 = Kcy * c * c - Kcx - Kcy - Kcz;
915 a001 = px * px * Khx;
916 a111 = pz * pz * Khz;
917 b01 = -2.0 * Khx * px * (1.0 + px);
918 b11 = -2.0 * Khz * pz * (1.0 + pz);
919 c1 = Khx * px * (2.0 + px) + Khz * pz * (2.0 + pz)
920 + Khy * (fastpow(c * py - py - 1.0, 2) - 1.0);
921 break;
922 case rnemdPzScale ://we don't really do this, do we?
923 c = 1 - targetFlux_ / Pcz;
924 a000 = Kcx;
925 a110 = Kcy;
926 c0 = Kcz * c * c - Kcx - Kcy - Kcz;
927 a001 = px * px * Khx;
928 a111 = py * py * Khy;
929 b01 = -2.0 * Khx * px * (1.0 + px);
930 b11 = -2.0 * Khy * py * (1.0 + py);
931 c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
932 + Khz * (fastpow(c * pz - pz - 1.0, 2) - 1.0);
933 break;
934 default :
935 break;
936 }
937
938 RealType v1 = a000 * a111 - a001 * a110;
939 RealType v2 = a000 * b01;
940 RealType v3 = a000 * b11;
941 RealType v4 = a000 * c1 - a001 * c0;
942 RealType v8 = a110 * b01;
943 RealType v10 = - b01 * c0;
944
945 RealType u0 = v2 * v10 - v4 * v4;
946 RealType u1 = -2.0 * v3 * v4;
947 RealType u2 = -v2 * v8 - v3 * v3 - 2.0 * v1 * v4;
948 RealType u3 = -2.0 * v1 * v3;
949 RealType u4 = - v1 * v1;
950 //rescale coefficients
951 RealType maxAbs = fabs(u0);
952 if (maxAbs < fabs(u1)) maxAbs = fabs(u1);
953 if (maxAbs < fabs(u2)) maxAbs = fabs(u2);
954 if (maxAbs < fabs(u3)) maxAbs = fabs(u3);
955 if (maxAbs < fabs(u4)) maxAbs = fabs(u4);
956 u0 /= maxAbs;
957 u1 /= maxAbs;
958 u2 /= maxAbs;
959 u3 /= maxAbs;
960 u4 /= maxAbs;
961 //max_element(start, end) is also available.
962 Polynomial<RealType> poly; //same as DoublePolynomial poly;
963 poly.setCoefficient(4, u4);
964 poly.setCoefficient(3, u3);
965 poly.setCoefficient(2, u2);
966 poly.setCoefficient(1, u1);
967 poly.setCoefficient(0, u0);
968 vector<RealType> realRoots = poly.FindRealRoots();
969
970 vector<RealType>::iterator ri;
971 RealType r1, r2, alpha0;
972 vector<pair<RealType,RealType> > rps;
973 for (ri = realRoots.begin(); ri !=realRoots.end(); ri++) {
974 r2 = *ri;
975 //check if FindRealRoots() give the right answer
976 if ( fabs(u0 + r2 * (u1 + r2 * (u2 + r2 * (u3 + r2 * u4)))) > 1e-6 ) {
977 sprintf(painCave.errMsg,
978 "RNEMD Warning: polynomial solve seems to have an error!");
979 painCave.isFatal = 0;
980 simError();
981 failRootCount_++;
982 }
983 //might not be useful w/o rescaling coefficients
984 alpha0 = -c0 - a110 * r2 * r2;
985 if (alpha0 >= 0.0) {
986 r1 = sqrt(alpha0 / a000);
987 if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111))
988 < 1e-6)
989 { rps.push_back(make_pair(r1, r2)); }
990 if (r1 > 1e-6) { //r1 non-negative
991 r1 = -r1;
992 if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111))
993 < 1e-6)
994 { rps.push_back(make_pair(r1, r2)); }
995 }
996 }
997 }
998 // Consider combining together the solving pair part w/ the searching
999 // best solution part so that we don't need the pairs vector
1000 if (!rps.empty()) {
1001 RealType smallestDiff = HONKING_LARGE_VALUE;
1002 RealType diff;
1003 pair<RealType,RealType> bestPair = make_pair(1.0, 1.0);
1004 vector<pair<RealType,RealType> >::iterator rpi;
1005 for (rpi = rps.begin(); rpi != rps.end(); rpi++) {
1006 r1 = (*rpi).first;
1007 r2 = (*rpi).second;
1008 switch(rnemdType_) {
1009 case rnemdKineticScale :
1010 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1011 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2)
1012 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
1013 break;
1014 case rnemdPxScale :
1015 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1016 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
1017 break;
1018 case rnemdPyScale :
1019 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1020 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2);
1021 break;
1022 case rnemdPzScale :
1023 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
1024 + fastpow(r1 * r1 / r2 / r2 - Kcy/Kcx, 2);
1025 default :
1026 break;
1027 }
1028 if (diff < smallestDiff) {
1029 smallestDiff = diff;
1030 bestPair = *rpi;
1031 }
1032 }
1033 #ifdef IS_MPI
1034 if (worldRank == 0) {
1035 #endif
1036 sprintf(painCave.errMsg,
1037 "RNEMD: roots r1= %lf\tr2 = %lf\n",
1038 bestPair.first, bestPair.second);
1039 painCave.isFatal = 0;
1040 painCave.severity = OPENMD_INFO;
1041 simError();
1042 #ifdef IS_MPI
1043 }
1044 #endif
1045
1046 switch(rnemdType_) {
1047 case rnemdKineticScale :
1048 x = bestPair.first;
1049 y = bestPair.first;
1050 z = bestPair.second;
1051 break;
1052 case rnemdPxScale :
1053 x = c;
1054 y = bestPair.first;
1055 z = bestPair.second;
1056 break;
1057 case rnemdPyScale :
1058 x = bestPair.first;
1059 y = c;
1060 z = bestPair.second;
1061 break;
1062 case rnemdPzScale :
1063 x = bestPair.first;
1064 y = bestPair.second;
1065 z = c;
1066 break;
1067 default :
1068 break;
1069 }
1070 vector<StuntDouble*>::iterator sdi;
1071 Vector3d vel;
1072 for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) {
1073 vel = (*sdi)->getVel();
1074 vel.x() *= x;
1075 vel.y() *= y;
1076 vel.z() *= z;
1077 (*sdi)->setVel(vel);
1078 }
1079 //convert to hotBin coefficient
1080 x = 1.0 + px * (1.0 - x);
1081 y = 1.0 + py * (1.0 - y);
1082 z = 1.0 + pz * (1.0 - z);
1083 for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) {
1084 vel = (*sdi)->getVel();
1085 vel.x() *= x;
1086 vel.y() *= y;
1087 vel.z() *= z;
1088 (*sdi)->setVel(vel);
1089 }
1090 successfulScale = true;
1091 exchangeSum_ += targetFlux_;
1092 }
1093 }
1094 if (successfulScale != true) {
1095 sprintf(painCave.errMsg,
1096 "RNEMD: exchange NOT performed!\n");
1097 painCave.isFatal = 0;
1098 painCave.severity = OPENMD_INFO;
1099 simError();
1100 failTrialCount_++;
1101 }
1102 }
1103
1104 void RNEMD::doShiftScale() {
1105
1106 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1107 Mat3x3d hmat = currentSnap_->getHmat();
1108
1109 seleMan_.setSelectionSet(evaluator_.evaluate());
1110
1111 int selei;
1112 StuntDouble* sd;
1113 int idx;
1114
1115 vector<StuntDouble*> hotBin, coldBin;
1116
1117 Vector3d Ph(V3Zero);
1118 RealType Mh = 0.0;
1119 RealType Kh = 0.0;
1120 Vector3d Pc(V3Zero);
1121 RealType Mc = 0.0;
1122 RealType Kc = 0.0;
1123
1124 for (sd = seleMan_.beginSelected(selei); sd != NULL;
1125 sd = seleMan_.nextSelected(selei)) {
1126
1127 idx = sd->getLocalIndex();
1128
1129 Vector3d pos = sd->getPos();
1130
1131 // wrap the stuntdouble's position back into the box:
1132
1133 if (usePeriodicBoundaryConditions_)
1134 currentSnap_->wrapVector(pos);
1135
1136 // which bin is this stuntdouble in?
1137 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
1138
1139 int binNo = int(nBins_ * (pos.z() / hmat(2,2) + zShift_ + 0.5)) % nBins_;
1140
1141 // if we're in bin 0 or the middleBin
1142 if (binNo == 0 || binNo == midBin_) {
1143
1144 RealType mass = sd->getMass();
1145 Vector3d vel = sd->getVel();
1146
1147 if (binNo == 0) {
1148 hotBin.push_back(sd);
1149 //std::cerr << "before, velocity = " << vel << endl;
1150 Ph += mass * vel;
1151 //std::cerr << "after, velocity = " << vel << endl;
1152 Mh += mass;
1153 Kh += mass * vel.lengthSquare();
1154 if (rnemdType_ == rnemdShiftScaleVAM) {
1155 if (sd->isDirectional()) {
1156 Vector3d angMom = sd->getJ();
1157 Mat3x3d I = sd->getI();
1158 if (sd->isLinear()) {
1159 int i = sd->linearAxis();
1160 int j = (i + 1) % 3;
1161 int k = (i + 2) % 3;
1162 Kh += angMom[j] * angMom[j] / I(j, j) +
1163 angMom[k] * angMom[k] / I(k, k);
1164 } else {
1165 Kh += angMom[0] * angMom[0] / I(0, 0) +
1166 angMom[1] * angMom[1] / I(1, 1) +
1167 angMom[2] * angMom[2] / I(2, 2);
1168 }
1169 }
1170 }
1171 } else { //midBin_
1172 coldBin.push_back(sd);
1173 Pc += mass * vel;
1174 Mc += mass;
1175 Kc += mass * vel.lengthSquare();
1176 if (rnemdType_ == rnemdShiftScaleVAM) {
1177 if (sd->isDirectional()) {
1178 Vector3d angMom = sd->getJ();
1179 Mat3x3d I = sd->getI();
1180 if (sd->isLinear()) {
1181 int i = sd->linearAxis();
1182 int j = (i + 1) % 3;
1183 int k = (i + 2) % 3;
1184 Kc += angMom[j] * angMom[j] / I(j, j) +
1185 angMom[k] * angMom[k] / I(k, k);
1186 } else {
1187 Kc += angMom[0] * angMom[0] / I(0, 0) +
1188 angMom[1] * angMom[1] / I(1, 1) +
1189 angMom[2] * angMom[2] / I(2, 2);
1190 }
1191 }
1192 }
1193 }
1194 }
1195 }
1196
1197 Kh *= 0.5;
1198 Kc *= 0.5;
1199
1200 std::cerr << "Mh= " << Mh << "\tKh= " << Kh << "\tMc= " << Mc
1201 << "\tKc= " << Kc << endl;
1202 std::cerr << "Ph= " << Ph << "\tPc= " << Pc << endl;
1203
1204 #ifdef IS_MPI
1205 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Ph[0], 3, MPI::REALTYPE, MPI::SUM);
1206 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pc[0], 3, MPI::REALTYPE, MPI::SUM);
1207 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Mh, 1, MPI::REALTYPE, MPI::SUM);
1208 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kh, 1, MPI::REALTYPE, MPI::SUM);
1209 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Mc, 1, MPI::REALTYPE, MPI::SUM);
1210 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kc, 1, MPI::REALTYPE, MPI::SUM);
1211 #endif
1212
1213 bool successfulExchange = false;
1214 if ((Mh > 0.0) && (Mc > 0.0)) {//both slabs are not empty
1215 Vector3d vc = Pc / Mc;
1216 Vector3d ac = njzp_ / Mc + vc;
1217 RealType cNumerator = Kc - targetJzKE_ - 0.5 * Mc * ac.lengthSquare();
1218 if (cNumerator > 0.0) {
1219 RealType cDenominator = Kc - 0.5 * Mc * vc.lengthSquare();
1220 if (cDenominator > 0.0) {
1221 RealType c = sqrt(cNumerator / cDenominator);
1222 if ((c > 0.9) && (c < 1.1)) {//restrict scaling coefficients
1223 Vector3d vh = Ph / Mh;
1224 Vector3d ah = jzp_ / Mh + vh;
1225 RealType hNumerator = Kh + targetJzKE_
1226 - 0.5 * Mh * ah.lengthSquare();
1227 if (hNumerator > 0.0) {
1228 RealType hDenominator = Kh - 0.5 * Mh * vh.lengthSquare();
1229 if (hDenominator > 0.0) {
1230 RealType h = sqrt(hNumerator / hDenominator);
1231 if ((h > 0.9) && (h < 1.1)) {
1232 std::cerr << "cold slab scaling coefficient: " << c << "\n";
1233 std::cerr << "hot slab scaling coefficient: " << h << "\n";
1234 vector<StuntDouble*>::iterator sdi;
1235 Vector3d vel;
1236 for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) {
1237 //vel = (*sdi)->getVel();
1238 vel = ((*sdi)->getVel() - vc) * c + ac;
1239 (*sdi)->setVel(vel);
1240 if (rnemdType_ == rnemdShiftScaleVAM) {
1241 if ((*sdi)->isDirectional()) {
1242 Vector3d angMom = (*sdi)->getJ() * c;
1243 (*sdi)->setJ(angMom);
1244 }
1245 }
1246 }
1247 for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) {
1248 //vel = (*sdi)->getVel();
1249 vel = ((*sdi)->getVel() - vh) * h + ah;
1250 (*sdi)->setVel(vel);
1251 if (rnemdType_ == rnemdShiftScaleVAM) {
1252 if ((*sdi)->isDirectional()) {
1253 Vector3d angMom = (*sdi)->getJ() * h;
1254 (*sdi)->setJ(angMom);
1255 }
1256 }
1257 }
1258 successfulExchange = true;
1259 exchangeSum_ += targetFlux_;
1260 // this is a redundant variable for doShiftScale() so that
1261 // RNEMD can output one exchange quantity needed in a job.
1262 // need a better way to do this.
1263 }
1264 }
1265 }
1266 }
1267 }
1268 }
1269 }
1270 if (successfulExchange != true) {
1271 sprintf(painCave.errMsg,
1272 "RNEMD: exchange NOT performed!\n");
1273 painCave.isFatal = 0;
1274 painCave.severity = OPENMD_INFO;
1275 simError();
1276 failTrialCount_++;
1277 }
1278 }
1279
1280 void RNEMD::doRNEMD() {
1281
1282 switch(rnemdType_) {
1283 case rnemdKineticScale :
1284 case rnemdKineticScaleVAM :
1285 case rnemdKineticScaleAM :
1286 case rnemdPxScale :
1287 case rnemdPyScale :
1288 case rnemdPzScale :
1289 doScale();
1290 break;
1291 case rnemdKineticSwap :
1292 case rnemdPx :
1293 case rnemdPy :
1294 case rnemdPz :
1295 doSwap();
1296 break;
1297 case rnemdShiftScaleV :
1298 case rnemdShiftScaleVAM :
1299 doShiftScale();
1300 break;
1301 case rnemdUnknown :
1302 default :
1303 break;
1304 }
1305 }
1306
1307 void RNEMD::collectData() {
1308
1309 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1310 Mat3x3d hmat = currentSnap_->getHmat();
1311
1312 seleMan_.setSelectionSet(evaluator_.evaluate());
1313
1314 int selei;
1315 StuntDouble* sd;
1316 int idx;
1317
1318 // alternative approach, track all molecules instead of only those
1319 // selected for scaling/swapping:
1320 /*
1321 SimInfo::MoleculeIterator miter;
1322 vector<StuntDouble*>::iterator iiter;
1323 Molecule* mol;
1324 StuntDouble* integrableObject;
1325 for (mol = info_->beginMolecule(miter); mol != NULL;
1326 mol = info_->nextMolecule(miter))
1327 integrableObject is essentially sd
1328 for (integrableObject = mol->beginIntegrableObject(iiter);
1329 integrableObject != NULL;
1330 integrableObject = mol->nextIntegrableObject(iiter))
1331 */
1332 for (sd = seleMan_.beginSelected(selei); sd != NULL;
1333 sd = seleMan_.nextSelected(selei)) {
1334
1335 idx = sd->getLocalIndex();
1336
1337 Vector3d pos = sd->getPos();
1338
1339 // wrap the stuntdouble's position back into the box:
1340
1341 if (usePeriodicBoundaryConditions_)
1342 currentSnap_->wrapVector(pos);
1343
1344 // which bin is this stuntdouble in?
1345 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
1346
1347 int binNo = int(rnemdLogWidth_ * (pos.z() / hmat(2,2) + 0.5)) %
1348 rnemdLogWidth_;
1349 // no symmetrization allowed due to arbitary rnemdLogWidth_
1350 /*
1351 if (rnemdLogWidth_ == midBin_ + 1)
1352 if (binNo > midBin_)
1353 binNo = nBins_ - binNo;
1354 */
1355 RealType mass = sd->getMass();
1356 mHist_[binNo] += mass;
1357 Vector3d vel = sd->getVel();
1358 RealType value;
1359 //RealType xVal, yVal, zVal;
1360
1361 if (outputTemp_) {
1362 value = mass * vel.lengthSquare();
1363 tempCount_[binNo] += 3;
1364 if (sd->isDirectional()) {
1365 Vector3d angMom = sd->getJ();
1366 Mat3x3d I = sd->getI();
1367 if (sd->isLinear()) {
1368 int i = sd->linearAxis();
1369 int j = (i + 1) % 3;
1370 int k = (i + 2) % 3;
1371 value += angMom[j] * angMom[j] / I(j, j) +
1372 angMom[k] * angMom[k] / I(k, k);
1373 tempCount_[binNo] +=2;
1374 } else {
1375 value += angMom[0] * angMom[0] / I(0, 0) +
1376 angMom[1]*angMom[1]/I(1, 1) +
1377 angMom[2]*angMom[2]/I(2, 2);
1378 tempCount_[binNo] +=3;
1379 }
1380 }
1381 value = value / PhysicalConstants::energyConvert
1382 / PhysicalConstants::kb;//may move to getStatus()
1383 tempHist_[binNo] += value;
1384 }
1385 if (outputVx_) {
1386 value = mass * vel[0];
1387 //vxzCount_[binNo]++;
1388 pxzHist_[binNo] += value;
1389 }
1390 if (outputVy_) {
1391 value = mass * vel[1];
1392 //vyzCount_[binNo]++;
1393 pyzHist_[binNo] += value;
1394 }
1395
1396 if (output3DTemp_) {
1397 value = mass * vel.x() * vel.x();
1398 xTempHist_[binNo] += value;
1399 value = mass * vel.y() * vel.y() / PhysicalConstants::energyConvert
1400 / PhysicalConstants::kb;
1401 yTempHist_[binNo] += value;
1402 value = mass * vel.z() * vel.z() / PhysicalConstants::energyConvert
1403 / PhysicalConstants::kb;
1404 zTempHist_[binNo] += value;
1405 xyzTempCount_[binNo]++;
1406 }
1407 if (outputRotTemp_) {
1408 if (sd->isDirectional()) {
1409 Vector3d angMom = sd->getJ();
1410 Mat3x3d I = sd->getI();
1411 if (sd->isLinear()) {
1412 int i = sd->linearAxis();
1413 int j = (i + 1) % 3;
1414 int k = (i + 2) % 3;
1415 value = angMom[j] * angMom[j] / I(j, j) +
1416 angMom[k] * angMom[k] / I(k, k);
1417 rotTempCount_[binNo] +=2;
1418 } else {
1419 value = angMom[0] * angMom[0] / I(0, 0) +
1420 angMom[1] * angMom[1] / I(1, 1) +
1421 angMom[2] * angMom[2] / I(2, 2);
1422 rotTempCount_[binNo] +=3;
1423 }
1424 }
1425 value = value / PhysicalConstants::energyConvert
1426 / PhysicalConstants::kb;//may move to getStatus()
1427 rotTempHist_[binNo] += value;
1428 }
1429
1430 }
1431 }
1432
1433 void RNEMD::getStarted() {
1434 collectData();
1435 /*now can output profile in step 0, but might not be useful;
1436 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1437 Stats& stat = currentSnap_->statData;
1438 stat[Stats::RNEMD_EXCHANGE_TOTAL] = exchangeSum_;
1439 */
1440 //may output a header for the log file here
1441 getStatus();
1442 }
1443
1444 void RNEMD::getStatus() {
1445
1446 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
1447 Stats& stat = currentSnap_->statData;
1448 RealType time = currentSnap_->getTime();
1449
1450 stat[Stats::RNEMD_EXCHANGE_TOTAL] = exchangeSum_;
1451 //or to be more meaningful, define another item as exchangeSum_ / time
1452 int j;
1453
1454 #ifdef IS_MPI
1455
1456 // all processors have the same number of bins, and STL vectors pack their
1457 // arrays, so in theory, this should be safe:
1458
1459 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &mHist_[0],
1460 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1461 if (outputTemp_) {
1462 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &tempHist_[0],
1463 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1464 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &tempCount_[0],
1465 rnemdLogWidth_, MPI::INT, MPI::SUM);
1466 }
1467 if (outputVx_) {
1468 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &pxzHist_[0],
1469 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1470 //MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &vxzCount_[0],
1471 // rnemdLogWidth_, MPI::INT, MPI::SUM);
1472 }
1473 if (outputVy_) {
1474 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &pyzHist_[0],
1475 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1476 //MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &vyzCount_[0],
1477 // rnemdLogWidth_, MPI::INT, MPI::SUM);
1478 }
1479 if (output3DTemp_) {
1480 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &xTempHist_[0],
1481 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1482 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &yTempHist_[0],
1483 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1484 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &zTempHist_[0],
1485 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1486 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &xyzTempCount_[0],
1487 rnemdLogWidth_, MPI::INT, MPI::SUM);
1488 }
1489 if (outputRotTemp_) {
1490 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &rotTempHist_[0],
1491 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1492 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &rotTempCount_[0],
1493 rnemdLogWidth_, MPI::INT, MPI::SUM);
1494 }
1495
1496 // If we're the root node, should we print out the results
1497 int worldRank = MPI::COMM_WORLD.Get_rank();
1498 if (worldRank == 0) {
1499 #endif
1500
1501 if (outputTemp_) {
1502 tempLog_ << time;
1503 for (j = 0; j < rnemdLogWidth_; j++) {
1504 tempLog_ << "\t" << tempHist_[j] / (RealType)tempCount_[j];
1505 }
1506 tempLog_ << endl;
1507 }
1508 if (outputVx_) {
1509 vxzLog_ << time;
1510 for (j = 0; j < rnemdLogWidth_; j++) {
1511 vxzLog_ << "\t" << pxzHist_[j] / mHist_[j];
1512 }
1513 vxzLog_ << endl;
1514 }
1515 if (outputVy_) {
1516 vyzLog_ << time;
1517 for (j = 0; j < rnemdLogWidth_; j++) {
1518 vyzLog_ << "\t" << pyzHist_[j] / mHist_[j];
1519 }
1520 vyzLog_ << endl;
1521 }
1522
1523 if (output3DTemp_) {
1524 RealType temp;
1525 xTempLog_ << time;
1526 for (j = 0; j < rnemdLogWidth_; j++) {
1527 if (outputVx_)
1528 xTempHist_[j] -= pxzHist_[j] * pxzHist_[j] / mHist_[j];
1529 temp = xTempHist_[j] / (RealType)xyzTempCount_[j]
1530 / PhysicalConstants::energyConvert / PhysicalConstants::kb;
1531 xTempLog_ << "\t" << temp;
1532 }
1533 xTempLog_ << endl;
1534 yTempLog_ << time;
1535 for (j = 0; j < rnemdLogWidth_; j++) {
1536 yTempLog_ << "\t" << yTempHist_[j] / (RealType)xyzTempCount_[j];
1537 }
1538 yTempLog_ << endl;
1539 zTempLog_ << time;
1540 for (j = 0; j < rnemdLogWidth_; j++) {
1541 zTempLog_ << "\t" << zTempHist_[j] / (RealType)xyzTempCount_[j];
1542 }
1543 zTempLog_ << endl;
1544 }
1545 if (outputRotTemp_) {
1546 rotTempLog_ << time;
1547 for (j = 0; j < rnemdLogWidth_; j++) {
1548 rotTempLog_ << "\t" << rotTempHist_[j] / (RealType)rotTempCount_[j];
1549 }
1550 rotTempLog_ << endl;
1551 }
1552
1553 #ifdef IS_MPI
1554 }
1555 #endif
1556
1557 for (j = 0; j < rnemdLogWidth_; j++) {
1558 mHist_[j] = 0.0;
1559 }
1560 if (outputTemp_)
1561 for (j = 0; j < rnemdLogWidth_; j++) {
1562 tempCount_[j] = 0;
1563 tempHist_[j] = 0.0;
1564 }
1565 if (outputVx_)
1566 for (j = 0; j < rnemdLogWidth_; j++) {
1567 //pxzCount_[j] = 0;
1568 pxzHist_[j] = 0.0;
1569 }
1570 if (outputVy_)
1571 for (j = 0; j < rnemdLogWidth_; j++) {
1572 //pyzCount_[j] = 0;
1573 pyzHist_[j] = 0.0;
1574 }
1575
1576 if (output3DTemp_)
1577 for (j = 0; j < rnemdLogWidth_; j++) {
1578 xTempHist_[j] = 0.0;
1579 yTempHist_[j] = 0.0;
1580 zTempHist_[j] = 0.0;
1581 xyzTempCount_[j] = 0;
1582 }
1583 if (outputRotTemp_)
1584 for (j = 0; j < rnemdLogWidth_; j++) {
1585 rotTempCount_[j] = 0;
1586 rotTempHist_[j] = 0.0;
1587 }
1588 }
1589 }
1590

Properties

Name Value
svn:keywords Author Id Revision Date