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