Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
WriteSLAC.cpp
Go to the documentation of this file.
1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2004 Sandia Corporation. Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 
16 #ifdef WIN32
17 #ifdef _DEBUG
18 // turn off warnings that say they debugging identifier has been truncated
19 // this warning comes up when using some STL containers
20 #pragma warning( disable : 4786 )
21 #endif
22 #endif
23 
24 #include "WriteSLAC.hpp"
25 
26 #include <utility>
27 #include <algorithm>
28 #include <ctime>
29 #include <string>
30 #include <vector>
31 #include <cstdio>
32 #include <cstring>
33 #include <iostream>
34 #include <cassert>
35 
36 #include "netcdf.h"
37 #include "moab/Interface.hpp"
38 #include "moab/Range.hpp"
39 #include "moab/CN.hpp"
40 #include "Internals.hpp"
41 #include "ExoIIUtil.hpp"
42 #include "MBTagConventions.hpp"
43 #include "moab/WriteUtilIface.hpp"
44 
45 #ifndef MOAB_HAVE_NETCDF
46 #error Attempt to compile WriteSLAC with NetCDF disabled.
47 #endif
48 
49 namespace moab
50 {
51 
52 #define INS_ID( stringvar, prefix, id ) sprintf( stringvar, prefix, id )
53 
54 #define GET_VAR( name, id, dims ) \
55  { \
56  ( id ) = -1; \
57  int gvfail = nc_inq_varid( ncFile, name, &( id ) ); \
58  if( NC_NOERR == gvfail ) \
59  { \
60  int ndims; \
61  gvfail = nc_inq_varndims( ncFile, id, &ndims ); \
62  if( NC_NOERR == gvfail ) \
63  { \
64  ( dims ).resize( ndims ); \
65  gvfail = nc_inq_vardimid( ncFile, id, &( dims )[0] ); \
66  } \
67  } \
68  }
69 
71 {
72  return new WriteSLAC( iface );
73 }
74 
75 WriteSLAC::WriteSLAC( Interface* impl ) : mbImpl( impl ), ncFile( 0 )
76 {
77  assert( impl != NULL );
78 
80 
81  // Initialize in case tag_get_handle fails below
82  //! get and cache predefined tag handles
83  int negone = -1;
85  &negone );
86 
88  &negone );
89 
91  &negone );
92 
93  mGlobalIdTag = impl->globalId_tag();
94 
95  int dum_val = -1;
96  impl->tag_get_handle( "__matSetIdTag", 1, MB_TYPE_INTEGER, mMatSetIdTag, MB_TAG_DENSE | MB_TAG_CREAT, &dum_val );
97 
98  impl->tag_get_handle( "WriteSLAC element mark", 1, MB_TYPE_BIT, mEntityMark, MB_TAG_CREAT );
99 }
100 
102 {
105 }
106 
107 void WriteSLAC::reset_matset( std::vector< WriteSLAC::MaterialSetData >& matset_info )
108 {
109  std::vector< WriteSLAC::MaterialSetData >::iterator iter;
110 
111  for( iter = matset_info.begin(); iter != matset_info.end(); ++iter )
112  delete( *iter ).elements;
113 }
114 
115 ErrorCode WriteSLAC::write_file( const char* file_name,
116  const bool overwrite,
117  const FileOptions&,
118  const EntityHandle* ent_handles,
119  const int num_sets,
120  const std::vector< std::string >& /* qa_list */,
121  const Tag* /* tag_list */,
122  int /* num_tags */,
123  int /* export_dimension */ )
124 {
125  assert( 0 != mMaterialSetTag && 0 != mNeumannSetTag && 0 != mDirichletSetTag );
126 
127  // Check the file name
128  if( NULL == strstr( file_name, ".ncdf" ) ) return MB_FAILURE;
129 
130  std::vector< EntityHandle > matsets, dirsets, neusets, entities;
131 
132  fileName = file_name;
133 
134  // Separate into material sets, dirichlet sets, neumann sets
135 
136  if( num_sets == 0 )
137  {
138  // Default to all defined sets
139  Range this_range;
140  mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mMaterialSetTag, NULL, 1, this_range );
141  std::copy( this_range.begin(), this_range.end(), std::back_inserter( matsets ) );
142  this_range.clear();
143  mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mDirichletSetTag, NULL, 1, this_range );
144  std::copy( this_range.begin(), this_range.end(), std::back_inserter( dirsets ) );
145  this_range.clear();
146  mbImpl->get_entities_by_type_and_tag( 0, MBENTITYSET, &mNeumannSetTag, NULL, 1, this_range );
147  std::copy( this_range.begin(), this_range.end(), std::back_inserter( neusets ) );
148  }
149  else
150  {
151  int dummy;
152  for( const EntityHandle* iter = ent_handles; iter < ent_handles + num_sets; ++iter )
153  {
154  if( MB_SUCCESS == mbImpl->tag_get_data( mMaterialSetTag, &( *iter ), 1, &dummy ) )
155  matsets.push_back( *iter );
156  else if( MB_SUCCESS == mbImpl->tag_get_data( mDirichletSetTag, &( *iter ), 1, &dummy ) )
157  dirsets.push_back( *iter );
158  else if( MB_SUCCESS == mbImpl->tag_get_data( mNeumannSetTag, &( *iter ), 1, &dummy ) )
159  neusets.push_back( *iter );
160  }
161  }
162 
163  // If there is nothing to write just return.
164  if( matsets.empty() && dirsets.empty() && neusets.empty() ) return MB_FILE_WRITE_ERROR;
165 
166  std::vector< WriteSLAC::MaterialSetData > matset_info;
167  std::vector< WriteSLAC::DirichletSetData > dirset_info;
168  std::vector< WriteSLAC::NeumannSetData > neuset_info;
169 
170  MeshInfo mesh_info;
171 
172  matset_info.clear();
173  if( gather_mesh_information( mesh_info, matset_info, neuset_info, dirset_info, matsets, neusets, dirsets ) !=
174  MB_SUCCESS )
175  {
176  reset_matset( matset_info );
177  return MB_FAILURE;
178  }
179 
180  // Try to open the file after gather mesh info succeeds
181  int fail = nc_create( file_name, overwrite ? NC_CLOBBER : NC_NOCLOBBER, &ncFile );
182  if( NC_NOERR != fail )
183  {
184  reset_matset( matset_info );
185  return MB_FAILURE;
186  }
187 
188  if( initialize_file( mesh_info ) != MB_SUCCESS )
189  {
190  reset_matset( matset_info );
191  return MB_FAILURE;
192  }
193 
194  if( write_nodes( mesh_info.num_nodes, mesh_info.nodes, mesh_info.num_dim ) != MB_SUCCESS )
195  {
196  reset_matset( matset_info );
197  return MB_FAILURE;
198  }
199 
200  if( write_matsets( mesh_info, matset_info, neuset_info ) )
201  {
202  reset_matset( matset_info );
203  return MB_FAILURE;
204  }
205 
206  fail = nc_close( ncFile );
207  if( NC_NOERR != fail ) return MB_FAILURE;
208 
209  return MB_SUCCESS;
210 }
211 
213  std::vector< WriteSLAC::MaterialSetData >& matset_info,
214  std::vector< WriteSLAC::NeumannSetData >& neuset_info,
215  std::vector< WriteSLAC::DirichletSetData >& dirset_info,
216  std::vector< EntityHandle >& matsets,
217  std::vector< EntityHandle >& neusets,
218  std::vector< EntityHandle >& dirsets )
219 {
220  std::vector< EntityHandle >::iterator vector_iter, end_vector_iter;
221 
222  mesh_info.num_nodes = 0;
223  mesh_info.num_elements = 0;
224  mesh_info.num_matsets = 0;
225 
226  int id = 0;
227 
228  vector_iter = matsets.begin();
229  end_vector_iter = matsets.end();
230 
231  mesh_info.num_matsets = matsets.size();
232 
233  std::vector< EntityHandle > parent_meshsets;
234 
235  // Clean out the bits for the element mark
237  mbImpl->tag_get_handle( "WriteSLAC element mark", 1, MB_TYPE_BIT, mEntityMark, MB_TAG_CREAT );
238 
239  int highest_dimension_of_element_matsets = 0;
240 
241  for( vector_iter = matsets.begin(); vector_iter != matsets.end(); ++vector_iter )
242  {
243  WriteSLAC::MaterialSetData matset_data;
244  matset_data.elements = new Range;
245 
246  // For the purpose of qa records, get the parents of these matsets
247  if( mbImpl->get_parent_meshsets( *vector_iter, parent_meshsets ) != MB_SUCCESS ) return MB_FAILURE;
248 
249  // Get all Entity Handles in the mesh set
250  Range dummy_range;
251  mbImpl->get_entities_by_handle( *vector_iter, dummy_range, true );
252 
253  // Wait a minute, we are doing some filtering here that doesn't make sense at this level CJS
254 
255  // Find the dimension of the last entity in this range
256  Range::iterator entity_iter = dummy_range.end();
257  entity_iter = dummy_range.end();
258  --entity_iter;
259  int this_dim = CN::Dimension( TYPE_FROM_HANDLE( *entity_iter ) );
260  entity_iter = dummy_range.begin();
261  while( entity_iter != dummy_range.end() && CN::Dimension( TYPE_FROM_HANDLE( *entity_iter ) ) != this_dim )
262  ++entity_iter;
263 
264  if( entity_iter != dummy_range.end() )
265  std::copy( entity_iter, dummy_range.end(), range_inserter( *( matset_data.elements ) ) );
266 
267  assert( matset_data.elements->begin() == matset_data.elements->end() ||
268  CN::Dimension( TYPE_FROM_HANDLE( *( matset_data.elements->begin() ) ) ) == this_dim );
269 
270  // Get the matset's id
271  if( mbImpl->tag_get_data( mMaterialSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS )
272  {
273  MB_SET_ERR( MB_FAILURE, "Couldn't get matset id from a tag for an element matset" );
274  }
275 
276  matset_data.id = id;
277  matset_data.number_attributes = 0;
278 
279  // Iterate through all the elements in the meshset
280  Range::iterator elem_range_iter, end_elem_range_iter;
281  elem_range_iter = matset_data.elements->begin();
282  end_elem_range_iter = matset_data.elements->end();
283 
284  // Get the entity type for this matset, verifying that it's the same for all elements
285  // THIS ASSUMES HANDLES SORT BY TYPE!!!
286  EntityType entity_type = TYPE_FROM_HANDLE( *elem_range_iter );
287  --end_elem_range_iter;
288  if( entity_type != TYPE_FROM_HANDLE( *( end_elem_range_iter++ ) ) )
289  {
290  MB_SET_ERR( MB_FAILURE, "Entities in matset " << id << " not of common type" );
291  }
292 
293  int dimension = -1;
294  if( entity_type == MBQUAD || entity_type == MBTRI )
295  dimension = 3; // Output shells by default
296  else if( entity_type == MBEDGE )
297  dimension = 2;
298  else
299  dimension = CN::Dimension( entity_type );
300 
301  if( dimension > highest_dimension_of_element_matsets ) highest_dimension_of_element_matsets = dimension;
302 
303  matset_data.moab_type = mbImpl->type_from_handle( *( matset_data.elements->begin() ) );
304  if( MBMAXTYPE == matset_data.moab_type ) return MB_FAILURE;
305 
306  std::vector< EntityHandle > tmp_conn;
307  mbImpl->get_connectivity( &( *( matset_data.elements->begin() ) ), 1, tmp_conn );
308  matset_data.element_type =
309  ExoIIUtil::get_element_type_from_num_verts( tmp_conn.size(), entity_type, dimension );
310 
311  if( matset_data.element_type == EXOII_MAX_ELEM_TYPE )
312  {
313  MB_SET_ERR( MB_FAILURE, "Element type in matset " << id << " didn't get set correctly" );
314  }
315 
317 
318  // Number of nodes for this matset
319  matset_data.number_elements = matset_data.elements->size();
320 
321  // Total number of elements
322  mesh_info.num_elements += matset_data.number_elements;
323 
324  // Get the nodes for the elements
325  mWriteIface->gather_nodes_from_elements( *matset_data.elements, mEntityMark, mesh_info.nodes );
326 
327  if( !neusets.empty() )
328  {
329  // If there are neusets, keep track of which elements are being written out
330  for( Range::iterator iter = matset_data.elements->begin(); iter != matset_data.elements->end(); ++iter )
331  {
332  unsigned char bit = 0x1;
333  mbImpl->tag_set_data( mEntityMark, &( *iter ), 1, &bit );
334  }
335  }
336 
337  matset_info.push_back( matset_data );
338  }
339 
340  // If user hasn't entered dimension, we figure it out
341  if( mesh_info.num_dim == 0 )
342  {
343  // Never want 1 or zero dimensions
344  if( highest_dimension_of_element_matsets < 2 )
345  mesh_info.num_dim = 3;
346  else
347  mesh_info.num_dim = highest_dimension_of_element_matsets;
348  }
349 
350  Range::iterator range_iter, end_range_iter;
351  range_iter = mesh_info.nodes.begin();
352  end_range_iter = mesh_info.nodes.end();
353 
354  mesh_info.num_nodes = mesh_info.nodes.size();
355 
356  //------dirsets--------
357 
358  vector_iter = dirsets.begin();
359  end_vector_iter = dirsets.end();
360 
361  for( ; vector_iter != end_vector_iter; ++vector_iter )
362  {
363  WriteSLAC::DirichletSetData dirset_data;
364  dirset_data.id = 0;
365  dirset_data.number_nodes = 0;
366 
367  // Get the dirset's id
368  if( mbImpl->tag_get_data( mDirichletSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS )
369  {
370  MB_SET_ERR( MB_FAILURE, "Couldn't get id tag for dirset " << id );
371  }
372 
373  dirset_data.id = id;
374 
375  std::vector< EntityHandle > node_vector;
376  // Get the nodes of the dirset that are in mesh_info.nodes
377  if( mbImpl->get_entities_by_handle( *vector_iter, node_vector, true ) != MB_SUCCESS )
378  {
379  MB_SET_ERR( MB_FAILURE, "Couldn't get nodes in dirset " << id );
380  }
381 
382  std::vector< EntityHandle >::iterator iter, end_iter;
383  iter = node_vector.begin();
384  end_iter = node_vector.end();
385 
386  int j = 0;
387  unsigned char node_marked = 0;
388  ErrorCode result;
389  for( ; iter != end_iter; ++iter )
390  {
391  if( TYPE_FROM_HANDLE( *iter ) != MBVERTEX ) continue;
392  result = mbImpl->tag_get_data( mEntityMark, &( *iter ), 1, &node_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" );
393 
394  if( 0x1 == node_marked ) dirset_data.nodes.push_back( *iter );
395  j++;
396  }
397 
398  dirset_data.number_nodes = dirset_data.nodes.size();
399  dirset_info.push_back( dirset_data );
400  }
401 
402  //------neusets--------
403  vector_iter = neusets.begin();
404  end_vector_iter = neusets.end();
405 
406  for( ; vector_iter != end_vector_iter; ++vector_iter )
407  {
408  WriteSLAC::NeumannSetData neuset_data;
409 
410  // Get the neuset's id
411  if( mbImpl->tag_get_data( mNeumannSetTag, &( *vector_iter ), 1, &id ) != MB_SUCCESS ) return MB_FAILURE;
412 
413  neuset_data.id = id;
414  neuset_data.mesh_set_handle = *vector_iter;
415 
416  // Get the sides in two lists, one forward the other reverse; starts with forward sense
417  // by convention
418  Range forward_elems, reverse_elems;
419  if( get_neuset_elems( *vector_iter, 0, forward_elems, reverse_elems ) == MB_FAILURE ) return MB_FAILURE;
420 
421  ErrorCode result = get_valid_sides( forward_elems, 1, neuset_data );MB_CHK_SET_ERR( result, "Couldn't get valid sides data" );
422  result = get_valid_sides( reverse_elems, -1, neuset_data );MB_CHK_SET_ERR( result, "Couldn't get valid sides data" );
423 
424  neuset_data.number_elements = neuset_data.elements.size();
425  neuset_info.push_back( neuset_data );
426  }
427 
428  // Get information about interior/exterior tets/hexes, and mark matset ids
429  return gather_interior_exterior( mesh_info, matset_info, neuset_info );
430 }
431 
432 ErrorCode WriteSLAC::get_valid_sides( Range& elems, const int sense, WriteSLAC::NeumannSetData& neuset_data )
433 {
434  // This is where we see if underlying element of side set element is included in output
435 
436  unsigned char element_marked = 0;
437  ErrorCode result;
438  for( Range::iterator iter = elems.begin(); iter != elems.end(); ++iter )
439  {
440  // Should insert here if "side" is a quad/tri on a quad/tri mesh
441  result = mbImpl->tag_get_data( mEntityMark, &( *iter ), 1, &element_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" );
442 
443  if( 0x1 == element_marked )
444  {
445  neuset_data.elements.push_back( *iter );
446 
447  // TJT TODO: the sense should really be # edges + 1or2
448  neuset_data.side_numbers.push_back( ( sense == 1 ? 1 : 2 ) );
449  }
450  else
451  { // Then "side" is probably a quad/tri on a hex/tet mesh
452  std::vector< EntityHandle > parents;
453  int dimension = CN::Dimension( TYPE_FROM_HANDLE( *iter ) );
454 
455  // Get the adjacent parent element of "side"
456  if( mbImpl->get_adjacencies( &( *iter ), 1, dimension + 1, false, parents ) != MB_SUCCESS )
457  {
458  MB_SET_ERR( MB_FAILURE, "Couldn't get adjacencies for neuset" );
459  }
460 
461  if( !parents.empty() )
462  {
463  // Make sure the adjacent parent element will be output
464  for( unsigned int k = 0; k < parents.size(); k++ )
465  {
466  result = mbImpl->tag_get_data( mEntityMark, &( parents[k] ), 1, &element_marked );MB_CHK_SET_ERR( result, "Couldn't get mark data" );
467 
468  int side_no, this_sense, this_offset;
469  if( 0x1 == element_marked &&
470  mbImpl->side_number( parents[k], *iter, side_no, this_sense, this_offset ) == MB_SUCCESS &&
471  this_sense == sense )
472  {
473  neuset_data.elements.push_back( parents[k] );
474  neuset_data.side_numbers.push_back( side_no + 1 );
475  break;
476  }
477  }
478  }
479  else
480  {
481  MB_SET_ERR( MB_FAILURE, "No parent element exists for element in neuset " << neuset_data.id );
482  }
483  }
484  }
485 
486  return MB_SUCCESS;
487 }
488 
489 ErrorCode WriteSLAC::write_nodes( const int num_nodes, const Range& nodes, const int dimension )
490 {
491  // See if should transform coordinates
492  ErrorCode result;
493  Tag trans_tag;
494  result = mbImpl->tag_get_handle( MESH_TRANSFORM_TAG_NAME, 16, MB_TYPE_DOUBLE, trans_tag );
495  bool transform_needed = true;
496  if( result == MB_TAG_NOT_FOUND ) transform_needed = false;
497 
498  int num_coords_to_fill = transform_needed ? 3 : dimension;
499 
500  std::vector< double* > coord_arrays( 3 );
501  coord_arrays[0] = new double[num_nodes];
502  coord_arrays[1] = new double[num_nodes];
503  coord_arrays[2] = NULL;
504 
505  if( num_coords_to_fill == 3 ) coord_arrays[2] = new double[num_nodes];
506 
507  result = mWriteIface->get_node_coords( dimension, num_nodes, nodes, mGlobalIdTag, 0, coord_arrays );
508  if( result != MB_SUCCESS )
509  {
510  delete[] coord_arrays[0];
511  delete[] coord_arrays[1];
512  if( coord_arrays[2] ) delete[] coord_arrays[2];
513  return result;
514  }
515 
516  if( transform_needed )
517  {
518  double trans_matrix[16];
519  const EntityHandle mesh = 0;
520  result = mbImpl->tag_get_data( trans_tag, &mesh, 1, trans_matrix );MB_CHK_SET_ERR( result, "Couldn't get transform data" );
521 
522  for( int i = 0; i < num_nodes; i++ )
523  {
524  double vec1[3];
525  double vec2[3];
526 
527  vec2[0] = coord_arrays[0][i];
528  vec2[1] = coord_arrays[1][i];
529  vec2[2] = coord_arrays[2][i];
530 
531  for( int row = 0; row < 3; row++ )
532  {
533  vec1[row] = 0.0;
534  for( int col = 0; col < 3; col++ )
535  vec1[row] += ( trans_matrix[( row * 4 ) + col] * vec2[col] );
536  }
537 
538  coord_arrays[0][i] = vec1[0];
539  coord_arrays[1][i] = vec1[1];
540  coord_arrays[2][i] = vec1[2];
541  }
542  }
543 
544  // Write the nodes
545  int nc_var = -1;
546  std::vector< int > dims;
547  GET_VAR( "coords", nc_var, dims );
548  if( -1 == nc_var ) return MB_FAILURE;
549  size_t start[2] = { 0, 0 }, count[2] = { static_cast< size_t >( num_nodes ), 1 };
550  int fail = nc_put_vara_double( ncFile, nc_var, start, count, coord_arrays[0] );
551  if( NC_NOERR != fail ) return MB_FAILURE;
552  start[1] = 1;
553  fail = nc_put_vara_double( ncFile, nc_var, start, count, coord_arrays[1] );
554  if( NC_NOERR != fail ) return MB_FAILURE;
555  start[1] = 2;
556  fail = nc_put_vara_double( ncFile, nc_var, start, count, coord_arrays[2] );
557  if( NC_NOERR != fail ) return MB_FAILURE;
558 
559  delete[] coord_arrays[0];
560  delete[] coord_arrays[1];
561  if( coord_arrays[2] ) delete[] coord_arrays[2];
562 
563  return MB_SUCCESS;
564 }
565 
567  std::vector< WriteSLAC::MaterialSetData >& matset_data,
568  std::vector< WriteSLAC::NeumannSetData >& neuset_data )
569 {
570  // Need to assign a tag with the matset id
571  Tag matset_id_tag;
572  unsigned int i;
573  int dum = -1;
574  ErrorCode result =
575  mbImpl->tag_get_handle( "__matset_id", 4, MB_TYPE_INTEGER, matset_id_tag, MB_TAG_DENSE | MB_TAG_CREAT, &dum );
576  if( MB_SUCCESS != result ) return result;
577 
578  Range::iterator rit;
579  mesh_info.num_int_hexes = mesh_info.num_int_tets = 0;
580 
581  for( i = 0; i < matset_data.size(); i++ )
582  {
583  WriteSLAC::MaterialSetData matset = matset_data[i];
584  if( matset.moab_type == MBHEX )
585  mesh_info.num_int_hexes += matset.elements->size();
586  else if( matset.moab_type == MBTET )
587  mesh_info.num_int_tets += matset.elements->size();
588  else
589  {
590  std::cout << "WriteSLAC doesn't support elements of type " << CN::EntityTypeName( matset.moab_type )
591  << std::endl;
592  continue;
593  }
594 
595  for( rit = matset.elements->begin(); rit != matset.elements->end(); ++rit )
596  {
597  result = mbImpl->tag_set_data( mMatSetIdTag, &( *rit ), 1, &( matset.id ) );
598  if( MB_SUCCESS != result ) return result;
599  }
600  }
601 
602  // Now go through the neumann sets, pulling out the hexes with faces on the
603  // boundary
604  std::vector< EntityHandle >::iterator vit;
605  for( i = 0; i < neuset_data.size(); i++ )
606  {
607  WriteSLAC::NeumannSetData neuset = neuset_data[i];
608  for( vit = neuset.elements.begin(); vit != neuset.elements.end(); ++vit )
609  {
610  if( TYPE_FROM_HANDLE( *vit ) == MBHEX )
611  mesh_info.bdy_hexes.insert( *vit );
612  else if( TYPE_FROM_HANDLE( *vit ) == MBTET )
613  mesh_info.bdy_tets.insert( *vit );
614  }
615  }
616 
617  // Now we have the number of bdy hexes and tets, we know how many interior ones
618  // there are too
619  mesh_info.num_int_hexes -= mesh_info.bdy_hexes.size();
620  mesh_info.num_int_tets -= mesh_info.bdy_tets.size();
621 
622  return MB_SUCCESS;
623 }
624 
626  std::vector< WriteSLAC::MaterialSetData >& matset_data,
627  std::vector< WriteSLAC::NeumannSetData >& neuset_data )
628 {
629  unsigned int i;
630  std::vector< int > connect;
631  const EntityHandle* connecth;
632  int num_connecth;
633  ErrorCode result;
634 
635  // First write the interior hexes
636  int hex_conn = -1;
637  std::vector< int > dims;
638  if( mesh_info.bdy_hexes.size() != 0 || mesh_info.num_int_hexes != 0 )
639  {
640  GET_VAR( "hexahedron_interior", hex_conn, dims );
641  if( -1 == hex_conn ) return MB_FAILURE;
642  }
643  connect.reserve( 13 );
644  Range::iterator rit;
645 
646  int elem_num = 0;
648  size_t start[2] = { 0, 0 }, count[2] = { 1, 1 };
649  int fail;
650  for( i = 0; i < matset_data.size(); i++ )
651  {
652  matset = matset_data[i];
653  if( matset.moab_type != MBHEX ) continue;
654 
655  int id = matset.id;
656  connect[0] = id;
657 
658  for( rit = matset.elements->begin(); rit != matset.elements->end(); ++rit )
659  {
660  // Skip if it's on the bdy
661  if( mesh_info.bdy_hexes.find( *rit ) != mesh_info.bdy_hexes.end() ) continue;
662 
663  // Get the connectivity of this element
664  result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
665  if( MB_SUCCESS != result ) return result;
666 
667  // Get the vertex ids
668  result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
669  if( MB_SUCCESS != result ) return result;
670 
671  // Put the variable at the right position
672  start[0] = elem_num++;
673  count[1] = 9;
674 
675  // Write the data
676  fail = nc_put_vara_int( ncFile, hex_conn, start, count, &connect[0] );
677  if( NC_NOERR != fail ) return MB_FAILURE;
678  }
679  }
680 
681  int tet_conn = -1;
682  if( mesh_info.bdy_tets.size() != 0 || mesh_info.num_int_tets != 0 )
683  {
684  GET_VAR( "tetrahedron_interior", tet_conn, dims );
685  if( -1 == tet_conn ) return MB_FAILURE;
686  }
687 
688  // Now the interior tets
689  elem_num = 0;
690  for( i = 0; i < matset_data.size(); i++ )
691  {
692  matset = matset_data[i];
693  if( matset.moab_type != MBTET ) continue;
694 
695  int id = matset.id;
696  connect[0] = id;
697  elem_num = 0;
698  for( rit = matset.elements->begin(); rit != matset.elements->end(); ++rit )
699  {
700  // Skip if it's on the bdy
701  if( mesh_info.bdy_tets.find( *rit ) != mesh_info.bdy_tets.end() ) continue;
702 
703  // Get the connectivity of this element
704  result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
705  if( MB_SUCCESS != result ) return result;
706 
707  // Get the vertex ids
708  result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
709  if( MB_SUCCESS != result ) return result;
710 
711  // Put the variable at the right position
712  start[0] = elem_num++;
713  count[1] = 5;
714  fail = nc_put_vara_int( ncFile, tet_conn, start, count, &connect[0] );
715  // Write the data
716  if( NC_NOERR != fail ) return MB_FAILURE;
717  }
718  }
719 
720  // Now the exterior hexes
721  if( mesh_info.bdy_hexes.size() != 0 )
722  {
723  hex_conn = -1;
724  GET_VAR( "hexahedron_exterior", hex_conn, dims );
725  if( -1 == hex_conn ) return MB_FAILURE;
726 
727  connect.reserve( 15 );
728  elem_num = 0;
729 
730  // Write the elements
731  for( rit = mesh_info.bdy_hexes.begin(); rit != mesh_info.bdy_hexes.end(); ++rit )
732  {
733  // Get the material set for this hex
734  result = mbImpl->tag_get_data( mMatSetIdTag, &( *rit ), 1, &connect[0] );
735  if( MB_SUCCESS != result ) return result;
736 
737  // Get the connectivity of this element
738  result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
739  if( MB_SUCCESS != result ) return result;
740 
741  // Get the vertex ids
742  result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
743  if( MB_SUCCESS != result ) return result;
744 
745  // Preset side numbers
746  for( i = 9; i < 15; i++ )
747  connect[i] = -1;
748 
749  // Now write the side numbers
750  for( i = 0; i < neuset_data.size(); i++ )
751  {
752  std::vector< EntityHandle >::iterator vit =
753  std::find( neuset_data[i].elements.begin(), neuset_data[i].elements.end(), *rit );
754  while( vit != neuset_data[i].elements.end() )
755  {
756  // Have a side - get the side # and put in connect array
757  int side_no = neuset_data[i].side_numbers[vit - neuset_data[i].elements.begin()];
758  connect[9 + side_no] = neuset_data[i].id;
759  ++vit;
760  vit = std::find( vit, neuset_data[i].elements.end(), *rit );
761  }
762  }
763 
764  // Put the variable at the right position
765  start[0] = elem_num++;
766  count[1] = 15;
767  fail = nc_put_vara_int( ncFile, hex_conn, start, count, &connect[0] );
768  // Write the data
769  if( NC_NOERR != fail ) return MB_FAILURE;
770  }
771  }
772 
773  // Now the exterior tets
774  if( mesh_info.bdy_tets.size() != 0 )
775  {
776  tet_conn = -1;
777  GET_VAR( "tetrahedron_exterior", tet_conn, dims );
778  if( -1 == tet_conn ) return MB_FAILURE;
779 
780  connect.reserve( 9 );
781  elem_num = 0;
782 
783  // Write the elements
784  for( rit = mesh_info.bdy_tets.begin(); rit != mesh_info.bdy_tets.end(); ++rit )
785  {
786  // Get the material set for this tet
787  result = mbImpl->tag_get_data( mMatSetIdTag, &( *rit ), 1, &connect[0] );
788  if( MB_SUCCESS != result ) return result;
789 
790  // Get the connectivity of this element
791  result = mbImpl->get_connectivity( *rit, connecth, num_connecth );
792  if( MB_SUCCESS != result ) return result;
793 
794  // Get the vertex ids
795  result = mbImpl->tag_get_data( mGlobalIdTag, connecth, num_connecth, &connect[1] );
796  if( MB_SUCCESS != result ) return result;
797 
798  // Preset side numbers
799  for( i = 5; i < 9; i++ )
800  connect[i] = -1;
801 
802  // Now write the side numbers
803  for( i = 0; i < neuset_data.size(); i++ )
804  {
805  std::vector< EntityHandle >::iterator vit =
806  std::find( neuset_data[i].elements.begin(), neuset_data[i].elements.end(), *rit );
807  while( vit != neuset_data[i].elements.end() )
808  {
809  // Have a side - get the side # and put in connect array
810  int side_no = neuset_data[i].side_numbers[vit - neuset_data[i].elements.begin()];
811  connect[5 + side_no] = neuset_data[i].id;
812  ++vit;
813  vit = std::find( vit, neuset_data[i].elements.end(), *rit );
814  }
815  }
816 
817  // Put the variable at the right position
818  start[0] = elem_num++;
819  count[1] = 9;
820  fail = nc_put_vara_int( ncFile, tet_conn, start, count, &connect[0] );
821  // Write the data
822  if( NC_NOERR != fail ) return MB_FAILURE;
823  }
824  }
825 
826  return MB_SUCCESS;
827 }
828 
830 {
831  // Perform the initializations
832 
833  int coord_size = -1, ncoords = -1;
834  // Initialization to avoid warnings on Linux
835  int hexinterior = -1, hexinteriorsize, hexexterior = -1, hexexteriorsize = -1;
836  int tetinterior = -1, tetinteriorsize, tetexterior = -1, tetexteriorsize = -1;
837 
838  if( nc_def_dim( ncFile, "coord_size", (size_t)mesh_info.num_dim, &coord_size ) != NC_NOERR )
839  {
840  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of dimensions" );
841  }
842 
843  if( nc_def_dim( ncFile, "ncoords", (size_t)mesh_info.num_nodes, &ncoords ) != NC_NOERR )
844  {
845  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of nodes" );
846  }
847 
848  if( 0 != mesh_info.num_int_hexes &&
849  nc_def_dim( ncFile, "hexinterior", (size_t)mesh_info.num_int_hexes, &hexinterior ) != NC_NOERR )
850  {
851  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of interior hex elements" );
852  }
853 
854  if( nc_def_dim( ncFile, "hexinteriorsize", (size_t)9, &hexinteriorsize ) != NC_NOERR )
855  {
856  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define interior hex element size" );
857  }
858 
859  if( 0 != mesh_info.bdy_hexes.size() &&
860  nc_def_dim( ncFile, "hexexterior", (size_t)mesh_info.bdy_hexes.size(), &hexexterior ) != NC_NOERR )
861  {
862  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of exterior hex elements" );
863  }
864 
865  if( nc_def_dim( ncFile, "hexexteriorsize", (size_t)15, &hexexteriorsize ) != NC_NOERR )
866  {
867  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define exterior hex element size" );
868  }
869 
870  if( 0 != mesh_info.num_int_tets &&
871  nc_def_dim( ncFile, "tetinterior", (size_t)mesh_info.num_int_tets, &tetinterior ) != NC_NOERR )
872  {
873  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of interior tet elements" );
874  }
875 
876  if( nc_def_dim( ncFile, "tetinteriorsize", (size_t)5, &tetinteriorsize ) != NC_NOERR )
877  {
878  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define interior tet element size" );
879  }
880 
881  if( 0 != mesh_info.bdy_tets.size() &&
882  nc_def_dim( ncFile, "tetexterior", (size_t)mesh_info.bdy_tets.size(), &tetexterior ) != NC_NOERR )
883  {
884  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define number of exterior tet elements" );
885  }
886 
887  if( nc_def_dim( ncFile, "tetexteriorsize", (size_t)9, &tetexteriorsize ) != NC_NOERR )
888  {
889  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define exterior tet element size" );
890  }
891 
892  /* ...and some variables */
893 
894  int dims[2];
895  dims[0] = hexinterior;
896  dims[1] = hexinteriorsize;
897  int dum_var;
898  if( 0 != mesh_info.num_int_hexes &&
899  NC_NOERR != nc_def_var( ncFile, "hexahedron_interior", NC_LONG, 2, dims, &dum_var ) )
900  {
901  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for interior hexes" );
902  }
903 
904  dims[0] = hexexterior;
905  dims[1] = hexexteriorsize;
906  if( 0 != mesh_info.bdy_hexes.size() &&
907  NC_NOERR != nc_def_var( ncFile, "hexahedron_exterior", NC_LONG, 2, dims, &dum_var ) )
908  {
909  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for exterior hexes" );
910  }
911 
912  dims[0] = tetinterior;
913  dims[1] = tetinteriorsize;
914  if( 0 != mesh_info.num_int_tets &&
915  NC_NOERR != nc_def_var( ncFile, "tetrahedron_exterior", NC_LONG, 2, dims, &dum_var ) )
916  {
917  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for interior tets" );
918  }
919 
920  dims[0] = tetexterior;
921  dims[1] = tetexteriorsize;
922  if( 0 != mesh_info.bdy_tets.size() &&
923  NC_NOERR != nc_def_var( ncFile, "tetrahedron_exterior", NC_LONG, 2, dims, &dum_var ) )
924  {
925  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to create connectivity array for exterior tets" );
926  }
927 
928  /* Node coordinate arrays: */
929 
930  dims[0] = ncoords;
931  dims[1] = coord_size;
932  if( NC_NOERR != nc_def_var( ncFile, "coords", NC_DOUBLE, 2, dims, &dum_var ) )
933  {
934  MB_SET_ERR( MB_FAILURE, "WriteSLAC: failed to define node coordinate array" );
935  }
936 
937  return MB_SUCCESS;
938 }
939 
940 ErrorCode WriteSLAC::open_file( const char* filename )
941 {
942  // Not a valid filname
943  if( strlen( (const char*)filename ) == 0 )
944  {
945  MB_SET_ERR( MB_FAILURE, "Output filename not specified" );
946  }
947 
948  int fail = nc_create( filename, NC_CLOBBER, &ncFile );
949  // File couldn't be opened
950  if( NC_NOERR != fail )
951  {
952  MB_SET_ERR( MB_FAILURE, "Cannot open " << filename );
953  }
954 
955  return MB_SUCCESS;
956 }
957 
959  int current_sense,
960  Range& forward_elems,
961  Range& reverse_elems )
962 {
963  Range ss_elems, ss_meshsets;
964 
965  // Get the sense tag; don't need to check return, might be an error if the tag
966  // hasn't been created yet
967  Tag sense_tag = 0;
968  mbImpl->tag_get_handle( "SENSE", 1, MB_TYPE_INTEGER, sense_tag );
969 
970  // Get the entities in this set
971  ErrorCode result = mbImpl->get_entities_by_handle( neuset, ss_elems, true );
972  if( MB_FAILURE == result ) return result;
973 
974  // Now remove the meshsets into the ss_meshsets; first find the first meshset,
975  Range::iterator range_iter = ss_elems.begin();
976  while( TYPE_FROM_HANDLE( *range_iter ) != MBENTITYSET && range_iter != ss_elems.end() )
977  ++range_iter;
978 
979  // Then, if there are some, copy them into ss_meshsets and erase from ss_elems
980  if( range_iter != ss_elems.end() )
981  {
982  std::copy( range_iter, ss_elems.end(), range_inserter( ss_meshsets ) );
983  ss_elems.erase( range_iter, ss_elems.end() );
984  }
985 
986  // OK, for the elements, check the sense of this set and copy into the right range
987  // (if the sense is 0, copy into both ranges)
988 
989  // Need to step forward on list until we reach the right dimension
990  Range::iterator dum_it = ss_elems.end();
991  --dum_it;
992  int target_dim = CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) );
993  dum_it = ss_elems.begin();
994  while( target_dim != CN::Dimension( TYPE_FROM_HANDLE( *dum_it ) ) && dum_it != ss_elems.end() )
995  ++dum_it;
996 
997  if( current_sense == 1 || current_sense == 0 ) std::copy( dum_it, ss_elems.end(), range_inserter( forward_elems ) );
998  if( current_sense == -1 || current_sense == 0 )
999  std::copy( dum_it, ss_elems.end(), range_inserter( reverse_elems ) );
1000 
1001  // Now loop over the contained meshsets, getting the sense of those and calling this
1002  // function recursively
1003  for( range_iter = ss_meshsets.begin(); range_iter != ss_meshsets.end(); ++range_iter )
1004  {
1005  // First get the sense; if it's not there, by convention it's forward
1006  int this_sense;
1007  if( 0 == sense_tag || MB_FAILURE == mbImpl->tag_get_data( sense_tag, &( *range_iter ), 1, &this_sense ) )
1008  this_sense = 1;
1009 
1010  // Now get all the entities on this meshset, with the proper (possibly reversed) sense
1011  get_neuset_elems( *range_iter, this_sense * current_sense, forward_elems, reverse_elems );
1012  }
1013 
1014  return result;
1015 }
1016 
1017 } // namespace moab