MOAB: Mesh Oriented datABase
(version 5.4.1)
|
00001 /** 00002 * MOAB, a Mesh-Oriented datABase, is a software component for creating, 00003 * storing and accessing finite element mesh data. 00004 * 00005 * Copyright 2004 Sandia Corporation. Under the terms of Contract 00006 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government 00007 * retains certain rights in this software. 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 */ 00015 00016 #ifdef WIN32 00017 #ifdef _DEBUG 00018 // turn off warnings that say they debugging identifier has been truncated 00019 // this warning comes up when using some STL containers 00020 #pragma warning( disable : 4786 ) 00021 #endif 00022 #endif 00023 00024 #include "WriteNCDF.hpp" 00025 00026 #include "netcdf.h" 00027 #include <utility> 00028 #include <algorithm> 00029 #include <ctime> 00030 #include <string> 00031 #include <vector> 00032 #include <cstdio> 00033 #include <cstring> 00034 #include <cassert> 00035 00036 #include "moab/Interface.hpp" 00037 #include "moab/Range.hpp" 00038 #include "moab/CN.hpp" 00039 #include "moab/FileOptions.hpp" 00040 #include "MBTagConventions.hpp" 00041 #include "Internals.hpp" 00042 #include "ExoIIUtil.hpp" 00043 #include "moab/WriteUtilIface.hpp" 00044 #include "exodus_order.h" 00045 00046 #ifndef MOAB_HAVE_NETCDF 00047 #error Attempt to compile WriteNCDF with NetCDF support disabled 00048 #endif 00049 00050 namespace moab 00051 { 00052 00053 const int TIME_STR_LEN = 11; 00054 00055 #define INS_ID( stringvar, prefix, id ) sprintf( stringvar, prefix, id ) 00056 00057 #define GET_DIM( ncdim, name, val ) \ 00058 { \ 00059 int gdfail = nc_inq_dimid( ncFile, name, &( ncdim ) ); \ 00060 if( NC_NOERR == gdfail ) \ 00061 { \ 00062 size_t tmp_val; \ 00063 gdfail = nc_inq_dimlen( ncFile, ncdim, &tmp_val ); \ 00064 if( NC_NOERR != gdfail ) \ 00065 { \ 00066 MB_SET_ERR( MB_FAILURE, "WriteNCDF:: couldn't get dimension length" ); \ 00067 } \ 00068 else \ 00069 ( val ) = tmp_val; \ 00070 } \ 00071 else \ 00072 ( val ) = 0; \ 00073 } 00074 00075 #define GET_DIMB( ncdim, name, varname, id, val ) \ 00076 INS_ID( name, varname, id ); \ 00077 GET_DIM( ncdim, name, val ); 00078 00079 #define GET_VAR( name, id, dims ) \ 00080 { \ 00081 ( id ) = -1; \ 00082 int gvfail = nc_inq_varid( ncFile, name, &( id ) ); \ 00083 if( NC_NOERR == gvfail ) \ 00084 { \ 00085 int ndims; \ 00086 gvfail = nc_inq_varndims( ncFile, id, &ndims ); \ 00087 if( NC_NOERR == gvfail ) \ 00088 { \ 00089 ( dims ).resize( ndims ); \ 00090 gvfail = nc_inq_vardimid( ncFile, id, &( dims )[0] ); \ 00091 } \ 00092 } \ 00093 } 00094 00095 WriterIface* WriteNCDF::factory( Interface* iface ) 00096 { 00097 return new WriteNCDF( iface ); 00098 } 00099 00100 WriteNCDF::WriteNCDF( Interface* impl ) 00101 : mdbImpl( impl ), ncFile( 0 ), mCurrentMeshHandle( 0 ), mGeomDimensionTag( 0 ), repeat_face_blocks( 0 ) 00102 { 00103 assert( impl != NULL ); 00104 00105 impl->query_interface( mWriteIface ); 00106 00107 // Initialize in case tag_get_handle fails below 00108 //! Get and cache predefined tag handles 00109 int negone = -1; 00110 impl->tag_get_handle( MATERIAL_SET_TAG_NAME, 1, MB_TYPE_INTEGER, mMaterialSetTag, MB_TAG_SPARSE | MB_TAG_CREAT, 00111 &negone ); 00112 00113 impl->tag_get_handle( DIRICHLET_SET_TAG_NAME, 1, MB_TYPE_INTEGER, mDirichletSetTag, MB_TAG_SPARSE | MB_TAG_CREAT, 00114 &negone ); 00115 00116 impl->tag_get_handle( NEUMANN_SET_TAG_NAME, 1, MB_TYPE_INTEGER, mNeumannSetTag, MB_TAG_SPARSE | MB_TAG_CREAT, 00117 &negone ); 00118 00119 mGlobalIdTag = impl->globalId_tag(); 00120 00121 int dum_val_array[] = { -1, -1, -1, -1 }; 00122 impl->tag_get_handle( HAS_MID_NODES_TAG_NAME, 4, MB_TYPE_INTEGER, mHasMidNodesTag, MB_TAG_SPARSE | MB_TAG_CREAT, 00123 dum_val_array ); 00124 00125 impl->tag_get_handle( "distFactor", 0, MB_TYPE_DOUBLE, mDistFactorTag, 00126 MB_TAG_SPARSE | MB_TAG_VARLEN | MB_TAG_CREAT ); 00127 00128 impl->tag_get_handle( "qaRecord", 0, MB_TYPE_OPAQUE, mQaRecordTag, MB_TAG_SPARSE | MB_TAG_VARLEN | MB_TAG_CREAT ); 00129 00130 impl->tag_get_handle( "WriteNCDF element mark", 1, MB_TYPE_BIT, mEntityMark, MB_TAG_CREAT ); 00131 } 00132 00133 WriteNCDF::~WriteNCDF() 00134 { 00135 mdbImpl->release_interface( mWriteIface ); 00136 00137 mdbImpl->tag_delete( mEntityMark ); 00138 00139 if( 0 != ncFile ) ncFile = 0; 00140 } 00141 00142 void WriteNCDF::reset_block( std::vector< MaterialSetData >& block_info ) 00143 { 00144 std::vector< MaterialSetData >::iterator iter; 00145 00146 for( iter = block_info.begin(); iter != block_info.end(); ++iter ) 00147 { 00148 iter->elements.clear(); 00149 } 00150 } 00151 00152 void WriteNCDF::time_and_date( char* time_string, char* date_string ) 00153 { 00154 struct tm* local_time; 00155 time_t calendar_time; 00156 00157 calendar_time = time( NULL ); 00158 local_time = localtime( &calendar_time ); 00159 00160 assert( NULL != time_string && NULL != date_string ); 00161 00162 strftime( time_string, TIME_STR_LEN, "%H:%M:%S", local_time ); 00163 strftime( date_string, TIME_STR_LEN, "%m/%d/%Y", local_time ); 00164 00165 // Terminate with NULL character 00166 time_string[10] = (char)NULL; 00167 date_string[10] = (char)NULL; 00168 } 00169 00170 ErrorCode WriteNCDF::write_file( const char* exodus_file_name, 00171 const bool overwrite, 00172 const FileOptions& opts, 00173 const EntityHandle* ent_handles, 00174 const int num_sets, 00175 const std::vector< std::string >& qa_records, 00176 const Tag*, 00177 int, 00178 int user_dimension ) 00179 { 00180 assert( 0 != mMaterialSetTag && 0 != mNeumannSetTag && 0 != mDirichletSetTag ); 00181 00182 if( user_dimension == 0 ) mdbImpl->get_dimension( user_dimension ); 00183 00184 if( opts.get_null_option( "REPEAT_FACE_BLOCKS" ) == MB_SUCCESS ) repeat_face_blocks = 1; 00185 00186 std::vector< EntityHandle > blocks, nodesets, sidesets, entities; 00187 00188 // Separate into blocks, nodesets, sidesets 00189 00190 if( num_sets == 0 ) 00191 { 00192 // Default to all defined block, nodeset and sideset-type sets 00193 Range this_range; 00194 mdbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mMaterialSetTag, NULL, 1, this_range ); 00195 std::copy( this_range.begin(), this_range.end(), std::back_inserter( blocks ) ); 00196 this_range.clear(); 00197 mdbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mDirichletSetTag, NULL, 1, this_range ); 00198 std::copy( this_range.begin(), this_range.end(), std::back_inserter( nodesets ) ); 00199 this_range.clear(); 00200 mdbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mNeumannSetTag, NULL, 1, this_range ); 00201 std::copy( this_range.begin(), this_range.end(), std::back_inserter( sidesets ) ); 00202 00203 // If there is nothing to write, write everything as one block. 00204 if( blocks.empty() && nodesets.empty() && sidesets.empty() ) 00205 { 00206 this_range.clear(); 00207 for( int d = user_dimension; d > 0 && this_range.empty(); --d ) 00208 mdbImpl->get_entities_by_dimension( 0, d, this_range, false ); 00209 if( this_range.empty() ) return MB_FILE_WRITE_ERROR; 00210 00211 EntityHandle block_handle; 00212 int block_id = 1; 00213 mdbImpl->create_meshset( MESHSET_SET, block_handle ); 00214 mdbImpl->tag_set_data( mMaterialSetTag, &block_handle, 1, &block_id ); 00215 mdbImpl->add_entities( block_handle, this_range ); 00216 blocks.push_back( block_handle ); 00217 } 00218 } 00219 else 00220 { 00221 int dummy; 00222 for( const EntityHandle* iter = ent_handles; iter < ent_handles + num_sets; ++iter ) 00223 { 00224 if( MB_SUCCESS == mdbImpl->tag_get_data( mMaterialSetTag, &( *iter ), 1, &dummy ) && -1 != dummy ) 00225 blocks.push_back( *iter ); 00226 else if( MB_SUCCESS == mdbImpl->tag_get_data( mDirichletSetTag, &( *iter ), 1, &dummy ) && -1 != dummy ) 00227 nodesets.push_back( *iter ); 00228 else if( MB_SUCCESS == mdbImpl->tag_get_data( mNeumannSetTag, &( *iter ), 1, &dummy ) && -1 != dummy ) 00229 sidesets.push_back( *iter ); 00230 } 00231 } 00232 00233 // If there is nothing to write just return. 00234 if( blocks.empty() && nodesets.empty() && sidesets.empty() ) return MB_FILE_WRITE_ERROR; 00235 00236 // Try to get mesh information 00237 ExodusMeshInfo mesh_info; 00238 00239 std::vector< MaterialSetData > block_info; 00240 std::vector< NeumannSetData > sideset_info; 00241 std::vector< DirichletSetData > nodeset_info; 00242 00243 mesh_info.num_dim = user_dimension; 00244 00245 if( qa_records.empty() ) 00246 { 00247 // qa records are empty - initialize some MB-standard ones 00248 mesh_info.qaRecords.push_back( "MB" ); 00249 mesh_info.qaRecords.push_back( "0.99" ); 00250 char string1[80], string2[80]; 00251 time_and_date( string2, string1 ); 00252 mesh_info.qaRecords.push_back( string2 ); 00253 mesh_info.qaRecords.push_back( string1 ); 00254 } 00255 else 00256 { 00257 // Constrained to multiples of 4 qa records 00258 assert( qa_records.size() % 4 == 0 ); 00259 00260 std::copy( qa_records.begin(), qa_records.end(), std::back_inserter( mesh_info.qaRecords ) ); 00261 } 00262 00263 block_info.clear(); 00264 if( gather_mesh_information( mesh_info, block_info, sideset_info, nodeset_info, blocks, sidesets, nodesets ) != 00265 MB_SUCCESS ) 00266 { 00267 reset_block( block_info ); 00268 return MB_FAILURE; 00269 } 00270 00271 // Try to open the file after gather mesh info succeeds 00272 int fail = nc_create( exodus_file_name, overwrite ? NC_CLOBBER : NC_NOCLOBBER, &ncFile ); 00273 if( NC_NOERR != fail ) 00274 { 00275 reset_block( block_info ); 00276 return MB_FAILURE; 00277 } 00278 00279 if( write_header( mesh_info, block_info, sideset_info, nodeset_info, exodus_file_name ) != MB_SUCCESS ) 00280 { 00281 reset_block( block_info ); 00282 return MB_FAILURE; 00283 } 00284 00285 { 00286 // write dummy time_whole 00287 double timev = 0.0; // dummy, to make paraview happy 00288 size_t start = 0, count = 1; 00289 int nc_var; 00290 std::vector< int > dims; 00291 GET_VAR( "time_whole", nc_var, dims ); 00292 fail = nc_put_vara_double( ncFile, nc_var, &start, &count, &timev ); 00293 if( NC_NOERR != fail ) 00294 { 00295 MB_SET_ERR( MB_FAILURE, "Failed writing dist factor array" ); 00296 } 00297 } 00298 00299 if( write_nodes( mesh_info.num_nodes, mesh_info.nodes, mesh_info.num_dim ) != MB_SUCCESS ) 00300 { 00301 reset_block( block_info ); 00302 return MB_FAILURE; 00303 } 00304 00305 if( !mesh_info.polyhedronFaces.empty() ) 00306 { 00307 if( write_poly_faces( mesh_info ) != MB_SUCCESS ) 00308 { 00309 reset_block( block_info ); 00310 return MB_FAILURE; 00311 } 00312 } 00313 00314 if( write_elementblocks( mesh_info, block_info ) ) 00315 { 00316 reset_block( block_info ); 00317 return MB_FAILURE; 00318 } 00319 00320 // Write the three maps 00321 if( write_global_node_order_map( mesh_info.num_nodes, mesh_info.nodes ) != MB_SUCCESS ) 00322 { 00323 reset_block( block_info ); 00324 return MB_FAILURE; 00325 } 00326 00327 if( write_global_element_order_map( mesh_info.num_elements ) != MB_SUCCESS ) 00328 { 00329 reset_block( block_info ); 00330 return MB_FAILURE; 00331 } 00332 00333 if( write_element_order_map( mesh_info.num_elements ) != MB_SUCCESS ) 00334 { 00335 reset_block( block_info ); 00336 return MB_FAILURE; 00337 } 00338 00339 /* 00340 if (write_elementmap(mesh_info) != MB_SUCCESS) 00341 return MB_FAILURE; 00342 */ 00343 00344 if( write_BCs( sideset_info, nodeset_info ) != MB_SUCCESS ) 00345 { 00346 reset_block( block_info ); 00347 return MB_FAILURE; 00348 } 00349 00350 if( write_qa_records( mesh_info.qaRecords ) != MB_SUCCESS ) return MB_FAILURE; 00351 00352 // Copy the qa records into the argument 00353 // mesh_info.qaRecords.swap(qa_records); 00354 // Close the file 00355 fail = nc_close( ncFile ); 00356 if( NC_NOERR != fail ) 00357 { 00358 MB_SET_ERR( MB_FAILURE, "Trouble closing file" ); 00359 } 00360 00361 return MB_SUCCESS; 00362 } 00363 00364 ErrorCode WriteNCDF::gather_mesh_information( ExodusMeshInfo& mesh_info, 00365 std::vector< MaterialSetData >& block_info, 00366 std::vector< NeumannSetData >& sideset_info, 00367 std::vector< DirichletSetData >& nodeset_info, 00368 std::vector< EntityHandle >& blocks, 00369 std::vector< EntityHandle >& sidesets, 00370 std::vector< EntityHandle >& nodesets ) 00371 { 00372 ErrorCode rval; 00373 std::vector< EntityHandle >::iterator vector_iter, end_vector_iter; 00374 00375 mesh_info.num_nodes = 0; 00376 mesh_info.num_elements = 0; 00377 mesh_info.num_elementblocks = 0; 00378 mesh_info.num_polyhedra_blocks = 0; 00379 00380 int id = 0; 00381 00382 vector_iter = blocks.begin(); 00383 end_vector_iter = blocks.end(); 00384 00385 std::vector< EntityHandle > parent_meshsets; 00386 00387 // Clean out the bits for the element mark 00388 rval = mdbImpl->tag_delete( mEntityMark ); 00389 if( MB_SUCCESS != rval ) return rval; 00390 rval = mdbImpl->tag_get_handle( "WriteNCDF element mark", 1, MB_TYPE_BIT, mEntityMark, MB_TAG_CREAT ); 00391 if( MB_SUCCESS != rval ) return rval; 00392 00393 int highest_dimension_of_element_blocks = 0; 00394 00395 for( vector_iter = blocks.begin(); vector_iter != blocks.end(); ++vector_iter ) 00396 { 00397 MaterialSetData block_data; 00398 00399 // For the purpose of qa records, get the parents of these blocks 00400 if( mdbImpl->get_parent_meshsets( *vector_iter, parent_meshsets ) != MB_SUCCESS ) return MB_FAILURE; 00401 00402 // Get all Entity Handles in the mesh set 00403 Range dummy_range; 00404 rval = mdbImpl->get_entities_by_handle( *vector_iter, dummy_range, true ); 00405 if( MB_SUCCESS != rval ) return rval; 00406 00407 // Skip empty blocks 00408 if( dummy_range.empty() ) continue; 00409 00410 // Get the block's id 00411 if( mdbImpl->tag_get_data( mMaterialSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS ) 00412 { 00413 MB_SET_ERR( MB_FAILURE, "Couldn't get block id from a tag for an element block" ); 00414 } 00415 00416 block_data.id = id; 00417 block_data.number_attributes = 0; 00418 00419 // Wait a minute, we are doing some filtering here that doesn't make sense at this level CJS 00420 00421 // Find the dimension of the last entity in this range 00422 int this_dim = CN::Dimension( TYPE_FROM_HANDLE( dummy_range.back() ) ); 00423 if( this_dim > 3 ) 00424 { 00425 MB_SET_ERR( MB_TYPE_OUT_OF_RANGE, "Block " << id << " contains entity sets" ); 00426 } 00427 block_data.elements = dummy_range.subset_by_dimension( this_dim ); 00428 00429 // End of -- wait a minute, we are doing some filtering here that doesn't make sense at this 00430 // level CJS 00431 00432 // Get the entity type for this block, verifying that it's the same for all elements 00433 EntityType entity_type = TYPE_FROM_HANDLE( block_data.elements.front() ); 00434 if( !block_data.elements.all_of_type( entity_type ) ) 00435 { 00436 MB_SET_ERR( MB_FAILURE, "Entities in block " << id << " not of common type" ); 00437 } 00438 00439 int dimension = -1; 00440 if( entity_type == MBQUAD || entity_type == MBTRI ) 00441 dimension = 2; // Output shells by default 00442 else if( entity_type == MBEDGE ) 00443 dimension = 1; 00444 else 00445 dimension = CN::Dimension( entity_type ); 00446 00447 if( dimension > highest_dimension_of_element_blocks ) highest_dimension_of_element_blocks = dimension; 00448 00449 std::vector< EntityHandle > tmp_conn; 00450 rval = mdbImpl->get_connectivity( &( block_data.elements.front() ), 1, tmp_conn ); 00451 if( MB_SUCCESS != rval ) return rval; 00452 block_data.element_type = ExoIIUtil::get_element_type_from_num_verts( tmp_conn.size(), entity_type, dimension ); 00453 00454 if( block_data.element_type == EXOII_MAX_ELEM_TYPE ) 00455 { 00456 MB_SET_ERR( MB_FAILURE, "Element type in block " << id << " didn't get set correctly" ); 00457 } 00458 00459 if( block_data.element_type == EXOII_POLYGON ) 00460 { 00461 // get all poly connectivity 00462 int numconn = 0; 00463 for( Range::iterator eit = block_data.elements.begin(); eit != block_data.elements.end(); eit++ ) 00464 { 00465 EntityHandle polg = *eit; 00466 int nnodes = 0; 00467 const EntityHandle* conn = NULL; 00468 rval = mdbImpl->get_connectivity( polg, conn, nnodes );MB_CHK_ERR( rval ); 00469 numconn += nnodes; 00470 } 00471 block_data.number_nodes_per_element = numconn; 00472 } 00473 else 00474 block_data.number_nodes_per_element = ExoIIUtil::VerticesPerElement[block_data.element_type]; 00475 00476 // Number of nodes for this block 00477 block_data.number_elements = block_data.elements.size(); 00478 00479 // Total number of elements 00480 mesh_info.num_elements += block_data.number_elements; 00481 00482 // Get the nodes for the elements 00483 rval = mWriteIface->gather_nodes_from_elements( block_data.elements, mEntityMark, mesh_info.nodes ); 00484 if( MB_SUCCESS != rval ) return rval; 00485 00486 // if polyhedra block 00487 if( EXOII_POLYHEDRON == block_data.element_type ) 00488 { 00489 rval = mdbImpl->get_connectivity( block_data.elements, mesh_info.polyhedronFaces );MB_CHK_ERR( rval ); 00490 mesh_info.num_polyhedra_blocks++; 00491 } 00492 00493 if( !sidesets.empty() ) 00494 { 00495 // If there are sidesets, keep track of which elements are being written out 00496 for( Range::iterator iter = block_data.elements.begin(); iter != block_data.elements.end(); ++iter ) 00497 { 00498 unsigned char bit = 0x1; 00499 rval = mdbImpl->tag_set_data( mEntityMark, &( *iter ), 1, &bit ); 00500 if( MB_SUCCESS != rval ) return rval; 00501 } 00502 } 00503 00504 block_info.push_back( block_data ); 00505 00506 const void* data = NULL; 00507 int size = 0; 00508 if( MB_SUCCESS == mdbImpl->tag_get_by_ptr( mQaRecordTag, &( *vector_iter ), 1, &data, &size ) && NULL != data ) 00509 { 00510 // There are qa records on this block - copy over to mesh qa records 00511 const char* qa_rec = static_cast< const char* >( data ); 00512 int start = 0; 00513 int count = 0; 00514 for( int i = 0; i < size; i++ ) 00515 { 00516 if( qa_rec[i] == '\0' ) 00517 { 00518 std::string qa_string( &qa_rec[start], i - start ); 00519 mesh_info.qaRecords.push_back( qa_string ); 00520 start = i + 1; 00521 count++; 00522 } 00523 } 00524 00525 // Constrained to multiples of 4 qa records 00526 if( count > 0 ) assert( count % 4 == 0 ); 00527 } 00528 } 00529 00530 mesh_info.num_elementblocks = block_info.size(); 00531 00532 for( std::vector< MaterialSetData >::iterator blit = block_info.begin(); blit != block_info.end(); blit++ ) 00533 { 00534 MaterialSetData& block = *blit; 00535 if( block.element_type != EXOII_POLYHEDRON ) 00536 { 00537 mesh_info.polyhedronFaces = subtract( mesh_info.polyhedronFaces, block.elements ); 00538 } 00539 } 00540 00541 // If user hasn't entered dimension, we figure it out 00542 if( mesh_info.num_dim == 0 ) 00543 { 00544 // Never want 1 or zero dimensions 00545 if( highest_dimension_of_element_blocks < 2 ) 00546 mesh_info.num_dim = 3; 00547 else 00548 mesh_info.num_dim = highest_dimension_of_element_blocks; 00549 } 00550 00551 Range::iterator range_iter, end_range_iter; 00552 range_iter = mesh_info.nodes.begin(); 00553 end_range_iter = mesh_info.nodes.end(); 00554 00555 mesh_info.num_nodes = mesh_info.nodes.size(); 00556 00557 //------nodesets-------- 00558 00559 vector_iter = nodesets.begin(); 00560 end_vector_iter = nodesets.end(); 00561 00562 for( ; vector_iter != end_vector_iter; ++vector_iter ) 00563 { 00564 DirichletSetData nodeset_data; 00565 nodeset_data.id = 0; 00566 nodeset_data.number_nodes = 0; 00567 00568 // Get the nodeset's id 00569 if( mdbImpl->tag_get_data( mDirichletSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS ) 00570 { 00571 MB_SET_ERR( MB_FAILURE, "Couldn't get id tag for nodeset " << id ); 00572 } 00573 00574 nodeset_data.id = id; 00575 00576 std::vector< EntityHandle > node_vector; 00577 // Get the nodes of the nodeset that are in mesh_info.nodes 00578 if( mdbImpl->get_entities_by_handle( *vector_iter, node_vector, true ) != MB_SUCCESS ) 00579 { 00580 MB_SET_ERR( MB_FAILURE, "Couldn't get nodes in nodeset " << id ); 00581 } 00582 00583 // Get the tag for distribution factors 00584 const double* dist_factor_vector; 00585 int dist_factor_size; 00586 const void* ptr = 0; 00587 00588 int has_dist_factors = 0; 00589 if( mdbImpl->tag_get_by_ptr( mDistFactorTag, &( *vector_iter ), 1, &ptr, &dist_factor_size ) == MB_SUCCESS && 00590 dist_factor_size ) 00591 has_dist_factors = 1; 00592 dist_factor_size /= sizeof( double ); 00593 dist_factor_vector = reinterpret_cast< const double* >( ptr ); 00594 std::vector< EntityHandle >::iterator iter, end_iter; 00595 iter = node_vector.begin(); 00596 end_iter = node_vector.end(); 00597 00598 int j = 0; 00599 unsigned char node_marked = 0; 00600 ErrorCode result; 00601 for( ; iter != end_iter; ++iter ) 00602 { 00603 if( TYPE_FROM_HANDLE( *iter ) != MBVERTEX ) continue; 00604 result = mdbImpl->tag_get_data( mEntityMark, &( *iter ), 1, &node_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" ); 00605 00606 if( 0x1 == node_marked ) 00607 { 00608 nodeset_data.nodes.push_back( *iter ); 00609 if( 0 != has_dist_factors ) 00610 nodeset_data.node_dist_factors.push_back( dist_factor_vector[j] ); 00611 else 00612 nodeset_data.node_dist_factors.push_back( 1.0 ); 00613 } 00614 j++; 00615 } 00616 00617 nodeset_data.number_nodes = nodeset_data.nodes.size(); 00618 nodeset_info.push_back( nodeset_data ); 00619 } 00620 00621 //------sidesets-------- 00622 vector_iter = sidesets.begin(); 00623 end_vector_iter = sidesets.end(); 00624 00625 for( ; vector_iter != end_vector_iter; ++vector_iter ) 00626 { 00627 NeumannSetData sideset_data; 00628 00629 // Get the sideset's id 00630 if( mdbImpl->tag_get_data( mNeumannSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS ) return MB_FAILURE; 00631 00632 sideset_data.id = id; 00633 sideset_data.mesh_set_handle = *vector_iter; 00634 00635 // Get the sides in two lists, one forward the other reverse; starts with forward sense 00636 // by convention 00637 Range forward_elems, reverse_elems; 00638 if( get_sideset_elems( *vector_iter, 0, forward_elems, reverse_elems ) == MB_FAILURE ) return MB_FAILURE; 00639 00640 ErrorCode result = get_valid_sides( forward_elems, mesh_info, 1, sideset_data );MB_CHK_SET_ERR( result, "Couldn't get valid sides data" ); 00641 result = get_valid_sides( reverse_elems, mesh_info, -1, sideset_data );MB_CHK_SET_ERR( result, "Couldn't get valid sides data" ); 00642 00643 sideset_data.number_elements = sideset_data.elements.size(); 00644 sideset_info.push_back( sideset_data ); 00645 } 00646 00647 return MB_SUCCESS; 00648 } 00649 00650 ErrorCode WriteNCDF::get_valid_sides( Range& elems, 00651 ExodusMeshInfo& /*mesh_info*/, 00652 const int sense, 00653 NeumannSetData& sideset_data ) 00654 { 00655 // This is where we see if underlying element of side set element is included in output 00656 00657 // Get the sideset-based info for distribution factors 00658 const double* dist_factor_vector = 0; 00659 int dist_factor_size = 0; 00660 00661 // Initialize dist_fac_iter to get rid of compiler warning 00662 const double* dist_fac_iter = 0; 00663 const void* ptr = 0; 00664 bool has_dist_factors = false; 00665 if( mdbImpl->tag_get_by_ptr( mDistFactorTag, &( sideset_data.mesh_set_handle ), 1, &ptr, &dist_factor_size ) == 00666 MB_SUCCESS && 00667 dist_factor_size ) 00668 { 00669 has_dist_factors = true; 00670 dist_factor_vector = reinterpret_cast< const double* >( ptr ); 00671 dist_fac_iter = dist_factor_vector; 00672 dist_factor_size /= sizeof( double ); 00673 } 00674 00675 unsigned char element_marked = 0; 00676 ErrorCode result; 00677 for( Range::iterator iter = elems.begin(); iter != elems.end(); ++iter ) 00678 { 00679 // Should insert here if "side" is a quad/tri on a quad/tri mesh 00680 result = mdbImpl->tag_get_data( mEntityMark, &( *iter ), 1, &element_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" ); 00681 00682 if( 0x1 == element_marked ) 00683 { 00684 sideset_data.elements.push_back( *iter ); 00685 00686 // TJT TODO: the sense should really be # edges + 1or2 00687 sideset_data.side_numbers.push_back( ( sense == 1 ? 1 : 2 ) ); 00688 } 00689 else 00690 { // Then "side" is probably a quad/tri on a hex/tet mesh 00691 std::vector< EntityHandle > parents; 00692 int dimension = CN::Dimension( TYPE_FROM_HANDLE( *iter ) ); 00693 00694 // Get the adjacent parent element of "side" 00695 if( mdbImpl->get_adjacencies( &( *iter ), 1, dimension + 1, false, parents ) != MB_SUCCESS ) 00696 { 00697 #if 0 00698 // This is not treated as an error, print warning messages for 00699 // debugging only 00700 fprintf(stderr, "[Warning]: Couldn't get adjacencies for sideset.\n"); 00701 #endif 00702 } 00703 00704 if( !parents.empty() ) 00705 { 00706 // Make sure the adjacent parent element will be output 00707 for( unsigned int k = 0; k < parents.size(); k++ ) 00708 { 00709 result = mdbImpl->tag_get_data( mEntityMark, &( parents[k] ), 1, &element_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" ); 00710 00711 int side_no, this_sense, this_offset; 00712 if( 0x1 == element_marked && 00713 mdbImpl->side_number( parents[k], *iter, side_no, this_sense, this_offset ) == MB_SUCCESS && 00714 this_sense == sense ) 00715 { 00716 sideset_data.elements.push_back( parents[k] ); 00717 sideset_data.side_numbers.push_back( side_no + 1 ); 00718 break; 00719 } 00720 } 00721 } 00722 else 00723 { 00724 #if 0 00725 // This is not treated as an error, print warning messages for 00726 // debugging only 00727 fprintf(stderr, "[Warning]: No parent element exists for element in sideset %i\n", sideset_data.id); 00728 #endif 00729 } 00730 } 00731 00732 if( sideset_data.elements.size() != 0 ) 00733 { 00734 // Distribution factors 00735 int num_nodes = CN::VerticesPerEntity( TYPE_FROM_HANDLE( *iter ) ); 00736 // put some dummy dist factors for polygons; why do we need them? 00737 if( TYPE_FROM_HANDLE( *iter ) == MBPOLYGON ) num_nodes = 1; // dummy 00738 if( has_dist_factors ) 00739 { 00740 std::copy( dist_fac_iter, dist_fac_iter + num_nodes, 00741 std::back_inserter( sideset_data.ss_dist_factors ) ); 00742 dist_fac_iter += num_nodes; 00743 } 00744 else 00745 { 00746 for( int j = 0; j < num_nodes; j++ ) 00747 sideset_data.ss_dist_factors.push_back( 1.0 ); 00748 } 00749 } 00750 } 00751 00752 return MB_SUCCESS; 00753 } 00754 00755 ErrorCode WriteNCDF::write_qa_records( std::vector< std::string >& qa_record_list ) 00756 { 00757 int i = 0; 00758 00759 for( std::vector< std::string >::iterator string_it = qa_record_list.begin(); string_it != qa_record_list.end(); ) 00760 { 00761 for( int j = 0; j < 4; j++ ) 00762 write_qa_string( ( *string_it++ ).c_str(), i, j ); 00763 i++; 00764 } 00765 00766 return MB_SUCCESS; 00767 } 00768 00769 ErrorCode WriteNCDF::write_qa_string( const char* string, int record_number, int record_position ) 00770 { 00771 // Get the variable id in the exodus file 00772 00773 std::vector< int > dims; 00774 int temp_var = -1; 00775 GET_VAR( "qa_records", temp_var, dims ); 00776 if( -1 == temp_var ) 00777 { 00778 MB_SET_ERR( MB_FAILURE, "WriteNCDF:: Problem getting qa record variable" ); 00779 } 00780 size_t count[3], start[3]; 00781 00782 // Write out the record 00783 start[0] = record_number; 00784 start[1] = record_position; 00785 start[2] = 0; 00786 00787 count[0] = 1; 00788 count[1] = 1; 00789 count[2] = (long)strlen( string ) + 1; 00790 int fail = nc_put_vara_text( ncFile, temp_var, start, count, string ); 00791 if( NC_NOERR != fail ) 00792 { 00793 MB_SET_ERR( MB_FAILURE, "Failed to position qa string variable" ); 00794 } 00795 00796 return MB_SUCCESS; 00797 } 00798 00799 ErrorCode WriteNCDF::write_nodes( int num_nodes, Range& nodes, int dimension ) 00800 { 00801 // Write coordinates names 00802 int nc_var = -1; 00803 std::vector< int > dims; 00804 GET_VAR( "coor_names", nc_var, dims ); 00805 if( -1 == nc_var ) 00806 { 00807 MB_SET_ERR( MB_FAILURE, "Trouble getting coordinate name variable" ); 00808 } 00809 00810 size_t start[2] = { 0, 0 }, count[2] = { 1, ExoIIInterface::MAX_STR_LENGTH }; 00811 char dum_str[ExoIIInterface::MAX_STR_LENGTH]; 00812 strcpy( dum_str, "x" ); 00813 int fail = nc_put_vara_text( ncFile, nc_var, start, count, dum_str ); 00814 if( NC_NOERR != fail ) 00815 { 00816 MB_SET_ERR( MB_FAILURE, "Trouble adding x coordinate name; netcdf message: " << nc_strerror( fail ) ); 00817 } 00818 00819 start[0] = 1; 00820 strcpy( dum_str, "y" ); 00821 fail = nc_put_vara_text( ncFile, nc_var, start, count, dum_str ); 00822 if( NC_NOERR != fail ) 00823 { 00824 MB_SET_ERR( MB_FAILURE, "Trouble adding y coordinate name; netcdf message: " << nc_strerror( fail ) ); 00825 } 00826 00827 start[0] = 2; 00828 strcpy( dum_str, "z" ); 00829 fail = nc_put_vara_text( ncFile, nc_var, start, count, dum_str ); 00830 if( NC_NOERR != fail ) 00831 { 00832 MB_SET_ERR( MB_FAILURE, "Trouble adding z coordinate name; netcdf message: " << nc_strerror( fail ) ); 00833 } 00834 00835 // See if should transform coordinates 00836 ErrorCode result; 00837 Tag trans_tag; 00838 result = mdbImpl->tag_get_handle( MESH_TRANSFORM_TAG_NAME, 16, MB_TYPE_DOUBLE, trans_tag ); 00839 bool transform_needed = true; 00840 if( result == MB_TAG_NOT_FOUND ) transform_needed = false; 00841 00842 int num_coords_to_fill = transform_needed ? 3 : dimension; 00843 00844 std::vector< double* > coord_arrays( 3 ); 00845 coord_arrays[0] = new double[num_nodes]; 00846 coord_arrays[1] = new double[num_nodes]; 00847 coord_arrays[2] = NULL; 00848 00849 if( num_coords_to_fill == 3 ) coord_arrays[2] = new double[num_nodes]; 00850 00851 result = mWriteIface->get_node_coords( dimension, num_nodes, nodes, mGlobalIdTag, 1, coord_arrays ); 00852 if( result != MB_SUCCESS ) 00853 { 00854 delete[] coord_arrays[0]; 00855 delete[] coord_arrays[1]; 00856 if( coord_arrays[2] ) delete[] coord_arrays[2]; 00857 return result; 00858 } 00859 00860 if( transform_needed ) 00861 { 00862 double trans_matrix[16]; 00863 const EntityHandle mesh = 0; 00864 result = mdbImpl->tag_get_data( trans_tag, &mesh, 0, trans_matrix );MB_CHK_SET_ERR( result, "Couldn't get transform data" ); 00865 00866 for( int i = 0; i < num_nodes; i++ ) 00867 { 00868 double vec1[3]; 00869 double vec2[3]; 00870 00871 vec2[0] = coord_arrays[0][i]; 00872 vec2[1] = coord_arrays[1][i]; 00873 vec2[2] = coord_arrays[2][i]; 00874 00875 for( int row = 0; row < 3; row++ ) 00876 { 00877 vec1[row] = 0.0; 00878 for( int col = 0; col < 3; col++ ) 00879 vec1[row] += ( trans_matrix[( row * 4 ) + col] * vec2[col] ); 00880 } 00881 00882 coord_arrays[0][i] = vec1[0]; 00883 coord_arrays[1][i] = vec1[1]; 00884 coord_arrays[2][i] = vec1[2]; 00885 } 00886 } 00887 00888 // Write the nodes 00889 nc_var = -1; 00890 GET_VAR( "coord", nc_var, dims ); 00891 if( -1 == nc_var ) 00892 { 00893 MB_SET_ERR( MB_FAILURE, "Trouble getting coordinate variable" ); 00894 } 00895 start[0] = 0; 00896 count[1] = num_nodes; 00897 fail = nc_put_vara_double( ncFile, nc_var, start, count, &( coord_arrays[0][0] ) ); 00898 if( NC_NOERR != fail ) 00899 { 00900 MB_SET_ERR( MB_FAILURE, "Trouble writing x coordinate" ); 00901 } 00902 00903 start[0] = 1; 00904 fail = nc_put_vara_double( ncFile, nc_var, start, count, &( coord_arrays[1][0] ) ); 00905 if( NC_NOERR != fail ) 00906 { 00907 MB_SET_ERR( MB_FAILURE, "Trouble writing y coordinate" ); 00908 } 00909 00910 start[0] = 2; 00911 fail = nc_put_vara_double( ncFile, nc_var, start, count, &( coord_arrays[2][0] ) ); 00912 if( NC_NOERR != fail ) 00913 { 00914 MB_SET_ERR( MB_FAILURE, "Trouble writing z coordinate" ); 00915 } 00916 00917 delete[] coord_arrays[0]; 00918 delete[] coord_arrays[1]; 00919 if( coord_arrays[2] ) delete[] coord_arrays[2]; 00920 00921 return MB_SUCCESS; 00922 } 00923 00924 ErrorCode WriteNCDF::write_poly_faces( ExodusMeshInfo& mesh_info ) 00925 { 00926 // write all polygons that are not in another element block; 00927 // usually they are nowhere else, but be sure, write in this block only ones that are not in the 00928 // other blocks 00929 Range pfaces = mesh_info.polyhedronFaces; 00930 00931 /* 00932 * int fbconn1(num_nod_per_fa1) ; 00933 fbconn1:elem_type = "nsided" ; 00934 int fbepecnt1(num_fa_in_blk1) ; 00935 fbepecnt1:entity_type1 = "NODE" ; 00936 fbepecnt1:entity_type2 = "FACE" ; 00937 */ 00938 if( pfaces.empty() ) return MB_SUCCESS; 00939 char wname[80]; 00940 int nc_var = -1; 00941 std::vector< int > dims; 00942 00943 // write one for each element block, to make paraview and visit happy 00944 int num_faces_in_block = (int)pfaces.size(); 00945 for( unsigned int bl = 0; bl < mesh_info.num_polyhedra_blocks; bl++ ) 00946 { 00947 INS_ID( wname, "fbconn%u", bl + 1 ); // it is the first block 00948 GET_VAR( wname, nc_var, dims ); // fbconn# variable, 1 dimensional 00949 00950 INS_ID( wname, "num_nod_per_fa%u", bl + 1 ); 00951 int ncdim, num_nod_per_face; 00952 GET_DIM( ncdim, wname, num_nod_per_face ); 00953 int* connectivity = new int[num_nod_per_face]; 00954 int ixcon = 0, j = 0; 00955 std::vector< int > fbepe( num_faces_in_block ); // fbepecnt1 00956 for( Range::iterator eit = pfaces.begin(); eit != pfaces.end(); eit++ ) 00957 { 00958 EntityHandle polyg = *eit; 00959 int nnodes = 0; 00960 const EntityHandle* conn = NULL; 00961 ErrorCode rval = mdbImpl->get_connectivity( polyg, conn, nnodes );MB_CHK_ERR( rval ); 00962 for( int k = 0; k < nnodes; k++ ) 00963 connectivity[ixcon++] = conn[k]; 00964 fbepe[j++] = nnodes; 00965 } 00966 size_t start[1] = { 0 }, count[1] = { 0 }; 00967 count[0] = ixcon; 00968 int fail = nc_put_vara_int( ncFile, nc_var, start, count, connectivity ); 00969 if( NC_NOERR != fail ) 00970 { 00971 delete[] connectivity; 00972 MB_SET_ERR( MB_FAILURE, "Couldn't write fbconn variable" ); 00973 } 00974 00975 INS_ID( wname, "fbepecnt%u", bl + 1 ); 00976 GET_VAR( wname, nc_var, dims ); // fbconn# variable, 1 dimensional 00977 count[0] = num_faces_in_block; 00978 00979 fail = nc_put_vara_int( ncFile, nc_var, start, count, &fbepe[0] ); 00980 if( NC_NOERR != fail ) 00981 { 00982 delete[] connectivity; 00983 MB_SET_ERR( MB_FAILURE, "Couldn't write fbepecnt variable" ); 00984 } 00985 00986 int id = bl + 1; 00987 if( write_exodus_integer_variable( "fa_prop1", &id, bl, 1 ) != MB_SUCCESS ) 00988 { 00989 MB_SET_ERR_CONT( "Problem writing element block id " << id ); 00990 } 00991 00992 int status = 1; 00993 if( write_exodus_integer_variable( "fa_status", &status, bl, 1 ) != MB_SUCCESS ) 00994 { 00995 MB_SET_ERR( MB_FAILURE, "Problem writing face block status" ); 00996 } 00997 00998 delete[] connectivity; 00999 if( 0 == repeat_face_blocks ) break; // do not repeat face blocks 01000 } 01001 01002 return MB_SUCCESS; 01003 } 01004 ErrorCode WriteNCDF::write_header( ExodusMeshInfo& mesh_info, 01005 std::vector< MaterialSetData >& block_info, 01006 std::vector< NeumannSetData >& sideset_info, 01007 std::vector< DirichletSetData >& nodeset_info, 01008 const char* filename ) 01009 { 01010 // Get the date and time 01011 char time[TIME_STR_LEN]; 01012 char date[TIME_STR_LEN]; 01013 time_and_date( time, date ); 01014 01015 std::string title_string = "MOAB"; 01016 title_string.append( "(" ); 01017 title_string.append( filename ); 01018 title_string.append( "): " ); 01019 title_string.append( date ); 01020 title_string.append( ": " ); 01021 title_string.append( "time " ); 01022 01023 if( title_string.length() > ExoIIInterface::MAX_LINE_LENGTH ) 01024 title_string.resize( ExoIIInterface::MAX_LINE_LENGTH ); 01025 01026 // Initialize the exodus file 01027 01028 int result = initialize_exodus_file( mesh_info, block_info, sideset_info, nodeset_info, title_string.c_str() ); 01029 01030 if( result == MB_FAILURE ) return MB_FAILURE; 01031 01032 return MB_SUCCESS; 01033 } 01034 01035 ErrorCode WriteNCDF::write_elementblocks( ExodusMeshInfo& mesh_info, std::vector< MaterialSetData >& block_data ) 01036 { 01037 unsigned int i; 01038 int block_index = 0; // Index into block list, may != 1 if there are inactive blocks 01039 int exodus_id = 1; 01040 01041 for( i = 0; i < block_data.size(); i++ ) 01042 { 01043 MaterialSetData& block = block_data[i]; 01044 01045 unsigned int num_nodes_per_elem = block.number_nodes_per_element; 01046 01047 // Write out the id for the block 01048 01049 int id = block.id; 01050 int num_values = 1; 01051 01052 if( write_exodus_integer_variable( "eb_prop1", &id, block_index, num_values ) != MB_SUCCESS ) 01053 { 01054 MB_SET_ERR_CONT( "Problem writing element block id " << id ); 01055 } 01056 01057 // Write out the block status 01058 01059 int status = 1; 01060 if( 0 == block.number_elements ) 01061 { 01062 MB_SET_ERR( MB_FAILURE, "No elements in block " << id ); 01063 } 01064 01065 if( write_exodus_integer_variable( "eb_status", &status, block_index, num_values ) != MB_SUCCESS ) 01066 { 01067 MB_SET_ERR( MB_FAILURE, "Problem writing element block status" ); 01068 } 01069 01070 // 01071 // Map the connectivity to the new nodes 01072 const unsigned int num_elem = block.number_elements; 01073 unsigned int num_nodes = num_nodes_per_elem * num_elem; 01074 if( EXOII_POLYGON == block.element_type || EXOII_POLYHEDRON == block.element_type ) 01075 { 01076 num_nodes = num_nodes_per_elem; 01077 } 01078 int* connectivity = new int[num_nodes]; 01079 01080 ErrorCode result = MB_SUCCESS; 01081 if( block.element_type != EXOII_POLYHEDRON ) 01082 mWriteIface->get_element_connect( num_elem, num_nodes_per_elem, mGlobalIdTag, block.elements, mGlobalIdTag, 01083 exodus_id, connectivity ); 01084 if( result != MB_SUCCESS ) 01085 { 01086 delete[] connectivity; 01087 MB_SET_ERR( result, "Couldn't get element array to write from" ); 01088 } 01089 01090 // If necessary, convert from EXODUS to CN node order 01091 const EntityType elem_type = ExoIIUtil::ExoIIElementMBEntity[block.element_type]; 01092 assert( block.elements.all_of_type( elem_type ) ); 01093 const int* reorder = 0; 01094 if( block.element_type != EXOII_POLYHEDRON && block.element_type != EXOII_POLYGON ) 01095 reorder = exodus_elem_order_map[elem_type][block.number_nodes_per_element]; 01096 if( reorder ) 01097 WriteUtilIface::reorder( reorder, connectivity, block.number_elements, block.number_nodes_per_element ); 01098 01099 char wname[80]; 01100 int nc_var = -1; 01101 std::vector< int > dims; 01102 if( block.element_type != EXOII_POLYHEDRON ) 01103 { 01104 exodus_id += num_elem; 01105 INS_ID( wname, "connect%u", i + 1 ); 01106 01107 GET_VAR( wname, nc_var, dims ); 01108 if( -1 == nc_var ) 01109 { 01110 delete[] connectivity; 01111 MB_SET_ERR( MB_FAILURE, "Couldn't get connectivity variable" ); 01112 } 01113 } 01114 01115 if( EXOII_POLYGON == block.element_type ) 01116 { 01117 size_t start[1] = { 0 }, count[1] = { num_nodes_per_elem }; 01118 int fail = nc_put_vara_int( ncFile, nc_var, start, count, connectivity ); 01119 if( NC_NOERR != fail ) 01120 { 01121 delete[] connectivity; 01122 MB_SET_ERR( MB_FAILURE, "Couldn't write connectivity variable" ); 01123 } 01124 // now put also number ebepecnt1 01125 INS_ID( wname, "ebepecnt%u", i + 1 ); 01126 GET_VAR( wname, nc_var, dims ); 01127 count[0] = block.number_elements; 01128 start[0] = 0; 01129 // reuse connectivity array, to not allocate another one 01130 int j = 0; 01131 for( Range::iterator eit = block.elements.begin(); eit != block.elements.end(); j++, eit++ ) 01132 { 01133 EntityHandle polg = *eit; 01134 int nnodes = 0; 01135 const EntityHandle* conn = NULL; 01136 ErrorCode rval = mdbImpl->get_connectivity( polg, conn, nnodes );MB_CHK_ERR( rval ); 01137 connectivity[j] = nnodes; 01138 } 01139 fail = nc_put_vara_int( ncFile, nc_var, start, count, connectivity ); 01140 if( NC_NOERR != fail ) 01141 { 01142 delete[] connectivity; 01143 MB_SET_ERR( MB_FAILURE, "Couldn't write ebepecnt variable" ); 01144 } 01145 } 01146 else if( block.element_type != EXOII_POLYHEDRON ) 01147 { 01148 size_t start[2] = { 0, 0 }, count[2] = { num_elem, num_nodes_per_elem }; 01149 int fail = nc_put_vara_int( ncFile, nc_var, start, count, connectivity ); 01150 if( NC_NOERR != fail ) 01151 { 01152 delete[] connectivity; 01153 MB_SET_ERR( MB_FAILURE, "Couldn't write connectivity variable" ); 01154 } 01155 } 01156 else // if (block.element_type == EXOII_POLYHEDRON) 01157 { 01158 /* write a lot of stuff // faconn 01159 num_fa_in_blk1 = 15 ; 01160 num_nod_per_fa1 = 58 ; 01161 num_el_in_blk1 = 3 ; 01162 num_fac_per_el1 = 17 ; 01163 int fbconn1(num_nod_per_fa1) ; 01164 fbconn1:elem_type = "nsided" ; 01165 int fbepecnt1(num_fa_in_blk1) ; 01166 fbepecnt1:entity_type1 = "NODE" ; 01167 fbepecnt1:entity_type2 = "FACE" ; 01168 int facconn1(num_fac_per_el1) ; 01169 facconn1:elem_type = "NFACED" ; 01170 int ebepecnt1(num_el_in_blk1) ; 01171 ebepecnt1:entity_type1 = "FACE" ; 01172 ebepecnt1:entity_type2 = "ELEM" ; 01173 01174 */ 01175 Range& block_faces = mesh_info.polyhedronFaces; 01176 // ErrorCode rval = mdbImpl->get_connectivity(block.elements, block_faces); 01177 // MB_CHK_ERR(rval); 01178 01179 // reuse now connectivity for facconn1 01180 INS_ID( wname, "facconn%u", i + 1 ); 01181 GET_VAR( wname, nc_var, dims ); // fbconn# variable, 1 dimensional 01182 01183 std::vector< int > ebepe( block.elements.size() ); // ebepecnt1 01184 int ixcon = 0, j = 0; 01185 size_t start[1] = { 0 }, count[1] = { 0 }; 01186 01187 for( Range::iterator eit = block.elements.begin(); eit != block.elements.end(); eit++ ) 01188 { 01189 EntityHandle polyh = *eit; 01190 int nfaces = 0; 01191 const EntityHandle* conn = NULL; 01192 ErrorCode rval = mdbImpl->get_connectivity( polyh, conn, nfaces );MB_CHK_ERR( rval ); 01193 for( int k = 0; k < nfaces; k++ ) 01194 { 01195 int index = block_faces.index( conn[k] ); 01196 if( index == -1 ) MB_SET_ERR( MB_FAILURE, "Couldn't find face in polyhedron" ); 01197 connectivity[ixcon++] = index + 1; 01198 } 01199 ebepe[j++] = nfaces; 01200 // num_faces+=nfaces; 01201 } 01202 count[0] = ixcon; // facconn1 01203 int fail = nc_put_vara_int( ncFile, nc_var, start, count, connectivity ); 01204 if( NC_NOERR != fail ) 01205 { 01206 delete[] connectivity; 01207 MB_SET_ERR( MB_FAILURE, "Couldn't write fbconn variable" ); 01208 } 01209 01210 INS_ID( wname, "ebepecnt%u", i + 1 ); 01211 GET_VAR( wname, nc_var, dims ); // ebepecnt# variable, 1 dimensional 01212 count[0] = block.elements.size(); 01213 01214 fail = nc_put_vara_int( ncFile, nc_var, start, count, &ebepe[0] ); 01215 if( NC_NOERR != fail ) 01216 { 01217 delete[] connectivity; 01218 MB_SET_ERR( MB_FAILURE, "Couldn't write fbepecnt variable" ); 01219 } 01220 } 01221 block_index++; 01222 delete[] connectivity; 01223 } 01224 01225 return MB_SUCCESS; 01226 } 01227 01228 ErrorCode WriteNCDF::write_global_node_order_map( int num_nodes, Range& nodes ) 01229 { 01230 // Note: this routine bypasses the standard exodusII interface for efficiency! 01231 01232 // Node order map 01233 int* map = new int[num_nodes]; 01234 01235 // For now, output a dummy map! 01236 01237 Range::iterator range_iter, end_iter; 01238 range_iter = nodes.begin(); 01239 end_iter = nodes.end(); 01240 01241 int i = 0; 01242 01243 for( ; range_iter != end_iter; ++range_iter ) 01244 { 01245 // TODO -- do we really want to cast this to an int? 01246 map[i++] = (int)ID_FROM_HANDLE( *range_iter ); 01247 } 01248 01249 // Output array and cleanup 01250 01251 int error = write_exodus_integer_variable( "node_num_map", map, 0, num_nodes ); 01252 01253 if( map ) delete[] map; 01254 01255 if( error < 0 ) 01256 { 01257 MB_SET_ERR( MB_FAILURE, "Failed writing global node order map" ); 01258 } 01259 01260 return MB_SUCCESS; 01261 } 01262 01263 ErrorCode WriteNCDF::write_global_element_order_map( int num_elements ) 01264 { 01265 // Allocate map array 01266 int* map = new int[num_elements]; 01267 01268 // Many Sandia codes assume this map is unique, and CUBIT does not currently 01269 // have unique ids for all elements. Therefore, to make sure nothing crashes, 01270 // insert a dummy map... 01271 01272 for( int i = 0; i < num_elements; i++ ) 01273 map[i] = i + 1; 01274 01275 // Output array and cleanup 01276 01277 int error = write_exodus_integer_variable( "elem_num_map", map, 0, num_elements ); 01278 01279 if( map ) delete[] map; 01280 01281 if( error < 0 ) 01282 { 01283 MB_SET_ERR( MB_FAILURE, "Failed writing global element order map" ); 01284 } 01285 01286 return MB_SUCCESS; 01287 } 01288 01289 ErrorCode WriteNCDF::write_element_order_map( int num_elements ) 01290 { 01291 // Note: this routine bypasses the standard exodusII interface for efficiency! 01292 01293 // Element order map 01294 int* map = new int[num_elements]; 01295 01296 // For now, output a dummy map! 01297 01298 for( int i = 0; i < num_elements; i++ ) 01299 { 01300 map[i] = i + 1; 01301 } 01302 01303 // Output array and cleanup 01304 01305 int error = write_exodus_integer_variable( "elem_map", map, 0, num_elements ); 01306 01307 if( map ) delete[] map; 01308 01309 if( error < 0 ) 01310 { 01311 MB_SET_ERR( MB_FAILURE, "Failed writing element map" ); 01312 } 01313 01314 return MB_SUCCESS; 01315 } 01316 01317 ErrorCode WriteNCDF::write_exodus_integer_variable( const char* variable_name, 01318 int* variable_array, 01319 int start_position, 01320 int number_values ) 01321 { 01322 // Note: this routine bypasses the standard exodusII interface for efficiency! 01323 01324 // Write directly to netcdf interface for efficiency 01325 01326 // Get the variable id of the element map 01327 int nc_var = -1; 01328 std::vector< int > dims; 01329 GET_VAR( variable_name, nc_var, dims ); 01330 if( -1 == nc_var ) 01331 { 01332 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to locate variable " << variable_name << " in file" ); 01333 } 01334 // This contortion is necessary because netCDF is expecting nclongs; 01335 // fortunately it's necessary only when ints and nclongs aren't the same size 01336 01337 size_t start[1], count[1]; 01338 start[0] = start_position; 01339 count[0] = number_values; 01340 01341 int fail = NC_NOERR; 01342 if( sizeof( int ) == sizeof( long ) ) 01343 { 01344 fail = nc_put_vara_int( ncFile, nc_var, start, count, variable_array ); 01345 } 01346 else 01347 { 01348 long* lptr = new long[number_values]; 01349 for( int jj = 0; jj < number_values; jj++ ) 01350 lptr[jj] = variable_array[jj]; 01351 fail = nc_put_vara_long( ncFile, nc_var, start, count, lptr ); 01352 delete[] lptr; 01353 } 01354 01355 if( NC_NOERR != fail ) 01356 { 01357 MB_SET_ERR( MB_FAILURE, "Failed to store variable " << variable_name ); 01358 } 01359 01360 return MB_SUCCESS; 01361 } 01362 01363 ErrorCode WriteNCDF::write_BCs( std::vector< NeumannSetData >& sidesets, std::vector< DirichletSetData >& nodesets ) 01364 { 01365 unsigned int i, j; 01366 int id; 01367 int ns_index = -1; 01368 01369 for( std::vector< DirichletSetData >::iterator ns_it = nodesets.begin(); ns_it != nodesets.end(); ++ns_it ) 01370 { 01371 // Get number of nodes in set 01372 int number_nodes = ( *ns_it ).number_nodes; 01373 if( 0 == number_nodes ) continue; 01374 01375 // If we're here, we have a non-empty nodeset; increment the index 01376 ns_index++; 01377 01378 // Get the node set id 01379 id = ( *ns_it ).id; 01380 01381 // Build new array to old exodus ids 01382 int* exodus_id_array = new int[number_nodes]; 01383 double* dist_factor_array = new double[number_nodes]; 01384 01385 std::vector< EntityHandle >::iterator begin_iter, end_iter; 01386 std::vector< double >::iterator other_iter; 01387 begin_iter = ( *ns_it ).nodes.begin(); 01388 end_iter = ( *ns_it ).nodes.end(); 01389 other_iter = ( *ns_it ).node_dist_factors.begin(); 01390 01391 j = 0; 01392 int exodus_id; 01393 ErrorCode result; 01394 // Fill up node array and dist. factor array at the same time 01395 for( ; begin_iter != end_iter; ++begin_iter ) 01396 { 01397 result = mdbImpl->tag_get_data( mGlobalIdTag, &( *begin_iter ), 1, &exodus_id );MB_CHK_SET_ERR( result, "Problem getting id tag data" ); 01398 01399 exodus_id_array[j] = exodus_id; 01400 dist_factor_array[j] = *( other_iter ); 01401 ++other_iter; 01402 j++; 01403 } 01404 01405 // Write out the id for the nodeset 01406 01407 int num_values = 1; 01408 01409 result = write_exodus_integer_variable( "ns_prop1", &id, ns_index, num_values );MB_CHK_SET_ERR_RET_VAL( result, "Problem writing node set id " << id, MB_FAILURE ); 01410 01411 // Write out the nodeset status 01412 01413 int status = 1; 01414 if( !number_nodes ) status = 0; 01415 01416 result = write_exodus_integer_variable( "ns_status", &status, ns_index, num_values );MB_CHK_SET_ERR_RET_VAL( result, "Problem writing node set status", MB_FAILURE ); 01417 01418 // Write it out 01419 char wname[80]; 01420 int nc_var = -1; 01421 std::vector< int > dims; 01422 INS_ID( wname, "node_ns%d", ns_index + 1 ); 01423 GET_VAR( wname, nc_var, dims ); 01424 if( -1 == nc_var ) 01425 { 01426 MB_SET_ERR( MB_FAILURE, "Failed to get node_ns variable" ); 01427 } 01428 01429 size_t start = 0, count = number_nodes; 01430 int fail = nc_put_vara_int( ncFile, nc_var, &start, &count, exodus_id_array ); 01431 if( NC_NOERR != fail ) 01432 { 01433 MB_SET_ERR( MB_FAILURE, "Failed writing exodus id array" ); 01434 } 01435 01436 // Write out nodeset distribution factors 01437 INS_ID( wname, "dist_fact_ns%d", ns_index + 1 ); 01438 nc_var = -1; 01439 GET_VAR( wname, nc_var, dims ); 01440 if( -1 == nc_var ) 01441 { 01442 MB_SET_ERR( MB_FAILURE, "Failed to get dist_fact variable" ); 01443 } 01444 fail = nc_put_vara_double( ncFile, nc_var, &start, &count, dist_factor_array ); 01445 if( NC_NOERR != fail ) 01446 { 01447 MB_SET_ERR( MB_FAILURE, "Failed writing dist factor array" ); 01448 } 01449 01450 delete[] dist_factor_array; 01451 delete[] exodus_id_array; 01452 } 01453 01454 // Now do sidesets 01455 int ss_index = 0; // Index of sideset - not the same as 'i' because 01456 // only writing non-empty side sets 01457 for( i = 0; i < sidesets.size(); i++ ) 01458 { 01459 NeumannSetData sideset_data = sidesets[i]; 01460 01461 // Get the side set id 01462 int side_set_id = sideset_data.id; 01463 01464 // Get number of elements in set 01465 int number_elements = sideset_data.number_elements; 01466 if( 0 == number_elements ) continue; 01467 01468 // Build new array to old exodus ids 01469 int* output_element_ids = new int[number_elements]; 01470 int* output_element_side_numbers = new int[number_elements]; 01471 01472 std::vector< EntityHandle >::iterator begin_iter, end_iter; 01473 begin_iter = sideset_data.elements.begin(); 01474 end_iter = sideset_data.elements.end(); 01475 std::vector< int >::iterator side_iter = sideset_data.side_numbers.begin(); 01476 01477 // Get the tag handle 01478 j = 0; 01479 int exodus_id; 01480 01481 // For each "side" 01482 for( ; begin_iter != end_iter; ++begin_iter, ++side_iter ) 01483 { 01484 ErrorCode result = mdbImpl->tag_get_data( mGlobalIdTag, &( *begin_iter ), 1, &exodus_id );MB_CHK_SET_ERR( result, "Problem getting exodus id for sideset element " 01485 << (long unsigned int)ID_FROM_HANDLE( *begin_iter ) ); 01486 01487 output_element_ids[j] = exodus_id; 01488 output_element_side_numbers[j++] = *side_iter; 01489 } 01490 01491 if( 0 != number_elements ) 01492 { 01493 // Write out the id for the nodeset 01494 01495 int num_values = 1; 01496 01497 // ss_prop1[ss_index] = side_set_id 01498 ErrorCode result = write_exodus_integer_variable( "ss_prop1", &side_set_id, ss_index, num_values );MB_CHK_SET_ERR_RET_VAL( result, "Problem writing node set id " << id, MB_FAILURE ); 01499 01500 // FIXME : Something seems wrong here. The we are within a block 01501 // started with if (0 != number_elements), so this condition is always 01502 // false. This code seems to indicate that we want to write all 01503 // sidesets, not just empty ones. But the code both here and in 01504 // initialize_exodus_file() skip empty side sets. 01505 // - j.k. 2007-03-09 01506 int status = 1; 01507 if( 0 == number_elements ) status = 0; 01508 01509 // ss_status[ss_index] = status 01510 result = write_exodus_integer_variable( "ss_status", &status, ss_index, num_values );MB_CHK_SET_ERR_RET_VAL( result, "Problem writing side set status", MB_FAILURE ); 01511 01512 // Increment ss_index now because we want a) we need to 01513 // increment it somewhere within the if (0 != number_elements) 01514 // block and b) the above calls need a zero-based index 01515 // while the following use a one-based index. 01516 ++ss_index; 01517 01518 char wname[80]; 01519 int nc_var; 01520 std::vector< int > dims; 01521 INS_ID( wname, "elem_ss%d", ss_index ); 01522 GET_VAR( wname, nc_var, dims ); 01523 if( -1 == nc_var ) 01524 { 01525 MB_SET_ERR( MB_FAILURE, "Failed to get elem_ss variable" ); 01526 } 01527 size_t start = 0, count = number_elements; 01528 int fail = nc_put_vara_int( ncFile, nc_var, &start, &count, output_element_ids ); 01529 if( NC_NOERR != fail ) 01530 { 01531 MB_SET_ERR( MB_FAILURE, "Failed writing sideset element array" ); 01532 } 01533 01534 INS_ID( wname, "side_ss%d", ss_index ); 01535 nc_var = -1; 01536 GET_VAR( wname, nc_var, dims ); 01537 if( -1 == nc_var ) 01538 { 01539 MB_SET_ERR( MB_FAILURE, "Failed to get side_ss variable" ); 01540 } 01541 fail = nc_put_vara_int( ncFile, nc_var, &start, &count, output_element_side_numbers ); 01542 if( NC_NOERR != fail ) 01543 { 01544 MB_SET_ERR( MB_FAILURE, "Failed writing sideset side array" ); 01545 } 01546 01547 INS_ID( wname, "dist_fact_ss%d", ss_index ); 01548 nc_var = -1; 01549 GET_VAR( wname, nc_var, dims ); 01550 if( -1 == nc_var ) 01551 { 01552 MB_SET_ERR( MB_FAILURE, "Failed to get sideset dist factors variable" ); 01553 } 01554 count = sideset_data.ss_dist_factors.size(); 01555 fail = nc_put_vara_double( ncFile, nc_var, &start, &count, &( sideset_data.ss_dist_factors[0] ) ); 01556 if( NC_NOERR != fail ) 01557 { 01558 MB_SET_ERR( MB_FAILURE, "Failed writing sideset dist factors array" ); 01559 } 01560 } 01561 01562 delete[] output_element_ids; 01563 delete[] output_element_side_numbers; 01564 } 01565 01566 return MB_SUCCESS; 01567 } 01568 01569 ErrorCode WriteNCDF::initialize_exodus_file( ExodusMeshInfo& mesh_info, 01570 std::vector< MaterialSetData >& block_data, 01571 std::vector< NeumannSetData >& sideset_data, 01572 std::vector< DirichletSetData >& nodeset_data, 01573 const char* title_string, 01574 bool write_maps, 01575 bool /* write_sideset_distribution_factors */ ) 01576 { 01577 // This routine takes the place of the exodusii routine ex_put_init, 01578 // and additionally pre-defines variables such as qa, element blocks, 01579 // sidesets and nodesets in a single pass. 01580 // 01581 // This is necessary because of the way exodusII works. Each time the 01582 // netcdf routine endef is called to take the file out of define mode, 01583 // the entire file is copied before the new information is added. 01584 // 01585 // With very large files, this is simply not workable. This routine takes 01586 // the definition portions of all applicable exodus routines and puts them 01587 // in a single definition, preventing repeated copying of the file. 01588 // 01589 // Most of the code is copied directly from the applicable exodus routine, 01590 // and thus this routine may not seem very consistent in usage or variable 01591 // naming, etc. 01592 01593 // Perform the initializations 01594 01595 int element_block_index; 01596 01597 // Inquire on defined string dimension and general dimension for qa 01598 01599 int dim_str, dim_four, dim_line, dim_time; 01600 if( nc_def_dim( ncFile, "len_string", ExoIIInterface::MAX_STR_LENGTH, &dim_str ) != NC_NOERR ) 01601 { 01602 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to get string length in file" ); 01603 } 01604 01605 if( nc_def_dim( ncFile, "len_line", ExoIIInterface::MAX_STR_LENGTH, &dim_line ) != NC_NOERR ) 01606 { 01607 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to get line length in file" ); 01608 } 01609 01610 if( nc_def_dim( ncFile, "four", 4, &dim_four ) != NC_NOERR ) 01611 { 01612 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to locate four in file" ); 01613 } 01614 01615 if( nc_def_dim( ncFile, "time_step", 1, &dim_time ) != NC_NOERR ) 01616 { 01617 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to locate time step in file" ); 01618 } 01619 // some whole_time dummy :( 01620 int dtime; 01621 if( NC_NOERR != nc_def_var( ncFile, "time_whole", NC_DOUBLE, 1, &dim_time, &dtime ) ) 01622 { 01623 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define time whole array" ); 01624 } 01625 01626 /* Put file into define mode */ 01627 01628 // It is possible that an NT filename using backslashes is in the title string 01629 // this can give fits to unix codes where the backslash is assumed to be an escape 01630 // sequence. For the exodus file, just flip the backslash to a slash to prevent 01631 // this problem 01632 01633 // Get a working copy of the title_string; 01634 01635 char working_title[80]; 01636 strncpy( working_title, title_string, 79 ); 01637 01638 int length = strlen( working_title ); 01639 for( int pos = 0; pos < length; pos++ ) 01640 { 01641 if( working_title[pos] == '\\' ) working_title[pos] = '/'; 01642 } 01643 01644 if( NC_NOERR != nc_put_att_text( ncFile, NC_GLOBAL, "title", length, working_title ) ) 01645 { 01646 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define title attribute" ); 01647 } 01648 01649 // Add other attributes while we're at it 01650 float dum_vers = 6.28F; 01651 if( NC_NOERR != nc_put_att_float( ncFile, NC_GLOBAL, "api_version", NC_FLOAT, 1, &dum_vers ) ) 01652 { 01653 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define api_version attribute" ); 01654 } 01655 dum_vers = 6.28F; 01656 if( NC_NOERR != nc_put_att_float( ncFile, NC_GLOBAL, "version", NC_FLOAT, 1, &dum_vers ) ) 01657 { 01658 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define version attribute" ); 01659 } 01660 int dum_siz = sizeof( double ); 01661 if( NC_NOERR != nc_put_att_int( ncFile, NC_GLOBAL, "floating_point_word_size", NC_INT, 1, &dum_siz ) ) 01662 { 01663 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define floating pt word size attribute" ); 01664 } 01665 01666 // Set up number of dimensions 01667 01668 int num_el_blk, num_elem, num_nodes, num_dim, num_fa_blk, num_faces; 01669 if( nc_def_dim( ncFile, "num_dim", (size_t)mesh_info.num_dim, &num_dim ) != NC_NOERR ) 01670 { 01671 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of dimensions" ); 01672 } 01673 01674 if( nc_def_dim( ncFile, "num_nodes", mesh_info.num_nodes, &num_nodes ) != NC_NOERR ) 01675 { 01676 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of nodes" ); 01677 } 01678 01679 int num_nod_per_fa; // it is needed for polyhedron only; need to compute it (connectivity of 01680 // faces of polyhedra) 01681 if( mesh_info.polyhedronFaces.size() > 0 ) 01682 if( nc_def_dim( ncFile, "num_faces", (int)mesh_info.polyhedronFaces.size(), &num_faces ) != NC_NOERR ) 01683 { 01684 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of nodes" ); 01685 } 01686 01687 if( nc_def_dim( ncFile, "num_elem", mesh_info.num_elements, &num_elem ) != NC_NOERR ) 01688 { 01689 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of elements" ); 01690 } 01691 01692 if( nc_def_dim( ncFile, "num_el_blk", mesh_info.num_elementblocks, &num_el_blk ) != NC_NOERR ) 01693 { 01694 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of element blocks" ); 01695 } 01696 01697 /* ...and some variables */ 01698 01699 /* Element block id status array */ 01700 int idstat = -1; 01701 if( NC_NOERR != nc_def_var( ncFile, "eb_status", NC_LONG, 1, &num_el_blk, &idstat ) ) 01702 { 01703 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define element block status array" ); 01704 } 01705 01706 /* Element block id array */ 01707 01708 int idarr = -1; 01709 if( NC_NOERR != nc_def_var( ncFile, "eb_prop1", NC_LONG, 1, &num_el_blk, &idarr ) ) 01710 { 01711 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define element block id array" ); 01712 } 01713 01714 /* store property name as attribute of property array variable */ 01715 if( NC_NOERR != nc_put_att_text( ncFile, idarr, "name", strlen( "ID" ), "ID" ) ) 01716 { 01717 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store element block property name ID" ); 01718 } 01719 01720 // count how many are polyhedron blocks 01721 int num_fa_blocks = 0, num_polyh_blocks = 0; 01722 for( unsigned int i = 0; i < block_data.size(); i++ ) 01723 { 01724 MaterialSetData& block = block_data[i]; 01725 if( EXOII_POLYHEDRON == block.element_type ) 01726 { 01727 num_fa_blocks++; 01728 num_polyh_blocks++; 01729 } 01730 } 01731 if( 0 == this->repeat_face_blocks && num_fa_blocks > 1 ) num_fa_blocks = 1; 01732 char wname[80]; 01733 01734 if( num_fa_blocks > 0 ) 01735 { 01736 /* face block id status array */ 01737 if( nc_def_dim( ncFile, "num_fa_blk", num_fa_blocks, &num_fa_blk ) != NC_NOERR ) 01738 { 01739 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of face blocks" ); 01740 } 01741 01742 int idstatf = -1; 01743 if( NC_NOERR != nc_def_var( ncFile, "fa_status", NC_LONG, 1, &num_fa_blk, &idstatf ) ) 01744 { 01745 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define face block status array" ); 01746 } 01747 01748 /* Element block id array */ 01749 01750 int idarrf = -1; 01751 if( NC_NOERR != nc_def_var( ncFile, "fa_prop1", NC_LONG, 1, &num_fa_blk, &idarrf ) ) 01752 { 01753 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define face block id array" ); 01754 } 01755 01756 /* store property name as attribute of property array variable */ 01757 if( NC_NOERR != nc_put_att_text( ncFile, idarrf, "name", strlen( "ID" ), "ID" ) ) 01758 { 01759 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store face block property name ID" ); 01760 } 01761 // determine the number of num_nod_per_face 01762 /* 01763 num_fa_in_blk1 = 15 ; 01764 num_nod_per_fa1 = 58 ; 01765 01766 int fbconn1(num_nod_per_fa1) ; 01767 fbconn1:elem_type = "nsided" ; 01768 int fbepecnt1(num_fa_in_blk1) ; 01769 fbepecnt1:entity_type1 = "NODE" ; 01770 fbepecnt1:entity_type2 = "FACE" ; 01771 */ 01772 01773 int num_nodes_per_face = 0; 01774 01775 int dims[1]; // maybe 1 is enough here 01776 for( Range::iterator eit = mesh_info.polyhedronFaces.begin(); eit != mesh_info.polyhedronFaces.end(); eit++ ) 01777 { 01778 EntityHandle polyg = *eit; 01779 int nnodes = 0; 01780 const EntityHandle* conn = NULL; 01781 ErrorCode rval = mdbImpl->get_connectivity( polyg, conn, nnodes );MB_CHK_ERR( rval ); 01782 num_nodes_per_face += nnodes; 01783 } 01784 01785 // duplicate if needed; default is not duplicate 01786 for( int j = 1; j <= num_fa_blocks; j++ ) 01787 { 01788 INS_ID( wname, "num_nod_per_fa%d", j ); 01789 if( nc_def_dim( ncFile, wname, (size_t)num_nodes_per_face, &num_nod_per_fa ) != NC_NOERR ) 01790 { 01791 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of nodes for face block " ); 01792 } 01793 dims[0] = num_nod_per_fa; 01794 INS_ID( wname, "fbconn%d", j ); // first one, or more 01795 int fbconn; 01796 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, dims, &fbconn ) ) 01797 { 01798 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create connectivity array for face block " << 1 ); 01799 } 01800 std::string element_type_string( "nsided" ); 01801 if( NC_NOERR != nc_put_att_text( ncFile, fbconn, "elem_type", element_type_string.length(), 01802 element_type_string.c_str() ) ) 01803 { 01804 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store element type nsided " ); 01805 } 01806 01807 INS_ID( wname, "num_fa_in_blk%d", j ); // first one, or more 01808 int num_fa_in_blk; 01809 if( nc_def_dim( ncFile, wname, (size_t)mesh_info.polyhedronFaces.size(), &num_fa_in_blk ) != NC_NOERR ) 01810 { 01811 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of nodes for face block " ); 01812 } 01813 01814 // fbepecnt 01815 INS_ID( wname, "fbepecnt%d", j ); // first one, or more 01816 int fbepecnt; 01817 dims[0] = num_fa_in_blk; 01818 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, dims, &fbepecnt ) ) 01819 { 01820 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create fbepecnt array for block " << 1 ); 01821 } 01822 std::string enttype1( "NODE" ); 01823 if( NC_NOERR != nc_put_att_text( ncFile, fbepecnt, "entity_type1", enttype1.length(), enttype1.c_str() ) ) 01824 { 01825 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store entity type 1 " ); 01826 } 01827 std::string enttype2( "FACE" ); 01828 if( NC_NOERR != nc_put_att_text( ncFile, fbepecnt, "entity_type2", enttype2.length(), enttype2.c_str() ) ) 01829 { 01830 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store entity type 2 " ); 01831 } 01832 } 01833 } 01834 01835 // Define element blocks 01836 01837 for( unsigned int i = 0; i < block_data.size(); i++ ) 01838 { 01839 MaterialSetData& block = block_data[i]; 01840 01841 element_block_index = i + 1; 01842 int num_el_in_blk = -1, num_att_in_blk = -1; 01843 int blk_attrib, connect; 01844 01845 /* Define number of elements in this block */ 01846 01847 INS_ID( wname, "num_el_in_blk%d", element_block_index ); 01848 if( nc_def_dim( ncFile, wname, (size_t)block.number_elements, &num_el_in_blk ) != NC_NOERR ) 01849 { 01850 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of elements/block for block " << i + 1 ); 01851 } 01852 01853 /* Define number of nodes per element for this block */ 01854 INS_ID( wname, "num_nod_per_el%d", element_block_index ); 01855 int num_nod_per_el = -1; 01856 if( EXOII_POLYHEDRON != block.element_type ) 01857 if( nc_def_dim( ncFile, wname, (size_t)block.number_nodes_per_element, &num_nod_per_el ) != NC_NOERR ) 01858 { 01859 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of nodes/element for block " << block.id ); 01860 } 01861 01862 /* Define element attribute array for this block */ 01863 int dims[3]; 01864 if( block.number_attributes > 0 ) 01865 { 01866 INS_ID( wname, "num_att_in_blk%d", element_block_index ); 01867 if( nc_def_dim( ncFile, wname, (size_t)block.number_attributes, &num_att_in_blk ) != NC_NOERR ) 01868 { 01869 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of attributes in block " << block.id ); 01870 } 01871 01872 INS_ID( wname, "attrib%d", element_block_index ); 01873 dims[0] = num_el_in_blk; 01874 dims[1] = num_att_in_blk; 01875 if( NC_NOERR != nc_def_var( ncFile, wname, NC_DOUBLE, 2, dims, &blk_attrib ) ) 01876 { 01877 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define attributes for element block " << block.id ); 01878 } 01879 } 01880 01881 /* Define element connectivity array for this block */ 01882 01883 if( EXOII_POLYGON != block.element_type && EXOII_POLYHEDRON != block.element_type ) 01884 { 01885 INS_ID( wname, "connect%d", element_block_index ); 01886 dims[0] = num_el_in_blk; 01887 dims[1] = num_nod_per_el; 01888 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 2, dims, &connect ) ) 01889 { 01890 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create connectivity array for block " << i + 1 ); 01891 } 01892 01893 /* Store element type as attribute of connectivity variable */ 01894 01895 std::string element_type_string( ExoIIUtil::ElementTypeNames[block.element_type] ); 01896 if( NC_NOERR != nc_put_att_text( ncFile, connect, "elem_type", element_type_string.length(), 01897 element_type_string.c_str() ) ) 01898 { 01899 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store element type name " << (int)block.element_type ); 01900 } 01901 } 01902 else if( EXOII_POLYGON == block.element_type ) 01903 { 01904 INS_ID( wname, "connect%d", element_block_index ); 01905 // need to define num_nod_per_el as total number of nodes 01906 // ebepecnt1 as number of nodes per polygon 01907 /* 01908 * int connect1(num_nod_per_el1) ; 01909 connect1:elem_type = "nsided" ; 01910 int ebepecnt1(num_el_in_blk1) ; 01911 ebepecnt1:entity_type1 = "NODE" ; 01912 ebepecnt1:entity_type2 = "ELEM" ;*/ 01913 dims[0] = num_nod_per_el; 01914 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, dims, &connect ) ) 01915 { 01916 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create connectivity array for block " << i + 1 ); 01917 } 01918 std::string element_type_string( "nsided" ); 01919 if( NC_NOERR != nc_put_att_text( ncFile, connect, "elem_type", element_type_string.length(), 01920 element_type_string.c_str() ) ) 01921 { 01922 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store element type name " << (int)block.element_type ); 01923 } 01924 INS_ID( wname, "ebepecnt%d", element_block_index ); 01925 int ebepecnt; 01926 dims[0] = num_el_in_blk; 01927 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, dims, &ebepecnt ) ) 01928 { 01929 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create ebepecnt array for block " << i + 1 ); 01930 } 01931 std::string etype1( "NODE" ); 01932 if( NC_NOERR != nc_put_att_text( ncFile, ebepecnt, "entity_type1", etype1.length(), etype1.c_str() ) ) 01933 { 01934 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store entity type1 " << (int)block.element_type ); 01935 } 01936 std::string etype2( "ELEM" ); 01937 if( NC_NOERR != nc_put_att_text( ncFile, ebepecnt, "entity_type2", etype2.length(), etype2.c_str() ) ) 01938 { 01939 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store entity type2 " << (int)block.element_type ); 01940 } 01941 } 01942 else if( EXOII_POLYHEDRON == block.element_type ) 01943 { 01944 // INS_ID(wname, "connect%d", element_block_index); 01945 /* 01946 testn face example: 3 polyh, 15 total faces, 2 shared; 15+2 = 17 01947 num_elem = 3 ; 01948 num_face = 15 ; // not needed? 01949 num_el_blk = 1 ; 01950 01951 num_el_in_blk1 = 3 ; 01952 num_fac_per_el1 = 17 ; 01953 01954 * num faces will be total face conn 01955 * num_faces_in_block will be number of faces (non repeated) 01956 * num_nodes_per_face will have total face connectivity 01957 */ 01958 int num_faces2 = 0; 01959 01960 for( Range::iterator eit = block.elements.begin(); eit != block.elements.end(); eit++ ) 01961 { 01962 EntityHandle polyh = *eit; 01963 int nfaces = 0; 01964 const EntityHandle* conn = NULL; 01965 ErrorCode rval = mdbImpl->get_connectivity( polyh, conn, nfaces );MB_CHK_ERR( rval ); 01966 num_faces2 += nfaces; 01967 } 01968 01969 int num_fac_per_el; 01970 01971 INS_ID( wname, "num_fac_per_el%d", element_block_index ); 01972 if( nc_def_dim( ncFile, wname, (size_t)num_faces2, &num_fac_per_el ) != NC_NOERR ) 01973 { 01974 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of faces per block " << block.id ); 01975 } 01976 01977 /* 01978 int facconn1(num_fac_per_el1) ; 01979 facconn1:elem_type = "NFACED" ; 01980 int ebepecnt1(num_el_in_blk1) ; 01981 ebepecnt1:entity_type1 = "FACE" ; 01982 ebepecnt1:entity_type2 = "ELEM" ; 01983 */ 01984 01985 // facconn 01986 INS_ID( wname, "facconn%d", element_block_index ); 01987 int facconn; 01988 dims[0] = num_fac_per_el; 01989 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, dims, &facconn ) ) 01990 { 01991 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create facconn array for block " << i + 1 ); 01992 } 01993 std::string etype( "NFACED" ); 01994 if( NC_NOERR != nc_put_att_text( ncFile, facconn, "elem_type", etype.length(), etype.c_str() ) ) 01995 { 01996 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store elem type " << (int)block.element_type ); 01997 } 01998 01999 // ebepecnt 02000 INS_ID( wname, "ebepecnt%d", element_block_index ); 02001 int ebepecnt; 02002 dims[0] = num_el_in_blk; 02003 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, dims, &ebepecnt ) ) 02004 { 02005 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create ebepecnt array for block " << i + 1 ); 02006 } 02007 std::string etype1( "FACE" ); 02008 if( NC_NOERR != nc_put_att_text( ncFile, ebepecnt, "entity_type1", etype1.length(), etype1.c_str() ) ) 02009 { 02010 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store entity type1 " << (int)block.element_type ); 02011 } 02012 std::string etype2( "ELEM" ); 02013 if( NC_NOERR != nc_put_att_text( ncFile, ebepecnt, "entity_type2", etype2.length(), etype2.c_str() ) ) 02014 { 02015 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store entity type2 " << (int)block.element_type ); 02016 } 02017 02018 block.number_nodes_per_element = num_faces2; // connectivity for all polyhedra in block 02019 } 02020 } 02021 02022 /* Node set id array: */ 02023 02024 int non_empty_nss = 0; 02025 // Need to go through nodesets to compute # nodesets, some might be empty 02026 std::vector< DirichletSetData >::iterator ns_it; 02027 for( ns_it = nodeset_data.begin(); ns_it != nodeset_data.end(); ++ns_it ) 02028 { 02029 if( 0 != ( *ns_it ).number_nodes ) non_empty_nss++; 02030 } 02031 02032 int num_ns = -1; 02033 int ns_idstat = -1, ns_idarr = -1; 02034 if( non_empty_nss > 0 ) 02035 { 02036 if( nc_def_dim( ncFile, "num_node_sets", (size_t)( non_empty_nss ), &num_ns ) != NC_NOERR ) 02037 { 02038 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of node sets" ); 02039 } 02040 02041 /* Node set id status array: */ 02042 02043 if( NC_NOERR != nc_def_var( ncFile, "ns_status", NC_LONG, 1, &num_ns, &ns_idstat ) ) 02044 { 02045 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create node sets status array" ); 02046 } 02047 02048 /* Node set id array: */ 02049 if( NC_NOERR != nc_def_var( ncFile, "ns_prop1", NC_LONG, 1, &num_ns, &ns_idarr ) ) 02050 { 02051 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create node sets property array" ); 02052 } 02053 02054 /* Store property name as attribute of property array variable */ 02055 if( NC_NOERR != nc_put_att_text( ncFile, NC_GLOBAL, "name", strlen( "ID" ), "ID" ) ) 02056 { 02057 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store node set property name ID" ); 02058 } 02059 02060 // Now, define the arrays needed for each node set 02061 02062 int index = 0; 02063 02064 for( unsigned i = 0; i < nodeset_data.size(); i++ ) 02065 { 02066 DirichletSetData node_set = nodeset_data[i]; 02067 02068 if( 0 == node_set.number_nodes ) 02069 { 02070 MB_SET_ERR_CONT( "WriteNCDF: empty nodeset " << node_set.id ); 02071 continue; 02072 } 02073 index++; 02074 02075 int num_nod_ns = -1; 02076 INS_ID( wname, "num_nod_ns%d", index ); 02077 if( nc_def_dim( ncFile, wname, (size_t)node_set.number_nodes, &num_nod_ns ) != NC_NOERR ) 02078 { 02079 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of nodes for set " << node_set.id ); 02080 } 02081 02082 /* Create variable array in which to store the node set node list */ 02083 int node_ns = -1; 02084 INS_ID( wname, "node_ns%d", index ); 02085 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, &num_nod_ns, &node_ns ) ) 02086 { 02087 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create node set " << node_set.id << " node list" ); 02088 } 02089 02090 // Create distribution factor array 02091 int fact_ns = -1; 02092 INS_ID( wname, "dist_fact_ns%d", index ); 02093 if( NC_NOERR != nc_def_var( ncFile, wname, NC_DOUBLE, 1, &num_nod_ns, &fact_ns ) ) 02094 { 02095 MB_SET_ERR( MB_FAILURE, 02096 "WriteNCDF: failed to create node set " << node_set.id << " distribution factor list" ); 02097 } 02098 } 02099 } 02100 02101 /* Side set id array: */ 02102 02103 long non_empty_ss = 0; 02104 // Need to go through nodesets to compute # nodesets, some might be empty 02105 std::vector< NeumannSetData >::iterator ss_it; 02106 for( ss_it = sideset_data.begin(); ss_it != sideset_data.end(); ++ss_it ) 02107 { 02108 if( 0 != ( *ss_it ).number_elements ) non_empty_ss++; 02109 } 02110 02111 if( non_empty_ss > 0 ) 02112 { 02113 int num_ss = -1; 02114 if( nc_def_dim( ncFile, "num_side_sets", non_empty_ss, &num_ss ) != NC_NOERR ) 02115 { 02116 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of side sets" ); 02117 } 02118 02119 /* Side set id status array: */ 02120 int ss_idstat = -1, ss_idarr = -1; 02121 if( NC_NOERR != nc_def_var( ncFile, "ss_status", NC_LONG, 1, &num_ss, &ss_idstat ) ) 02122 { 02123 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define side set status" ); 02124 } 02125 02126 /* Side set id array: */ 02127 if( NC_NOERR != nc_def_var( ncFile, "ss_prop1", NC_LONG, 1, &num_ss, &ss_idarr ) ) 02128 { 02129 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define side set property" ); 02130 } 02131 02132 /* Store property name as attribute of property array variable */ 02133 if( NC_NOERR != nc_put_att_text( ncFile, ss_idarr, "name", strlen( "ID" ), "ID" ) ) 02134 { 02135 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to store side set property name ID" ); 02136 } 02137 02138 // Now, define the arrays needed for each side set 02139 02140 int index = 0; 02141 for( unsigned int i = 0; i < sideset_data.size(); i++ ) 02142 { 02143 NeumannSetData side_set = sideset_data[i]; 02144 02145 // Don't define an empty set 02146 if( 0 == side_set.number_elements ) continue; 02147 02148 index++; 02149 02150 int num_side_ss = -1; 02151 int elem_ss = -1, side_ss = -1; 02152 INS_ID( wname, "num_side_ss%d", index ); 02153 if( nc_def_dim( ncFile, wname, (size_t)side_set.number_elements, &num_side_ss ) != NC_NOERR ) 02154 { 02155 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of sides in side set " << side_set.id ); 02156 } 02157 02158 INS_ID( wname, "elem_ss%d", index ); 02159 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, &num_side_ss, &elem_ss ) ) 02160 { 02161 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create element list for side set " 02162 << side_set.id ); /* Exit define mode and return */ 02163 } 02164 INS_ID( wname, "side_ss%d", index ); 02165 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, &num_side_ss, &side_ss ) ) 02166 { 02167 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create side list for side set " 02168 << side_set.id ); /* Exit define mode and return */ 02169 } 02170 02171 // sideset distribution factors 02172 int num_df_ss = -1; 02173 INS_ID( wname, "num_df_ss%d", index ); 02174 if( nc_def_dim( ncFile, wname, (size_t)side_set.ss_dist_factors.size(), &num_df_ss ) != NC_NOERR ) 02175 { 02176 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define number of dist factors in side set " 02177 << side_set.id ); /* Exit define mode and return */ 02178 } 02179 02180 /* Create variable array in which to store the side set distribution factors */ 02181 02182 int fact_ss = -1; 02183 INS_ID( wname, "dist_fact_ss%d", index ); 02184 if( NC_NOERR != nc_def_var( ncFile, wname, NC_LONG, 1, &num_df_ss, &fact_ss ) ) 02185 { 02186 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create dist factors list for side set " 02187 << side_set.id ); /* Exit define mode and return */ 02188 } 02189 } 02190 } 02191 02192 /* Node coordinate arrays: */ 02193 02194 int coord, name_coord, dims[3]; 02195 dims[0] = num_dim; 02196 dims[1] = num_nodes; 02197 if( NC_NOERR != nc_def_var( ncFile, "coord", NC_DOUBLE, 2, dims, &coord ) ) 02198 { 02199 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define node coordinate array" ); 02200 } 02201 02202 /* Coordinate names array */ 02203 02204 dims[0] = num_dim; 02205 dims[1] = dim_str; 02206 if( NC_NOERR != nc_def_var( ncFile, "coor_names", NC_CHAR, 2, dims, &name_coord ) ) 02207 { 02208 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define coordinate name array" ); 02209 } 02210 02211 // Define genesis maps if required 02212 02213 if( write_maps ) 02214 { 02215 // Element map 02216 int elem_map = -1, elem_map2 = -1, node_map = -1; 02217 if( NC_NOERR != nc_def_var( ncFile, "elem_map", NC_LONG, 1, &num_elem, &elem_map ) ) 02218 { 02219 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create element map array" ); /* Exit define mode and return */ 02220 } 02221 02222 // Create the element number map 02223 if( NC_NOERR != nc_def_var( ncFile, "elem_num_map", NC_LONG, 1, &num_elem, &elem_map2 ) ) 02224 { 02225 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create element numbering map" ); /* Exit define mode 02226 and return */ 02227 } 02228 02229 // Create node number map 02230 if( NC_NOERR != nc_def_var( ncFile, "node_num_map", NC_LONG, 1, &num_nodes, &node_map ) ) 02231 { 02232 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to create node numbering map array" ); /* Exit define mode and 02233 return */ 02234 } 02235 } 02236 02237 // Define qa records to be used 02238 02239 int num_qa_rec = mesh_info.qaRecords.size() / 4; 02240 int num_qa = -1; 02241 02242 if( nc_def_dim( ncFile, "num_qa_rec", (long)num_qa_rec, &num_qa ) != NC_NOERR ) 02243 { 02244 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define qa record array size" ); 02245 } 02246 02247 // Define qa array 02248 int qa_title; 02249 dims[0] = num_qa; 02250 dims[1] = dim_four; 02251 dims[2] = dim_str; 02252 if( NC_NOERR != nc_def_var( ncFile, "qa_records", NC_CHAR, 3, dims, &qa_title ) ) 02253 { 02254 MB_SET_ERR( MB_FAILURE, "WriteNCDF: failed to define qa record array" ); 02255 } 02256 02257 // Take it out of define mode 02258 if( NC_NOERR != nc_enddef( ncFile ) ) 02259 { 02260 MB_SET_ERR( MB_FAILURE, "WriteNCDF: Trouble leaving define mode" ); 02261 } 02262 02263 return MB_SUCCESS; 02264 } 02265 02266 ErrorCode WriteNCDF::open_file( const char* filename ) 02267 { 02268 // Not a valid filename 02269 if( strlen( (const char*)filename ) == 0 ) 02270 { 02271 MB_SET_ERR( MB_FAILURE, "Output Exodus filename not specified" ); 02272 } 02273 02274 int fail = nc_create( filename, NC_CLOBBER, &ncFile ); 02275 02276 // File couldn't be opened 02277 if( NC_NOERR != fail ) 02278 { 02279 MB_SET_ERR( MB_FAILURE, "Cannot open " << filename ); 02280 } 02281 02282 return MB_SUCCESS; 02283 } 02284 02285 ErrorCode WriteNCDF::get_sideset_elems( EntityHandle sideset, 02286 int current_sense, 02287 Range& forward_elems, 02288 Range& reverse_elems ) 02289 { 02290 Range ss_elems, ss_meshsets; 02291 02292 // Get the sense tag; don't need to check return, might be an error if the tag 02293 // hasn't been created yet 02294 Tag sense_tag = 0; 02295 mdbImpl->tag_get_handle( "SENSE", 1, MB_TYPE_INTEGER, sense_tag ); 02296 02297 // Get the entities in this set 02298 ErrorCode result = mdbImpl->get_entities_by_handle( sideset, ss_elems, true ); 02299 if( MB_FAILURE == result ) return result; 02300 02301 // Now remove the meshsets into the ss_meshsets; first find the first meshset, 02302 Range::iterator range_iter = ss_elems.begin(); 02303 while( TYPE_FROM_HANDLE( *range_iter ) != MBENTITYSET && range_iter != ss_elems.end() ) 02304 ++range_iter; 02305 02306 // Then, if there are some, copy them into ss_meshsets and erase from ss_elems 02307 if( range_iter != ss_elems.end() ) 02308 { 02309 std::copy( range_iter, ss_elems.end(), range_inserter( ss_meshsets ) ); 02310 ss_elems.erase( range_iter, ss_elems.end() ); 02311 } 02312 02313 // OK, for the elements, check the sense of this set and copy into the right range 02314 // (if the sense is 0, copy into both ranges) 02315 02316 // Need to step forward on list until we reach the right dimension 02317 Range::iterator dum_it = ss_elems.end(); 02318 --dum_it; 02319 int target_dim = CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) ); 02320 dum_it = ss_elems.begin(); 02321 while( target_dim != CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) ) && dum_it != ss_elems.end() ) 02322 ++dum_it; 02323 02324 if( current_sense == 1 || current_sense == 0 ) std::copy( dum_it, ss_elems.end(), range_inserter( forward_elems ) ); 02325 if( current_sense == -1 || current_sense == 0 ) 02326 std::copy( dum_it, ss_elems.end(), range_inserter( reverse_elems ) ); 02327 02328 // Now loop over the contained meshsets, getting the sense of those and calling this 02329 // function recursively 02330 for( range_iter = ss_meshsets.begin(); range_iter != ss_meshsets.end(); ++range_iter ) 02331 { 02332 // First get the sense; if it's not there, by convention it's forward 02333 int this_sense; 02334 if( 0 == sense_tag || MB_FAILURE == mdbImpl->tag_get_data( sense_tag, &( *range_iter ), 1, &this_sense ) ) 02335 this_sense = 1; 02336 02337 // Now get all the entities on this meshset, with the proper (possibly reversed) sense 02338 get_sideset_elems( *range_iter, this_sense * current_sense, forward_elems, reverse_elems ); 02339 } 02340 02341 return result; 02342 } 02343 02344 } // namespace moab