• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

QCAD_SaddleValueResponseFunction.cpp

Go to the documentation of this file.
00001 //*****************************************************************//
00002 //    Albany 2.0:  Copyright 2012 Sandia Corporation               //
00003 //    This Software is released under the BSD license detailed     //
00004 //    in the file "license.txt" in the top-level Albany directory  //
00005 //*****************************************************************//
00006 #include <Teuchos_Array.hpp>
00007 #include <Epetra_LocalMap.h>
00008 #include "Albany_Utils.hpp"
00009 #include "QCAD_SaddleValueResponseFunction.hpp"
00010 #include "QCAD_GreensFunctionTunneling.hpp"
00011 #include <fstream>
00012 
00014 namespace QCAD 
00015 {
00016   bool ptInPolygon(const std::vector<QCAD::mathVector>& polygon, const QCAD::mathVector& pt);
00017   bool ptInPolygon(const std::vector<QCAD::mathVector>& polygon, const double* pt);
00018 
00019   void gatherVector(std::vector<double>& v, std::vector<double>& gv,
00020         const Epetra_Comm& comm_);
00021   void getOrdering(const std::vector<double>& v, std::vector<int>& ordering);
00022   bool lessOp(std::pair<std::size_t, double> const& a,
00023         std::pair<std::size_t, double> const& b);
00024   double averageOfVector(const std::vector<double>& v);
00025   double distance(const std::vector<double>* vCoords, int ind1, int ind2, std::size_t nDims);
00026 }
00027 
00028 QCAD::SaddleValueResponseFunction::
00029 SaddleValueResponseFunction(
00030   const Teuchos::RCP<Albany::Application>& application,
00031   const Teuchos::RCP<Albany::AbstractProblem>& problem,
00032   const Teuchos::RCP<Albany::MeshSpecsStruct>&  ms,
00033   const Teuchos::RCP<Albany::StateManager>& stateMgr,
00034   Teuchos::ParameterList& params) : 
00035   Albany::FieldManagerScalarResponseFunction(application, problem, ms, stateMgr),
00036   numDims(problem->spatialDimension()),
00037   comm(application->getComm() )
00038 {
00039   TEUCHOS_TEST_FOR_EXCEPTION (numDims < 2 || numDims > 3, Teuchos::Exceptions::InvalidParameter, std::endl 
00040         << "Saddle Point not implemented for " << numDims << " dimensions." << std::endl); 
00041 
00042   params.set("Response Function", Teuchos::rcp(this,false));
00043 
00044   Teuchos::Array<double> ar;
00045 
00046   imagePtSize   = params.get<double>("Image Point Size", 0.01);
00047   nImagePts     = params.get<int>("Number of Image Points", 10);
00048   maxTimeStep   = params.get<double>("Max Time Step", 1.0);
00049   minTimeStep   = params.get<double>("Min Time Step", 0.002);
00050   maxIterations = params.get<int>("Maximum Iterations", 100);
00051   backtraceAfterIters = params.get<int>("Backtrace After Iteration", 10000000);
00052   convergeTolerance   = params.get<double>("Convergence Tolerance", 1e-5);
00053   minSpringConstant   = params.get<double>("Min Spring Constant", 1.0);
00054   maxSpringConstant   = params.get<double>("Max Spring Constant", 1.0);
00055   outputFilename = params.get<std::string>("Output Filename", "");
00056   debugFilename  = params.get<std::string>("Debug Filename", "");
00057   appendOutput   = params.get<bool>("Append Output", false);
00058   nEvery         = params.get<int>("Output Interval", 0);
00059   bClimbing      = params.get<bool>("Climbing NEB", true);
00060   antiKinkFactor = params.get<double>("Anti-Kink Factor", 0.0);
00061   bAggregateWorksets = params.get<bool>("Aggregate Worksets", false);
00062   bAdaptivePointSize = params.get<bool>("Adaptive Image Point Size", false);
00063   minAdaptivePointWt = params.get<double>("Adaptive Min Point Weight", 5);
00064   maxAdaptivePointWt = params.get<double>("Adaptive Max Point Weight", 10);
00065   shortenBeginPc = params.get<double>("Percent to Shorten Begin", 0);
00066   shortenEndPc   = params.get<double>("Percent to Shorten End", 0);
00067 
00068   fieldCutoffFctr = params.get<double>("Levelset Field Cutoff Factor", 1.0);
00069   minPoolDepthFctr = params.get<double>("Levelset Minimum Pool Depth Factor", 1.0);
00070   distanceCutoffFctr = params.get<double>("Levelset Distance Cutoff Factor", 1.0);
00071   levelSetRadius = params.get<double>("Levelset Radius", 0);
00072 
00073   // set default maxFinalPts to nImagePts
00074   maxFinalPts = params.get<int>("Maximum Number of Final Points", nImagePts);
00075   gfGridSpacing  = params.get<double>("GF-CBR Method Grid Spacing", 0.0005);
00076   fieldScaling = params.get<double>("Field Scaling Factor", 1.0);
00077   
00078   // set Vds information
00079   bSweepVds = params.get<bool>("GF-CBR Method Vds Sweep", false);
00080   initVds = params.get<double>("GF-CBR Method Vds Initial Value", 0.0);
00081   finalVds = params.get<double>("GF-CBR Method Vds Final Value", 0.0);
00082   stepsVds = params.get<int>("GF-CBR Method Vds Steps", 0);
00083 
00084   // specify the eigensolver to be used for the GF-CBR calculation
00085   gfEigensolver = params.get<std::string>("GF-CBR Method Eigensolver", "tql2");
00086   std::cout << "gfEigensolver = " << gfEigensolver << std::endl; 
00087   
00088   bGetCurrent = (params.get<std::string>("Return Field Name", "") == "current");
00089   
00090   // set default value to 0.5 eV (always want a positive value)
00091   current_Ecutoff_offset_from_Emax = params.get<double>("GF-CBR Method Energy Cutoff Offset", 0.5);
00092 
00093   if(backtraceAfterIters < 0) backtraceAfterIters = 10000000;
00094   else if(backtraceAfterIters <= 1) backtraceAfterIters = 2; // can't backtrace until the second iteration
00095 
00096   bLockToPlane = false;
00097   if(params.isParameter("Lock to z-coord")) {
00098     bLockToPlane = true;
00099     lockedZ = params.get<double>("Lock to z-coord");
00100   }
00101 
00102   iSaddlePt = -1;        //clear "found" saddle point index
00103   returnFieldVal = -1.0; //init to nonzero is important - so doesn't "match" default init
00104 
00105   //Beginning target region
00106   if(params.isParameter("Begin Point")) {
00107     beginRegionType = "Point";
00108     ar = params.get<Teuchos::Array<double> >("Begin Point");
00109     TEUCHOS_TEST_FOR_EXCEPTION (ar.size() != (int)numDims, Teuchos::Exceptions::InvalidParameter, std::endl 
00110         << "Begin Point does not have " << numDims << " elements" << std::endl); 
00111     beginPolygon.resize(1); beginPolygon[0].resize(numDims);
00112     for(std::size_t i=0; i<numDims; i++) beginPolygon[0][i] = ar[i];
00113   }
00114   else if(params.isParameter("Begin Element Block")) {
00115     beginRegionType = "Element Block";
00116     beginElementBlock = params.get<std::string>("Begin Element Block");
00117   }
00118   else if(params.isSublist("Begin Polygon")) {
00119     beginRegionType = "Polygon";
00120 
00121     Teuchos::ParameterList& polyList = params.sublist("Begin Polygon");
00122     int nPts = polyList.get<int>("Number of Points");
00123     beginPolygon.resize(nPts); 
00124 
00125     for(int i=0; i<nPts; i++) {
00126       beginPolygon[i].resize(numDims);
00127       ar = polyList.get<Teuchos::Array<double> >( Albany::strint("Point",i) );
00128       TEUCHOS_TEST_FOR_EXCEPTION (ar.size() != (int)numDims, Teuchos::Exceptions::InvalidParameter, std::endl 
00129           << "Begin polygon point does not have " << numDims << " elements" << std::endl); 
00130       for(std::size_t k=0; k<numDims; k++) beginPolygon[i][k] = ar[k];
00131     }
00132   }
00133   else TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl 
00134           << "No beginning region specified for saddle pt" << std::endl); 
00135 
00136   
00137 
00138   //Ending target region
00139   if(params.isParameter("End Point")) {
00140     endRegionType = "Point";
00141     ar = params.get<Teuchos::Array<double> >("End Point");
00142     TEUCHOS_TEST_FOR_EXCEPTION (ar.size() != (int)numDims, Teuchos::Exceptions::InvalidParameter, std::endl 
00143         << "End Point does not have " << numDims << " elements" << std::endl); 
00144     endPolygon.resize(1); endPolygon[0].resize(numDims);
00145     for(std::size_t i=0; i<numDims; i++) endPolygon[0][i] = ar[i];
00146   }
00147   else if(params.isParameter("End Element Block")) {
00148     endRegionType = "Element Block";
00149     endElementBlock = params.get<std::string>("End Element Block");
00150   }
00151   else if(params.isSublist("End Polygon")) {
00152     endRegionType = "Polygon";
00153     
00154     Teuchos::ParameterList& polyList = params.sublist("End Polygon");
00155     int nPts = polyList.get<int>("Number of Points");
00156     endPolygon.resize(nPts); 
00157     
00158     for(int i=0; i<nPts; i++) {
00159       endPolygon[i].resize(numDims);
00160       ar = polyList.get<Teuchos::Array<double> >( Albany::strint("Point",i) );
00161       TEUCHOS_TEST_FOR_EXCEPTION (ar.size() != (int)numDims, Teuchos::Exceptions::InvalidParameter, std::endl 
00162           << "End polygon point does not have " << numDims << " elements" << std::endl); 
00163       for(std::size_t k=0; k<numDims; k++) endPolygon[i][k] = ar[k];
00164     }
00165   }
00166   else TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl 
00167           << "No ending region specified for saddle pt" << std::endl); 
00168   
00169 
00170   //Guess at the saddle point
00171   saddleGuessGiven = false;
00172   if(params.isParameter("Saddle Point Guess")) {
00173     saddleGuessGiven = true;
00174     ar = params.get<Teuchos::Array<double> >("Saddle Point Guess");
00175     TEUCHOS_TEST_FOR_EXCEPTION (ar.size() != (int)numDims, Teuchos::Exceptions::InvalidParameter, std::endl 
00176         << "Saddle point guess does not have " << numDims << " elements" << std::endl); 
00177     saddlePointGuess.resize(numDims);
00178     for(std::size_t i=0; i<numDims; i++) saddlePointGuess[i] = ar[i];
00179   }
00180 
00181   debugMode = params.get<int>("Debug Mode",0);
00182 
00183   imagePts.resize(nImagePts);
00184   imagePtValues.resize(nImagePts);
00185   imagePtWeights.resize(nImagePts);
00186   imagePtGradComps.resize(nImagePts*numDims);
00187 
00188   // Add allowed z-range if in 3D (lateral volume assumed)
00189   //  - rest (xmin, etc) computed dynamically
00190   if(numDims > 2) {
00191     zmin = params.get<double>("z min");
00192     zmax = params.get<double>("z max");
00193   }  
00194 
00195   this->setup(params);
00196   this->num_responses = 5;
00197 }
00198 
00199 QCAD::SaddleValueResponseFunction::
00200 ~SaddleValueResponseFunction()
00201 {
00202 }
00203 
00204 unsigned int
00205 QCAD::SaddleValueResponseFunction::
00206 numResponses() const 
00207 {
00208   return this->num_responses;  // returnFieldValue, fieldValue, saddleX, saddleY, saddleZ
00209 }
00210 
00211 void
00212 QCAD::SaddleValueResponseFunction::
00213 evaluateResponse(const double current_time,
00214          const Epetra_Vector* xdot,
00215          const Epetra_Vector* xdotdot,
00216          const Epetra_Vector& x,
00217          const Teuchos::Array<ParamVec>& p,
00218          Epetra_Vector& g)
00219 {
00220   int dbMode = (comm->MyPID() == 0) ? debugMode : 0;
00221   if(comm->MyPID() != 0) outputFilename = ""; //Only root process outputs to files
00222   if(comm->MyPID() != 0) debugFilename = ""; //Only root process outputs to files
00223   
00224   TEUCHOS_TEST_FOR_EXCEPTION (nImagePts < 2, Teuchos::Exceptions::InvalidParameter, std::endl 
00225         << "Saddle Point needs more than 2 image pts (" << nImagePts << " given)" << std::endl); 
00226 
00227   // Clear output file if we're not told to append output
00228   if( outputFilename.length() > 0) {
00229     std::fstream out;
00230     if(appendOutput) {
00231       out.open(outputFilename.c_str(), std::fstream::out | std::fstream::app);
00232       out << std::endl << "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%" << std::endl; // to separate new data
00233     }
00234     else out.open(outputFilename.c_str(), std::fstream::out);
00235     out.close();
00236   }
00237 
00238   // Find saddle point in stages:
00239  
00240   //  1) Initialize image points
00241   initializeImagePoints(current_time, xdot, x, p, g, dbMode);
00242   
00243   if(maxIterations > 0) {
00244     //  2) Perform Nudged Elastic Band (NEB) algorithm on image points (iterative)
00245     doNudgedElasticBand(current_time, xdot, x, p, g, dbMode);
00246   }
00247   else {
00248     // If no NEB iteractions, choose center image point as saddle point
00249     int nFirstLeg = (nImagePts+1)/2, iCenter = nFirstLeg-1;
00250     iSaddlePt = iCenter; //don't need to check for positive weight at this point
00251   }
00252 
00253   //  3) Perform level-set method in a radius around saddle image point
00254   doLevelSet(current_time, xdot, x, p, g, dbMode);
00255 
00256   //  4) Get data at "final points" which can be more dense than neb image points, if desired
00257   if(maxIterations > 0 && maxFinalPts > 0) {
00258     initializeFinalImagePoints(current_time, xdot, x, p, g, dbMode);
00259     getFinalImagePointValues(current_time, xdot, x, p, g, dbMode);
00260 
00261     // append "final point" data to output
00262     if( outputFilename.length() > 0) {
00263       std::fstream out; double pathLength = 0.0;
00264       out.open(outputFilename.c_str(), std::fstream::out | std::fstream::app);
00265       out << std::endl << std::endl << "% Saddle point path - interpolated 'final' points" << std::endl;
00266       out << "% index xCoord yCoord value pathLength pointRadius" << std::endl;
00267       for(std::size_t i=0; i<finalPts.size(); i++) {
00268   out << i << " " << finalPts[i].coords[0] << " " << finalPts[i].coords[1] 
00269       << " " << finalPts[i].value << " " << pathLength << " " << finalPts[i].radius << std::endl;
00270   if(i < (finalPts.size()-1)) pathLength += finalPts[i].coords.distanceTo(finalPts[i+1].coords);
00271       }
00272       out.close();
00273     }
00274   }
00275 
00276   //  5) Fill response (g-vector) with values near the highest image point (computes current if desired)
00277   fillSaddlePointData(current_time, xdot, x, p, g, dbMode);
00278 
00279   return;
00280 }
00281 
00282 
00283 void
00284 QCAD::SaddleValueResponseFunction::
00285 initializeImagePoints(const double current_time,
00286          const Epetra_Vector* xdot,
00287          const Epetra_Vector& x,
00288          const Teuchos::Array<ParamVec>& p,
00289          Epetra_Vector& g, int dbMode)
00290 {
00291   // 1) Determine initial and final points depending on region type
00292   //     - Point: take point given directly
00293   //     - Element Block: take minimum point within the specified element block (and allowed z-range)
00294   //     - Polygon: take minimum point within specified 2D polygon and allowed z-range
00295   
00296   if(dbMode > 1) std::cout << "Saddle Point:  Beginning end point location" << std::endl;
00297 
00298     // Initialize intial/final points
00299   imagePts[0].init(numDims, imagePtSize);
00300   imagePts[nImagePts-1].init(numDims, imagePtSize);
00301 
00302   mode = "Point location";
00303   Albany::FieldManagerScalarResponseFunction::evaluateResponse(
00304   current_time, xdot, NULL, x, p, g);
00305   if(dbMode > 2) std::cout << "Saddle Point:   -- done evaluation" << std::endl;
00306 
00307   if(beginRegionType == "Point") {
00308     imagePts[0].coords = beginPolygon[0];
00309   }
00310   else { 
00311 
00312     //MPI: get global min for begin point
00313     double globalMin; int procToBcast, winner;
00314     comm->MinAll( &imagePts[0].value, &globalMin, 1);
00315     if( fabs(imagePts[0].value - globalMin) < 1e-8 ) 
00316       procToBcast = comm->MyPID();
00317     else procToBcast = -1;
00318 
00319     comm->MaxAll( &procToBcast, &winner, 1 );
00320     comm->Broadcast( imagePts[0].coords.data(), numDims, winner); //broadcast winner's min position to others
00321     imagePts[0].value = globalMin;                               //no need to broadcast winner's value
00322   }
00323 
00324   if(endRegionType   == "Point") {
00325     imagePts[nImagePts-1].coords = endPolygon[0];
00326   }
00327   else { 
00328 
00329     //MPI: get global min for end point
00330     double globalMin; int procToBcast, winner;
00331     comm->MinAll( &imagePts[nImagePts-1].value, &globalMin, 1);
00332     if( fabs(imagePts[nImagePts-1].value - globalMin) < 1e-8 ) 
00333       procToBcast = comm->MyPID();
00334     else procToBcast = -1;
00335 
00336     comm->MaxAll( &procToBcast, &winner, 1 );
00337     comm->Broadcast( imagePts[nImagePts-1].coords.data(), numDims, winner); //broadcast winner's min position to others
00338     imagePts[nImagePts-1].value = globalMin;                               //no need to broadcast winner's value
00339   }
00340 
00342   if(shortenBeginPc > 1e-6) {
00343      if(saddleGuessGiven)
00344        imagePts[0].coords = imagePts[0].coords + (saddlePointGuess - imagePts[0].coords) * (shortenBeginPc/100.0);
00345      else
00346        imagePts[0].coords = imagePts[0].coords + (imagePts[nImagePts-1].coords - imagePts[0].coords) * (shortenBeginPc/100.0);
00347   }
00348   if(shortenEndPc > 1e-6) {
00349      if(saddleGuessGiven)
00350        imagePts[nImagePts-1].coords = imagePts[nImagePts-1].coords + (saddlePointGuess - imagePts[nImagePts-1].coords) * (shortenEndPc/100.0);
00351      else
00352        imagePts[nImagePts-1].coords = imagePts[nImagePts-1].coords + (imagePts[0].coords - imagePts[nImagePts-1].coords) * (shortenEndPc/100.0);
00353   }
00354 
00355   if(dbMode > 2) std::cout << "Saddle Point:   -- done begin/end point initialization" << std::endl;
00356 
00358   //   interpolate between initial and final points (and possibly guess point) 
00359   //   to get all the image points
00360   const mathVector& initialPt = imagePts[0].coords;
00361   const mathVector& finalPt   = imagePts[nImagePts-1].coords;
00362 
00363   // Lock z-coordinate of initial and final points (and therefore of the rest of the points) if requested
00364   if(bLockToPlane && numDims > 2)
00365     imagePts[0].coords[2] = imagePts[nImagePts-1].coords[2] = lockedZ;
00366 
00367   if(saddleGuessGiven) {
00368 
00369     // two line segements (legs) initialPt -> guess, guess -> finalPt
00370     int nFirstLeg = (nImagePts+1)/2, nSecondLeg = nImagePts - nFirstLeg + 1; // +1 because both legs include middle pt
00371     for(int i=1; i<nFirstLeg-1; i++) {
00372       double s = i * 1.0/(nFirstLeg-1);
00373       imagePts[i].init(initialPt + (saddlePointGuess - initialPt) * s, imagePtSize);
00374     }
00375     for(int i=0; i<nSecondLeg-1; i++) {
00376       double s = i * 1.0/(nSecondLeg-1);
00377       imagePts[i+nFirstLeg-1].init(saddlePointGuess + (finalPt - saddlePointGuess) * s, imagePtSize);
00378     }
00379   }
00380   else {
00381 
00382     // one line segment initialPt -> finalPt
00383     for(std::size_t i=1; i<nImagePts-1; i++) {
00384       double s = i * 1.0/(nImagePts-1);   // nIntervals = nImagePts-1
00385       imagePts[i].init(initialPt + (finalPt - initialPt) * s, imagePtSize);
00386     }     
00387   }
00388  
00389   // Print initial point locations to stdout if requested
00390   if(dbMode > 1) {
00391     for(std::size_t i=0; i<nImagePts; i++)
00392       std::cout << "Saddle Point:   -- imagePt[" << i << "] = " << imagePts[i].coords << std::endl;
00393   }
00394 
00395   // If we aggregate workset data then call evaluator once more to accumulate 
00396   //  field and coordinate data into vFieldValues and vCoords members.
00397   if(bAggregateWorksets) {
00398     vFieldValues.clear();
00399     vCoords.clear();
00400     vGrads.clear();
00401 
00402     mode = "Accumulate all field data";
00403     Albany::FieldManagerScalarResponseFunction::evaluateResponse(
00404             current_time, xdot, NULL, x, p, g);
00405     //No MPI here - each proc only holds all of it's worksets -- not other procs worksets
00406   }
00407 
00408 
00409   return;
00410 }
00411 
00412 void
00413 QCAD::SaddleValueResponseFunction::
00414 initializeFinalImagePoints(const double current_time,
00415          const Epetra_Vector* xdot,
00416          const Epetra_Vector& x,
00417          const Teuchos::Array<ParamVec>& p,
00418          Epetra_Vector& g, int dbMode)
00419 {
00420   // Determine the locations of the "final" image points, which interpolate between the image points used
00421   //    in the nudged elastic band algorithm, and are used only as a means of getting more dense output data (more points along saddle path)
00422   
00423   if(dbMode > 1) std::cout << "Saddle Point:  Initializing Final Image Points" << std::endl;
00424 
00425   int maxPoints = maxFinalPts;    // maximum number of total final image points
00426   
00427   double* segmentLength = new double[nImagePts-1]; // segmentLength[i] == distance between imagePt[i] and imagePt[i+1]
00428   double lengthBefore = 0.0, lengthAfter = 0.0;    // path length before and after saddle point
00429   double radius = 0.0;
00430   int nPtsBefore = 0, nPtsAfter = 0, nFinalPts;
00431 
00432   // Get the distances along each leg of the current (final) saddle path
00433   for(std::size_t i = 0; i < nImagePts-1; i++) {
00434     segmentLength[i] = imagePts[i].coords.distanceTo(imagePts[i+1].coords);
00435     radius += imagePts[i].radius;
00436     if( (int)i < iSaddlePt ) lengthBefore += segmentLength[i];
00437     else lengthAfter += segmentLength[i];
00438   }
00439   
00440   radius += imagePts[nImagePts-1].radius;
00441   radius /= nImagePts;  // average radius
00442 
00443 /*
00444   // We'd like to put equal number of final points on each side of the saddle point.  Compute here how 
00445   //  many final points (fixed spacing) will lie on each side of the saddle point.
00446   if(maxPoints * ptSpacing < lengthBefore + lengthAfter) {
00447     if( maxPoints * ptSpacing / 2 > lengthBefore)
00448       nPtsBefore = int(lengthBefore / ptSpacing);
00449     else if( maxPoints * ptSpacing / 2 > lengthAfter)
00450       nPtsBefore = maxPoints - int(lengthAfter / ptSpacing);
00451     else nPtsBefore = maxPoints / 2;
00452 
00453     nPtsAfter = maxPoints - nPtsBefore;
00454   }
00455   else {
00456     nPtsBefore = int(lengthBefore / ptSpacing);
00457     nPtsAfter  = int(lengthAfter  / ptSpacing);
00458   }
00459 */
00460 
00461   // calculate point spacing for the entire saddle path and given maxPoints
00462   double ptSpacing = (lengthBefore + lengthAfter)/(maxPoints-1); 
00463   
00464   // nPtsBefore = int(lengthBefore / ptSpacing);
00465   // nPtsAfter  = int(lengthAfter  / ptSpacing);
00466   // nFinalPts = nPtsBefore + nPtsAfter + 1;     // one extra for "on/at" saddle point
00467   
00468   nFinalPts = maxPoints; 
00469   
00470   finalPts.resize(nFinalPts);
00471   finalPtValues.resize(nFinalPts);
00472   finalPtWeights.resize(nFinalPts);
00473 
00479   
00480   // Assign the starting and ending image points to finalPts
00481   finalPts[0].init(imagePts[0].coords, imagePts[0].radius);
00482   finalPts[nFinalPts-1].init(imagePts[nImagePts-1].coords, imagePts[nImagePts-1].radius);
00483   
00484   double offset = ptSpacing;  
00485   int iCurFinalPt = 1;
00486   
00487   for(std::size_t i = 0; i < nImagePts-1; i++) {
00488     const mathVector& initialPt = imagePts[i].coords;
00489     const mathVector& v = (imagePts[i+1].coords - imagePts[i].coords) * (1.0/segmentLength[i]);  // normalized vector from initial -> final pt
00490 
00491     if(segmentLength[i] > offset) {
00492       int nPtSegs = int((segmentLength[i]-offset) / ptSpacing);
00493       int nPts = nPtSegs + 1;
00494       double leftover = (segmentLength[i]-offset) - ptSpacing * nPtSegs;
00495 
00496       for(int j = 0; j < nPts && iCurFinalPt < nFinalPts; j++) {
00497         finalPts[iCurFinalPt].init(initialPt + v * (ptSpacing * j + offset), radius );
00498         iCurFinalPt++;
00499       }
00500       offset = ptSpacing - leftover; //how much to advance the first point of the next segment
00501     }
00502     else {
00503       offset -= segmentLength[i];
00504     }
00505   }
00506   
00507   //If there are any leftover points, initialize them too
00508   for(int j = iCurFinalPt; j < nFinalPts; j++) 
00509     finalPts[j].init(imagePts[nImagePts-1].coords, imagePts[nImagePts-1].radius);
00510   
00511 
00512 /*
00513   double offset = ptSpacing;
00514   int iCurFinalPt = nPtsBefore-1;
00515   for(int i = iSaddlePt-1; i >= 0; i--) {
00516     const mathVector& initialPt = imagePts[i+1].coords;
00517     const mathVector& v = (imagePts[i].coords - imagePts[i+1].coords) * (1.0/segmentLength[i]);  // normalized vector from initial -> final pt
00518 
00519     if(segmentLength[i] > offset) {
00520       int nPtSegs = int((segmentLength[i]-offset) / ptSpacing);
00521       int nPts = nPtSegs + 1;
00522       double leftover = (segmentLength[i]-offset) - ptSpacing * nPtSegs;
00523 
00524       for(int j=0; j<nPts && iCurFinalPt >= 0; j++) {
00525         //radius = (imagePts[i].radius + imagePts[i+1].radius)/2; // use average radius
00526         finalPts[iCurFinalPt].init(initialPt + v * (ptSpacing * j + offset), radius );
00527         iCurFinalPt--;
00528       }
00529       offset = ptSpacing - leftover; //how much to advance the first point of the next segment
00530     }
00531     else {
00532       offset -= segmentLength[i];
00533     }
00534   }
00535 
00536   //If there are any leftover points (at beginning), initialize them too
00537   for(int j=0; j<=iCurFinalPt; j++) 
00538     finalPts[j].init(imagePts[0].coords, imagePts[0].radius);
00539 
00540 
00541   offset = ptSpacing;  //start initial point *after* saddle point this time
00542   iCurFinalPt = nPtsBefore+1;
00543   for(std::size_t i = iSaddlePt; i < nImagePts-1; i++) {
00544     const mathVector& initialPt = imagePts[i].coords;
00545     const mathVector& v = (imagePts[i+1].coords - imagePts[i].coords) * (1.0/segmentLength[i]);  // normalized vector from initial -> final pt
00546 
00547     if(segmentLength[i] > offset) {
00548       int nPtSegs = int((segmentLength[i]-offset) / ptSpacing);
00549       int nPts = nPtSegs + 1;
00550       double leftover = (segmentLength[i]-offset) - ptSpacing * nPtSegs;
00551 
00552       for(int j=0; j<nPts && iCurFinalPt < nFinalPts; j++) {
00553         // radius = (imagePts[i].radius + imagePts[i+1].radius)/2; // use average radius
00554         finalPts[iCurFinalPt].init(initialPt + v * (ptSpacing * j + offset), radius );
00555         iCurFinalPt++;
00556       }
00557       offset = ptSpacing - leftover; //how much to advance the first point of the next segment
00558     }
00559     else {
00560       offset -= segmentLength[i];
00561     }
00562   }
00563 
00564   //If there are any leftover points, initialize them too
00565   for(int j=iCurFinalPt; j<nFinalPts; j++) 
00566     finalPts[j].init(imagePts[nImagePts-1].coords, imagePts[nImagePts-1].radius);
00567 
00568 */
00569 
00570   return;
00571 }
00572 
00573 
00574 void
00575 QCAD::SaddleValueResponseFunction::
00576 doNudgedElasticBand(const double current_time,
00577         const Epetra_Vector* xdot,
00578         const Epetra_Vector& x,
00579         const Teuchos::Array<ParamVec>& p,
00580         Epetra_Vector& g, int dbMode)
00581 {
00582   //  2) Perform Nudged Elastic Band Algorithm to find saddle point.
00583   //      Iterate over field manager fills of each image point's value and gradient
00584   //       then update image point positions user Verlet algorithm
00585 
00586   std::size_t nIters, nInitialIterations;
00587   double dp, s;
00588   double gradScale, springScale, springBase;
00589   double avgForce=0, avgOpposingForce=0;
00590   double dt = maxTimeStep;
00591   double dt2 = dt*dt;
00592   double acceptedHighestPtGradNorm = -1.0, highestPtGradNorm;
00593   int iHighestPt, nConsecLowForceDiff=0;  
00594 
00595   mathVector tangent(numDims);  
00596   std::vector<mathVector> force(nImagePts), lastForce(nImagePts), lastPositions(nImagePts), lastVelocities(nImagePts);
00597   std::vector<double> springConstants(nImagePts-1, minSpringConstant);
00598 
00599   //initialize force variables and last positions
00600   for(std::size_t i=0; i<nImagePts; i++) {
00601     force[i].resize(numDims); force[i].fill(0.0);
00602     lastForce[i] = force[i];
00603     lastPositions[i] = imagePts[i].coords;
00604     lastVelocities[i] = imagePts[i].velocity;
00605   }
00606 
00607   //get distance between initial and final points
00608   double max_dCoords = imagePts[0].coords.distanceTo( imagePts[nImagePts-1].coords ) / nImagePts;
00609 
00610   nIters = 0;
00611   nInitialIterations = 20; // TODO: make into parameter?
00612   
00613   //Storage for aggrecated image point data (needed for MPI)
00614   double*  globalPtValues   = new double [nImagePts];
00615   double*  globalPtWeights  = new double [nImagePts];
00616   double*  globalPtGrads    = new double [nImagePts*numDims];
00617 
00618   //Write header to debug file
00619   std::fstream fDebug;
00620   if(debugFilename.length() > 0) {
00621     fDebug.open(debugFilename.c_str(), std::fstream::out);
00622     fDebug << "% HighestValue  HighestIndex  AverageForce  TimeStep"
00623      << "  HighestPtGradNorm  AverageOpposingForce  SpringBase" << std::endl;
00624   }
00625 
00626   // Begin NEB iteration loop
00627   while( ++nIters <= maxIterations) {
00628 
00629     if(dbMode > 1) std::cout << "Saddle Point:  NEB Algorithm iteration " << nIters << " -----------------------" << std::endl;
00630     writeOutput(nIters);
00631 
00632 
00633     if(nIters > 1) {
00634       //Update coordinates and velocity using (modified) Verlet integration. Reset
00635       // the velocity to zero if it is directed opposite to force (reduces overshoot)
00636       for(std::size_t i=1; i<nImagePts-1; i++) {
00637   dp = imagePts[i].velocity.dot(force[i]);
00638   if(dp < 0) imagePts[i].velocity.fill(0.0);
00639 
00640   //save last position & velocity in case the new position brings 
00641   //  us outside the mesh or we need to backtrace
00642   lastPositions[i] = imagePts[i].coords; 
00643   lastVelocities[i] = imagePts[i].velocity; //Note: will be zero if force opposed velocity (above)
00644 
00645   // ** Update **
00646   mathVector dCoords = lastVelocities[i] * dt + force[i] * dt2 * 0.5;
00647   imagePts[i].coords = lastPositions[i] + dCoords;
00648   imagePts[i].velocity = lastVelocities[i] + force[i] * dt;
00649       }
00650     }
00651 
00652     getImagePointValues(current_time, xdot, x, p, g, 
00653       globalPtValues, globalPtWeights, globalPtGrads,
00654       lastPositions, dbMode);
00655     iHighestPt = getHighestPtIndex();
00656     highestPtGradNorm = imagePts[iHighestPt].grad.norm();
00657 
00658     // Setup scaling factors on first iteration
00659     if(nIters == 1) initialIterationSetup(gradScale, springScale, dbMode);
00660 
00661     // If in "backtrace" mode, require grad norm to decrease (or take minimum timestep)
00662     if(nIters > backtraceAfterIters) {
00663       while(dt > minTimeStep && highestPtGradNorm > acceptedHighestPtGradNorm) {
00664 
00665   //reduce dt
00666   dt = (dt/2 < minTimeStep) ? minTimeStep : dt/2;
00667   dt /= 2; dt2=dt*dt; 
00668   
00669   if(dbMode > 2) std::cout << "Saddle Point:  ** Backtrace dt => " << dt << std::endl;
00670 
00671   //Update coordinates and velocity using (modified) Verlet integration. Reset
00672   // the velocity to zero if it is directed opposite to force (reduces overshoot)
00673   for(std::size_t i=1; i<nImagePts-1; i++) {
00674     mathVector dCoords = lastVelocities[i] * dt + force[i] * dt2 * 0.5;
00675     imagePts[i].coords = lastPositions[i] + dCoords;
00676     imagePts[i].velocity = lastVelocities[i] + force[i] * dt;
00677   }
00678   
00679   getImagePointValues(current_time, xdot, x, p, g, 
00680           globalPtValues, globalPtWeights, globalPtGrads,
00681           lastPositions, dbMode);
00682   iHighestPt = getHighestPtIndex();
00683   highestPtGradNorm = imagePts[iHighestPt].grad.norm();
00684       }
00685 
00686       if(dt == minTimeStep && highestPtGradNorm > acceptedHighestPtGradNorm && dbMode > 2)
00687   std::cout << "Saddle Point:  ** Warning: backtrace hit min dt == " << dt << std::endl;
00688     } 
00689     acceptedHighestPtGradNorm = highestPtGradNorm;
00690 
00691     // Compute spring base constant for this iteration
00692     s = ((double)nIters-1.0)/maxIterations;    
00693     springBase = springScale * ( (1.0-s)*minSpringConstant + s*maxSpringConstant ); 
00694     for(std::size_t i=0; i<nImagePts-1; i++) springConstants[i] = springBase;
00695     
00696     avgForce = avgOpposingForce = 0.0;
00697 
00698     // Compute force acting on each image point
00699     for(std::size_t i=1; i<nImagePts-1; i++) {
00700       if(dbMode > 2) std::cout << std::endl << "Saddle Point:  >> Updating pt[" << i << "]:" << imagePts[i];
00701 
00702       // compute the tangent vector for the ith image point
00703       computeTangent(i, tangent, dbMode);
00704 
00705       // compute the force vector for the ith image point
00706       if((int)i == iHighestPt && bClimbing && nIters > nInitialIterations)
00707   computeClimbingForce(i, tangent, gradScale, force[i], dbMode);
00708       else
00709   computeForce(i, tangent, springConstants, gradScale, springScale,
00710          force[i], dt, dt2, dbMode);
00711 
00712       // update avgForce and avgOpposingForce
00713       avgForce += force[i].norm();
00714       dp = force[i].dot(lastForce[i]) / (force[i].norm() * lastForce[i].norm()); 
00715       if( dp < 0 ) {  //if current force and last force point in "opposite" directions
00716   mathVector v = force[i] - lastForce[i];
00717   avgOpposingForce += v.norm() / (force[i].norm() + lastForce[i].norm());
00718   //avgOpposingForce += dp;  //an alternate implementation
00719       } 
00720     } // end of loop over image points 
00721 
00722     avgForce /= (nImagePts-2);
00723     avgOpposingForce /= (nImagePts-2);
00724 
00725 
00726     //print debug output
00727     if(dbMode > 1) 
00728       std::cout << "Saddle Point:  ** Summary:"
00729     << "  highest val[" << iHighestPt << "] = " << imagePts[iHighestPt].value
00730     << "  AverageForce = " << avgForce << "  dt = " << dt 
00731     << "  gradNorm = " << imagePts[iHighestPt].grad.norm() 
00732     << "  AvgOpposingForce = " << avgOpposingForce 
00733     << "  SpringBase = " << springBase << std::endl;
00734     if(debugFilename.length() > 0)
00735       fDebug << imagePts[iHighestPt].value << "  " << iHighestPt << "  "
00736        << avgForce << "  "  << dt << "  " << imagePts[iHighestPt].grad.norm() << "  "
00737        << avgOpposingForce << "  " << springBase << std::endl;
00738 
00739 
00740     // Check for convergence in gradient norm
00741     if(imagePts[iHighestPt].grad.norm() < convergeTolerance) {
00742       if(dbMode > 2) std::cout << "Saddle Point:  ** Converged (grad norm " << 
00743          imagePts[iHighestPt].grad.norm() << " < " << convergeTolerance << ")" << std::endl;
00744       break; // exit iterations loop
00745     }
00746     else if(nIters == maxIterations) break; //max iterations reached -- exit iterations loop now
00747                                             // (important so coords & radii don't get updated)
00748 
00749     // Save last force for next iteration
00750     for(std::size_t i=1; i<nImagePts-1; i++) lastForce[i] = force[i];
00751     
00752     // If all forces have remained in the same direction, tally this.  If this happens too many times
00753     //  increase dt, as this is a sign the time step is too small.
00754     if(avgOpposingForce < 1e-6) nConsecLowForceDiff++; else nConsecLowForceDiff = 0;
00755     if(nConsecLowForceDiff >= 3 && dt < maxTimeStep) { 
00756       dt *= 2; dt2=dt*dt; nConsecLowForceDiff = 0;
00757       if(dbMode > 2) std::cout << "Saddle Point:  ** Consecutive low dForce => dt = " << dt << std::endl;
00758     }
00759 
00760     //Shouldn't be necessary since grad_z == 0, but just to be sure all points 
00761     //  are locked to their given (initial) z-coordinate
00762     if(bLockToPlane && numDims > 2) {
00763       for(std::size_t i=1; i<nImagePts-1; i++) force[i][2] = 0.0;
00764     }
00765 
00766     //Reduce dt if movement of any point exceeds initial average distance btwn pts
00767     bool reduce_dt = true;
00768     while(reduce_dt && dt/2 > minTimeStep) {
00769       reduce_dt = false;
00770       for(std::size_t i=1; i<nImagePts-1; i++) {
00771   if(imagePts[i].velocity.norm() * dt > max_dCoords) { reduce_dt = true; break; }
00772   if(0.5 * force[i].norm() * dt2 > max_dCoords) { reduce_dt = true; break; }
00773       }
00774       if(reduce_dt) { 
00775   dt /= 2; dt2=dt*dt;
00776   if(dbMode > 2) std::cout << "Saddle Point:  ** Warning: dCoords too large: dt => " << dt << std::endl;
00777       }
00778     }
00779     
00780     // adjust image point size based on weight (if requested)
00781     //  --> try to get weight between MIN/MAX target weights by varying image pt size
00782     if(bAdaptivePointSize) {
00783       for(std::size_t i=0; i<nImagePts; i++) {
00784   if(imagePts[i].weight < minAdaptivePointWt) imagePts[i].radius *= 2;
00785   else if(imagePts[i].weight > maxAdaptivePointWt) imagePts[i].radius /= 2;
00786       }
00787     }
00788 
00789   }  // end of NEB iteration loops
00790 
00791   //deallocate storage used for MPI communication
00792   delete [] globalPtValues; 
00793   delete [] globalPtWeights;
00794   delete [] globalPtGrads;  
00795 
00796   // Check if converged: nIters < maxIters ?
00797   if(dbMode) {
00798     if(nIters <= maxIterations) 
00799       std::cout << "Saddle Point:  NEB Converged after " << nIters << " iterations" << std::endl;
00800     else
00801       std::cout << "Saddle Point:  NEB Giving up after " << maxIterations << " iterations" << std::endl;
00802 
00803     for(std::size_t i=0; i<nImagePts; i++) {
00804       std::cout << "Saddle Point:  --   Final pt[" << i << "] = " << imagePts[i].value 
00805     << " : " << imagePts[i].coords << "  (wt = " << imagePts[i].weight << " )" 
00806     << "  (r= " << imagePts[i].radius << " )" << std::endl;
00807     }
00808   }
00809 
00810   // Choose image point with highest value (and positive weight) as saddle point
00811   std::size_t imax = 0;
00812   for(std::size_t i=0; i<nImagePts; i++) {
00813     if(imagePts[i].weight > 0) { imax = i; break; }
00814   }
00815   for(std::size_t i=imax+1; i<nImagePts; i++) {
00816     if(imagePts[i].value > imagePts[imax].value && imagePts[i].weight > 0) imax = i;
00817   }
00818   iSaddlePt = imax;
00819 
00820   if(debugFilename.length() > 0) fDebug.close();
00821   return;
00822 }
00823 
00824 void
00825 QCAD::SaddleValueResponseFunction::
00826 fillSaddlePointData(const double current_time,
00827         const Epetra_Vector* xdot,
00828         const Epetra_Vector& x,
00829         const Teuchos::Array<ParamVec>& p,
00830         Epetra_Vector& g, int dbMode)
00831 {
00832   if(dbMode > 1) std::cout << "Saddle Point:  Begin filling saddle point data" << std::endl;
00833 
00834   if(bAggregateWorksets) {  //in aggregate workset mode, there are currently no x-y cutoffs imposed on points in getImagePointValues
00835     xmin = -1e10; xmax = 1e10; ymin = -1e10; ymax = 1e10;
00836   }
00837 
00838   mode = "Fill saddle point";
00839   Albany::FieldManagerScalarResponseFunction::evaluateResponse(
00840            current_time, xdot, NULL, x, p, g);
00841   if(dbMode > 1) std::cout << "Saddle Point:  Done filling saddle point data" << std::endl;
00842 
00843   //Note: MPI: saddle weight is already summed in evaluator's 
00844   //   postEvaluate, so no need to do anything here
00845 
00846   returnFieldVal = g[0];
00847   imagePts[iSaddlePt].value = g[1];
00848   
00849   // Overwrite response indices 2+ with saddle point coordinates
00850   for(std::size_t i=0; i<numDims; i++) g[2+i] = imagePts[iSaddlePt].coords[i]; 
00851 
00852   if(dbMode) {
00853     std::cout << "Saddle Point:  Return Field value = " << g[0] << std::endl;
00854     std::cout << "Saddle Point:         Field value = " << g[1] << std::endl;
00855     for(std::size_t i=0; i<numDims; i++)
00856       std::cout << "Saddle Point:         Coord[" << i << "] = " << g[2+i] << std::endl;
00857   }
00858 
00859   if( outputFilename.length() > 0) {
00860     std::fstream out; double pathLength = 0.0;
00861     out.open(outputFilename.c_str(), std::fstream::out | std::fstream::app);
00862     out << std::endl << std::endl << "% Saddle point path - Image points" << std::endl;
00863     out << "% index xCoord yCoord value pathLength pointRadius" << std::endl;
00864     for(std::size_t i=0; i<nImagePts; i++) {
00865       out << i << " " << imagePts[i].coords[0] << " " << imagePts[i].coords[1]
00866     << " " << imagePts[i].value << " " << pathLength << " " << imagePts[i].radius << std::endl;
00867       if(i<nImagePts-1) pathLength += imagePts[i].coords.distanceTo(imagePts[i+1].coords);
00868     }    
00869     out.close();
00870   }
00871 
00872   return;
00873 }
00874 
00875 
00876 
00877 void
00878 QCAD::SaddleValueResponseFunction::
00879 doLevelSet(const double current_time,
00880      const Epetra_Vector* xdot,
00881      const Epetra_Vector& x,
00882      const Teuchos::Array<ParamVec>& p,
00883      Epetra_Vector& g, int dbMode)
00884 {
00885   int result;
00886 
00887   if( fabs(levelSetRadius) < 1e-9 ) return; //don't run if level-set radius is zero
00888 
00889   vlsFieldValues.clear(); vlsCellAreas.clear();
00890   for(std::size_t k=0; k<numDims; k++) vlsCoords[k].clear();
00891 
00892   mode = "Level set data collection";
00893   Albany::FieldManagerScalarResponseFunction::evaluateResponse(
00894            current_time, xdot, NULL, x, p, g);
00895 
00897   std::vector<double> allFieldVals;
00898   std::vector<double> allCellAreas;
00899   std::vector<double> allCoords[MAX_DIMENSIONS];
00900 
00901   QCAD::gatherVector(vlsFieldValues, allFieldVals, *comm);  
00902   QCAD::gatherVector(vlsCellAreas, allCellAreas, *comm);
00903   for(std::size_t k=0; k<numDims; k++)
00904     QCAD::gatherVector(vlsCoords[k], allCoords[k], *comm);
00905 
00907   if( allFieldVals.size()  == 0 ) return;
00908 
00910   if(dbMode) {
00911     std::cout << std::endl << "--- Begin Saddle Level Set Algorithm ---" << std::endl;
00912     std::cout << "--- Saddle Level Set: local size (this proc) = " << vlsFieldValues.size()
00913         << ", gathered size (all procs) = " << allFieldVals.size() << std::endl;
00914   }
00915 
00917   std::vector<int> ordering;
00918   QCAD::getOrdering(allFieldVals, ordering);
00919 
00920 
00922   double maxFieldVal = allFieldVals[0], minFieldVal = allFieldVals[0];
00923   double maxCoords[3], minCoords[3];
00924 
00925   for(std::size_t k=0; k<numDims && k < 3; k++)
00926     maxCoords[k] = minCoords[k] = allCoords[k][0];
00927 
00928   std::size_t N = allFieldVals.size();
00929   for(std::size_t i=0; i<N; i++) {
00930     for(std::size_t k=0; k<numDims && k < 3; k++) {
00931       if(allCoords[k][i] > maxCoords[k]) maxCoords[k] = allCoords[k][i];
00932       if(allCoords[k][i] < minCoords[k]) minCoords[k] = allCoords[k][i];
00933     }
00934     if(allFieldVals[i] > maxFieldVal) maxFieldVal = allFieldVals[i];
00935     if(allFieldVals[i] < minFieldVal) minFieldVal = allFieldVals[i];
00936   }
00937   
00938   double avgCellLength = pow(QCAD::averageOfVector(allCellAreas), 0.5); //assume 2D areas
00939   double maxFieldDifference = fabs(maxFieldVal - minFieldVal);
00940   double currentSaddleValue = imagePts[iSaddlePt].value;
00941   
00942 
00943   if(dbMode > 1) {
00944     std::cout << "--- Saddle Level Set: max field difference = " << maxFieldDifference
00945         << ", avg cell length = " << avgCellLength << std::endl;
00946   }
00947 
00949   double cutoffDistance, cutoffFieldVal, minDepth;
00950   cutoffDistance = avgCellLength * distanceCutoffFctr;
00951   cutoffFieldVal = maxFieldDifference * fieldCutoffFctr;
00952   minDepth = minPoolDepthFctr * (currentSaddleValue - minFieldVal) / 2.0; //maxFieldDifference * minPoolDepthFctr;
00953 
00954   result = FindSaddlePoint_LevelSet(allFieldVals, allCoords, ordering,
00955          cutoffDistance, cutoffFieldVal, minDepth, dbMode, g);
00956   // result == 0 ==> success: found 2 "deep" pools & saddle pt
00957   if(result == 0) { 
00958     //update imagePts[iSaddlePt] to be newly found saddle value
00959     for(std::size_t i=0; i<numDims; i++) imagePts[iSaddlePt].coords[i] = g[2+i];
00960     imagePts[iSaddlePt].value = g[1];
00961     imagePts[iSaddlePt].radius = 1e-5; //very small so only pick up point of interest?
00962     //set weight?
00963   }
00964 
00965   return;
00966 }
00967 
00969 int QCAD::SaddleValueResponseFunction::
00970 FindSaddlePoint_LevelSet(std::vector<double>& allFieldVals,
00971     std::vector<double>* allCoords, std::vector<int>& ordering,
00972     double cutoffDistance, double cutoffFieldVal, double minDepth, int dbMode,
00973     Epetra_Vector& g)
00974 {
00975   if(dbMode) {
00976     std::cout << "--- Saddle Level Set: distance cutoff = " << cutoffDistance
00977         << ", field cutoff = " << cutoffFieldVal 
00978         << ", min depth = " << minDepth << std::endl;
00979   }
00980 
00981   // Walk through sorted data.  At current point, walk backward in list 
00982   //  until either 1) a "close" point is found, as given by tolerance -> join to tree
00983   //            or 2) the change in field value exceeds some maximium -> new tree
00984   std::size_t N = allFieldVals.size();
00985   std::vector<int> treeIDs(N, -1);
00986   std::vector<double> minFieldVals; //for each tree
00987   std::vector<int> treeSizes; //for each tree
00988   int nextAvailableTreeID = 0;
00989 
00990   int nTrees = 0, nMaxTrees = 0;
00991   int nDeepTrees=0, lastDeepTrees=0, treeIDtoReplace;
00992   int I, J, K;
00993   for(std::size_t i=0; i < N; i++) {
00994     I = ordering[i];
00995 
00996     if(dbMode > 1) {
00997       nDeepTrees = 0;
00998       for(std::size_t t=0; t < treeSizes.size(); t++) {
00999   if(treeSizes[t] > 0 && (allFieldVals[I]-minFieldVals[t]) > minDepth) nDeepTrees++;
01000       }
01001     }
01002 
01003     if(dbMode > 3) std::cout << "DEBUG: i=" << i << "( I = " << I << "), val="
01004        << allFieldVals[I] << ", loc=(" << allCoords[0][I] 
01005        << "," << allCoords[1][I] << ")" << " nD=" << nDeepTrees;
01006 
01007     if(dbMode > 1 && lastDeepTrees != nDeepTrees) {
01008       std::cout << "--- Saddle: i=" << i << " new deep pool: nPools=" << nTrees 
01009     << " nDeep=" << nDeepTrees << std::endl;
01010       lastDeepTrees = nDeepTrees;
01011     }
01012 
01013     for(int j=i-1; j >= 0 && fabs(allFieldVals[I] - allFieldVals[ordering[j]]) < cutoffFieldVal; j--) {
01014       J = ordering[j];
01015 
01016       if( QCAD::distance(allCoords, I, J, numDims) < cutoffDistance ) {
01017   if(treeIDs[I] == -1) {
01018     treeIDs[I] = treeIDs[J];
01019     treeSizes[treeIDs[I]]++;
01020 
01021     if(dbMode > 3) std::cout << " --> tree " << treeIDs[J] 
01022              << " ( size=" << treeSizes[treeIDs[J]] << ", depth=" 
01023              << (allFieldVals[I]-minFieldVals[treeIDs[J]]) << ")" << std::endl;
01024   }
01025   else if(treeIDs[I] != treeIDs[J]) {
01026 
01027     //update number of deep trees
01028     nDeepTrees = 0;
01029     for(std::size_t t=0; t < treeSizes.size(); t++) {
01030       if(treeSizes[t] > 0 && (allFieldVals[I]-minFieldVals[t]) > minDepth) nDeepTrees++;
01031     }
01032 
01033     bool mergingTwoDeepTrees = false;
01034     if((allFieldVals[I]-minFieldVals[treeIDs[I]]) > minDepth && 
01035        (allFieldVals[I]-minFieldVals[treeIDs[J]]) > minDepth) {
01036       mergingTwoDeepTrees = true;
01037       nDeepTrees--;
01038     }
01039 
01040     treeIDtoReplace = treeIDs[I];
01041     if( minFieldVals[treeIDtoReplace] < minFieldVals[treeIDs[J]] )
01042       minFieldVals[treeIDs[J]] = minFieldVals[treeIDtoReplace];
01043 
01044     for(int k=i; k >=0; k--) {
01045       K = ordering[k];
01046       if(treeIDs[K] == treeIDtoReplace) {
01047         treeIDs[K] = treeIDs[J];
01048         treeSizes[treeIDs[J]]++;
01049       }
01050     }
01051     treeSizes[treeIDtoReplace] = 0;
01052     nTrees -= 1;
01053 
01054     if(dbMode > 3) std::cout << "DEBUG:   also --> " << treeIDs[J] 
01055              << " [merged] size=" << treeSizes[treeIDs[J]]
01056              << " (treecount after merge = " << nTrees << ")" << std::endl;
01057 
01058     if(dbMode > 1) std::cout << "--- Saddle: i=" << i << "merge: nPools=" << nTrees 
01059            << " nDeep=" << nDeepTrees << std::endl;
01060 
01061 
01062     if(mergingTwoDeepTrees && nDeepTrees == 1) {
01063       if(dbMode > 3) std::cout << "DEBUG: FOUND SADDLE! exiting." << std::endl;
01064       if(dbMode > 1) std::cout << "--- Saddle: i=" << i << " Found saddle at ";
01065 
01066             //Found saddle at I
01067       g[0] = 0; //TODO - change this g[.] interface to something more readable -- and we don't use g[0] now
01068             g[1] = allFieldVals[I];
01069             for(std::size_t k=0; k<numDims && k < 3; k++) {
01070               g[2+k] = allCoords[k][I];
01071               if(dbMode > 1) std::cout << allCoords[k][I] << ", ";
01072       }
01073             
01074       if(dbMode > 1) std::cout << "ret=" << g[0] << std::endl;
01075             return 0; //success
01076     }
01077 
01078   }
01079       }
01080 
01081     } //end j loop
01082     
01083     if(treeIDs[I] == -1) {
01084       if(dbMode > 3) std::cout << " --> new tree with ID " << nextAvailableTreeID
01085              << " (treecount after new = " << (nTrees+1) << ")" << std::endl;
01086       if(dbMode > 1) std::cout << "--- Saddle: i=" << i << " new pool: nPools=" << (nTrees+1) 
01087              << " nDeep=" << nDeepTrees << std::endl;
01088 
01089       treeIDs[I] = nextAvailableTreeID++;
01090       minFieldVals.push_back(allFieldVals[I]);
01091       treeSizes.push_back(1);
01092 
01093       nTrees += 1;
01094       if(nTrees > nMaxTrees) nMaxTrees = nTrees;
01095     }
01096 
01097   } // end i loop
01098 
01099   // if no saddle found, return all zeros
01100   if(dbMode > 3) std::cout << "DEBUG: NO SADDLE. exiting." << std::endl;
01101   for(std::size_t k=0; k<5; k++) g[k] = 0;
01102 
01103   // if two or more trees where found, then reason for failure is that not
01104   //  enough deep pools were found - so could try to reduce minDepth and re-run.
01105   if(nMaxTrees >= 2) return 1;
01106 
01107   // nMaxTrees < 2 - so we need more trees.  Could try to increase cutoffDistance and/or cutoffFieldVal.
01108   return 2;
01109 }
01110 
01111 
01112 double QCAD::SaddleValueResponseFunction::getCurrent
01113   (const double& lattTemp, const Teuchos::RCP<QCAD::MaterialDatabase>& materialDB) const
01114 {
01115   const double kB = 8.617332e-5;  // eV/K
01116   double Temp = lattTemp;   // K
01117 
01118   // segmentLength[i] == distance between imagePt[i] and imagePt[i+1]
01119   double* segmentLength = new double[nImagePts-1]; 
01120 
01121   // path length before and after saddle point
01122   double lengthBefore = 0.0, lengthAfter = 0.0;    
01123 
01124   // get the distances along each leg of the final saddle path
01125   for(std::size_t i = 0; i < nImagePts-1; i++) 
01126   {
01127     segmentLength[i] = imagePts[i].coords.distanceTo(imagePts[i+1].coords);
01128     if( (int)i < iSaddlePt ) 
01129       lengthBefore += segmentLength[i];
01130     else 
01131       lengthAfter += segmentLength[i];
01132   }
01133   
01134   // recalculate gfGridSpacing to obtain an integer number of points for GF-CBR calculation,
01135   // this strategy produces path length that is slightly non-equally spaced due to precision.
01136   // int nGFPts = int( (lengthBefore + lengthAfter)/gfGridSpacing ) + 1;
01137   // double ptSpacing = (lengthBefore + lengthAfter)/(nGFPts-1);  // actual GF Grid Spacing
01138   
01139   // set actual grid spacing to user-defined value for GF-CBR calculation,
01140   double ptSpacing = gfGridSpacing;
01141   int nGFPts = int( (lengthBefore + lengthAfter)/gfGridSpacing );
01142   std::cout << "nGFPts = " << nGFPts << ", actual gfGridSpacing = " << ptSpacing << std::endl; 
01143 
01144   // hard-code eff. mass along the saddle path using Reference Material's transverse eff. mass
01145   std::string refMtrlName = materialDB->getParam<std::string>("Reference Material");
01146   double effMass = materialDB->getMaterialParam<double>(refMtrlName,"Transverse Electron Effective Mass");
01147 
01148   // hard-code electron affinity using the Reference Material's value
01149   double matChi = materialDB->getMaterialParam<double>(refMtrlName,"Electron Affinity");
01150 
01151   // unscale the Field Scaling Factor to obtain the actual Potential in [V]
01152   Teuchos::RCP<std::vector<double> > pot = Teuchos::rcp( new std::vector<double>(finalPts.size()) );
01153   for(std::size_t i = 0; i < finalPts.size(); i++)
01154     (*pot)[i] = finalPts[i].value / fieldScaling;
01155     
01156   // compute energy reference
01157   double qPhiRef;
01158   {
01159     std::string category = materialDB->getMaterialParam<std::string>(refMtrlName,"Category");
01160     if (category == "Semiconductor") 
01161     {
01162       // Same qPhiRef needs to be used for the entire structure
01163       double mdn = materialDB->getMaterialParam<double>(refMtrlName,"Electron DOS Effective Mass");
01164       double mdp = materialDB->getMaterialParam<double>(refMtrlName,"Hole DOS Effective Mass");
01165       double Chi = materialDB->getMaterialParam<double>(refMtrlName,"Electron Affinity");
01166       double Eg0 = materialDB->getMaterialParam<double>(refMtrlName,"Zero Temperature Band Gap");
01167       double alpha = materialDB->getMaterialParam<double>(refMtrlName,"Band Gap Alpha Coefficient");
01168       double beta = materialDB->getMaterialParam<double>(refMtrlName,"Band Gap Beta Coefficient");
01169       
01170       double Eg = Eg0 - alpha*pow(Temp,2.0)/(beta+Temp); // in [eV]
01171       double kbT = kB * Temp;      // in [eV]
01172       double Eic = -Eg/2. + 3./4.*kbT*log(mdp/mdn);  // (Ei-Ec) in [eV]
01173       qPhiRef = Chi - Eic;  // (Evac-Ei) in [eV] where Evac = vacuum level
01174     }
01175     else 
01176       TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl 
01177         << "Error!  Invalid category " << category << " for reference material !" << std::endl);
01178   }  
01179   
01180   // compute conduction band [eV] from the potential
01181   Teuchos::RCP<std::vector<double> > Ec = Teuchos::rcp( new std::vector<double>(finalPts.size()) );
01182   Teuchos::RCP<std::vector<double> > pathLen = Teuchos::rcp( new std::vector<double>(finalPts.size()) );
01183   
01184   double pathLength = 0.0;
01185   for(std::size_t i = 0; i < finalPts.size(); i++)
01186   {
01187     (*Ec)[i] = qPhiRef - matChi - (*pot)[i];
01188     (*pathLen)[i] = pathLength;  
01189     if (i < (finalPts.size()-1))
01190       pathLength += finalPts[i].coords.distanceTo(finalPts[i+1].coords);
01191   }
01192     
01193   // append the computed Ec data to output file
01194   if( outputFilename.length() > 0) 
01195   {
01196     std::fstream out; 
01197     out.open(outputFilename.c_str(), std::fstream::out | std::fstream::app);
01198     out << std::endl << std::endl << "% Computed conduction band Ec (assumes field is Potential) -- 'final' points" << std::endl;
01199     out << "% index xCoord yCoord Ec pathLength pointRadius" << std::endl;
01200     for(std::size_t i = 0; i < finalPts.size(); i++) 
01201     {
01202       out << i << " " << finalPts[i].coords[0] << " " << finalPts[i].coords[1] 
01203           << " " << (*Ec)[i] << " " << (*pathLen)[i] << " " << finalPts[i].radius << std::endl;
01204     }
01205     out.close();
01206   }   
01207 
01208   double I = 0.0; 
01209 
01210   // instantiate the GF-CBR solver to compute current
01211   QCAD::GreensFunctionTunnelingSolver solver(Ec, pathLen, nGFPts, ptSpacing, effMass, comm, outputFilename); //Teuchos::rcp(comm.Clone())
01212   
01213   // set the eigensolver to be used
01214   bool bUseAnasazi = false; 
01215   if (gfEigensolver == "Anasazi")
01216      bUseAnasazi = true; 
01217   else if (gfEigensolver == "tql2")
01218      bUseAnasazi = false; 
01219   else
01220      TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl 
01221         << "Error!  Invalid GF-CBR Method Eigensolver, must be either Anasazi or tql2 !" << std::endl);
01222   
01223   // compute the currents for a range of Vds values
01224   if (bSweepVds)   
01225   {
01226     int ptsVds = stepsVds + 1;  // include the ending point
01227     std::vector<double> rangeVds(ptsVds, 0.0);
01228     std::vector<double> rangeIds(ptsVds, 0.0); 
01229     
01230     double deltaVds = (finalVds - initVds) / double(ptsVds-1); 
01231     for (int i = 0; i < ptsVds; i++)
01232       rangeVds[i] = initVds + deltaVds * double(i); 
01233     
01234     solver.computeCurrentRange(rangeVds, kB * Temp, current_Ecutoff_offset_from_Emax, rangeIds, bUseAnasazi);
01235     
01236     // set I to the last value of rangeIds
01237     I = rangeIds[ptsVds-1];
01238 
01239     // write Vds vs. Ids data to file
01240     if ( outputFilename.length() > 0) 
01241     {
01242       std::fstream out; 
01243       out.open(outputFilename.c_str(), std::fstream::out | std::fstream::app);
01244       out << std::endl << std::endl << "% Current vs Voltage IV curve (GF-CBR method)" << std::endl;
01245       out << "% index, Vds [V] vs Ids [A] data" << std::endl;
01246       for(std::size_t i = 0; i < rangeVds.size(); i++) 
01247         out << i << " " << rangeVds[i] << " " << rangeIds[i] << " " << std::endl;
01248       out.close();
01249     }
01250     
01251   }  // end of if (bSweepVds)
01252   
01253   // compute the current for a single Vds value
01254   else             
01255     I = solver.computeCurrent(finalVds, kB * Temp, current_Ecutoff_offset_from_Emax, bUseAnasazi); // overwrite "Return Field Val" with current
01256   
01257   std::cout << "Final Vds = " << finalVds << " V, Current Ids = " << I << " Amps" << std::endl;
01258   
01259   return I;
01260 }
01261 
01262 
01263 void
01264 QCAD::SaddleValueResponseFunction::
01265 evaluateTangent(const double alpha, 
01266     const double beta,
01267     const double omega,
01268     const double current_time,
01269     bool sum_derivs,
01270     const Epetra_Vector* xdot,
01271     const Epetra_Vector* xdotdot,
01272     const Epetra_Vector& x,
01273     const Teuchos::Array<ParamVec>& p,
01274     ParamVec* deriv_p,
01275     const Epetra_MultiVector* Vxdot,
01276     const Epetra_MultiVector* Vxdotdot,
01277     const Epetra_MultiVector* Vx,
01278     const Epetra_MultiVector* Vp,
01279     Epetra_Vector* g,
01280     Epetra_MultiVector* gx,
01281     Epetra_MultiVector* gp)
01282 {
01283 
01284   // Require that g be computed to get tangent info 
01285   if(g != NULL) {
01286     
01287     // HACK: for now do not evaluate response when tangent is requested,
01288     //   as it is assumed that evaluateResponse has already been called
01289     //   directly or by evaluateGradient.  This prevents repeated calling 
01290     //   of evaluateResponse within the dg/dp loop of Albany::ModelEvaluator's
01291     //   evalModel(...) function.  matchesCurrentResults(...) would be able to 
01292     //   determine if evaluateResponse needs to be run, but 
01293     //   Albany::AggregateScalarReponseFunction does not copy from global g 
01294     //   to local g so the g parameter passed to this function will always 
01295     //   be zeros when used in an aggregate response fn.  Change this?
01296 
01297     // Evaluate response g and run algorithm (if it hasn't run already)
01298     //if(!matchesCurrentResults(*g)) 
01299     //  evaluateResponse(current_time, xdot, x, p, *g);
01300 
01301     mode = "Fill saddle point";
01302     Albany::FieldManagerScalarResponseFunction::evaluateTangent(
01303                 alpha, beta, omega, current_time, sum_derivs, xdot, xdotdot,
01304             x, p, deriv_p, Vxdot, Vxdotdot, Vx, Vp, g, gx, gp);
01305   }
01306   else {
01307     if (gx != NULL) gx->PutScalar(0.0);
01308     if (gp != NULL) gp->PutScalar(0.0);
01309   }
01310 }
01311 
01312 void
01313 QCAD::SaddleValueResponseFunction::
01314 evaluateGradient(const double current_time,
01315      const Epetra_Vector* xdot,
01316      const Epetra_Vector* xdotdot,
01317      const Epetra_Vector& x,
01318      const Teuchos::Array<ParamVec>& p,
01319      ParamVec* deriv_p,
01320      Epetra_Vector* g,
01321      Epetra_MultiVector* dg_dx,
01322      Epetra_MultiVector* dg_dxdot,
01323      Epetra_MultiVector* dg_dxdotdot,
01324      Epetra_MultiVector* dg_dp)
01325 {
01326 
01327   // Require that g be computed to get gradient info 
01328   if(g != NULL) {
01329 
01330     // Evaluate response g and run algorithm (if it hasn't run already)
01331     if(!matchesCurrentResults(*g)) 
01332       evaluateResponse(current_time, xdot, xdotdot, x, p, *g);
01333 
01334     mode = "Fill saddle point";
01335     Albany::FieldManagerScalarResponseFunction::evaluateGradient(
01336      current_time, xdot, xdotdot, x, p, deriv_p, g, dg_dx, dg_dxdot, dg_dxdotdot, dg_dp);
01337   }
01338   else {
01339     if (dg_dx != NULL)    dg_dx->PutScalar(0.0);
01340     if (dg_dxdot != NULL) dg_dxdot->PutScalar(0.0);
01341     if (dg_dp != NULL)    dg_dp->PutScalar(0.0);
01342   }
01343 }
01344 
01345 void 
01346 QCAD::SaddleValueResponseFunction::
01347 postProcessResponses(const Epetra_Comm& comm_, const Teuchos::RCP<Epetra_Vector>& g)
01348 {
01349 }
01350 
01351 void 
01352 QCAD::SaddleValueResponseFunction::
01353 postProcessResponseDerivatives(const Epetra_Comm& comm_, const Teuchos::RCP<Epetra_MultiVector>& gt)
01354 {
01355 }
01356 
01357 
01358 void
01359 QCAD::SaddleValueResponseFunction::
01360 getImagePointValues(const double current_time,
01361         const Epetra_Vector* xdot,
01362         const Epetra_Vector& x,
01363         const Teuchos::Array<ParamVec>& p,
01364         Epetra_Vector& g, 
01365         double* globalPtValues,
01366         double* globalPtWeights,
01367         double* globalPtGrads,
01368         std::vector<QCAD::mathVector> lastPositions,
01369         int dbMode)
01370 {
01371   //Set xmax,xmin,ymax,ymin based on points
01372   xmax = xmin = imagePts[0].coords[0];
01373   ymax = ymin = imagePts[0].coords[1];
01374   for(std::size_t i=1; i<nImagePts; i++) {
01375     xmin = std::min(imagePts[i].coords[0],xmin);
01376     xmax = std::max(imagePts[i].coords[0],xmax);
01377     ymin = std::min(imagePts[i].coords[1],ymin);
01378     ymax = std::max(imagePts[i].coords[1],ymax);
01379   }
01380   xmin -= 5*imagePtSize; xmax += 5*imagePtSize;
01381   ymin -= 5*imagePtSize; ymax += 5*imagePtSize;
01382     
01383   //Reset value, weight, and gradient of image points as these are accumulated by evaluator fill
01384   imagePtValues.fill(0.0);
01385   imagePtWeights.fill(0.0);
01386   imagePtGradComps.fill(0.0);
01387 
01388   if(bAggregateWorksets) {
01389     //Use cached field and coordinate values to perform fill    
01390     for(std::size_t i=0; i<vFieldValues.size(); i++) {
01391       addImagePointData( vCoords[i].data, vFieldValues[i], vGrads[i].data );
01392     } 
01393   }
01394   else {
01395     mode = "Collect image point data";
01396     Albany::FieldManagerScalarResponseFunction::evaluateResponse(
01397              current_time, xdot, NULL, x, p, g);
01398   }
01399 
01400   //MPI -- sum weights, value, and gradient for each image pt
01401   comm->SumAll( imagePtValues.data(),    globalPtValues,  nImagePts );
01402   comm->SumAll( imagePtWeights.data(),   globalPtWeights, nImagePts );
01403   comm->SumAll( imagePtGradComps.data(), globalPtGrads,   nImagePts*numDims );
01404 
01405   // Put summed data into imagePts, normalizing value and 
01406   //   gradient from different cell contributions
01407   for(std::size_t i=0; i<nImagePts; i++) {
01408     imagePts[i].weight = globalPtWeights[i];
01409     if(globalPtWeights[i] > 1e-6) {
01410       imagePts[i].value = globalPtValues[i] / imagePts[i].weight;
01411       for(std::size_t k=0; k<numDims; k++) 
01412   imagePts[i].grad[k] = globalPtGrads[k*nImagePts+i] / imagePts[i].weight;
01413     }
01414     else { 
01415       //assume point has drifted off region: leave value as, set gradient to zero, and reset position
01416       imagePts[i].grad.fill(0.0);
01417       imagePts[i].coords = lastPositions[i];
01418     }
01419   }
01420 
01421   return;
01422 }
01423 
01424 void
01425 QCAD::SaddleValueResponseFunction::
01426 getFinalImagePointValues(const double current_time,
01427         const Epetra_Vector* xdot,
01428         const Epetra_Vector& x,
01429         const Teuchos::Array<ParamVec>& p,
01430         Epetra_Vector& g, 
01431         int dbMode)
01432 {
01433   //Set xmax,xmin,ymax,ymin based on points
01434   xmax = xmin = imagePts[0].coords[0];
01435   ymax = ymin = imagePts[0].coords[1];
01436   for(std::size_t i=1; i<nImagePts; i++) {
01437     xmin = std::min(imagePts[i].coords[0],xmin);
01438     xmax = std::max(imagePts[i].coords[0],xmax);
01439     ymin = std::min(imagePts[i].coords[1],ymin);
01440     ymax = std::max(imagePts[i].coords[1],ymax);
01441   }
01442   xmin -= 5*imagePtSize; xmax += 5*imagePtSize;
01443   ymin -= 5*imagePtSize; ymax += 5*imagePtSize;
01444     
01445   //Reset value and weight of final image points as these are accumulated by evaluator fill
01446   finalPtValues.fill(0.0);
01447   finalPtWeights.fill(0.0);
01448 
01449   if(bAggregateWorksets) {
01450     //Use cached field and coordinate values to perform fill    
01451     for(std::size_t i=0; i<vFieldValues.size(); i++) {
01452       addFinalImagePointData( vCoords[i].data, vFieldValues[i] );
01453     } 
01454   }
01455   else {
01456     mode = "Collect final image point data";
01457     Albany::FieldManagerScalarResponseFunction::evaluateResponse(
01458              current_time, xdot, NULL, x, p, g);
01459   }
01460 
01461   //MPI -- sum weights, value, and gradient for each image pt
01462   std::size_t nFinalPts = finalPts.size();
01463   if(nFinalPts > 0) {
01464     double*  globalPtValues   = new double [nFinalPts];
01465     double*  globalPtWeights  = new double [nFinalPts];
01466     comm->SumAll( finalPtValues.data(),    globalPtValues,  nFinalPts );
01467     comm->SumAll( finalPtWeights.data(),   globalPtWeights, nFinalPts );
01468 
01469     // Put summed data into imagePts, normalizing value from different cell contributions
01470     for(std::size_t i=0; i<nFinalPts; i++) {
01471       finalPts[i].weight = globalPtWeights[i];
01472       finalPts[i].grad.fill(0.0); // don't use gradient -- always fill with zeros
01473 
01474       if(globalPtWeights[i] > 1e-6) 
01475   finalPts[i].value = globalPtValues[i] / finalPts[i].weight;
01476       else 
01477   finalPts[i].value = 0.0; // no weight, so just set value to zero
01478     }
01479   }
01480 
01481   return;
01482 }
01483 
01484 
01485 
01486 void
01487 QCAD::SaddleValueResponseFunction::
01488 writeOutput(int nIters)
01489 {
01490   // Write output every nEvery iterations
01491   if( (nEvery > 0) && (nIters % nEvery == 1) && (outputFilename.length() > 0)) {
01492     std::fstream out; double pathLength = 0.0;
01493     out.open(outputFilename.c_str(), std::fstream::out | std::fstream::app);
01494     out << std::endl << std::endl << "% NEB Iteration " << nIters << std::endl;
01495     out << "% index xCoord yCoord value pathLength pointRadius" << std::endl;
01496     for(std::size_t i=0; i<nImagePts; i++) {
01497       out << i << " " << imagePts[i].coords[0] << " " << imagePts[i].coords[1]
01498     << " " << imagePts[i].value << " " << pathLength << " " << imagePts[i].radius << std::endl;
01499       if(i<nImagePts-1) pathLength += imagePts[i].coords.distanceTo(imagePts[i+1].coords);
01500     }    
01501     out.close();
01502   }
01503 }
01504 
01505 void
01506 QCAD::SaddleValueResponseFunction::
01507 initialIterationSetup(double& gradScale, double& springScale, int dbMode)
01508 {
01509   const QCAD::mathVector& initialPt = imagePts[0].coords;
01510   const QCAD::mathVector& finalPt = imagePts[nImagePts-1].coords;
01511 
01512   double maxGradMag = 0.0, avgWeight = 0.0, ifDist;
01513   for(std::size_t i=0; i<nImagePts; i++) {
01514     maxGradMag = std::max(maxGradMag, imagePts[i].grad.norm());
01515     avgWeight += imagePts[i].weight;
01516   }
01517   ifDist = initialPt.distanceTo(finalPt);
01518   avgWeight /= nImagePts;
01519   gradScale = ifDist / maxGradMag;  // want scale*maxGradMag*(dt=1.0) = distance btw initial & final pts
01520 
01521   // want springScale * (baseSpringConst=1.0) * (initial distance btwn pts) = scale*maxGradMag = distance btwn initial & final pts
01522   //  so springScale = (nImagePts-1)
01523   springScale = (double) (nImagePts-1);
01524 
01525   if(dbMode) std::cout << "Saddle Point:  First iteration:  maxGradMag=" << maxGradMag
01526            << " |init-final|=" << ifDist << " gradScale=" << gradScale 
01527            << " springScale=" << springScale << " avgWeight=" << avgWeight << std::endl;
01528   return;
01529 }
01530 
01531 void
01532 QCAD::SaddleValueResponseFunction::
01533 computeTangent(std::size_t i, QCAD::mathVector& tangent, int dbMode)
01534 {
01535   // Compute tangent vector: use only higher neighboring imagePt.  
01536   //   Linear combination if both neighbors are above/below to smoothly interpolate cases
01537   double dValuePrev = imagePts[i-1].value - imagePts[i].value;
01538   double dValueNext = imagePts[i+1].value - imagePts[i].value;
01539 
01540   if(dValuePrev * dValueNext < 0.0) { //if both neighbors are either above or below current pt
01541     double dmax = std::max( fabs(dValuePrev), fabs(dValueNext) );
01542     double dmin = std::min( fabs(dValuePrev), fabs(dValueNext) );
01543     if(imagePts[i-1].value > imagePts[i+1].value)
01544       tangent = (imagePts[i+1].coords - imagePts[i].coords) * dmin + (imagePts[i].coords - imagePts[i-1].coords) * dmax;
01545     else
01546       tangent = (imagePts[i+1].coords - imagePts[i].coords) * dmax + (imagePts[i].coords - imagePts[i-1].coords) * dmin;
01547   }
01548   else {  //if one neighbor is above, the other below, just use the higher neighbor
01549     if(imagePts[i+1].value > imagePts[i].value)
01550       tangent = (imagePts[i+1].coords - imagePts[i].coords);
01551     else
01552       tangent = (imagePts[i].coords - imagePts[i-1].coords);
01553   }
01554   tangent.normalize();
01555   return;
01556 }
01557 
01558 void
01559 QCAD::SaddleValueResponseFunction::
01560 computeClimbingForce(std::size_t i, const QCAD::mathVector& tangent, const double& gradScale,
01561          QCAD::mathVector& force, int dbMode)
01562 {
01563   // Special case for highest point in climbing-NEB: force has full -Grad(V) but with parallel 
01564   //    component reversed and no force from springs (Future: add some perp spring force to avoid plateaus?)
01565   double dp = imagePts[i].grad.dot( tangent );
01566   force = (imagePts[i].grad * -1.0 + (tangent*dp) * 2) * gradScale; // force += -Grad(V) + 2*Grad(V)_parallel
01567 
01568   if(dbMode > 2) {
01569     std::cout << "Saddle Point:  --   tangent = " << tangent << std::endl;
01570     std::cout << "Saddle Point:  --   grad along tangent = " << dp << std::endl;
01571     std::cout << "Saddle Point:  --   total force (climbing) = " << force[i] << std::endl;
01572   }
01573 }
01574 
01575 void
01576 QCAD::SaddleValueResponseFunction::
01577 computeForce(std::size_t i, const QCAD::mathVector& tangent, const std::vector<double>& springConstants,
01578        const double& gradScale,  const double& springScale, QCAD::mathVector& force,
01579        double& dt, double& dt2, int dbMode)
01580 {
01581   force.fill(0.0);
01582   
01583   // Get gradient projected perpendicular to the tangent and add to the force
01584   double dp = imagePts[i].grad.dot( tangent );
01585   force -= (imagePts[i].grad - tangent * dp) * gradScale; // force += -Grad(V)_perp
01586 
01587   if(dbMode > 2) {
01588     std::cout << "Saddle Point:  --   tangent = " << tangent << std::endl;
01589     std::cout << "Saddle Point:  --   grad along tangent = " << dp << std::endl;
01590     std::cout << "Saddle Point:  --   grad force = " << force[i] << std::endl;
01591   }
01592 
01593   // Get spring force projected parallel to the tangent and add to the force
01594   mathVector dNext(numDims), dPrev(numDims);
01595   mathVector parallelSpringForce(numDims), perpSpringForce(numDims);
01596   mathVector springForce(numDims);
01597 
01598   dPrev = imagePts[i-1].coords - imagePts[i].coords;
01599   dNext = imagePts[i+1].coords - imagePts[i].coords;
01600 
01601   double prevNorm = dPrev.norm();
01602   double nextNorm = dNext.norm();
01603 
01604   double perpFactor = 0.5 * (1 + cos(3.141592 * fabs(dPrev.dot(dNext) / (prevNorm * nextNorm))));
01605   springForce = ((dNext * springConstants[i]) + (dPrev * springConstants[i-1]));
01606   parallelSpringForce = tangent * springForce.dot(tangent);
01607   perpSpringForce = (springForce - tangent * springForce.dot(tangent) );
01608   
01609   springForce = parallelSpringForce + perpSpringForce * (perpFactor * antiKinkFactor);  
01610   while(springForce.norm() * dt2 > std::max(dPrev.norm(),dNext.norm()) && dt > minTimeStep) {
01611     dt /= 2; dt2=dt*dt;
01612     if(dbMode > 2) std::cout << "Saddle Point:  ** Warning: spring forces seem too large: dt => " << dt << std::endl;
01613   }
01614 
01615   force += springForce; // force += springForce_parallel + part of springForce_perp
01616 
01617   if(dbMode > 2) {
01618     std::cout << "Saddle Point:  --   spring force = " << springForce << std::endl;
01619     std::cout << "Saddle Point:  --   total force = " << force[i] << std::endl;
01620   }
01621 }
01622 
01623 
01624 
01625 std::string QCAD::SaddleValueResponseFunction::getMode()
01626 {
01627   return mode;
01628 }
01629 
01630 
01631 bool QCAD::SaddleValueResponseFunction::
01632 pointIsInImagePtRegion(const double* p, double refZ) const
01633 {
01634   //assumes at least 2 dimensions
01635   if(numDims > 2 && (refZ < zmin || refZ > zmax)) return false;
01636   return !(p[0] < xmin || p[1] < ymin || p[0] > xmax || p[1] > ymax);
01637 }
01638 
01639 bool QCAD::SaddleValueResponseFunction::
01640 pointIsInAccumRegion(const double* p, double refZ) const
01641 {
01642   //assumes at least 2 dimensions
01643   if(numDims > 2 && (refZ < zmin || refZ > zmax)) return false;
01644   return true;
01645 }
01646 
01647 bool QCAD::SaddleValueResponseFunction::
01648 pointIsInLevelSetRegion(const double* p, double refZ) const
01649 {
01650   //assumes at least 2 dimensions
01651   if(numDims > 2 && (refZ < zmin || refZ > zmax)) return false;
01652   return (imagePts[iSaddlePt].coords.distanceTo(p) < levelSetRadius);
01653 }
01654 
01655 
01656 
01657 void QCAD::SaddleValueResponseFunction::
01658 addBeginPointData(const std::string& elementBlock, const double* p, double value)
01659 {
01660   //"Point" case: no need to process anything
01661   if( beginRegionType == "Point" ) return;
01662 
01663   //"Element Block" case: keep track of point with minimum value
01664   if( beginRegionType == "Element Block" ) {
01665     if(elementBlock == beginElementBlock) {
01666       if( value < imagePts[0].value || imagePts[0].weight == 0 ) {
01667   imagePts[0].value = value;
01668   imagePts[0].weight = 1.0; //positive weight flags initialization
01669   imagePts[0].coords.fill(p);
01670       }
01671     }
01672     return;
01673   }
01674 
01675   //"Polygon" case: keep track of point with minimum value
01676   if( beginRegionType == "Polygon" ) {
01677     if( QCAD::ptInPolygon(beginPolygon, p) ) {
01678       if( value < imagePts[0].value || imagePts[0].weight == 0 ) {
01679   imagePts[0].value = value;
01680   imagePts[0].weight = 1.0; //positive weight flags initialization
01681   imagePts[0].coords.fill(p);
01682       }
01683     }
01684     return;
01685   }
01686 
01687   TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl 
01688       << "Invalid region type: " << beginRegionType << " for begin pt" << std::endl); 
01689   return;
01690 }
01691 
01692 void QCAD::SaddleValueResponseFunction::
01693 addEndPointData(const std::string& elementBlock, const double* p, double value)
01694 {
01695   //"Point" case: no need to process anything
01696   if( endRegionType == "Point" ) return;
01697 
01698   //"Element Block" case: keep track of point with minimum value
01699   if( endRegionType == "Element Block" ) {
01700     if(elementBlock == endElementBlock) {
01701       if( value < imagePts[nImagePts-1].value || imagePts[nImagePts-1].weight == 0 ) {
01702   imagePts[nImagePts-1].value = value;
01703   imagePts[nImagePts-1].weight = 1.0; //positive weight flags initialization
01704   imagePts[nImagePts-1].coords.fill(p);
01705       }
01706     }
01707     return;
01708   }
01709 
01710   //"Polygon" case: keep track of point with minimum value
01711   if( endRegionType == "Polygon" ) {
01712     if( QCAD::ptInPolygon(endPolygon, p) ) {
01713       if( value < imagePts[nImagePts-1].value || imagePts[nImagePts-1].weight == 0 ) {
01714   imagePts[nImagePts-1].value = value;
01715   imagePts[nImagePts-1].weight = 1.0; //positive weight flags initialization
01716   imagePts[nImagePts-1].coords.fill(p);
01717       }
01718     }
01719     return;
01720   }
01721 
01722   TEUCHOS_TEST_FOR_EXCEPTION (true, Teuchos::Exceptions::InvalidParameter, std::endl 
01723       << "Invalid region type: " << endRegionType << " for end pt" << std::endl); 
01724   return;
01725 }
01726 
01727 
01728 void QCAD::SaddleValueResponseFunction::
01729 addImagePointData(const double* p, double value, double* grad)
01730 {
01731   double w, effDims = (bLockToPlane && numDims > 2) ? 2 : numDims;
01732   for(std::size_t i=0; i<nImagePts; i++) {
01733     w = pointFn(imagePts[i].coords.distanceTo(p) , imagePts[i].radius );
01734     if(w > 0) {
01735       imagePtWeights[i] += w;
01736       imagePtValues[i] += w*value;
01737       for(std::size_t k=0; k<effDims; k++)
01738   imagePtGradComps[k*nImagePts+i] += w*grad[k];
01739       //std::cout << "DEBUG Image Pt " << i << " close to (" << p[0] << "," << p[1] << "," << p[2] << ")=" << value
01740       //  << "  wt=" << w << "  totalW=" << imagePtWeights[i] << "  totalVal=" << imagePtValues[i]
01741       //  << "  val=" << imagePtValues[i] / imagePtWeights[i] << std::endl;
01742     }
01743   }
01744   return;
01745 }
01746 
01747 void QCAD::SaddleValueResponseFunction::
01748 addFinalImagePointData(const double* p, double value)
01749 {
01750   double w;
01751   for(std::size_t i=0; i< finalPts.size(); i++) {
01752     w = pointFn(finalPts[i].coords.distanceTo(p) , finalPts[i].radius );
01753     if(w > 0) {
01754       finalPtWeights[i] += w;
01755       finalPtValues[i] += w*value;
01756     }
01757   }
01758   return;
01759 }
01760 
01761 void QCAD::SaddleValueResponseFunction::
01762 accumulatePointData(const double* p, double value, double* grad)
01763 {
01764   vFieldValues.push_back(value);
01765   vCoords.push_back( QCAD::maxDimPt(p,numDims) );
01766   vGrads.push_back( QCAD::maxDimPt(grad,numDims) );
01767 }
01768 
01769 
01770 void QCAD::SaddleValueResponseFunction::
01771 accumulateLevelSetData(const double* p, double value, double cellArea)
01772 {
01773   vlsFieldValues.push_back(value);
01774   vlsCellAreas.push_back(cellArea);
01775   for(std::size_t i=0; i < numDims; ++i)
01776     vlsCoords[i].push_back(p[i]);
01777 }
01778  
01779 
01780 //Adds and returns the weight of a point relative to the saddle point position.
01781 double QCAD::SaddleValueResponseFunction::
01782 getSaddlePointWeight(const double* p) const
01783 {
01784   return pointFn(imagePts[iSaddlePt].coords.distanceTo(p) , imagePts[iSaddlePt].radius );
01785 }
01786 
01787 double QCAD::SaddleValueResponseFunction::
01788 getTotalSaddlePointWeight() const
01789 {
01790   return imagePts[iSaddlePt].weight;
01791 }
01792 
01793 const double* QCAD::SaddleValueResponseFunction::
01794 getSaddlePointPosition() const
01795 {
01796   return imagePts[iSaddlePt].coords.data();
01797 }
01798 
01799 bool QCAD::SaddleValueResponseFunction::
01800 matchesCurrentResults(Epetra_Vector& g) const
01801 {
01802   const double TOL = 1e-8;
01803 
01804   if(iSaddlePt < 0) return false;
01805 
01806   if( fabs(g[0] - returnFieldVal) > TOL || fabs(g[1] - imagePts[iSaddlePt].value) > TOL)
01807     return false;
01808 
01809   for(std::size_t i=0; i<numDims; i++) {
01810     if(  fabs(g[2+i] - imagePts[iSaddlePt].coords[i]) > TOL ) return false;
01811   }
01812 
01813   return true;
01814 }
01815 
01816 
01817 double QCAD::SaddleValueResponseFunction::
01818 pointFn(double d, double radius) const {
01819   //return ( d < radius ) ? 1.0 : 0.0;  //alternative?
01820 
01821   const double N = 1.0;
01822   double val = N*exp(-d*d / (2*radius*radius));
01823   return (val >= 1e-2) ? val : 0.0;
01824 }
01825 
01826 int QCAD::SaddleValueResponseFunction::
01827 getHighestPtIndex() const 
01828 {
01829   // Find the highest image point 
01830   int iHighestPt = 0; // init to the first point being the highest
01831   for(std::size_t i=1; i<nImagePts; i++) {
01832     if(imagePts[i].value > imagePts[iHighestPt].value) iHighestPt = i;
01833   }
01834   return iHighestPt;
01835 }
01836 
01837 
01838 
01839 /*************************************************************/
01841 /*************************************************************/
01842 
01843 /*double distanceFromLineSegment(const double* p, const double* p1, const double* p2, int dims)
01844 {
01845   //get pt c, the point along the full line p1->p2 closest to p
01846   double s, dp = 0, mag2 = 0; 
01847 
01848   for(int k=0; k<dims; k++) mag2 += pow(p2[k]-p1[k],2);
01849   for(int k=0; k<dims; k++) dp += (p[k]-p1[k])*(p2[k]-p1[k]);
01850   s = dp / sqrt(mag2); // < 0 or > 1 if c is outside segment, 0 <= s <= 1 if c is on segment
01851 
01852   if(0 <= s && s <= 1) { //just return distance between c and p
01853     double cp = 0;
01854     for(int k=0; k<dims; k++) cp += pow(p[k] - (p1[k]+s*(p2[k]-p1[k])),2);
01855     return sqrt(cp);
01856   }
01857   else { //take closer distance from the endpoints
01858     double d1=0, d2=0;
01859     for(int k=0; k<dims; k++) d1 += pow(p[k]-p1[k],2);
01860     for(int k=0; k<dims; k++) d2 += pow(p[k]-p2[k],2);
01861     if(d1 < d2) return sqrt(d1);
01862     else return sqrt(d2);
01863   }
01864   }*/
01865 
01866 // Returns true if point is inside polygon, false otherwise
01867 //  Assumes 2D points (more dims ok, but uses only first two components)
01868 //  Algorithm = ray trace along positive x-axis
01869 bool QCAD::ptInPolygon(const std::vector<QCAD::mathVector>& polygon, const QCAD::mathVector& pt) 
01870 {
01871   return QCAD::ptInPolygon(polygon, pt.data());
01872 }
01873 
01874 bool QCAD::ptInPolygon(const std::vector<QCAD::mathVector>& polygon, const double* pt)
01875 {
01876   bool c = false;
01877   int n = (int)polygon.size();
01878   double x=pt[0], y=pt[1];
01879   const int X=0,Y=1;
01880 
01881   for (int i = 0, j = n-1; i < n; j = i++) {
01882     const QCAD::mathVector& pi = polygon[i];
01883     const QCAD::mathVector& pj = polygon[j];
01884     if ((((pi[Y] <= y) && (y < pj[Y])) ||
01885    ((pj[Y] <= y) && (y < pi[Y]))) &&
01886   (x < (pj[X] - pi[X]) * (y - pi[Y]) / (pj[Y] - pi[Y]) + pi[X]))
01887       c = !c;
01888   }
01889   return c;
01890 }
01891 
01892 
01893 //Not used - but keep for reference
01894 // Returns true if point is inside polygon, false otherwise
01895 /*bool orig_ptInPolygon(int npol, float *xp, float *yp, float x, float y)
01896 {
01897   int i, j; bool c = false;
01898   for (i = 0, j = npol-1; i < npol; j = i++) {
01899     if ((((yp[i] <= y) && (y < yp[j])) ||
01900    ((yp[j] <= y) && (y < yp[i]))) &&
01901   (x < (xp[j] - xp[i]) * (y - yp[i]) / (yp[j] - yp[i]) + xp[i]))
01902       c = !c;
01903   }
01904   return c;
01905 }*/
01906 
01907 
01908 
01909 
01910 
01911 
01912 
01913 /*************************************************************/
01915 /*************************************************************/
01916 
01917 QCAD::mathVector::mathVector() 
01918 {
01919   dim_ = -1;
01920 }
01921 
01922 QCAD::mathVector::mathVector(int n) 
01923  :data_(n) 
01924 { 
01925   dim_ = n;
01926 }
01927 
01928 
01929 QCAD::mathVector::mathVector(const mathVector& copy) 
01930 { 
01931   data_ = copy.data_;
01932   dim_ = copy.dim_;
01933 }
01934 
01935 QCAD::mathVector::~mathVector() 
01936 {
01937 }
01938 
01939 
01940 void 
01941 QCAD::mathVector::resize(std::size_t n) 
01942 { 
01943   data_.resize(n); 
01944   dim_ = n;
01945 }
01946 
01947 void 
01948 QCAD::mathVector::fill(double d) 
01949 { 
01950   for(int i=0; i<dim_; i++) data_[i] = d;
01951 }
01952 
01953 void 
01954 QCAD::mathVector::fill(const double* vec) 
01955 { 
01956   for(int i=0; i<dim_; i++) data_[i] = vec[i];
01957 }
01958 
01959 double 
01960 QCAD::mathVector::dot(const mathVector& v2) const
01961 {
01962   double d=0;
01963   for(int i=0; i<dim_; i++)
01964     d += data_[i] * v2[i];
01965   return d;
01966 }
01967 
01968 QCAD::mathVector& 
01969 QCAD::mathVector::operator=(const mathVector& rhs)
01970 {
01971   data_ = rhs.data_;
01972   dim_ = rhs.dim_;
01973   return *this;
01974 }
01975 
01976 QCAD::mathVector 
01977 QCAD::mathVector::operator+(const mathVector& v2) const
01978 {
01979   mathVector result(dim_);
01980   for(int i=0; i<dim_; i++) result[i] = data_[i] + v2[i];
01981   return result;
01982 }
01983 
01984 QCAD::mathVector 
01985 QCAD::mathVector::operator-(const mathVector& v2) const
01986 {
01987   mathVector result(dim_);
01988   for(int i=0; i<dim_; i++) result[i] = data_[i] - v2[i];
01989   return result;
01990 }
01991 
01992 QCAD::mathVector
01993 QCAD::mathVector::operator*(double scale) const 
01994 {
01995   mathVector result(dim_);
01996   for(int i=0; i<dim_; i++) result[i] = scale*data_[i];
01997   return result;
01998 }
01999 
02000 QCAD::mathVector& 
02001 QCAD::mathVector::operator+=(const mathVector& v2)
02002 {
02003   for(int i=0; i<dim_; i++) data_[i] += v2[i];
02004   return *this;
02005 }
02006 
02007 QCAD::mathVector& 
02008 QCAD::mathVector::operator-=(const mathVector& v2) 
02009 {
02010   for(int i=0; i<dim_; i++) data_[i] -= v2[i];
02011   return *this;
02012 }
02013 
02014 QCAD::mathVector& 
02015 QCAD::mathVector::operator*=(double scale) 
02016 {
02017   for(int i=0; i<dim_; i++) data_[i] *= scale;
02018   return *this;
02019 }
02020 
02021 QCAD::mathVector&
02022 QCAD::mathVector::operator/=(double scale) 
02023 {
02024   for(int i=0; i<dim_; i++) data_[i] /= scale;
02025   return *this;
02026 }
02027 
02028 double&
02029 QCAD::mathVector::operator[](int i) 
02030 { 
02031   return data_[i];
02032 }
02033 
02034 const double& 
02035 QCAD::mathVector::operator[](int i) const 
02036 { 
02037   return data_[i];
02038 }
02039 
02040 double 
02041 QCAD::mathVector::distanceTo(const mathVector& v2) const
02042 {
02043   double d = 0.0;
02044   for(int i=0; i<dim_; i++) d += pow(data_[i]-v2[i],2);
02045   return sqrt(d);
02046 }
02047 
02048 double 
02049 QCAD::mathVector::distanceTo(const double* p) const
02050 {
02051   double d = 0.0;
02052   for(int i=0; i<dim_; i++) d += pow(data_[i]-p[i],2);
02053   return sqrt(d);
02054 }
02055          
02056 double 
02057 QCAD::mathVector::norm() const
02058 { 
02059   return sqrt(dot(*this)); 
02060 }
02061 
02062 double 
02063 QCAD::mathVector::norm2() const
02064 { 
02065   return dot(*this); 
02066 }
02067 
02068 
02069 void 
02070 QCAD::mathVector::normalize() 
02071 {
02072   (*this) /= norm(); 
02073 }
02074 
02075 const double* 
02076 QCAD::mathVector::data() const
02077 { 
02078   return data_.data();
02079 }
02080 
02081 double* 
02082 QCAD::mathVector::data()
02083 { 
02084   return data_.data();
02085 }
02086 
02087 
02088 std::size_t 
02089 QCAD::mathVector::size() const
02090 {
02091   return dim_; 
02092 }
02093 
02094 std::ostream& QCAD::operator<<(std::ostream& os, const QCAD::mathVector& mv) 
02095 {
02096   std::size_t size = mv.size();
02097   os << "(";
02098   for(std::size_t i=0; i<size-1; i++) os << mv[i] << ", ";
02099   if(size > 0) os << mv[size-1];
02100   os << ")";
02101   return os;
02102 }
02103 
02104 std::ostream& QCAD::operator<<(std::ostream& os, const QCAD::nebImagePt& np)
02105 {
02106   os << std::endl;
02107   os << "coords = " << np.coords << std::endl;
02108   os << "veloc  = " << np.velocity << std::endl;
02109   os << "grad   = " << np.grad << std::endl;
02110   os << "value  = " << np.value << std::endl;
02111   os << "weight = " << np.weight << std::endl;
02112   return os;
02113 }
02114 
02115 
02116 
02117 /*************************************************************/
02119 /*************************************************************/
02120 
02121 void QCAD::gatherVector(std::vector<double>& v, std::vector<double>& gv, const Epetra_Comm& comm_)
02122 {
02123   double *pvec, zeroSizeDummy = 0;
02124   pvec = (v.size() > 0) ? &v[0] : &zeroSizeDummy;
02125 
02126   Epetra_Map map(-1, v.size(), 0, comm_);
02127   Epetra_Vector ev(View, map, pvec);
02128   int  N = map.NumGlobalElements();
02129   Epetra_LocalMap lomap(N,0,comm_);
02130 
02131   gv.resize(N);
02132   pvec = (gv.size() > 0) ? &gv[0] : &zeroSizeDummy;
02133   Epetra_Vector egv(View, lomap, pvec);
02134   Epetra_Import import(lomap,map);
02135   egv.Import(ev, import, Insert);
02136 }
02137 
02138 bool QCAD::lessOp(std::pair<std::size_t, double> const& a,
02139       std::pair<std::size_t, double> const& b) {
02140   return a.second < b.second;
02141 }
02142 
02143 void QCAD::getOrdering(const std::vector<double>& v, std::vector<int>& ordering)
02144 {
02145   typedef std::vector<double>::const_iterator dbl_iter;
02146   typedef std::vector<std::pair<std::size_t, double> >::const_iterator pair_iter;
02147   std::vector<std::pair<std::size_t, double> > vPairs(v.size());
02148 
02149   size_t n = 0;
02150   for (dbl_iter it = v.begin(); it != v.end(); ++it, ++n)
02151     vPairs[n] = std::make_pair(n, *it);
02152 
02153 
02154   std::sort(vPairs.begin(), vPairs.end(), QCAD::lessOp);
02155 
02156   ordering.resize(v.size()); n = 0;
02157   for (pair_iter it = vPairs.begin(); it != vPairs.end(); ++it, ++n)
02158     ordering[n] = it->first;
02159 }
02160 
02161 
02162 double QCAD::averageOfVector(const std::vector<double>& v)
02163 {
02164   double avg = 0.0;
02165   for(std::size_t i=0; i < v.size(); i++) {
02166     avg += v[i];
02167   }
02168   avg /= v.size();
02169   return avg;
02170 }
02171 
02172 double QCAD::distance(const std::vector<double>* vCoords, int ind1, int ind2, std::size_t nDims)
02173 {
02174   double d2 = 0;
02175   for(std::size_t k=0; k<nDims; k++)
02176     d2 += pow( vCoords[k][ind1] - vCoords[k][ind2], 2 );
02177   return sqrt(d2);
02178 }

Generated on Wed Mar 26 2014 18:36:44 for Albany: a Trilinos-based PDE code by  doxygen 1.7.1