Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
compareFiles.cpp
Go to the documentation of this file.
1 /*
2  * compareFiles.cpp
3  * this tool will take two existing h5m files, for the same mesh;
4  * they will both have the same GLOBAL_IDs for the elements, but the entity handles can be
5  * very different (depending on how the mesh was partitioned, and saved in parallel)
6  *
7  * will compare then the difference between tags, and store the result on one of the files (saved
8  * again)
9  *
10  *
11  * example of usage:
12  * ./mbcmpfiles -i file1.h5m -j file2.h5m -n \c tag_name -o out.file
13  *
14  * if no tag name is specified, it will try to compare all tags in the files
15  *
16  *
17  * Basically, will output a new h5m file (out.file), which has an extra tag, corresponding to the
18  * difference between the 2 values
19  *
20  */
21 
22 #include "moab/ProgOptions.hpp"
23 #include "moab/Core.hpp"
24 
25 #include <cmath>
26 #include <sstream>
27 #include <iostream>
28 #include <iomanip>
29 #include <fstream>
30 
31 using namespace moab;
32 using namespace std;
33 
34 int main( int argc, char* argv[] )
35 {
36 
37  ProgOptions opts;
38 
39  std::string inputfile1, inputfile2, outfile;
40 
41  std::string tag_name;
42  int dim = 2;
43 
44  opts.addOpt< std::string >( "input1,i", "input mesh filename 1", &inputfile1 );
45  opts.addOpt< std::string >( "input2,j", "input mesh filename 2", &inputfile2 );
46  opts.addOpt< std::string >( "tagname,n", "tag to compare (compare all tags if not specified)", &tag_name );
47  opts.addOpt< int >( "dimension,d", "topological dimension of entities to compare", &dim );
48  opts.addOpt< std::string >( "outfile,o", "output file with differences", &outfile );
49 
50  opts.parseCommandLine( argc, argv );
51 
52  ErrorCode rval;
53  Core* mb = new Core();
54 
55  MB_CHK_SET_ERR( mb->load_file( inputfile1.c_str() ), "can't load input file 1" );
56 
57  Core* mb2 = new Core();
58  MB_CHK_SET_ERR( mb2->load_file( inputfile2.c_str() ), "can't load input file 2" );
59 
60  std::cout << " opened " << inputfile1 << " and " << inputfile2 << " with initial h5m data.\n";
61  // open the netcdf file, and see if it has that variable we are looking for
62 
63  Range nodes;
64  MB_CHK_SET_ERR( mb->get_entities_by_dimension( 0, 0, nodes ), "can't get nodes" );
65 
66  Range edges;
67  MB_CHK_SET_ERR( mb->get_entities_by_dimension( 0, 1, edges ), "can't get edges" );
68 
69  Range cells;
70  MB_CHK_SET_ERR( mb->get_entities_by_dimension( 0, 2, cells ), "can't get cells" );
71 
72  Range solids;
73  MB_CHK_SET_ERR( mb->get_entities_by_dimension( 0, 3, solids ), "can't get cells" );
74 
75  std::cout << inputfile1 << " has " << nodes.size() << " vertices " << edges.size() << " edges " << cells.size()
76  << " cells " << solids.size() << " solids \n";
77 
78  // construct maps between global id and handles
79 
80  std::map< int, EntityHandle > cGidHandle;
81  std::vector< int > gids;
82  Tag gid = mb->globalId_tag();
83 
84  Range ents = cells;
85  if( dim == 0 ) ents = nodes;
86  if( dim == 1 ) ents = edges;
87  if( dim == 3 ) ents = solids;
88  gids.resize( ents.size() );
89  MB_CHK_SET_ERR( mb->tag_get_data( gid, ents, &gids[0] ), "can't get global id on entities" );
90 
91  int i = 0;
92  for( Range::iterator vit = ents.begin(); vit != ents.end(); ++vit )
93  {
94  cGidHandle[gids[i++]] = *vit;
95  }
96 
97  Range nodes2;
98  MB_CHK_SET_ERR( mb2->get_entities_by_dimension( 0, 0, nodes2 ), "can't get nodes2" );
99 
100  Range edges2;
101  MB_CHK_SET_ERR( mb2->get_entities_by_dimension( 0, 1, edges2 ), "can't get edges2" );
102 
103  Range cells2;
104  MB_CHK_SET_ERR( mb2->get_entities_by_dimension( 0, 2, cells2 ), "can't get cells2" );
105 
106  Range solids2;
107  MB_CHK_SET_ERR( mb2->get_entities_by_dimension( 0, 3, solids2 ), "can't get solids2" );
108 
109  std::cout << inputfile2 << " has " << nodes2.size() << " vertices " << edges2.size() << " edges " << cells2.size()
110  << " cells " << solids2.size() << " solids \n";
111 
112  Range ents2 = cells2;
113  if( dim == 0 ) ents2 = nodes2;
114  if( dim == 1 ) ents2 = edges2;
115  if( dim == 3 ) ents2 = solids2;
116  // construct maps between global id and handles
117  std::map< int, EntityHandle > cGidHandle2;
118 
119  Tag gid2 = mb2->globalId_tag();
120  std::vector< int > gids2( ents2.size() );
121  MB_CHK_SET_ERR( mb2->tag_get_data( gid2, ents2, &gids2[0] ), "can't get global id on second entities" );
122 
123  i = 0;
124  for( Range::iterator vit = ents2.begin(); vit != ents2.end(); ++vit )
125  {
126  cGidHandle2[gids2[i++]] = *vit;
127  }
128 
129  if( ents.size() != ents2.size() )
130  {
131  std::cout << "cannot compare tags, because number of entities is different:" << ents.size() << " "
132  << ents2.size() << "\n";
133  exit( 1 );
134  }
135 
136  if( tag_name.length() > 0 ) // old tool
137  {
138  Tag tag;
139  MB_CHK_SET_ERR( mb->tag_get_handle( tag_name.c_str(), tag ), "can't get tag on file 1" );
140 
141  int len_tag = 0;
142  MB_CHK_SET_ERR( mb->tag_get_length( tag, len_tag ), "can't get tag length on tag" );
143  std::cout << "length tag : " << len_tag << "\n";
144 
145  moab::DataType dtype;
146  MB_CHK_SET_ERR( mb->tag_get_data_type( tag, dtype ), "can't get tag data type" );
147  if( dtype != MB_TYPE_INTEGER && dtype != MB_TYPE_DOUBLE )
148  {
149  std::cout << "tag data type is not integer or double, do not compare \n";
150  exit( 1 );
151  }
152 
153  bool doubleType = ( dtype == MB_TYPE_DOUBLE );
154  std::vector< double > vals;
155  std::vector< int > ivals;
156  if( doubleType )
157  {
158  vals.resize( len_tag * ents.size() );
159  MB_CHK_SET_ERR( mb->tag_get_data( tag, ents, &vals[0] ), "can't get tag data on double tag" );
160  }
161  else
162  {
163  ivals.resize( len_tag * ents.size() );
164  MB_CHK_SET_ERR( mb->tag_get_data( tag, ents, &ivals[0] ), "can't get tag data on integer tag" );
165  }
166 
167  Tag tag2;
168  MB_CHK_SET_ERR( mb2->tag_get_handle( tag_name.c_str(), tag2 ), "can't get tag on file 2" );
169  std::vector< double > vals2;
170  std::vector< int > ivals2;
171  if( doubleType )
172  {
173  vals2.resize( len_tag * ents2.size() );
174  MB_CHK_SET_ERR( mb2->tag_get_data( tag2, ents2, &vals2[0] ), "can't get tag data on file 2" );
175  }
176  else
177  {
178  ivals2.resize( len_tag * ents2.size() );
179  MB_CHK_SET_ERR( mb2->tag_get_data( tag2, ents2, &ivals2[0] ), "can't get tag data on file 2" );
180  }
181  std::string new_tag_name = tag_name + "_2";
182  Tag newTag, newTagDiff;
183  std::string tag_name_diff = tag_name + "_diff";
184  if( doubleType )
185  {
186  std::vector< double > def_vald( len_tag, 0.0 );
187  MB_CHK_SET_ERR( mb->tag_get_default_value( tag, &def_vald[0] ), "can't get default double tag value" );
188  MB_CHK_SET_ERR( mb->tag_get_handle( new_tag_name.c_str(), len_tag, dtype, newTag,
189  MB_TAG_CREAT | MB_TAG_DENSE, &def_vald[0] ),
190  "can't define new double tag" );
191  MB_CHK_SET_ERR( mb->tag_get_handle( tag_name_diff.c_str(), len_tag, dtype, newTagDiff,
192  MB_TAG_CREAT | MB_TAG_DENSE | MB_TAG_DFTOK, &def_vald[0] ),
193  "can't define new double tag diff" );
194  }
195  else
196  {
197  std::vector< int > def_vali( len_tag, 0 );
198  MB_CHK_SET_ERR( mb->tag_get_default_value( tag, &def_vali[0] ), "can't get default integer tag value" );
199  // the difference should be the same size tag
200  MB_CHK_SET_ERR( mb->tag_get_handle( new_tag_name.c_str(), len_tag, dtype, newTag,
201  MB_TAG_CREAT | MB_TAG_DENSE, &def_vali[0] ),
202  "can't define new integer tag" );
203  MB_CHK_SET_ERR( mb->tag_get_handle( tag_name_diff.c_str(), len_tag, dtype, newTagDiff,
204  MB_TAG_CREAT | MB_TAG_DENSE | MB_TAG_DFTOK, &def_vali[0] ),
205  "can't define new integer tag diff" );
206  }
207 
208  i = 0;
209  double l2norm = 0;
210  for( Range::iterator c2it = ents2.begin(); c2it != ents2.end(); ++c2it )
211  {
212  double* val2 = nullptr;
213  int* ival2 = nullptr;
214  if( doubleType )
215  val2 = &vals2[i * len_tag];
216  else
217  ival2 = &ivals2[i * len_tag];
218 
219  int id2 = gids2[i];
220  i++;
221  EntityHandle c1 = cGidHandle[id2];
222  if( doubleType )
223  {
224  MB_CHK_SET_ERR( mb->tag_set_data( newTag, &c1, 1, val2 ), "can't set new tag" );
225  }
226  else
227  {
228  MB_CHK_SET_ERR( mb->tag_set_data( newTag, &c1, 1, ival2 ), "can't set new tag" );
229  }
230  int indx = ents.index( c1 );
231  if( doubleType )
232  {
233  double* diff = &vals[indx * len_tag];
234  for( int k = 0; k < len_tag; k++ )
235  {
236  diff[k] -= val2[k];
237  l2norm += diff[k] * diff[k];
238  }
239  MB_CHK_SET_ERR( mb->tag_set_data( newTagDiff, &c1, 1, diff ), "can't set diff double tag" );
240  }
241  else
242  {
243  int* diffi = &ivals[indx * len_tag];
244  for( int k = 0; k < len_tag; k++ )
245  {
246  diffi[k] -= ival2[k];
247  l2norm += diffi[k] * diffi[k];
248  }
249  MB_CHK_SET_ERR( mb->tag_set_data( newTagDiff, &c1, 1, diffi ), "can't set diff int tag" );
250  }
251  }
252  l2norm = sqrt( l2norm );
253 
254  if( !outfile.empty() )
255  {
256  MB_CHK_SET_ERR( mb->write_file( outfile.c_str() ), "can't write file" );
257  std::cout << " wrote file " << outfile << "\n";
258  }
259  std::cout << " l2norm of the diff: " << l2norm << "\n";
260  }
261  else // look at all tags that can be compared on ents
262  {
263  // compare all tags
264  std::vector< Tag > list1;
265  MB_CHK_SET_ERR( mb->tag_get_tags( list1 ), "can't get tags 1" );
266 
267  std::map< int, int > gidMap2;
268  for( size_t i = 0; i < ents2.size(); i++ )
269  {
270  gidMap2[gids2[i]] = i;
271  }
272  int k = 0; // number of different fields
273  int k1 = 0; // number of exactly the same fields
274 
275  std::vector< std::string > same_fields;
276  std::vector< std::string > skipped_fields;
277  std::vector< Tag > diffTags;
278  for( size_t i = 0; i < list1.size(); i++ )
279  {
280  Tag tag = list1[i];
281  if( tag == gid ) continue; // do not compare global id tag
282  std::string name;
283  MB_CHK_SET_ERR( mb->tag_get_name( tag, name ), "can't get tag name" );
284  DataType type;
285  MB_CHK_SET_ERR( mb->tag_get_data_type( tag, type ), "can't get tag data type" );
286  if( MB_TYPE_DOUBLE != type && MB_TYPE_INTEGER != type ) continue;
287  bool doubleType = ( type == MB_TYPE_DOUBLE );
288  TagType tag_type;
289  MB_CHK_SET_ERR( mb->tag_get_type( tag, tag_type ), "can't get tag type" );
290  if( MB_TAG_DENSE != tag_type ) continue;
291  int length = 0;
292  MB_CHK_SET_ERR( mb->tag_get_length( tag, length ), "can't get tag length" );
293  if( 1 != length ) continue;
294  Tag tag2;
295  //std::cout <<" tag : " << name << "\n";
296  MB_CHK_SET_ERR( mb2->tag_get_handle( name.c_str(), tag2 ), "can't get tag on second model" );
297  std::vector< double > vals1;
298  std::vector< int > ivals1;
299  if( doubleType )
300  {
301  vals1.resize( ents.size() );
302  rval = mb->tag_get_data( tag, ents, &vals1[0] );
303  }
304  else
305  {
306  ivals1.resize( ents.size() );
307  rval = mb->tag_get_data( tag, ents, &ivals1[0] );
308  }
309 
310  if( MB_SUCCESS != rval )
311  {
312  std::cout << " can't get values for tag " << name << " on model 1; skip it in comparison \n";
313  skipped_fields.push_back( name );
314  continue;
315  }
316  std::vector< double > vals2;
317  std::vector< int > ivals2;
318  if( doubleType )
319  {
320  vals2.resize( ents2.size() );
321  rval = mb2->tag_get_data( tag2, ents2, &vals2[0] );
322  }
323  else
324  {
325  ivals2.resize( ents2.size() );
326  rval = mb2->tag_get_data( tag2, ents2, &ivals2[0] );
327  }
328 
329  if( MB_SUCCESS != rval )
330  {
331  std::cout << " can't get values for tag " << name << " on model 2; skip it in comparison \n";
332  skipped_fields.push_back( name );
333  }
334 
335  double minv1, maxv1, minv2, maxv2;
336  if( vals1.size() > 0 )
337  {
338  minv1 = maxv1 = vals1[0];
339  }
340  if( vals2.size() > 0 )
341  {
342  minv2 = maxv2 = vals2[0];
343  }
344  if( ivals1.size() > 0 )
345  {
346  minv1 = maxv1 = ivals1[0];
347  }
348  if( ivals2.size() > 0 )
349  {
350  minv2 = maxv2 = ivals2[0];
351  }
352  // compute the difference
353  double sum = 0;
354  for( size_t j = 0; j < ents.size(); j++ )
355  {
356  double value1, value2;
357  if( doubleType )
358  value1 = vals1[j];
359  else
360  value1 = ivals1[j];
361 
362  int index2 = gidMap2[gids[j]];
363  if( doubleType )
364  value2 = vals2[index2];
365  else
366  value2 = ivals2[index2];
367 
368  sum += fabs( value1 - value2 );
369  if( value1 < minv1 ) minv1 = value1;
370  if( value1 > maxv1 ) maxv1 = value1;
371  if( value2 < minv2 ) minv2 = value2;
372  if( value2 > maxv2 ) maxv2 = value2;
373  }
374 
375  if( sum > 0. )
376  {
377  std::cout << " tag: " << name << " \t difference : " << sum << " \t min/max (" << minv1 << "/" << maxv1
378  << ") \t (" << minv2 << "/" << maxv2 << ") \n";
379  k++;
380 
381  for( size_t j = 0; j < ents.size(); j++ )
382  {
383  int index2 = gidMap2[gids[j]];
384  if( doubleType )
385  vals1[j] -= vals2[index2];
386  else
387  ivals1[j] -= ivals2[index2];
388  }
389 
390  std::string diffTagName = name + "_diff";
391  Tag newTag;
392  MB_CHK_ERR( mb->tag_get_handle( diffTagName.c_str(), 1, type, newTag, MB_TAG_CREAT | MB_TAG_DENSE ) );
393  if( doubleType )
394  {
395  MB_CHK_ERR( mb->tag_set_data( newTag, ents, &vals1[0] ) );
396  }
397  else
398  {
399  MB_CHK_ERR( mb->tag_set_data( newTag, ents, &ivals1[0] ) );
400  }
401  diffTags.push_back( newTag );
402  }
403  else
404  {
405  same_fields.push_back( name );
406  k1++;
407  }
408  }
409  if( k > 0 && !outfile.empty() )
410  {
411  MB_CHK_ERR( mb->write_file( outfile.c_str(), 0, 0, 0, 0, &diffTags[0], diffTags.size() ) );
412  std::cout << " wrote difference file: " << outfile << "\n";
413  }
414  std::cout << " different fields:" << k << " \n exactly the same fields:" << k1 << "\n";
415  std::cout << " number of skipped fields: " << skipped_fields.size() << "\n";
416  for( size_t i = 0; i < same_fields.size(); i++ )
417  {
418  std::cout << " " << same_fields[i];
419  }
420  std::cout << "\n";
421  }
422  delete mb;
423  delete mb2;
424  return 0;
425 }