Mesh Oriented datABase  (version 5.5.1)
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 <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  rval = mb->load_file( inputfile1.c_str() );MB_CHK_SET_ERR( rval, "can't load input file 1" );
56 
57  Core* mb2 = new Core();
58  rval = mb2->load_file( inputfile2.c_str() );MB_CHK_SET_ERR( rval, "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  rval = mb->get_entities_by_dimension( 0, 0, nodes );MB_CHK_SET_ERR( rval, "can't get nodes" );
65 
66  Range edges;
67  rval = mb->get_entities_by_dimension( 0, 1, edges );MB_CHK_SET_ERR( rval, "can't get edges" );
68 
69  Range cells;
70  rval = mb->get_entities_by_dimension( 0, 2, cells );MB_CHK_SET_ERR( rval, "can't get cells" );
71 
72  Range solids;
73  rval = mb->get_entities_by_dimension( 0, 3, solids );MB_CHK_SET_ERR( rval, "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;
83  rval = mb->tag_get_handle( "GLOBAL_ID", gid );MB_CHK_SET_ERR( rval, "can't get global id tag" );
84 
85  Range ents = cells;
86  if( dim == 0 ) ents = nodes;
87  if( dim == 1 ) ents = edges;
88  if( dim == 3 ) ents = solids;
89  gids.resize( ents.size() );
90  rval = mb->tag_get_data( gid, ents, &gids[0] );MB_CHK_SET_ERR( rval, "can't get global id on entities" );
91 
92  int i = 0;
93  for( Range::iterator vit = ents.begin(); vit != ents.end(); ++vit )
94  {
95  cGidHandle[gids[i++]] = *vit;
96  }
97 
98  Range nodes2;
99  rval = mb2->get_entities_by_dimension( 0, 0, nodes2 );MB_CHK_SET_ERR( rval, "can't get nodes2" );
100 
101  Range edges2;
102  rval = mb2->get_entities_by_dimension( 0, 1, edges2 );MB_CHK_SET_ERR( rval, "can't get edges2" );
103 
104  Range cells2;
105  rval = mb2->get_entities_by_dimension( 0, 2, cells2 );MB_CHK_SET_ERR( rval, "can't get cells2" );
106 
107  Range solids2;
108  rval = mb2->get_entities_by_dimension( 0, 3, solids2 );MB_CHK_SET_ERR( rval, "can't get solids2" );
109 
110  std::cout << inputfile2 << " has " << nodes2.size() << " vertices " << edges2.size() << " edges " << cells2.size()
111  << " cells " << solids2.size() << " solids \n";
112 
113  Range ents2 = cells2;
114  if( dim == 0 ) ents2 = nodes2;
115  if( dim == 1 ) ents2 = edges2;
116  if( dim == 3 ) ents2 = solids2;
117  // construct maps between global id and handles
118  std::map< int, EntityHandle > cGidHandle2;
119 
120  Tag gid2;
121  rval = mb2->tag_get_handle( "GLOBAL_ID", gid2 );MB_CHK_SET_ERR( rval, "can't get global id tag2" );
122 
123  std::vector< int > gids2( ents2.size() );
124  rval = mb2->tag_get_data( gid2, ents2, &gids2[0] );MB_CHK_SET_ERR( rval, "can't get global id on second entities" );
125  i = 0;
126  for( Range::iterator vit = ents2.begin(); vit != ents2.end(); ++vit )
127  {
128  cGidHandle2[gids2[i++]] = *vit;
129  }
130 
131  if( ents.size() != ents2.size() )
132  {
133  std::cout << "cannot compare tags, because number of entities is different:" << ents.size() << " "
134  << ents2.size() << "\n";
135  exit( 1 );
136  }
137  if( tag_name.length() > 0 ) // old tool
138  {
139  Tag tag;
140  rval = mb->tag_get_handle( tag_name.c_str(), tag );MB_CHK_SET_ERR( rval, "can't get tag on file 1" );
141 
142  int len_tag = 0;
143  rval = mb->tag_get_length( tag, len_tag );MB_CHK_SET_ERR( rval, "can't get tag length on tag" );
144  std::cout << "length tag : " << len_tag << "\n";
145  moab::DataType dtype;
146  rval = mb->tag_get_data_type( tag, dtype );MB_CHK_SET_ERR( rval, "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  bool doubleType = ( dtype == MB_TYPE_DOUBLE );
153  std::vector< double > vals;
154  std::vector< int > ivals;
155  if( doubleType )
156  {
157  vals.resize( len_tag * ents.size() );
158  rval = mb->tag_get_data( tag, ents, &vals[0] );MB_CHK_SET_ERR( rval, "can't get tag data on double tag" );
159  }
160  else
161  {
162  ivals.resize( len_tag * ents.size() );
163  rval = mb->tag_get_data( tag, ents, &ivals[0] );MB_CHK_SET_ERR( rval, "can't get tag data on integer tag" );
164  }
165 
166  Tag tag2;
167  rval = mb2->tag_get_handle( tag_name.c_str(), tag2 );MB_CHK_SET_ERR( rval, "can't get tag on file 2" );
168  std::vector< double > vals2;
169  std::vector< int > ivals2;
170  if( doubleType )
171  {
172  vals2.resize( len_tag * ents2.size() );
173  rval = mb2->tag_get_data( tag2, ents2, &vals2[0] );MB_CHK_SET_ERR( rval, "can't get tag data on file 2" );
174  }
175  else
176  {
177  ivals2.resize( len_tag * ents2.size() );
178  rval = mb2->tag_get_data( tag2, ents2, &ivals2[0] );MB_CHK_SET_ERR( rval, "can't get tag data on file 2" );
179  }
180  std::string new_tag_name = tag_name + "_2";
181  Tag newTag, newTagDiff;
182  std::string tag_name_diff = tag_name + "_diff";
183  if( doubleType )
184  {
185  std::vector<double> def_vald(len_tag);
186  rval = mb->tag_get_default_value( tag, &def_vald[0] );MB_CHK_SET_ERR( rval, "can't get default" );
187  rval = mb->tag_get_handle( new_tag_name.c_str(), len_tag, dtype, newTag, MB_TAG_CREAT | MB_TAG_DENSE, &def_vald[0] );MB_CHK_SET_ERR( rval, "can't define new tag" );
188  for (size_t k=0; k<len_tag; k++)
189  def_vald[k] = 0.;
190  rval = mb->tag_get_handle( tag_name_diff.c_str(), len_tag, dtype, newTagDiff,
191  MB_TAG_CREAT | MB_TAG_DENSE | MB_TAG_DFTOK, &def_vald[0] );MB_CHK_SET_ERR( rval, "can't define new tag diff" );
192  }
193  else
194  {
195  std::vector<int> def_vali(len_tag);
196  rval = mb->tag_get_default_value( tag, &def_vali[0] );MB_CHK_SET_ERR( rval, "can't get default" );
197  // the difference should be the same size tag
198  rval = mb->tag_get_handle( new_tag_name.c_str(), len_tag, dtype, newTag, MB_TAG_CREAT | MB_TAG_DENSE, &def_vali[0] );MB_CHK_SET_ERR( rval, "can't define new tag" );
199  for (size_t k=0; k<len_tag; k++)
200  def_vali[k] = 0.;
201  rval = mb->tag_get_handle( tag_name_diff.c_str(), len_tag, dtype, newTagDiff,
202  MB_TAG_CREAT | MB_TAG_DENSE | MB_TAG_DFTOK, &def_vali[0] );MB_CHK_SET_ERR( rval, "can't define new tag diff" );
203  }
204 
205  i = 0;
206  double l2norm = 0;
207  for( Range::iterator c2it = ents2.begin(); c2it != ents2.end(); ++c2it )
208  {
209  double *val2 = nullptr;
210  int * ival2= nullptr;
211  if( doubleType )
212  val2 = &vals2[i*len_tag];
213  else
214  ival2 = &ivals2[i*len_tag];
215 
216  int id2 = gids2[i];
217  i++;
218  EntityHandle c1 = cGidHandle[id2];
219  if( doubleType )
220  {
221  rval = mb->tag_set_data( newTag, &c1, 1, val2 );MB_CHK_SET_ERR( rval, "can't set new tag" );
222  }
223  else
224  {
225  rval = mb->tag_set_data( newTag, &c1, 1, ival2 );MB_CHK_SET_ERR( rval, "can't set new tag" );
226  }
227  int indx = ents.index( c1 );
228  if( doubleType )
229  {
230  double *diff = &vals[indx * len_tag];
231  for (int k=0; k<len_tag; k++)
232  {
233  diff[k] -= val2[k];
234  l2norm += diff[k] * diff[k];
235  }
236  rval = mb->tag_set_data( newTagDiff, &c1, 1, diff );MB_CHK_SET_ERR( rval, "can't set diff double tag" );
237  }
238  else
239  {
240  int *diffi = &ivals[indx * len_tag];
241  for (int k=0; k<len_tag; k++)
242  {
243  diffi[k] -= ival2[k];
244  l2norm += diffi[k] * diffi[k];
245  }
246  rval = mb->tag_set_data( newTagDiff, &c1, 1, diffi );MB_CHK_SET_ERR( rval, "can't set diff int tag" );
247  }
248  }
249  l2norm = sqrt( l2norm );
250 
251  if (!outfile.empty())
252  {
253  rval = mb->write_file( outfile.c_str() );MB_CHK_SET_ERR( rval, "can't write file" );
254  std::cout << " wrote file " << outfile << "\n";
255  }
256  std::cout << " l2norm of the diff: " << l2norm << "\n";
257 
258  }
259  else // look at all tags that can be compared on ents
260  {
261  // compare all tags
262  std::vector< Tag > list1;
263  rval = mb->tag_get_tags( list1 );MB_CHK_SET_ERR( rval, "can't get tags 1" );
264 
265  std::map< int, int > gidMap2;
266  for( int i = 0; i < ents2.size(); i++ )
267  {
268  gidMap2[gids2[i]] = i;
269  }
270  int k = 0; // number of different fields
271  int k1 = 0; // number of exactly the same fields
272 
273  std::vector< std::string > same_fields;
274  std::vector< std::string > skipped_fields;
275  std::vector< Tag > diffTags;
276  for( size_t i = 0; i < list1.size(); i++ )
277  {
278  Tag tag = list1[i];
279  if (tag == gid) continue; // do not compare global id tag
280  std::string name;
281  rval = mb->tag_get_name( tag, name );MB_CHK_SET_ERR( rval, "can't get tag name" );
282  DataType type;
283  rval = mb->tag_get_data_type( tag, type );MB_CHK_SET_ERR( rval, "can't get tag data type" );
284  if( MB_TYPE_DOUBLE != type && MB_TYPE_INTEGER != type ) continue;
285  bool doubleType = ( type == MB_TYPE_DOUBLE );
286  TagType tag_type;
287  rval = mb->tag_get_type( tag, tag_type );MB_CHK_SET_ERR( rval, "can't get tag type" );
288  if( MB_TAG_DENSE != tag_type ) continue;
289  int length = 0;
290  rval = mb->tag_get_length( tag, length );MB_CHK_SET_ERR( rval, "can't get tag length" );
291  if( 1 != length ) continue;
292  Tag tag2;
293  //std::cout <<" tag : " << name << "\n";
294  rval = mb2->tag_get_handle( name.c_str(), tag2 );MB_CHK_SET_ERR( rval, "can't get tag on second model" );
295  std::vector< double > vals1;
296  std::vector< int > ivals1;
297  if( doubleType )
298  {
299  vals1.resize( ents.size() );
300  rval = mb->tag_get_data( tag, ents, &vals1[0] );
301  }
302  else
303  {
304  ivals1.resize( ents.size() );
305  rval = mb->tag_get_data( tag, ents, &ivals1[0] );
306  }
307 
308  if( MB_SUCCESS != rval )
309  {
310  std::cout << " can't get values for tag " << name << " on model 1; skip it in comparison \n";
311  skipped_fields.push_back( name );
312  continue;
313  }
314  std::vector< double > vals2;
315  std::vector< int > ivals2;
316  if( doubleType )
317  {
318  vals2.resize( ents2.size() );
319  rval = mb2->tag_get_data( tag2, ents2, &vals2[0] );
320  }
321  else
322  {
323  ivals2.resize( ents2.size() );
324  rval = mb2->tag_get_data( tag2, ents2, &ivals2[0] );
325  }
326 
327  if( MB_SUCCESS != rval )
328  {
329  std::cout << " can't get values for tag " << name << " on model 2; skip it in comparison \n";
330  skipped_fields.push_back( name );
331  }
332 
333  double minv1, maxv1, minv2, maxv2;
334  if( vals1.size() > 0 )
335  {
336  minv1 = maxv1 = vals1[0];
337  }
338  if( vals2.size() > 0 )
339  {
340  minv2 = maxv2 = vals2[0];
341  }
342  if( ivals1.size() > 0 )
343  {
344  minv1 = maxv1 = ivals1[0];
345  }
346  if( ivals2.size() > 0 )
347  {
348  minv2 = maxv2 = ivals2[0];
349  }
350  // compute the difference
351  double sum = 0;
352  for( int j = 0; j < ents.size(); j++ )
353  {
354  double value1, value2;
355  if( doubleType )
356  value1 = vals1[j];
357  else
358  value1 = ivals1[j];
359 
360  int index2 = gidMap2[gids[j]];
361  if( doubleType )
362  value2 = vals2[index2];
363  else
364  value2 = ivals2[index2];
365 
366  sum += fabs( value1 - value2 );
367  if( value1 < minv1 ) minv1 = value1;
368  if( value1 > maxv1 ) maxv1 = value1;
369  if( value2 < minv2 ) minv2 = value2;
370  if( value2 > maxv2 ) maxv2 = value2;
371  }
372 
373  if( sum > 0. )
374  {
375  std::cout << " tag: " << name << " \t difference : " << sum << " \t min/max (" << minv1 << "/" << maxv1
376  << ") \t (" << minv2 << "/" << maxv2 << ") \n";
377  k++;
378 
379  for( int j = 0; j < ents.size(); j++ )
380  {
381  int index2 = gidMap2[gids[j]];
382  if( doubleType )
383  vals1[j] -= vals2[index2];
384  else
385  ivals1[j] -= ivals2[index2];
386  }
387 
388  std::string diffTagName = name + "_diff";
389  Tag newTag;
390  rval = mb->tag_get_handle( diffTagName.c_str(), 1, type, newTag, MB_TAG_CREAT | MB_TAG_DENSE );MB_CHK_ERR( rval );
391  if( doubleType )
392  {
393  rval = mb->tag_set_data( newTag, ents, &vals1[0] );MB_CHK_ERR( rval );
394  }
395  else
396  {
397  rval = mb->tag_set_data( newTag, ents, &ivals1[0] );MB_CHK_ERR( rval );
398  }
399  diffTags.push_back( newTag );
400  }
401  else
402  {
403  same_fields.push_back( name );
404  k1++;
405  }
406  }
407  if( k > 0 && !outfile.empty())
408  {
409  rval = mb->write_file( outfile.c_str(), 0, 0, 0, 0, &diffTags[0], diffTags.size() );MB_CHK_ERR( rval );
410  std::cout << " wrote difference file: " << outfile << "\n";
411  }
412  std::cout << " different fields:" << k << " \n exactly the same fields:" << k1 << "\n";
413  std::cout << " number of skipped fields: " << skipped_fields.size() << "\n";
414  for( size_t i = 0; i < same_fields.size(); i++ )
415  {
416  std::cout << " " << same_fields[i];
417  }
418  std::cout << "\n";
419  }
420  delete mb;
421  delete mb2;
422  return 0;
423 }