SundanceExodusMeshReader.cpp
Go to the documentation of this file.
00001 /* @HEADER@ */
00002 // ************************************************************************
00003 // 
00004 //                             Sundance
00005 //                 Copyright 2011 Sandia Corporation
00006 // 
00007 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
00008 // the U.S. Government retains certain rights in this software.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Kevin Long (kevin.long@ttu.edu)
00038 // 
00039 
00040 /* @HEADER@ */
00041 
00042 
00043 #include "SundanceExodusMeshReader.hpp"
00044 #include "SundanceVertexSort.hpp"
00045 #include "SundanceOut.hpp"
00046 #include "PlayaExceptions.hpp"
00047 #include "SundancePathUtils.hpp"
00048 #include "Teuchos_Time.hpp"
00049 #include "Teuchos_TimeMonitor.hpp"
00050 
00051 #ifdef HAVE_SUNDANCE_EXODUS
00052 #include "exodusII.h"
00053 #endif 
00054 
00055 using namespace Teuchos;
00056 using namespace Sundance;
00057 using namespace std;
00058 
00059 static Time& getExoTimer() 
00060 {
00061   static RCP<Time> rtn 
00062     = TimeMonitor::getNewTimer("raw exodus reader functions"); 
00063   return *rtn;
00064 }
00065 
00066 
00067 static Time& getExoFillTimer() 
00068 {
00069   static RCP<Time> rtn 
00070     = TimeMonitor::getNewTimer("exodus reader fillMesh"); 
00071   return *rtn;
00072 }
00073 
00074 
00075 ExodusMeshReader::ExodusMeshReader(const std::string& fname,
00076   const MeshType& meshType,
00077   int verbosity,
00078   const MPIComm& comm)
00079   : MeshReaderBase(fname, meshType, verbosity, comm), 
00080     exoFilename_(fname),
00081     parFilename_(fname)
00082 {
00083   Tabs tab0(0);
00084 
00085   if (nProc() > 1)
00086     {
00087       std::string suffix =  "-" + Teuchos::toString(nProc()) 
00088         + "-" + Teuchos::toString(myRank());
00089       exoFilename_ = exoFilename_ + suffix;
00090       parFilename_ = parFilename_ + suffix;
00091     }
00092   exoFilename_ = exoFilename_ + ".exo";
00093   parFilename_ = parFilename_ + ".pxo";
00094   
00095   PLAYA_MSG1(verb(), "exodus filename = " << exoFilename_);
00096   
00097   if (nProc() > 1)
00098   {
00099     SUNDANCE_OUT(this->verb() > 1,
00100       "par filename = " << parFilename_);
00101   }
00102 }
00103 
00104 
00105 
00106 
00107 
00108 Mesh ExodusMeshReader::fillMesh() const 
00109 {
00110   TimeMonitor fillTimer(getExoFillTimer());
00111   Tabs tab0(0);
00112   Tabs tab1;
00113   Mesh mesh;
00114 #ifndef HAVE_SUNDANCE_EXODUS
00115   TEUCHOS_TEST_FOR_EXCEPTION(true, std::runtime_error, 
00116     "ExodusMeshReader called for a build without ExodusII");
00117 #else
00118   PLAYA_ROOT_MSG1(verb(), tab0 << "in ExodusMeshReader::fillMesh()");
00119 
00120   int CPU_word_size = 8;
00121   int IO_word_size = 0;
00122   float version;
00123 
00124   Array<int> ptGID;
00125   Array<int> ptOwner;
00126   Array<int> elemGID;
00127   Array<int> elemOwner;
00128 
00129   readParallelInfo(ptGID, ptOwner, elemGID, elemOwner);
00130 
00131   if (verb() > 2) ex_opts(EX_DEBUG | EX_VERBOSE);
00132 
00133   PLAYA_MSG3(verb(), tab1 << "opening file");
00134   std::string resolvedName = searchForFile(exoFilename_);
00135   int exoID = ex_open(resolvedName.c_str(), EX_READ, 
00136     &CPU_word_size, &IO_word_size, &version);
00137 
00138   TEUCHOS_TEST_FOR_EXCEPTION(exoID < 0, std::runtime_error, "ExodusMeshReader unable to "
00139     "open file: " << exoFilename_);
00140 
00141   PLAYA_MSG3(verb(), tab1 << "exoID=" << exoID);
00142 
00143   TEUCHOS_TEST_FOR_EXCEPT(IO_word_size != 8 || CPU_word_size != 8);
00144 
00145   char title[MAX_LINE_LENGTH+1];
00146 
00147   int dim = 0;
00148   int numNodes = 0;
00149   int numElems = 0;
00150   int numElemBlocks = 0;
00151   int numNodeSets = 0;
00152   int numSideSets = 0;
00153 
00154   int ierr = ex_get_init(exoID, title, &dim, &numNodes, &numElems,
00155     &numElemBlocks, &numNodeSets, &numSideSets);
00156 
00157   TEUCHOS_TEST_FOR_EXCEPTION(numNodes <= 0, std::runtime_error, "invalid numNodes=" 
00158     << numNodes);
00159   TEUCHOS_TEST_FOR_EXCEPTION(numElems <= 0, std::runtime_error, "invalid numElems=" 
00160     << numElems);
00161 
00162   PLAYA_MSG2(verb(), tab1 << "numNodes=" << numNodes);
00163   PLAYA_MSG2(verb(), tab1 << "numElems=" << numElems);
00164 
00165   /* */
00166   if (nProc()==1)
00167   {
00168     ptGID.resize(numNodes);
00169     ptOwner.resize(numNodes);
00170     for (int i=0; i<numNodes; i++)
00171     {
00172       ptGID[i] = i;
00173       ptOwner[i] = 0;
00174     }
00175   }
00176   else
00177   {
00178     /* If we're running in parallel, we'd better have consistent numbers
00179      * of points in the .exo and .pex files. */
00180     TEUCHOS_TEST_FOR_EXCEPTION((int)ptGID.size() != numNodes, std::runtime_error,
00181       "ExodusMeshReader::getMesh() found inconsistent "
00182       "numbers of points in .exo file and .pex files. Exo "
00183       "file " << exoFilename_ << " had nPoints=" 
00184       << numNodes << " but .pex file " 
00185       << parFilename_ << " had nPoints=" << ptGID.size());
00186   }
00187 
00188   /* now we can build the mesh */
00189   mesh = createMesh(dim);
00190 
00191 
00192 
00193   /* Read the points */
00194   PLAYA_MSG2(verb(), tab1 << "reading vertices");
00195   Array<double> x(numNodes);
00196   Array<double> y(numNodes);
00197   Array<double> z(numNodes * (dim > 2));
00198 
00199   if (dim == 2)
00200   {
00201     ierr = ex_get_coord(exoID, &(x[0]), &(y[0]), (void*) 0);
00202     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00203     TEUCHOS_TEST_FOR_EXCEPT(ierr > 0);
00204   }
00205   else if (dim==3)
00206   {
00207     ierr = ex_get_coord(exoID, (void*) &(x[0]), (void*) &(y[0]), (void*) &(z[0]));
00208     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00209   }
00210   else 
00211   {
00212     TEUCHOS_TEST_FOR_EXCEPTION(dim < 2 || dim > 3, std::runtime_error, 
00213       "invalid dimension=" << dim << " in ExodusMeshReader");
00214   }
00215 
00216 
00217   /* add the points to the mesh */
00218   PLAYA_MSG2(verb(), tab1 << "adding vertices to mesh");
00219   for (int n=0; n<numNodes; n++)
00220   {
00221     Point p;
00222     if (dim==2)
00223     {
00224       p = Point(x[n], y[n]);
00225     }
00226     else
00227     {
00228       p = Point(x[n], y[n], z[n]);
00229     }
00230     mesh.addVertex(ptGID[n], p, ptOwner[n], 0);
00231   }
00232 
00233 
00234   /* Set up the element numbering */
00235   if (nProc()==1)
00236   {
00237     elemGID.resize(numElems);
00238     elemOwner.resize(numElems);
00239     for (int i=0; i<numElems; i++)
00240     {
00241       elemGID[i] = i;
00242       elemOwner[i] = 0;
00243     }
00244   }
00245   else
00246   {
00247     /* If we're running in parallel, we'd better have consistent numbers
00248      * of elements in the .exo and .pex files. */
00249     TEUCHOS_TEST_FOR_EXCEPTION((int)elemGID.size() != numElems, std::runtime_error,
00250       "ExodusMeshReader::readElems() found inconsistent "
00251       "numbers of elements in .exo file and .pex files. Exodus "
00252       "file " << exoFilename_ << " had nElems=" 
00253       << numElems << " but .pex file " 
00254       << parFilename_ << " had nElems=" << elemGID.size());
00255   }
00256 
00257   /* Read the elements for each block */
00258 
00259   PLAYA_MSG2(verb(), tab1 << "reading elements");
00260   Array<int> blockIDs(numElemBlocks);
00261   if (numElemBlocks > 0)
00262   {
00263     TimeMonitor timer(getExoTimer());
00264     ierr = ex_get_elem_blk_ids(exoID, &(blockIDs[0]));
00265   }
00266   TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00267   PLAYA_MSG2(verb(), tab1 << "file contains block IDs " << blockIDs);
00268   int count = 0;
00269   Array<int> permKey;
00270   permKey.resize(numElems);
00271 //  Sundance::Map<int,Array<int> > elemVerts;
00272   Array<int> blockIsSimplicial(numElemBlocks);
00273   bool allBlocksAreSimplicial = true;
00274 
00275   for (int b=0; b<numElemBlocks; b++)
00276   {
00277     Tabs tab2;
00278     char elemType[MAX_LINE_LENGTH+1];
00279     int elsInBlock=0;
00280     int nodesPerEl=0;
00281     int numAttrs=0;
00282     int bid = blockIDs[b];
00283     PLAYA_MSG2(verb(), tab2 << "reading elems for block ID=" << bid);
00284     {
00285       TimeMonitor timer(getExoTimer());
00286       ierr = ex_get_elem_block(exoID, bid, elemType, &elsInBlock,
00287         &nodesPerEl, &numAttrs);
00288     }
00289     TEUCHOS_TEST_FOR_EXCEPTION(ierr < 0, std::runtime_error,
00290       "ex_get_elem_block returned error code ierr=" << ierr);
00291 
00292     bool blockIsSimplicial = true;
00293     if (nodesPerEl != dim+1) 
00294     {
00295       blockIsSimplicial=false;
00296       allBlocksAreSimplicial=false;
00297     }
00298 
00299 
00300     /* get element connectivity */
00301     PLAYA_MSG2(verb(), tab2 << "reading connectivity for block ID=" << bid);
00302     Array<int> connect(elsInBlock * nodesPerEl);
00303 
00304     {
00305       TimeMonitor timer(getExoTimer());
00306       ierr = ex_get_elem_conn(exoID, bid, &(connect[0]));
00307     }
00308     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00309     int n=0;
00310     Array<int> orderedVerts(nodesPerEl);
00311     Array<int> exVerts(nodesPerEl);
00312 
00313     for (int e=0; e<elsInBlock; e++, n+=nodesPerEl, count++)
00314     {
00315 
00316       for (int v=0; v<nodesPerEl; v++)
00317       {
00318         orderedVerts[v] = ptGID[connect[n+v]-1];
00319       }
00320       exVerts = orderedVerts;
00321       int key = -1;
00322       if (blockIsSimplicial) 
00323       {
00324         vertexSort(orderedVerts, &key);
00325 //        elemVerts.put(elemGID[count], orderedVerts); 
00326       }
00327 
00328       int elemLID 
00329         = mesh.addElement(elemGID[count], orderedVerts, 
00330           elemOwner[count], bid);
00331       if (blockIsSimplicial) 
00332       {
00333 //        elemVerts.put(elemLID, orderedVerts); 
00334         permKey[elemLID]=key;
00335       }
00336     }
00337   }
00338 
00339   /* The topology of the mesh is now fully defined and we can call
00340    * topological functions */
00341   mesh.freezeTopology();
00342  
00343 
00344   /* Read the node sets */
00345   Array<int> nsIDs(numNodeSets);
00346   if (numNodeSets > 0)
00347   {
00348     TimeMonitor timer(getExoTimer());
00349     ierr = ex_get_node_set_ids(exoID, &(nsIDs[0]));
00350   }
00351   TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00352   for (int ns=0; ns<numNodeSets; ns++)
00353   {
00354     int nNodes;
00355     int nDist;
00356     int nsID = nsIDs[ns];
00357     {
00358       TimeMonitor timer(getExoTimer());
00359       ierr = ex_get_node_set_param(exoID, nsID, &nNodes, &nDist);
00360     }
00361     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00362     Array<int> nodes(nNodes);
00363     {
00364       TimeMonitor timer(getExoTimer());
00365       ierr = ex_get_node_set(exoID, nsID, &(nodes[0]));
00366     }
00367     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00368     for (int n=0; n<nNodes; n++)
00369     {
00370       mesh.setLabel(0, nodes[n]-1, nsID);
00371     }
00372   }
00373 
00374     
00375   /* Read the side sets */
00376   Array<int> ssIDs(numSideSets);
00377   if (numSideSets > 0)
00378   {
00379     TimeMonitor timer(getExoTimer());
00380     ierr = ex_get_side_set_ids(exoID, &(ssIDs[0]));
00381   }
00382   TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00383   for (int ss=0; ss<numSideSets; ss++)
00384   {
00385     int nSides;
00386     int nDist;
00387     int ssID = ssIDs[ss];
00388     {
00389       TimeMonitor timer(getExoTimer());
00390       ierr = ex_get_side_set_param(exoID, ssID, &nSides, &nDist);
00391     }
00392     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00393     Array<int> sides(nSides);
00394     Array<int> elems(nSides);
00395     {
00396       TimeMonitor timer(getExoTimer());
00397       ierr = ex_get_side_set(exoID, ssID, &(elems[0]), &(sides[0]));
00398     }
00399     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00400     for (int n=0; n<nSides; n++)
00401     {
00402       int elemID = elems[n]-1;
00403       int facetNum = sides[n]-1;
00404       int fsign;
00405       if (allBlocksAreSimplicial)
00406       {
00407         int key = permKey[elemID];
00408         facetNum = exFacetIndexToUFCFacetIndex(dim, key, facetNum);
00409       }
00410       int sideLID = mesh.facetLID(dim, elemID, dim-1, 
00411         facetNum, fsign);
00412       mesh.setLabel(dim-1, sideLID, ssID);
00413     }
00414   }
00415 
00416 
00417   /* Read the nodal attributes */
00418   int nNodalVars = 0;
00419   {
00420     TimeMonitor timer(getExoTimer());
00421     ierr = ex_get_var_param(exoID, "N", &nNodalVars);
00422   }
00423   TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00424 
00425   Array<Array<double> >& funcVals = *nodeAttributes();
00426   funcVals.resize(nNodalVars);
00427 
00428   for (int i=0; i<nNodalVars; i++)
00429   {
00430     int t = 1;
00431     funcVals[i].resize(mesh.numCells(0));
00432     {
00433       TimeMonitor timer(getExoTimer());
00434       ierr = ex_get_nodal_var(exoID, t, i+1, mesh.numCells(0), &(funcVals[i][0]));
00435     }
00436     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00437   }
00438 
00439   /* Read the element attributes */
00440   int nElemVars = 0;
00441   {
00442       TimeMonitor timer(getExoTimer());
00443       ierr = ex_get_var_param(exoID, "E", &nElemVars);
00444   }
00445   TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00446 
00447   Array<Array<double> >& eFuncVals = *elemAttributes();
00448   eFuncVals.resize(nElemVars);
00449 
00450   for (int i=0; i<nElemVars; i++)
00451   {
00452     int t = 1;
00453     eFuncVals[i].resize(mesh.numCells(mesh.spatialDim()));
00454     {
00455       TimeMonitor timer(getExoTimer());
00456       ierr = ex_get_elem_var(exoID, t, i+1, 1, mesh.numCells(mesh.spatialDim()), &(eFuncVals[i][0]));
00457     }
00458     TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00459   }
00460 
00461   ierr = ex_close(exoID);
00462   TEUCHOS_TEST_FOR_EXCEPT(ierr < 0);
00463 
00464 #endif
00465   return mesh;
00466 }
00467 
00468 
00469 
00470 
00471 void ExodusMeshReader::readParallelInfo(Array<int>& ptGID, 
00472   Array<int>& ptOwner,
00473   Array<int>& cellGID, 
00474   Array<int>& cellOwner) const
00475 {
00476   int nPoints;
00477   int nElems;
00478   std::string line;
00479   Array<string> tokens;
00480   try
00481   {
00482     ptGID.resize(0);
00483     ptOwner.resize(0);
00484     cellGID.resize(0);
00485     cellOwner.resize(0);
00486 
00487     /* if we're running in parallel, read the info on processor 
00488      * distribution */
00489     if (nProc() > 1)
00490     {
00491       RCP<std::ifstream> parStream 
00492         = openFile(parFilename_, "parallel info");
00493      
00494       /* read the number of processors and the processor rank in 
00495        * the file. These must be consistent with the current number of
00496        * processors and the current rank */
00497       getNextLine(*parStream, line, tokens, '#');
00498       
00499       TEUCHOS_TEST_FOR_EXCEPTION(tokens.length() != 2, std::runtime_error,
00500         "ExodusMeshReader::getMesh() expects 2 entries "
00501         "on the first line of .par file. In " 
00502         << parFilename_ << " I found \n[" << line << "]\n");
00503 
00504       int np = atoi(tokens[1]);
00505       int pid = atoi(tokens[0]);
00506 
00507       /* check consistency with the current number of
00508        * processors and the current rank */
00509       
00510       TEUCHOS_TEST_FOR_EXCEPTION(np != nProc(), std::runtime_error,
00511         "ExodusMeshReader::getMesh() found "
00512         "a mismatch between the current number of processors="
00513         << nProc() << 
00514         "and the number of processors=" << np
00515         << "in the file " << parFilename_);
00516 
00517       TEUCHOS_TEST_FOR_EXCEPTION(pid != myRank(), std::runtime_error,
00518         "ExodusMeshReader::getMesh() found "
00519         "a mismatch between the current processor rank="
00520         << myRank() << "and the processor rank="
00521         << pid << " in the file " << parFilename_);
00522 
00523       /* read the number of points */
00524       getNextLine(*parStream, line, tokens, '#');
00525 
00526       TEUCHOS_TEST_FOR_EXCEPTION(tokens.length() != 1, std::runtime_error,
00527         "ExodusMeshReader::getMesh() requires 1 entry "
00528         "on the second line of .pxo file. Found line \n[" 
00529         << line << "]\n in file " << parFilename_);
00530       
00531       nPoints = StrUtils::atoi(tokens[0]);
00532 
00533       /* read the global ID and the owner PID for each point */
00534       ptGID.resize(nPoints);
00535       ptOwner.resize(nPoints);
00536 
00537       for (int i=0; i<nPoints; i++)
00538       {
00539         getNextLine(*parStream, line, tokens, '#');
00540 
00541         TEUCHOS_TEST_FOR_EXCEPTION(tokens.length() != 3, std::runtime_error,
00542           "ExodusMeshReader::getMesh() requires 3 "
00543           "entries on each line of the point section in "
00544           "the .pxo file. Found line \n[" << line
00545           << "]\n in file " << parFilename_);
00546 
00547         ptGID[i] = StrUtils::atoi(tokens[1]);
00548         ptOwner[i] = StrUtils::atoi(tokens[2]);
00549       }
00550 
00551 
00552       /* Read the number of elements */
00553 
00554       getNextLine(*parStream, line, tokens, '#');
00555 
00556       TEUCHOS_TEST_FOR_EXCEPTION(tokens.length() != 1, std::runtime_error,
00557         "ExodusMeshReader::getMesh() requires 1 entry "
00558         "on the cell count line of .pxo file. Found line \n[" 
00559         << line << "]\n in file " << parFilename_);
00560 
00561       nElems = StrUtils::atoi(tokens[0]);
00562 
00563       SUNDANCE_OUT(this->verb() > 1,
00564         "read nElems = " << nElems);
00565 
00566 
00567       /* read the global ID and the owner PID for each element */
00568 
00569       cellGID.resize(nElems);
00570       cellOwner.resize(nElems);
00571       for (int i=0; i<nElems; i++)
00572       {
00573         getNextLine(*parStream, line, tokens, '#');
00574 
00575         TEUCHOS_TEST_FOR_EXCEPTION(tokens.length() != 3, std::runtime_error,
00576           "ExodusMeshReader::getMesh() requires 3 "
00577           "entries on each line of the element section in "
00578           "the .pxo file. Found line \n[" << line
00579           << "]\n in file " << parFilename_);
00580 
00581         cellGID[i] = StrUtils::atoi(tokens[1]);
00582         cellOwner[i] = StrUtils::atoi(tokens[2]);
00583       }
00584     }
00585 
00586     nPoints = ptGID.length();
00587     nElems = cellGID.length();
00588   }
00589   catch(std::exception& e)
00590   {
00591     SUNDANCE_TRACE(e);
00592   }
00593 }

Site Contact