ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/OpenMD/branches/development/src/rnemd/RNEMD.cpp
(Generate patch)

Comparing branches/development/src/integrators/RNEMD.cpp (file contents):
Revision 1627 by gezelter, Tue Sep 13 22:05:04 2011 UTC vs.
Revision 1723 by gezelter, Thu May 24 20:59:54 2012 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines