moab
ReadNCDF.cpp
Go to the documentation of this file.
00001 
00016 #ifdef WIN32
00017 #pragma warning(disable:4786)
00018 #endif
00019 
00020 #include "ReadNCDF.hpp"
00021 #include "netcdf.h"
00022 
00023 #include <algorithm>
00024 #include <string>
00025 #include <assert.h>
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include <cmath>
00029 #include <sstream>
00030 #include <iostream>
00031 #include <map>
00032 
00033 #include "moab/CN.hpp"
00034 #include "moab/Range.hpp"
00035 #include "moab/Interface.hpp"
00036 #include "ExoIIUtil.hpp"
00037 #include "MBTagConventions.hpp"
00038 #include "Internals.hpp"
00039 #include "moab/ReadUtilIface.hpp"
00040 #include "exodus_order.h"
00041 #include "moab/FileOptions.hpp"
00042 #include "moab/AdaptiveKDTree.hpp"
00043 #include "moab/CartVect.hpp"
00044 
00045 namespace moab {
00046 
00047 #define INS_ID(stringvar, prefix, id) \
00048           sprintf(stringvar, prefix, id)
00049           
00050 #define GET_DIM(ncdim, name, val)\
00051     {                            \
00052     int gdfail = nc_inq_dimid(ncFile, name, &ncdim);          \
00053     if (NC_NOERR == gdfail) {                                             \
00054       size_t tmp_val;                                                   \
00055       gdfail = nc_inq_dimlen(ncFile, ncdim, &tmp_val);                        \
00056       if (NC_NOERR != gdfail) {                                           \
00057         readMeshIface->report_error("ReadNCDF:: couldn't get dimension length."); \
00058         return MB_FAILURE;                                              \
00059       }                                                                 \
00060       else val = tmp_val;                                               \
00061     } else val = 0;}
00062 
00063 #define GET_DIMB(ncdim, name, varname, id, val) \
00064           INS_ID(name, varname, id); \
00065           GET_DIM(ncdim, name, val);
00066 
00067 #define GET_VAR(name, id, dims) \
00068     {                           \
00069     id = -1;\
00070     int gvfail = nc_inq_varid(ncFile, name, &id);   \
00071     if (NC_NOERR == gvfail) {       \
00072     int ndims;\
00073     gvfail = nc_inq_varndims(ncFile, id, &ndims);\
00074     if (NC_NOERR == gvfail) {\
00075     dims.resize(ndims);    \
00076     gvfail = nc_inq_vardimid(ncFile, id, &dims[0]);}}}
00077     
00078 #define GET_1D_INT_VAR(name, id, vals) \
00079     {GET_VAR(name, id, vals);  \
00080   if (-1 != id) {\
00081     size_t ntmp;\
00082     int ivfail = nc_inq_dimlen(ncFile, vals[0], &ntmp);\
00083     vals.resize(ntmp);\
00084     size_t ntmp1 = 0;                                                           \
00085     ivfail = nc_get_vara_int(ncFile, id, &ntmp1, &ntmp, &vals[0]);\
00086     if (NC_NOERR != ivfail) {\
00087       readMeshIface->report_error("ReadNCDF:: Problem getting variable %s.", name);\
00088       return MB_FAILURE;}}}
00089 
00090 
00091 #define GET_1D_DBL_VAR(name, id, vals) \
00092     {std::vector<int> dum_dims;        \
00093   GET_VAR(name, id, dum_dims);\
00094   if (-1 != id) {\
00095     size_t ntmp;\
00096     int dvfail = nc_inq_dimlen(ncFile, dum_dims[0], &ntmp);\
00097     vals.resize(ntmp);\
00098     size_t ntmp1 = 0;                                                           \
00099     dvfail = nc_get_vara_double(ncFile, id, &ntmp1, &ntmp, &vals[0]);\
00100     if (NC_NOERR != dvfail) {\
00101       readMeshIface->report_error("ReadNCDF:: Problem getting variable %s.", name);\
00102       return MB_FAILURE;}}}
00103 
00104 ReaderIface* ReadNCDF::factory( Interface* iface )
00105   { return new ReadNCDF( iface ); }
00106 
00107 ReadNCDF::ReadNCDF(Interface* impl)
00108     : mdbImpl(impl), max_line_length(-1), max_str_length(-1)
00109 {
00110   assert(impl != NULL);
00111   reset();
00112   
00113   impl->query_interface( readMeshIface );
00114 
00115   // initialize in case tag_get_handle fails below
00116   mMaterialSetTag  = 0;
00117   mDirichletSetTag = 0;
00118   mNeumannSetTag   = 0;
00119   mHasMidNodesTag  = 0;
00120   mDistFactorTag   = 0;
00121   mQaRecordTag     = 0;
00122   mGlobalIdTag     = 0;
00123 
00125   ErrorCode result;
00126   const int zero = 0, negone = -1;
00127   result = impl->tag_get_handle(MATERIAL_SET_TAG_NAME, 1, MB_TYPE_INTEGER,
00128                                 mMaterialSetTag, MB_TAG_SPARSE|MB_TAG_CREAT, &negone);
00129   assert(MB_SUCCESS == result);
00130   result = impl->tag_get_handle(DIRICHLET_SET_TAG_NAME, 1, MB_TYPE_INTEGER,
00131                                 mDirichletSetTag, MB_TAG_SPARSE|MB_TAG_CREAT, &negone);
00132   assert(MB_SUCCESS == result);
00133   result = impl->tag_get_handle(NEUMANN_SET_TAG_NAME, 1, MB_TYPE_INTEGER,
00134                                 mNeumannSetTag, MB_TAG_SPARSE|MB_TAG_CREAT, &negone);
00135   assert(MB_SUCCESS == result);
00136   const int mids[] = {-1, -1, -1, -1};
00137   result = impl->tag_get_handle(HAS_MID_NODES_TAG_NAME, 4, MB_TYPE_INTEGER,
00138                                 mHasMidNodesTag, MB_TAG_SPARSE|MB_TAG_CREAT, mids);
00139   assert(MB_SUCCESS == result);
00140   result = impl->tag_get_handle("distFactor", 0, MB_TYPE_DOUBLE, mDistFactorTag,
00141                                 MB_TAG_SPARSE|MB_TAG_VARLEN|MB_TAG_CREAT);
00142   assert(MB_SUCCESS == result);
00143   result = impl->tag_get_handle("qaRecord", 0, MB_TYPE_OPAQUE, mQaRecordTag,
00144                                 MB_TAG_SPARSE|MB_TAG_VARLEN|MB_TAG_CREAT);
00145   result = impl->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER,
00146                                 mGlobalIdTag, MB_TAG_SPARSE|MB_TAG_CREAT, &zero);
00147   assert(MB_SUCCESS == result);
00148 #ifdef NDEBUG
00149   if (MB_SUCCESS == result) {}; // line to avoid compiler warning about unused variable
00150 #endif
00151   ncFile = 0;
00152 }
00153 
00154 void ReadNCDF::reset()
00155 {
00156   numberDimensions_loading = -1;
00157   mCurrentMeshHandle = 0;
00158   vertexOffset = 0; 
00159 
00160   numberNodes_loading = 0;
00161   numberElements_loading = 0;
00162   numberElementBlocks_loading = 0;
00163   numberNodeSets_loading = 0;
00164   numberSideSets_loading = 0;
00165   numberDimensions_loading = 0;
00166 
00167   if( !blocksLoading.empty() )
00168     blocksLoading.clear();
00169 
00170   if( !nodesInLoadedBlocks.empty() )
00171     nodesInLoadedBlocks.clear();
00172 }
00173 
00174 ReadNCDF::~ReadNCDF() 
00175 {
00176   mdbImpl->release_interface(readMeshIface);
00177 }
00178   
00179 ErrorCode ReadNCDF::read_tag_values(const char* file_name,
00180                                     const char* tag_name,
00181                                     const FileOptions& ,
00182                                     std::vector<int>& id_array,
00183                                     const SubsetList* subset_list )
00184 {
00185   if (subset_list) {
00186     readMeshIface->report_error( "ExodusII reader supports subset read only by material ID." );
00187     return MB_UNSUPPORTED_OPERATION;
00188   }
00189 
00190       // open netcdf/exodus file
00191   int fail = nc_open(file_name, 0, &ncFile);
00192   if (NC_NOWRITE != fail) {
00193     readMeshIface->report_error("ReadNCDF:: problem opening Netcdf/Exodus II file %s",file_name);
00194     return MB_FILE_DOES_NOT_EXIST;
00195   }
00196 
00197     // 1. Read the header
00198   ErrorCode rval = read_exodus_header( );
00199   if (MB_FAILURE == rval) 
00200     return rval;
00201   
00202   int count = 0;
00203   const char* prop;
00204   const char* blocks   = "eb_prop1";
00205   const char* nodesets = "ns_prop1";
00206   const char* sidesets = "ss_prop1";
00207   
00208   if (!strcmp(tag_name, MATERIAL_SET_TAG_NAME)) {
00209     count = numberElementBlocks_loading;
00210     prop = blocks;
00211   }
00212   else if (!strcmp(tag_name, DIRICHLET_SET_TAG_NAME)) {
00213     count = numberNodeSets_loading;
00214     prop = nodesets;
00215   }
00216   else if (!strcmp(tag_name, NEUMANN_SET_TAG_NAME)) {
00217     count = numberSideSets_loading;
00218     prop = sidesets;
00219   }
00220   else {  
00221     ncFile = 0;
00222     return MB_TAG_NOT_FOUND;
00223   }
00224   
00225   if (count) {
00226     int nc_var = -1;
00227     GET_1D_INT_VAR(prop, nc_var, id_array);
00228     if (!nc_var) {
00229       readMeshIface->report_error("Problem getting prop variable.");
00230       return MB_FAILURE;
00231     }
00232   }
00233   
00234   return MB_SUCCESS;
00235 }
00236 
00237 ErrorCode ReadNCDF::load_file(const char *exodus_file_name,
00238                               const EntityHandle* file_set,
00239                               const FileOptions& opts,
00240                               const ReaderIface::SubsetList* subset_list,
00241                               const Tag* file_id_tag)
00242 {
00243   ErrorCode status;
00244   int fail;
00245   
00246   int num_blocks = 0;
00247   const int* blocks_to_load = 0;
00248   if (subset_list) {
00249     if (subset_list->tag_list_length > 1 ||
00250         !strcmp( subset_list->tag_list[0].tag_name, MATERIAL_SET_TAG_NAME) ) {
00251       readMeshIface->report_error( "ExodusII reader supports subset read only by material ID." );
00252       return MB_UNSUPPORTED_OPERATION;
00253     }
00254     if (subset_list->num_parts) {
00255       readMeshIface->report_error( "ExodusII reader does not support mesh partitioning");
00256       return MB_UNSUPPORTED_OPERATION;
00257     }
00258     blocks_to_load = subset_list->tag_list[0].tag_values;
00259     num_blocks = subset_list->tag_list[0].num_tag_values;
00260   }
00261   
00262     // this function directs the reading of an exoii file, but doesn't do any of
00263     // the actual work
00264   
00265   //See if opts has tdata.
00266   ErrorCode rval;
00267   std::string s;
00268   rval = opts.get_str_option("tdata", s ); 
00269   if(MB_SUCCESS == rval && !s.empty())
00270     return update(exodus_file_name, opts, num_blocks, blocks_to_load, *file_set); 
00271 
00272   reset();
00273 
00274   // 0. Open the file.
00275 
00276       // open netcdf/exodus file
00277   fail = nc_open(exodus_file_name, 0, &ncFile);
00278   if (NC_NOERR != fail)
00279   {
00280     readMeshIface->report_error("ReadNCDF:: problem opening Netcdf/Exodus II file %s",exodus_file_name);
00281     return MB_FILE_DOES_NOT_EXIST;
00282   }
00283 
00284     // 1. Read the header
00285   status = read_exodus_header();
00286   if (MB_FAILURE == status) return status;
00287   
00288   status = mdbImpl->get_entities_by_handle(0, initRange);
00289   if (MB_FAILURE == status) return status;
00290 
00291     // 2. Read the nodes unless they've already been read before
00292   status = read_nodes(file_id_tag);
00293   if (MB_FAILURE == status) return status;
00294  
00295     //3. 
00296   status = read_block_headers(blocks_to_load, num_blocks);
00297   if (MB_FAILURE == status) return status;
00298 
00299     // 4. Read elements (might not read them, depending on active blocks)
00300   status = read_elements(file_id_tag);
00301   if (MB_FAILURE == status) return status;
00302   
00303     // 5. Read global ids
00304   status = read_global_ids();
00305   if (MB_FAILURE == status) return status;
00306   
00307     // 6. Read nodesets
00308   status = read_nodesets();
00309   if (MB_FAILURE == status) return status;
00310   
00311     // 7. Read sidesets
00312   status = read_sidesets();
00313   if (MB_FAILURE == status) return status;
00314 
00315     // 8. Read qa records
00316   if (file_set) {
00317     status = read_qa_records(*file_set);
00318     if (MB_FAILURE == status) return status;
00319   }
00320 
00321     // what about properties???
00322 
00323   ncFile = 0;
00324   return MB_SUCCESS;
00325 }
00326 
00327 ErrorCode ReadNCDF::read_exodus_header()
00328 {
00329   CPU_WORD_SIZE = sizeof(double);  // With ExodusII version 2, all floats
00330   IO_WORD_SIZE = sizeof(double);   // should be changed to doubles
00331   
00332     // NetCDF doesn't check its own limits on file read, so check
00333     // them here so it doesn't corrupt memory any more than absolutely
00334     // necessary.
00335   int ndims;
00336   int fail = nc_inq_ndims(ncFile, &ndims);
00337   if (NC_NOERR != fail || ndims > NC_MAX_DIMS) {
00338     readMeshIface->report_error("ReadNCDF: File contains %d dims but NetCDF library supports only %d\n",
00339                                 ndims, (int)NC_MAX_DIMS);
00340     return MB_FAILURE;
00341   }
00342   int nvars;
00343   fail = nc_inq_nvars(ncFile, &nvars);
00344   if (nvars > NC_MAX_VARS) {
00345     readMeshIface->report_error("ReadNCDF: File contains %d vars but NetCDF library supports only %d\n",
00346                                 nvars, (int)NC_MAX_VARS);
00347     return MB_FAILURE;
00348   }
00349   
00350     // get the attributes
00351 
00352     // get the word size, scalar value
00353   nc_type att_type;
00354   size_t att_len;
00355   fail = nc_inq_att(ncFile, NC_GLOBAL, "floating_point_word_size", &att_type, &att_len);
00356   if (NC_NOERR != fail) {
00357     readMeshIface->report_error("ReadNCDF:: Problem getting floating_point_word_size attribute.");
00358     return MB_FAILURE;
00359   }
00360   if (att_type != NC_INT || att_len != 1) {
00361     readMeshIface->report_error("ReadNCDF:: Word size didn't have type int or size 1.");
00362     return MB_FAILURE;
00363   }
00364   fail = nc_get_att_int(ncFile, NC_GLOBAL, "floating_point_word_size", &IO_WORD_SIZE);
00365   if (NC_NOERR != fail) {
00366     readMeshIface->report_error("ReadNCDF:: Trouble getting word size.");
00367     return MB_FAILURE;
00368   }
00369 
00370     // exodus version
00371   fail = nc_inq_att(ncFile, NC_GLOBAL, "version", &att_type, &att_len);
00372   if (NC_NOERR != fail) {
00373     readMeshIface->report_error("ReadNCDF:: Problem getting version attribute.");
00374     return MB_FAILURE;
00375   }
00376   if (att_type != NC_FLOAT || att_len != 1) {
00377     readMeshIface->report_error("ReadNCDF:: Version didn't have type float or size 1.");
00378     return MB_FAILURE;
00379   }
00380     // float version = temp_att->as_float(0);
00381 
00382     // read in initial variables
00383   int temp_dim;
00384   GET_DIM(temp_dim, "num_dim", numberDimensions_loading);
00385   GET_DIM(temp_dim, "num_nodes", numberNodes_loading);
00386   GET_DIM(temp_dim, "num_elem", numberElements_loading);
00387   GET_DIM(temp_dim, "num_el_blk", numberElementBlocks_loading);
00388   GET_DIM(temp_dim, "num_elem", numberElements_loading);
00389   GET_DIM(temp_dim, "num_node_sets", numberNodeSets_loading);
00390   GET_DIM(temp_dim, "num_side_sets", numberSideSets_loading);
00391   GET_DIM(temp_dim, "len_string", max_str_length);
00392   GET_DIM(temp_dim, "len_line", max_line_length);
00393 
00394     // title; why are we even bothering if we're not going to keep it???
00395   fail = nc_inq_att(ncFile, NC_GLOBAL, "title", &att_type, &att_len);
00396   if (NC_NOERR != fail) {
00397     readMeshIface->report_error("ReadNCDF:: Problem getting title attribute.");
00398     return MB_FAILURE;
00399   }
00400   if (att_type != NC_CHAR) {
00401     readMeshIface->report_error("ReadNCDF:: title didn't have type char.");
00402     return MB_FAILURE;
00403   }
00404   char *title = new char[att_len + 1];
00405   fail = nc_get_att_text(ncFile, NC_GLOBAL, "title", title);
00406   if (NC_NOERR != fail) {
00407     readMeshIface->report_error("ReadNCDF:: trouble getting title.");
00408     delete[] title;
00409     return MB_FAILURE;
00410   }
00411   delete[] title;
00412 
00413   return MB_SUCCESS;
00414 }
00415  
00416 ErrorCode ReadNCDF::read_nodes(const Tag* file_id_tag)
00417 {
00418     // read the nodes into memory
00419 
00420   assert(0 != ncFile);
00421 
00422   // create a sequence to hold the node coordinates
00423   // get the current number of entities and start at the next slot
00424 
00425   EntityHandle node_handle = 0;
00426   std::vector<double*> arrays;
00427   readMeshIface->get_node_coords(3, numberNodes_loading, 
00428       MB_START_ID, node_handle, arrays);
00429   
00430   vertexOffset = ID_FROM_HANDLE( node_handle ) - MB_START_ID;
00431 
00432   // read in the coordinates
00433   int fail;
00434   int coord = 0;
00435   nc_inq_varid(ncFile, "coord", &coord );
00436   
00437   // single var for all coords
00438   size_t start[2] = {0, 0}, count[2] = {1, static_cast<size_t>(numberNodes_loading)};
00439   if (coord) {
00440     
00441     for (int d = 0; d < numberDimensions_loading; ++d) {
00442       start[0] = d;
00443       fail = nc_get_vara_double(ncFile, coord, start, count, arrays[d]);
00444       if (NC_NOERR != fail) {
00445         readMeshIface->report_error("ReadNCDF:: Problem getting %c coord array.", 'x'+d);
00446         return MB_FAILURE;
00447       }
00448     }
00449   }
00450   // var for each coord
00451   else {
00452     char varname[] = "coord ";
00453     for (int d = 0; d < numberDimensions_loading; ++d) {
00454       varname[5] = 'x'+ (char)d;
00455       fail = nc_inq_varid(ncFile, varname, &coord );
00456       if (NC_NOERR != fail) {
00457         readMeshIface->report_error("ReadNCDF:: Problem getting %c coord variable.", 'x'+d);
00458         return MB_FAILURE;
00459       }
00460       
00461       fail = nc_get_vara_double(ncFile, coord, start, &count[1], arrays[d]);
00462       if (NC_NOERR != fail) {
00463         readMeshIface->report_error("ReadNCDF:: Problem getting %c coord array.", 'x'+d);
00464         return MB_FAILURE;
00465       }
00466     }
00467   }
00468   
00469   // zero out any coord values that are in database but not in file
00470   // (e.g. if MOAB has 3D coords but file is 2D then set Z coords to zero.)
00471   for (unsigned d = numberDimensions_loading; d < arrays.size(); ++d)
00472     std::fill( arrays[d], arrays[d]+numberNodes_loading, 0.0 );
00473   
00474   if (file_id_tag) {
00475     Range nodes;
00476     nodes.insert( node_handle, node_handle + numberNodes_loading - 1 );
00477     readMeshIface->assign_ids( *file_id_tag, nodes, vertexOffset );
00478   }
00479   
00480   return MB_SUCCESS;
00481 }
00482 
00483 ErrorCode ReadNCDF::read_block_headers(const int *blocks_to_load,
00484                                            const int num_blocks)
00485 {
00486      
00487     // get the element block ids; keep this in a separate list, 
00488     // which is not offset by blockIdOffset; this list used later for
00489     // reading block connectivity
00490 
00491 
00492   // get the ids of all the blocks of this file we're reading in
00493   std::vector<int> block_ids(numberElementBlocks_loading);
00494   int nc_block_ids = -1;
00495   GET_1D_INT_VAR("eb_prop1", nc_block_ids, block_ids);
00496   if (-1 == nc_block_ids) {
00497     readMeshIface->report_error("ReadNCDF:: Problem getting eb_prop1 variable.");
00498     return MB_FAILURE;
00499   }
00500 
00501   int exodus_id = 1;
00502 
00503   // if the active_block_id_list is NULL all blocks are active. 
00504   if (NULL == blocks_to_load || 0 == num_blocks) {
00505     blocks_to_load = &block_ids[0];
00506   }
00507 
00508   std::vector<int> new_blocks(blocks_to_load,blocks_to_load+numberElementBlocks_loading);
00509 
00510   std::vector<int>::iterator iter, end_iter;
00511   iter = block_ids.begin();
00512   end_iter = block_ids.end();
00513 
00514     // read header information and initialize header-type block information
00515   int temp_dim;
00516   std::vector<char> temp_string_storage(max_str_length+1);
00517   char *temp_string = &temp_string_storage[0];
00518   int block_seq_id = 1;
00519   
00520   for(; iter != end_iter; iter++, block_seq_id++ )
00521   {
00522     int num_elements;
00523 
00524     GET_DIMB(temp_dim, temp_string, "num_el_in_blk%d", block_seq_id, num_elements);
00525 
00526       // don't read element type string for now, since it's an attrib
00527       // on the connectivity
00528       // get the entity type corresponding to this ExoII element type
00529       //ExoIIElementType elem_type = 
00530       //ExoIIUtil::static_element_name_to_type(element_type_string);
00531 
00532     // tag each element block(mesh set) with enum for ElementType (SHELL, QUAD4, ....etc)
00533     ReadBlockData block_data;
00534     block_data.elemType = EXOII_MAX_ELEM_TYPE;
00535     block_data.blockId = *iter;
00536     block_data.startExoId = exodus_id; 
00537     block_data.numElements = num_elements;
00538 
00539     //if block is in 'blocks_to_load'----load it!
00540     if( std::find(new_blocks.begin(), new_blocks.end(), *iter) 
00541         != block_ids.end()) 
00542     { 
00543       block_data.reading_in = true;
00544     }
00545     else
00546     {
00547       block_data.reading_in = false;
00548     }
00549 
00550     blocksLoading.push_back( block_data );
00551     exodus_id += num_elements;
00552 
00553   }
00554 
00555   return MB_SUCCESS;
00556 }
00557 
00558 ErrorCode ReadNCDF::read_elements(const Tag* file_id_tag)
00559 {
00560     // read in elements
00561   
00562   int result = 0;
00563 
00564   // intialize the nodeInLoadedBlocks vector
00565   nodesInLoadedBlocks.resize(numberNodes_loading+1);
00566   memset(&nodesInLoadedBlocks[0], 0, (numberNodes_loading+1)*sizeof(char));
00567 
00568   std::vector<ReadBlockData>::iterator this_it;
00569     this_it = blocksLoading.begin();
00570 
00571 
00572   std::vector<char> temp_string_storage(max_str_length+1);
00573   char *temp_string = &temp_string_storage[0];
00574   int nc_var;
00575   int block_seq_id = 1;
00576   std::vector<int> dims;
00577   size_t start[2] = {0, 0}, count[2];
00578   
00579   for (; this_it != blocksLoading.end(); this_it++, block_seq_id++) 
00580   {
00581     // if this block isn't to be read in --- continue
00582     if( !(*this_it).reading_in )
00583       continue;
00584 
00585     // get some information about this block
00586     int block_id = (*this_it).blockId;
00587     EntityHandle *conn = 0;
00588 
00589       // get the ncdf connect variable and the element type
00590     INS_ID(temp_string, "connect%d", block_seq_id);
00591     GET_VAR(temp_string, nc_var, dims);
00592     if (!nc_var) {
00593       readMeshIface->report_error("ReadNCDF:: Problem getting connect variable.");
00594       return MB_FAILURE;
00595     }
00596     nc_type att_type;
00597     size_t att_len;
00598     int fail = nc_inq_att(ncFile, nc_var, "elem_type", &att_type, &att_len);
00599     if (NC_NOERR != fail) {
00600       readMeshIface->report_error("ReadNCDF:: Problem getting elem type attribute.");
00601       return MB_FAILURE;
00602     }
00603     std::vector<char> dum_str(att_len+1);
00604     fail = nc_get_att_text(ncFile, nc_var, "elem_type", &dum_str[0]);
00605     if (NC_NOERR != fail) {
00606       readMeshIface->report_error("ReadNCDF:: Problem getting elem type.");
00607       return MB_FAILURE;
00608     }
00609     ExoIIElementType elem_type = 
00610       ExoIIUtil::static_element_name_to_type(&dum_str[0]);
00611     (*this_it).elemType = elem_type;
00612     
00613     int verts_per_element = ExoIIUtil::VerticesPerElement[(*this_it).elemType];
00614     int number_nodes = (*this_it).numElements*verts_per_element;
00615     const EntityType mb_type = ExoIIUtil::ExoIIElementMBEntity[(*this_it).elemType];
00616 
00617     // allocate an array to read in connectivity data
00618     readMeshIface->get_element_connect(
00619         this_it->numElements,
00620         verts_per_element,
00621         mb_type,
00622         this_it->startExoId,
00623         this_it->startMBId,
00624         conn);
00625         
00626         // create a range for this sequence of elements
00627       EntityHandle start_range, end_range;
00628       start_range = (*this_it).startMBId;
00629       end_range   = start_range + (*this_it).numElements-1;
00630 
00631       Range new_range(start_range, end_range);
00632       //Range<EntityHandle> new_range((*this_it).startMBId, 
00633       //                                  (*this_it).startMBId+(*this_it).numElements-1);
00634     
00635         // create a MBSet for this block and set the material tag
00636 
00637       EntityHandle ms_handle;
00638       if( mdbImpl->create_meshset( MESHSET_SET | MESHSET_TRACK_OWNER, ms_handle ) != MB_SUCCESS)
00639         return MB_FAILURE;
00640 
00641       if( mdbImpl->add_entities( ms_handle, new_range) != MB_SUCCESS )
00642         return MB_FAILURE;
00643         
00644       int mid_nodes[4];
00645       CN::HasMidNodes( mb_type, verts_per_element, mid_nodes );
00646       if( mdbImpl->tag_set_data( mHasMidNodesTag, &ms_handle, 1, mid_nodes ) != MB_SUCCESS )
00647         return MB_FAILURE;
00648       
00649     // just a check because the following code won't work if this case fails
00650     assert(sizeof(EntityHandle) >= sizeof(int));
00651 
00652     // tmp_ptr is of type int* and points at the same place as conn
00653     int* tmp_ptr = reinterpret_cast<int*>(conn);
00654     
00655     // read the connetivity into that memory,  this will take only part of the array
00656     // 1/2 if sizeof(EntityHandle) == 64 bits.
00657     count[0] = this_it->numElements;
00658     count[1] = verts_per_element;
00659     fail = nc_get_vara_int(ncFile, nc_var, start, count, tmp_ptr);
00660     if (NC_NOERR != fail) {
00661       readMeshIface->report_error("ReadNCDF:: Problem getting connectivity.");
00662       return MB_FAILURE;
00663     }
00664 
00665       // Convert from exodus indices to vertex handles.
00666       // Iterate backwards in case handles are larger than ints.
00667     for (int i = number_nodes - 1; i >= 0; --i)
00668     {
00669       if ((unsigned)tmp_ptr[i] >= nodesInLoadedBlocks.size()) {
00670         readMeshIface->report_error( "Invalid node ID in block connectivity\n");
00671         return MB_FAILURE;
00672       }
00673       nodesInLoadedBlocks[tmp_ptr[i]] = 1;
00674       conn[i] = static_cast<EntityHandle>(tmp_ptr[i]) + vertexOffset;
00675     }
00676     
00677     // Adjust connectivity order if necessary
00678     const int* reorder = exodus_elem_order_map[mb_type][verts_per_element];
00679     if (reorder)
00680       ReadUtilIface::reorder( reorder, conn, this_it->numElements, verts_per_element );
00681 
00682     readMeshIface->update_adjacencies((*this_it).startMBId, (*this_it).numElements,
00683                                       ExoIIUtil::VerticesPerElement[(*this_it).elemType], conn);
00684 
00685     if ( result == -1 )
00686     {
00687       readMeshIface->report_error("ReadNCDF:: error getting element connectivity for block %i",
00688           block_id);
00689       return MB_FAILURE;
00690     }
00691 
00692     //set the block id with an offset
00693     if( mdbImpl->tag_set_data( mMaterialSetTag, &ms_handle, 1, &block_id ) != MB_SUCCESS )
00694       return MB_FAILURE;
00695     if( mdbImpl->tag_set_data( mGlobalIdTag, &ms_handle, 1, &block_id ) != MB_SUCCESS )
00696       return MB_FAILURE;
00697 
00698     if (file_id_tag) {
00699       Range range;
00700       range.insert( this_it->startMBId, this_it->startMBId + this_it->numElements - 1 );
00701       readMeshIface->assign_ids( *file_id_tag, range, this_it->startExoId );
00702     }
00703   }
00704 
00705   return MB_SUCCESS;
00706 }
00707   
00708 ErrorCode ReadNCDF::read_global_ids()
00709 {
00710     // read in the map from the exodus file
00711   std::vector<int> ids(std::max(numberElements_loading, numberNodes_loading));
00712 
00713   int varid = -1;
00714   GET_1D_INT_VAR("elem_map", varid, ids);
00715   if (-1 != varid) {
00716     std::vector<ReadBlockData>::iterator iter;
00717     int id_pos = 0;
00718     for(iter = blocksLoading.begin(); iter != blocksLoading.end(); ++iter)
00719     {
00720       if (iter->reading_in)
00721       {
00722         if (iter->startMBId != 0)
00723         {
00724           Range range(iter->startMBId, iter->startMBId+iter->numElements-1);
00725           ErrorCode error = mdbImpl->tag_set_data(mGlobalIdTag, 
00726                                                     range, &ids[id_pos]);
00727           if (error != MB_SUCCESS)
00728             return error;
00729           id_pos += iter->numElements;
00730         }
00731         else
00732         {
00733           return MB_FAILURE;
00734         }
00735       }
00736     }
00737   }
00738 
00739     // read in node map next
00740   varid = -1;
00741   GET_1D_INT_VAR("node_num_map", varid, ids);
00742   if (-1 != varid) {
00743     Range range(MB_START_ID+vertexOffset, 
00744                   MB_START_ID+vertexOffset+numberNodes_loading-1);
00745     ErrorCode error = mdbImpl->tag_set_data(mGlobalIdTag, 
00746                                               range, &ids[0]);
00747     if (MB_SUCCESS != error)
00748       readMeshIface->report_error("ReadNCDF:: Problem setting node global ids.");
00749   }
00750   
00751   return MB_SUCCESS;
00752 }
00753 
00754 ErrorCode ReadNCDF::read_nodesets() 
00755 {
00756     // read in the nodesets for the model
00757 
00758   if(0 == numberNodeSets_loading) return MB_SUCCESS;
00759   std::vector<int> id_array(numberNodeSets_loading);
00760 
00761     // read in the nodeset ids
00762   int nc_var;
00763   GET_1D_INT_VAR("ns_prop1", nc_var, id_array);
00764   if (-1 == nc_var) {
00765     readMeshIface->report_error("ReadNCDF:: Problem getting ns_prop1 variable.");
00766     return MB_FAILURE;
00767   }
00768 
00769     // use a vector of ints to read node handles
00770   std::vector<int> node_handles;
00771 
00772   int i;
00773   std::vector<char> temp_string_storage(max_str_length+1);
00774   char *temp_string = &temp_string_storage[0];
00775   int temp_dim;
00776   for(i = 0; i < numberNodeSets_loading; i++)
00777   {
00778       // get nodeset parameters
00779     int number_nodes_in_set;
00780     int number_dist_factors_in_set;
00781 
00782     GET_DIMB(temp_dim, temp_string, "num_nod_ns%d", i+1, number_nodes_in_set);
00783     GET_DIMB(temp_dim, temp_string, "num_df_ns%d", i+1, number_dist_factors_in_set);
00784 
00785       // need to new a vector to store dist. factors 
00786       // this vector * gets stored as a tag on the sideset meshset
00787     std::vector<double> temp_dist_factor_vector( number_nodes_in_set );
00788     if( number_dist_factors_in_set != 0)
00789     {
00790       INS_ID(temp_string, "dist_fact_ns%d", i+1);
00791       GET_1D_DBL_VAR(temp_string, temp_dim, temp_dist_factor_vector);
00792       if (-1 == temp_dim) {
00793         readMeshIface->report_error("ReadNCDF:: Problem getting dist fact variable.");
00794         return MB_FAILURE;
00795       }
00796     }
00797 
00798       // size new arrays and get ids and distribution factors
00799     if (node_handles.size() < (unsigned int)number_nodes_in_set) {
00800       node_handles.reserve(number_nodes_in_set);
00801       node_handles.resize(number_nodes_in_set);
00802     }
00803 
00804     INS_ID(temp_string, "node_ns%d", i+1);
00805     int temp_var = -1;
00806     GET_1D_INT_VAR(temp_string, temp_var, node_handles);
00807     if (-1 == temp_var) {
00808       readMeshIface->report_error("ReadNCDF:: Problem getting nodeset node variable.");
00809       return MB_FAILURE;
00810     }
00811 
00812       // Maybe there is already a nodesets meshset here we can append to 
00813     Range child_meshsets;
00814     if( mdbImpl->get_entities_by_handle(0, child_meshsets ) != MB_SUCCESS ) 
00815       return MB_FAILURE;
00816 
00817     child_meshsets = subtract( child_meshsets, initRange);
00818 
00819     Range::iterator iter, end_iter;
00820     iter = child_meshsets.begin();
00821     end_iter = child_meshsets.end();
00822 
00823     EntityHandle ns_handle = 0;
00824     for(; iter != end_iter; iter++)
00825     {
00826       int nodeset_id;
00827       if( mdbImpl->tag_get_data( mDirichletSetTag, &(*iter), 1, &nodeset_id ) != MB_SUCCESS )
00828         continue; 
00829 
00830       if(id_array[i] == nodeset_id )
00831       {
00832           //found the meshset
00833         ns_handle = *iter;
00834         break;
00835       }
00836     } 
00837 
00838     std::vector< EntityHandle > nodes_of_nodeset;
00839     if( ns_handle )
00840       if( mdbImpl->get_entities_by_handle( ns_handle, nodes_of_nodeset, true) != MB_SUCCESS )
00841         return MB_FAILURE;
00842 
00843       // make these into entity handles
00844       // TODO: could we have read it into EntityHandle sized array in the first place?
00845     int j, temp;
00846     std::vector<EntityHandle> nodes;
00847     std::vector<double> dist_factor_vector;
00848     for (j = 0; j < number_nodes_in_set; j++)
00849     {
00850         //see if this node is one we're currently reading in
00851       if( nodesInLoadedBlocks[node_handles[j]] == 1 )
00852       {
00853           //make sure that it already isn't in a nodeset
00854         unsigned int node_id = CREATE_HANDLE(MBVERTEX, node_handles[j]+vertexOffset, temp);
00855         if( !ns_handle || 
00856             std::find(nodes_of_nodeset.begin(), nodes_of_nodeset.end(), node_id) == nodes_of_nodeset.end() )
00857         { 
00858           nodes.push_back( node_id );
00859         
00860           if( number_dist_factors_in_set != 0)
00861           {
00862             dist_factor_vector.push_back( temp_dist_factor_vector[j] );
00863           }
00864         }
00865       }
00866     }
00867     
00868       // no nodes to add 
00869     if( nodes.empty() )
00870       continue; 
00871 
00872       //if there was no meshset found --> create one
00873     if( ns_handle == 0)
00874     {
00875       if( mdbImpl->create_meshset( MESHSET_ORDERED | MESHSET_TRACK_OWNER, ns_handle ) != MB_SUCCESS) 
00876         return MB_FAILURE;
00877 
00878         // set a tag signifying dirichlet bc
00879         // TODO: create this tag another way
00880 
00881       int nodeset_id = id_array[i];
00882       if( mdbImpl->tag_set_data(mDirichletSetTag, &ns_handle, 1, &nodeset_id ) != MB_SUCCESS )
00883         return MB_FAILURE;
00884       if( mdbImpl->tag_set_data(mGlobalIdTag, &ns_handle, 1, &nodeset_id ) != MB_SUCCESS )
00885         return MB_FAILURE;
00886 
00887       if( !dist_factor_vector.empty() )
00888       {
00889         int size = dist_factor_vector.size();  
00890         const void* data = &dist_factor_vector[0];    
00891         if( mdbImpl->tag_set_by_ptr( mDistFactorTag, &ns_handle, 1, &data, &size ) != MB_SUCCESS )
00892           return MB_FAILURE;
00893       }
00894     }
00895     else if( !dist_factor_vector.empty() )
00896     {
00897         // append dist factors to vector 
00898       const void* ptr = 0;
00899       int size = 0;
00900       if( mdbImpl->tag_get_by_ptr( mDistFactorTag, &ns_handle, 1, &ptr, &size ) != MB_SUCCESS )
00901         return MB_FAILURE;
00902       
00903       const double* data = reinterpret_cast<const double*>(ptr);
00904       dist_factor_vector.reserve( dist_factor_vector.size() + size );
00905       std::copy( data, data+size, std::back_inserter( dist_factor_vector ) );
00906       size = dist_factor_vector.size();  
00907       ptr = &dist_factor_vector[0];    
00908       if( mdbImpl->tag_set_by_ptr( mDistFactorTag, &ns_handle, 1, &ptr, &size ) != MB_SUCCESS )
00909         return MB_FAILURE;
00910     }
00911 
00912       // add the nodes to the meshset
00913     if( mdbImpl->add_entities(ns_handle, &nodes[0], nodes.size()) != MB_SUCCESS )
00914       return MB_FAILURE;
00915 
00916   }
00917 
00918   return MB_SUCCESS;
00919 }
00920 
00921 ErrorCode ReadNCDF::read_sidesets() 
00922 {
00923   // uhhh if you read the same file (previously_read==true) then blow away the 
00924   // sidesets pertaining to this file?  How do you do that?  If you read a 
00925   // new file make sure all the offsets are correct.
00926   
00927   // if not loading any sidesets -- exit
00928   if(0 == numberSideSets_loading) 
00929     return MB_SUCCESS;
00930   
00931     // read in the sideset ids
00932   std::vector<int> id_array(numberSideSets_loading);
00933   int temp_var = -1;
00934   GET_1D_INT_VAR("ss_prop1", temp_var, id_array);
00935   if (-1 == temp_var) {
00936     readMeshIface->report_error("ReadNCDF:: Problem getting ss_prop1 variable.");
00937     return MB_FAILURE;
00938   }
00939 
00940   // create a side set for each one
00941   int number_sides_in_set;
00942   int number_dist_factors_in_set;
00943 
00944 
00945   // Maybe there is already a sidesets meshset here we can append to 
00946   Range child_meshsets;
00947   if( mdbImpl->get_entities_by_type(0, MBENTITYSET, 
00948                                     child_meshsets ) != MB_SUCCESS ) 
00949     return MB_FAILURE;
00950 
00951   child_meshsets = subtract( child_meshsets, initRange);
00952 
00953   Range::iterator iter, end_iter;
00954 
00955   int i;
00956   std::vector<char> temp_string_storage(max_str_length+1);
00957   char *temp_string = &temp_string_storage[0];
00958   int temp_dim;
00959   for(i = 0; i < numberSideSets_loading; i++)
00960   {
00961 
00962     // get sideset parameters
00963     GET_DIMB(temp_dim, temp_string, "num_side_ss%d", i+1, number_sides_in_set);
00964     GET_DIMB(temp_dim, temp_string, "num_df_ss%d", i+1, number_dist_factors_in_set);
00965 
00966     // size new arrays and get element and side lists
00967     std::vector<int> side_list(number_sides_in_set);
00968     std::vector<int> element_list(number_sides_in_set);
00969     INS_ID(temp_string, "side_ss%d", i+1);
00970     temp_var = -1;
00971     GET_1D_INT_VAR(temp_string, temp_var, side_list);
00972     if (-1 == temp_var) {
00973       readMeshIface->report_error("ReadNCDF:: Problem getting sideset side variable.");
00974       return MB_FAILURE;
00975     }
00976 
00977     INS_ID(temp_string, "elem_ss%d", i+1);
00978     temp_var = -1;
00979     GET_1D_INT_VAR(temp_string, temp_var, element_list);
00980     if (-1 == temp_var) {
00981       readMeshIface->report_error("ReadNCDF:: Problem getting sideset elem variable.");
00982       return MB_FAILURE;
00983     }
00984 
00985     std::vector<double> temp_dist_factor_vector;
00986     std::vector<EntityHandle> entities_to_add, reverse_entities;
00987     // create the sideset entities 
00988     if( create_ss_elements( &element_list[0], &side_list[0], number_sides_in_set, number_dist_factors_in_set, 
00989                             entities_to_add, reverse_entities, temp_dist_factor_vector, 
00990                             i+1) != MB_SUCCESS )
00991       return MB_FAILURE;
00992 
00993       //if there are elements to add
00994     if( !entities_to_add.empty() || !reverse_entities.empty())
00995     {
00996       iter = child_meshsets.begin();
00997       end_iter = child_meshsets.end();
00998 
00999       EntityHandle ss_handle = 0;
01000       for(; iter != end_iter; iter++)
01001       {
01002         int sideset_id;
01003         if( mdbImpl->tag_get_data( mNeumannSetTag, &(*iter), 1, &sideset_id ) != MB_SUCCESS )
01004           continue; 
01005 
01006         if( id_array[i] == sideset_id )
01007         {
01008           //found the meshset
01009           ss_handle = *iter;
01010           break;
01011         }
01012       } 
01013 
01014       //if we didn't find a sideset already 
01015       if( ss_handle == 0 )
01016       {
01017         if( mdbImpl->create_meshset( MESHSET_ORDERED | MESHSET_TRACK_OWNER, ss_handle ) != MB_SUCCESS )
01018           return MB_FAILURE;
01019     
01020         if (ss_handle == 0) 
01021         {
01022           return MB_FAILURE;
01023         }
01024 
01025         int sideset_id = id_array[i];
01026         if( mdbImpl->tag_set_data(mNeumannSetTag, &ss_handle, 1, &sideset_id ) != MB_SUCCESS)
01027           return MB_FAILURE;
01028         if( mdbImpl->tag_set_data(mGlobalIdTag, &ss_handle, 1, &sideset_id ) != MB_SUCCESS)
01029           return MB_FAILURE;
01030 
01031         if (!reverse_entities.empty()) {
01032             // also make a reverse set to put in this set
01033           EntityHandle reverse_set;
01034           if (mdbImpl->create_meshset(MESHSET_SET | MESHSET_TRACK_OWNER, reverse_set) != MB_SUCCESS)
01035             return MB_FAILURE;
01036 
01037 
01038             // add the reverse set to the sideset set and the entities to the reverse set
01039           ErrorCode result = mdbImpl->add_entities(ss_handle, &reverse_set, 1);
01040           if (MB_SUCCESS != result) return result;
01041 
01042           result = mdbImpl->add_entities(reverse_set, &reverse_entities[0], reverse_entities.size());
01043           if (MB_SUCCESS != result) return result;
01044 
01045             // set the reverse tag
01046           Tag sense_tag;
01047           int dum_sense = 0;
01048           result = mdbImpl->tag_get_handle("NEUSET_SENSE", 1, MB_TYPE_INTEGER, sense_tag, 
01049                                            MB_TAG_SPARSE|MB_TAG_CREAT, &dum_sense);
01050           if (result != MB_SUCCESS) return result;
01051           dum_sense = -1;
01052           result = mdbImpl->tag_set_data(sense_tag, &reverse_set, 1, &dum_sense);
01053           if (result != MB_SUCCESS) return result;
01054         }
01055       }
01056 
01057       if( mdbImpl->add_entities( ss_handle, &entities_to_add[0], 
01058                                  entities_to_add.size()) != MB_SUCCESS ) 
01059         return MB_FAILURE; 
01060 
01061       //distribution factor stuff
01062       if( number_dist_factors_in_set )
01063       {
01064         //if this sideset does not already has a distribution factor array...set one
01065         const void* ptr = 0;
01066         int size = 0;
01067         if (MB_SUCCESS == mdbImpl->tag_get_by_ptr( mDistFactorTag, &ss_handle, 1, &ptr, &size )) {
01068           const double* data = reinterpret_cast<const double*>(ptr);
01069           std::copy( data, data+size, std::back_inserter( temp_dist_factor_vector ) );
01070         }
01071         
01072         ptr = &temp_dist_factor_vector[0];
01073         size =  temp_dist_factor_vector.size();
01074         if (mdbImpl->tag_set_by_ptr( mDistFactorTag, &ss_handle, 1, &ptr, &size ) != MB_SUCCESS)
01075           return MB_FAILURE;
01076       }
01077     }
01078   }
01079 
01080   return MB_SUCCESS;
01081 
01082 }
01083 
01084 ErrorCode ReadNCDF::create_ss_elements( int *element_ids, 
01085                                             int *side_list, 
01086                                             int num_sides,  
01087                                             int num_dist_factors, 
01088                                             std::vector<EntityHandle> &entities_to_add,
01089                                             std::vector<EntityHandle> &reverse_entities,
01090                                             std::vector<double> &dist_factor_vector, 
01091                                            int ss_seq_id)
01092 {
01093   //determine entity type from element id
01094   int i, k;
01095 
01096   // if there are dist. factors, create a vector to hold the array
01097   // and place this array as a tag onto the sideset meshset
01098   
01099   std::vector<double> temp_dist_factor_vector(num_dist_factors);
01100   std::vector<char> temp_string_storage(max_str_length+1);
01101   char *temp_string = &temp_string_storage[0];
01102   int temp_var;
01103   if( num_dist_factors )
01104   {
01105     INS_ID(temp_string, "dist_fact_ss%d", ss_seq_id);
01106     temp_var = -1;
01107     GET_1D_DBL_VAR(temp_string, temp_var, temp_dist_factor_vector);
01108     if (-1 == temp_var) {
01109       readMeshIface->report_error("ReadNCDF:: Problem getting dist fact variable.");
01110       return MB_FAILURE;
01111     }
01112   }
01113 
01114   EntityType subtype;
01115   int num_side_nodes, num_elem_nodes;
01116   const EntityHandle* nodes;
01117   std::vector<EntityHandle> connectivity;
01118   int side_node_idx[32];
01119 
01120   int df_index = 0;
01121   int sense;
01122   for(i=0; i < num_sides; i++)
01123   {
01124     ExoIIElementType exoii_type;
01125     ReadBlockData block_data;
01126     block_data.elemType = EXOII_MAX_ELEM_TYPE;
01127 
01128     if( find_side_element_type( element_ids[i], exoii_type, block_data, df_index, side_list[i]) != MB_SUCCESS )
01129       continue; //isn't being read in this time
01130 
01131     EntityType type = ExoIIUtil::ExoIIElementMBEntity[exoii_type];
01132 
01133     EntityHandle ent_handle = element_ids[i] - block_data.startExoId + block_data.startMBId;
01134 
01135     const int side_num = side_list[i] - 1;
01136     if(type == MBHEX)
01137     {
01138       //get the nodes of the element
01139       if( mdbImpl->get_connectivity( ent_handle, nodes, num_elem_nodes ) != MB_SUCCESS )
01140         return MB_FAILURE;
01141 
01142       CN::SubEntityNodeIndices( type, num_elem_nodes, 2, side_num, subtype, num_side_nodes, side_node_idx );
01143       if (num_side_nodes <= 0)
01144         return MB_FAILURE;
01145       
01146       connectivity.resize( num_side_nodes );
01147       for (k = 0; k < num_side_nodes; ++k)
01148         connectivity[k] = nodes[ side_node_idx[k] ];
01149         
01150       if (MB_SUCCESS != create_sideset_element( connectivity, subtype, ent_handle, sense ))
01151         return MB_FAILURE;
01152       if (1 == sense) entities_to_add.push_back( ent_handle );
01153       else reverse_entities.push_back(ent_handle);
01154 
01155       //read in distribution factor array
01156       if( num_dist_factors )
01157       {
01158         for(k=0; k<4; k++)
01159           dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01160       }
01161     }
01162 
01163     // if it is a Tet
01164     else if(type == MBTET)
01165     {
01166       //get the nodes of the element
01167       if( mdbImpl->get_connectivity( ent_handle, nodes, num_elem_nodes ) != MB_SUCCESS )
01168         return MB_FAILURE;
01169 
01170       CN::SubEntityNodeIndices( type, num_elem_nodes, 2, side_num, subtype, num_side_nodes, side_node_idx );
01171       if (num_side_nodes <= 0)
01172         return MB_FAILURE;
01173       
01174       connectivity.resize( num_side_nodes );
01175       for (k = 0; k < num_side_nodes; ++k)
01176         connectivity[k] = nodes[ side_node_idx[k] ];
01177         
01178       if (MB_SUCCESS != create_sideset_element( connectivity, subtype, ent_handle, sense ))
01179         return MB_FAILURE;
01180       if (1 == sense) entities_to_add.push_back( ent_handle );
01181       else reverse_entities.push_back(ent_handle);
01182 
01183       //read in distribution factor array
01184       if( num_dist_factors )
01185       {
01186         for(k=0; k<3; k++)
01187           dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01188       }
01189 
01190     }
01191     else if( type == MBQUAD &&
01192              exoii_type >= EXOII_SHELL && exoii_type <= EXOII_SHELL9 )
01193     {
01194       //ent_handle = CREATE_HANDLE(MBQUAD, base_id, error );
01195 
01196       //just use this quad
01197       if( side_list[i] == 1)
01198       {
01199         if (1 == sense) entities_to_add.push_back( ent_handle );
01200         else reverse_entities.push_back(ent_handle);
01201 
01202         if( num_dist_factors )
01203         {
01204           for(k=0; k<4; k++)
01205             dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01206         }
01207 
01208         continue;
01209       }
01210       else if ( side_list[i] == 2)
01211       {
01212         reverse_entities.push_back(ent_handle);
01213         
01214         if( num_dist_factors )
01215         {
01216           for(k=0; k<4; k++)
01217             dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01218         }
01219 
01220         continue;
01221       }
01222       else
01223       {
01224         //get the nodes of the element
01225         if( mdbImpl->get_connectivity( ent_handle, nodes, num_elem_nodes ) != MB_SUCCESS )
01226           return MB_FAILURE;
01227 
01228         CN::SubEntityNodeIndices( type, num_elem_nodes, 1, side_num-2, subtype, num_side_nodes, side_node_idx );
01229         if (num_side_nodes <= 0)
01230           return MB_FAILURE;
01231 
01232         connectivity.resize( num_side_nodes );
01233         for (k = 0; k < num_side_nodes; ++k)
01234           connectivity[k] = nodes[ side_node_idx[k] ];
01235 
01236         if (MB_SUCCESS != create_sideset_element( connectivity, subtype, ent_handle, sense ))
01237           return MB_FAILURE;
01238         if (1 == sense) entities_to_add.push_back( ent_handle );
01239         else reverse_entities.push_back(ent_handle);
01240 
01241         if( num_dist_factors )
01242         {
01243           for(k=0; k<2; k++)
01244             dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01245         }
01246       }
01247     }
01248     // if it is a Quad
01249     else if(type == MBQUAD)
01250     {
01251       //get the nodes of the element
01252       if( mdbImpl->get_connectivity( ent_handle, nodes, num_elem_nodes ) != MB_SUCCESS )
01253         return MB_FAILURE;
01254 
01255       CN::SubEntityNodeIndices( type, num_elem_nodes, 1, side_num, subtype, num_side_nodes, side_node_idx );
01256       if (num_side_nodes <= 0)
01257         return MB_FAILURE;
01258       
01259       connectivity.resize( num_side_nodes );
01260       for (k = 0; k < num_side_nodes; ++k)
01261         connectivity[k] = nodes[ side_node_idx[k] ];
01262         
01263       if (MB_SUCCESS != create_sideset_element( connectivity, subtype, ent_handle, sense ))
01264         return MB_FAILURE;
01265       if (1 == sense) entities_to_add.push_back( ent_handle );
01266       else reverse_entities.push_back(ent_handle);
01267 
01268       //read in distribution factor array
01269       if( num_dist_factors )
01270       {
01271         for(k=0; k<2; k++)
01272           dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01273       }
01274     }
01275     else if(type == MBTRI)
01276     {
01277       int side_offset = 0;
01278       if(number_dimensions() == 3 && side_list[i] <= 2)
01279       {
01280         if (1 == sense) entities_to_add.push_back(ent_handle);
01281         else reverse_entities.push_back(ent_handle);
01282         if( num_dist_factors )
01283         {
01284           for(k=0; k<3; k++)
01285             dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01286         }
01287       }
01288       else
01289       {
01290         if(number_dimensions() == 3)
01291         {
01292           if(side_list[i] > 2)
01293             side_offset = 2;
01294         }
01295 
01296         //get the nodes of the element
01297         if( mdbImpl->get_connectivity( ent_handle, nodes, num_elem_nodes ) != MB_SUCCESS )
01298           return MB_FAILURE;
01299 
01300         CN::SubEntityNodeIndices( type, num_elem_nodes, 1, side_num-side_offset, subtype, num_side_nodes, side_node_idx );
01301         if (num_side_nodes <= 0)
01302           return MB_FAILURE;
01303 
01304         connectivity.resize( num_side_nodes );
01305         for (k = 0; k < num_side_nodes; ++k)
01306           connectivity[k] = nodes[ side_node_idx[k] ];
01307 
01308         if (MB_SUCCESS != create_sideset_element( connectivity, subtype, ent_handle, sense ))
01309           return MB_FAILURE;
01310         if (1 == sense) entities_to_add.push_back( ent_handle );
01311         else reverse_entities.push_back(ent_handle);
01312 
01313         if( num_dist_factors )
01314         {
01315           for(k=0; k<2; k++)
01316             dist_factor_vector.push_back( temp_dist_factor_vector[df_index++] );
01317         }
01318       }
01319     }
01320   }
01321 
01322   return MB_SUCCESS; 
01323 }
01324 
01325 ErrorCode ReadNCDF::create_sideset_element( const std::vector<EntityHandle>& connectivity, 
01326                                             EntityType type, EntityHandle& handle, int &sense)
01327 {
01328   // get adjacent entities
01329   ErrorCode error = MB_SUCCESS;
01330   int to_dim = CN::Dimension(type);
01331   std::vector<EntityHandle> adj_ent;
01332   mdbImpl->get_adjacencies(&(connectivity[0]), 1, to_dim, false, adj_ent);
01333 
01334   // for each entity, see if we can find a match
01335   // if we find a match, return it
01336   bool match_found = false;
01337   std::vector<EntityHandle> match_conn;
01338     // by default, assume positive sense
01339   sense = 1;
01340   for(unsigned int i=0; i<adj_ent.size() && match_found == false; i++)
01341   {
01342     // get the connectivity
01343     error = mdbImpl->get_connectivity(&( adj_ent[i]), 1, match_conn );
01344     if(error != MB_SUCCESS)
01345       continue;
01346 
01347     // make sure they have the same number of vertices (higher order elements ?)
01348     if(match_conn.size() != connectivity.size())
01349       continue;
01350 
01351     // find a matching node
01352     std::vector<EntityHandle>::iterator iter;
01353     iter = std::find(match_conn.begin(), match_conn.end(), connectivity[0]);
01354     if(iter == match_conn.end())
01355       continue;
01356    
01357     // rotate to match connectivity 
01358     std::rotate(match_conn.begin(), iter, match_conn.end());
01359 
01360     bool they_match = true;
01361     unsigned int j;
01362     for(j=1; j<connectivity.size(); j++)
01363     {
01364       if(connectivity[j] != match_conn[j])
01365       {
01366         they_match = false;
01367         break;
01368       }
01369     }
01370 
01371     // if we didn't get a match
01372     if(they_match != true)
01373     {
01374       // try the opposite sense
01375       they_match = true;
01376 
01377       unsigned int k = connectivity.size() - 1;
01378       for(j=1; j<connectivity.size(); )
01379       {
01380         if(connectivity[j] != match_conn[k])
01381         {
01382           they_match = false;
01383           break;
01384         }
01385         ++j;
01386         --k;
01387       }
01388         // if they matched here, sense is reversed
01389       if (they_match) sense = -1;
01390     }
01391     match_found = they_match;
01392     if(match_found == true)
01393       handle = adj_ent[i];
01394   }
01395 
01396   // if we didn't find a match, create an element
01397   if(match_found == false)
01398     error = mdbImpl->create_element(type, &connectivity[0], connectivity.size(), handle);
01399 
01400   return error;
01401 }
01402 
01403 ErrorCode ReadNCDF::find_side_element_type( const int exodus_id, ExoIIElementType &elem_type, 
01404                                                 ReadBlockData &block_data, int &df_index, int side_id)
01405 {
01406   std::vector<ReadBlockData>::iterator iter, end_iter;
01407   iter = blocksLoading.begin();
01408   end_iter = blocksLoading.end();
01409   elem_type = EXOII_MAX_ELEM_TYPE;
01410 
01411   for(; iter != end_iter; ++iter )
01412   {
01413     if( exodus_id >= (*iter).startExoId && 
01414          exodus_id < (*iter).startExoId + (*iter).numElements )
01415     {
01416       elem_type = (*iter).elemType;
01417 
01418       //if we're not reading this block in
01419       if( !(*iter).reading_in ) 
01420       {
01421         //offset df_indes according to type
01422          
01423         if( elem_type >= EXOII_HEX && elem_type <= EXOII_HEX27 )
01424           df_index += 4;
01425         else if( elem_type >= EXOII_TETRA && elem_type <= EXOII_TETRA14 )
01426           df_index += 3;
01427         else if( elem_type >= EXOII_QUAD && elem_type <= EXOII_QUAD9 )
01428           df_index += 2;
01429         else if( elem_type >= EXOII_SHELL && elem_type <= EXOII_SHELL9)
01430         {
01431          if(side_id == 1 || side_id == 2)
01432            df_index += 4;
01433          else
01434            df_index += 2;
01435         }
01436         else if( elem_type >= EXOII_TRI && elem_type <= EXOII_TRI7 )
01437           df_index += 3;
01438 
01439         return MB_FAILURE;
01440       }
01441 
01442       block_data = *iter;
01443 
01444       return MB_SUCCESS;
01445     } 
01446   }
01447   return MB_FAILURE;
01448 }
01449 
01450 ErrorCode ReadNCDF::read_qa_records(EntityHandle file_set)
01451 {
01452   std::vector<std::string> qa_records;
01453   read_qa_information( qa_records );
01454   
01455   std::vector<char> tag_data;
01456   for (std::vector<std::string>::iterator i = qa_records.begin(); i != qa_records.end(); ++i) {
01457     std::copy( i->begin(), i->end(), std::back_inserter(tag_data) );
01458     tag_data.push_back( '\0' );
01459   }
01460 
01461   //if there were qa_records...tag them to the mCurrentMeshHandle
01462   if( !tag_data.empty() )
01463   {
01464     const void* ptr = &tag_data[0];
01465     int size = tag_data.size();
01466     if( mdbImpl->tag_set_by_ptr( mQaRecordTag, &file_set, 1, &ptr, &size  ) != MB_SUCCESS ) {
01467       return MB_FAILURE;
01468     }
01469   }
01470 
01471   return MB_SUCCESS;
01472 }
01473 
01474 ErrorCode ReadNCDF::read_qa_information(std::vector<std::string> &qa_record_list)
01475 {
01476   // inquire on the genesis file to find the number of qa records
01477 
01478   int number_records = 0;
01479 
01480   int temp_dim;
01481   GET_DIM(temp_dim, "num_qa_rec", number_records);
01482   std::vector<char> data(max_str_length+1);
01483   
01484   for(int i = 0; i < number_records; i++)
01485   {
01486     for(int j = 0; j < 4; j++)
01487     {
01488       data[max_str_length] = '\0';
01489       if (read_qa_string(&data[0], i, j) != MB_SUCCESS)
01490       {
01491         return MB_FAILURE;
01492       }
01493       qa_record_list.push_back(&data[0]);
01494     }
01495   }
01496   return MB_SUCCESS;
01497 }
01498 
01499 ErrorCode ReadNCDF::read_qa_string(char *temp_string,
01500                                      int record_number,
01501                                      int record_position)
01502 {
01503   std::vector<int> dims;
01504   int temp_var = -1;
01505   GET_VAR("qa_records", temp_var, dims);
01506   if (-1 == temp_var) {
01507     readMeshIface->report_error("ReadNCDF:: Problem getting qa record variable.");
01508     return MB_FAILURE;
01509   }
01510   size_t count[3], start[3];
01511   start[0] = record_number; start[1] = record_position; start[2] = 0;
01512   count[0] = 1; count[1] = 1; count[2] = max_str_length;
01513   int fail = nc_get_vara_text(ncFile, temp_var, start, count, temp_string);
01514   if (NC_NOERR != fail) {
01515     readMeshIface->report_error("ReadNCDF:: Problem setting current record number variable position.");
01516     return MB_FAILURE;
01517   }
01518     // get the variable id in the exodus file
01519 
01520   return MB_SUCCESS;
01521 }
01522 
01523 // The cub_file_set contains the mesh to be updated. There could exist other
01524 // file sets that should be kept separate, such as the geometry file set from
01525 // ReadCGM.
01526 ErrorCode ReadNCDF::update(const char *exodus_file_name, 
01527                              const FileOptions& opts, 
01528                              const int num_blocks, 
01529                              const int *blocks_to_load,
01530                              const EntityHandle cub_file_set)
01531 {
01532   //Function : updating current database from new exodus_file. 
01533   //Creator:   Jane Hu
01534   //opts is currently designed as following
01535   //tdata = <var_name>[, time][,op][,destination]
01536   //where var_name show the tag name to be updated, this version just takes
01537   //coord.
01538   //time is the optional, and it gives time step of each of the mesh
01539   //info in exodus file. It start from 1.
01540   //op is the operation that is going to be performed on the var_name info.
01541   //currently support 'set'
01542   //destination shows where to store the updated info, currently assume it is
01543   //stored in the same database by replacing the old info if there's no input
01544   //for destination, or the destination data is given in exodus format and just
01545   //need to update the coordinates.
01546   //Assumptions:
01547   //1. Assume the num_el_blk's in both DB and update exodus file are the same. 
01548   //2. Assume num_el_in_blk1...num_el_in_blk(num_el_blk) numbers are matching, may in 
01549   //different order. example: num_el_in_blk11 = num_el_in_blk22 && num_el_in_blk12 = 
01550   //num_el_in_blk21.
01551   //3. In exodus file, get node_num_map
01552   //4. loop through the node_num_map, use it to find the node in the cub file.
01553   //5. Replace coord[0][n] with coordx[m]+vals_nod_var1(time_step, m) for all directions for matching nodes.   
01554   // Test: try to get hexes
01555 
01556   // *******************************************************************
01557   // Move nodes to their deformed locations.
01558   // *******************************************************************  
01559   ErrorCode rval;
01560   std::string s;
01561   rval = opts.get_str_option("tdata", s ); 
01562   if(MB_SUCCESS != rval)
01563   {
01564     readMeshIface->report_error("ReadNCDF:: Problem reading file options.");
01565     return MB_FAILURE;
01566   }
01567   std::vector< std::string > tokens;
01568   tokenize(s, tokens,",");
01569     
01570   //1. check for time step to find the match time
01571   int time_step = 1;
01572   if(tokens.size() > 1 && !tokens[1].empty())
01573   {
01574     const char* time_s = tokens[1].c_str();
01575     char* endptr;
01576     long int pval = strtol( time_s, &endptr, 0 );
01577     std::string end = endptr;
01578     if (!end.empty()) // syntax error
01579       return MB_TYPE_OUT_OF_RANGE;
01580 
01581     // check for overflow (parsing long int, returning int)
01582     time_step = pval;
01583     if (pval != (long int)time_step)
01584       return MB_TYPE_OUT_OF_RANGE;
01585     if(time_step <= 0)
01586       return MB_TYPE_OUT_OF_RANGE;
01587   }
01588 
01589   //2. check for the operations, currently support set.
01590   const char* op;
01591   if (tokens.size() < 3 || (tokens[2] != "set" && tokens[2] != "add")) {
01592     readMeshIface->report_error("ReadNCDF: invalid operation specified for update");
01593     return MB_TYPE_OUT_OF_RANGE;
01594   }
01595   op = tokens[2].c_str();
01596 
01597       // open netcdf/exodus file
01598   ncFile = 0;
01599   int fail = nc_open(exodus_file_name, 0, &ncFile);
01600   if (!ncFile)
01601   {
01602     readMeshIface->report_error("ReadNCDF:: problem opening Netcdf/Exodus II file %s",exodus_file_name);
01603     return MB_FILE_DOES_NOT_EXIST;
01604   }
01605 
01606   rval = read_exodus_header();
01607   if (MB_SUCCESS != rval)
01608     return rval;
01609 
01610   // check to make sure that the requested time step exists
01611   int ncdim = -1;
01612   int max_time_steps;
01613   GET_DIM(ncdim, "time_step", max_time_steps);
01614   if (-1 == ncdim) {
01615     std::cout << "ReadNCDF: could not get number of time steps" << std::endl;
01616     return MB_FAILURE;
01617   }
01618   std::cout << "  Maximum time step=" << max_time_steps << std::endl;
01619   if(max_time_steps < time_step) {
01620     std::cout << "ReadNCDF: time step is greater than max_time_steps" << std::endl;
01621     return MB_FAILURE;
01622   }
01623   
01624   // get the time
01625   std::vector<double> times(max_time_steps);
01626   int nc_var = -1;
01627   GET_1D_DBL_VAR("time_whole", nc_var, times);
01628   if(-1 == nc_var) {
01629     std::cout << "ReadNCDF: unable to get time variable" << std::endl;
01630   } else {
01631     std::cout << "  Step " << time_step << " is at " << times[time_step-1] 
01632               << " seconds" << std::endl;
01633   }
01634 
01635   //read in the node_num_map .
01636   std::vector<int> ptr(numberNodes_loading);
01637 
01638   int varid = -1;
01639   GET_1D_INT_VAR("node_num_map", varid, ptr);
01640   if (-1 == varid) {
01641     readMeshIface->report_error("ReadNCDF:: Problem getting node number map data.");
01642     return MB_FAILURE;
01643   }
01644 
01645   // read in the deformations.
01646   std::vector< std::vector<double> > deformed_arrays(3) ;
01647   std::vector< std::vector<double> >  orig_coords(3) ;
01648   deformed_arrays[0].reserve(numberNodes_loading);
01649   deformed_arrays[1].reserve(numberNodes_loading);
01650   deformed_arrays[2].reserve(numberNodes_loading);
01651   orig_coords[0].reserve(numberNodes_loading);
01652   orig_coords[1].reserve(numberNodes_loading);
01653   orig_coords[2].reserve(numberNodes_loading);
01654   size_t start[2] = {static_cast<size_t>(time_step-1),0}, count[2] = {1, static_cast<size_t>(numberNodes_loading)};
01655   std::vector<int> dims;
01656   int coordx = -1, coordy = -1, coordz = -1;
01657   GET_VAR("vals_nod_var1", coordx, dims);
01658   GET_VAR("vals_nod_var2", coordy, dims);
01659   if(numberDimensions_loading == 3)
01660     GET_VAR("vals_nod_var3", coordz, dims);
01661   if (-1 == coordx || -1 == coordy || 
01662       (numberDimensions_loading == 3 && -1 == coordz)) {
01663     readMeshIface->report_error("ReadNCDF:: Problem getting coords variable.");
01664     return MB_FAILURE;
01665   }
01666 
01667   fail = nc_get_vara_double(ncFile, coordx, start, count, &deformed_arrays[0][0]);
01668   if (NC_NOERR != fail) {
01669     readMeshIface->report_error("ReadNCDF:: Problem getting x deformation array.");
01670     return MB_FAILURE;
01671   }
01672 
01673   fail = nc_get_vara_double(ncFile, coordy, start, count, &deformed_arrays[1][0]);
01674   if (NC_NOERR != fail) {
01675     readMeshIface->report_error("ReadNCDF:: Problem getting y deformation array.");
01676     return MB_FAILURE;
01677   }
01678   if (numberDimensions_loading == 3 )
01679   {
01680     fail = nc_get_vara_double(ncFile, coordz, start, count, &deformed_arrays[2][0]);
01681     if (NC_NOERR != fail) {
01682       readMeshIface->report_error("ReadNCDF:: Problem getting z deformation array.");
01683       return MB_FAILURE;
01684     }
01685   }
01686 
01687   int coord1 = -1, coord2 = -1, coord3 = -1;
01688   GET_1D_DBL_VAR("coordx", coord1, orig_coords[0]);
01689   if (-1 == coord1) {
01690     readMeshIface->report_error("ReadNCDF:: Problem getting x coord array.");
01691     return MB_FAILURE;
01692   }
01693   GET_1D_DBL_VAR("coordy", coord2, orig_coords[1]);
01694   if (-1 == coord2) {
01695     readMeshIface->report_error("ReadNCDF:: Problem getting y coord array.");
01696     return MB_FAILURE;
01697   }
01698   if (numberDimensions_loading == 3 )
01699   {
01700     GET_1D_DBL_VAR("coordz", coord3, orig_coords[2]);
01701     if (-1 == coord3) {
01702       readMeshIface->report_error("ReadNCDF:: Problem getting z coord array.");
01703       return MB_FAILURE;
01704     }
01705   }
01706 
01707   //b. Deal with DB file : get node info. according to node_num_map.
01708   if (tokens[0] != "coord" && tokens[0] != "COORD")
01709     return MB_NOT_IMPLEMENTED;
01710 
01711   if( strcmp (op, "set") && strcmp (op, " set"))
01712     return MB_NOT_IMPLEMENTED;
01713 
01714   // Two methods of matching nodes (id vs. proximity)
01715   const bool match_node_ids = true;
01716 
01717   // Get nodes in cubit file
01718   Range cub_verts;
01719   rval = mdbImpl->get_entities_by_type( cub_file_set, MBVERTEX, cub_verts );
01720   if(MB_SUCCESS != rval) return rval;
01721   std::cout << "  cub_file_set contains " << cub_verts.size() << " nodes." 
01722         << std::endl;
01723 
01724   // Some accounting
01725   std::cout << "  exodus file contains " << numberNodes_loading << " nodes." 
01726             << std::endl;
01727   double max_magnitude = 0;
01728   double average_magnitude = 0;
01729   int found = 0;
01730   int lost = 0;
01731   std::map<int,EntityHandle> cub_verts_id_map;
01732   AdaptiveKDTree kdtree( mdbImpl);
01733   EntityHandle root;
01734 
01735   // Should not use cub verts unless they have been matched. Place in a map
01736   // for fast handle_by_id lookup.
01737   std::map<int,EntityHandle> matched_cub_vert_id_map;
01738 
01739   // Place cub verts in a map for searching by id
01740   if(match_node_ids) {
01741     std::vector<int> cub_ids( cub_verts.size() );
01742     rval = mdbImpl->tag_get_data( mGlobalIdTag, cub_verts, &cub_ids[0] );
01743     if(MB_SUCCESS != rval) return rval;
01744     for(unsigned i=0; i!=cub_verts.size(); ++i) {
01745       cub_verts_id_map.insert ( std::pair<int,EntityHandle>(cub_ids[i],cub_verts[i]) );
01746     }
01747 
01748   // Place cub verts in a kdtree for searching by proximity
01749   } else {
01750     FileOptions tree_opts("MAX_PER_LEAF=1;SPLITS_PER_DIR=1;CANDIDATE_PLANE_SET=0");
01751     rval = kdtree.build_tree( cub_verts, &root, &tree_opts);
01752     if(MB_SUCCESS != rval) return rval;
01753     AdaptiveKDTreeIter tree_iter;                                                     
01754     rval = kdtree.get_tree_iterator( root, tree_iter );
01755     if(MB_SUCCESS != rval) return rval;
01756   }
01757 
01758   // For each exo vert, find the matching cub vert
01759   for(int i=0; i<numberNodes_loading; ++i) {
01760     int exo_id = ptr[i];
01761     CartVect exo_coords( orig_coords[0][i], orig_coords[1][i], orig_coords[2][i] );
01762     EntityHandle cub_vert = 0;
01763     bool found_match = false;
01764 
01765     // by id
01766     if(match_node_ids) {
01767       std::map<int,EntityHandle>::iterator i_iter;
01768       i_iter = cub_verts_id_map.find( exo_id );
01769       if(i_iter != cub_verts_id_map.end()) {
01770         found_match = true;
01771         cub_vert = i_iter->second;
01772       }
01773 
01774     // by proximity
01775     } else {
01776       // The MAX_NODE_DIST is the farthest distance to  search for a node.
01777       // For the 1/12th symmetry 85 pin model, the max node dist could not be less
01778       // than 1e-1 (March 26, 2010).
01779       const double MAX_NODE_DIST = 1e-1;
01780 
01781       std::vector<EntityHandle> leaves;
01782       double min_dist = MAX_NODE_DIST;
01783       rval = kdtree.distance_search(exo_coords.array(), MAX_NODE_DIST, leaves);
01784       if(MB_SUCCESS != rval) return rval;
01785       for(std::vector<EntityHandle>::const_iterator j=leaves.begin(); j!=leaves.end(); ++j) {
01786     std::vector<EntityHandle> leaf_verts;
01787     rval = mdbImpl->get_entities_by_type( *j, MBVERTEX, leaf_verts );
01788     if(MB_SUCCESS != rval) return rval;
01789     for(std::vector<EntityHandle>::const_iterator k=leaf_verts.begin(); k!=leaf_verts.end(); ++k) {
01790       CartVect orig_cub_coords, difference;
01791       rval = mdbImpl->get_coords( &(*k), 1, orig_cub_coords.array() );
01792           if(MB_SUCCESS != rval) return rval;
01793           difference = orig_cub_coords - exo_coords;
01794           double dist = difference.length();
01795           if(dist < min_dist) {
01796             min_dist = dist;
01797             cub_vert = *k;
01798           }
01799         }
01800       }
01801       if(0 != cub_vert) found_match = true;
01802     }
01803 
01804     // If a match is found, update it with the deformed coords from the exo file.
01805     if(found_match) {
01806       CartVect updated_exo_coords;
01807       matched_cub_vert_id_map.insert( std::pair<int,EntityHandle>(exo_id,cub_vert) );
01808       updated_exo_coords[0] = orig_coords[0][i] + deformed_arrays[0][i];
01809       updated_exo_coords[1] = orig_coords[1][i] + deformed_arrays[1][i];
01810       if(numberDimensions_loading == 3 )
01811         updated_exo_coords[2] = orig_coords[2][i] + deformed_arrays[2][i];
01812       rval = mdbImpl->set_coords( &cub_vert, 1, updated_exo_coords.array() );
01813       if(MB_SUCCESS != rval) return rval;
01814       ++found;
01815       double magnitude = sqrt(deformed_arrays[0][i]*deformed_arrays[0][i] +
01816                       deformed_arrays[1][i]*deformed_arrays[1][i] +
01817                   deformed_arrays[2][i]*deformed_arrays[2][i]);
01818       if(magnitude>max_magnitude) max_magnitude = magnitude;
01819       average_magnitude += magnitude;
01820     } else {
01821       ++lost;
01822       std::cout << "cannot match exo node " << exo_id << " " << exo_coords << std::endl;
01823     }
01824   }
01825 
01826   // Exo verts that could not be matched have already been printed. Now print the
01827   // cub verts that could not be matched.
01828   if(matched_cub_vert_id_map.size() < cub_verts.size()) {
01829     Range unmatched_cub_verts = cub_verts;
01830     for(std::map<int,EntityHandle>::const_iterator i=matched_cub_vert_id_map.begin();
01831         i!=matched_cub_vert_id_map.end(); ++i) {
01832       unmatched_cub_verts.erase( i->second ); 
01833     }
01834     for(Range::const_iterator i=unmatched_cub_verts.begin(); i!=unmatched_cub_verts.end(); ++i) {
01835       int cub_id;
01836       rval = mdbImpl->tag_get_data( mGlobalIdTag, &(*i), 1, &cub_id );
01837       if(MB_SUCCESS != rval) return rval;
01838       CartVect cub_coords;
01839       rval = mdbImpl->get_coords( &(*i), 1, cub_coords.array() );      
01840       if(MB_SUCCESS != rval) return rval;
01841       std::cout << "cannot match cub node " << cub_id << " " << cub_coords << std::endl;
01842     }
01843     std::cout << "  " << unmatched_cub_verts.size() 
01844               << " nodes from the cub file could not be matched." << std::endl;
01845   }
01846 
01847   // Summarize statistics
01848   std::cout << "  " << found << " nodes from the exodus file were matched in the cub_file_set ";
01849   if(match_node_ids) {
01850     std::cout << "by id." << std::endl;
01851   } else {
01852     std::cout << "by proximity." << std::endl;
01853   }
01854 
01855   // Fail if all of the nodes could not be matched.
01856   if(0 != lost) {
01857     std::cout << "Error:  " << lost << " nodes from the exodus file could not be matched." 
01858               << std::endl;
01859     //return MB_FAILURE;
01860   }
01861   std::cout << "  maximum node displacement magnitude: " << max_magnitude 
01862             << " cm" << std::endl;
01863   std::cout << "  average node displacement magnitude: " << average_magnitude/found 
01864             << " cm" << std::endl;
01865 
01866   // *******************************************************************
01867   // Remove dead elements from the MOAB instance.
01868   // *******************************************************************
01869 
01870   // How many element variables are in the file?
01871   int n_elem_var;
01872   GET_DIM(ncdim, "num_elem_var", n_elem_var);
01873 
01874   // Get element variable names
01875   varid = -1;
01876   int cstatus = nc_inq_varid(ncFile, "name_elem_var", &varid);
01877   std::vector<char> names_memory(n_elem_var * max_str_length);
01878   std::vector<char*> names(n_elem_var);
01879   for (int i = 0; i < n_elem_var; ++i)
01880     names[i] = &names_memory[i*max_str_length];
01881   if (cstatus!=NC_NOERR || varid == -1) {
01882     std::cout << "ReadNCDF: name_elem_var does not exist" << std::endl;
01883     return MB_FAILURE;
01884   }
01885   int status = nc_get_var_text(ncFile, varid, &names_memory[0]);
01886   if (NC_NOERR != status) {
01887     readMeshIface->report_error("ReadNCDF: Problem getting element variable names.");
01888     return MB_FAILURE;
01889   }
01890 
01891   // Is one of the element variable names "death_status"? If so, get its index
01892   // in the element variable array.
01893   int death_index;
01894   bool found_death_index = false;
01895   for(int i=0; i<n_elem_var; ++i) {
01896     std::string temp(names[i]);
01897     std::string::size_type pos0 = temp.find("death_status");
01898     std::string::size_type pos1 = temp.find("Death_Status");
01899     std::string::size_type pos2 = temp.find("DEATH_STATUS");
01900     if(std::string::npos!=pos0 || std::string::npos!=pos1 || std::string::npos!=pos2) {
01901       found_death_index = true;
01902       death_index = i+1; // NetCDF variables start with 1
01903       break;
01904     }
01905   }
01906   if(!found_death_index) {
01907     std::cout << "ReadNCDF: Problem getting index of death_status variable." << std::endl;
01908     return MB_FAILURE;
01909   }
01910     
01911   // The exodus header has already been read. This contains the number of element
01912   // blocks.
01913 
01914   // Dead elements are listed by block. Read the block headers to determine how
01915   // many elements are in each block.
01916   rval = read_block_headers(blocks_to_load, num_blocks);
01917   if (MB_FAILURE == rval) {
01918     std::cout << "ReadNCDF: Problem reading block headers." << std::endl;
01919     return rval;
01920   }
01921 
01922   // Dead elements from the Exodus file can be located in the cub_file_set by id
01923   // or by connectivity. Currently, finding elements by id requires careful book
01924   // keeping when constructing the model in Cubit. To avoid this, one can match
01925   // elements by connectivity instead.
01926   const bool match_elems_by_connectivity = true;
01927 
01928   // Get the element id map. The ids in the map are from the elementsin the blocks.
01929   // elem_num_map( blk1 elem ids, blk2 elem ids, blk3 elem ids, ... )
01930   std::vector<int> elem_ids(numberNodes_loading);
01931   if(!match_elems_by_connectivity) {
01932     GET_1D_INT_VAR("elem_num_map", varid, elem_ids);
01933     if (-1 == varid) {
01934       std::cout << "ReadNCDF: Problem getting element number map data." << std::endl;
01935       return MB_FAILURE;
01936     }
01937   }
01938 
01939   // For each block
01940   int first_elem_id_in_block = 0;
01941   int block_count = 1; // NetCDF variables start with 1
01942   int total_elems = 0;
01943   int total_dead_elems = 0;
01944   for(std::vector<ReadBlockData>::iterator i=blocksLoading.begin();
01945       i!=blocksLoading.end(); ++i) {
01946 
01947     // get the ncdf connect variable
01948     std::string temp_string("connect");
01949     std::stringstream temp_ss;
01950     temp_ss << block_count;
01951     temp_string += temp_ss.str();
01952     temp_string += "\0";
01953     std::vector<int> ldims;
01954     GET_VAR(temp_string.c_str(), nc_var, ldims);
01955     if (!nc_var) {
01956       readMeshIface->report_error("ReadNCDF:: Problem getting connect variable.");
01957       return MB_FAILURE;
01958     }
01959     // the element type is an attribute of the connectivity variable
01960     nc_type att_type;
01961     size_t att_len;
01962     fail = nc_inq_att(ncFile, nc_var, "elem_type", &att_type, &att_len);
01963     if (NC_NOERR != fail) {
01964       readMeshIface->report_error("ReadNCDF:: Problem getting elem type attribute.");
01965       return MB_FAILURE;
01966     }
01967     std::vector<char> dum_str(att_len+1);
01968     fail = nc_get_att_text(ncFile, nc_var, "elem_type", &dum_str[0]);
01969     if (NC_NOERR != fail) {
01970       readMeshIface->report_error("ReadNCDF:: Problem getting elem type.");
01971       return MB_FAILURE;
01972     }
01973     ExoIIElementType elem_type = ExoIIUtil::static_element_name_to_type(&dum_str[0]);
01974     (*i).elemType = elem_type;
01975     const EntityType mb_type = ExoIIUtil::ExoIIElementMBEntity[(*i).elemType];
01976 
01977     // Get the number of nodes per element
01978     unsigned int nodes_per_element = ExoIIUtil::VerticesPerElement[(*i).elemType];
01979     
01980     // read the connectivity into that memory. 
01981     //int exo_conn[i->numElements][nodes_per_element];
01982     int *exo_conn = new int [i->numElements*nodes_per_element];
01983     //NcBool status = temp_var->get( &exo_conn[0][0], i->numElements, nodes_per_element);
01984     size_t lstart[2] = {0, 0}, lcount[2];
01985     lcount[0] = i->numElements;
01986     lcount[1] = nodes_per_element;
01987     fail = nc_get_vara_int(ncFile, nc_var, lstart, lcount, exo_conn);
01988     if (NC_NOERR != fail) {
01989       readMeshIface->report_error("ReadNCDF:: Problem getting connectivity.");
01990       delete [] exo_conn;
01991       return MB_FAILURE;
01992     }
01993 
01994     // get the death_status at the correct time step.
01995     std::vector<double> death_status(i->numElements); // it seems wrong, but it uses doubles
01996     std::string array_name("vals_elem_var");
01997     temp_ss.str(""); // stringstream won't clear by temp.clear() 
01998     temp_ss << death_index;
01999     array_name += temp_ss.str();
02000     array_name += "eb";
02001     temp_ss.str(""); // stringstream won't clear by temp.clear()
02002     temp_ss << block_count;
02003     array_name += temp_ss.str();
02004     array_name += "\0";
02005     GET_VAR(array_name.c_str(), nc_var, ldims);
02006     if (!nc_var) {
02007       readMeshIface->report_error("ReadNCDF:: Problem getting death status variable.");
02008       return MB_FAILURE;
02009     }
02010     lstart[0] = time_step-1; lstart[1] = 0;
02011     lcount[0] = 1;
02012     lcount[1] = i->numElements;
02013     status = nc_get_vara_double(ncFile, nc_var, lstart, lcount, &death_status[0]);
02014     if (NC_NOERR != status) {
02015       std::cout << "ReadNCDF: Problem setting time step for death_status." << std::endl;
02016       delete[] exo_conn;
02017       return MB_FAILURE;
02018     }
02019 
02020     // Look for dead elements. If there is too many dead elements and this starts
02021     // to take too long, I should put the elems in a kd-tree for more efficient 
02022     // searching. Alternatively I could get the exo connectivity and match nodes.
02023     int dead_elem_counter = 0, missing_elem_counter = 0;
02024     for (int j=0; j<i->numElements; ++j) {
02025       if (1 != death_status[j]) {
02026 
02027         Range cub_elem, cub_nodes;
02028         if(match_elems_by_connectivity) {
02029           // get exodus nodes for the element
02030       std::vector<int> elem_conn(nodes_per_element);
02031           for(unsigned int k=0; k<nodes_per_element; ++k) {
02032             //elem_conn[k] = exo_conn[j][k];
02033             elem_conn[k] = exo_conn[j*nodes_per_element + k];
02034       }
02035           // get the ids of the nodes (assume we are matching by id)
02036           // Remember that the exodus array locations start with 1 (not 0).
02037       std::vector<int> elem_conn_node_ids(nodes_per_element);
02038           for(unsigned int k=0; k<nodes_per_element; ++k) {
02039             elem_conn_node_ids[k] = ptr[ elem_conn[k]-1 ];
02040           }
02041           // get the cub_file_set nodes by id
02042           // The map is a log search and takes almost no time. 
02043           // MOAB's linear tag search takes 5-10 minutes.
02044           for(unsigned int k=0; k<nodes_per_element; ++k) {
02045         std::map<int,EntityHandle>::iterator k_iter;
02046             k_iter = matched_cub_vert_id_map.find( elem_conn_node_ids[k] );
02047             
02048             if(k_iter == matched_cub_vert_id_map.end()) {
02049           std::cout << "ReadNCDF: Found no cub node with id=" << elem_conn_node_ids[k] 
02050                         << ", but expected to find only 1." << std::endl;
02051               break;
02052             }
02053             cub_nodes.insert( k_iter->second ); 
02054           }
02055 
02056           if(nodes_per_element != cub_nodes.size()) {
02057         std::cout << "ReadNCDF: nodes_per_elemenet != cub_nodes.size()" << std::endl;
02058             delete[] exo_conn;
02059             return MB_INVALID_SIZE;
02060           }
02061 
02062           // get the cub_file_set element with the same nodes
02063           int to_dim = CN::Dimension(mb_type);
02064           rval = mdbImpl->get_adjacencies( cub_nodes, to_dim, false, cub_elem);
02065           if(MB_SUCCESS != rval) {
02066         std::cout << "ReadNCDF: could not get dead cub element" << std::endl;
02067             delete[] exo_conn;
02068             return rval;
02069           }
02070 
02071           // Pronto/Presto renumbers elements, so matching cub and exo elements by
02072           // id is not possible at this time.
02073         } else {
02074 
02075           // get dead element's id
02076           int elem_id = elem_ids[first_elem_id_in_block+j];
02077           void *id[] = {&elem_id};
02078           // get the element by id
02079           rval = mdbImpl->get_entities_by_type_and_tag( cub_file_set, mb_type, 
02080                                 &mGlobalIdTag, id, 1, cub_elem, 
02081                                                         Interface::INTERSECT );
02082           if(MB_SUCCESS != rval) {
02083             delete[] exo_conn;
02084             return rval;
02085           }
02086         }
02087 
02088         if(1 == cub_elem.size()) {
02089           // Delete the dead element from the cub file. It will be removed from sets
02090           // ONLY if they are tracking meshsets.
02091           rval = mdbImpl->remove_entities( cub_file_set, cub_elem );
02092           if(MB_SUCCESS != rval) {
02093             delete[] exo_conn;
02094             return rval;
02095           }
02096           rval = mdbImpl->delete_entities( cub_elem );
02097           if(MB_SUCCESS != rval) {
02098             delete[] exo_conn;
02099             return rval;
02100           }
02101         } else {
02102           std::cout << "ReadNCDF: Should have found 1 element with  type=" 
02103                     << mb_type << " in cub_file_set, but instead found " 
02104                     << cub_elem.size() << std::endl;
02105           rval = mdbImpl->list_entities( cub_nodes );
02106           ++missing_elem_counter;      
02107           delete[] exo_conn;
02108           return MB_FAILURE;
02109         }
02110         ++dead_elem_counter;
02111       }
02112     }
02113     // Print some statistics
02114     temp_ss.str("");
02115     temp_ss << i->blockId;
02116     total_dead_elems += dead_elem_counter;
02117     total_elems      += i->numElements;
02118     std::cout << "  Block " << temp_ss.str() << " has " << dead_elem_counter << "/"
02119               << i->numElements << " dead elements." << std::endl;
02120     if(0 != missing_elem_counter) {
02121       std::cout << "    " << missing_elem_counter 
02122                 << " dead elements in this block were not found in the cub_file_set. "
02123                 << std::endl;
02124     }
02125  
02126     // advance the pointers into element ids and block_count. memory cleanup.
02127     first_elem_id_in_block += i->numElements;
02128     ++block_count;
02129     delete[] exo_conn;
02130 
02131   }
02132 
02133   std::cout << " Total: " << total_dead_elems << "/" << total_elems 
02134             << " dead elements." << std::endl;
02135 
02136   return MB_SUCCESS;
02137 }
02138  
02139 void ReadNCDF::tokenize( const std::string& str,
02140                          std::vector<std::string>& tokens,
02141                          const char* delimiters )
02142 {
02143   std::string::size_type last = str.find_first_not_of( delimiters, 0 );
02144   std::string::size_type pos  = str.find_first_of( delimiters, last );
02145   while (std::string::npos != pos && std::string::npos != last) {
02146     tokens.push_back( str.substr( last, pos - last ) );
02147     last = str.find_first_not_of( delimiters, pos );
02148     pos  = str.find_first_of( delimiters, last );
02149     if(std::string::npos == pos)
02150       pos = str.size();
02151   }
02152 }
02153 
02154 } // namespace moab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines