Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
addncdata.cpp
Go to the documentation of this file.
1 /*
2  * addncdata.cpp
3  * this tool will take an existing h5m file and add data from an nc type file
4  * will support mainly showing the data associated with unstructured meshes (Homme, MPAS) with Visit
5  *
6  * example of usage:
7  * ./mbaddnc -i wholeFineATM.h5m -n surfdata_ne11np4_simyr1850_c160614.nc -o
8  * whole_LONGXY_surfdata.h5m -v LONGXY
9  *
10  * Basically, will output a new h5m file (whole_LONGXY_surfdata.h5m), which has an extra tag,
11  * corresponding to the variable LONGXY from the file surfdata_ne11np4_simyr1850_c160614.nc;
12  * matching is based on the global ids between what we think is the order on the original file
13  * (wholeFineATM.h5m) and the order of surfdata_ne11np4_simyr1850_c160614.nc
14  *
15  * file wholeFineATM.h5m is obtained from a coupled run in e3sm, with the ne 11, np 4,
16  *
17  * add an option to output the nc data to the original coarse ATM file, the one that also has the
18  * GLOBAL_DOFS tag with the global DOFs of the GLL points
19  */
20 
21 #include "moab/ProgOptions.hpp"
22 #include "moab/Core.hpp"
23 
24 #include "netcdf.h"
25 #include <cmath>
26 #include <sstream>
27 
28 using namespace moab;
29 
30 // copy from ReadNCDF.cpp some useful macros for reading from a netcdf file (exodus?)
31 // ncFile is an integer initialized when opening the nc file in read mode
32 
33 int ncFile;
34 
35 #define INS_ID( stringvar, prefix, id ) sprintf( stringvar, prefix, id )
36 
37 #define GET_DIM( ncdim, name, val ) \
38  { \
39  int gdfail = nc_inq_dimid( ncFile, name, &( ncdim ) ); \
40  if( NC_NOERR == gdfail ) \
41  { \
42  size_t tmp_val; \
43  gdfail = nc_inq_dimlen( ncFile, ncdim, &tmp_val ); \
44  if( NC_NOERR != gdfail ) \
45  { \
46  MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension length" ); \
47  } \
48  else \
49  ( val ) = tmp_val; \
50  } \
51  else \
52  ( val ) = 0; \
53  }
54 
55 #define GET_DIMB( ncdim, name, varname, id, val ) \
56  INS_ID( name, varname, id ); \
57  GET_DIM( ncdim, name, val );
58 
59 #define GET_VAR( name, id, dims ) \
60  { \
61  ( id ) = -1; \
62  int gvfail = nc_inq_varid( ncFile, name, &( id ) ); \
63  if( NC_NOERR == gvfail ) \
64  { \
65  int ndims; \
66  gvfail = nc_inq_varndims( ncFile, id, &ndims ); \
67  if( NC_NOERR == gvfail ) \
68  { \
69  ( dims ).resize( ndims ); \
70  gvfail = nc_inq_vardimid( ncFile, id, &( dims )[0] ); \
71  if( NC_NOERR != gvfail ) \
72  { \
73  MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get variable dimension IDs" ); \
74  } \
75  } \
76  } \
77  }
78 
79 #define GET_1D_INT_VAR( name, id, vals ) \
80  { \
81  GET_VAR( name, id, vals ); \
82  if( -1 != ( id ) ) \
83  { \
84  size_t ntmp; \
85  int ivfail = nc_inq_dimlen( ncFile, ( vals )[0], &ntmp ); \
86  if( NC_NOERR != ivfail ) \
87  { \
88  MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension length" ); \
89  } \
90  ( vals ).resize( ntmp ); \
91  size_t ntmp1 = 0; \
92  ivfail = nc_get_vara_int( ncFile, id, &ntmp1, &ntmp, &( vals )[0] ); \
93  if( NC_NOERR != ivfail ) \
94  { \
95  MB_SET_ERR( MB_FAILURE, "addncdata:: Problem getting variable " << ( name ) ); \
96  } \
97  } \
98  }
99 
100 #define GET_1D_DBL_VAR( name, id, vals ) \
101  { \
102  std::vector< int > dum_dims; \
103  GET_VAR( name, id, dum_dims ); \
104  if( -1 != ( id ) ) \
105  { \
106  size_t ntmp; \
107  int dvfail = nc_inq_dimlen( ncFile, dum_dims[0], &ntmp ); \
108  if( NC_NOERR != dvfail ) \
109  { \
110  MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension length" ); \
111  } \
112  ( vals ).resize( ntmp ); \
113  size_t ntmp1 = 0; \
114  dvfail = nc_get_vara_double( ncFile, id, &ntmp1, &ntmp, &( vals )[0] ); \
115  if( NC_NOERR != dvfail ) \
116  { \
117  MB_SET_ERR( MB_FAILURE, "addncdata:: Problem getting variable " << ( name ) ); \
118  } \
119  } \
120  }
121 
122 #define GET_1D_FLT_VAR( name, id, vals ) \
123  { \
124  std::vector< int > dum_dims; \
125  GET_VAR( name, id, dum_dims ); \
126  if( -1 != ( id ) ) \
127  { \
128  size_t ntmp; \
129  int dvfail = nc_inq_dimlen( ncFile, dum_dims[0], &ntmp ); \
130  if( NC_NOERR != dvfail ) \
131  { \
132  MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension length" ); \
133  } \
134  ( vals ).resize( ntmp ); \
135  size_t ntmp1 = 0; \
136  dvfail = nc_get_vara_float( ncFile, id, &ntmp1, &ntmp, &( vals )[0] ); \
137  if( NC_NOERR != dvfail ) \
138  { \
139  MB_SET_ERR( MB_FAILURE, "addncdata:: Problem getting variable " << ( name ) ); \
140  } \
141  } \
142  }
143 
144 int main( int argc, char* argv[] )
145 {
146  ErrorCode rval;
147  ProgOptions opts;
148 
149  std::string inputfile, outfile( "out.h5m" ), netcdfFile, variable_name, sefile_name;
150 
151  opts.addOpt< std::string >( "input,i", "input mesh filename", &inputfile );
152  opts.addOpt< std::string >( "netcdfFile,n", "netcdf file aligned with the mesh input file", &netcdfFile );
153  opts.addOpt< std::string >( "output,o", "output mesh filename", &outfile );
154 
155  opts.addOpt< std::string >( "var,v", "variable to extract and add to output file", &variable_name );
156 
157  opts.addOpt< std::string >( "sefile,s", "spectral elements file (coarse SE mesh)", &sefile_name );
158  opts.parseCommandLine( argc, argv );
159 
160  Core* mb = new Core();
161 
162  rval = mb->load_file( inputfile.c_str() );MB_CHK_SET_ERR( rval, "can't load input file" );
163 
164  std::cout << " opened " << inputfile << " with initial h5m data.\n";
165  // open the netcdf file, and see if it has that variable we are looking for
166 
167  Range nodes;
168  rval = mb->get_entities_by_dimension( 0, 0, nodes );MB_CHK_SET_ERR( rval, "can't get nodes" );
169 
170  Range edges;
171  rval = mb->get_entities_by_dimension( 0, 1, edges );MB_CHK_SET_ERR( rval, "can't get edges" );
172 
173  Range cells;
174  rval = mb->get_entities_by_dimension( 0, 2, cells );MB_CHK_SET_ERR( rval, "can't get cells" );
175 
176  std::cout << " it has " << nodes.size() << " vertices " << edges.size() << " edges " << cells.size() << " cells\n";
177 
178  // construct maps between global id and handles
179  std::map< int, EntityHandle > vGidHandle;
180  std::map< int, EntityHandle > eGidHandle;
181  std::map< int, EntityHandle > cGidHandle;
182  std::vector< int > gids;
183  Tag gid;
184  rval = mb->tag_get_handle( "GLOBAL_ID", gid );MB_CHK_SET_ERR( rval, "can't get global id tag" );
185  gids.resize( nodes.size() );
186  rval = mb->tag_get_data( gid, nodes, &gids[0] );MB_CHK_SET_ERR( rval, "can't get global id on vertices" );
187  int i = 0;
188  for( Range::iterator vit = nodes.begin(); vit != nodes.end(); vit++ )
189  {
190  vGidHandle[gids[i++]] = *vit;
191  }
192 
193  gids.resize( edges.size() );
194  rval = mb->tag_get_data( gid, edges, &gids[0] );MB_CHK_SET_ERR( rval, "can't get global id on edges" );
195  i = 0;
196  for( Range::iterator vit = edges.begin(); vit != edges.end(); vit++ )
197  {
198  eGidHandle[gids[i++]] = *vit;
199  }
200 
201  gids.resize( cells.size() );
202  rval = mb->tag_get_data( gid, cells, &gids[0] );MB_CHK_SET_ERR( rval, "can't get global id on cells" );
203  i = 0;
204  for( Range::iterator vit = cells.begin(); vit != cells.end(); vit++ )
205  {
206  cGidHandle[gids[i++]] = *vit;
207  }
208 
209  // Open netcdf/exodus file
210  int fail = nc_open( netcdfFile.c_str(), 0, &ncFile );
211  if( NC_NOWRITE != fail )
212  {
213  MB_SET_ERR( MB_FILE_DOES_NOT_EXIST, "ReadNCDF:: problem opening Netcdf II file " << netcdfFile );
214  }
215 
216  std::cout << " opened " << netcdfFile << " with new data \n";
217  std::vector< int > dims;
218  int nc_var;
219 
220  size_t recs;
221  char recname[NC_MAX_NAME + 1];
222 
223  std::cout << " looking for variable " << variable_name << "\n";
224  GET_VAR( variable_name.c_str(), nc_var, dims );
225  std::cout << " it has " << dims.size() << " dimensions\n";
226 
227  int dimIndex = -1; // index of the dimension of interest
228  bool vertex_data = false;
229  bool cell_data = false;
230  for( size_t j = 0; j < dims.size(); j++ )
231  {
232  fail = nc_inq_dim( ncFile, dims[j], recname, &recs );
233  if( NC_NOERR != fail ) MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension" );
234  std::string name_dim( recname );
235  std::cout << " dimension index " << j << " in file: " << dims[j] << " name: " << name_dim << " recs:" << recs
236  << "\n";
237  if( recs == nodes.size() )
238  {
239  dimIndex = j;
240  vertex_data = true;
241  }
242  if( recs == cells.size() )
243  {
244  dimIndex = j;
245  cell_data = true;
246  }
247  }
248 
249  int otherDim = 1 - dimIndex; // used only if 2 dimensions ; could be 0 or 1;
250  size_t size_tag = 1; // good for one dimension
251  std::vector< int > evals; // size of size_tag
252  std::vector< double > dvals; // size of size_tag
253  nc_type dataType;
254 
255  // read the variable, and set it to the tag
256  fail = nc_inq_vartype( ncFile, nc_var, &dataType );
257  if( NC_NOERR != fail ) MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get variable type" );
258  DataType mbtype = MB_TYPE_DOUBLE;
259  bool float_var = false;
260  if( NC_INT == dataType )
261  mbtype = MB_TYPE_INTEGER;
262  else if( NC_DOUBLE != dataType && NC_FLOAT != dataType )
263  MB_CHK_SET_ERR( MB_FAILURE, "unknown type" );
264 
265  if( NC_FLOAT == dataType ) float_var = true;
266 
267  bool use_time = false;
268  int time_id = -1;
269  std::vector< float > times;
270  fail = nc_inq_varid( ncFile, "time", &time_id );
271  if( NC_NOERR == fail )
272  {
273  use_time = true;
274  int ii;
275  GET_1D_FLT_VAR( "time", ii, times );
276  }
277  Tag newTag;
278 
279  if( ( dims.size() >= 1 && dims.size() <= 2 ) && ( vertex_data || cell_data ) )
280  {
281 
282  if( dims.size() == 2 )
283  {
284  fail = nc_inq_dim( ncFile, dims[otherDim], recname, &size_tag );
285  if( NC_NOERR != fail ) MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension" );
286  }
287 
288  int def_val = 0;
289  rval = mb->tag_get_handle( variable_name.c_str(), (int)size_tag, mbtype, newTag, MB_TAG_CREAT | MB_TAG_DENSE,
290  &def_val );MB_CHK_SET_ERR( rval, "can't define new tag" );
291 
292  if( NC_INT == dataType )
293  {
294  std::vector< int > vals;
295  if( 1 == dims.size() )
296  {
297  GET_1D_INT_VAR( variable_name.c_str(), dims[0], vals );
298  if( vertex_data )
299  {
300  for( size_t k = 0; k < vals.size(); k++ )
301  {
302  EntityHandle vh = vGidHandle[k + 1];
303  rval = mb->tag_set_data( newTag, &vh, 1, &vals[k] );MB_CHK_SET_ERR( rval, "can't set tag on vertex" );
304  }
305  }
306  else // cell_data
307  {
308  for( size_t k = 0; k < vals.size(); k++ )
309  {
310  EntityHandle ch = cGidHandle[k + 1]; // cell handle
311  rval = mb->tag_set_data( newTag, &ch, 1, &vals[k] );MB_CHK_SET_ERR( rval, "can't set tag on cell" );
312  }
313  }
314  }
315  else // dims.size() == 2
316  {
317  // Single var for all coords
318  size_t start[2] = { 0, 0 }, count[2] = { 1, 1 };
319  count[dimIndex] = recs;
320  count[otherDim] = size_tag;
321  vals.resize( recs * size_tag );
322  fail = nc_get_vara_int( ncFile, nc_var, start, count, &vals[0] );
323  evals.resize( size_tag );
324 
325  if( vertex_data )
326  {
327  for( size_t k = 0; k < recs; k++ )
328  {
329  EntityHandle vh = vGidHandle[k + 1];
330  size_t start_in_vals = k * size_tag, stride = 1;
331  for( size_t j = 0; j < size_tag; j++ )
332  evals[j] = vals[start_in_vals + j * stride];
333  rval = mb->tag_set_data( newTag, &vh, 1, &evals[0] );MB_CHK_SET_ERR( rval, "can't set tag on vertex" );
334  }
335  }
336  else // cell_data
337  {
338  for( size_t k = 0; k < recs; k++ )
339  {
340  EntityHandle ch = cGidHandle[k + 1]; // cell handle
341  size_t start_in_vals = k * size_tag, stride = 1;
342  for( size_t j = 0; j < size_tag; j++ )
343  evals[j] = vals[start_in_vals + j * stride];
344  rval = mb->tag_set_data( newTag, &ch, 1, &evals[0] );MB_CHK_SET_ERR( rval, "can't set tag on cell" );
345  }
346  }
347  }
348  }
349  else
350  {
351  std::vector< double > vals;
352  if( 1 == dims.size() )
353  {
354  GET_1D_DBL_VAR( variable_name.c_str(), dims[0], vals );
355  if( vertex_data )
356  {
357  for( size_t k = 0; k < vals.size(); k++ )
358  {
359  EntityHandle vh = vGidHandle[k + 1];
360  rval = mb->tag_set_data( newTag, &vh, 1, &vals[k] );MB_CHK_SET_ERR( rval, "can't set tag on vertex" );
361  }
362  }
363  else // cell_data
364  {
365  for( size_t k = 0; k < vals.size(); k++ )
366  {
367  EntityHandle ch = cGidHandle[k + 1]; // cell handle
368  rval = mb->tag_set_data( newTag, &ch, 1, &vals[k] );MB_CHK_SET_ERR( rval, "can't set tag on vertex" );
369  }
370  }
371  }
372  else // dims.size() == 2
373  {
374  // Single var for all coords
375  size_t start[2] = { 0, 0 }, count[2] = { 1, 1 };
376  count[dimIndex] = recs;
377  count[otherDim] = size_tag;
378  vals.resize( recs * size_tag );
379  fail = nc_get_vara_double( ncFile, nc_var, start, count, &vals[0] );
380  dvals.resize( size_tag );
381 
382  if( vertex_data )
383  {
384  for( size_t k = 0; k < recs; k++ )
385  {
386  EntityHandle vh = vGidHandle[k + 1];
387  size_t start_in_vals = k * size_tag, stride = 1;
388  for( size_t j = 0; j < size_tag; j++ )
389  dvals[j] = vals[start_in_vals + j * stride];
390  rval = mb->tag_set_data( newTag, &vh, 1, &dvals[0] );MB_CHK_SET_ERR( rval, "can't set tag on vertex" );
391  }
392  }
393  else // cell_data
394  {
395  for( size_t k = 0; k < recs; k++ )
396  {
397  EntityHandle ch = cGidHandle[k + 1]; // cell handle
398  size_t start_in_vals = k * size_tag, stride = 1;
399  for( size_t j = 0; j < size_tag; j++ )
400  dvals[j] = vals[start_in_vals + j * stride];
401  rval = mb->tag_set_data( newTag, &ch, 1, &dvals[0] );MB_CHK_SET_ERR( rval, "can't set tag on cell" );
402  }
403  }
404  }
405  }
406  }
407  else if( ( dims.size() == 3 ) && vertex_data && dimIndex == 2 && mbtype == MB_TYPE_DOUBLE &&
408  use_time ) // the last one is the vertex
409  {
410  // the case when the last dim is ncol (for homme type mesh))
411  size_t dim0, dim1; // dim 2 is ncol..
412  char recname0[NC_MAX_NAME + 1], recname1[NC_MAX_NAME + 1];
413  fail = nc_inq_dim( ncFile, dims[0], recname0, &dim0 );
414  if( NC_NOERR != fail ) MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension" );
415  fail = nc_inq_dim( ncFile, dims[1], recname1, &dim1 );
416  if( NC_NOERR != fail ) MB_SET_ERR( MB_FAILURE, "addncdata:: Couldn't get dimension" );
417  std::string name0( recname0 );
418  std::string name1( recname1 );
419  std::string timestr( "time" );
420  size_t start[3] = { 0, 0, 0 };
421  size_t count[3] = { 1, 0, 0 };
422  count[1] = dim1;
423  count[2] = nodes.size();
424  // create a few tags, with name inserted
425  if( name0.compare( "time" ) == 0 )
426  {
427 
428  std::vector< double > dvalues( dim1 * count[2] );
429  std::vector< float > fvalues( dim1 * count[2] );
430  std::vector< double > transp( dim1 * count[2] );
431  // get the variable time
432  for( size_t k = 0; k < dim0; k++ )
433  {
434  // create a tag for each time, and
435  std::stringstream tag_name;
436  tag_name << variable_name << "_t" << times[k];
437  std::vector< double > defvals( dim1, 0. );
438  rval = mb->tag_get_handle( tag_name.str().c_str(), (int)dim1, mbtype, newTag,
439  MB_TAG_CREAT | MB_TAG_DENSE, &defvals[0] );MB_CHK_SET_ERR( rval, "can't define new tag" );
440  start[0] = k;
441 
442  if( float_var )
443  {
444  fail = nc_get_vara_float( ncFile, nc_var, start, count, &fvalues[0] );
445  // now arrange them in a tag, transpose data
446  for( size_t ii = 0; ii < dim1; ii++ )
447  for( size_t j = 0; j < count[2]; j++ )
448  {
449  transp[j * dim1 + ii] = fvalues[ii * count[2] + j];
450  }
451  }
452  else // double
453  {
454  fail = nc_get_vara_double( ncFile, nc_var, start, count, &dvalues[0] );
455  // now arrange them in a tag, transpose data
456  for( size_t ii = 0; ii < dim1; ii++ )
457  for( size_t j = 0; j < count[2]; j++ )
458  {
459  transp[j * dim1 + ii] = dvalues[ii * count[2] + j];
460  }
461  }
462  for( size_t ii = 0; ii < nodes.size(); ii++ )
463  {
464  EntityHandle vh = vGidHandle[ii + 1];
465  rval = mb->tag_set_data( newTag, &vh, 1, &transp[ii * dim1] );MB_CHK_SET_ERR( rval, "can't set tag on nodes" );
466  }
467  }
468  }
469  }
470  rval = mb->write_file( outfile.c_str() );MB_CHK_SET_ERR( rval, "can't write file" );
471  std::cout << " wrote file " << outfile << "\n";
472 
473  // now, if s option, load the coarse mesh and put data on each element, according to a matrix
474  if( !sefile_name.empty() )
475  {
476  // load the file, check for GLOBAL_DOFS tag, and create a new tag with the data associated
477  Core* mb2 = new Core();
478  rval = mb2->load_file( sefile_name.c_str() );MB_CHK_SET_ERR( rval, "can't load spectral element file" );
479  std::cout << " loaded spectral file " << sefile_name << "\n";
480  // look for GLOBAL_DOFS tag
481  Tag gdofeTag;
482  rval = mb2->tag_get_handle( "GLOBAL_DOFS", gdofeTag );MB_CHK_SET_ERR( rval, "file does not have GLOBAL_DOFS file" );
483  int sizeTag;
484  rval = mb2->tag_get_length( gdofeTag, sizeTag );MB_CHK_SET_ERR( rval, "can't get size of tag" );
485  int np = (int)sqrt( 1.0 * sizeTag );
486  std::cout << " size of tag: " << sizeTag << " np = " << np << "\n";
487  std::vector< int > gdofs;
488  Range cells2;
489  rval = mb2->get_entities_by_dimension( 0, 2, cells2 );MB_CHK_SET_ERR( rval, "can't get cells on spectral mesh" );
490  gdofs.resize( cells2.size() * sizeTag );
491  rval = mb2->tag_get_data( gdofeTag, cells2, &gdofs[0] );MB_CHK_SET_ERR( rval, "can't get global dofs tag" );
492  // create a new tag for element data arranged as DFIELD
493 
494  std::vector< double > dfield;
495  dfield.resize( sizeTag, 0.0 );
496  Tag newTag2;
497  rval = mb2->tag_get_handle( variable_name.c_str(), (int)sizeTag, mbtype, newTag2, MB_TAG_CREAT | MB_TAG_DENSE,
498  &dfield[0] );MB_CHK_SET_ERR( rval, "can't define new tag" );
499 
500  int i1 = 0; // index in the gdofs array, per element
501 
502  // get the tag values from the other moab core, for newTag
503  int dataTagLen;
504  rval = mb->tag_get_length( newTag, dataTagLen );MB_CHK_SET_ERR( rval, "can't get size of newTag" );
505  //
506  std::vector< double > oldData;
507  oldData.resize( dataTagLen * nodes.size() ); //
508 
509  // get the "old" values
510  rval = mb->tag_get_data( newTag, nodes, &oldData[0] );MB_CHK_SET_ERR( rval, "can't get old values" );
511  for( Range::iterator it = cells2.begin(); it != cells2.end(); it++ )
512  {
513  EntityHandle cel = *it;
514  // gdofs per element are gdofs[i:i+np*np];
515  for( int k = 0; k < sizeTag; k++ )
516  {
517  int gdof = gdofs[i1 + k];
518  EntityHandle node = vGidHandle[gdof];
519  int index = nodes.index( node );
520  // get last layer of data
521  double val = oldData[index * dataTagLen + dataTagLen - 1]; //
522  dfield[k] = val;
523  }
524  i1 = i1 + sizeTag;
525  rval = mb2->tag_set_data( newTag2, &cel, 1, &dfield[0] );MB_CHK_SET_ERR( rval, "can't set new tag" );
526  }
527 
528  // write the appended file with the new field:
529  rval = mb2->write_file( "atm2.h5m" );MB_CHK_SET_ERR( rval, "can't write new spectral file" );
530  std::cout << " wrote file atm2.h5m \n";
531  }
532  return 0;
533 }