moab
|
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