![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
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
00028 #include
00029 #include
00030 #include
00031 #include
00032 #include
00033 #include
00034 #include
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