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

Albany_STKDiscretization.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 
00007 
00008 #include <limits>
00009 #include "Epetra_Export.h"
00010 
00011 #include "Albany_Utils.hpp"
00012 #include "Albany_STKDiscretization.hpp"
00013 #include "Albany_NodalGraphUtils.hpp"
00014 #include "Albany_STKNodeFieldContainer.hpp"
00015 
00016 #include <string>
00017 #include <iostream>
00018 #include <fstream>
00019 
00020 #include <Shards_BasicTopologies.hpp>
00021 #include "Shards_CellTopology.hpp"
00022 #include "Shards_CellTopologyData.h"
00023 
00024 #include <stk_util/parallel/Parallel.hpp>
00025 
00026 #include <stk_mesh/base/Entity.hpp>
00027 #include <stk_mesh/base/GetEntities.hpp>
00028 #include <stk_mesh/base/GetBuckets.hpp>
00029 #include <stk_mesh/base/FieldData.hpp>
00030 #include <stk_mesh/base/Selector.hpp>
00031 
00032 #include <PHAL_Dimension.hpp>
00033 
00034 #include <stk_mesh/fem/FEMHelpers.hpp>
00035 
00036 #ifdef ALBANY_SEACAS
00037 #include <Ionit_Initializer.h>
00038 #include <netcdf.h>
00039 
00040 #ifdef ALBANY_PAR_NETCDF
00041 extern "C" {
00042 #include <netcdf_par.h>
00043 }
00044 #endif
00045 #endif
00046 
00047 #include <algorithm>
00048 #include "EpetraExt_MultiVectorOut.h"
00049 
00050 const double pi = 3.1415926535897932385;
00051 
00052 //uncomment the following line if you want debug output to be printed to screen
00053 //#define OUTPUT_TO_SCREEN
00054 
00055 Albany::STKDiscretization::STKDiscretization(Teuchos::RCP<Albany::AbstractSTKMeshStruct> stkMeshStruct_,
00056                const Teuchos::RCP<const Epetra_Comm>& comm_,
00057                          const Teuchos::RCP<Piro::MLRigidBodyModes>& rigidBodyModes_) :
00058 
00059   out(Teuchos::VerboseObjectBase::getDefaultOStream()),
00060   previous_time_label(-1.0e32),
00061   metaData(*stkMeshStruct_->metaData),
00062   bulkData(*stkMeshStruct_->bulkData),
00063   comm(comm_),
00064   rigidBodyModes(rigidBodyModes_),
00065   neq(stkMeshStruct_->neq),
00066   stkMeshStruct(stkMeshStruct_),
00067   interleavedOrdering(stkMeshStruct_->interleavedOrdering)
00068 {
00069   Albany::STKDiscretization::updateMesh();
00070 }
00071 
00072 Albany::STKDiscretization::~STKDiscretization()
00073 {
00074 #ifdef ALBANY_SEACAS
00075   if (stkMeshStruct->exoOutput || stkMeshStruct->cdfOutput) delete mesh_data;
00076 
00077   if (stkMeshStruct->cdfOutput)
00078     if (const int ierr = nc_close (netCDFp))
00079       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
00080         "close returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
00081 
00082 #endif
00083 
00084   for (int i=0; i< toDelete.size(); i++) delete [] toDelete[i];
00085 }
00086 
00087 
00088 Teuchos::RCP<const Epetra_Map>
00089 Albany::STKDiscretization::getMap() const
00090 {
00091   return map;
00092 }
00093 
00094 Teuchos::RCP<const Epetra_Map>
00095 Albany::STKDiscretization::getOverlapMap() const
00096 {
00097   return overlap_map;
00098 }
00099 
00100 Teuchos::RCP<const Epetra_CrsGraph>
00101 Albany::STKDiscretization::getJacobianGraph() const
00102 {
00103   return graph;
00104 }
00105 
00106 Teuchos::RCP<const Epetra_CrsGraph>
00107 Albany::STKDiscretization::getOverlapJacobianGraph() const
00108 {
00109   return overlap_graph;
00110 }
00111 
00112 Teuchos::RCP<const Epetra_Map>
00113 Albany::STKDiscretization::getNodeMap() const
00114 {
00115   return node_map;
00116 }
00117 
00118 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<Teuchos::ArrayRCP<int> > > >::type&
00119 Albany::STKDiscretization::getWsElNodeEqID() const
00120 {
00121   return wsElNodeEqID;
00122 }
00123 
00124 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<int> > >::type&
00125 Albany::STKDiscretization::getWsElNodeID() const
00126 {
00127   return wsElNodeID;
00128 }
00129 
00130 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double*> > >::type&
00131 Albany::STKDiscretization::getCoords() const
00132 {
00133   return coords;
00134 }
00135 
00136 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double> > >::type&
00137 Albany::STKDiscretization::getSurfaceHeight() const
00138 {
00139   return sHeight;
00140 }
00141 
00142 const Albany::WorksetArray<Teuchos::ArrayRCP<double> >::type&
00143 Albany::STKDiscretization::getTemperature() const
00144 {
00145   return temperature;
00146 }
00147 
00148 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double> > >::type&
00149 Albany::STKDiscretization::getBasalFriction() const
00150 {
00151   return basalFriction;
00152 }
00153 
00154 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double> > >::type&
00155 Albany::STKDiscretization::getThickness() const
00156 {
00157   return thickness;
00158 }
00159 
00160 const Albany::WorksetArray<Teuchos::ArrayRCP<double> >::type&
00161 Albany::STKDiscretization::getFlowFactor() const
00162 {
00163   return flowFactor;
00164 }
00165 
00166 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double*> > >::type&
00167 Albany::STKDiscretization::getSurfaceVelocity() const
00168 {
00169   return surfaceVelocity;
00170 }
00171 
00172 const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double*> > >::type&
00173 Albany::STKDiscretization::getVelocityRMS() const
00174 {
00175   return velocityRMS;
00176 }
00177 
00178 void
00179 Albany::STKDiscretization::printCoords() const
00180 {
00181 
00182 std::cout << "Processor " << bulkData.parallel_rank() << " has " << coords.size() << " worksets." << std::endl;
00183 
00184        for (int ws=0; ws<coords.size(); ws++) {  //workset
00185          for (int e=0; e<coords[ws].size(); e++) { //cell
00186            for (int j=0; j<coords[ws][e].size(); j++) { //node
00187              for (int d=0; d<stkMeshStruct->numDim; d++){  //node
00188 std::cout << "Coord for workset: " << ws << " element: " << e << " node: " << j << " DOF: " << d << " is: " <<
00189                 coords[ws][e][j][d] << std::endl;
00190        } } } }
00191 
00192 }
00193 
00194 
00195 Teuchos::ArrayRCP<double>&
00196 Albany::STKDiscretization::getCoordinates() const
00197 {
00198   // Coordinates are computed here, and not precomputed,
00199   // since the mesh can move in shape opt problems
00200 
00201   AbstractSTKFieldContainer::VectorFieldType* coordinates_field = stkMeshStruct->getCoordinatesField();
00202 
00203   for (int i=0; i < numOverlapNodes; i++)  {
00204     int node_gid = gid(overlapnodes[i]);
00205     int node_lid = overlap_node_map->LID(node_gid);
00206 
00207     double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00208     for (int dim=0; dim<stkMeshStruct->numDim; dim++)
00209       coordinates[3*node_lid + dim] = x[dim];
00210 
00211   }
00212 
00213   return coordinates;
00214 }
00215 
00216 //The function transformMesh() maps a unit cube domain by applying the transformation
00217 //x = L*x
00218 //y = L*y
00219 //z = s(x,y)*z + b(x,y)*(1-z)
00220 //where b(x,y) and s(x,y) are curves specifying the bedrock and top surface
00221 //geometries respectively.
00222 //Currently this function is only needed for some FELIX problems.
00223 
00224 
00225 void
00226 Albany::STKDiscretization::transformMesh()
00227 {
00228   using std::cout; using std::endl;
00229   AbstractSTKFieldContainer::VectorFieldType* coordinates_field = stkMeshStruct->getCoordinatesField();
00230   std::string transformType = stkMeshStruct->transformType;
00231 
00232   if (transformType == "None") {}
00233 #ifdef ALBANY_FELIX
00234   else if (transformType == "ISMIP-HOM Test A") {
00235 #ifdef OUTPUT_TO_SCREEN
00236     *out << "Test A!" << endl;
00237 #endif
00238     double L = stkMeshStruct->felixL;
00239     double alpha = stkMeshStruct->felixAlpha;
00240 #ifdef OUTPUT_TO_SCREEN
00241     *out << "L: " << L << endl;
00242     *out << "alpha degrees: " << alpha << endl;
00243 #endif
00244     alpha = alpha*pi/180; //convert alpha, read in from ParameterList, to radians
00245 #ifdef OUTPUT_TO_SCREEN
00246     *out << "alpha radians: " << alpha << endl;
00247 #endif
00248     stkMeshStruct->PBCStruct.scale[0]*=L;
00249     stkMeshStruct->PBCStruct.scale[1]*=L;
00250     AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field = stkMeshStruct->getFieldContainer()->getSurfaceHeightField();
00251     for (int i=0; i < numOverlapNodes; i++)  {
00252       double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00253       x[0] = L*x[0];
00254       x[1] = L*x[1];
00255       double s = -x[0]*tan(alpha);
00256       double b = s - 1.0 + 0.5*sin(2*pi/L*x[0])*sin(2*pi/L*x[1]);
00257       x[2] = s*x[2] + b*(1-x[2]);
00258       *stk::mesh::field_data(*surfaceHeight_field, *overlapnodes[i]) = s;
00259      }
00260    }
00261   else if (transformType == "ISMIP-HOM Test B") {
00262 #ifdef OUTPUT_TO_SCREEN
00263     *out << "Test B!" << endl;
00264 #endif
00265     double L = stkMeshStruct->felixL;
00266     double alpha = stkMeshStruct->felixAlpha;
00267 #ifdef OUTPUT_TO_SCREEN
00268     *out << "L: " << L << endl;
00269     *out << "alpha degrees: " << alpha << endl;
00270 #endif
00271     alpha = alpha*pi/180; //convert alpha, read in from ParameterList, to radians
00272 #ifdef OUTPUT_TO_SCREEN
00273     *out << "alpha radians: " << alpha << endl;
00274 #endif
00275     stkMeshStruct->PBCStruct.scale[0]*=L;
00276     stkMeshStruct->PBCStruct.scale[1]*=L;
00277     AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field = stkMeshStruct->getFieldContainer()->getSurfaceHeightField();
00278     for (int i=0; i < numOverlapNodes; i++)  {
00279       double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00280       x[0] = L*x[0];
00281       x[1] = L*x[1];
00282       double s = -x[0]*tan(alpha);
00283       double b = s - 1.0 + 0.5*sin(2*pi/L*x[0]);
00284       x[2] = s*x[2] + b*(1-x[2]);
00285       *stk::mesh::field_data(*surfaceHeight_field, *overlapnodes[i]) = s;
00286      }
00287    }
00288    else if ((transformType == "ISMIP-HOM Test C") || (transformType == "ISMIP-HOM Test D")) {
00289 #ifdef OUTPUT_TO_SCREEN
00290     *out << "Test C and D!" << endl;
00291 #endif
00292     double L = stkMeshStruct->felixL;
00293     double alpha = stkMeshStruct->felixAlpha;
00294 #ifdef OUTPUT_TO_SCREEN
00295     *out << "L: " << L << endl;
00296     *out << "alpha degrees: " << alpha << endl;
00297 #endif
00298     alpha = alpha*pi/180; //convert alpha, read in from ParameterList, to radians
00299 #ifdef OUTPUT_TO_SCREEN
00300     *out << "alpha radians: " << alpha << endl;
00301 #endif
00302     stkMeshStruct->PBCStruct.scale[0]*=L;
00303     stkMeshStruct->PBCStruct.scale[1]*=L;
00304     AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field = stkMeshStruct->getFieldContainer()->getSurfaceHeightField();
00305     for (int i=0; i < numOverlapNodes; i++)  {
00306       double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00307       x[0] = L*x[0];
00308       x[1] = L*x[1];
00309       double s = -x[0]*tan(alpha);
00310       double b = s - 1.0;
00311       x[2] = s*x[2] + b*(1-x[2]);
00312       *stk::mesh::field_data(*surfaceHeight_field, *overlapnodes[i]) = s;
00313      }
00314    }
00315    else if (transformType == "Dome") {
00316 #ifdef OUTPUT_TO_SCREEN
00317     *out << "Dome transform!" << endl;
00318 #endif
00319     double L = 0.7071*30;
00320     stkMeshStruct->PBCStruct.scale[0]*=L;
00321     stkMeshStruct->PBCStruct.scale[1]*=L;
00322     AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field = stkMeshStruct->getFieldContainer()->getSurfaceHeightField();
00323     for (int i=0; i < numOverlapNodes; i++)  {
00324       double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00325       x[0] = L*x[0];
00326       x[1] = L*x[1];
00327       double s = 0.7071*sqrt(450.0 - x[0]*x[0] - x[1]*x[1])/sqrt(450.0);
00328       x[2] = s*x[2];
00329       *stk::mesh::field_data(*surfaceHeight_field, *overlapnodes[i]) = s;
00330     }
00331   }
00332    else if (transformType == "Confined Shelf") {
00333 #ifdef OUTPUT_TO_SCREEN
00334     *out << "Confined shelf transform!" << endl;
00335 #endif
00336     double L = stkMeshStruct->felixL;
00337     cout << "L: " << L << endl;
00338     stkMeshStruct->PBCStruct.scale[0]*=L;
00339     stkMeshStruct->PBCStruct.scale[1]*=L;
00340     AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field = stkMeshStruct->getFieldContainer()->getSurfaceHeightField();
00341     for (int i=0; i < numOverlapNodes; i++)  {
00342       double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00343       x[0] = L*x[0];
00344       x[1] = L*x[1];
00345       double s = 0.06; //top surface is at z=0.06km=60m
00346       double b = -0.440; //basal surface is at z=-0.440km=-440m
00347       x[2] = s*x[2] + b*(1.0-x[2]);
00348       *stk::mesh::field_data(*surfaceHeight_field, *overlapnodes[i]) = s;
00349     }
00350   }
00351   else if (transformType == "Circular Shelf") {
00352 #ifdef OUTPUT_TO_SCREEN
00353     *out << "Circular shelf transform!" << endl;
00354 #endif
00355     double L = stkMeshStruct->felixL;
00356 #ifdef OUTPUT_TO_SCREEN
00357     *out << "L: " << L << endl;
00358 #endif
00359     double rhoIce = 910.0; //ice density, in kg/m^3
00360     double rhoOcean = 1028.0; //ocean density, in kg/m^3
00361     stkMeshStruct->PBCStruct.scale[0]*=L;
00362     stkMeshStruct->PBCStruct.scale[1]*=L;
00363     AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field = stkMeshStruct->getFieldContainer()->getSurfaceHeightField();
00364     for (int i=0; i < numOverlapNodes; i++)  {
00365       double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00366       x[0] = L*x[0];
00367       x[1] = L*x[1];
00368       double s = 1.0-rhoIce/rhoOcean; //top surface is at z=(1-rhoIce/rhoOcean) km
00369       double b = s - 1.0; //basal surface is at z=s-1 km
00370       x[2] = s*x[2] + b*(1.0-x[2]);
00371       *stk::mesh::field_data(*surfaceHeight_field, *overlapnodes[i]) = s;
00372     }
00373   }
00374 #endif
00375 #ifdef ALBANY_AERAS
00376   else if (transformType == "Aeras Schar Mountain") {
00377     *out << "Aeras Schar Mountain transformation!" << endl;
00378     double rhoOcean = 1028.0; //ocean density, in kg/m^3
00379     for (int i=0; i < numOverlapNodes; i++)  {
00380       double* x = stk::mesh::field_data(*coordinates_field, *overlapnodes[i]);
00381       x[0] = x[0];
00382       double hstar = 0.0, h;
00383       if (std::abs(x[0]-150.0) <= 25.0) hstar = 3.0* std::pow(cos(M_PI*(x[0]-150.0) / 50.0),2);
00384       h = hstar * std::pow(cos(M_PI*(x[0]-150.0) / 8.0),2);
00385       x[1] = x[1] + h*(25.0 - x[1])/25.0;
00386     }
00387   }
00388 #endif
00389   else {
00390     TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
00391       "STKDiscretization::transformMesh() Unknown transform type :" << transformType << std::endl);
00392   }
00393 }
00394 
00395 void
00396 Albany::STKDiscretization::setupMLCoords()
00397 {
00398 
00399   // if ML is not used, return
00400 
00401   if(rigidBodyModes.is_null()) return;
00402 
00403   if(!rigidBodyModes->isMLUsed()) return;
00404 
00405   // Function to return x,y,z at owned nodes as double*, specifically for ML
00406   int numDim = stkMeshStruct->numDim;
00407   AbstractSTKFieldContainer::VectorFieldType* coordinates_field = stkMeshStruct->getCoordinatesField();
00408 
00409   rigidBodyModes->resize(numDim, numOwnedNodes);
00410 
00411   double *xx;
00412   double *yy;
00413   double *zz;
00414 
00415   rigidBodyModes->getCoordArrays(&xx, &yy, &zz);
00416 
00417   for (int i=0; i < numOwnedNodes; i++)  {
00418     int node_gid = gid(ownednodes[i]);
00419     int node_lid = node_map->LID(node_gid);
00420 
00421     double* X = stk::mesh::field_data(*coordinates_field, *ownednodes[i]);
00422     if (numDim > 0) xx[node_lid] = X[0];
00423     if (numDim > 1) yy[node_lid] = X[1];
00424     if (numDim > 2) zz[node_lid] = X[2];
00425   }
00426 
00427 
00428   //see if user wants to write the coordinates to matrix market file
00429   bool writeCoordsToMMFile = stkMeshStruct->writeCoordsToMMFile;
00430   //if user wants to write the coordinates to matrix market file, write them to matrix market file
00431   if (writeCoordsToMMFile == true) {
00432     if (node_map->Comm().MyPID()==0) {std::cout << "Writing mesh coordinates to Matrix Market file." << std::endl;}
00433     //Writing of coordinates to MatrixMarket file for Ray
00434     Epetra_Vector xCoords(Copy, *node_map, xx);
00435     EpetraExt::MultiVectorToMatrixMarketFile("xCoords.mm", xCoords);
00436     if (yy != NULL) {
00437       Epetra_Vector yCoords(Copy, *node_map, yy);
00438       EpetraExt::MultiVectorToMatrixMarketFile("yCoords.mm", yCoords);
00439     }
00440     if (zz != NULL){
00441       Epetra_Vector zCoords(Copy, *node_map, zz);
00442       EpetraExt::MultiVectorToMatrixMarketFile("zCoords.mm", zCoords);
00443     }
00444   }
00445 
00446   rigidBodyModes->informML();
00447 
00448 }
00449 
00450 
00451 const Albany::WorksetArray<std::string>::type&
00452 Albany::STKDiscretization::getWsEBNames() const
00453 {
00454   return wsEBNames;
00455 }
00456 
00457 const Albany::WorksetArray<int>::type&
00458 Albany::STKDiscretization::getWsPhysIndex() const
00459 {
00460   return wsPhysIndex;
00461 }
00462 
00463 //void Albany::STKDiscretization::outputToExodus(const Epetra_Vector& soln, const double time, const bool overlapped)
00464 void Albany::STKDiscretization::writeSolution(const Epetra_Vector& soln, const double time, const bool overlapped){
00465 
00466   // Put solution as Epetra_Vector into STK Mesh
00467   if(!overlapped)
00468 
00469     setSolutionField(soln);
00470 
00471   // soln coming in is overlapped
00472   else
00473 
00474     setOvlpSolutionField(soln);
00475 
00476 
00477 #ifdef ALBANY_SEACAS
00478 
00479   if (stkMeshStruct->exoOutput && stkMeshStruct->transferSolutionToCoords) {
00480 
00481    Teuchos::RCP<AbstractSTKFieldContainer> container = stkMeshStruct->getFieldContainer();
00482 
00483    container->transferSolutionToCoords();
00484 
00485    if (mesh_data != NULL) {
00486 
00487      // Mesh coordinates have changed. Rewrite output file by deleting the mesh data object and recreate it
00488      delete mesh_data;
00489      setupExodusOutput();
00490 
00491    }
00492   }
00493 
00494 
00495    // Skip this write unless the proper interval has been reached
00496   if (stkMeshStruct->exoOutput && !(outputInterval % stkMeshStruct->exoOutputInterval)) {
00497 
00498      double time_label = monotonicTimeLabel(time);
00499 
00500      int out_step = stk::io::process_output_request(*mesh_data, bulkData, time_label);
00501 
00502      if (map->Comm().MyPID()==0) {
00503        *out << "Albany::STKDiscretization::writeSolution: writing time " << time;
00504        if (time_label != time) *out << " with label " << time_label;
00505        *out << " to index " <<out_step<<" in file "<<stkMeshStruct->exoOutFile<< std::endl;
00506      }
00507   }
00508   if (stkMeshStruct->cdfOutput && !(outputInterval % stkMeshStruct->cdfOutputInterval)) {
00509 
00510      double time_label = monotonicTimeLabel(time);
00511 
00512      const int out_step = processNetCDFOutputRequest();
00513 
00514      if (map->Comm().MyPID()==0) {
00515        *out << "Albany::STKDiscretization::writeSolution: writing time " << time;
00516        if (time_label != time) *out << " with label " << time_label;
00517        *out << " to index " <<out_step<<" in file "<<stkMeshStruct->cdfOutFile<< std::endl;
00518      }
00519   }
00520   outputInterval++;
00521 #endif
00522 }
00523 
00524 double
00525 Albany::STKDiscretization::monotonicTimeLabel(const double time)
00526 {
00527   // If increasing, then all is good
00528   if (time > previous_time_label) {
00529     previous_time_label = time;
00530     return time;
00531   }
00532 // Try absolute value
00533   double time_label = fabs(time);
00534   if (time_label > previous_time_label) {
00535     previous_time_label = time_label;
00536     return time_label;
00537   }
00538 
00539   // Try adding 1.0 to time
00540   if (time_label+1.0 > previous_time_label) {
00541     previous_time_label = time_label+1.0;
00542     return time_label+1.0;
00543   }
00544 
00545   // Otherwise, just add 1.0 to previous
00546   previous_time_label += 1.0;
00547   return previous_time_label;
00548 }
00549 
00550 void
00551 Albany::STKDiscretization::setResidualField(const Epetra_Vector& residual)
00552 {
00553 #ifdef ALBANY_LCM
00554   Teuchos::RCP<AbstractSTKFieldContainer> container = stkMeshStruct->getFieldContainer();
00555 
00556   if(container->hasResidualField()){
00557 
00558     // Iterate over the on-processor nodes
00559     stk::mesh::Selector locally_owned = metaData.locally_owned_part();
00560 
00561     container->saveResVector(residual, locally_owned, node_map);
00562 
00563     // Write the overlapped data
00564 //    stk::mesh::Selector select_owned_or_shared = metaData.locally_owned_part() | metaData.globally_shared_part();
00565 
00566 //    container->saveResVector(residual, select_owned_or_shared, overlap_node_map);
00567   }
00568 #endif
00569 }
00570 
00571 Teuchos::RCP<Epetra_Vector>
00572 Albany::STKDiscretization::getSolutionField() const
00573 {
00574   // Copy soln vector into solution field, one node at a time
00575   Teuchos::RCP<Epetra_Vector> soln = Teuchos::rcp(new Epetra_Vector(*map));
00576   this->getSolutionField(*soln);
00577   return soln;
00578 }
00579 
00580 int
00581 Albany::STKDiscretization::getSolutionFieldHistoryDepth() const
00582 {
00583   return stkMeshStruct->getSolutionFieldHistoryDepth();
00584 }
00585 
00586 Teuchos::RCP<Epetra_MultiVector>
00587 Albany::STKDiscretization::getSolutionFieldHistory() const
00588 {
00589   const int stepCount = this->getSolutionFieldHistoryDepth();
00590   return this->getSolutionFieldHistoryImpl(stepCount);
00591 }
00592 
00593 Teuchos::RCP<Epetra_MultiVector>
00594 Albany::STKDiscretization::getSolutionFieldHistory(int maxStepCount) const
00595 {
00596   const int stepCount = std::min(this->getSolutionFieldHistoryDepth(), maxStepCount);
00597   return this->getSolutionFieldHistoryImpl(stepCount);
00598 }
00599 
00600 void
00601 Albany::STKDiscretization::getSolutionFieldHistory(Epetra_MultiVector &result) const
00602 {
00603   TEUCHOS_TEST_FOR_EXCEPT(!this->map->SameAs(result.Map()));
00604   const int stepCount = std::min(this->getSolutionFieldHistoryDepth(), result.NumVectors());
00605   Epetra_MultiVector head(View, result, 0, stepCount);
00606   this->getSolutionFieldHistoryImpl(head);
00607 }
00608 
00609 Teuchos::RCP<Epetra_MultiVector>
00610 Albany::STKDiscretization::getSolutionFieldHistoryImpl(int stepCount) const
00611 {
00612   const int vectorCount = stepCount > 0 ? stepCount : 1; // A valid MultiVector has at least one vector
00613   const Teuchos::RCP<Epetra_MultiVector> result = Teuchos::rcp(new Epetra_MultiVector(*map, vectorCount));
00614   if (stepCount > 0) {
00615     this->getSolutionFieldHistoryImpl(*result);
00616   }
00617   return result;
00618 }
00619 
00620 void
00621 Albany::STKDiscretization::getSolutionFieldHistoryImpl(Epetra_MultiVector &result) const
00622 {
00623   const int stepCount = result.NumVectors();
00624   for (int i = 0; i < stepCount; ++i) {
00625     stkMeshStruct->loadSolutionFieldHistory(i);
00626     Epetra_Vector v(View, result, i);
00627     this->getSolutionField(v);
00628   }
00629 }
00630 
00631 void
00632 Albany::STKDiscretization::getSolutionField(Epetra_Vector &result) const
00633 {
00634 
00635   Teuchos::RCP<AbstractSTKFieldContainer> container = stkMeshStruct->getFieldContainer();
00636 
00637   // Iterate over the on-processor nodes by getting node buckets and iterating over each bucket.
00638   stk::mesh::Selector locally_owned = metaData.locally_owned_part();
00639 
00640   container->fillSolnVector(result, locally_owned, node_map);
00641 
00642 }
00643 
00644 /*****************************************************************/
00645 /*** Private functions follow. These are just used in above code */
00646 /*****************************************************************/
00647 
00648 void
00649 Albany::STKDiscretization::setSolutionField(const Epetra_Vector& soln)
00650 {
00651   // Copy soln vector into solution field, one node at a time
00652   // Note that soln coming in is the local (non overlapped) soln
00653 
00654   Teuchos::RCP<AbstractSTKFieldContainer> container = stkMeshStruct->getFieldContainer();
00655 
00656   // Iterate over the on-processor nodes
00657   stk::mesh::Selector locally_owned = metaData.locally_owned_part();
00658 
00659   container->saveSolnVector(soln, locally_owned, node_map);
00660 
00661 }
00662 
00663 void
00664 Albany::STKDiscretization::setOvlpSolutionField(const Epetra_Vector& soln)
00665 {
00666   // Copy soln vector into solution field, one node at a time
00667   // Note that soln coming in is the local+ghost (overlapped) soln
00668 
00669   Teuchos::RCP<AbstractSTKFieldContainer> container = stkMeshStruct->getFieldContainer();
00670 
00671   // Iterate over the processor-visible nodes
00672   stk::mesh::Selector select_owned_or_shared = metaData.locally_owned_part() | metaData.globally_shared_part();
00673 
00674   container->saveSolnVector(soln, select_owned_or_shared, overlap_node_map);
00675 
00676 }
00677 
00678 inline int Albany::STKDiscretization::gid(const stk::mesh::Entity& node) const
00679 { return node.identifier()-1; }
00680 
00681 inline int Albany::STKDiscretization::gid(const stk::mesh::Entity* node) const
00682 { return gid(*node); }
00683 
00684 int Albany::STKDiscretization::getOwnedDOF(const int inode, const int eq) const
00685 {
00686   if (interleavedOrdering) return inode*neq + eq;
00687   else  return inode + numOwnedNodes*eq;
00688 }
00689 
00690 int Albany::STKDiscretization::getOverlapDOF(const int inode, const int eq) const
00691 {
00692   if (interleavedOrdering) return inode*neq + eq;
00693   else  return inode + numOverlapNodes*eq;
00694 }
00695 
00696 int Albany::STKDiscretization::getGlobalDOF(const int inode, const int eq) const
00697 {
00698   if (interleavedOrdering) return inode*neq + eq;
00699   else  return inode + numGlobalNodes*eq;
00700 }
00701 
00702 int Albany::STKDiscretization::nonzeroesPerRow(const int neq) const
00703 {
00704   int numDim = stkMeshStruct->numDim;
00705   int estNonzeroesPerRow;
00706   switch (numDim) {
00707   case 0: estNonzeroesPerRow=1*neq; break;
00708   case 1: estNonzeroesPerRow=3*neq; break;
00709   case 2: estNonzeroesPerRow=9*neq; break;
00710   case 3: estNonzeroesPerRow=27*neq; break;
00711   default: TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
00712             "STKDiscretization:  Bad numDim"<< numDim);
00713   }
00714   return estNonzeroesPerRow;
00715 }
00716 
00717 void Albany::STKDiscretization::computeOwnedNodesAndUnknowns()
00718 {
00719   // Loads member data:  ownednodes, numOwnedNodes, node_map, numGlobalNodes, map
00720   // maps for owned nodes and unknowns
00721   stk::mesh::Selector select_owned_in_part =
00722     stk::mesh::Selector( metaData.universal_part() ) &
00723     stk::mesh::Selector( metaData.locally_owned_part() );
00724 
00725   stk::mesh::get_selected_entities( select_owned_in_part ,
00726             bulkData.buckets( metaData.node_rank() ) ,
00727             ownednodes );
00728 
00729   numOwnedNodes = ownednodes.size();
00730   std::vector<int> indices(numOwnedNodes);
00731   for (int i=0; i < numOwnedNodes; i++) 
00732 
00733     indices[i] = gid(ownednodes[i]);
00734 
00735   node_map = Teuchos::null; // delete existing map happens here on remesh
00736 
00737   node_map = Teuchos::rcp(new Epetra_Map(-1, numOwnedNodes,
00738            &(indices[0]), 0, *comm));
00739 
00740   numGlobalNodes = node_map->MaxAllGID() + 1;
00741 
00742   if(Teuchos::nonnull(stkMeshStruct->nodal_data_block))
00743     stkMeshStruct->nodal_data_block->resizeLocalMap(indices, *comm);
00744 
00745   indices.resize(numOwnedNodes * neq);
00746   for (int i=0; i < numOwnedNodes; i++)
00747     for (std::size_t j=0; j < neq; j++)
00748       indices[getOwnedDOF(i,j)] = getGlobalDOF(gid(ownednodes[i]),j);
00749 
00750   map = Teuchos::null; // delete existing map happens here on remesh
00751 
00752   map = Teuchos::rcp(new Epetra_Map(-1, indices.size(), &(indices[0]), 0, *comm));
00753 
00754 
00755 }
00756 
00757 void Albany::STKDiscretization::computeOverlapNodesAndUnknowns()
00758 {
00759   // Loads member data:  overlapodes, numOverlapodes, overlap_node_map, coordinates
00760   std::vector<int> indices;
00761   // maps for overlap unknowns
00762   stk::mesh::Selector select_overlap_in_part =
00763     stk::mesh::Selector( metaData.universal_part() ) &
00764     ( stk::mesh::Selector( metaData.locally_owned_part() )
00765       | stk::mesh::Selector( metaData.globally_shared_part() ) );
00766 
00767   //  overlapnodes used for overlap map -- stored for changing coords
00768   stk::mesh::get_selected_entities( select_overlap_in_part ,
00769             bulkData.buckets( metaData.node_rank() ) ,
00770             overlapnodes );
00771 
00772   numOverlapNodes = overlapnodes.size();
00773   indices.resize(numOverlapNodes * neq);
00774   for (int i=0; i < numOverlapNodes; i++)
00775     for (std::size_t j=0; j < neq; j++)
00776       indices[getOverlapDOF(i,j)] = getGlobalDOF(gid(overlapnodes[i]),j);
00777 
00778   overlap_map = Teuchos::null; // delete existing map happens here on remesh
00779 
00780   overlap_map = Teuchos::rcp(new Epetra_Map(-1, indices.size(),
00781               &(indices[0]), 0, *comm));
00782 
00783   // Set up epetra map of node IDs
00784   indices.resize(numOverlapNodes);
00785   for (int i=0; i < numOverlapNodes; i++)
00786     indices[i] = gid(overlapnodes[i]);
00787 
00788   overlap_node_map = Teuchos::null; // delete existing map happens here on remesh
00789 
00790   overlap_node_map = Teuchos::rcp(new Epetra_Map(-1, indices.size(),
00791              &(indices[0]), 0, *comm));
00792 
00793   if(Teuchos::nonnull(stkMeshStruct->nodal_data_block))
00794     stkMeshStruct->nodal_data_block->resizeOverlapMap(indices, *comm);
00795 
00796   coordinates.resize(3*numOverlapNodes);
00797 
00798 }
00799 
00800 
00801 void Albany::STKDiscretization::computeGraphs()
00802 {
00803 
00804   std::map<int, stk::mesh::Part*>::iterator pv = stkMeshStruct->partVec.begin();
00805   int nodes_per_element =  metaData.get_cell_topology(*(pv->second)).getNodeCount();
00806 // int nodes_per_element_est =  metaData.get_cell_topology(*(stkMeshStruct->partVec[0])).getNodeCount();
00807 
00808   // Loads member data:  overlap_graph, numOverlapodes, overlap_node_map, coordinates, graphs
00809 
00810   overlap_graph = Teuchos::null; // delete existing graph happens here on remesh
00811 
00812   overlap_graph =
00813     Teuchos::rcp(new Epetra_CrsGraph(Copy, *overlap_map,
00814                                      neq*nodes_per_element, false));
00815 
00816   stk::mesh::Selector select_owned_in_part =
00817     stk::mesh::Selector( metaData.universal_part() ) &
00818     stk::mesh::Selector( metaData.locally_owned_part() );
00819 
00820   stk::mesh::get_selected_entities( select_owned_in_part ,
00821             bulkData.buckets( metaData.element_rank() ) ,
00822             cells );
00823 
00824 
00825   if (comm->MyPID()==0)
00826     *out << "STKDisc: " << cells.size() << " elements on Proc 0 " << std::endl;
00827 
00828   int row, col;
00829 
00830   for (std::size_t i=0; i < cells.size(); i++) {
00831     stk::mesh::Entity& e = *cells[i];
00832     stk::mesh::PairIterRelation rel = e.relations(metaData.NODE_RANK);
00833 
00834     // loop over local nodes
00835     for (std::size_t j=0; j < rel.size(); j++) {
00836       stk::mesh::Entity& rowNode = * rel[j].entity();
00837 
00838       // loop over eqs
00839       for (std::size_t k=0; k < neq; k++) {
00840         row = getGlobalDOF(gid(rowNode), k);
00841         for (std::size_t l=0; l < rel.size(); l++) {
00842           stk::mesh::Entity& colNode = * rel[l].entity();
00843           for (std::size_t m=0; m < neq; m++) {
00844             col = getGlobalDOF(gid(colNode), m);
00845             overlap_graph->InsertGlobalIndices(row, 1, &col);
00846           }
00847         }
00848       }
00849     }
00850   }
00851   overlap_graph->FillComplete();
00852 
00853   // Create Owned graph by exporting overlap with known row map
00854 
00855   graph = Teuchos::null; // delete existing graph happens here on remesh
00856 
00857   graph = Teuchos::rcp(new Epetra_CrsGraph(Copy, *map, nonzeroesPerRow(neq), false));
00858 
00859   // Create non-overlapped matrix using two maps and export object
00860   Epetra_Export exporter(*overlap_map, *map);
00861   graph->Export(*overlap_graph, exporter, Insert);
00862   graph->FillComplete();
00863 
00864 }
00865 
00866 void Albany::STKDiscretization::computeWorksetInfo()
00867 {
00868 
00869   stk::mesh::Selector select_owned_in_part =
00870     stk::mesh::Selector( metaData.universal_part() ) &
00871     stk::mesh::Selector( metaData.locally_owned_part() );
00872 
00873   std::vector< stk::mesh::Bucket * > buckets ;
00874   stk::mesh::get_buckets( select_owned_in_part ,
00875                           bulkData.buckets( metaData.element_rank() ) ,
00876                           buckets);
00877 
00878   int numBuckets =  buckets.size();
00879 
00880   AbstractSTKFieldContainer::VectorFieldType* coordinates_field = stkMeshStruct->getCoordinatesField();
00881   AbstractSTKFieldContainer::ScalarFieldType* surfaceHeight_field;
00882   AbstractSTKFieldContainer::ScalarFieldType* temperature_field;
00883   AbstractSTKFieldContainer::ScalarFieldType* basalFriction_field;
00884   AbstractSTKFieldContainer::ScalarFieldType* thickness_field;
00885   AbstractSTKFieldContainer::ScalarFieldType* flowFactor_field;
00886   AbstractSTKFieldContainer::VectorFieldType* surfaceVelocity_field;
00887   AbstractSTKFieldContainer::VectorFieldType* velocityRMS_field;
00888 
00889   if(stkMeshStruct->getFieldContainer()->hasSurfaceHeightField())
00890     surfaceHeight_field = stkMeshStruct->getFieldContainer()->getSurfaceHeightField();
00891 
00892   if(stkMeshStruct->getFieldContainer()->hasTemperatureField())
00893     temperature_field = stkMeshStruct->getFieldContainer()->getTemperatureField();
00894 
00895   if(stkMeshStruct->getFieldContainer()->hasBasalFrictionField())
00896     basalFriction_field = stkMeshStruct->getFieldContainer()->getBasalFrictionField();
00897 
00898   if(stkMeshStruct->getFieldContainer()->hasThicknessField())
00899     thickness_field = stkMeshStruct->getFieldContainer()->getThicknessField();
00900 
00901   if(stkMeshStruct->getFieldContainer()->hasFlowFactorField())
00902     flowFactor_field = stkMeshStruct->getFieldContainer()->getFlowFactorField();
00903 
00904   if(stkMeshStruct->getFieldContainer()->hasSurfaceVelocityField())
00905     surfaceVelocity_field = stkMeshStruct->getFieldContainer()->getSurfaceVelocityField();
00906 
00907   if(stkMeshStruct->getFieldContainer()->hasVelocityRMSField())
00908     velocityRMS_field = stkMeshStruct->getFieldContainer()->getVelocityRMSField();
00909 
00910   wsEBNames.resize(numBuckets);
00911   for (int i=0; i<numBuckets; i++) {
00912     std::vector< stk::mesh::Part * >  bpv;
00913     buckets[i]->supersets(bpv);
00914     for (std::size_t j=0; j<bpv.size(); j++) {
00915       if (bpv[j]->primary_entity_rank() == metaData.element_rank()) {
00916         if (bpv[j]->name()[0] != '{') {
00917     // *out << "Bucket " << i << " is in Element Block:  " << bpv[j]->name()
00918     //      << "  and has " << buckets[i]->size() << " elements." << std::endl;
00919           wsEBNames[i]=bpv[j]->name();
00920         }
00921       }
00922     }
00923   }
00924 
00925   wsPhysIndex.resize(numBuckets);
00926   if (stkMeshStruct->allElementBlocksHaveSamePhysics)
00927     for (int i=0; i<numBuckets; i++) wsPhysIndex[i]=0;
00928   else
00929     for (int i=0; i<numBuckets; i++) wsPhysIndex[i]=stkMeshStruct->ebNameToIndex[wsEBNames[i]];
00930 
00931   // Fill  wsElNodeEqID(workset, el_LID, local node, Eq) => unk_LID
00932 
00933   wsElNodeEqID.resize(numBuckets);
00934   wsElNodeID.resize(numBuckets);
00935   coords.resize(numBuckets);
00936   sHeight.resize(numBuckets);
00937   temperature.resize(numBuckets);
00938   basalFriction.resize(numBuckets);
00939   thickness.resize(numBuckets);
00940   flowFactor.resize(numBuckets);
00941   surfaceVelocity.resize(numBuckets);
00942   velocityRMS.resize(numBuckets);
00943 
00944   // Clear map if remeshing
00945   if(!elemGIDws.empty()) elemGIDws.clear();
00946 
00947   for (int b=0; b < numBuckets; b++) {
00948 
00949     stk::mesh::Bucket& buck = *buckets[b];
00950     wsElNodeEqID[b].resize(buck.size());
00951     wsElNodeID[b].resize(buck.size());
00952     coords[b].resize(buck.size());
00953 #ifdef ALBANY_FELIX
00954     if(stkMeshStruct->getFieldContainer()->hasSurfaceHeightField())
00955       sHeight[b].resize(buck.size());
00956     if(stkMeshStruct->getFieldContainer()->hasTemperatureField())
00957       temperature[b].resize(buck.size());
00958     if(stkMeshStruct->getFieldContainer()->hasBasalFrictionField())
00959       basalFriction[b].resize(buck.size());
00960     if(stkMeshStruct->getFieldContainer()->hasThicknessField())
00961       thickness[b].resize(buck.size());
00962     if(stkMeshStruct->getFieldContainer()->hasFlowFactorField())
00963       flowFactor[b].resize(buck.size());
00964     if(stkMeshStruct->getFieldContainer()->hasSurfaceVelocityField())
00965       surfaceVelocity[b].resize(buck.size());
00966     if(stkMeshStruct->getFieldContainer()->hasVelocityRMSField())
00967       velocityRMS[b].resize(buck.size());
00968 #endif
00969 
00970     // i is the element index within bucket b
00971 
00972     for (std::size_t i=0; i < buck.size(); i++) {
00973 
00974       // Traverse all the elements in this bucket
00975       stk::mesh::Entity& element = buck[i];
00976 
00977       // Now, save a map from element GID to workset on this PE
00978       elemGIDws[gid(element)].ws = b;
00979 
00980       // Now, save a map from element GID to local id on this workset on this PE
00981       elemGIDws[gid(element)].LID = i;
00982 
00983       stk::mesh::PairIterRelation rel = element.relations(metaData.NODE_RANK);
00984 
00985       int nodes_per_element = rel.size();
00986       wsElNodeEqID[b][i].resize(nodes_per_element);
00987       wsElNodeID[b][i].resize(nodes_per_element);
00988       coords[b][i].resize(nodes_per_element);
00989 #ifdef ALBANY_FELIX
00990       if(stkMeshStruct->getFieldContainer()->hasSurfaceHeightField())
00991         sHeight[b][i].resize(nodes_per_element);
00992       if(stkMeshStruct->getFieldContainer()->hasTemperatureField())
00993         temperature[b][i] = *stk::mesh::field_data(*temperature_field, element);
00994       if(stkMeshStruct->getFieldContainer()->hasBasalFrictionField())
00995         basalFriction[b][i].resize(nodes_per_element);
00996       if(stkMeshStruct->getFieldContainer()->hasThicknessField())
00997         thickness[b][i].resize(nodes_per_element);
00998       if(stkMeshStruct->getFieldContainer()->hasFlowFactorField())
00999          flowFactor[b][i] = *stk::mesh::field_data(*flowFactor_field, element);
01000       if(stkMeshStruct->getFieldContainer()->hasSurfaceVelocityField())
01001         surfaceVelocity[b][i].resize(nodes_per_element);
01002       if(stkMeshStruct->getFieldContainer()->hasVelocityRMSField())
01003         velocityRMS[b][i].resize(nodes_per_element);
01004 #endif
01005       // loop over local nodes
01006       for (int j=0; j < nodes_per_element; j++) {
01007         stk::mesh::Entity& rowNode = * rel[j].entity();
01008         int node_gid = gid(rowNode);
01009         int node_lid = overlap_node_map->LID(node_gid);
01010 
01011         TEUCHOS_TEST_FOR_EXCEPTION(node_lid<0, std::logic_error,
01012          "STK1D_Disc: node_lid out of range " << node_lid << std::endl);
01013         coords[b][i][j] = stk::mesh::field_data(*coordinates_field, rowNode);
01014 #ifdef ALBANY_FELIX
01015         if(stkMeshStruct->getFieldContainer()->hasSurfaceHeightField())
01016           sHeight[b][i][j] = *stk::mesh::field_data(*surfaceHeight_field, rowNode);
01017         if(stkMeshStruct->getFieldContainer()->hasBasalFrictionField())
01018           basalFriction[b][i][j] = *stk::mesh::field_data(*basalFriction_field, rowNode);
01019         if(stkMeshStruct->getFieldContainer()->hasThicknessField())
01020           thickness[b][i][j] = *stk::mesh::field_data(*thickness_field, rowNode);
01021         if(stkMeshStruct->getFieldContainer()->hasSurfaceVelocityField())
01022           surfaceVelocity[b][i][j] = stk::mesh::field_data(*surfaceVelocity_field, rowNode);
01023         if(stkMeshStruct->getFieldContainer()->hasVelocityRMSField())
01024           velocityRMS[b][i][j] = stk::mesh::field_data(*velocityRMS_field, rowNode);
01025 #endif
01026 
01027         wsElNodeEqID[b][i][j].resize(neq);
01028         wsElNodeID[b][i][j] = node_gid;
01029 
01030         for (std::size_t eq=0; eq < neq; eq++)
01031           wsElNodeEqID[b][i][j][eq] = getOverlapDOF(node_lid,eq);
01032       }
01033     }
01034   }
01035 
01036   for (int d=0; d<stkMeshStruct->numDim; d++) {
01037   if (stkMeshStruct->PBCStruct.periodic[d]) {
01038     for (int b=0; b < numBuckets; b++) {
01039       for (std::size_t i=0; i < buckets[b]->size(); i++) {
01040         int nodes_per_element = (*buckets[b])[i].relations(metaData.NODE_RANK).size();
01041         bool anyXeqZero=false;
01042         for (int j=0; j < nodes_per_element; j++)  if (coords[b][i][j][d]==0.0) anyXeqZero=true;
01043         if (anyXeqZero)  {
01044           bool flipZeroToScale=false;
01045           for (int j=0; j < nodes_per_element; j++)
01046               if (coords[b][i][j][d] > stkMeshStruct->PBCStruct.scale[d]/1.9) flipZeroToScale=true;
01047           if (flipZeroToScale) {
01048             for (int j=0; j < nodes_per_element; j++)  {
01049               if (coords[b][i][j][d] == 0.0) {
01050                 double* xleak = new double [stkMeshStruct->numDim];
01051                 for (int k=0; k < stkMeshStruct->numDim; k++)
01052                   if (k==d) xleak[d]=stkMeshStruct->PBCStruct.scale[d];
01053                   else xleak[k] = coords[b][i][j][k];
01054                 std::string transformType = stkMeshStruct->transformType;
01055                 double alpha = stkMeshStruct->felixAlpha;
01056                 alpha *= pi/180.; //convert alpha, read in from ParameterList, to radians
01057                 if ((transformType=="ISMIP-HOM Test A" || transformType == "ISMIP-HOM Test B" ||
01058                      transformType=="ISMIP-HOM Test C" || transformType == "ISMIP-HOM Test D") && d==0) {
01059                     xleak[2] -= stkMeshStruct->PBCStruct.scale[d]*tan(alpha);
01060 #ifdef ALBANY_FELIX
01061                     if(stkMeshStruct->getFieldContainer()->hasSurfaceHeightField())
01062                       sHeight[b][i][j] -= stkMeshStruct->PBCStruct.scale[d]*tan(alpha);
01063 #endif
01064                 }
01065                 coords[b][i][j] = xleak; // replace ptr to coords
01066                 toDelete.push_back(xleak);
01067               }
01068             }
01069           }
01070         }
01071       }
01072     }
01073   }
01074   }
01075 
01076   typedef Albany::AbstractSTKFieldContainer::ScalarValueState ScalarValueState;
01077   typedef Albany::AbstractSTKFieldContainer::QPScalarState QPScalarState ;
01078   typedef Albany::AbstractSTKFieldContainer::QPVectorState QPVectorState;
01079   typedef Albany::AbstractSTKFieldContainer::QPTensorState QPTensorState;
01080 
01081   typedef Albany::AbstractSTKFieldContainer::ScalarState ScalarState ;
01082   typedef Albany::AbstractSTKFieldContainer::VectorState VectorState;
01083   typedef Albany::AbstractSTKFieldContainer::TensorState TensorState;
01084 
01085   // Pull out pointers to shards::Arrays for every bucket, for every state
01086   // Code is data-type dependent
01087 
01088   ScalarValueState scalarValue_states = stkMeshStruct->getFieldContainer()->getScalarValueStates();
01089   QPScalarState qpscalar_states = stkMeshStruct->getFieldContainer()->getQPScalarStates();
01090   QPVectorState qpvector_states = stkMeshStruct->getFieldContainer()->getQPVectorStates();
01091   QPTensorState qptensor_states = stkMeshStruct->getFieldContainer()->getQPTensorStates();
01092   double& time = stkMeshStruct->getFieldContainer()->getTime();
01093 
01094   stateArrays.elemStateArrays.resize(numBuckets);
01095   for (std::size_t b=0; b < buckets.size(); b++) {
01096     stk::mesh::Bucket& buck = *buckets[b];
01097     for (QPScalarState::iterator qpss = qpscalar_states.begin();
01098               qpss != qpscalar_states.end(); ++qpss){
01099       stk::mesh::BucketArray<Albany::AbstractSTKFieldContainer::QPScalarFieldType> array(**qpss, buck);
01100 //Debug
01101 //std::cout << "Buck.size(): " << buck.size() << " QPSFT dim[1]: " << array.dimension(1) << std::endl;
01102       MDArray ar = array;
01103       stateArrays.elemStateArrays[b][(*qpss)->name()] = ar;
01104     }
01105     for (QPVectorState::iterator qpvs = qpvector_states.begin();
01106               qpvs != qpvector_states.end(); ++qpvs){
01107       stk::mesh::BucketArray<Albany::AbstractSTKFieldContainer::QPVectorFieldType> array(**qpvs, buck);
01108 //Debug
01109 //std::cout << "Buck.size(): " << buck.size() << " QPVFT dim[2]: " << array.dimension(2) << std::endl;
01110       MDArray ar = array;
01111       stateArrays.elemStateArrays[b][(*qpvs)->name()] = ar;
01112     }
01113     for (QPTensorState::iterator qpts = qptensor_states.begin();
01114               qpts != qptensor_states.end(); ++qpts){
01115       stk::mesh::BucketArray<Albany::AbstractSTKFieldContainer::QPTensorFieldType> array(**qpts, buck);
01116 //Debug
01117 //std::cout << "Buck.size(): " << buck.size() << " QPTFT dim[3]: " << array.dimension(3) << std::endl;
01118       MDArray ar = array;
01119       stateArrays.elemStateArrays[b][(*qpts)->name()] = ar;
01120     }
01121     for (ScalarValueState::iterator svs = scalarValue_states.begin();
01122               svs != scalarValue_states.end(); ++svs){
01123       const int size = 1;
01124       shards::Array<double, shards::NaturalOrder, Cell> array(&time, size);
01125       MDArray ar = array;
01126       stateArrays.elemStateArrays[b][*svs] = ar;
01127     }
01128   }
01129 
01130 // Process node data sets if present
01131 
01132   if(Teuchos::nonnull(stkMeshStruct->nodal_data_block)){
01133 
01134     Teuchos::RCP<Albany::NodeFieldContainer> node_states = stkMeshStruct->nodal_data_block->getNodeContainer();
01135   
01136     stk::mesh::get_buckets( select_owned_in_part ,
01137                             bulkData.buckets( metaData.node_rank() ) ,
01138                             buckets);
01139   
01140     numBuckets =  buckets.size();
01141   
01142     stateArrays.nodeStateArrays.resize(numBuckets);
01143     for (std::size_t b=0; b < buckets.size(); b++) {
01144       stk::mesh::Bucket& buck = *buckets[b];
01145       for (Albany::NodeFieldContainer::iterator nfs = node_states->begin();
01146                 nfs != node_states->end(); ++nfs){
01147         stateArrays.nodeStateArrays[b][(*nfs).first] = 
01148              Teuchos::rcp_dynamic_cast<Albany::AbstractSTKNodeFieldContainer>((*nfs).second)->getMDA(buck);
01149       }
01150     }
01151   }
01152 }
01153 
01154 void Albany::STKDiscretization::computeSideSets(){
01155 
01156   // Clean up existing sideset structure if remeshing
01157 
01158   for(int i = 0; i < sideSets.size(); i++)
01159     sideSets[i].clear(); // empty the ith map
01160 
01161   const stk::mesh::EntityRank element_rank = metaData.element_rank();
01162 
01163   // iterator over all side_rank parts found in the mesh
01164   std::map<std::string, stk::mesh::Part*>::iterator ss = stkMeshStruct->ssPartVec.begin();
01165 
01166   int numBuckets = wsEBNames.size();
01167 
01168   sideSets.resize(numBuckets); // Need a sideset list per workset
01169 
01170   while ( ss != stkMeshStruct->ssPartVec.end() ) {
01171 
01172     // Get all owned sides in this side set
01173     stk::mesh::Selector select_owned_in_sspart =
01174 
01175       // get only entities in the ss part (ss->second is the current sideset part)
01176       stk::mesh::Selector( *(ss->second) ) &
01177       // and only if the part is local
01178       stk::mesh::Selector( metaData.locally_owned_part() );
01179 
01180     std::vector< stk::mesh::Entity * > sides ;
01181     stk::mesh::get_selected_entities( select_owned_in_sspart , // sides local to this processor
01182               bulkData.buckets( metaData.side_rank() ) ,
01183               sides ); // store the result in "sides"
01184 
01185     *out << "STKDisc: sideset "<< ss->first <<" has size " << sides.size() << "  on Proc 0." << std::endl;
01186 
01187     // loop over the sides to see what they are, then fill in the data holder
01188     // for side set options, look at $TRILINOS_DIR/packages/stk/stk_usecases/mesh/UseCase_13.cpp
01189 
01190     for (std::size_t localSideID=0; localSideID < sides.size(); localSideID++) {
01191 
01192       stk::mesh::Entity &sidee = *sides[localSideID];
01193 
01194       const stk::mesh::PairIterRelation side_elems = sidee.relations(element_rank); // get the elements
01195             // containing the side. Note that if the side is internal, it will show up twice in the
01196             // element list, once for each element that contains it.
01197 
01198       TEUCHOS_TEST_FOR_EXCEPTION(side_elems.size() != 1, std::logic_error,
01199          "STKDisc: cannot figure out side set topology for side set " << ss->first << std::endl);
01200 
01201       const stk::mesh::Entity & elem = *side_elems[0].entity();
01202 
01203       SideStruct sStruct;
01204 
01205       // Save elem id. This is the global element id
01206       sStruct.elem_GID = gid(elem);
01207 
01208       int workset = elemGIDws[sStruct.elem_GID].ws; // Get the ws that this element lives in
01209 
01210       // Save elem id. This is the local element id within the workset
01211       sStruct.elem_LID = elemGIDws[sStruct.elem_GID].LID;
01212 
01213       // Save the side identifier inside of the element. This starts at zero here.
01214       sStruct.side_local_id = determine_local_side_id(elem, sidee);
01215 
01216       // Save the index of the element block that this elem lives in
01217       sStruct.elem_ebIndex = stkMeshStruct->ebNameToIndex[wsEBNames[workset]];
01218 
01219       SideSetList& ssList = sideSets[workset];   // Get a ref to the side set map for this ws
01220       SideSetList::iterator it = ssList.find(ss->first); // Get an iterator to the correct sideset (if
01221                                                                 // it exists)
01222 
01223       if(it != ssList.end()) // The sideset has already been created
01224 
01225         it->second.push_back(sStruct); // Save this side to the vector that belongs to the name ss->first
01226 
01227       else { // Add the key ss->first to the map, and the side vector to that map
01228 
01229         std::vector<SideStruct> tmpSSVec;
01230         tmpSSVec.push_back(sStruct);
01231 
01232         ssList.insert(SideSetList::value_type(ss->first, tmpSSVec));
01233 
01234       }
01235 
01236     }
01237 
01238     ss++;
01239   }
01240 }
01241 
01242 unsigned
01243 Albany::STKDiscretization::determine_local_side_id( const stk::mesh::Entity & elem , stk::mesh::Entity & side ) {
01244 
01245   using namespace stk;
01246 
01247   const CellTopologyData * const elem_top = mesh::fem::get_cell_topology( elem ).getCellTopologyData();
01248 
01249   const mesh::PairIterRelation elem_nodes = elem.relations( mesh::fem::FEMMetaData::NODE_RANK );
01250   const mesh::PairIterRelation side_nodes = side.relations( mesh::fem::FEMMetaData::NODE_RANK );
01251 
01252   int side_id = -1 ;
01253 
01254   if(elem_nodes.size() == 0 || side_nodes.size() == 0){ // Node relations are not present, look at elem->face
01255 
01256     int elem_rank = elem.entity_rank();
01257     const mesh::PairIterRelation elem_sides = elem.relations( elem_rank - 1);
01258 
01259     for ( unsigned i = 0 ; i < elem_sides.size() ; ++i ) {
01260 
01261       const stk::mesh::Entity & elem_side = *elem_sides[i].entity();
01262 
01263       if(elem_side.identifier() == side.identifier()){ // Found the local side in the element
01264 
01265          side_id = static_cast<int>(i);
01266 
01267          return side_id;
01268 
01269       }
01270 
01271     }
01272 
01273     if ( side_id < 0 ) {
01274       std::ostringstream msg ;
01275       msg << "determine_local_side_id( " ;
01276       msg << elem_top->name ;
01277       msg << " , Element[ " ;
01278       msg << elem.identifier();
01279       msg << " ]{" ;
01280       for ( unsigned i = 0 ; i < elem_sides.size() ; ++i ) {
01281         msg << " " << elem_sides[i].entity()->identifier();
01282       }
01283       msg << " } , Side[ " ;
01284       msg << side.identifier();
01285       msg << " ] ) FAILED" ;
01286       throw std::runtime_error( msg.str() );
01287     }
01288 
01289   }
01290   else { // Conventional elem->node - side->node connectivity present
01291 
01292     for ( unsigned i = 0 ; side_id == -1 && i < elem_top->side_count ; ++i ) {
01293       const CellTopologyData & side_top = * elem_top->side[i].topology ;
01294       const unsigned     * side_map =   elem_top->side[i].node ;
01295 
01296       if ( side_nodes.size() == side_top.node_count ) {
01297 
01298         side_id = i ;
01299 
01300         for ( unsigned j = 0 ;
01301               side_id == static_cast<int>(i) && j < side_top.node_count ; ++j ) {
01302 
01303           mesh::Entity * const elem_node = elem_nodes[ side_map[j] ].entity();
01304 
01305           bool found = false ;
01306 
01307           for ( unsigned k = 0 ; ! found && k < side_top.node_count ; ++k ) {
01308             found = elem_node == side_nodes[k].entity();
01309           }
01310 
01311           if ( ! found ) { side_id = -1 ; }
01312         }
01313       }
01314     }
01315 
01316     if ( side_id < 0 ) {
01317       std::ostringstream msg ;
01318       msg << "determine_local_side_id( " ;
01319       msg << elem_top->name ;
01320       msg << " , Element[ " ;
01321       msg << elem.identifier();
01322       msg << " ]{" ;
01323       for ( unsigned i = 0 ; i < elem_nodes.size() ; ++i ) {
01324         msg << " " << elem_nodes[i].entity()->identifier();
01325       }
01326       msg << " } , Side[ " ;
01327       msg << side.identifier();
01328       msg << " ]{" ;
01329       for ( unsigned i = 0 ; i < side_nodes.size() ; ++i ) {
01330         msg << " " << side_nodes[i].entity()->identifier();
01331       }
01332       msg << " } ) FAILED" ;
01333       throw std::runtime_error( msg.str() );
01334     }
01335   }
01336 
01337   return static_cast<unsigned>(side_id) ;
01338 }
01339 
01340 void Albany::STKDiscretization::computeNodeSets()
01341 {
01342 
01343   std::map<std::string, stk::mesh::Part*>::iterator ns = stkMeshStruct->nsPartVec.begin();
01344   AbstractSTKFieldContainer::VectorFieldType* coordinates_field = stkMeshStruct->getCoordinatesField();
01345 
01346   while ( ns != stkMeshStruct->nsPartVec.end() ) { // Iterate over Node Sets
01347     // Get all owned nodes in this node set
01348     stk::mesh::Selector select_owned_in_nspart =
01349       stk::mesh::Selector( *(ns->second) ) &
01350       stk::mesh::Selector( metaData.locally_owned_part() );
01351 
01352     std::vector< stk::mesh::Entity * > nodes ;
01353     stk::mesh::get_selected_entities( select_owned_in_nspart ,
01354               bulkData.buckets( metaData.node_rank() ) ,
01355               nodes );
01356 
01357     nodeSets[ns->first].resize(nodes.size());
01358     nodeSetCoords[ns->first].resize(nodes.size());
01359 //    nodeSetIDs.push_back(ns->first); // Grab string ID
01360     *out << "STKDisc: nodeset "<< ns->first <<" has size " << nodes.size() << "  on Proc 0." << std::endl;
01361     for (std::size_t i=0; i < nodes.size(); i++) {
01362       int node_gid = gid(nodes[i]);
01363       int node_lid = node_map->LID(node_gid);
01364       nodeSets[ns->first][i].resize(neq);
01365       for (std::size_t eq=0; eq < neq; eq++)  nodeSets[ns->first][i][eq] = getOwnedDOF(node_lid,eq);
01366       nodeSetCoords[ns->first][i] = stk::mesh::field_data(*coordinates_field, *nodes[i]);
01367     }
01368     ns++;
01369   }
01370 }
01371 
01372 void Albany::STKDiscretization::setupExodusOutput()
01373 {
01374 #ifdef ALBANY_SEACAS
01375   if (stkMeshStruct->exoOutput) {
01376 
01377     outputInterval = 0;
01378 
01379     std::string str = stkMeshStruct->exoOutFile;
01380 
01381     Ioss::Init::Initializer io;
01382     mesh_data = new stk::io::MeshData();
01383     stk::io::create_output_mesh(str,
01384       Albany::getMpiCommFromEpetraComm(*comm),
01385       bulkData, *mesh_data);
01386 
01387     stk::io::define_output_fields(*mesh_data, metaData);
01388 
01389   }
01390 #else
01391   if (stkMeshStruct->exoOutput)
01392     *out << "\nWARNING: exodus output requested but SEACAS not compiled in:"
01393          << " disabling exodus output \n" << std::endl;
01394 
01395 #endif
01396 }
01397 
01398 namespace {
01399   const std::vector<double> spherical_to_cart(const std::pair<double, double> & sphere){
01400     const double radius_of_earth = 1;
01401     std::vector<double> cart(3);
01402 
01403     cart[0] = radius_of_earth*std::cos(sphere.first)*std::cos(sphere.second);
01404     cart[1] = radius_of_earth*std::cos(sphere.first)*std::sin(sphere.second);
01405     cart[2] = radius_of_earth*std::sin(sphere.first);
01406 
01407     return cart;
01408   }
01409   double distance (const double* x, const double* y) {
01410     const double d = std::sqrt((x[0]-y[0])*(x[0]-y[0]) + 
01411                                (x[1]-y[1])*(x[1]-y[1]) + 
01412                                (x[2]-y[2])*(x[2]-y[2]));
01413     return d;
01414   }
01415   double distance (const std::vector<double> &x, const std::vector<double> &y) {
01416     const double d = std::sqrt((x[0]-y[0])*(x[0]-y[0]) + 
01417                                (x[1]-y[1])*(x[1]-y[1]) + 
01418                                (x[2]-y[2])*(x[2]-y[2]));
01419     return d;
01420   }
01421   
01422   bool point_inside(const Teuchos::ArrayRCP<double*> &coords, 
01423                     const std::vector<double>        &sphere_xyz) {
01424     // first check if point is near the element:
01425     const double  tol_inside = 1e-12;
01426     const double elem_diam = std::max(::distance(coords[0],coords[2]), ::distance(coords[1],coords[3]));
01427     std::vector<double> center(3,0);
01428     for (unsigned i=0; i<4; ++i) 
01429       for (unsigned j=0; j<3; ++j) center[j] += coords[i][j];
01430     for (unsigned j=0; j<3; ++j) center[j] /= 4;
01431     bool inside = true;
01432     
01433     if ( ::distance(&center[0],&sphere_xyz[0]) > 1.0*elem_diam ) inside = false;
01434 
01435     unsigned j=3;
01436     for (unsigned i=0; i<4 && inside; ++i) {
01437       std::vector<double> cross(3);
01438       // outward normal to plane containing j->i edge:  corner(i) x corner(j)
01439       // sphere dot (corner(i) x corner(j) ) = negative if inside
01440       cross[0]=  coords[i][1]*coords[j][2] - coords[i][2]*coords[j][1];
01441       cross[1]=-(coords[i][0]*coords[j][2] - coords[i][2]*coords[j][0]);
01442       cross[2]=  coords[i][0]*coords[j][1] - coords[i][1]*coords[j][0];
01443       j = i;
01444       const double dotprod = cross[0]*sphere_xyz[0] + 
01445                              cross[1]*sphere_xyz[1] + 
01446                              cross[2]*sphere_xyz[2];
01447       
01448       // dot product is proportional to elem_diam. positive means outside,
01449       // but allow machine precision tolorence: 
01450       if (tol_inside*elem_diam < dotprod) inside = false;
01451     }         
01452     return inside;
01453   }
01454 
01455   std::pair<double, double>  ref2sphere(const Teuchos::ArrayRCP<double*> &coords,
01456                                          const std::pair<double, double> &ref) {
01457 
01458     static const double DIST_THRESHOLD= 1.0e-9;
01459     const double a = ref.first;
01460     const double b = ref.second;
01461     const double q[4]={ (1-a)*(1-b)/4, 
01462                         (1+a)*(1-b)/4, 
01463                         (1+a)*(1+b)/4, 
01464                         (1-a)*(1+b)/4} ;
01465   
01466     double x[3]={0,0,0};
01467     for (unsigned i=0; i<3; ++i) 
01468       for (unsigned j=0; j<4; ++j) 
01469         x[i] += coords[j][i] * q[j];
01470 
01471     const double r = std::sqrt(x[0]*x[0] + x[1]*x[1] + x[2]*x[2]);
01472 
01473     for (unsigned i=0; i<3; ++i) x[i] /= r; 
01474 
01475     std::pair<double, double> sphere(std::asin(x[2]), std::atan2(x[1],x[0]));
01476 
01477     // ==========================================================
01478     // enforce three facts:
01479     //
01480     // 1) lon at poles is defined to be zero
01481     //
01482     // 2) Grid points must be separated by about .01 Meter (on earth)
01483     //   from pole to be considered "not the pole".
01484     //
01485     // 3) range of lon is { 0<= lon < 2*PI }
01486     //
01487     // ==========================================================
01488 
01489     if (std::abs(std::abs(sphere.first)-pi/2) < DIST_THRESHOLD) sphere.second = 0;
01490     else if (sphere.second < 0) sphere.second += 2*pi;
01491 
01492     return sphere;
01493   }
01494 
01495   void Dmap(const Teuchos::ArrayRCP<double*> &coords,
01496             const std::pair<double, double>  &sphere,
01497             const std::pair<double, double>  &ref,
01498             double D[][2]) {
01499 
01500     const double th     = sphere.first;
01501     const double lam    = sphere.second; 
01502     const double sinlam = std::sin(lam); 
01503     const double sinth  = std::sin(th);
01504     const double coslam = std::cos(lam); 
01505     const double costh  = std::cos(th);
01506 
01507     const double D1[2][3] = {{-sinlam, coslam, 0},
01508                              {      0,      0, 1}};
01509 
01510     const double D2[3][3] = {{ sinlam*sinlam*costh*costh+sinth*sinth, -sinlam*coslam*costh*costh,             -coslam*sinth*costh},
01511                              {-sinlam*coslam*costh*costh,              coslam*coslam*costh*costh+sinth*sinth, -sinlam*sinth*costh},
01512                              {-coslam*sinth,                          -sinlam*sinth,                                        costh}};
01513 
01514     const double DD[4][2] = {{ (-1+ref.second)/4, (-1+ref.first)/4 },
01515                              { ( 1-ref.second)/4, (-1-ref.first)/4 },
01516                              { ( 1+ref.second)/4, ( 1+ref.first)/4 },
01517                              { (-1-ref.second)/4, ( 1-ref.first)/4 }};
01518 
01519     double D3[3][2] = {0};
01520     for (unsigned i=0; i<3; ++i) 
01521       for (unsigned j=0; j<2; ++j) 
01522         for (unsigned k=0; k<4; ++k) 
01523           D3[i][j] += coords[k][i] * DD[k][j];
01524 
01525     double D4[3][2] = {0};
01526     for (unsigned i=0; i<3; ++i) 
01527       for (unsigned j=0; j<2; ++j) 
01528         for (unsigned k=0; k<3; ++k) 
01529            D4[i][j] += D2[i][k] * D3[k][j];
01530 
01531     for (unsigned i=0; i<2; ++i) 
01532       for (unsigned j=0; j<2; ++j) D[i][j] = 0;
01533 
01534     for (unsigned i=0; i<2; ++i) 
01535       for (unsigned j=0; j<2; ++j) 
01536         for (unsigned k=0; k<3; ++k) 
01537           D[i][j] += D1[i][k] * D4[k][j];
01538 
01539   }
01540 
01541   std::pair<double, double> parametric_coordinates(const Teuchos::ArrayRCP<double*> &coords, 
01542                                                    const std::pair<double, double>  &sphere) {
01543     static const double tol_sq = 1e-26;
01544     static const unsigned MAX_NR_ITER = 10;
01545     double costh = std::cos(sphere.first);
01546     double D[2][2], Dinv[2][2];
01547     double resa = 1;
01548     double resb = 1;
01549     std::pair<double, double> ref(0,0); // initial guess is center of element.
01550 
01551     for (unsigned i=0; i<MAX_NR_ITER && tol_sq < (costh*resb*resb + resa*resa) ; ++i) {
01552       const std::pair<double, double> sph = ref2sphere(coords,ref);
01553       resa = sph.first  - sphere.first;
01554       resb = sph.second - sphere.second;
01555 
01556       if (resb >  pi) resb -= 2*pi;
01557       if (resb < -pi) resb += 2*pi;
01558  
01559       Dmap(coords, sph, ref, D);
01560       const double detD = D[0][0]*D[1][1] - D[0][1]*D[1][0];
01561       Dinv[0][0] =  D[1][1]/detD;
01562       Dinv[0][1] = -D[0][1]/detD;
01563       Dinv[1][0] = -D[1][0]/detD;
01564       Dinv[1][1] =  D[0][0]/detD;
01565  
01566       const std::pair<double, double> del( Dinv[0][0]*costh*resb + Dinv[0][1]*resa, 
01567                                            Dinv[1][0]*costh*resb + Dinv[1][1]*resa);
01568       ref.first  -= del.first;
01569       ref.second -= del.second;
01570     }
01571     return ref;
01572   }
01573    
01574   const std::pair<bool,std::pair<unsigned, unsigned> >point_in_element(const std::pair<double, double> &sphere, 
01575       const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double*> > >::type& coords, 
01576       std::pair<double, double> &parametric) {
01577     const std::vector<double> sphere_xyz = spherical_to_cart(sphere);
01578     std::pair<bool,std::pair<unsigned, unsigned> > element(false,std::pair<unsigned, unsigned>(0,0));
01579     for (unsigned i=0; i<coords.size() && !element.first; ++i) {
01580       for (unsigned j=0; j<coords[i].size() && !element.first; ++j) {
01581         const bool found =  point_inside(coords[i][j], sphere_xyz);
01582         if (found) {
01583           parametric = parametric_coordinates(coords[i][j], sphere);
01584           if (parametric.first  < -1) parametric.first  = -1;
01585           if (parametric.second < -1) parametric.second = -1;
01586           if (1 < parametric.first  ) parametric.first  =  1;
01587           if (1 < parametric.second ) parametric.second =  1;
01588           element.first         = true;
01589           element.second.first  = i;
01590           element.second.second = j;
01591         }
01592       }
01593     }
01594     return element;
01595   }
01596 
01597   void setup_latlon_interp(
01598     const unsigned nlat, const double nlon,
01599     const Albany::WorksetArray<Teuchos::ArrayRCP<Teuchos::ArrayRCP<double*> > >::type& coords,
01600     Albany::WorksetArray<Teuchos::ArrayRCP<std::vector<Albany::STKDiscretization::interp> > >::type& interpdata,
01601     const Teuchos::RCP<const Epetra_Comm> comm) { 
01602     
01603     double err;
01604     std::vector<double> lat(nlat);
01605     std::vector<double> lon(nlon);
01606     
01607     unsigned count=0;
01608     for (unsigned i=0; i<nlat; ++i) lat[i] = -pi/2 + i*pi/(nlat-1);
01609     for (unsigned i=0; i<nlon; ++i) lon[i] =       2*i*pi/nlon;
01610     for (unsigned i=0; i<nlat; ++i) {
01611       for (unsigned j=0; j<nlon; ++j) {
01612         const std::pair<double, double> sphere(lat[i],lon[j]);
01613         std::pair<double, double> paramtric;
01614         const std::pair<bool,std::pair<unsigned, unsigned> >element = point_in_element(sphere, coords, paramtric);
01615         if (element.first) {
01616           // compute error: map 'cart' back to sphere and compare with original
01617           // interpolation point:
01618           const unsigned b = element.second.first ;
01619           const unsigned e = element.second.second;
01620           const std::vector<double> sphere2_xyz = spherical_to_cart(ref2sphere(coords[b][e], paramtric));
01621           const std::vector<double> sphere_xyz  = spherical_to_cart(sphere);
01622           err = std::max(err, ::distance(&sphere2_xyz[0],&sphere_xyz[0]));
01623           Albany::STKDiscretization::interp interp;
01624           interp.parametric_coords = paramtric;
01625           interp.latitude_longitude = std::pair<unsigned,unsigned>(i,j);
01626           interpdata[b][e].push_back(interp);
01627           ++count;
01628         }
01629       }
01630       if (!comm->MyPID() && (!(i%64) || i==nlat-1)) std::cout<< "Finished Latitude "<<i<<" of "<<nlat<<std::endl;
01631     }
01632     if (!comm->MyPID()) std::cout<<"Max interpolation point search error: "<<err<<std::endl;
01633   }
01634 
01635   double interpolate_to_point(const Teuchos::ArrayRCP<double> height, const std::pair<double, double> &parametric) {
01636     const double a = parametric.first;
01637     const double b = parametric.second;
01638     const double q[4]={ (1-a)*(1-b)/4, 
01639                         (1+a)*(1-b)/4, 
01640                         (1+a)*(1+b)/4, 
01641                         (1-a)*(1+b)/4} ;
01642     double y=0;
01643     for (unsigned j=0; j<4; ++j) y += height[j]*q[j];
01644     return y;
01645   }
01646 }
01647 
01648 int Albany::STKDiscretization::processNetCDFOutputRequest() {
01649 #ifdef ALBANY_SEACAS
01650   const unsigned nlat = stkMeshStruct->nLat;
01651   const unsigned nlon = stkMeshStruct->nLon;
01652 
01653   std::vector<double> local(nlat*nlon, -std::numeric_limits<double>::max());
01654 
01655   unsigned count=0;
01656   Teuchos::ArrayRCP<double> height(4);
01657   const double theta     = netCDFOutputRequest*pi/18;
01658   const double rot[2][2] = {{ std::sin(theta), std::cos(theta)},
01659                             {-std::cos(theta), std::sin(theta)}};
01660 
01661   for (unsigned b=0; b<interpolateData.size(); ++b) {
01662     Teuchos::ArrayRCP<std::vector<interp> >        Interpb = interpolateData[b]; 
01663     Teuchos::ArrayRCP<Teuchos::ArrayRCP<double*> > Coordsb = coords[b]; 
01664     //Teuchos::ArrayRCP<Teuchos::ArrayRCP<double> >  Heightb = sHeight   [b];
01665     for (unsigned e=0; e<Interpb.size(); ++e) {
01666       const std::vector<interp>                    &interp = Interpb[e];
01667       Teuchos::ArrayRCP<double*>                    coordp = Coordsb[e]; 
01668       //const Teuchos::ArrayRCP<double>               height = Heightb[e]; 
01669       for (unsigned i=0; i<4; ++i) height[i] =  rot[0][0]*coordp[i][0] + rot[0][1]*coordp[i][1];
01670       for (unsigned p=0; p<interp.size(); ++p) {
01671         Albany::STKDiscretization::interp par    = interp[p]; 
01672         double y = interpolate_to_point(height, par.parametric_coords);
01673         std::pair<unsigned,unsigned> latlon =   par.latitude_longitude;
01674         local[latlon.first + nlat*latlon.second] = y;
01675         ++count;
01676       }
01677     }
01678   }
01679   std::vector<double> global(nlat*nlon);
01680   comm->MaxAll(&local[0], &global[0], nlat*nlon);
01681 
01682   const long long unsigned rank = comm->MyPID();
01683 #ifdef ALBANY_PAR_NETCDF
01684   const long long unsigned np   = comm->NumProc();
01685   const size_t start            = static_cast<size_t>((rank*nlat)/np);
01686   const size_t end              = static_cast<size_t>(((rank+1)*nlat)/np);
01687   const size_t len              = end-start;
01688 
01689   const size_t  startp[] = {netCDFOutputRequest,    0, start, 0};
01690   const size_t  countp[] = {1, 1, len, nlon};
01691   if (const int ierr = nc_put_vara_double (netCDFp, varHeight, startp, countp, &global[0]))
01692     TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01693       "nc_put_vara_double returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01694 #else
01695   const size_t  startp[] = {netCDFOutputRequest,    0, 0, 0};
01696   const size_t  countp[] = {1, 1, nlat, nlon};
01697   if (!rank) 
01698     if (const int ierr = nc_put_vara_double (netCDFp, varHeight, startp, countp, &global[0]))
01699       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01700         "nc_put_vara returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01701 #endif
01702 #endif
01703   return netCDFOutputRequest++;
01704 }
01705 
01706 void Albany::STKDiscretization::setupNetCDFOutput()
01707 {
01708 #ifdef ALBANY_SEACAS
01709   if (stkMeshStruct->cdfOutput) {
01710 
01711     outputInterval = 0;
01712     const unsigned nlat = stkMeshStruct->nLat;
01713     const unsigned nlon = stkMeshStruct->nLon;
01714 
01715 
01716     std::string str = stkMeshStruct->cdfOutFile;
01717 
01718     interpolateData.resize(coords.size());
01719     for (int b=0; b < coords.size(); b++) interpolateData[b].resize(coords[b].size());
01720 
01721     setup_latlon_interp(nlat, nlon, coords, interpolateData, comm);
01722 
01723     const std::string name = stkMeshStruct->cdfOutFile;
01724     netCDFp=0;
01725     netCDFOutputRequest=0;
01726 
01727 
01728 #ifdef ALBANY_PAR_NETCDF
01729     MPI_Comm theMPIComm = Albany::getMpiCommFromEpetraComm(*comm);
01730     MPI_Info info;
01731     MPI_Info_create(&info);
01732     if (const int ierr = nc_create_par (name.c_str(), NC_NETCDF4 | NC_MPIIO | NC_CLOBBER, theMPIComm, info, &netCDFp))
01733       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01734         "nc_create_par returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01735     MPI_Info_free(&info);
01736 #else
01737     if (const int ierr = nc_create (name.c_str(), NC_NETCDF4 | NC_CLOBBER, &netCDFp))
01738       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01739         "nc_create returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01740 #endif
01741    
01742     const size_t nlev = 1;
01743     const char *dimnames[] = {"time","lev","lat","lon"};
01744     const size_t  dimlen[] = {NC_UNLIMITED, nlev, nlat, nlon};
01745     int dimID[4]={0,0,0,0};
01746 
01747     for (unsigned i=0; i<4; ++i) {
01748       if (const int ierr = nc_def_dim (netCDFp,  dimnames[i], dimlen[i], &dimID[i]))
01749         TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01750           "nc_def_dim returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01751     }
01752     const char *field_name = "height";
01753     varHeight=0;
01754     if (const int ierr = nc_def_var (netCDFp,  field_name, NC_DOUBLE, 4, dimID, &varHeight))
01755       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01756         "nc_def_var "<<field_name<<" returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01757     
01758     const double fillVal = -9999.0;
01759     if (const int ierr = nc_put_att (netCDFp,  varHeight, "FillValue", NC_DOUBLE, 1, &fillVal))
01760       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01761         "nc_put_att FillValue returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01762 
01763     const char lat_name[] = "latitude";
01764     const char lat_unit[] = "degrees_north";
01765     const char lon_name[] = "longitude";
01766     const char lon_unit[] = "degrees_east";
01767     int latVarID=0;
01768     if (const int ierr = nc_def_var (netCDFp,  "lat", NC_DOUBLE, 1, &dimID[3], &latVarID))
01769       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01770         "nc_def_var lat returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01771     if (const int ierr = nc_put_att_text (netCDFp,  latVarID, "long_name", sizeof(lat_name), lat_name))
01772       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01773         "nc_put_att_text "<<lat_name<<" returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01774     if (const int ierr = nc_put_att_text (netCDFp,  latVarID, "units", sizeof(lat_unit), lat_unit))
01775       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01776         "nc_put_att_text "<<lat_unit<<" returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01777 
01778     int lonVarID=0;
01779     if (const int ierr = nc_def_var (netCDFp,  "lon", NC_DOUBLE, 1, &dimID[2], &lonVarID))
01780       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01781         "nc_def_var lon returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01782     if (const int ierr = nc_put_att_text (netCDFp,  lonVarID, "long_name", sizeof(lon_name), lon_name))
01783       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01784         "nc_put_att_text "<<lon_name<<" returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01785     if (const int ierr = nc_put_att_text (netCDFp,  lonVarID, "units", sizeof(lon_unit), lon_unit))
01786       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01787         "nc_put_att_text "<<lon_unit<<" returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01788     
01789     const char history[]="Created by Albany";
01790     if (const int ierr = nc_put_att_text (netCDFp,  NC_GLOBAL, "history", sizeof(history), history))
01791       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01792         "nc_put_att_text "<<history<<" returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01793 
01794     if (const int ierr = nc_enddef (netCDFp))
01795       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01796         "nc_enddef returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01797 
01798     std::vector<double> deglon(nlon);
01799     std::vector<double> deglat(nlat);
01800     for (unsigned i=0; i<nlon; ++i) deglon[i] =((      2*i*pi/nlon) *   (180./pi)) - 180.;
01801     for (unsigned i=0; i<nlat; ++i) deglat[i] = (-pi/2 + i*pi/(nlat-1))*(180./pi);
01802 
01803   
01804     if (const int ierr = nc_put_var (netCDFp, lonVarID, &deglon[0]))
01805       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01806         "nc_put_var lon returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01807     if (const int ierr = nc_put_var (netCDFp, latVarID, &deglat[0]))
01808       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01809         "nc_put_var lat returned error code "<<ierr<<" - "<<nc_strerror(ierr)<<std::endl);
01810 
01811   }
01812 #else
01813   if (stkMeshStruct->cdfOutput)
01814     *out << "\nWARNING: NetCDF output requested but SEACAS not compiled in:"
01815          << " disabling NetCDF output \n" << std::endl;
01816   stkMeshStruct->cdfOutput = false;
01817 
01818 #endif
01819 }
01820 
01821 void Albany::STKDiscretization::reNameExodusOutput(std::string& filename)
01822 {
01823 #ifdef ALBANY_SEACAS
01824   if (stkMeshStruct->exoOutput && mesh_data != NULL) {
01825 
01826    // Delete the mesh data object and recreate it
01827    delete mesh_data;
01828 
01829    stkMeshStruct->exoOutFile = filename;
01830 
01831    // reset reference value for monotonic time function call as we are writing to a new file
01832    previous_time_label = -1.0e32;
01833 
01834   }
01835 #else
01836   if (stkMeshStruct->exoOutput)
01837     *out << "\nWARNING: exodus output requested but SEACAS not compiled in:"
01838          << " disabling exodus output \n" << std::endl;
01839 
01840 #endif
01841 }
01842 
01843 void
01844 Albany::STKDiscretization::meshToGraph()
01845 {
01846 /*
01847   Convert the stk mesh on this processor to a nodal graph
01848 */
01849 
01850   // Elements that surround a given node, in the form of Entity *'s
01851   std::vector<std::vector<stk::mesh::Entity *> > sur_elem;
01852   // numOverlapNodes are the total # of nodes seen by this pe
01853   // numOwnedNodes are the total # of nodes owned by this pe
01854   sur_elem.resize(numOverlapNodes);
01855 
01856   std::size_t max_nsur = 0;
01857 
01858   // Get the elements owned by the current processor
01859   stk::mesh::Selector select_owned_in_part =
01860     stk::mesh::Selector( metaData.universal_part() ) &
01861     stk::mesh::Selector( metaData.locally_owned_part() );
01862 
01863   std::vector< stk::mesh::Bucket * > buckets ;
01864   stk::mesh::get_buckets( select_owned_in_part ,
01865                           bulkData.buckets( metaData.element_rank() ) ,
01866                           buckets);
01867 
01868   int numBuckets = buckets.size();
01869   std::vector<const std::size_t *> table(numBuckets);
01870   std::vector<std::size_t> nconnect(numBuckets);
01871 
01872 
01873   for (int b=0; b < numBuckets; b++) {
01874 
01875     stk::mesh::Bucket& cells = *buckets[b];
01876 
01877     const CellTopologyData * const elem_top 
01878              = stk::mesh::fem::get_cell_topology( cells[0] ).getCellTopologyData();
01879 
01880     if(strncmp(elem_top->name, "Hexahedron", 10) == 0){
01881        table[b] = hex_table;
01882        nconnect[b] = hex_nconnect;
01883     }
01884     else if(strncmp(elem_top->name, "Tetrahedron", 11) == 0){
01885        table[b] = tet_table;
01886        nconnect[b] = tet_nconnect;
01887     }
01888     else if(strncmp(elem_top->name, "Triangle", 8) == 0){
01889        table[b] = tri_table;
01890        nconnect[b] = tri_nconnect;
01891     }
01892     else if(strncmp(elem_top->name, "Quadrilateral", 13) == 0){
01893        table[b] = quad_table;
01894        nconnect[b] = quad_nconnect;
01895     }
01896     else
01897 
01898       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01899                            "Error - unknown element type : " << elem_top->name 
01900                            << " requested in nodal graph algorithm" << std::endl);
01901 
01902     /* Find the surrounding elements for each node owned by this processor */
01903     for (std::size_t ecnt=0; ecnt < cells.size(); ecnt++) {
01904       stk::mesh::Entity& e = cells[ecnt];
01905       stk::mesh::PairIterRelation rel = e.relations(metaData.NODE_RANK);
01906 
01907       // loop over nodes within the element
01908       for (std::size_t ncnt=0; ncnt < rel.size(); ncnt++) {
01909         stk::mesh::Entity& rowNode = * rel[ncnt].entity();
01910         int nodeGID = gid(rowNode);
01911         int nodeLID = overlap_node_map->LID(nodeGID);
01912 
01913         /*
01914          * in the case of degenerate elements, where a node can be
01915          * entered into the connect table twice, need to check to
01916          * make sure that this element is not already listed as
01917          * surrounding this node
01918          */
01919 
01920         if (sur_elem[nodeLID].empty() || entity_in_list(&e, sur_elem[nodeLID]) < 0) {
01921           /* Add the element to the list */
01922           sur_elem[nodeLID].push_back(&e);
01923         }
01924       }
01925     } /* End "for(ecnt=0; ecnt < mesh->num_elems; ecnt++)" */
01926   } // End of loop over buckets
01927 
01928   for(std::size_t ncnt=0; ncnt < numOverlapNodes; ncnt++) {
01929     if(sur_elem[ncnt].empty()) {
01930       TEUCHOS_TEST_FOR_EXCEPTION(true, std::logic_error,
01931         "Node = " << ncnt+1 << " has no elements" << std::endl);
01932     }
01933     else {
01934       std::size_t nsur = sur_elem[ncnt].size();
01935       if (nsur > max_nsur)
01936         max_nsur = nsur;
01937     }
01938   }
01939 
01940 //end find_surrnd_elems
01941 
01942 // find_adjacency
01943 
01944     // Note that the center node of a subgraph must be owned by this pe, but we want all nodes in the overlap
01945     // graph to be covered in the nodal graph
01946 
01947     /* Allocate memory necessary for the adjacency */
01948     nodalGraph.start.resize(numOverlapNodes + 1);
01949     nodalGraph.adj.clear();
01950     std::size_t nadj = 0;
01951 
01952 
01953       // loop over all the nodes owned by this PE
01954       for(std::size_t ncnt=0; ncnt < numOverlapNodes; ncnt++) {
01955 //std::cout << "Center node is : " << ncnt + 1 << " num elems around it : " << sur_elem[ncnt].size() << std::endl;
01956         // save the starting location for the nodes surrounding ncnt
01957   nodalGraph.start[ncnt] = nadj;
01958         // loop over the elements surrounding node ncnt
01959   for(std::size_t ecnt=0; ecnt < sur_elem[ncnt].size(); ecnt++) {
01960     stk::mesh::Entity* elem   = sur_elem[ncnt][ecnt];
01961 //std::cout << "   Element is : " << elem->identifier() << std::endl;
01962 
01963           stk::mesh::PairIterRelation rel = elem->relations(metaData.NODE_RANK);
01964 
01965           std::size_t ws = elemGIDws[gid(elem)].ws;
01966 
01967           // loop over the nodes in the surrounding element elem
01968           for (std::size_t lnode=0; lnode < rel.size(); lnode++) {
01969             stk::mesh::Entity& node_a = * rel[lnode].entity();
01970             // entry is the GID of each node
01971             std::size_t entry = gid(node_a);
01972 
01973             // if "entry" is not the center node AND "entry" does not appear in the current list of nodes surrounding
01974             // "ncnt", add "entry" to the adj list
01975       if(overlap_node_map->GID(ncnt) == entry){ // entry - offset lnode - is where we are in the node
01976                                                       // ordering within the element
01977 
01978                for(std::size_t k = 0; k < nconnect[ws]; k++){
01979 
01980                   int local_node = table[ws][lnode * nconnect[ws] + k]; // local number of the node connected to the center "entry"
01981 
01982                   std::size_t global_node_id = gid(*rel[local_node].entity());
01983 //std::cout << "      Local test node is : " << local_node + 1 << " offset is : " << k << " global node is : " << global_node_id + 1 <<  std::endl;
01984 
01985                   if(in_list(global_node_id,
01986            nodalGraph.adj.size()-nodalGraph.start[ncnt],
01987            &nodalGraph.adj[nodalGraph.start[ncnt]]) < 0) {
01988                        nodalGraph.adj.push_back(global_node_id);
01989 //std::cout << "            Added edge node : " << global_node_id + 1 << std::endl;
01990             }
01991                }
01992                break;
01993             }
01994     }
01995   } /* End "for(ecnt=0; ecnt < graph->nsur_elem[ncnt]; ecnt++)" */
01996 
01997         nadj = nodalGraph.adj.size();
01998 
01999       } /* End "for(ncnt=0; ncnt < mesh->num_nodes; ncnt++)" */
02000 
02001     nodalGraph.start[numOverlapNodes] = nadj;
02002 
02003 // end find_adjacency
02004 
02005 }
02006 
02007 void
02008 Albany::STKDiscretization::printVertexConnectivity(){
02009 
02010   for(std::size_t i = 0; i < numOverlapNodes; i++){
02011 
02012     std::cout << "Center vert is : " << overlap_node_map->GID(i) + 1 << std::endl;
02013 
02014     for(std::size_t j = nodalGraph.start[i]; j < nodalGraph.start[i + 1]; j++)
02015 
02016       std::cout << "                  " << nodalGraph.adj[j] + 1 << std::endl;
02017 
02018    }
02019 }
02020 
02021 void
02022 Albany::STKDiscretization::updateMesh()
02023 {
02024 
02025   computeOwnedNodesAndUnknowns();
02026 
02027   setupMLCoords();
02028 
02029   computeOverlapNodesAndUnknowns();
02030 
02031   transformMesh();
02032 
02033   computeGraphs();
02034 
02035   computeWorksetInfo();
02036 
02037   computeNodeSets();
02038 
02039   computeSideSets();
02040 
02041   setupExodusOutput();
02042 
02043   setupNetCDFOutput();
02044 //meshToGraph();
02045 //printVertexConnectivity();
02046 
02047 }

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