ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/integrators/RNEMD.cpp
Revision: 1728
Committed: Wed May 30 16:07:03 2012 UTC (12 years, 11 months ago) by jmarr
File size: 53008 byte(s)
Log Message:
resolved

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

Properties

Name Value
svn:keywords Author Id Revision Date