ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/rnemd/RNEMD.cpp
Revision: 1769
Committed: Mon Jul 9 14:15:52 2012 UTC (12 years, 9 months ago) by gezelter
File size: 52767 byte(s)
Log Message:
Code readability updates.

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

Properties

Name Value
svn:keywords Author Id Revision Date