Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
NCWriteMPAS.cpp
Go to the documentation of this file.
1 /*
2  * NCWriteMPAS.cpp
3  *
4  * Created on: April 9, 2014
5  */
6 
7 #include "NCWriteMPAS.hpp"
8 #include "MBTagConventions.hpp"
9 
10 namespace moab
11 {
12 
14 {
15  // TODO Auto-generated destructor stub
16 }
17 
19 {
20  Interface*& mbImpl = _writeNC->mbImpl;
21  std::vector< std::string >& dimNames = _writeNC->dimNames;
22  std::vector< int >& dimLens = _writeNC->dimLens;
23  Tag& mGlobalIdTag = _writeNC->mGlobalIdTag;
24 
25  // Look for time dimension
26  std::vector< std::string >::iterator vecIt;
27  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "Time" ) ) != dimNames.end() )
28  tDim = vecIt - dimNames.begin();
29  else if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "time" ) ) != dimNames.end() )
30  tDim = vecIt - dimNames.begin();
31  else
32  {
33  MB_SET_ERR( MB_FAILURE, "Couldn't find 'Time' or 'time' dimension" );
34  }
35  nTimeSteps = dimLens[tDim];
36 
37  // Get number of levels
38  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nVertLevels" ) ) != dimNames.end() )
39  levDim = vecIt - dimNames.begin();
40  else
41  {
42  MB_SET_ERR( MB_FAILURE, "Couldn't find 'nVertLevels' dimension" );
43  }
44  nLevels = dimLens[levDim];
45 
46  // Get local vertices
48  "Trouble getting local vertices in current file set" );
49  assert( !localVertsOwned.empty() );
50 
51  // Get local edges
53  "Trouble getting local edges in current file set" );
54  // There are no edges if NO_EDGES read option is set
55 
56  // Get local cells
58  "Trouble getting local cells in current file set" );
59  assert( !localCellsOwned.empty() );
60 
61 #ifdef MOAB_HAVE_MPI
62  bool& isParallel = _writeNC->isParallel;
63  if( isParallel )
64  {
65  ParallelComm*& myPcomm = _writeNC->myPcomm;
66  int rank = myPcomm->proc_config().proc_rank();
67  int procs = myPcomm->proc_config().proc_size();
68  if( procs > 1 )
69  {
70 #ifndef NDEBUG
71  unsigned int num_local_verts = localVertsOwned.size();
72 #endif
74  "Trouble getting owned vertices in current file set" );
75 
76  // Assume that PARALLEL_RESOLVE_SHARED_ENTS option is set
77  // Verify that not all local vertices are owned by the last processor
78  if( procs - 1 == rank )
79  assert( "PARALLEL_RESOLVE_SHARED_ENTS option is set" && localVertsOwned.size() < num_local_verts );
80 
81  if( !localEdgesOwned.empty() )
82  {
84  "Trouble getting owned edges in current file set" );
85  }
86 
88  "Trouble getting owned cells in current file set" );
89  }
90  }
91 #endif
92 
93  std::vector< int > gids( localVertsOwned.size() );
94  MB_CHK_SET_ERR( mbImpl->tag_get_data( mGlobalIdTag, localVertsOwned, &gids[0] ),
95  "Trouble getting global IDs on local vertices" );
96 
97  // Get localGidVertsOwned
98  std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidVertsOwned ) );
99 
100  if( !localEdgesOwned.empty() )
101  {
102  gids.resize( localEdgesOwned.size() );
103  MB_CHK_SET_ERR( mbImpl->tag_get_data( mGlobalIdTag, localEdgesOwned, &gids[0] ),
104  "Trouble getting global IDs on local edges" );
105 
106  // Get localGidEdgesOwned
107  std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidEdgesOwned ) );
108  }
109 
110  gids.resize( localCellsOwned.size() );
111  MB_CHK_SET_ERR( mbImpl->tag_get_data( mGlobalIdTag, localCellsOwned, &gids[0] ),
112  "Trouble getting global IDs on local cells" );
113 
114  // Get localGidCellsOwned
115  std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidCellsOwned ) );
116 
117  return MB_SUCCESS;
118 }
119 
120 ErrorCode NCWriteMPAS::collect_variable_data( std::vector< std::string >& var_names, std::vector< int >& tstep_nums )
121 {
122  NCWriteHelper::collect_variable_data( var_names, tstep_nums );
123 
124  std::vector< std::string >& dimNames = _writeNC->dimNames;
125  std::vector< int >& dimLens = _writeNC->dimLens;
126 
127  // Dimension indices for other optional levels
128  std::vector< unsigned int > opt_lev_dims;
129 
130  unsigned int lev_idx;
131  std::vector< std::string >::iterator vecIt;
132 
133  // Get index of vertex levels P1
134  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nVertLevelsP1" ) ) != dimNames.end() )
135  {
136  lev_idx = vecIt - dimNames.begin();
137  opt_lev_dims.push_back( lev_idx );
138  }
139 
140  // Get index of vertex levels P2
141  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nVertLevelsP2" ) ) != dimNames.end() )
142  {
143  lev_idx = vecIt - dimNames.begin();
144  opt_lev_dims.push_back( lev_idx );
145  }
146 
147  // Get index of soil levels
148  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "nSoilLevels" ) ) != dimNames.end() )
149  {
150  lev_idx = vecIt - dimNames.begin();
151  opt_lev_dims.push_back( lev_idx );
152  }
153 
154  std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
155 
156  for( size_t i = 0; i < var_names.size(); i++ )
157  {
158  std::string varname = var_names[i];
159  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname );
160  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname );
161 
162  WriteNC::VarData& currentVarData = vit->second;
163  std::vector< int >& varDims = currentVarData.varDims;
164 
165  // Skip edge variables, if there are no edges
166  if( localEdgesOwned.empty() && currentVarData.entLoc == WriteNC::ENTLOCEDGE ) continue;
167 
168  // If nVertLevels dimension is not found, try other optional levels such as nVertLevelsP1
169  if( std::find( varDims.begin(), varDims.end(), levDim ) == varDims.end() )
170  {
171  for( unsigned int j = 0; j < opt_lev_dims.size(); j++ )
172  {
173  if( std::find( varDims.begin(), varDims.end(), opt_lev_dims[j] ) != varDims.end() )
174  {
175  currentVarData.numLev = dimLens[opt_lev_dims[j]];
176  break;
177  }
178  }
179  }
180 
181  // Skip set variables, which were already processed in
182  // NCWriteHelper::collect_variable_data()
183  if( WriteNC::ENTLOCSET == currentVarData.entLoc ) continue;
184 
185  // Set up writeStarts and writeCounts (maximum number of dimensions is 3)
186  currentVarData.writeStarts.resize( 3 );
187  currentVarData.writeCounts.resize( 3 );
188  unsigned int dim_idx = 0;
189 
190  // First: Time
191  if( currentVarData.has_tsteps )
192  {
193  // Non-set variables with timesteps
194  // 3 dimensions like (Time, nCells, nVertLevels)
195  // 2 dimensions like (Time, nCells)
196  assert( 3 == varDims.size() || 2 == varDims.size() );
197 
198  // Time should be the first dimension
199  assert( tDim == varDims[0] );
200 
201  currentVarData.writeStarts[dim_idx] = 0; // This value is timestep dependent, will be set later
202  currentVarData.writeCounts[dim_idx] = 1;
203  dim_idx++;
204  }
205  else
206  {
207  // Non-set variables without timesteps
208  // 2 dimensions like (nCells, nVertLevels)
209  // 1 dimension like (nCells)
210  assert( 2 == varDims.size() || 1 == varDims.size() );
211  }
212 
213  // Next: nVertices / nCells / nEdges
214  switch( currentVarData.entLoc )
215  {
216  case WriteNC::ENTLOCVERT:
217  // Vertices
218  // Start from the first localGidVerts
219  // Actually, this will be reset later for writing
220  currentVarData.writeStarts[dim_idx] = localGidVertsOwned[0] - 1;
221  currentVarData.writeCounts[dim_idx] = localGidVertsOwned.size();
222  break;
223  case WriteNC::ENTLOCFACE:
224  // Faces
225  // Start from the first localGidCells
226  // Actually, this will be reset later for writing
227  currentVarData.writeStarts[dim_idx] = localGidCellsOwned[0] - 1;
228  currentVarData.writeCounts[dim_idx] = localGidCellsOwned.size();
229  break;
230  case WriteNC::ENTLOCEDGE:
231  // Edges
232  // Start from the first localGidEdges
233  // Actually, this will be reset later for writing
234  currentVarData.writeStarts[dim_idx] = localGidEdgesOwned[0] - 1;
235  currentVarData.writeCounts[dim_idx] = localGidEdgesOwned.size();
236  break;
237  default:
238  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << varname );
239  }
240  dim_idx++;
241 
242  // Finally: nVertLevels or other optional levels, it is possible that there is no
243  // level dimension (numLev is 0) for this non-set variable, e.g. (Time, nCells)
244  if( currentVarData.numLev > 0 )
245  {
246  // Non-set variables with levels
247  // 3 dimensions like (Time, nCells, nVertLevels)
248  // 2 dimensions like (nCells, nVertLevels)
249  assert( 3 == varDims.size() || 2 == varDims.size() );
250 
251  currentVarData.writeStarts[dim_idx] = 0;
252  currentVarData.writeCounts[dim_idx] = currentVarData.numLev;
253  dim_idx++;
254  }
255  else
256  {
257  // Non-set variables without levels
258  // 2 dimensions like (Time, nCells)
259  // 1 dimension like (nCells)
260  assert( 2 == varDims.size() || 1 == varDims.size() );
261  }
262 
263  // Get variable size
264  currentVarData.sz = 1;
265  for( std::size_t idx = 0; idx < dim_idx; idx++ )
266  currentVarData.sz *= currentVarData.writeCounts[idx];
267  }
268 
269  return MB_SUCCESS;
270 }
271 
272 ErrorCode NCWriteMPAS::write_nonset_variables( std::vector< WriteNC::VarData >& vdatas, std::vector< int >& tstep_nums )
273 {
274  Interface*& mbImpl = _writeNC->mbImpl;
275 
276  int success;
277 
278  // For each variable tag in the indexed lists, write a time step data
279  for( unsigned int i = 0; i < vdatas.size(); i++ )
280  {
281  WriteNC::VarData& variableData = vdatas[i];
282 
283  // Skip edge variables, if there are no edges
284  if( localEdgesOwned.empty() && variableData.entLoc == WriteNC::ENTLOCEDGE ) continue;
285 
286  // Get local owned entities of this variable
287  Range* pLocalEntsOwned = NULL;
288  Range* pLocalGidEntsOwned = NULL;
289  switch( variableData.entLoc )
290  {
291  case WriteNC::ENTLOCVERT:
292  // Vertices
293  pLocalEntsOwned = &localVertsOwned;
294  pLocalGidEntsOwned = &localGidVertsOwned;
295  break;
296  case WriteNC::ENTLOCEDGE:
297  // Edges
298  pLocalEntsOwned = &localEdgesOwned;
299  pLocalGidEntsOwned = &localGidEdgesOwned;
300  break;
301  case WriteNC::ENTLOCFACE:
302  // Cells
303  pLocalEntsOwned = &localCellsOwned;
304  pLocalGidEntsOwned = &localGidCellsOwned;
305  break;
306  default:
307  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << variableData.varName );
308  }
309 
310  unsigned int num_timesteps;
311  unsigned int ents_idx = 0;
312  if( variableData.has_tsteps )
313  {
314  // Non-set variables with timesteps
315  // 3 dimensions like (Time, nCells, nVertLevels)
316  // 2 dimensions like (Time, nCells)
317  num_timesteps = tstep_nums.size();
318  ents_idx++;
319  }
320  else
321  {
322  // Non-set variables without timesteps
323  // 2 dimensions like (nCells, nVertLevels)
324  // 1 dimension like (nCells)
325  num_timesteps = 1;
326  }
327 
328  unsigned int num_lev;
329  if( variableData.numLev > 0 )
330  {
331  // Non-set variables with levels
332  // 3 dimensions like (Time, nCells, nVertLevels)
333  // 2 dimensions like (nCells, nVertLevels)
334  num_lev = variableData.numLev;
335  }
336  else
337  {
338  // Non-set variables without levels
339  // 2 dimensions like (Time, nCells)
340  // 1 dimension like (nCells)
341  num_lev = 1;
342  }
343 
344  for( unsigned int t = 0; t < num_timesteps; t++ )
345  {
346  // We will write one time step, and count will be one; start will be different
347  // Use tag_get_data instead of tag_iterate to copy tag data, as localEntsOwned
348  // might not be contiguous.
349  if( tDim == variableData.varDims[0] ) variableData.writeStarts[0] = t; // This is start for time
350  std::vector< double > tag_data( pLocalEntsOwned->size() * num_lev );
351  MB_CHK_SET_ERR( mbImpl->tag_get_data( variableData.varTags[t], *pLocalEntsOwned, &tag_data[0] ),
352  "Trouble getting tag data on owned entities" );
353 
354 #ifdef MOAB_HAVE_PNETCDF
355  size_t nb_writes = pLocalGidEntsOwned->psize();
356  std::vector< int > requests( nb_writes ), statuss( nb_writes );
357  size_t idxReq = 0;
358 #endif
359 
360  // Now write copied tag data
361  // Use nonblocking put (request aggregation)
362  switch( variableData.varDataType )
363  {
364  case NC_DOUBLE: {
365  size_t indexInDoubleArray = 0;
366  size_t ic = 0;
367  for( Range::pair_iterator pair_iter = pLocalGidEntsOwned->pair_begin();
368  pair_iter != pLocalGidEntsOwned->pair_end(); ++pair_iter, ic++ )
369  {
370  EntityHandle starth = pair_iter->first;
371  EntityHandle endh = pair_iter->second;
372  variableData.writeStarts[ents_idx] = (NCDF_SIZE)( starth - 1 );
373  variableData.writeCounts[ents_idx] = (NCDF_SIZE)( endh - starth + 1 );
374 
375  // Do a partial write, in each subrange
376 #ifdef MOAB_HAVE_PNETCDF
377  // Wait outside this loop
378  success =
379  NCFUNCREQP( _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
380  &( variableData.writeCounts[0] ),
381  &( tag_data[indexInDoubleArray] ), &requests[idxReq++] );
382 #else
383  success = NCFUNCAP(
384  _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
385  &( variableData.writeCounts[0] ), &( tag_data[indexInDoubleArray] ) );
386 #endif
387  if( success )
388  MB_SET_ERR( MB_FAILURE,
389  "Failed to write double data in a loop for variable " << variableData.varName );
390  // We need to increment the index in double array for the
391  // next subrange
392  indexInDoubleArray += ( endh - starth + 1 ) * num_lev;
393  }
394  assert( ic == pLocalGidEntsOwned->psize() );
395 #ifdef MOAB_HAVE_PNETCDF
396  success = ncmpi_wait_all( _fileId, requests.size(), &requests[0], &statuss[0] );
397  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
398 #endif
399  break;
400  }
401  default:
402  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double data is not implemented yet" );
403  }
404  }
405  }
406 
407  return MB_SUCCESS;
408 }
409 
410 } /* namespace moab */