Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
NCWriteHelper.cpp
Go to the documentation of this file.
1 /*
2  * NCWriteHelper.cpp
3  *
4  * Created on: Mar 28, 2014
5  * Author: iulian
6  */
7 
8 #include "NCWriteHelper.hpp"
9 #include "NCWriteEuler.hpp"
10 #include "NCWriteFV.hpp"
11 #include "NCWriteHOMME.hpp"
12 #include "NCWriteMPAS.hpp"
13 #include "NCWriteGCRM.hpp"
14 
15 #include "moab/WriteUtilIface.hpp"
16 #include "MBTagConventions.hpp"
17 
18 #include <sstream>
19 
20 #ifdef WIN32
21 #ifdef size_t
22 #undef size_t
23 #endif
24 #endif
25 
26 namespace moab
27 {
28 
29 //! Get appropriate helper instance for WriteNC class; based on some info in the file set
31  int fileId,
32  const FileOptions& opts,
33  EntityHandle fileSet )
34 {
35  std::string& grid_type = writeNC->grid_type;
36  if( grid_type == "CAM_EUL" )
37  return new( std::nothrow ) NCWriteEuler( writeNC, fileId, opts, fileSet );
38  else if( grid_type == "CAM_FV" )
39  return new( std::nothrow ) NCWriteFV( writeNC, fileId, opts, fileSet );
40  else if( grid_type == "CAM_SE" )
41  return new( std::nothrow ) NCWriteHOMME( writeNC, fileId, opts, fileSet );
42  else if( grid_type == "MPAS" )
43  return new( std::nothrow ) NCWriteMPAS( writeNC, fileId, opts, fileSet );
44  else if( grid_type == "GCRM" )
45  return new( std::nothrow ) NCWriteGCRM( writeNC, fileId, opts, fileSet );
46 
47  // Unknown NetCDF grid
48  return NULL;
49 }
50 
51 ErrorCode NCWriteHelper::collect_variable_data( std::vector< std::string >& var_names, std::vector< int >& tstep_nums )
52 {
53  Interface*& mbImpl = _writeNC->mbImpl;
54  std::vector< std::string >& dimNames = _writeNC->dimNames;
55  std::vector< int >& dimLens = _writeNC->dimLens;
56  std::set< std::string >& usedCoordinates = _writeNC->usedCoordinates;
57  std::set< std::string >& dummyVarNames = _writeNC->dummyVarNames;
58  std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
59  DebugOutput& dbgOut = _writeNC->dbgOut;
60 
61  usedCoordinates.clear();
62  if( tstep_nums.empty() && nTimeSteps > 0 )
63  {
64  // No timesteps input, get them all
65  for( int i = 0; i < nTimeSteps; i++ )
66  tstep_nums.push_back( i );
67  }
68 
69  for( size_t i = 0; i < var_names.size(); i++ )
70  {
71  std::string varname = var_names[i];
72  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname );
73  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname );
74 
75  WriteNC::VarData& currentVarData = vit->second;
76 
77  dbgOut.tprintf( 2, " for variable %s varDims.size %d \n", varname.c_str(),
78  (int)currentVarData.varDims.size() );
79  for( size_t j = 0; j < currentVarData.varDims.size(); j++ )
80  {
81  std::string dimName = dimNames[currentVarData.varDims[j]];
82  vit = varInfo.find( dimName );
83  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << dimName );
84 
85  usedCoordinates.insert( dimName ); // Collect those used, we will need to write them to the file
86  dbgOut.tprintf( 2, " for variable %s need dimension %s with length %d\n", varname.c_str(),
87  dimName.c_str(), dimLens[currentVarData.varDims[j]] );
88  }
89 
90  // Process coordinate variables later
91  if( usedCoordinates.find( varname ) != usedCoordinates.end() ) continue;
92 
93  // Default has_tsteps is false
94  if( std::find( currentVarData.varDims.begin(), currentVarData.varDims.end(), tDim ) !=
95  currentVarData.varDims.end() )
96  currentVarData.has_tsteps = true;
97 
98  // Default numLev is 0
99  if( ( std::find( currentVarData.varDims.begin(), currentVarData.varDims.end(), levDim ) !=
100  currentVarData.varDims.end() ) )
101  currentVarData.numLev = nLevels;
102 
103  // Process set variables
104  if( WriteNC::ENTLOCSET == currentVarData.entLoc )
105  {
106  if( currentVarData.has_tsteps )
107  {
108  // Set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen)
109  // TBD
110  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing set variables with timesteps is not implemented yet" );
111  }
112  else
113  {
114  // Get the tag with varname
115  Tag tag = 0;
116  MB_CHK_SET_ERR( mbImpl->tag_get_handle( varname.c_str(), tag ), "Can't find tag " << varname );
117  currentVarData.varTags.push_back( tag ); // Really, only one for these
118  const void* data;
119  int size;
120  MB_CHK_SET_ERR( mbImpl->tag_get_by_ptr( tag, &_fileSet, 1, &data, &size ),
121  "Can't get data of tag " << varname );
122 
123  // Find the type of tag, and use it
124  DataType type;
125  MB_CHK_SET_ERR( mbImpl->tag_get_data_type( tag, type ), "Can't get data type of tag " << varname );
126 
127  currentVarData.varDataType = NC_DOUBLE;
128  if( MB_TYPE_INTEGER == type ) currentVarData.varDataType = NC_INT;
129 
130  assert( 0 == currentVarData.memoryHogs.size() ); // Nothing so far
131  currentVarData.memoryHogs.push_back( (void*)data );
132 
133  if( currentVarData.varDims.empty() )
134  {
135  // Scalar variable
136  currentVarData.writeStarts.push_back( 0 );
137  currentVarData.writeCounts.push_back( 1 );
138  }
139  else
140  {
141  for( size_t j = 0; j < currentVarData.varDims.size(); j++ )
142  {
143  currentVarData.writeStarts.push_back( 0 );
144  currentVarData.writeCounts.push_back( dimLens[currentVarData.varDims[j]] );
145  }
146  }
147 
148  // Get variable size
149  currentVarData.sz = 1;
150  for( std::size_t idx = 0; idx != currentVarData.writeCounts.size(); idx++ )
151  currentVarData.sz *= currentVarData.writeCounts[idx];
152  }
153  } // if (WriteNC::ENTLOCSET == currentVarData.entLoc)
154  // Process non-set variables
155  else
156  {
157  Tag indexedTag = 0;
158 
159  if( currentVarData.has_tsteps )
160  {
161  for( unsigned int t = 0; t < tstep_nums.size(); t++ )
162  {
163  std::stringstream ssTagNameWithIndex;
164  ssTagNameWithIndex << varname << tstep_nums[t];
165  MB_CHK_SET_ERR( mbImpl->tag_get_handle( ssTagNameWithIndex.str().c_str(), indexedTag ),
166  "Can't find tag " << ssTagNameWithIndex.str() );
167  dbgOut.tprintf( 2, " found indexed tag %d with name %s\n", tstep_nums[t],
168  ssTagNameWithIndex.str().c_str() );
169  currentVarData.varTags.push_back( indexedTag );
170  }
171  }
172  else
173  {
174  // This should be a user-created non-set variable without timesteps
175  // Treat it like having one, 0th, timestep
176  std::stringstream ssTagNameWithIndex;
177  ssTagNameWithIndex << varname << 0;
178  MB_CHK_SET_ERR( mbImpl->tag_get_handle( ssTagNameWithIndex.str().c_str(), indexedTag ),
179  "Can't find tag " << ssTagNameWithIndex.str() << " for a user-created variable" );
180  dbgOut.tprintf( 2, " found indexed tag 0 with name %s\n", ssTagNameWithIndex.str().c_str() );
181  currentVarData.varTags.push_back( indexedTag );
182  }
183 
184  // The type of the tag is fixed though
185  DataType type;
186  MB_CHK_SET_ERR( mbImpl->tag_get_data_type( indexedTag, type ), "Can't get data type of tag " << varname );
187 
188  currentVarData.varDataType = NC_DOUBLE;
189  if( MB_TYPE_INTEGER == type ) currentVarData.varDataType = NC_INT;
190  }
191  } // for (size_t i = 0; i < var_names.size(); i++)
192 
193  // Process coordinate variables here
194  // Check that for used coordinates we have found the tags
195  for( std::set< std::string >::iterator setIt = usedCoordinates.begin(); setIt != usedCoordinates.end(); ++setIt )
196  {
197  const std::string& coordName = *setIt;
198 
199  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( coordName );
200  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << coordName );
201 
202  WriteNC::VarData& varCoordData = vit->second;
203  Tag coordTag = 0;
204  MB_CHK_SET_ERR( mbImpl->tag_get_handle( coordName.c_str(), coordTag ), "Can't find tag " << coordName );
205  varCoordData.varTags.push_back( coordTag ); // Really, only one for these
206 
207  const void* data;
208  int sizeCoordinate;
209  MB_CHK_SET_ERR( mbImpl->tag_get_by_ptr( coordTag, &_fileSet, 1, &data, &sizeCoordinate ),
210  "Can't get coordinate values of " << coordName );
211  dbgOut.tprintf( 2, " found coordinate tag with name %s and length %d\n", coordName.c_str(), sizeCoordinate );
212 
213  // Find the type of tag, and use it
214  DataType type;
215  MB_CHK_SET_ERR( mbImpl->tag_get_data_type( coordTag, type ), "Can't get data type of tag " << coordName );
216  varCoordData.varDataType = NC_DOUBLE;
217  if( MB_TYPE_INTEGER == type ) varCoordData.varDataType = NC_INT;
218 
219  // Get dimension length (the only dimension of this coordinate variable, with the same name)
220  assert( 1 == varCoordData.varDims.size() );
221  int coordDimLen = dimLens[varCoordData.varDims[0]];
222 
223  if( dummyVarNames.find( coordName ) != dummyVarNames.end() )
224  {
225  // For a dummy coordinate variable, the tag size is always 1
226  // The number of coordinates should be set to dimension length, instead of 1
227  assert( 1 == sizeCoordinate );
228  sizeCoordinate = coordDimLen;
229 
230  // No variable data to write
231  data = NULL;
232  }
233  else
234  {
235  // The number of coordinates should be exactly the same as dimension length
236  // However, if timesteps spread across files and time tag has been updated,
237  // sizeCoordinate will be larger
238  if( varCoordData.varDims[0] != tDim ) assert( sizeCoordinate == coordDimLen );
239  }
240 
241  // For time, the actual output size and values are determined by tstep_nums
242  if( varCoordData.varDims[0] == tDim )
243  {
244  // Does not apply to dummy time tag (e.g. 'Time' tag of MPAS), when timesteps
245  // spread across files
246  if( NULL != data ) assert( tstep_nums.size() > 0 && tstep_nums.size() <= (size_t)sizeCoordinate );
247 
248  sizeCoordinate = tstep_nums.size();
249 
250  if( NULL != data )
251  {
252  assert( NC_DOUBLE == varCoordData.varDataType );
253  timeStepVals.resize( sizeCoordinate );
254  for( unsigned int t = 0; t < tstep_nums.size(); t++ )
255  timeStepVals[t] = ( (double*)data )[tstep_nums[t]];
256 
257  data = &timeStepVals[0];
258  }
259  }
260 
261  // This is the length
262  varCoordData.sz = sizeCoordinate;
263  varCoordData.writeStarts.resize( 1 );
264  varCoordData.writeStarts[0] = 0;
265  varCoordData.writeCounts.resize( 1 );
266  varCoordData.writeCounts[0] = sizeCoordinate;
267 
268  assert( 0 == varCoordData.memoryHogs.size() ); // Nothing so far
269  varCoordData.memoryHogs.push_back( (void*)data );
270  } // for (std::set<std::string>::iterator setIt ...
271 
272  return MB_SUCCESS;
273 }
274 
275 ErrorCode NCWriteHelper::init_file( std::vector< std::string >& var_names,
276  std::vector< std::string >& desired_names,
277  bool append )
278 {
279  std::vector< std::string >& dimNames = _writeNC->dimNames;
280  std::set< std::string >& usedCoordinates = _writeNC->usedCoordinates;
281  std::set< std::string >& dummyVarNames = _writeNC->dummyVarNames;
282  std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
283  std::map< std::string, WriteNC::AttData >& globalAtts = _writeNC->globalAtts;
284  DebugOutput& dbgOut = _writeNC->dbgOut;
285 
286  int tDim_in_dimNames = tDim;
287  int levDim_in_dimNames = levDim;
288 
289  // If append mode, make sure we are in define mode; a simple open will not allow creation of new
290  // variables
291  if( append )
292  {
293  int errcode = NCFUNC( redef )( _fileId );
294  if( errcode != NC_NOERR ) MB_SET_ERR( MB_FAILURE, "Can't open file in redefine mode" );
295  }
296 
297  // First initialize all coordinates, then fill VarData for actual variables (and dimensions)
298  // Check that for used coordinates we have found the tags
299  for( std::set< std::string >::iterator setIt = usedCoordinates.begin(); setIt != usedCoordinates.end(); ++setIt )
300  {
301  const std::string& coordName = *setIt;
302 
303  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( coordName );
304  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << coordName );
305 
306  WriteNC::VarData& varCoordData = vit->second;
307  varCoordData.varDims.resize( 1 );
308 
309  // If not append, create it for sure
310  // If append, we might already have it, including the tag / variable with the same name
311  /*
312  * int ncmpi_inq_dimid(int ncid, const char *name, int *idp);
313  */
314  if( append )
315  {
316  int dimId;
317  if( NCFUNC( inq_dimid )( _fileId, coordName.c_str(), &dimId ) == NC_NOERR )
318  { // If not found, create it later
319  varCoordData.varDims[0] = dimId;
320  dbgOut.tprintf( 2, " file already has coordName %s dim id is %d \n", coordName.c_str(),
321  (int)varCoordData.varDims[0] );
322 
323  // Update tDim and levDim to actual dimension id
324  if( coordName == dimNames[tDim_in_dimNames] )
325  tDim = varCoordData.varDims[0];
326  else if( coordName == dimNames[levDim_in_dimNames] )
327  levDim = varCoordData.varDims[0];
328 
329  // Skip dummy coordinate variables (e.g. ncol)
330  if( dummyVarNames.find( coordName ) != dummyVarNames.end() ) continue;
331 
332  // Check that the coordinate is a variable too
333  // Inquire for a variable with the same name
334  int varId;
335  if( NCFUNC( inq_varid )( _fileId, coordName.c_str(), &varId ) != NC_NOERR )
336  MB_SET_ERR( MB_FAILURE, "We do not have a variable with the same name " << coordName );
337  // We should also check that this variable has one dimension, and it is dimId
338  varCoordData.varId = varId;
339  dbgOut.tprintf( 2, " file already has coordinate %s and varId is %d \n", coordName.c_str(), varId );
340 
341  continue; // Maybe more checks are needed here
342  }
343  }
344 
345  /* int nc_def_dim (int ncid, const char *name, size_t len, int *dimidp);
346  * example: status = nc_def_dim(fileId, "lat", 18L, &latid);
347  */
348 
349  // Actually define a dimension
350  if( NCFUNC( def_dim )( _fileId, coordName.c_str(), (size_t)varCoordData.sz, &varCoordData.varDims[0] ) !=
351  NC_NOERR )
352  MB_SET_ERR( MB_FAILURE, "Failed to generate dimension " << coordName );
353  dbgOut.tprintf( 2, " for coordName %s dim id is %d \n", coordName.c_str(), (int)varCoordData.varDims[0] );
354 
355  // Update tDim and levDim to actual dimension id
356  if( coordName == dimNames[tDim_in_dimNames] )
357  tDim = varCoordData.varDims[0];
358  else if( coordName == dimNames[levDim_in_dimNames] )
359  levDim = varCoordData.varDims[0];
360 
361  // Create a variable with the same name, and its only dimension the one we just defined
362  /*
363  * int nc_def_var (int ncid, const char *name, nc_type xtype,
364  int ndims, const int dimids[], int *varidp);
365  example:
366  http://www.unidata.ucar.edu/software/netcdf/docs/netcdf-c/nc_005fdef_005fvar.html#nc_005fdef_005fvar
367  */
368 
369  // Skip dummy coordinate variables (e.g. ncol)
370  if( dummyVarNames.find( coordName ) != dummyVarNames.end() ) continue;
371 
372  // Define a coordinate variable
373  if( NCFUNC( def_var )( _fileId, coordName.c_str(), varCoordData.varDataType, 1, &( varCoordData.varDims[0] ),
374  &varCoordData.varId ) != NC_NOERR )
375  MB_SET_ERR( MB_FAILURE, "Failed to create coordinate variable " << coordName );
376 
377  dbgOut.tprintf( 2, " for coordName %s variable id is %d \n", coordName.c_str(), varCoordData.varId );
378  }
379 
380  // Now look at requested variables, and update from the index in dimNames to the actual
381  // dimension id
382  for( size_t i = 0; i < var_names.size(); i++ )
383  {
384  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( var_names[i] );
385  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find requested variable " << var_names[i] );
386 
387  // Skip coordinate variables
388  if( usedCoordinates.find( var_names[i] ) != usedCoordinates.end() ) continue;
389 
390  WriteNC::VarData& variableData = vit->second;
391 
392  // The index is for dimNames; we need to find out the actual dimension id (from above)
393  int numDims = (int)variableData.varDims.size();
394  for( int j = 0; j < numDims; j++ )
395  {
396  std::string dimName = dimNames[variableData.varDims[j]];
397  std::map< std::string, WriteNC::VarData >::iterator vit2 = varInfo.find( dimName );
398  if( vit2 == varInfo.end() )
399  MB_SET_ERR( MB_FAILURE, "Can't find requested coordinate variable " << dimName );
400 
401  WriteNC::VarData& coordData = vit2->second;
402  // Index in dimNames to actual dimension id
403  variableData.varDims[j] = coordData.varDims[0]; // This one, being a coordinate, is the only one
404  dbgOut.tprintf( 2, " dimension with index %d name %s has ID %d \n", j, dimName.c_str(),
405  variableData.varDims[j] );
406  }
407 
408  // Define the variable now:
409  int errCode =
410  NCFUNC( def_var )( _fileId, desired_names[i].c_str(), variableData.varDataType,
411  (int)variableData.varDims.size(), &( variableData.varDims[0] ), &variableData.varId );
412  if( errCode != NC_NOERR ) MB_SET_ERR( MB_FAILURE, "Failed to create requested variable " << desired_names[i] );
413 
414  dbgOut.tprintf( 2, " for variable %s with desired name %s variable id is %d \n", var_names[i].c_str(),
415  desired_names[i].c_str(), variableData.varId );
416  // Now define the variable, with all dimensions
417  }
418 
419  // Define global attributes (exactly copied from the original file for the time being)
420  // Should we modify some of them (e.g. revision_Id) later?
421  std::map< std::string, WriteNC::AttData >::iterator attIt;
422  for( attIt = globalAtts.begin(); attIt != globalAtts.end(); ++attIt )
423  {
424  const std::string& attName = attIt->first;
425  WriteNC::AttData& attData = attIt->second;
426  NCDF_SIZE& attLen = attData.attLen;
427  nc_type& attDataType = attData.attDataType;
428  const std::string& attValue = attData.attValue;
429 
430  switch( attDataType )
431  {
432  case NC_BYTE:
433  case NC_CHAR:
434  if( NC_NOERR !=
435  NCFUNC( put_att_text )( _fileId, NC_GLOBAL, attName.c_str(), attLen, attValue.c_str() ) )
436  MB_SET_ERR( MB_FAILURE, "Failed to define text type attribute" );
437  break;
438  case NC_DOUBLE:
439  if( NC_NOERR != NCFUNC( put_att_double )( _fileId, NC_GLOBAL, attName.c_str(), NC_DOUBLE, 1,
440  (double*)attValue.c_str() ) )
441  MB_SET_ERR( MB_FAILURE, "Failed to define double type attribute" );
442  break;
443  case NC_FLOAT:
444  if( NC_NOERR != NCFUNC( put_att_float )( _fileId, NC_GLOBAL, attName.c_str(), NC_FLOAT, 1,
445  (float*)attValue.c_str() ) )
446  MB_SET_ERR( MB_FAILURE, "Failed to define float type attribute" );
447  break;
448  case NC_INT:
449  if( NC_NOERR !=
450  NCFUNC( put_att_int )( _fileId, NC_GLOBAL, attName.c_str(), NC_INT, 1, (int*)attValue.c_str() ) )
451  MB_SET_ERR( MB_FAILURE, "Failed to define int type attribute" );
452  break;
453  case NC_SHORT:
454  if( NC_NOERR != NCFUNC( put_att_short )( _fileId, NC_GLOBAL, attName.c_str(), NC_SHORT, 1,
455  (short*)attValue.c_str() ) )
456  MB_SET_ERR( MB_FAILURE, "Failed to define short type attribute" );
457  break;
458  default:
459  MB_SET_ERR( MB_FAILURE, "Unknown attribute data type" );
460  }
461  }
462 
463  // Take it out of define mode
464  if( NC_NOERR != NCFUNC( enddef )( _fileId ) ) MB_SET_ERR( MB_FAILURE, "Failed to close define mode" );
465 
466  return MB_SUCCESS;
467 }
468 
469 ErrorCode NCWriteHelper::write_values( std::vector< std::string >& var_names, std::vector< int >& tstep_nums )
470 {
471  std::set< std::string >& usedCoordinates = _writeNC->usedCoordinates;
472  std::set< std::string >& dummyVarNames = _writeNC->dummyVarNames;
473  std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
474 
475  std::vector< WriteNC::VarData > vdatas;
476  std::vector< WriteNC::VarData > vsetdatas;
477 
478  // For set variables, include coordinates used by requested var_names
479  for( std::set< std::string >::iterator setIt = usedCoordinates.begin(); setIt != usedCoordinates.end(); ++setIt )
480  {
481  const std::string& coordName = *setIt;
482 
483  // Skip dummy coordinate variables (if any)
484  if( dummyVarNames.find( coordName ) != dummyVarNames.end() ) continue;
485 
486  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( coordName );
487  if( vit == varInfo.end() )
488  {
489  MB_SET_ERR( MB_FAILURE, "Can't find coordinate variable " << coordName );
490  }
491 
492  vsetdatas.push_back( vit->second );
493  }
494 
495  // Collect non-set and set variables from requested var_names
496  for( unsigned int i = 0; i < var_names.size(); i++ )
497  {
498  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( var_names[i] );
499  if( vit == varInfo.end() )
500  {
501  MB_SET_ERR( MB_FAILURE, "Can't find requested variable " << var_names[i] );
502  }
503 
504  WriteNC::VarData& variableData = vit->second;
505  if( WriteNC::ENTLOCSET == variableData.entLoc )
506  {
507  // Used coordinates has all ready been included
508  if( usedCoordinates.find( var_names[i] ) != usedCoordinates.end() ) continue;
509 
510  vsetdatas.push_back( variableData );
511  }
512  else
513  vdatas.push_back( variableData );
514  }
515 
516  // Assume that the data ranges do not overlap across processors
517  // While overlapped writing might still work, we should better not take that risk
518  write_nonset_variables( vdatas, tstep_nums );
519 
520  // Use independent I/O mode put, since this write is only for the root processor
521  write_set_variables( vsetdatas, tstep_nums );
522 
523  return MB_SUCCESS;
524 }
525 
526 ErrorCode NCWriteHelper::write_set_variables( std::vector< WriteNC::VarData >& vsetdatas,
527  std::vector< int >& /* tstep_nums */ )
528 {
529  int success;
530 
531  // CAUTION: if the NetCDF ID is from a previous call to ncmpi_create rather than ncmpi_open,
532  // all processors need to call ncmpi_begin_indep_data(). If only the root processor does so,
533  // ncmpi_begin_indep_data() call will be blocked forever :(
534 #ifdef MOAB_HAVE_PNETCDF
535  // Enter independent I/O mode
536  success = NCFUNC( begin_indep_data )( _fileId );
537  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to begin independent I/O mode" );
538 #endif
539 
540  int rank = 0;
541 #ifdef MOAB_HAVE_MPI
542  bool& isParallel = _writeNC->isParallel;
543  if( isParallel )
544  {
545  ParallelComm*& myPcomm = _writeNC->myPcomm;
546  rank = myPcomm->proc_config().proc_rank();
547  }
548 #endif
549  if( 0 == rank )
550  {
551  for( unsigned int i = 0; i < vsetdatas.size(); i++ )
552  {
553  WriteNC::VarData& variableData = vsetdatas[i];
554 
555  // Set variables with timesteps, e.g. xtime(Time) or xtime(Time, StrLen)
556  if( variableData.has_tsteps )
557  {
558  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing set variables with timesteps is not implemented yet" );
559  }
560 
561  switch( variableData.varDataType )
562  {
563  case NC_DOUBLE:
564  // Independent I/O mode put
565  success = NCFUNCP( _vara_double )( _fileId, variableData.varId, &variableData.writeStarts[0],
566  &variableData.writeCounts[0],
567  (double*)( variableData.memoryHogs[0] ) );
568  if( success )
569  MB_SET_ERR( MB_FAILURE, "Failed to write double data for variable " << variableData.varName );
570  break;
571  case NC_INT:
572  // Independent I/O mode put
573  success =
574  NCFUNCP( _vara_int )( _fileId, variableData.varId, &variableData.writeStarts[0],
575  &variableData.writeCounts[0], (int*)( variableData.memoryHogs[0] ) );
576  if( success )
577  MB_SET_ERR( MB_FAILURE, "Failed to write int data for variable " << variableData.varName );
578  break;
579  default:
580  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double or non-int data is not implemented yet" );
581  }
582  }
583  }
584 
585 #ifdef MOAB_HAVE_PNETCDF
586  // End independent I/O mode
587  success = NCFUNC( end_indep_data )( _fileId );
588  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to end independent I/O mode" );
589 #endif
590 
591  return MB_SUCCESS;
592 }
593 
595 {
596  Interface*& mbImpl = _writeNC->mbImpl;
597  std::vector< std::string >& dimNames = _writeNC->dimNames;
598  std::vector< int >& dimLens = _writeNC->dimLens;
599 
600  // Look for time dimension
601  std::vector< std::string >::iterator vecIt;
602  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "time" ) ) != dimNames.end() )
603  tDim = vecIt - dimNames.begin();
604  else if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "t" ) ) != dimNames.end() )
605  tDim = vecIt - dimNames.begin();
606  else
607  {
608  MB_SET_ERR( MB_FAILURE, "Couldn't find 'time' or 't' dimension" );
609  }
610  nTimeSteps = dimLens[tDim];
611 
612  // Get number of levels
613  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "lev" ) ) != dimNames.end() )
614  levDim = vecIt - dimNames.begin();
615  else if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "ilev" ) ) != dimNames.end() )
616  levDim = vecIt - dimNames.begin();
617  else
618  {
619  MB_SET_ERR( MB_FAILURE, "Couldn't find 'lev' or 'ilev' dimension" );
620  }
621  nLevels = dimLens[levDim];
622 
623  // __<dim_name>_LOC_MINMAX (for slon, slat, lon and lat)
624  Tag convTag = 0;
625  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "__slon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY ),
626  "Trouble getting conventional tag __slon_LOC_MINMAX" );
627  int val[2];
628  MB_CHK_SET_ERR( mbImpl->tag_get_data( convTag, &_fileSet, 1, val ),
629  "Trouble getting data of conventional tag __slon_LOC_MINMAX" );
630  lDims[0] = val[0];
631  lDims[3] = val[1];
632 
633  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "__slat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY ),
634  "Trouble getting conventional tag __slat_LOC_MINMAX" );
635  MB_CHK_SET_ERR( mbImpl->tag_get_data( convTag, &_fileSet, 1, val ),
636  "Trouble getting data of conventional tag __slat_LOC_MINMAX" );
637  lDims[1] = val[0];
638  lDims[4] = val[1];
639 
640  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "__lon_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY ),
641  "Trouble getting conventional tag __lon_LOC_MINMAX" );
642  MB_CHK_SET_ERR( mbImpl->tag_get_data( convTag, &_fileSet, 1, val ),
643  "Trouble getting data of conventional tag __lon_LOC_MINMAX" );
644  lCDims[0] = val[0];
645  lCDims[3] = val[1];
646 
647  MB_CHK_SET_ERR( mbImpl->tag_get_handle( "__lat_LOC_MINMAX", 0, MB_TYPE_INTEGER, convTag, MB_TAG_ANY ),
648  "Trouble getting conventional tag __lat_LOC_MINMAX" );
649  MB_CHK_SET_ERR( mbImpl->tag_get_data( convTag, &_fileSet, 1, val ),
650  "Trouble getting data of conventional tag __lat_LOC_MINMAX" );
651  lCDims[1] = val[0];
652  lCDims[4] = val[1];
653 
654  // Get local faces
656  "Trouble getting local faces in current file set" );
657  assert( !localCellsOwned.empty() );
658 
659 #ifdef MOAB_HAVE_MPI
660  bool& isParallel = _writeNC->isParallel;
661  if( isParallel )
662  {
663  ParallelComm*& myPcomm = _writeNC->myPcomm;
664  int procs = myPcomm->proc_config().proc_size();
665  if( procs > 1 )
666  {
668  "Trouble getting owned faces in current file set" );
669  }
670  }
671 #endif
672 
673  return MB_SUCCESS;
674 }
675 
676 ErrorCode ScdNCWriteHelper::collect_variable_data( std::vector< std::string >& var_names,
677  std::vector< int >& tstep_nums )
678 {
679  NCWriteHelper::collect_variable_data( var_names, tstep_nums );
680 
681  std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
682 
683  for( size_t i = 0; i < var_names.size(); i++ )
684  {
685  std::string varname = var_names[i];
686  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname );
687  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname );
688 
689  WriteNC::VarData& currentVarData = vit->second;
690 #ifndef NDEBUG
691  std::vector< int >& varDims = currentVarData.varDims;
692 #endif
693 
694  // Skip set variables, which were already processed in
695  // NCWriteHelper::collect_variable_data()
696  if( WriteNC::ENTLOCSET == currentVarData.entLoc ) continue;
697 
698  // Set up writeStarts and writeCounts (maximum number of dimensions is 4)
699  currentVarData.writeStarts.resize( 4 );
700  currentVarData.writeCounts.resize( 4 );
701  unsigned int dim_idx = 0;
702 
703  // First: time
704  if( currentVarData.has_tsteps )
705  {
706  // Non-set variables with timesteps
707  // 4 dimensions like (time, lev, lat, lon)
708  // 3 dimensions like (time, lat, lon)
709  assert( 4 == varDims.size() || 3 == varDims.size() );
710 
711  // Time should be the first dimension
712  assert( tDim == varDims[0] );
713 
714  currentVarData.writeStarts[dim_idx] = 0; // This value is timestep dependent, will be set later
715  currentVarData.writeCounts[dim_idx] = 1;
716  dim_idx++;
717  }
718  else
719  {
720  // Non-set variables without timesteps
721  // 3 dimensions like (lev, lat, lon)
722  // 2 dimensions like (lat, lon)
723  assert( 3 == varDims.size() || 2 == varDims.size() );
724  }
725 
726  // Next: lev
727  if( currentVarData.numLev > 0 )
728  {
729  // Non-set variables with levels
730  // 4 dimensions like (time, lev, lat, lon)
731  // 3 dimensions like (lev, lat, lon)
732  assert( 4 == varDims.size() || 3 == varDims.size() );
733 
734  currentVarData.writeStarts[dim_idx] = 0;
735  currentVarData.writeCounts[dim_idx] = currentVarData.numLev;
736  dim_idx++;
737  }
738  else
739  {
740  // Non-set variables without levels
741  // 3 dimensions like (time, lat, lon)
742  // 2 dimensions like (lat, lon)
743  assert( 3 == varDims.size() || 2 == varDims.size() );
744  }
745 
746  // Finally: lat and lon
747  switch( currentVarData.entLoc )
748  {
749  case WriteNC::ENTLOCFACE:
750  // Faces
751  currentVarData.writeStarts[dim_idx] = lCDims[1];
752  currentVarData.writeCounts[dim_idx] = lCDims[4] - lCDims[1] + 1;
753  currentVarData.writeStarts[dim_idx + 1] = lCDims[0];
754  currentVarData.writeCounts[dim_idx + 1] = lCDims[3] - lCDims[0] + 1;
755  break;
756  default:
757  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << varname );
758  }
759  dim_idx += 2;
760 
761  // Get variable size
762  currentVarData.sz = 1;
763  for( std::size_t idx = 0; idx < dim_idx; idx++ )
764  currentVarData.sz *= currentVarData.writeCounts[idx];
765  } // for (size_t i = 0; i < var_names.size(); i++)
766 
767  return MB_SUCCESS;
768 }
769 
770 // Write CAM-EUL and CAM-FV non-set variables on non-shared quads (e.g. T)
771 // We assume that there are no variables on vertices and we do not support
772 // variables on edges (e.g. US in CAM-FV) for the time being
773 ErrorCode ScdNCWriteHelper::write_nonset_variables( std::vector< WriteNC::VarData >& vdatas,
774  std::vector< int >& tstep_nums )
775 {
776  Interface*& mbImpl = _writeNC->mbImpl;
777 
778  int success;
779 
780  // For each indexed variable tag, write a time step data
781  for( unsigned int i = 0; i < vdatas.size(); i++ )
782  {
783  WriteNC::VarData& variableData = vdatas[i];
784 
785  // Assume this variable is on faces for the time being
786  switch( variableData.entLoc )
787  {
788  case WriteNC::ENTLOCFACE:
789  // Faces
790  break;
791  default:
792  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << variableData.varName );
793  }
794 
795  unsigned int num_timesteps;
796  unsigned int lat_idx = 0;
797  unsigned int lon_idx = 1;
798  if( variableData.has_tsteps )
799  {
800  // Non-set variables with timesteps
801  // 4 dimensions like (time, lev, lat, lon)
802  // 3 dimensions like (time, lat, lon)
803  num_timesteps = tstep_nums.size();
804  lat_idx++;
805  lon_idx++;
806  }
807  else
808  {
809  // Non-set variables without timesteps
810  // 3 dimensions like (lev, lat, lon)
811  // 2 dimensions like (lat, lon)
812  num_timesteps = 1;
813  }
814 
815  unsigned int num_lev;
816  if( variableData.numLev > 0 )
817  {
818  // Non-set variables with levels
819  // 4 dimensions like (time, lev, lat, lon)
820  // 3 dimensions like (lev, lat, lon)
821  num_lev = variableData.numLev;
822  lat_idx++;
823  lon_idx++;
824  }
825  else
826  {
827  // Non-set variables without levels
828  // 3 dimensions like (time, lat, lon)
829  // 2 dimensions like (lat, lon)
830  num_lev = 1;
831  }
832 
833  size_t ni = variableData.writeCounts[lon_idx]; // lon
834  size_t nj = variableData.writeCounts[lat_idx]; // lat
835 
836  // At each timestep, we need to transpose tag format (lat, lon, lev) back
837  // to NC format (lev, lat, lon) for writing
838  for( unsigned int t = 0; t < num_timesteps; t++ )
839  {
840  // We will write one time step, and count will be one; start will be different
841  // Use tag_iterate to get tag data (assume that localCellsOwned is contiguous)
842  // We should also transpose for level so that means deep copy for transpose
843  if( tDim == variableData.varDims[0] ) variableData.writeStarts[0] = t; // This is start for time
844  int count;
845  void* dataptr;
846  MB_CHK_SET_ERR( mbImpl->tag_iterate( variableData.varTags[t], localCellsOwned.begin(),
847  localCellsOwned.end(), count, dataptr ),
848  "Failed to iterate tag on owned faces" );
849  assert( count == (int)localCellsOwned.size() );
850 
851  // Now transpose and write tag data
852  // Use collective I/O mode put (synchronous write) for the time being, we can try
853  // nonblocking put (request aggregation) later
854  switch( variableData.varDataType )
855  {
856  case NC_DOUBLE: {
857  std::vector< double > tmpdoubledata( ni * nj * num_lev );
858  if( num_lev > 1 )
859  // Transpose (lat, lon, lev) back to (lev, lat, lon)
860  jik_to_kji( ni, nj, num_lev, &tmpdoubledata[0], (double*)( dataptr ) );
861  success = NCFUNCAP( _vara_double )( _fileId, variableData.varId, &variableData.writeStarts[0],
862  &variableData.writeCounts[0], &tmpdoubledata[0] );
863  if( success )
864  MB_SET_ERR( MB_FAILURE, "Failed to write double data for variable " << variableData.varName );
865  break;
866  }
867  default:
868  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double data is not implemented yet" );
869  }
870  }
871  }
872 
873  return MB_SUCCESS;
874 }
875 
876 } /* namespace moab */