Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
NCHelperFV.cpp
Go to the documentation of this file.
1 #include "NCHelperFV.hpp"
2 #include "moab/FileOptions.hpp"
3 
4 #include <cmath>
5 #include <sstream>
6 
7 namespace moab
8 {
9 
10 bool NCHelperFV::can_read_file( ReadNC* readNC, int fileId )
11 {
12  std::vector< std::string >& dimNames = readNC->dimNames;
13 
14  // If dimension names "lon" AND "lat" AND "slon" AND "slat" exist then it should be the FV grid
15  if( ( std::find( dimNames.begin(), dimNames.end(), std::string( "lon" ) ) != dimNames.end() ) &&
16  ( std::find( dimNames.begin(), dimNames.end(), std::string( "lat" ) ) != dimNames.end() ) &&
17  ( std::find( dimNames.begin(), dimNames.end(), std::string( "slon" ) ) != dimNames.end() ) &&
18  ( std::find( dimNames.begin(), dimNames.end(), std::string( "slat" ) ) != dimNames.end() ) )
19  {
20  // Make sure it is CAM grid
21  std::map< std::string, ReadNC::AttData >::iterator attIt = readNC->globalAtts.find( "source" );
22  if( attIt == readNC->globalAtts.end() ) return false;
23  unsigned int sz = attIt->second.attLen;
24  std::string att_data;
25  att_data.resize( sz + 1 );
26  att_data[sz] = '\000';
27  int success =
28  NCFUNC( get_att_text )( fileId, attIt->second.attVarId, attIt->second.attName.c_str(), &att_data[0] );
29  if( success ) return false;
30  if( att_data.find( "CAM" ) == std::string::npos ) return false;
31 
32  return true;
33  }
34 
35  return false;
36 }
37 
39 {
40  Interface*& mbImpl = _readNC->mbImpl;
41  std::vector< std::string >& dimNames = _readNC->dimNames;
42  std::vector< int >& dimLens = _readNC->dimLens;
43  std::map< std::string, ReadNC::VarData >& varInfo = _readNC->varInfo;
44  DebugOutput& dbgOut = _readNC->dbgOut;
45  bool& isParallel = _readNC->isParallel;
46  int& partMethod = _readNC->partMethod;
47  ScdParData& parData = _readNC->parData;
48 
49  // Look for names of i/j dimensions
50  // First i
51  std::vector< std::string >::iterator vit;
52  unsigned int idx;
53  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "slon" ) ) != dimNames.end() )
54  idx = vit - dimNames.begin();
55  else
56  {
57  MB_SET_ERR( MB_FAILURE, "Couldn't find 'slon' variable" );
58  }
59  iDim = idx;
60  gDims[0] = 0;
61  gDims[3] = dimLens[idx] - 1;
62 
63  // Then j
64  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "slat" ) ) != dimNames.end() )
65  idx = vit - dimNames.begin();
66  else
67  {
68  MB_SET_ERR( MB_FAILURE, "Couldn't find 'slat' variable" );
69  }
70  jDim = idx;
71  gDims[1] = 0;
72  gDims[4] = dimLens[idx] - 1 + 2; // Add 2 for the pole points
73 
74  // Look for names of center i/j dimensions
75  // First i
76  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "lon" ) ) != dimNames.end() )
77  idx = vit - dimNames.begin();
78  else
79  {
80  MB_SET_ERR( MB_FAILURE, "Couldn't find 'lon' variable" );
81  }
82  iCDim = idx;
83  gCDims[0] = 0;
84  gCDims[3] = dimLens[idx] - 1;
85 
86  // Check i periodicity and set globallyPeriodic[0]
87  std::vector< double > til_vals( 2 );
88  MB_CHK_SET_ERR( read_coordinate( "lon", gCDims[3] - 1, gCDims[3], til_vals ), "Trouble reading 'lon' variable" );
89  if( std::fabs( 2 * til_vals[1] - til_vals[0] - 360 ) < 0.001 ) globallyPeriodic[0] = 1;
90  if( globallyPeriodic[0] )
91  assert( "Number of vertices and edges should be same" && gDims[3] == gCDims[3] );
92  else
93  assert( "Number of vertices should equal to number of edges plus one" && gDims[3] == gCDims[3] + 1 );
94 
95  // Then j
96  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "lat" ) ) != dimNames.end() )
97  idx = vit - dimNames.begin();
98  else
99  {
100  MB_SET_ERR( MB_FAILURE, "Couldn't find 'lat' dimension" );
101  }
102  jCDim = idx;
103  gCDims[1] = 0;
104  gCDims[4] = dimLens[idx] - 1;
105 
106  // For FV models, will always be non-periodic in j
107  assert( gDims[4] == gCDims[4] + 1 );
108 
109  // Try a truly 2D mesh
110  gDims[2] = -1;
111  gDims[5] = -1;
112 
113  // Look for time dimension
114  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "time" ) ) != dimNames.end() )
115  idx = vit - dimNames.begin();
116  else if( ( vit = std::find( dimNames.begin(), dimNames.end(), "t" ) ) != dimNames.end() )
117  idx = vit - dimNames.begin();
118  else
119  {
120  MB_SET_ERR( MB_FAILURE, "Couldn't find 'time' or 't' dimension" );
121  }
122  tDim = idx;
123  nTimeSteps = dimLens[idx];
124 
125  // Get number of levels
126  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "lev" ) ) != dimNames.end() )
127  idx = vit - dimNames.begin();
128  else if( ( vit = std::find( dimNames.begin(), dimNames.end(), "ilev" ) ) != dimNames.end() )
129  idx = vit - dimNames.begin();
130  else
131  {
132  MB_SET_ERR( MB_FAILURE, "Couldn't find 'lev' or 'ilev' dimension" );
133  }
134  levDim = idx;
135  nLevels = dimLens[idx];
136 
137  // Parse options to get subset
138  int rank = 0, procs = 1;
139 #ifdef MOAB_HAVE_MPI
140  if( isParallel )
141  {
142  ParallelComm*& myPcomm = _readNC->myPcomm;
143  rank = myPcomm->proc_config().proc_rank();
144  procs = myPcomm->proc_config().proc_size();
145  }
146 #endif
147  if( procs > 1 )
148  {
149  for( int i = 0; i < 6; i++ )
150  parData.gDims[i] = gDims[i];
151  for( int i = 0; i < 3; i++ )
152  parData.gPeriodic[i] = globallyPeriodic[i];
153  parData.partMethod = partMethod;
154  int pdims[3];
155 
156  MB_CHK_ERR( ScdInterface::compute_partition( procs, rank, parData, lDims, locallyPeriodic, pdims ) );
157  for( int i = 0; i < 3; i++ )
158  parData.pDims[i] = pdims[i];
159 
160  dbgOut.tprintf( 1, "Partition: %dx%d (out of %dx%d)\n", lDims[3] - lDims[0] + 1, lDims[4] - lDims[1] + 1,
161  gDims[3] - gDims[0] + 1, gDims[4] - gDims[1] + 1 );
162  if( 0 == rank )
163  dbgOut.tprintf( 1, "Contiguous chunks of size %d bytes.\n",
164  8 * ( lDims[3] - lDims[0] + 1 ) * ( lDims[4] - lDims[1] + 1 ) );
165  }
166  else
167  {
168  for( int i = 0; i < 6; i++ )
169  lDims[i] = gDims[i];
171  }
172 
173  _opts.get_int_option( "IMIN", lDims[0] );
174  _opts.get_int_option( "IMAX", lDims[3] );
175  _opts.get_int_option( "JMIN", lDims[1] );
176  _opts.get_int_option( "JMAX", lDims[4] );
177 
178  // Now get actual coordinate values for vertices and cell centers
179  lCDims[0] = lDims[0];
180  if( locallyPeriodic[0] )
181  // If locally periodic, doesn't matter what global periodicity is, # vertex coords = # elem
182  // coords
183  lCDims[3] = lDims[3];
184  else
185  lCDims[3] = lDims[3] - 1;
186 
187  // For FV models, will always be non-periodic in j
188  lCDims[1] = lDims[1];
189  lCDims[4] = lDims[4] - 1;
190 
191  // Resize vectors to store values later
192  if( -1 != lDims[0] ) ilVals.resize( lDims[3] - lDims[0] + 1 );
193  if( -1 != lCDims[0] ) ilCVals.resize( lCDims[3] - lCDims[0] + 1 );
194  if( -1 != lDims[1] ) jlVals.resize( lDims[4] - lDims[1] + 1 );
195  if( -1 != lCDims[1] ) jlCVals.resize( lCDims[4] - lCDims[1] + 1 );
196  if( nTimeSteps > 0 ) tVals.resize( nTimeSteps );
197 
198  // Now read coord values
199  std::map< std::string, ReadNC::VarData >::iterator vmit;
200  if( -1 != lCDims[0] )
201  {
202  if( ( vmit = varInfo.find( "lon" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
203  {
204  MB_CHK_SET_ERR( read_coordinate( "lon", lCDims[0], lCDims[3], ilCVals ), "Trouble reading 'lon' variable" );
205  }
206  else
207  {
208  MB_SET_ERR( MB_FAILURE, "Couldn't find 'lon' variable" );
209  }
210  }
211 
212  if( -1 != lCDims[1] )
213  {
214  if( ( vmit = varInfo.find( "lat" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
215  {
216  MB_CHK_SET_ERR( read_coordinate( "lat", lCDims[1], lCDims[4], jlCVals ), "Trouble reading 'lat' variable" );
217  }
218  else
219  {
220  MB_SET_ERR( MB_FAILURE, "Couldn't find 'lat' variable" );
221  }
222  }
223 
224  if( -1 != lDims[0] )
225  {
226  if( ( vmit = varInfo.find( "slon" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
227  {
228  // Last column
229  if( !locallyPeriodic[0] && globallyPeriodic[0] && lDims[3] > gDims[3] )
230  {
231  assert( lDims[3] == gDims[3] + 1 );
232  std::vector< double > dummyVar( lDims[3] - lDims[0] );
233  MB_CHK_ERR( read_coordinate( "slon", lDims[0], lDims[3] - 1, dummyVar ) );
234  double dif = dummyVar[1] - dummyVar[0];
235  std::size_t i;
236  for( i = 0; i != dummyVar.size(); i++ )
237  ilVals[i] = dummyVar[i];
238  ilVals[i] = ilVals[i - 1] + dif;
239  }
240  else
241  {
242  MB_CHK_SET_ERR( read_coordinate( "slon", lDims[0], lDims[3], ilVals ),
243  "Trouble reading 'slon' variable" );
244  }
245  }
246  else
247  {
248  MB_SET_ERR( MB_FAILURE, "Couldn't find 'slon' variable" );
249  }
250  }
251 
252  if( -1 != lDims[1] )
253  {
254  if( ( vmit = varInfo.find( "slat" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
255  {
256  if( !isParallel || ( ( gDims[4] - gDims[1] ) == ( lDims[4] - lDims[1] ) ) )
257  {
258  std::vector< double > dummyVar( lDims[4] - lDims[1] - 1 );
259  MB_CHK_SET_ERR( read_coordinate( "slat", lDims[1], lDims[4] - 2, dummyVar ),
260  "Trouble reading 'slat' variable" );
261  // Copy the correct piece
262  jlVals[0] = -90.0;
263  std::size_t i = 0;
264  for( i = 1; i != dummyVar.size() + 1; i++ )
265  jlVals[i] = dummyVar[i - 1];
266  jlVals[i] = 90.0; // Using value of i after loop exits.
267  }
268  else
269  {
270  // If this is the first row
271  // Need to read one less then available and read it into a dummy var
272  if( lDims[1] == gDims[1] )
273  {
274  std::vector< double > dummyVar( lDims[4] - lDims[1] );
275  MB_CHK_SET_ERR( read_coordinate( "slat", lDims[1], lDims[4] - 1, dummyVar ),
276  "Trouble reading 'slat' variable" );
277  // Copy the correct piece
278  jlVals[0] = -90.0;
279  for( int i = 1; i < lDims[4] + 1; i++ )
280  jlVals[i] = dummyVar[i - 1];
281  }
282  // Or if it's the last row
283  else if( lDims[4] == gDims[4] )
284  {
285  std::vector< double > dummyVar( lDims[4] - lDims[1] );
286  MB_CHK_SET_ERR( read_coordinate( "slat", lDims[1] - 1, lDims[4] - 2, dummyVar ),
287  "Trouble reading 'slat' variable" );
288  // Copy the correct piece
289  std::size_t i = 0;
290  for( i = 0; i != dummyVar.size(); i++ )
291  jlVals[i] = dummyVar[i];
292  jlVals[i] = 90.0; // Using value of i after loop exits.
293  }
294  // It's in the middle
295  else
296  {
297  MB_CHK_SET_ERR( read_coordinate( "slat", lDims[1] - 1, lDims[4] - 1, jlVals ),
298  "Trouble reading 'slat' variable" );
299  }
300  }
301  }
302  else
303  {
304  MB_SET_ERR( MB_FAILURE, "Couldn't find 'slat' variable" );
305  }
306  }
307 
308  // Store time coordinate values in tVals
309  if( nTimeSteps > 0 )
310  {
311  if( ( vmit = varInfo.find( "time" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
312  {
313  MB_CHK_SET_ERR( read_coordinate( "time", 0, nTimeSteps - 1, tVals ), "Trouble reading 'time' variable" );
314  }
315  else if( ( vmit = varInfo.find( "t" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
316  {
317  MB_CHK_SET_ERR( read_coordinate( "t", 0, nTimeSteps - 1, tVals ), "Trouble reading 't' variable" );
318  }
319  else
320  {
321  // If expected time variable is not available, set dummy time coordinate values to tVals
322  for( int t = 0; t < nTimeSteps; t++ )
323  tVals.push_back( (double)t );
324  }
325  }
326 
327  dbgOut.tprintf( 1, "I=%d-%d, J=%d-%d\n", lDims[0], lDims[3], lDims[1], lDims[4] );
328  dbgOut.tprintf( 1, "%d elements, %d vertices\n", ( lDims[3] - lDims[0] ) * ( lDims[4] - lDims[1] ),
329  ( lDims[3] - lDims[0] + 1 ) * ( lDims[4] - lDims[1] + 1 ) );
330 
331  // For each variable, determine the entity location type and number of levels
332  std::map< std::string, ReadNC::VarData >::iterator mit;
333  for( mit = varInfo.begin(); mit != varInfo.end(); ++mit )
334  {
335  ReadNC::VarData& vd = ( *mit ).second;
336 
337  // Default entLoc is ENTLOCSET
338  if( std::find( vd.varDims.begin(), vd.varDims.end(), tDim ) != vd.varDims.end() )
339  {
340  if( ( std::find( vd.varDims.begin(), vd.varDims.end(), iCDim ) != vd.varDims.end() ) &&
341  ( std::find( vd.varDims.begin(), vd.varDims.end(), jCDim ) != vd.varDims.end() ) )
343  else if( ( std::find( vd.varDims.begin(), vd.varDims.end(), jDim ) != vd.varDims.end() ) &&
344  ( std::find( vd.varDims.begin(), vd.varDims.end(), iCDim ) != vd.varDims.end() ) )
346  else if( ( std::find( vd.varDims.begin(), vd.varDims.end(), jCDim ) != vd.varDims.end() ) &&
347  ( std::find( vd.varDims.begin(), vd.varDims.end(), iDim ) != vd.varDims.end() ) )
349  }
350 
351  // Default numLev is 0
352  if( std::find( vd.varDims.begin(), vd.varDims.end(), levDim ) != vd.varDims.end() ) vd.numLev = nLevels;
353  }
354 
355  std::vector< std::string > ijdimNames( 4 );
356  ijdimNames[0] = "__slon";
357  ijdimNames[1] = "__slat";
358  ijdimNames[2] = "__lon";
359  ijdimNames[3] = "__lat";
360 
361  std::string tag_name;
362  Tag tagh;
363 
364  // __<dim_name>_LOC_MINMAX (for slon, slat, lon and lat)
365  for( unsigned int i = 0; i != ijdimNames.size(); i++ )
366  {
367  std::vector< int > val( 2, 0 );
368  if( ijdimNames[i] == "__slon" )
369  {
370  val[0] = lDims[0];
371  val[1] = lDims[3];
372  }
373  else if( ijdimNames[i] == "__slat" )
374  {
375  val[0] = lDims[1];
376  val[1] = lDims[4];
377  }
378  else if( ijdimNames[i] == "__lon" )
379  {
380  val[0] = lCDims[0];
381  val[1] = lCDims[3];
382  }
383  else if( ijdimNames[i] == "__lat" )
384  {
385  val[0] = lCDims[1];
386  val[1] = lCDims[4];
387  }
388  std::stringstream ss_tag_name;
389  ss_tag_name << ijdimNames[i] << "_LOC_MINMAX";
390  tag_name = ss_tag_name.str();
391  MB_CHK_SET_ERR( mbImpl->tag_get_handle( tag_name.c_str(), 2, MB_TYPE_INTEGER, tagh,
393  "Trouble creating conventional tag " << tag_name );
394  MB_CHK_SET_ERR( mbImpl->tag_set_data( tagh, &_fileSet, 1, &val[0] ),
395  "Trouble setting data to conventional tag " << tag_name );
396  dbgOut.tprintf( 2, "Conventional tag %s is created.\n", tag_name.c_str() );
397  }
398 
399  // __<dim_name>_LOC_VALS (for slon, slat, lon and lat)
400  // Assume all have the same data type as lon (expected type is float or double)
401  switch( varInfo["lon"].varDataType )
402  {
403  case NC_FLOAT:
404  case NC_DOUBLE:
405  break;
406  default:
407  MB_SET_ERR( MB_FAILURE, "Unexpected variable data type for 'lon'" );
408  }
409 
410  for( unsigned int i = 0; i != ijdimNames.size(); i++ )
411  {
412  void* val = NULL;
413  int val_len = 0;
414  if( ijdimNames[i] == "__slon" )
415  {
416  val = &ilVals[0];
417  val_len = ilVals.size();
418  }
419  else if( ijdimNames[i] == "__slat" )
420  {
421  val = &jlVals[0];
422  val_len = jlVals.size();
423  }
424  else if( ijdimNames[i] == "__lon" )
425  {
426  val = &ilCVals[0];
427  val_len = ilCVals.size();
428  }
429  else if( ijdimNames[i] == "__lat" )
430  {
431  val = &jlCVals[0];
432  val_len = jlCVals.size();
433  }
434 
435  std::stringstream ss_tag_name;
436  ss_tag_name << ijdimNames[i] << "_LOC_VALS";
437  tag_name = ss_tag_name.str();
438  MB_CHK_SET_ERR( mbImpl->tag_get_handle( tag_name.c_str(), 0, MB_TYPE_DOUBLE, tagh,
440  "Trouble creating conventional tag " << tag_name );
441  MB_CHK_SET_ERR( mbImpl->tag_set_by_ptr( tagh, &_fileSet, 1, &val, &val_len ),
442  "Trouble setting data to conventional tag " << tag_name );
443  dbgOut.tprintf( 2, "Conventional tag %s is created.\n", tag_name.c_str() );
444  }
445 
446  // __<dim_name>_GLOBAL_MINMAX (for slon, slat, lon and lat)
447  for( unsigned int i = 0; i != ijdimNames.size(); i++ )
448  {
449  std::vector< int > val( 2, 0 );
450  if( ijdimNames[i] == "__slon" )
451  {
452  val[0] = gDims[0];
453  val[1] = gDims[3];
454  }
455  else if( ijdimNames[i] == "__slat" )
456  {
457  val[0] = gDims[1];
458  val[1] = gDims[4];
459  }
460  else if( ijdimNames[i] == "__lon" )
461  {
462  val[0] = gCDims[0];
463  val[1] = gCDims[3];
464  }
465  else if( ijdimNames[i] == "__lat" )
466  {
467  val[0] = gCDims[1];
468  val[1] = gCDims[4];
469  }
470  std::stringstream ss_tag_name;
471  ss_tag_name << ijdimNames[i] << "_GLOBAL_MINMAX";
472  tag_name = ss_tag_name.str();
473  MB_CHK_SET_ERR( mbImpl->tag_get_handle( tag_name.c_str(), 2, MB_TYPE_INTEGER, tagh,
475  "Trouble creating conventional tag " << tag_name );
476  MB_CHK_SET_ERR( mbImpl->tag_set_data( tagh, &_fileSet, 1, &val[0] ),
477  "Trouble setting data to conventional tag " << tag_name );
478  dbgOut.tprintf( 2, "Conventional tag %s is created.\n", tag_name.c_str() );
479  }
480 
481  // Hack: create dummy variables, if needed, for dimensions with no corresponding coordinate
482  // variables
483  MB_CHK_SET_ERR( create_dummy_variables(), "Failed to create dummy variables" );
484 
485  return MB_SUCCESS;
486 }
487 
488 } // namespace moab