Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
propagate_tags.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2005 Lawrence Livermore National Laboratory under
3  * contract number B545069 with the University of Wisconsin - Madison.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <iostream>
27 #include <vector>
28 #include <cstdlib>
29 
30 #include "parse.hpp"
31 
32 #include "moab/Core.hpp"
33 #include "moab/Range.hpp"
34 #include "moab/Interface.hpp"
35 #define IS_BUILDING_MB
36 #include "Internals.hpp"
37 #undef IS_BUILDING_MB
38 
39 using namespace moab;
40 
41 #define CALL( A, B ) \
42  do \
43  { \
44  ErrorCode _r = iface->A B; \
45  if( MB_SUCCESS != _r ) \
46  { \
47  std::cerr << #A << #B << " failed at " << __FILE__ << ":" << __LINE__ << std::endl; \
48  exit( 5 ); \
49  } \
50  } while( false )
51 
53 const char* exe_name = 0;
54 
55 static void usage( bool error = true )
56 {
57  std::ostream& s = error ? std::cerr : std::cout;
58 
59  s << "Usage: " << exe_name << " <options> <input_file> <output_file>" << std::endl
60  << " " << exe_name << " -h" << std::endl
61  << "Options: " << std::endl
62  << " -t <ident_tag>[=<value>] " << std::endl
63  << " -d <data_tag>[=<default>] " << std::endl
64  << " -c <data_tag=type:size>[=defult] " << std::endl
65  << " -w <write_tag> " << std::endl
66  << " -n|-e|-E " << std::endl
67  << std::endl;
68  if( error )
69  {
70  s << "Try '-h' for verbose help." << std::endl;
71  exit( 1 );
72  }
73 
74  s << "This utility will write tag data to a subset of the mesh entities " << std::endl
75  << "contained in a file. The behavior is controlled by three main " << std::endl
76  << "properties:" << std::endl
77  << " 1) The ident_tag is used to identify sets of entities for which " << std::endl
78  << " data will be stored on each contained element or node. The -n " << std::endl
79  << " or -e flags can be used to restrict operation to only nodes or " << std::endl
80  << " elements, respectively." << std::endl
81  << " 2) The data_tag is used to identify which value to write on to " << std::endl
82  << " each entity. This is a tag on the set containing the entities." << std::endl
83  << " 3) The write_tag is the name of the tag that the data is stored in " << std::endl
84  << " on each mesh entity." << std::endl
85  << std::endl
86  << " -t : Specify an ident_tag. If a value is specified, only those " << std::endl
87  << " sets with the specified value are processed. At least one " << std::endl
88  << " ident_tag must be specified. Multiple ident_tags may be " << std::endl
89  << " specified, in which case any set that matches any of the " << std::endl
90  << " specified ident_tags will be processed (logical OR)." << std::endl
91  << std::endl
92  << " -d : Specify the data_tag. If multiple ident_tags are specified " << std::endl
93  << " then the data_tag must be specified. If only one ident_tag " << std::endl
94  << " is specified then the data_tag specification is optional." << std::endl
95  << " If no data_tag is specified, the value of the ident_tag " << std::endl
96  << " will be used. If a value is specified for the data_tag, " << std::endl
97  << " then the specified value will be used for any set that " << std::endl
98  << " doesn't have a value for the data_tag." << std::endl
99  << std::endl
100  << " -c : Similar to -d, except that the tag is created if it doesn't" << std::endl
101  << " already exist. If the tag is created, then all entities" << std::endl
102  << " receive the specified default value for the tag. In this " << std::endl
103  << " case it is an error if no default value is specified." << std::endl
104  << std::endl
105  << " -w : Specify the tag to create and store values in on mesh " << std::endl
106  << " entities. If no write_tag is specified, the data_tag " << std::endl
107  << " will be used." << std::endl
108  << std::endl
109  << " -n : Write tag data only on nodes (vertices)." << std::endl
110  << " -e : Write tag data only on elements." << std::endl
111  << " -E : Tag value on each node is that of one of its adjacent elements." << std::endl
112  << std::endl
113  << "The syntax for specifying tag values is as follows: " << std::endl
114  << std::endl;
115  tag_syntax( s );
116  s << std::endl;
117  exit( 0 );
118 }
119 
120 static void about( bool error = true )
121 {
122  std::ostream& s = error ? std::cerr : std::cout;
123  s << "A utility to propogate tag values from the entity sets "
124  "containing mesh entities to the entities contained in "
125  "those sets."
126  << std::endl
127  << std::endl;
128  usage( error );
129 }
130 
131 static void parse_error( const char* msg, const char* val = 0 )
132 {
133  std::cerr << msg;
134  if( val ) std::cerr << ": " << val;
135  std::cerr << std::endl;
136  std::cerr << "Try '" << exe_name << " -h' for help" << std::endl;
137  exit( 1 );
138 }
139 
140 int main( int argc, char* argv[] )
141 {
142  Core mb_core;
143  exe_name = argv[0];
144  iface = &mb_core;
145 
146  if( argc == 1 ) about();
147 
148  // find file names
149  // load input file before processing other options so
150  // tags are defined
151  const char* input_name = 0;
152  const char* output_name = 0;
153  for( int i = 1; i < argc; ++i )
154  {
155  if( argv[i][0] == '-' )
156  {
157  switch( argv[i][1] )
158  {
159  case 't':
160  case 'c':
161  case 'd':
162  case 'w':
163  ++i;
164  case 'n':
165  case 'e':
166  case 'E':
167  break;
168  case 'h':
169  usage( false );
170  break;
171  default:
172  parse_error( "Invalid option", argv[i] );
173  break;
174  }
175  }
176  else if( !input_name )
177  input_name = argv[i];
178  else if( !output_name )
179  output_name = argv[i];
180  else
181  parse_error( "Unexpected argument", argv[i] );
182  }
183 
184  if( !input_name ) parse_error( "No input file specified." );
185  if( !output_name ) parse_error( "No output file specified." );
186 
187  // Read the input file
188  if( MB_SUCCESS != iface->load_mesh( input_name ) )
189  {
190  std::cerr << "Failed to read file: " << input_name << std::endl;
191  std::string message;
192  if( MB_SUCCESS == iface->get_last_error( message ) ) std::cerr << message << std::endl;
193  return 2;
194  }
195 
196  bool nodes_spec = false;
197  bool elems_spec = false;
198  bool node_from_elem_spec = false;
199  bool have_data_tag = false;
200  const char* write_tag_name = 0;
201  Tag write_tag = 0;
202  TagSpec data_tag = { 0, 0 };
203  typedef std::vector< TagSpec > TagVect;
204  TagVect ident_tags;
205  int data_size = 0;
206 
207  for( int i = 1; i < argc; ++i )
208  {
209  if( argv[i] == input_name || argv[i] == output_name )
210  continue;
211  else if( !strcmp( argv[i], "-n" ) )
212  nodes_spec = true;
213  else if( !strcmp( argv[i], "-e" ) )
214  elems_spec = true;
215  else if( !strcmp( argv[i], "-E" ) )
216  {
217  node_from_elem_spec = true;
218  elems_spec = true;
219  nodes_spec = false;
220  }
221  else if( !argv[i][0] )
222  usage();
223  else
224  {
225  char flag = argv[i][1];
226  if( ( flag != 't' && flag != 'd' && flag != 'w' && flag != 'c' ) || argv[i][2] )
227  parse_error( "Invalid argument", argv[i] );
228 
229  ++i;
230  if( i == argc ) parse_error( "Expected tag spec following option", argv[i - 1] );
231 
232  if( flag == 'w' )
233  {
234  if( write_tag_name ) parse_error( "Invalid argument", argv[i] );
235  write_tag_name = argv[i];
236  }
237  else if( flag == 'c' )
238  {
239  TagSpec spec;
240  if( parse_tag_create( argv[i], spec, iface ) ) parse_error( "Failed to parse tag spec", argv[i] );
241 
242  if( have_data_tag ) parse_error( "Invalid argument", argv[i] );
243 
244  data_tag = spec;
245  have_data_tag = true;
246  }
247  else
248  {
249  TagSpec spec;
250  if( parse_tag_spec( argv[i], spec, iface ) ) parse_error( "Failed to parse tag spec", argv[i] );
251 
252  if( flag == 'd' )
253  {
254  if( have_data_tag ) parse_error( "Invalid argument", argv[i] );
255 
256  data_tag = spec;
257  have_data_tag = true;
258  }
259  else
260  {
261  ident_tags.push_back( spec );
262  }
263  }
264  }
265  } // for(args)
266 
267  // if neither, default to both
268  if( !nodes_spec && !elems_spec ) nodes_spec = elems_spec = true;
269 
270  // must have at least one identifying tag
271  if( ident_tags.empty() ) parse_error( "At least one identifying tag must be specified." );
272 
273  // If data tag wasn't specified, use identifying tag for data
274  if( !have_data_tag )
275  {
276  if( ident_tags.size() > 1 ) parse_error( "No data tag specified." );
277  data_tag.value = 0;
278  data_tag.handle = ident_tags[0].handle;
279  }
280  CALL( tag_get_bytes, ( data_tag.handle, data_size ) );
281 
282  // If write dat wasn't specified, use data tag
283  if( !write_tag_name )
284  {
285  write_tag = data_tag.handle;
286  }
287  // If write tag was specified, if it exists its type
288  // msut match that of the data tag. If it doesn't exist,
289  // create it.
290  else
291  {
292  DataType data_type;
293  CALL( tag_get_data_type, ( data_tag.handle, data_type ) );
294 
295  CALL( tag_get_handle,
296  ( write_tag_name, data_size, data_type, write_tag, MB_TAG_SPARSE | MB_TAG_BYTES | MB_TAG_CREAT ) );
297  }
298 
299  /**************** Done processing input -- do actual work ****************/
300 
301  // Get list of sets with identifying tags
302  Range sets, temp;
303  for( TagVect::iterator i = ident_tags.begin(); i != ident_tags.end(); ++i )
304  {
305  const void* value[] = { i->value };
306  CALL( get_entities_by_type_and_tag, ( 0, MBENTITYSET, &i->handle, i->value ? value : 0, 1, temp ) );
307  sets.merge( temp );
308  }
309 
310  // For each set, set tag on contained entities
311  std::vector< unsigned char > tag_data( data_size );
312  for( Range::iterator i = sets.begin(); i != sets.end(); ++i )
313  {
314  // Get tag value
315  ErrorCode rval = iface->tag_get_data( data_tag.handle, &*i, 1, &tag_data[0] );
316  if( MB_TAG_NOT_FOUND == rval )
317  {
318  if( !data_tag.value )
319  {
320  std::cerr << "Data tag not set for entityset " << iface->id_from_handle( *i ) << std::endl;
321  continue;
322  }
323  memcpy( &tag_data[0], data_tag.value, data_size );
324  }
325  else if( MB_SUCCESS != rval )
326  {
327  CALL( tag_get_data, ( data_tag.handle, &*i, 1, &tag_data[0] ) );
328  }
329 
330  // Get entities
331  Range entities;
332  CALL( get_entities_by_handle, ( *i, entities, true ) );
333  int junk;
334  Range::iterator eb = entities.lower_bound( entities.begin(), entities.end(), CREATE_HANDLE( MBEDGE, 0, junk ) );
335  if( elems_spec )
336  for( Range::iterator j = eb; j != entities.end(); ++j )
337  CALL( tag_set_data, ( write_tag, &*j, 1, &tag_data[0] ) );
338  if( nodes_spec )
339  for( Range::iterator j = entities.begin(); j != eb; ++j )
340  CALL( tag_set_data, ( write_tag, &*j, 1, &tag_data[0] ) );
341  if( node_from_elem_spec )
342  {
343  Range elems;
344  elems.merge( eb, entities.end() );
345  entities.clear();
346  CALL( get_adjacencies, ( elems, 0, false, entities, Interface::UNION ) );
347  for( Range::iterator j = entities.begin(); j != entities.end(); ++j )
348  CALL( tag_set_data, ( write_tag, &*j, 1, &tag_data[0] ) );
349  }
350  }
351 
352  // Write the output file
353  if( MB_SUCCESS != iface->write_mesh( output_name ) )
354  {
355  std::cerr << "Failed to write file: " << output_name << std::endl;
356  std::string message;
357  if( MB_SUCCESS == iface->get_last_error( message ) ) std::cerr << message << std::endl;
358  return 2;
359  }
360 
361  return 0;
362 }