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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines