Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
WriteCCMIO.cpp
Go to the documentation of this file.
1 /*
2  * CCMIO file structure
3  *
4  * Root
5  * State(kCCMIOState)
6  * Processor*
7  * VerticesID
8  * TopologyID
9  * InitialID
10  * SolutionID
11  * Vertices*
12  * ->WriteVerticesx, WriteMap
13  * Topology*
14  * Boundary faces*(kCCMIOBoundaryFaces)
15  * ->WriteFaces, WriteFaceCells, WriteMap
16  * Internal faces(kCCMIOInternalFaces)
17  * Cells (kCCMIOCells)
18  * ->WriteCells (mapID), WriteMap, WriteCells
19  * Solution
20  * Phase
21  * Field
22  * FieldData
23  * Problem(kCCMIOProblemDescription)
24  * CellType* (kCCMIOCellType)
25  * Index (GetEntityIndex), MaterialId(WriteOpti), MaterialType(WriteOptstr),
26  * PorosityId(WriteOpti), SpinId(WriteOpti), GroupId(WriteOpti)
27  *
28  * MaterialType (CCMIOWriteOptstr in readexample)
29  * constants (see readexample)
30  * lagrangian data (CCMIOWriteLagrangianData)
31  * vertices label (CCMIOEntityDescription)
32  * restart info: char solver[], iterations, time, char timeUnits[], angle
33  * (CCMIOWriteRestartInfo, kCCMIORestartData), reference data?
34  * phase:
35  * field: char name[], dims, CCMIODataType datatype, char units[]
36  * dims = kCCMIOScalar (CCMIOWriteFieldDataf),
37  * kCCMIOVector (CCMIOWriteMultiDimensionalFieldData),
38  * kCCMIOTensor
39  * MonitoringSets: num, name (CellSet, VertexSet, BoundarySet, BlockSet, SplineSet, CoupleSet)
40  * CCMIOGetProstarSet, CCMIOWriteOpt1i,
41  */
42 
43 #ifdef WIN32
44 #ifdef _DEBUG
45 // turn off warnings that say they debugging identifier has been truncated
46 // this warning comes up when using some STL containers
47 #pragma warning( disable : 4786 )
48 #endif
49 #endif
50 
51 #include "WriteCCMIO.hpp"
52 #include "ccmio.h"
53 #include "ccmioutility.h"
54 #include "ccmiocore.h"
55 #include <utility>
56 #include <algorithm>
57 #include <ctime>
58 #include <string>
59 #include <vector>
60 #include <cstdio>
61 #include <iostream>
62 #include <algorithm>
63 #include <sstream>
64 
65 #include "moab/Interface.hpp"
66 #include "moab/Range.hpp"
67 #include "moab/CN.hpp"
68 #include "moab/Skinner.hpp"
69 #include <cassert>
70 #include "Internals.hpp"
71 #include "ExoIIUtil.hpp"
72 #include "MBTagConventions.hpp"
73 #ifdef MOAB_HAVE_MPI
74 #include "MBParallelConventions.h"
75 #endif
76 #include "moab/WriteUtilIface.hpp"
77 
78 namespace moab
79 {
80 
81 static char const kStateName[] = "default";
82 
83 /*
84  static const int ccm_types[] = {
85  1, // MBVERTEX
86  2, // MBEDGE
87  -1, // MBTRI
88  -1, // MBQUAD
89  -1, // MBPOLYGON
90  13, // MBTET
91  14, // MBPYRAMID
92  12, // MBPRISM
93  -1, // MBKNIFE
94  11, // MBHEX
95  255 // MBPOLYHEDRON
96  };
97 */
98 
99 #define INS_ID( stringvar, prefix, id ) sprintf( stringvar, prefix, id )
100 
101 #define CHK_SET_CCMERR( ccm_err_code, ccm_err_msg ) \
102  { \
103  if( kCCMIONoErr != ( ccm_err_code ) ) MB_SET_ERR( MB_FAILURE, ccm_err_msg ); \
104  }
105 
107 {
108  return new WriteCCMIO( iface );
109 }
110 
112  : mbImpl( impl ), mCurrentMeshHandle( 0 ), mPartitionSetTag( 0 ), mNameTag( 0 ), mMaterialIdTag( 0 ),
113  mMaterialTypeTag( 0 ), mRadiationTag( 0 ), mPorosityIdTag( 0 ), mSpinIdTag( 0 ), mGroupIdTag( 0 ),
114  mColorIdxTag( 0 ), mProcessorIdTag( 0 ), mLightMaterialTag( 0 ), mFreeSurfaceMaterialTag( 0 ), mThicknessTag( 0 ),
115  mProstarRegionNumberTag( 0 ), mBoundaryTypeTag( 0 ), mCreatingProgramTag( 0 ), mDimension( 0 ),
116  mWholeMesh( false )
117 {
118  assert( impl != NULL );
119 
120  impl->query_interface( mWriteIface );
121 
122  // Initialize in case tag_get_handle fails below
123  //! Get and cache predefined tag handles
124  int negone = -1;
126  &negone );
127 
129  &negone );
130 
132  &negone );
133 
134  mGlobalIdTag = impl->globalId_tag();
135 
136 #ifdef MOAB_HAVE_MPI
138  // No need to check result, if it's not there, we don't create one
139 #endif
140 
141  int dum_val_array[] = { -1, -1, -1, -1 };
143  dum_val_array );
144 
145  impl->tag_get_handle( "__WriteCCMIO element mark", 1, MB_TYPE_BIT, mEntityMark, MB_TAG_CREAT );
146 
147  // Don't need to check return of following, since it doesn't matter if there isn't one
149 }
150 
152 {
155 }
156 
157 ErrorCode WriteCCMIO::write_file( const char* file_name,
158  const bool overwrite,
159  const FileOptions&,
160  const EntityHandle* ent_handles,
161  const int num_sets,
162  const std::vector< std::string >& /* qa_list */,
163  const Tag* /* tag_list */,
164  int /* num_tags */,
165  int /* export_dimension */ )
166 {
167  assert( 0 != mMaterialSetTag && 0 != mNeumannSetTag && 0 != mDirichletSetTag );
168 
169  ErrorCode result;
170 
171  // Check overwrite flag and file existence
172  if( !overwrite )
173  {
174  FILE* file = fopen( file_name, "r" );
175  if( file )
176  {
177  fclose( file );
178  MB_SET_ERR( MB_FILE_WRITE_ERROR, "File exists but overwrite set to false" );
179  }
180  }
181 
182  mDimension = 3;
183 
184  std::vector< EntityHandle > matsets, dirsets, neusets, partsets;
185 
186  // Separate into material, dirichlet, neumann, partition sets
187  result = get_sets( ent_handles, num_sets, matsets, dirsets, neusets, partsets );MB_CHK_SET_ERR( result, "Failed to get material/etc. sets" );
188 
189  // If entity handles were input but didn't contain matsets, return error
190  if( ent_handles && matsets.empty() )
191  {
192  MB_SET_ERR( MB_FILE_WRITE_ERROR, "Sets input to write but no material sets found" );
193  }
194 
195  // Otherwise, if no matsets, use root set
196  if( matsets.empty() ) matsets.push_back( 0 );
197 
198  std::vector< MaterialSetData > matset_info;
199  Range all_verts;
200  result = gather_matset_info( matsets, matset_info, all_verts );MB_CHK_SET_ERR( result, "gathering matset info failed" );
201 
202  // Assign vertex gids
203  result = mWriteIface->assign_ids( all_verts, mGlobalIdTag, 1 );MB_CHK_SET_ERR( result, "Failed to assign vertex global ids" );
204 
205  // Some CCMIO descriptors
206  CCMIOID rootID, topologyID, stateID, problemID, verticesID, processorID;
207 
208  // Try to open the file and establish state
209  result = open_file( file_name, overwrite, rootID );MB_CHK_SET_ERR( result, "Couldn't open file or create state" );
210 
211  result = create_ccmio_structure( rootID, stateID, processorID );MB_CHK_SET_ERR( result, "Problem creating CCMIO file structure" );
212 
213  result = write_nodes( rootID, all_verts, mDimension, verticesID );MB_CHK_SET_ERR( result, "write_nodes failed" );
214 
215  std::vector< NeumannSetData > neuset_info;
216  result = gather_neuset_info( neusets, neuset_info );MB_CHK_SET_ERR( result, "Failed to get neumann set info" );
217 
218  result = write_cells_and_faces( rootID, matset_info, neuset_info, all_verts, topologyID );MB_CHK_SET_ERR( result, "write_cells_and_faces failed" );
219 
220  result = write_problem_description( rootID, stateID, problemID, processorID, matset_info, neuset_info );MB_CHK_SET_ERR( result, "write_problem_description failed" );
221 
222  result = write_solution_data();MB_CHK_SET_ERR( result, "Trouble writing solution data" );
223 
224  result = write_processor( processorID, verticesID, topologyID );MB_CHK_SET_ERR( result, "Trouble writing processor" );
225 
226  result = close_and_compress( file_name, rootID );MB_CHK_SET_ERR( result, "Close or compress failed" );
227 
228  return MB_SUCCESS;
229 }
230 
232 {
233  // For now, no solution (tag) data
234  return MB_SUCCESS;
235 }
236 
237 ErrorCode WriteCCMIO::write_processor( CCMIOID processorID, CCMIOID verticesID, CCMIOID topologyID )
238 {
239  CCMIOError error = kCCMIONoErr;
240 
241  // Now we have the mesh (vertices and topology) and the post data written.
242  // Since we now have their IDs, we can write out the processor information.
243  CCMIOWriteProcessor( &error, processorID, NULL, &verticesID, NULL, &topologyID, NULL, NULL, NULL, NULL );
244  CHK_SET_CCMERR( error, "Problem writing CCMIO processor" );
245 
246  return MB_SUCCESS;
247 }
248 
249 ErrorCode WriteCCMIO::create_ccmio_structure( CCMIOID rootID, CCMIOID& stateID, CCMIOID& processorID )
250 {
251  // Create problem state and other CCMIO nodes under it
252  CCMIOError error = kCCMIONoErr;
253 
254  // Create a new state (or re-use an existing one).
255  if( CCMIOGetState( NULL, rootID, kStateName, NULL, &stateID ) != kCCMIONoErr )
256  {
257  CCMIONewState( &error, rootID, kStateName, NULL, NULL, &stateID );
258  CHK_SET_CCMERR( error, "Trouble creating state" );
259  }
260 
261  // Create or get an old processor for this state
262  CCMIOSize_t i = CCMIOSIZEC( 0 );
263  if( CCMIONextEntity( NULL, stateID, kCCMIOProcessor, &i, &processorID ) != kCCMIONoErr )
264  {
265  CCMIONewEntity( &error, stateID, kCCMIOProcessor, NULL, &processorID );
266  CHK_SET_CCMERR( error, "Trouble creating processor node" );
267  }
268  // Get rid of any data that may be in this processor (if the state was
269  // not new).
270  else
271  {
272  CCMIOClearProcessor( &error, stateID, processorID, TRUE, TRUE, TRUE, TRUE, TRUE );
273  CHK_SET_CCMERR( error, "Trouble clearing processor data" );
274  }
275 
276  /*
277  // for (; i < CCMIOSIZEC(partsets.size()); i++) {
278  CCMIOSize_t id = CCMIOSIZEC(0);
279  if (CCMIONextEntity(NULL, stateID, kCCMIOProcessor, &id, &processorID) != kCCMIONoErr)
280  CCMIONewEntity(&error, stateID, kCCMIOProcessor, NULL, &processorID);
281  CHKCCMERR(error, "Trouble creating processor node.");
282  */
283  return MB_SUCCESS;
284 }
285 
286 ErrorCode WriteCCMIO::close_and_compress( const char*, CCMIOID rootID )
287 {
288  CCMIOError error = kCCMIONoErr;
289  CCMIOCloseFile( &error, rootID );
290  CHK_SET_CCMERR( error, "File close failed" );
291 
292  // The CCMIO library uses ADF to store the actual data. Unfortunately,
293  // ADF leaks disk space; deleting a node does not recover all the disk
294  // space. Now that everything is successfully written it might be useful
295  // to call CCMIOCompress() here to ensure that the file is as small as
296  // possible. Please see the Core API documentation for caveats on its
297  // usage.
298  // CCMIOCompress(&error, const_cast<char*>(filename));CHK_SET_CCMERR(error, "Error compressing
299  // file");
300 
301  return MB_SUCCESS;
302 }
303 
304 ErrorCode WriteCCMIO::open_file( const char* filename, bool, CCMIOID& rootID )
305 {
306  CCMIOError error = kCCMIONoErr;
307  CCMIOOpenFile( &error, filename, kCCMIOWrite, &rootID );
308  CHK_SET_CCMERR( error, "Cannot open file" );
309 
310  return MB_SUCCESS;
311 }
312 
314  int num_sets,
315  std::vector< EntityHandle >& matsets,
316  std::vector< EntityHandle >& dirsets,
317  std::vector< EntityHandle >& neusets,
318  std::vector< EntityHandle >& partsets )
319 {
320  if( num_sets == 0 )
321  {
322  // Default to all defined sets
323  Range this_range;
324  mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mMaterialSetTag, NULL, 1, this_range );
325  std::copy( this_range.begin(), this_range.end(), std::back_inserter( matsets ) );
326  this_range.clear();
327  mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mDirichletSetTag, NULL, 1, this_range );
328  std::copy( this_range.begin(), this_range.end(), std::back_inserter( dirsets ) );
329  this_range.clear();
330  mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mNeumannSetTag, NULL, 1, this_range );
331  std::copy( this_range.begin(), this_range.end(), std::back_inserter( neusets ) );
332  if( mPartitionSetTag )
333  {
334  this_range.clear();
335  mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mPartitionSetTag, NULL, 1, this_range );
336  std::copy( this_range.begin(), this_range.end(), std::back_inserter( partsets ) );
337  }
338  }
339  else
340  {
341  int dummy;
342  for( const EntityHandle* iter = ent_handles; iter < ent_handles + num_sets; ++iter )
343  {
344  if( MB_SUCCESS == mbImpl->tag_get_data( mMaterialSetTag, &( *iter ), 1, &dummy ) )
345  matsets.push_back( *iter );
346  else if( MB_SUCCESS == mbImpl->tag_get_data( mDirichletSetTag, &( *iter ), 1, &dummy ) )
347  dirsets.push_back( *iter );
348  else if( MB_SUCCESS == mbImpl->tag_get_data( mNeumannSetTag, &( *iter ), 1, &dummy ) )
349  neusets.push_back( *iter );
350  else if( mPartitionSetTag && MB_SUCCESS == mbImpl->tag_get_data( mPartitionSetTag, &( *iter ), 1, &dummy ) )
351  partsets.push_back( *iter );
352  }
353  }
354 
355  return MB_SUCCESS;
356 }
357 
359  CCMIOID stateID,
360  CCMIOID& problemID,
361  CCMIOID processorID,
362  std::vector< WriteCCMIO::MaterialSetData >& matset_data,
363  std::vector< WriteCCMIO::NeumannSetData >& neuset_data )
364 {
365  // Write out a dummy problem description. If we happen to know that
366  // there already is a problem description previously recorded that
367  // is valid we could skip this step.
368  CCMIOID id;
369  CCMIOError error = kCCMIONoErr;
370  ErrorCode rval;
371  const EntityHandle mesh = 0;
372 
373  bool root_tagged = false, other_set_tagged = false;
374  Tag simname;
375  Range dum_sets;
376  rval = mbImpl->tag_get_handle( "Title", 0, MB_TYPE_OPAQUE, simname, MB_TAG_ANY );
377  if( MB_SUCCESS == rval )
378  {
379  int tag_size;
380  rval = mbImpl->tag_get_bytes( simname, tag_size );
381  if( MB_SUCCESS == rval )
382  {
383  std::vector< char > title_tag( tag_size + 1 );
384  rval = mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &simname, NULL, 1, dum_sets );
385  if( MB_SUCCESS == rval && !dum_sets.empty() )
386  {
387  rval = mbImpl->tag_get_data( simname, &( *dum_sets.begin() ), 1, &title_tag[0] );MB_CHK_SET_ERR( rval, "Problem getting simulation name tag" );
388  other_set_tagged = true;
389  }
390  else if( MB_SUCCESS == rval )
391  {
392  // Check to see if interface was tagged
393  rval = mbImpl->tag_get_data( simname, &mesh, 1, &title_tag[0] );
394  if( MB_SUCCESS == rval )
395  root_tagged = true;
396  else
397  rval = MB_SUCCESS;
398  }
399  *title_tag.rbegin() = '\0';
400  if( root_tagged || other_set_tagged )
401  {
402  CCMIONode rootNode;
403  if( kCCMIONoErr == CCMIOGetEntityNode( &error, rootID, &rootNode ) )
404  {
405  CCMIOSetTitle( &error, rootNode, &title_tag[0] );
406  CHK_SET_CCMERR( error, "Trouble setting title" );
407  }
408  }
409  }
410  }
411 
412  rval = mbImpl->tag_get_handle( "CreatingProgram", 0, MB_TYPE_OPAQUE, mCreatingProgramTag, MB_TAG_ANY );
413  if( MB_SUCCESS == rval )
414  {
415  int tag_size;
416  rval = mbImpl->tag_get_bytes( mCreatingProgramTag, tag_size );
417  if( MB_SUCCESS == rval )
418  {
419  std::vector< char > cp_tag( tag_size + 1 );
420  rval = mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mCreatingProgramTag, NULL, 1, dum_sets );
421  if( MB_SUCCESS == rval && !dum_sets.empty() )
422  {
423  rval = mbImpl->tag_get_data( mCreatingProgramTag, &( *dum_sets.begin() ), 1, &cp_tag[0] );MB_CHK_SET_ERR( rval, "Problem getting creating program tag" );
424  other_set_tagged = true;
425  }
426  else if( MB_SUCCESS == rval )
427  {
428  // Check to see if interface was tagged
429  rval = mbImpl->tag_get_data( mCreatingProgramTag, &mesh, 1, &cp_tag[0] );
430  if( MB_SUCCESS == rval )
431  root_tagged = true;
432  else
433  rval = MB_SUCCESS;
434  }
435  *cp_tag.rbegin() = '\0';
436  if( root_tagged || other_set_tagged )
437  {
438  CCMIONode rootNode;
439  if( kCCMIONoErr == CCMIOGetEntityNode( &error, rootID, &rootNode ) )
440  {
441  CCMIOWriteOptstr( &error, processorID, "CreatingProgram", &cp_tag[0] );
442  CHK_SET_CCMERR( error, "Trouble setting creating program" );
443  }
444  }
445  }
446  }
447 
448  CCMIONewEntity( &error, rootID, kCCMIOProblemDescription, NULL, &problemID );
449  CHK_SET_CCMERR( error, "Trouble creating problem node" );
450 
451  // Write material types and other info
452  for( unsigned int i = 0; i < matset_data.size(); i++ )
453  {
454  if( !matset_data[i].setName.empty() )
455  {
456  CCMIONewIndexedEntity( &error, problemID, kCCMIOCellType, matset_data[i].matsetId,
457  matset_data[i].setName.c_str(), &id );
458  CHK_SET_CCMERR( error, "Failure creating celltype node" );
459 
460  CCMIOWriteOptstr( &error, id, "MaterialType", matset_data[i].setName.c_str() );
461  CHK_SET_CCMERR( error, "Error assigning material name" );
462  }
463  else
464  {
465  char dum_name[NAME_TAG_SIZE];
466  std::ostringstream os;
467  std::string mat_name = "Material", temp_str;
468  os << mat_name << ( i + 1 );
469  temp_str = os.str();
470  strcpy( dum_name, temp_str.c_str() );
471  CCMIONewIndexedEntity( &error, problemID, kCCMIOCellType, matset_data[i].matsetId, dum_name, &id );
472  CHK_SET_CCMERR( error, "Failure creating celltype node" );
473 
474  CCMIOWriteOptstr( &error, id, "MaterialType", dum_name );
475  CHK_SET_CCMERR( error, "Error assigning material name" );
476 
477  os.str( "" );
478  }
479  rval = write_int_option( "MaterialId", matset_data[i].setHandle, mMaterialIdTag, id );MB_CHK_SET_ERR( rval, "Trouble writing MaterialId option" );
480 
481  rval = write_int_option( "Radiation", matset_data[i].setHandle, mRadiationTag, id );MB_CHK_SET_ERR( rval, "Trouble writing Radiation option" );
482 
483  rval = write_int_option( "PorosityId", matset_data[i].setHandle, mPorosityIdTag, id );MB_CHK_SET_ERR( rval, "Trouble writing PorosityId option" );
484 
485  rval = write_int_option( "SpinId", matset_data[i].setHandle, mSpinIdTag, id );MB_CHK_SET_ERR( rval, "Trouble writing SpinId option" );
486 
487  rval = write_int_option( "GroupId", matset_data[i].setHandle, mGroupIdTag, id );MB_CHK_SET_ERR( rval, "Trouble writing GroupId option" );
488 
489  rval = write_int_option( "ColorIdx", matset_data[i].setHandle, mColorIdxTag, id );MB_CHK_SET_ERR( rval, "Trouble writing ColorIdx option" );
490 
491  rval = write_int_option( "ProcessorId", matset_data[i].setHandle, mProcessorIdTag, id );MB_CHK_SET_ERR( rval, "Trouble writing ProcessorId option" );
492 
493  rval = write_int_option( "LightMaterial", matset_data[i].setHandle, mLightMaterialTag, id );MB_CHK_SET_ERR( rval, "Trouble writing LightMaterial option." );
494 
495  rval = write_int_option( "FreeSurfaceMaterial", matset_data[i].setHandle, mFreeSurfaceMaterialTag, id );MB_CHK_SET_ERR( rval, "Trouble writing FreeSurfaceMaterial option" );
496 
497  rval = write_dbl_option( "Thickness", matset_data[i].setHandle, mThicknessTag, id );MB_CHK_SET_ERR( rval, "Trouble writing Thickness option" );
498 
499  rval = write_str_option( "MaterialType", matset_data[i].setHandle, mMaterialTypeTag, id );MB_CHK_SET_ERR( rval, "Trouble writing MaterialType option" );
500  }
501 
502  // Write neumann set info
503  for( unsigned int i = 0; i < neuset_data.size(); i++ )
504  {
505  // Use the label to encode the id
506  std::ostringstream dum_id;
507  dum_id << neuset_data[i].neusetId;
508  CCMIONewIndexedEntity( &error, problemID, kCCMIOBoundaryRegion, neuset_data[i].neusetId, dum_id.str().c_str(),
509  &id );
510  CHK_SET_CCMERR( error, "Failure creating BoundaryRegion node" );
511 
512  rval = write_str_option( "BoundaryName", neuset_data[i].setHandle, mNameTag, id );MB_CHK_SET_ERR( rval, "Trouble writing boundary type number" );
513 
514  rval = write_str_option( "BoundaryType", neuset_data[i].setHandle, mBoundaryTypeTag, id );MB_CHK_SET_ERR( rval, "Trouble writing boundary type number" );
515 
516  rval = write_int_option( "ProstarRegionNumber", neuset_data[i].setHandle, mProstarRegionNumberTag, id );MB_CHK_SET_ERR( rval, "Trouble writing prostar region number" );
517  }
518 
519  CCMIOWriteState( &error, stateID, problemID, "Example state" );
520  CHK_SET_CCMERR( error, "Failure writing problem state" );
521 
522  // Get cell types; reuse cell ids array
523  // for (i = 0, rit = all_elems.begin(); i < num_elems; i++, ++rit) {
524  // egids[i] = ccm_types[mbImpl->type_from_handle(*rit)];
525  // assert(-1 != egids[i]);
526  // }
527 
528  return MB_SUCCESS;
529 }
530 
531 ErrorCode WriteCCMIO::write_int_option( const char* opt_name, EntityHandle seth, Tag& tag, CCMIOID& node )
532 {
533  ErrorCode rval;
534 
535  if( !tag )
536  {
537  rval = mbImpl->tag_get_handle( opt_name, 1, MB_TYPE_INTEGER, tag );
538  // Return success since that just means we don't have to write this option
539  if( MB_SUCCESS != rval ) return MB_SUCCESS;
540  }
541 
542  int dum_val;
543  rval = mbImpl->tag_get_data( tag, &seth, 1, &dum_val );
544  // Return success since that just means we don't have to write this option
545  if( MB_SUCCESS != rval ) return MB_SUCCESS;
546 
547  CCMIOError error = kCCMIONoErr;
548  CCMIOWriteOpti( &error, node, opt_name, dum_val );
549  CHK_SET_CCMERR( error, "Trouble writing int option" );
550 
551  return MB_SUCCESS;
552 }
553 
554 ErrorCode WriteCCMIO::write_dbl_option( const char* opt_name, EntityHandle seth, Tag& tag, CCMIOID& node )
555 {
556  ErrorCode rval;
557 
558  if( !tag )
559  {
560  rval = mbImpl->tag_get_handle( opt_name, 1, MB_TYPE_DOUBLE, tag );
561  // Return success since that just means we don't have to write this option
562  if( MB_SUCCESS != rval ) return MB_SUCCESS;
563  }
564 
565  double dum_val;
566  rval = mbImpl->tag_get_data( tag, &seth, 1, &dum_val );
567  // Return success since that just means we don't have to write this option
568  if( MB_SUCCESS != rval ) return MB_SUCCESS;
569 
570  CCMIOError error = kCCMIONoErr;
571  CCMIOWriteOptf( &error, node, opt_name, dum_val );
572  CHK_SET_CCMERR( error, "Trouble writing int option" );
573 
574  return MB_SUCCESS;
575 }
576 
578  EntityHandle seth,
579  Tag& tag,
580  CCMIOID& node,
581  const char* other_name )
582 {
583  int tag_size;
584  ErrorCode rval;
585 
586  if( !tag )
587  {
588  rval = mbImpl->tag_get_handle( opt_name, 0, MB_TYPE_OPAQUE, tag, MB_TAG_ANY );
589  // Return success since that just means we don't have to write this option
590  if( MB_SUCCESS != rval ) return MB_SUCCESS;
591  }
592 
593  rval = mbImpl->tag_get_bytes( tag, tag_size );
594  if( MB_SUCCESS != rval ) return MB_SUCCESS;
595  std::vector< char > opt_val( tag_size + 1 );
596 
597  rval = mbImpl->tag_get_data( tag, &seth, 1, &opt_val[0] );
598  if( MB_SUCCESS != rval ) return MB_SUCCESS;
599 
600  // Null-terminate if necessary
601  if( std::find( opt_val.begin(), opt_val.end(), '\0' ) == opt_val.end() ) *opt_val.rbegin() = '\0';
602 
603  CCMIOError error = kCCMIONoErr;
604  if( other_name )
605  {
606  CCMIOWriteOptstr( &error, node, other_name, &opt_val[0] );
607  CHK_SET_CCMERR( error, "Failure writing an option string MaterialType" );
608  }
609  else
610  {
611  CCMIOWriteOptstr( &error, node, opt_name, &opt_val[0] );
612  CHK_SET_CCMERR( error, "Failure writing an option string MaterialType" );
613  }
614 
615  return MB_SUCCESS;
616 }
617 
618 ErrorCode WriteCCMIO::gather_matset_info( std::vector< EntityHandle >& matsets,
619  std::vector< MaterialSetData >& matset_data,
620  Range& all_verts )
621 {
622  ErrorCode result;
623  matset_data.resize( matsets.size() );
624  if( 1 == matsets.size() && 0 == matsets[0] )
625  {
626  // Whole mesh
627  mWholeMesh = true;
628 
629  result = mbImpl->get_entities_by_dimension( 0, mDimension, matset_data[0].elems );MB_CHK_SET_ERR( result, "Trouble getting all elements in mesh" );
630  result = mWriteIface->gather_nodes_from_elements( matset_data[0].elems, mEntityMark, all_verts );MB_CHK_SET_ERR( result, "Trouble gathering nodes from elements" );
631 
632  return result;
633  }
634 
635  std::vector< unsigned char > marks;
636  for( unsigned int i = 0; i < matsets.size(); i++ )
637  {
638  EntityHandle this_set = matset_data[i].setHandle = matsets[i];
639 
640  // Get all Entity Handles in the set
641  result = mbImpl->get_entities_by_dimension( this_set, mDimension, matset_data[i].elems, true );MB_CHK_SET_ERR( result, "Trouble getting m-dimensional ents" );
642 
643  // Get all connected vertices
644  result = mWriteIface->gather_nodes_from_elements( matset_data[i].elems, mEntityMark, all_verts );MB_CHK_SET_ERR( result, "Trouble getting vertices for a matset" );
645 
646  // Check for consistent entity type
647  EntityType start_type = mbImpl->type_from_handle( *matset_data[i].elems.begin() );
648  if( start_type == mbImpl->type_from_handle( *matset_data[i].elems.rbegin() ) )
649  matset_data[i].entityType = start_type;
650 
651  // Mark elements in this matset
652  marks.resize( matset_data[i].elems.size(), 0x1 );
653  result = mbImpl->tag_set_data( mEntityMark, matset_data[i].elems, &marks[0] );MB_CHK_SET_ERR( result, "Couln't mark entities being output" );
654 
655  // Get id for this matset
656  result = mbImpl->tag_get_data( mMaterialSetTag, &this_set, 1, &matset_data[i].matsetId );MB_CHK_SET_ERR( result, "Couln't get global id for material set" );
657 
658  // Get name for this matset
659  if( mNameTag )
660  {
661  char dum_name[NAME_TAG_SIZE];
662  result = mbImpl->tag_get_data( mNameTag, &this_set, 1, dum_name );
663  if( MB_SUCCESS == result ) matset_data[i].setName = dum_name;
664 
665  // Reset success, so later checks don't fail
666  result = MB_SUCCESS;
667  }
668  }
669 
670  if( all_verts.empty() )
671  {
672  MB_SET_ERR( MB_FILE_WRITE_ERROR, "No vertices from elements" );
673  }
674 
675  return MB_SUCCESS;
676 }
677 
678 ErrorCode WriteCCMIO::gather_neuset_info( std::vector< EntityHandle >& neusets,
679  std::vector< NeumannSetData >& neuset_info )
680 {
681  ErrorCode result;
682 
683  neuset_info.resize( neusets.size() );
684  for( unsigned int i = 0; i < neusets.size(); i++ )
685  {
686  EntityHandle this_set = neuset_info[i].setHandle = neusets[i];
687 
688  // Get all Entity Handles of one less dimension than that being output
689  result = mbImpl->get_entities_by_dimension( this_set, mDimension - 1, neuset_info[i].elems, true );MB_CHK_SET_ERR( result, "Trouble getting (m-1)-dimensional ents for neuset" );
690 
691  result = mbImpl->tag_get_data( mGlobalIdTag, &this_set, 1, &neuset_info[i].neusetId );
692  if( MB_TAG_NOT_FOUND == result )
693  {
694  result = mbImpl->tag_get_data( mNeumannSetTag, &this_set, 1, &neuset_info[i].neusetId );
695  if( MB_SUCCESS != result )
696  // Need some id; use the loop iteration number
697  neuset_info[i].neusetId = i;
698  }
699 
700  // Get name for this neuset
701  if( mNameTag )
702  {
703  char dum_name[NAME_TAG_SIZE];
704  result = mbImpl->tag_get_data( mNameTag, &this_set, 1, dum_name );
705  if( MB_SUCCESS == result ) neuset_info[i].setName = dum_name;
706 
707  // Reset success, so later checks don't fail
708  result = MB_SUCCESS;
709  }
710  }
711 
712  return MB_SUCCESS;
713 }
714 
715 ErrorCode WriteCCMIO::get_gids( const Range& ents, int*& gids, int& minid, int& maxid )
716 {
717  int num_ents = ents.size();
718  gids = new int[num_ents];
719  ErrorCode result = mbImpl->tag_get_data( mGlobalIdTag, ents, &gids[0] );MB_CHK_SET_ERR( result, "Couldn't get global id data" );
720  minid = *std::min_element( gids, gids + num_ents );
721  maxid = *std::max_element( gids, gids + num_ents );
722  if( 0 == minid )
723  {
724  // gids need to be assigned
725  for( int i = 1; i <= num_ents; i++ )
726  gids[i] = i;
727  result = mbImpl->tag_set_data( mGlobalIdTag, ents, &gids[0] );MB_CHK_SET_ERR( result, "Couldn't set global id data" );
728  maxid = num_ents;
729  }
730 
731  return MB_SUCCESS;
732 }
733 
734 ErrorCode WriteCCMIO::write_nodes( CCMIOID rootID, const Range& verts, const int dimension, CCMIOID& verticesID )
735 {
736  // Get/write map (global ids) first (gids already assigned)
737  unsigned int num_verts = verts.size();
738  std::vector< int > vgids( num_verts );
739  ErrorCode result = mbImpl->tag_get_data( mGlobalIdTag, verts, &vgids[0] );MB_CHK_SET_ERR( result, "Failed to get global ids for vertices" );
740 
741  // Create the map node for vertex ids, and write them to that node
742  CCMIOID mapID;
743  CCMIOError error = kCCMIONoErr;
744  CCMIONewEntity( &error, rootID, kCCMIOMap, "Vertex map", &mapID );
745  CHK_SET_CCMERR( error, "Failure creating Vertex map node" );
746 
747  int maxid = *std::max_element( vgids.begin(), vgids.end() );
748 
749  CCMIOWriteMap( &error, mapID, CCMIOSIZEC( num_verts ), CCMIOSIZEC( maxid ), &vgids[0], CCMIOINDEXC( kCCMIOStart ),
750  CCMIOINDEXC( kCCMIOEnd ) );
751  CHK_SET_CCMERR( error, "Problem writing node map" );
752 
753  // Create the vertex coordinate node, and write it
754  CCMIONewEntity( &error, rootID, kCCMIOVertices, "Vertices", &verticesID );
755  CHK_SET_CCMERR( error, "Trouble creating vertices node" );
756 
757  // Get the vertex locations
758  double* coords = new double[3 * num_verts];
759  std::vector< double* > coord_arrays( 3 );
760  // Cppcheck warning (false positive): variable coord_arrays is assigned a value that is never
761  // used
762  coord_arrays[0] = coords;
763  coord_arrays[1] = coords + num_verts;
764  coord_arrays[2] = ( dimension == 3 ? coords + 2 * num_verts : NULL );
765  result = mWriteIface->get_node_coords( -1, verts.begin(), verts.end(), 3 * num_verts, coords );
766  if( result != MB_SUCCESS )
767  {
768  delete[] coords;
769  return result;
770  }
771 
772  // Transform coordinates, if necessary
773  result = transform_coords( dimension, num_verts, coords );
774  if( result != MB_SUCCESS )
775  {
776  delete[] coords;
777  MB_SET_ERR( result, "Trouble transforming vertex coordinates" );
778  }
779 
780  // Write the vertices
781  CCMIOWriteVerticesd( &error, verticesID, CCMIOSIZEC( dimension ), 1.0, mapID, coords, CCMIOINDEXC( kCCMIOStart ),
782  CCMIOINDEXC( kCCMIOEnd ) );
783  CHK_SET_CCMERR( error, "CCMIOWriteVertices failed" );
784 
785  // Clean up
786  delete[] coords;
787 
788  return MB_SUCCESS;
789 }
790 
791 ErrorCode WriteCCMIO::transform_coords( const int dimension, const int num_nodes, double* coords )
792 {
793  Tag trans_tag;
795  if( result == MB_TAG_NOT_FOUND )
796  return MB_SUCCESS;
797  else if( MB_SUCCESS != result )
798  return result;
799  double trans_matrix[16];
800  const EntityHandle mesh = 0;
801  result = mbImpl->tag_get_data( trans_tag, &mesh, 1, trans_matrix );MB_CHK_SET_ERR( result, "Couldn't get transform data" );
802 
803  double* tmp_coords = coords;
804  for( int i = 0; i < num_nodes; i++, tmp_coords += 1 )
805  {
806  double vec1[3] = { 0.0, 0.0, 0.0 };
807  for( int row = 0; row < 3; row++ )
808  {
809  vec1[row] += ( trans_matrix[( row * 4 ) + 0] * coords[0] );
810  vec1[row] += ( trans_matrix[( row * 4 ) + 1] * coords[num_nodes] );
811  if( 3 == dimension ) vec1[row] += ( trans_matrix[( row * 4 ) + 2] * coords[2 * num_nodes] );
812  }
813 
814  coords[0] = vec1[0];
815  coords[num_nodes] = vec1[1];
816  coords[2 * num_nodes] = vec1[2];
817  }
818 
819  return MB_SUCCESS;
820 }
821 
823  std::vector< MaterialSetData >& matset_data,
824  std::vector< NeumannSetData >& neuset_data,
825  Range& /* verts */,
826  CCMIOID& topologyID )
827 {
828  std::vector< int > connect;
829  ErrorCode result;
830  CCMIOID cellMapID, cells;
831  CCMIOError error = kCCMIONoErr;
832 
833  // Don't usually have anywhere near 31 nodes per element
834  connect.reserve( 31 );
836 
837  // Create the topology node, and the cell and cell map nodes
838  CCMIONewEntity( &error, rootID, kCCMIOTopology, "Topology", &topologyID );
839  CHK_SET_CCMERR( error, "Trouble creating topology node" );
840 
841  CCMIONewEntity( &error, rootID, kCCMIOMap, "Cell map", &cellMapID );
842  CHK_SET_CCMERR( error, "Failure creating Cell Map node" );
843 
844  CCMIONewEntity( &error, topologyID, kCCMIOCells, "Cells", &cells );
845  CHK_SET_CCMERR( error, "Trouble creating Cell node under Topology node" );
846 
847  //================================================
848  // Loop over material sets, doing each one at a time
849  //================================================
850  Range all_elems;
851  unsigned int i, num_elems = 0;
852  int max_id = 1;
853  std::vector< int > egids;
854  int tot_elems = 0;
855 
856  for( unsigned int m = 0; m < matset_data.size(); m++ )
857  tot_elems += matset_data[m].elems.size();
858 
859  for( unsigned int m = 0; m < matset_data.size(); m++ )
860  {
861  unsigned int this_num = matset_data[m].elems.size();
862 
863  //================================================
864  // Save all elements being output
865  //================================================
866  all_elems.merge( matset_data[m].elems );
867 
868  //================================================
869  // Assign global ids for elements being written
870  //================================================
871  egids.resize( matset_data[m].elems.size() );
872  for( i = 0; i < this_num; i++ )
873  egids[i] = max_id++;
874  result = mbImpl->tag_set_data( mGlobalIdTag, matset_data[m].elems, &egids[0] );MB_CHK_SET_ERR( result, "Failed to assign global ids for all elements being written" );
875 
876  //================================================
877  // Write cell ids and material types for this matset; reuse egids for cell mat type
878  //================================================
879  CCMIOWriteMap( &error, cellMapID, CCMIOSIZEC( tot_elems ), CCMIOSIZEC( tot_elems ), &egids[0],
880  CCMIOINDEXC( 0 == m ? kCCMIOStart : num_elems ),
881  CCMIOINDEXC( matset_data.size() == m ? kCCMIOEnd : num_elems + this_num ) );
882  CHK_SET_CCMERR( error, "Trouble writing cell map" );
883 
884  if( -1 == matset_data[m].matsetId )
885  {
886  for( i = 0; i < this_num; i++ )
887  egids[i] = m;
888  }
889  else
890  {
891  for( i = 0; i < this_num; i++ )
892  egids[i] = matset_data[m].matsetId;
893  }
894 
895  CCMIOWriteCells( &error, cells, cellMapID, &egids[0], CCMIOINDEXC( 0 == m ? kCCMIOStart : num_elems ),
896  CCMIOINDEXC( matset_data.size() == m ? kCCMIOEnd : num_elems + this_num ) );
897  CHK_SET_CCMERR( error, "Trouble writing Cell node" );
898 
899  //================================================
900  // Write cell entity types
901  //================================================
902  const EntityHandle* conn;
903  int num_conn;
904  int has_mid_nodes[4];
905  std::vector< EntityHandle > storage;
906  for( i = 0, rit = matset_data[m].elems.begin(); i < this_num; i++, ++rit )
907  {
908  result = mbImpl->get_connectivity( *rit, conn, num_conn, false, &storage );MB_CHK_SET_ERR( result, "Trouble getting connectivity for entity type check" );
909  CN::HasMidNodes( mbImpl->type_from_handle( *rit ), num_conn, has_mid_nodes );
910  egids[i] = moab_to_ccmio_type( mbImpl->type_from_handle( *rit ), has_mid_nodes );
911  }
912 
913  CCMIOWriteOpt1i( &error, cells, "CellTopologyType", CCMIOSIZEC( tot_elems ), &egids[0],
914  CCMIOINDEXC( 0 == m ? kCCMIOStart : num_elems ),
915  CCMIOINDEXC( matset_data.size() == m ? kCCMIOEnd : num_elems + this_num ) );
916  CHK_SET_CCMERR( error, "Failed to write cell topo types" );
917 
918  num_elems += this_num;
919  }
920 
921  //================================================
922  // Get skin and neumann set faces
923  //================================================
924  Range neuset_facets, skin_facets;
925  Skinner skinner( mbImpl );
926  result = skinner.find_skin( 0, all_elems, mDimension - 1, skin_facets );MB_CHK_SET_ERR( result, "Failed to get skin facets" );
927 
928  // Remove neumann set facets from skin facets, we have to output these
929  // separately
930  for( i = 0; i < neuset_data.size(); i++ )
931  neuset_facets.merge( neuset_data[i].elems );
932 
933  skin_facets -= neuset_facets;
934  // Make neuset_facets the union, and get ids for them
935  neuset_facets.merge( skin_facets );
936  result = mWriteIface->assign_ids( neuset_facets, mGlobalIdTag, 1 );
937 
938  int fmaxid = neuset_facets.size();
939 
940  //================================================
941  // Write external faces
942  //================================================
943  for( i = 0; i < neuset_data.size(); i++ )
944  {
946  unsigned char cmarks[2];
947  Range ext_faces;
948  std::vector< EntityHandle > mcells;
949  // Removing the faces connected to two regions
950  for( rrit = neuset_data[i].elems.rbegin(); rrit != neuset_data[i].elems.rend(); ++rrit )
951  {
952  mcells.clear();
953  result = mbImpl->get_adjacencies( &( *rrit ), 1, mDimension, false, mcells );MB_CHK_SET_ERR( result, "Trouble getting bounding cells" );
954 
955  result = mbImpl->tag_get_data( mEntityMark, &mcells[0], mcells.size(), cmarks );MB_CHK_SET_ERR( result, "Trouble getting mark tags on cells bounding facets" );
956 
957  if( mcells.size() == 2 && ( mWholeMesh || ( cmarks[0] && cmarks[1] ) ) )
958  {
959  }
960  else
961  {
962  // External face
963  ext_faces.insert( *rrit );
964  }
965  }
966  if( ext_faces.size() != 0 && neuset_data[i].neusetId != 0 )
967  {
968  result = write_external_faces( rootID, topologyID, neuset_data[i].neusetId, ext_faces );MB_CHK_SET_ERR( result, "Trouble writing Neumann set facets" );
969  }
970  ext_faces.clear();
971  }
972 
973  if( !skin_facets.empty() )
974  {
975  result = write_external_faces( rootID, topologyID, 0, skin_facets );MB_CHK_SET_ERR( result, "Trouble writing skin facets" );
976  }
977 
978  //================================================
979  // Now internal faces; loop over elements, do each face on the element
980  //================================================
981  // Mark tag, for face marking on each non-polyhedral element
982 
983  if( num_elems > 1 )
984  { // No internal faces for just one element
985  Tag fmark_tag;
986  unsigned char mval = 0x0, omval;
987  result = mbImpl->tag_get_handle( "__fmark", 1, MB_TYPE_OPAQUE, fmark_tag, MB_TAG_DENSE | MB_TAG_CREAT, &mval );MB_CHK_SET_ERR( result, "Couldn't create mark tag" );
988 
989  std::vector< EntityHandle > tmp_face_cells, storage;
990  std::vector< int > iface_connect, iface_cells;
991  EntityHandle tmp_connect[CN::MAX_NODES_PER_ELEMENT]; // tmp connect vector
992  const EntityHandle *connectc, *oconnectc;
993  int num_connectc; // Cell connectivity
994  const EntityHandle* connectf;
995  int num_connectf; // Face connectivity
996 
997  for( i = 0, rit = all_elems.begin(); i < num_elems; i++, ++rit )
998  {
999  EntityType etype = TYPE_FROM_HANDLE( *rit );
1000 
1001  //-----------------------
1002  // If not polyh, get mark
1003  //-----------------------
1004  if( MBPOLYHEDRON != etype && MBPOLYGON != etype )
1005  {
1006  result = mbImpl->tag_get_data( fmark_tag, &( *rit ), 1, &mval );MB_CHK_SET_ERR( result, "Couldn't get mark data" );
1007  }
1008 
1009  //-----------------------
1010  // Get cell connectivity, and whether it's a polyhedron
1011  //-----------------------
1012  result = mbImpl->get_connectivity( *rit, connectc, num_connectc, false, &storage );MB_CHK_SET_ERR( result, "Couldn't get entity connectivity" );
1013 
1014  // If polyh, write faces directly
1015  bool is_polyh = ( MBPOLYHEDRON == etype );
1016 
1017  int num_facets = ( is_polyh ? num_connectc : CN::NumSubEntities( etype, mDimension - 1 ) );
1018 
1019  //----------------------------------------------------------
1020  // Loop over each facet of element, outputting it if not marked
1021  //----------------------------------------------------------
1022  for( int f = 0; f < num_facets; f++ )
1023  {
1024  //.............................................
1025  // If this face marked, skip
1026  //.............................................
1027  if( !is_polyh && ( ( mval >> f ) & 0x1 ) ) continue;
1028 
1029  //.................
1030  // Get face connect and adj cells
1031  //.................
1032  if( !is_polyh )
1033  {
1034  // (from CN)
1035  CN::SubEntityConn( connectc, etype, mDimension - 1, f, tmp_connect, num_connectf );
1036  connectf = tmp_connect;
1037  }
1038  else
1039  {
1040  // Directly
1041  result = mbImpl->get_connectivity( connectc[f], connectf, num_connectf, false );MB_CHK_SET_ERR( result, "Couldn't get polyhedron connectivity" );
1042  }
1043 
1044  //............................
1045  // Get adj cells from face connect (same for poly's and not, since both usually
1046  // go through vertices anyway)
1047  //............................
1048  tmp_face_cells.clear();
1049  result = mbImpl->get_adjacencies( connectf, num_connectf, mDimension, false, tmp_face_cells );MB_CHK_SET_ERR( result, "Error getting adj hexes" );
1050 
1051  //...............................
1052  // If this face only bounds one cell, skip, since we exported external faces
1053  // before this loop
1054  //...............................
1055  if( tmp_face_cells.size() != 2 ) continue;
1056 
1057  //.................
1058  // Switch cells so that *rit is always 1st (face connectivity is always written such
1059  // that that one is with forward sense)
1060  //.................
1061  int side_num = 0, sense = 0, offset = 0;
1062  if( !is_polyh && tmp_face_cells[0] != *rit )
1063  {
1064  EntityHandle tmph = tmp_face_cells[0];
1065  tmp_face_cells[0] = tmp_face_cells[1];
1066  tmp_face_cells[1] = tmph;
1067  }
1068 
1069  //.................
1070  // Save ids of cells
1071  //.................
1072  assert( tmp_face_cells[0] != tmp_face_cells[1] );
1073  iface_cells.resize( iface_cells.size() + 2 );
1074  result = mbImpl->tag_get_data( mGlobalIdTag, &tmp_face_cells[0], tmp_face_cells.size(),
1075  &iface_cells[iface_cells.size() - 2] );MB_CHK_SET_ERR( result, "Trouble getting global ids for bounded cells" );
1076  iface_connect.push_back( num_connectf );
1077 
1078  //.................
1079  // Save indices of face vertices
1080  //.................
1081  unsigned int tmp_size = iface_connect.size();
1082  iface_connect.resize( tmp_size + num_connectf );
1083  result = mbImpl->tag_get_data( mGlobalIdTag, connectf, num_connectf, &iface_connect[tmp_size] );MB_CHK_SET_ERR( result, "Trouble getting global id for internal face" );
1084 
1085  //.................
1086  // Mark other cell with the right side #
1087  //.................
1088  if( !is_polyh )
1089  {
1090  // Mark other cell for this face, if there is another cell
1091 
1092  result = mbImpl->get_connectivity( tmp_face_cells[1], oconnectc, num_connectc, false, &storage );MB_CHK_SET_ERR( result, "Couldn't get other entity connectivity" );
1093 
1094  // Get side number in other cell
1095  CN::SideNumber( TYPE_FROM_HANDLE( tmp_face_cells[1] ), oconnectc, connectf, num_connectf,
1096  mDimension - 1, side_num, sense, offset );
1097  // Set mark for that face on the other cell
1098  result = mbImpl->tag_get_data( fmark_tag, &tmp_face_cells[1], 1, &omval );MB_CHK_SET_ERR( result, "Couldn't get mark data for other cell" );
1099  }
1100 
1101  omval |= ( 0x1 << (unsigned int)side_num );
1102  result = mbImpl->tag_set_data( fmark_tag, &tmp_face_cells[1], 1, &omval );MB_CHK_SET_ERR( result, "Couldn't set mark data for other cell" );
1103  } // Loop over faces in elem
1104  } // Loop over elems
1105 
1106  //================================================
1107  // Write internal faces
1108  //================================================
1109 
1110  CCMIOID mapID;
1111  CCMIONewEntity( &error, rootID, kCCMIOMap, NULL, &mapID );
1112  CHK_SET_CCMERR( error, "Trouble creating Internal Face map node" );
1113 
1114  unsigned int num_ifaces = iface_cells.size() / 2;
1115 
1116  // Set gids for internal faces; reuse egids
1117  egids.resize( num_ifaces );
1118  for( i = 1; i <= num_ifaces; i++ )
1119  egids[i - 1] = fmaxid + i;
1120  CCMIOWriteMap( &error, mapID, CCMIOSIZEC( num_ifaces ), CCMIOSIZEC( fmaxid + num_ifaces ), &egids[0],
1121  CCMIOINDEXC( kCCMIOStart ), CCMIOINDEXC( kCCMIOEnd ) );
1122  CHK_SET_CCMERR( error, "Trouble writing Internal Face map node" );
1123 
1124  CCMIOID id;
1125  CCMIONewEntity( &error, topologyID, kCCMIOInternalFaces, "Internal faces", &id );
1126  CHK_SET_CCMERR( error, "Failed to create Internal face node under Topology node" );
1127  CCMIOWriteFaces( &error, id, kCCMIOInternalFaces, mapID, CCMIOSIZEC( iface_connect.size() ), &iface_connect[0],
1128  CCMIOINDEXC( kCCMIOStart ), CCMIOINDEXC( kCCMIOEnd ) );
1129  CHK_SET_CCMERR( error, "Failure writing Internal face connectivity" );
1130  CCMIOWriteFaceCells( &error, id, kCCMIOInternalFaces, mapID, &iface_cells[0], CCMIOINDEXC( kCCMIOStart ),
1131  CCMIOINDEXC( kCCMIOEnd ) );
1132  CHK_SET_CCMERR( error, "Failure writing Internal face cells" );
1133  }
1134 
1135  return MB_SUCCESS;
1136 }
1137 
1138 int WriteCCMIO::moab_to_ccmio_type( EntityType etype, int has_mid_nodes[] )
1139 {
1140  int ctype = -1;
1141  if( has_mid_nodes[0] || has_mid_nodes[2] || has_mid_nodes[3] ) return ctype;
1142 
1143  switch( etype )
1144  {
1145  case MBVERTEX:
1146  ctype = 1;
1147  break;
1148  case MBEDGE:
1149  if( !has_mid_nodes[1] )
1150  ctype = 2;
1151  else
1152  ctype = 28;
1153  break;
1154  case MBQUAD:
1155  if( has_mid_nodes[1] )
1156  ctype = 4;
1157  else
1158  ctype = 3;
1159  break;
1160  case MBTET:
1161  if( has_mid_nodes[1] )
1162  ctype = 23;
1163  else
1164  ctype = 13;
1165  break;
1166  case MBPRISM:
1167  if( has_mid_nodes[1] )
1168  ctype = 22;
1169  else
1170  ctype = 12;
1171  break;
1172  case MBPYRAMID:
1173  if( has_mid_nodes[1] )
1174  ctype = 24;
1175  else
1176  ctype = 14;
1177  break;
1178  case MBHEX:
1179  if( has_mid_nodes[1] )
1180  ctype = 21;
1181  else
1182  ctype = 11;
1183  break;
1184  case MBPOLYHEDRON:
1185  ctype = 255;
1186  break;
1187  default:
1188  break;
1189  }
1190 
1191  return ctype;
1192 }
1193 
1194 ErrorCode WriteCCMIO::write_external_faces( CCMIOID rootID, CCMIOID topologyID, int set_num, Range& facets )
1195 {
1196  CCMIOError error = kCCMIONoErr;
1197  CCMIOID mapID, id;
1198 
1199  // Get gids for these faces
1200  int *gids = NULL, minid, maxid;
1201  ErrorCode result = get_gids( facets, gids, minid, maxid );MB_CHK_SET_ERR( result, "Trouble getting global ids for facets" );
1202 
1203  // Write the face id map
1204  CCMIONewEntity( &error, rootID, kCCMIOMap, NULL, &mapID );
1205  CHK_SET_CCMERR( error, "Problem creating face id map" );
1206 
1207  CCMIOWriteMap( &error, mapID, CCMIOSIZEC( facets.size() ), CCMIOSIZEC( maxid ), gids, CCMIOINDEXC( kCCMIOStart ),
1208  CCMIOINDEXC( kCCMIOEnd ) );
1209  CHK_SET_CCMERR( error, "Problem writing face id map" );
1210 
1211  // Get the connectivity of the faces; set size by how many verts in last facet
1212  const EntityHandle* connect;
1213  int num_connect;
1214  result = mbImpl->get_connectivity( *facets.rbegin(), connect, num_connect );MB_CHK_SET_ERR( result, "Failed to get connectivity of last facet" );
1215  std::vector< int > fconnect( facets.size() * ( num_connect + 1 ) );
1216 
1217  result = mWriteIface->get_element_connect( facets.begin(), facets.end(), num_connect, mGlobalIdTag, fconnect.size(),
1218  &fconnect[0], true );MB_CHK_SET_ERR( result, "Failed to get facet connectivity" );
1219 
1220  // Get and write a new external face entity
1221  CCMIONewIndexedEntity( &error, topologyID, kCCMIOBoundaryFaces, set_num, "Boundary faces", &id );
1222  CHK_SET_CCMERR( error, "Problem creating boundary face entity" );
1223 
1224  CCMIOWriteFaces( &error, id, kCCMIOBoundaryFaces, mapID, CCMIOSIZEC( fconnect.size() ), &fconnect[0],
1225  CCMIOINDEXC( kCCMIOStart ), CCMIOINDEXC( kCCMIOEnd ) );
1226  CHK_SET_CCMERR( error, "Problem writing boundary faces" );
1227 
1228  // Get info on bounding cells; reuse fconnect
1229  std::vector< EntityHandle > cells;
1230  unsigned char cmarks[2];
1231  int i, j = 0;
1232  Range dead_facets;
1233  Range::iterator rit;
1234 
1235  // About error checking in this loop: if any facets have no bounding cells,
1236  // this is an error, since global ids for facets are computed outside this loop
1237  for( rit = facets.begin(), i = 0; rit != facets.end(); ++rit, i++ )
1238  {
1239  cells.clear();
1240 
1241  // Get cell then gid of cell
1242  result = mbImpl->get_adjacencies( &( *rit ), 1, mDimension, false, cells );MB_CHK_SET_ERR( result, "Trouble getting bounding cells" );
1243  if( cells.empty() )
1244  {
1245  MB_SET_ERR( MB_FILE_WRITE_ERROR, "External facet with no output bounding cell" );
1246  }
1247 
1248  // Check we don't bound more than one cell being output
1249  result = mbImpl->tag_get_data( mEntityMark, &cells[0], cells.size(), cmarks );MB_CHK_SET_ERR( result, "Trouble getting mark tags on cells bounding facets" );
1250  if( cells.size() == 2 && ( mWholeMesh || ( cmarks[0] && cmarks[1] ) ) )
1251  {
1252  MB_SET_ERR( MB_FILE_WRITE_ERROR, "External facet with two output bounding cells" );
1253  }
1254  else if( 1 == cells.size() && !mWholeMesh && !cmarks[0] )
1255  {
1256  MB_SET_ERR( MB_FILE_WRITE_ERROR, "External facet with no output bounding cells" );
1257  }
1258 
1259  // Make sure 1st cell is the one being output
1260  if( 2 == cells.size() && !( cmarks[0] | 0x0 ) && ( cmarks[1] & 0x1 ) ) cells[0] = cells[1];
1261 
1262  // Get gid for bounded cell
1263  result = mbImpl->tag_get_data( mGlobalIdTag, &cells[0], 1, &fconnect[j] );MB_CHK_SET_ERR( result, "Couldn't get global id tag for bounded cell" );
1264 
1265  j++;
1266  }
1267 
1268  // Write the bounding cell data
1269  CCMIOWriteFaceCells( &error, id, kCCMIOBoundaryFaces, mapID, &fconnect[0], CCMIOINDEXC( kCCMIOStart ),
1270  CCMIOINDEXC( kCCMIOEnd ) );
1271  CHK_SET_CCMERR( error, "Problem writing boundary cell data" );
1272 
1273  return MB_SUCCESS;
1274 }
1275 
1277  int current_sense,
1278  Range& forward_elems,
1279  Range& reverse_elems )
1280 {
1281  Range neuset_elems, neuset_meshsets;
1282 
1283  // Get the sense tag; don't need to check return, might be an error if the tag
1284  // hasn't been created yet
1285  Tag sense_tag = 0;
1286  mbImpl->tag_get_handle( "SENSE", 1, MB_TYPE_INTEGER, sense_tag );
1287 
1288  // Get the entities in this set, non-recursive
1289  ErrorCode result = mbImpl->get_entities_by_handle( neuset, neuset_elems );
1290  if( MB_FAILURE == result ) return result;
1291 
1292  // Now remove the meshsets into the neuset_meshsets; first find the first meshset,
1293  Range::iterator range_iter = neuset_elems.begin();
1294  while( TYPE_FROM_HANDLE( *range_iter ) != MBENTITYSET && range_iter != neuset_elems.end() )
1295  ++range_iter;
1296 
1297  // Then, if there are some, copy them into neuset_meshsets and erase from neuset_elems
1298  if( range_iter != neuset_elems.end() )
1299  {
1300  std::copy( range_iter, neuset_elems.end(), range_inserter( neuset_meshsets ) );
1301  neuset_elems.erase( range_iter, neuset_elems.end() );
1302  }
1303 
1304  // OK, for the elements, check the sense of this set and copy into the right range
1305  // (if the sense is 0, copy into both ranges)
1306 
1307  // Need to step forward on list until we reach the right dimension
1308  Range::iterator dum_it = neuset_elems.end();
1309  --dum_it;
1310  int target_dim = CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) );
1311  dum_it = neuset_elems.begin();
1312  while( target_dim != CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) ) && dum_it != neuset_elems.end() )
1313  ++dum_it;
1314 
1315  if( current_sense == 1 || current_sense == 0 )
1316  std::copy( dum_it, neuset_elems.end(), range_inserter( forward_elems ) );
1317  if( current_sense == -1 || current_sense == 0 )
1318  std::copy( dum_it, neuset_elems.end(), range_inserter( reverse_elems ) );
1319 
1320  // Now loop over the contained meshsets, getting the sense of those and calling this
1321  // function recursively
1322  for( range_iter = neuset_meshsets.begin(); range_iter != neuset_meshsets.end(); ++range_iter )
1323  {
1324  // First get the sense; if it's not there, by convention it's forward
1325  int this_sense;
1326  if( 0 == sense_tag || MB_FAILURE == mbImpl->tag_get_data( sense_tag, &( *range_iter ), 1, &this_sense ) )
1327  this_sense = 1;
1328 
1329  // Now get all the entities on this meshset, with the proper (possibly reversed) sense
1330  get_neuset_elems( *range_iter, this_sense * current_sense, forward_elems, reverse_elems );
1331  }
1332 
1333  return result;
1334 }
1335 } // namespace moab