ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/integrators/RNEMD.cpp
Revision: 1627
Committed: Tue Sep 13 22:05:04 2011 UTC (13 years, 7 months ago) by gezelter
File size: 33271 byte(s)
Log Message:
Splitting out ifstrstream into a header and an implementation.  This
means that much of the code that depends on it can be compiled only
once and the parallel I/O is concentrated into a few files.  To do
this, a number of files that relied on basic_ifstrstream to load the
mpi header had to be modified to manage their own headers.


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/SquareMatrix3.hpp"
46 #include "math/Polynomial.hpp"
47 #include "primitives/Molecule.hpp"
48 #include "primitives/StuntDouble.hpp"
49 #include "utils/PhysicalConstants.hpp"
50 #include "utils/Tuple.hpp"
51
52 #ifndef IS_MPI
53 #include "math/SeqRandNumGen.hpp"
54 #else
55 #include <mpi.h>
56 #include "math/ParallelRandNumGen.hpp"
57 #endif
58
59 #define HONKING_LARGE_VALUE 1.0e10
60
61 namespace OpenMD {
62
63 RNEMD::RNEMD(SimInfo* info) : info_(info), evaluator_(info), seleMan_(info), usePeriodicBoundaryConditions_(info->getSimParams()->getUsePeriodicBoundaryConditions()) {
64
65 failTrialCount_ = 0;
66 failRootCount_ = 0;
67
68 int seedValue;
69 Globals * simParams = info->getSimParams();
70
71 stringToEnumMap_["KineticSwap"] = rnemdKineticSwap;
72 stringToEnumMap_["KineticScale"] = rnemdKineticScale;
73 stringToEnumMap_["PxScale"] = rnemdPxScale;
74 stringToEnumMap_["PyScale"] = rnemdPyScale;
75 stringToEnumMap_["PzScale"] = rnemdPzScale;
76 stringToEnumMap_["Px"] = rnemdPx;
77 stringToEnumMap_["Py"] = rnemdPy;
78 stringToEnumMap_["Pz"] = rnemdPz;
79 stringToEnumMap_["Unknown"] = rnemdUnknown;
80
81 rnemdObjectSelection_ = simParams->getRNEMD_objectSelection();
82 evaluator_.loadScriptString(rnemdObjectSelection_);
83 seleMan_.setSelectionSet(evaluator_.evaluate());
84
85 // do some sanity checking
86
87 int selectionCount = seleMan_.getSelectionCount();
88 int nIntegrable = info->getNGlobalIntegrableObjects();
89
90 if (selectionCount > nIntegrable) {
91 sprintf(painCave.errMsg,
92 "RNEMD warning: The current RNEMD_objectSelection,\n"
93 "\t\t%s\n"
94 "\thas resulted in %d selected objects. However,\n"
95 "\tthe total number of integrable objects in the system\n"
96 "\tis only %d. This is almost certainly not what you want\n"
97 "\tto do. A likely cause of this is forgetting the _RB_0\n"
98 "\tselector in the selection script!\n",
99 rnemdObjectSelection_.c_str(),
100 selectionCount, nIntegrable);
101 painCave.isFatal = 0;
102 simError();
103
104 }
105
106 const std::string st = simParams->getRNEMD_exchangeType();
107
108 std::map<std::string, RNEMDTypeEnum>::iterator i;
109 i = stringToEnumMap_.find(st);
110 rnemdType_ = (i == stringToEnumMap_.end()) ? RNEMD::rnemdUnknown : i->second;
111 if (rnemdType_ == rnemdUnknown) {
112 std::cerr << "WARNING! RNEMD Type Unknown!\n";
113 }
114
115 #ifdef IS_MPI
116 if (worldRank == 0) {
117 #endif
118
119 std::string rnemdFileName;
120 std::string xTempFileName;
121 std::string yTempFileName;
122 std::string zTempFileName;
123 switch(rnemdType_) {
124 case rnemdKineticSwap :
125 case rnemdKineticScale :
126 rnemdFileName = "temperature.log";
127 break;
128 case rnemdPx :
129 case rnemdPxScale :
130 case rnemdPy :
131 case rnemdPyScale :
132 rnemdFileName = "momemtum.log";
133 xTempFileName = "temperatureX.log";
134 yTempFileName = "temperatureY.log";
135 zTempFileName = "temperatureZ.log";
136 xTempLog_.open(xTempFileName.c_str());
137 yTempLog_.open(yTempFileName.c_str());
138 zTempLog_.open(zTempFileName.c_str());
139 break;
140 case rnemdPz :
141 case rnemdPzScale :
142 case rnemdUnknown :
143 default :
144 rnemdFileName = "rnemd.log";
145 break;
146 }
147 rnemdLog_.open(rnemdFileName.c_str());
148
149 #ifdef IS_MPI
150 }
151 #endif
152
153 set_RNEMD_exchange_time(simParams->getRNEMD_exchangeTime());
154 set_RNEMD_nBins(simParams->getRNEMD_nBins());
155 midBin_ = nBins_ / 2;
156 if (simParams->haveRNEMD_logWidth()) {
157 rnemdLogWidth_ = simParams->getRNEMD_logWidth();
158 if (rnemdLogWidth_ != nBins_ && rnemdLogWidth_ != midBin_ + 1) {
159 std::cerr << "WARNING! RNEMD_logWidth has abnormal value!\n";
160 std::cerr << "Automaically set back to default.\n";
161 rnemdLogWidth_ = nBins_;
162 }
163 } else {
164 rnemdLogWidth_ = nBins_;
165 }
166 valueHist_.resize(rnemdLogWidth_, 0.0);
167 valueCount_.resize(rnemdLogWidth_, 0);
168 xTempHist_.resize(rnemdLogWidth_, 0.0);
169 yTempHist_.resize(rnemdLogWidth_, 0.0);
170 zTempHist_.resize(rnemdLogWidth_, 0.0);
171
172 set_RNEMD_exchange_total(0.0);
173 if (simParams->haveRNEMD_targetFlux()) {
174 set_RNEMD_target_flux(simParams->getRNEMD_targetFlux());
175 } else {
176 set_RNEMD_target_flux(0.0);
177 }
178
179 #ifndef IS_MPI
180 if (simParams->haveSeed()) {
181 seedValue = simParams->getSeed();
182 randNumGen_ = new SeqRandNumGen(seedValue);
183 }else {
184 randNumGen_ = new SeqRandNumGen();
185 }
186 #else
187 if (simParams->haveSeed()) {
188 seedValue = simParams->getSeed();
189 randNumGen_ = new ParallelRandNumGen(seedValue);
190 }else {
191 randNumGen_ = new ParallelRandNumGen();
192 }
193 #endif
194 }
195
196 RNEMD::~RNEMD() {
197 delete randNumGen_;
198
199 #ifdef IS_MPI
200 if (worldRank == 0) {
201 #endif
202 std::cerr << "total fail trials: " << failTrialCount_ << "\n";
203 rnemdLog_.close();
204 if (rnemdType_ == rnemdKineticScale || rnemdType_ == rnemdPxScale || rnemdType_ == rnemdPyScale)
205 std::cerr<< "total root-checking warnings: " << failRootCount_ << "\n";
206 if (rnemdType_ == rnemdPx || rnemdType_ == rnemdPxScale || rnemdType_ == rnemdPy || rnemdType_ == rnemdPyScale) {
207 xTempLog_.close();
208 yTempLog_.close();
209 zTempLog_.close();
210 }
211 #ifdef IS_MPI
212 }
213 #endif
214 }
215
216 void RNEMD::doSwap() {
217
218 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
219 Mat3x3d hmat = currentSnap_->getHmat();
220
221 seleMan_.setSelectionSet(evaluator_.evaluate());
222
223 int selei;
224 StuntDouble* sd;
225 int idx;
226
227 RealType min_val;
228 bool min_found = false;
229 StuntDouble* min_sd;
230
231 RealType max_val;
232 bool max_found = false;
233 StuntDouble* max_sd;
234
235 for (sd = seleMan_.beginSelected(selei); sd != NULL;
236 sd = seleMan_.nextSelected(selei)) {
237
238 idx = sd->getLocalIndex();
239
240 Vector3d pos = sd->getPos();
241
242 // wrap the stuntdouble's position back into the box:
243
244 if (usePeriodicBoundaryConditions_)
245 currentSnap_->wrapVector(pos);
246
247 // which bin is this stuntdouble in?
248 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
249
250 int binNo = int(nBins_ * (pos.z() / hmat(2,2) + 0.5)) % nBins_;
251
252
253 // if we're in bin 0 or the middleBin
254 if (binNo == 0 || binNo == midBin_) {
255
256 RealType mass = sd->getMass();
257 Vector3d vel = sd->getVel();
258 RealType value;
259
260 switch(rnemdType_) {
261 case rnemdKineticSwap :
262
263 value = mass * (vel[0]*vel[0] + vel[1]*vel[1] +
264 vel[2]*vel[2]);
265 if (sd->isDirectional()) {
266 Vector3d angMom = sd->getJ();
267 Mat3x3d I = sd->getI();
268
269 if (sd->isLinear()) {
270 int i = sd->linearAxis();
271 int j = (i + 1) % 3;
272 int k = (i + 2) % 3;
273 value += angMom[j] * angMom[j] / I(j, j) +
274 angMom[k] * angMom[k] / I(k, k);
275 } else {
276 value += angMom[0]*angMom[0]/I(0, 0)
277 + angMom[1]*angMom[1]/I(1, 1)
278 + angMom[2]*angMom[2]/I(2, 2);
279 }
280 }
281 //make exchangeSum_ comparable between swap & scale
282 //temporarily without using energyConvert
283 //value = value * 0.5 / PhysicalConstants::energyConvert;
284 value *= 0.5;
285 break;
286 case rnemdPx :
287 value = mass * vel[0];
288 break;
289 case rnemdPy :
290 value = mass * vel[1];
291 break;
292 case rnemdPz :
293 value = mass * vel[2];
294 break;
295 default :
296 break;
297 }
298
299 if (binNo == 0) {
300 if (!min_found) {
301 min_val = value;
302 min_sd = sd;
303 min_found = true;
304 } else {
305 if (min_val > value) {
306 min_val = value;
307 min_sd = sd;
308 }
309 }
310 } else { //midBin_
311 if (!max_found) {
312 max_val = value;
313 max_sd = sd;
314 max_found = true;
315 } else {
316 if (max_val < value) {
317 max_val = value;
318 max_sd = sd;
319 }
320 }
321 }
322 }
323 }
324
325 #ifdef IS_MPI
326 int nProc, worldRank;
327
328 nProc = MPI::COMM_WORLD.Get_size();
329 worldRank = MPI::COMM_WORLD.Get_rank();
330
331 bool my_min_found = min_found;
332 bool my_max_found = max_found;
333
334 // Even if we didn't find a minimum, did someone else?
335 MPI::COMM_WORLD.Allreduce(&my_min_found, &min_found,
336 1, MPI::BOOL, MPI::LAND);
337
338 // Even if we didn't find a maximum, did someone else?
339 MPI::COMM_WORLD.Allreduce(&my_max_found, &max_found,
340 1, MPI::BOOL, MPI::LAND);
341
342 struct {
343 RealType val;
344 int rank;
345 } max_vals, min_vals;
346
347 if (min_found) {
348 if (my_min_found)
349 min_vals.val = min_val;
350 else
351 min_vals.val = HONKING_LARGE_VALUE;
352
353 min_vals.rank = worldRank;
354
355 // Who had the minimum?
356 MPI::COMM_WORLD.Allreduce(&min_vals, &min_vals,
357 1, MPI::REALTYPE_INT, MPI::MINLOC);
358 min_val = min_vals.val;
359 }
360
361 if (max_found) {
362 if (my_max_found)
363 max_vals.val = max_val;
364 else
365 max_vals.val = -HONKING_LARGE_VALUE;
366
367 max_vals.rank = worldRank;
368
369 // Who had the maximum?
370 MPI::COMM_WORLD.Allreduce(&max_vals, &max_vals,
371 1, MPI::REALTYPE_INT, MPI::MAXLOC);
372 max_val = max_vals.val;
373 }
374 #endif
375
376 if (max_found && min_found) {
377 if (min_val< max_val) {
378
379 #ifdef IS_MPI
380 if (max_vals.rank == worldRank && min_vals.rank == worldRank) {
381 // I have both maximum and minimum, so proceed like a single
382 // processor version:
383 #endif
384 // objects to be swapped: velocity & angular velocity
385 Vector3d min_vel = min_sd->getVel();
386 Vector3d max_vel = max_sd->getVel();
387 RealType temp_vel;
388
389 switch(rnemdType_) {
390 case rnemdKineticSwap :
391 min_sd->setVel(max_vel);
392 max_sd->setVel(min_vel);
393 if (min_sd->isDirectional() && max_sd->isDirectional()) {
394 Vector3d min_angMom = min_sd->getJ();
395 Vector3d max_angMom = max_sd->getJ();
396 min_sd->setJ(max_angMom);
397 max_sd->setJ(min_angMom);
398 }
399 break;
400 case rnemdPx :
401 temp_vel = min_vel.x();
402 min_vel.x() = max_vel.x();
403 max_vel.x() = temp_vel;
404 min_sd->setVel(min_vel);
405 max_sd->setVel(max_vel);
406 break;
407 case rnemdPy :
408 temp_vel = min_vel.y();
409 min_vel.y() = max_vel.y();
410 max_vel.y() = temp_vel;
411 min_sd->setVel(min_vel);
412 max_sd->setVel(max_vel);
413 break;
414 case rnemdPz :
415 temp_vel = min_vel.z();
416 min_vel.z() = max_vel.z();
417 max_vel.z() = temp_vel;
418 min_sd->setVel(min_vel);
419 max_sd->setVel(max_vel);
420 break;
421 default :
422 break;
423 }
424 #ifdef IS_MPI
425 // the rest of the cases only apply in parallel simulations:
426 } else if (max_vals.rank == worldRank) {
427 // I had the max, but not the minimum
428
429 Vector3d min_vel;
430 Vector3d max_vel = max_sd->getVel();
431 MPI::Status status;
432
433 // point-to-point swap of the velocity vector
434 MPI::COMM_WORLD.Sendrecv(max_vel.getArrayPointer(), 3, MPI::REALTYPE,
435 min_vals.rank, 0,
436 min_vel.getArrayPointer(), 3, MPI::REALTYPE,
437 min_vals.rank, 0, status);
438
439 switch(rnemdType_) {
440 case rnemdKineticSwap :
441 max_sd->setVel(min_vel);
442
443 if (max_sd->isDirectional()) {
444 Vector3d min_angMom;
445 Vector3d max_angMom = max_sd->getJ();
446
447 // point-to-point swap of the angular momentum vector
448 MPI::COMM_WORLD.Sendrecv(max_angMom.getArrayPointer(), 3,
449 MPI::REALTYPE, min_vals.rank, 1,
450 min_angMom.getArrayPointer(), 3,
451 MPI::REALTYPE, min_vals.rank, 1,
452 status);
453
454 max_sd->setJ(min_angMom);
455 }
456 break;
457 case rnemdPx :
458 max_vel.x() = min_vel.x();
459 max_sd->setVel(max_vel);
460 break;
461 case rnemdPy :
462 max_vel.y() = min_vel.y();
463 max_sd->setVel(max_vel);
464 break;
465 case rnemdPz :
466 max_vel.z() = min_vel.z();
467 max_sd->setVel(max_vel);
468 break;
469 default :
470 break;
471 }
472 } else if (min_vals.rank == worldRank) {
473 // I had the minimum but not the maximum:
474
475 Vector3d max_vel;
476 Vector3d min_vel = min_sd->getVel();
477 MPI::Status status;
478
479 // point-to-point swap of the velocity vector
480 MPI::COMM_WORLD.Sendrecv(min_vel.getArrayPointer(), 3, MPI::REALTYPE,
481 max_vals.rank, 0,
482 max_vel.getArrayPointer(), 3, MPI::REALTYPE,
483 max_vals.rank, 0, status);
484
485 switch(rnemdType_) {
486 case rnemdKineticSwap :
487 min_sd->setVel(max_vel);
488
489 if (min_sd->isDirectional()) {
490 Vector3d min_angMom = min_sd->getJ();
491 Vector3d max_angMom;
492
493 // point-to-point swap of the angular momentum vector
494 MPI::COMM_WORLD.Sendrecv(min_angMom.getArrayPointer(), 3,
495 MPI::REALTYPE, max_vals.rank, 1,
496 max_angMom.getArrayPointer(), 3,
497 MPI::REALTYPE, max_vals.rank, 1,
498 status);
499
500 min_sd->setJ(max_angMom);
501 }
502 break;
503 case rnemdPx :
504 min_vel.x() = max_vel.x();
505 min_sd->setVel(min_vel);
506 break;
507 case rnemdPy :
508 min_vel.y() = max_vel.y();
509 min_sd->setVel(min_vel);
510 break;
511 case rnemdPz :
512 min_vel.z() = max_vel.z();
513 min_sd->setVel(min_vel);
514 break;
515 default :
516 break;
517 }
518 }
519 #endif
520 exchangeSum_ += max_val - min_val;
521 } else {
522 std::cerr << "exchange NOT performed!\nmin_val > max_val.\n";
523 failTrialCount_++;
524 }
525 } else {
526 std::cerr << "exchange NOT performed!\n";
527 std::cerr << "at least one of the two slabs empty.\n";
528 failTrialCount_++;
529 }
530
531 }
532
533 void RNEMD::doScale() {
534
535 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
536 Mat3x3d hmat = currentSnap_->getHmat();
537
538 seleMan_.setSelectionSet(evaluator_.evaluate());
539
540 int selei;
541 StuntDouble* sd;
542 int idx;
543
544 std::vector<StuntDouble*> hotBin, coldBin;
545
546 RealType Phx = 0.0;
547 RealType Phy = 0.0;
548 RealType Phz = 0.0;
549 RealType Khx = 0.0;
550 RealType Khy = 0.0;
551 RealType Khz = 0.0;
552 RealType Pcx = 0.0;
553 RealType Pcy = 0.0;
554 RealType Pcz = 0.0;
555 RealType Kcx = 0.0;
556 RealType Kcy = 0.0;
557 RealType Kcz = 0.0;
558
559 for (sd = seleMan_.beginSelected(selei); sd != NULL;
560 sd = seleMan_.nextSelected(selei)) {
561
562 idx = sd->getLocalIndex();
563
564 Vector3d pos = sd->getPos();
565
566 // wrap the stuntdouble's position back into the box:
567
568 if (usePeriodicBoundaryConditions_)
569 currentSnap_->wrapVector(pos);
570
571 // which bin is this stuntdouble in?
572 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
573
574 int binNo = int(nBins_ * (pos.z() / hmat(2,2) + 0.5)) % nBins_;
575
576 // if we're in bin 0 or the middleBin
577 if (binNo == 0 || binNo == midBin_) {
578
579 RealType mass = sd->getMass();
580 Vector3d vel = sd->getVel();
581
582 if (binNo == 0) {
583 hotBin.push_back(sd);
584 Phx += mass * vel.x();
585 Phy += mass * vel.y();
586 Phz += mass * vel.z();
587 Khx += mass * vel.x() * vel.x();
588 Khy += mass * vel.y() * vel.y();
589 Khz += mass * vel.z() * vel.z();
590 } else { //midBin_
591 coldBin.push_back(sd);
592 Pcx += mass * vel.x();
593 Pcy += mass * vel.y();
594 Pcz += mass * vel.z();
595 Kcx += mass * vel.x() * vel.x();
596 Kcy += mass * vel.y() * vel.y();
597 Kcz += mass * vel.z() * vel.z();
598 }
599 }
600 }
601
602 Khx *= 0.5;
603 Khy *= 0.5;
604 Khz *= 0.5;
605 Kcx *= 0.5;
606 Kcy *= 0.5;
607 Kcz *= 0.5;
608
609 #ifdef IS_MPI
610 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phx, 1, MPI::REALTYPE, MPI::SUM);
611 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phy, 1, MPI::REALTYPE, MPI::SUM);
612 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Phz, 1, MPI::REALTYPE, MPI::SUM);
613 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcx, 1, MPI::REALTYPE, MPI::SUM);
614 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcy, 1, MPI::REALTYPE, MPI::SUM);
615 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Pcz, 1, MPI::REALTYPE, MPI::SUM);
616
617 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khx, 1, MPI::REALTYPE, MPI::SUM);
618 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khy, 1, MPI::REALTYPE, MPI::SUM);
619 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Khz, 1, MPI::REALTYPE, MPI::SUM);
620 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcx, 1, MPI::REALTYPE, MPI::SUM);
621 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcy, 1, MPI::REALTYPE, MPI::SUM);
622 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &Kcz, 1, MPI::REALTYPE, MPI::SUM);
623 #endif
624
625 //use coldBin coeff's
626 RealType px = Pcx / Phx;
627 RealType py = Pcy / Phy;
628 RealType pz = Pcz / Phz;
629
630 RealType a000, a110, c0, a001, a111, b01, b11, c1, c;
631 switch(rnemdType_) {
632 case rnemdKineticScale :
633 /*used hotBin coeff's & only scale x & y dimensions
634 RealType px = Phx / Pcx;
635 RealType py = Phy / Pcy;
636 a110 = Khy;
637 c0 = - Khx - Khy - targetFlux_;
638 a000 = Khx;
639 a111 = Kcy * py * py
640 b11 = -2.0 * Kcy * py * (1.0 + py);
641 c1 = Kcy * py * (2.0 + py) + Kcx * px * ( 2.0 + px) + targetFlux_;
642 b01 = -2.0 * Kcx * px * (1.0 + px);
643 a001 = Kcx * px * px;
644 */
645
646 //scale all three dimensions, let c_x = c_y
647 a000 = Kcx + Kcy;
648 a110 = Kcz;
649 c0 = targetFlux_ - Kcx - Kcy - Kcz;
650 a001 = Khx * px * px + Khy * py * py;
651 a111 = Khz * pz * pz;
652 b01 = -2.0 * (Khx * px * (1.0 + px) + Khy * py * (1.0 + py));
653 b11 = -2.0 * Khz * pz * (1.0 + pz);
654 c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
655 + Khz * pz * (2.0 + pz) - targetFlux_;
656 break;
657 case rnemdPxScale :
658 c = 1 - targetFlux_ / Pcx;
659 a000 = Kcy;
660 a110 = Kcz;
661 c0 = Kcx * c * c - Kcx - Kcy - Kcz;
662 a001 = py * py * Khy;
663 a111 = pz * pz * Khz;
664 b01 = -2.0 * Khy * py * (1.0 + py);
665 b11 = -2.0 * Khz * pz * (1.0 + pz);
666 c1 = Khy * py * (2.0 + py) + Khz * pz * (2.0 + pz)
667 + Khx * (fastpow(c * px - px - 1.0, 2) - 1.0);
668 break;
669 case rnemdPyScale :
670 c = 1 - targetFlux_ / Pcy;
671 a000 = Kcx;
672 a110 = Kcz;
673 c0 = Kcy * c * c - Kcx - Kcy - Kcz;
674 a001 = px * px * Khx;
675 a111 = pz * pz * Khz;
676 b01 = -2.0 * Khx * px * (1.0 + px);
677 b11 = -2.0 * Khz * pz * (1.0 + pz);
678 c1 = Khx * px * (2.0 + px) + Khz * pz * (2.0 + pz)
679 + Khy * (fastpow(c * py - py - 1.0, 2) - 1.0);
680 break;
681 case rnemdPzScale ://we don't really do this, do we?
682 c = 1 - targetFlux_ / Pcz;
683 a000 = Kcx;
684 a110 = Kcy;
685 c0 = Kcz * c * c - Kcx - Kcy - Kcz;
686 a001 = px * px * Khx;
687 a111 = py * py * Khy;
688 b01 = -2.0 * Khx * px * (1.0 + px);
689 b11 = -2.0 * Khy * py * (1.0 + py);
690 c1 = Khx * px * (2.0 + px) + Khy * py * (2.0 + py)
691 + Khz * (fastpow(c * pz - pz - 1.0, 2) - 1.0);
692 break;
693 default :
694 break;
695 }
696
697 RealType v1 = a000 * a111 - a001 * a110;
698 RealType v2 = a000 * b01;
699 RealType v3 = a000 * b11;
700 RealType v4 = a000 * c1 - a001 * c0;
701 RealType v8 = a110 * b01;
702 RealType v10 = - b01 * c0;
703
704 RealType u0 = v2 * v10 - v4 * v4;
705 RealType u1 = -2.0 * v3 * v4;
706 RealType u2 = -v2 * v8 - v3 * v3 - 2.0 * v1 * v4;
707 RealType u3 = -2.0 * v1 * v3;
708 RealType u4 = - v1 * v1;
709 //rescale coefficients
710 RealType maxAbs = fabs(u0);
711 if (maxAbs < fabs(u1)) maxAbs = fabs(u1);
712 if (maxAbs < fabs(u2)) maxAbs = fabs(u2);
713 if (maxAbs < fabs(u3)) maxAbs = fabs(u3);
714 if (maxAbs < fabs(u4)) maxAbs = fabs(u4);
715 u0 /= maxAbs;
716 u1 /= maxAbs;
717 u2 /= maxAbs;
718 u3 /= maxAbs;
719 u4 /= maxAbs;
720 //max_element(start, end) is also available.
721 Polynomial<RealType> poly; //same as DoublePolynomial poly;
722 poly.setCoefficient(4, u4);
723 poly.setCoefficient(3, u3);
724 poly.setCoefficient(2, u2);
725 poly.setCoefficient(1, u1);
726 poly.setCoefficient(0, u0);
727 std::vector<RealType> realRoots = poly.FindRealRoots();
728
729 std::vector<RealType>::iterator ri;
730 RealType r1, r2, alpha0;
731 std::vector<std::pair<RealType,RealType> > rps;
732 for (ri = realRoots.begin(); ri !=realRoots.end(); ri++) {
733 r2 = *ri;
734 //check if FindRealRoots() give the right answer
735 if ( fabs(u0 + r2 * (u1 + r2 * (u2 + r2 * (u3 + r2 * u4)))) > 1e-6 ) {
736 sprintf(painCave.errMsg,
737 "RNEMD Warning: polynomial solve seems to have an error!");
738 painCave.isFatal = 0;
739 simError();
740 failRootCount_++;
741 }
742 //might not be useful w/o rescaling coefficients
743 alpha0 = -c0 - a110 * r2 * r2;
744 if (alpha0 >= 0.0) {
745 r1 = sqrt(alpha0 / a000);
746 if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111)) < 1e-6)
747 { rps.push_back(std::make_pair(r1, r2)); }
748 if (r1 > 1e-6) { //r1 non-negative
749 r1 = -r1;
750 if (fabs(c1 + r1 * (b01 + r1 * a001) + r2 * (b11 + r2 * a111)) <1e-6)
751 { rps.push_back(std::make_pair(r1, r2)); }
752 }
753 }
754 }
755 // Consider combininig together the solving pair part w/ the searching
756 // best solution part so that we don't need the pairs vector
757 if (!rps.empty()) {
758 RealType smallestDiff = HONKING_LARGE_VALUE;
759 RealType diff;
760 std::pair<RealType,RealType> bestPair = std::make_pair(1.0, 1.0);
761 std::vector<std::pair<RealType,RealType> >::iterator rpi;
762 for (rpi = rps.begin(); rpi != rps.end(); rpi++) {
763 r1 = (*rpi).first;
764 r2 = (*rpi).second;
765 switch(rnemdType_) {
766 case rnemdKineticScale :
767 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
768 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2)
769 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
770 break;
771 case rnemdPxScale :
772 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
773 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcy, 2);
774 break;
775 case rnemdPyScale :
776 diff = fastpow(1.0 - r1, 2) + fastpow(1.0 - r2, 2)
777 + fastpow(r1 * r1 / r2 / r2 - Kcz/Kcx, 2);
778 break;
779 case rnemdPzScale :
780 default :
781 break;
782 }
783 if (diff < smallestDiff) {
784 smallestDiff = diff;
785 bestPair = *rpi;
786 }
787 }
788 #ifdef IS_MPI
789 if (worldRank == 0) {
790 #endif
791 std::cerr << "we choose r1 = " << bestPair.first
792 << " and r2 = " << bestPair.second << "\n";
793 #ifdef IS_MPI
794 }
795 #endif
796
797 RealType x, y, z;
798 switch(rnemdType_) {
799 case rnemdKineticScale :
800 x = bestPair.first;
801 y = bestPair.first;
802 z = bestPair.second;
803 break;
804 case rnemdPxScale :
805 x = c;
806 y = bestPair.first;
807 z = bestPair.second;
808 break;
809 case rnemdPyScale :
810 x = bestPair.first;
811 y = c;
812 z = bestPair.second;
813 break;
814 case rnemdPzScale :
815 x = bestPair.first;
816 y = bestPair.second;
817 z = c;
818 break;
819 default :
820 break;
821 }
822 std::vector<StuntDouble*>::iterator sdi;
823 Vector3d vel;
824 for (sdi = coldBin.begin(); sdi != coldBin.end(); sdi++) {
825 vel = (*sdi)->getVel();
826 vel.x() *= x;
827 vel.y() *= y;
828 vel.z() *= z;
829 (*sdi)->setVel(vel);
830 }
831 //convert to hotBin coefficient
832 x = 1.0 + px * (1.0 - x);
833 y = 1.0 + py * (1.0 - y);
834 z = 1.0 + pz * (1.0 - z);
835 for (sdi = hotBin.begin(); sdi != hotBin.end(); sdi++) {
836 vel = (*sdi)->getVel();
837 vel.x() *= x;
838 vel.y() *= y;
839 vel.z() *= z;
840 (*sdi)->setVel(vel);
841 }
842 exchangeSum_ += targetFlux_;
843 //we may want to check whether the exchange has been successful
844 } else {
845 std::cerr << "exchange NOT performed!\n";//MPI incompatible
846 failTrialCount_++;
847 }
848
849 }
850
851 void RNEMD::doRNEMD() {
852
853 switch(rnemdType_) {
854 case rnemdKineticScale :
855 case rnemdPxScale :
856 case rnemdPyScale :
857 case rnemdPzScale :
858 doScale();
859 break;
860 case rnemdKineticSwap :
861 case rnemdPx :
862 case rnemdPy :
863 case rnemdPz :
864 doSwap();
865 break;
866 case rnemdUnknown :
867 default :
868 break;
869 }
870 }
871
872 void RNEMD::collectData() {
873
874 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
875 Mat3x3d hmat = currentSnap_->getHmat();
876
877 seleMan_.setSelectionSet(evaluator_.evaluate());
878
879 int selei;
880 StuntDouble* sd;
881 int idx;
882
883 for (sd = seleMan_.beginSelected(selei); sd != NULL;
884 sd = seleMan_.nextSelected(selei)) {
885
886 idx = sd->getLocalIndex();
887
888 Vector3d pos = sd->getPos();
889
890 // wrap the stuntdouble's position back into the box:
891
892 if (usePeriodicBoundaryConditions_)
893 currentSnap_->wrapVector(pos);
894
895 // which bin is this stuntdouble in?
896 // wrapped positions are in the range [-0.5*hmat(2,2), +0.5*hmat(2,2)]
897
898 int binNo = int(nBins_ * (pos.z() / hmat(2,2) + 0.5)) % nBins_;
899
900 if (rnemdLogWidth_ == midBin_ + 1)
901 if (binNo > midBin_)
902 binNo = nBins_ - binNo;
903
904 RealType mass = sd->getMass();
905 Vector3d vel = sd->getVel();
906 RealType value;
907 RealType xVal, yVal, zVal;
908
909 switch(rnemdType_) {
910 case rnemdKineticSwap :
911 case rnemdKineticScale :
912
913 value = mass * (vel[0]*vel[0] + vel[1]*vel[1] +
914 vel[2]*vel[2]);
915
916 valueCount_[binNo] += 3;
917 if (sd->isDirectional()) {
918 Vector3d angMom = sd->getJ();
919 Mat3x3d I = sd->getI();
920
921 if (sd->isLinear()) {
922 int i = sd->linearAxis();
923 int j = (i + 1) % 3;
924 int k = (i + 2) % 3;
925 value += angMom[j] * angMom[j] / I(j, j) +
926 angMom[k] * angMom[k] / I(k, k);
927
928 valueCount_[binNo] +=2;
929
930 } else {
931 value += angMom[0]*angMom[0]/I(0, 0)
932 + angMom[1]*angMom[1]/I(1, 1)
933 + angMom[2]*angMom[2]/I(2, 2);
934 valueCount_[binNo] +=3;
935 }
936 }
937 value = value / PhysicalConstants::energyConvert / PhysicalConstants::kb;
938
939 break;
940 case rnemdPx :
941 case rnemdPxScale :
942 value = mass * vel[0];
943 valueCount_[binNo]++;
944 xVal = mass * vel.x() * vel.x() / PhysicalConstants::energyConvert
945 / PhysicalConstants::kb;
946 yVal = mass * vel.y() * vel.y() / PhysicalConstants::energyConvert
947 / PhysicalConstants::kb;
948 zVal = mass * vel.z() * vel.z() / PhysicalConstants::energyConvert
949 / PhysicalConstants::kb;
950 xTempHist_[binNo] += xVal;
951 yTempHist_[binNo] += yVal;
952 zTempHist_[binNo] += zVal;
953 break;
954 case rnemdPy :
955 case rnemdPyScale :
956 value = mass * vel[1];
957 valueCount_[binNo]++;
958 break;
959 case rnemdPz :
960 case rnemdPzScale :
961 value = mass * vel[2];
962 valueCount_[binNo]++;
963 break;
964 case rnemdUnknown :
965 default :
966 break;
967 }
968 valueHist_[binNo] += value;
969 }
970
971 }
972
973 void RNEMD::getStarted() {
974 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
975 Stats& stat = currentSnap_->statData;
976 stat[Stats::RNEMD_EXCHANGE_TOTAL] = exchangeSum_;
977 }
978
979 void RNEMD::getStatus() {
980
981 Snapshot* currentSnap_ = info_->getSnapshotManager()->getCurrentSnapshot();
982 Stats& stat = currentSnap_->statData;
983 RealType time = currentSnap_->getTime();
984
985 stat[Stats::RNEMD_EXCHANGE_TOTAL] = exchangeSum_;
986 //or to be more meaningful, define another item as exchangeSum_ / time
987 int j;
988
989 #ifdef IS_MPI
990
991 // all processors have the same number of bins, and STL vectors pack their
992 // arrays, so in theory, this should be safe:
993
994 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &valueHist_[0],
995 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
996 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &valueCount_[0],
997 rnemdLogWidth_, MPI::INT, MPI::SUM);
998 if (rnemdType_ == rnemdPx || rnemdType_ == rnemdPxScale) {
999 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &xTempHist_[0],
1000 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1001 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &yTempHist_[0],
1002 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1003 MPI::COMM_WORLD.Allreduce(MPI::IN_PLACE, &zTempHist_[0],
1004 rnemdLogWidth_, MPI::REALTYPE, MPI::SUM);
1005 }
1006 // If we're the root node, should we print out the results
1007 int worldRank = MPI::COMM_WORLD.Get_rank();
1008 if (worldRank == 0) {
1009 #endif
1010 rnemdLog_ << time;
1011 for (j = 0; j < rnemdLogWidth_; j++) {
1012 rnemdLog_ << "\t" << valueHist_[j] / (RealType)valueCount_[j];
1013 }
1014 rnemdLog_ << "\n";
1015 if (rnemdType_ == rnemdPx || rnemdType_ == rnemdPxScale ) {
1016 xTempLog_ << time;
1017 for (j = 0; j < rnemdLogWidth_; j++) {
1018 xTempLog_ << "\t" << xTempHist_[j] / (RealType)valueCount_[j];
1019 }
1020 xTempLog_ << "\n";
1021 yTempLog_ << time;
1022 for (j = 0; j < rnemdLogWidth_; j++) {
1023 yTempLog_ << "\t" << yTempHist_[j] / (RealType)valueCount_[j];
1024 }
1025 yTempLog_ << "\n";
1026 zTempLog_ << time;
1027 for (j = 0; j < rnemdLogWidth_; j++) {
1028 zTempLog_ << "\t" << zTempHist_[j] / (RealType)valueCount_[j];
1029 }
1030 zTempLog_ << "\n";
1031 }
1032 #ifdef IS_MPI
1033 }
1034 #endif
1035 for (j = 0; j < rnemdLogWidth_; j++) {
1036 valueCount_[j] = 0;
1037 valueHist_[j] = 0.0;
1038 }
1039 if (rnemdType_ == rnemdPx || rnemdType_ == rnemdPxScale)
1040 for (j = 0; j < rnemdLogWidth_; j++) {
1041 xTempHist_[j] = 0.0;
1042 yTempHist_[j] = 0.0;
1043 zTempHist_[j] = 0.0;
1044 }
1045 }
1046 }

Properties

Name Value
svn:keywords Author Id Revision Date