Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
NCWriteGCRM.cpp
Go to the documentation of this file.
1 /*
2  * NCWriteGCRM.cpp
3  *
4  * Created on: April 9, 2014
5  */
6 
7 #include "NCWriteGCRM.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(), "layers" ) ) != dimNames.end() )
39  levDim = vecIt - dimNames.begin();
40  else
41  {
42  MB_SET_ERR( MB_FAILURE, "Couldn't find 'layers' 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 NCWriteGCRM::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 interface levels
134  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "interfaces" ) ) != dimNames.end() )
135  {
136  lev_idx = vecIt - dimNames.begin();
137  opt_lev_dims.push_back( lev_idx );
138  }
139 
140  std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
141 
142  for( size_t i = 0; i < var_names.size(); i++ )
143  {
144  std::string varname = var_names[i];
145  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname );
146  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname );
147 
148  WriteNC::VarData& currentVarData = vit->second;
149  std::vector< int >& varDims = currentVarData.varDims;
150 
151  // Skip edge variables, if there are no edges
152  if( localEdgesOwned.empty() && currentVarData.entLoc == WriteNC::ENTLOCEDGE ) continue;
153 
154  // If layers dimension is not found, try other optional levels such as interfaces
155  if( std::find( varDims.begin(), varDims.end(), levDim ) == varDims.end() )
156  {
157  for( unsigned int j = 0; j < opt_lev_dims.size(); j++ )
158  {
159  if( std::find( varDims.begin(), varDims.end(), opt_lev_dims[j] ) != varDims.end() )
160  {
161  currentVarData.numLev = dimLens[opt_lev_dims[j]];
162  break;
163  }
164  }
165  }
166 
167  // Skip set variables, which were already processed in
168  // NCWriteHelper::collect_variable_data()
169  if( WriteNC::ENTLOCSET == currentVarData.entLoc ) continue;
170 
171  // Set up writeStarts and writeCounts (maximum number of dimensions is 3)
172  currentVarData.writeStarts.resize( 3 );
173  currentVarData.writeCounts.resize( 3 );
174  unsigned int dim_idx = 0;
175 
176  // First: time
177  if( currentVarData.has_tsteps )
178  {
179  // Non-set variables with timesteps
180  // 3 dimensions like (time, cells, layers)
181  // 2 dimensions like (time, cells)
182  assert( 3 == varDims.size() || 2 == varDims.size() );
183 
184  // Time should be the first dimension
185  assert( tDim == varDims[0] );
186 
187  currentVarData.writeStarts[dim_idx] = 0; // This value is timestep dependent, will be set later
188  currentVarData.writeCounts[dim_idx] = 1;
189  dim_idx++;
190  }
191  else
192  {
193  // Non-set variables without timesteps
194  // 2 dimensions like (cells, layers)
195  // 1 dimension like (cells)
196  assert( 2 == varDims.size() || 1 == varDims.size() );
197  }
198 
199  // Next: corners / cells / edges
200  switch( currentVarData.entLoc )
201  {
202  case WriteNC::ENTLOCVERT:
203  // Vertices
204  // Start from the first localGidVerts
205  // Actually, this will be reset later for writing
206  currentVarData.writeStarts[dim_idx] = localGidVertsOwned[0] - 1;
207  currentVarData.writeCounts[dim_idx] = localGidVertsOwned.size();
208  break;
209  case WriteNC::ENTLOCFACE:
210  // Faces
211  // Start from the first localGidCells
212  // Actually, this will be reset later for writing
213  currentVarData.writeStarts[dim_idx] = localGidCellsOwned[0] - 1;
214  currentVarData.writeCounts[dim_idx] = localGidCellsOwned.size();
215  break;
216  case WriteNC::ENTLOCEDGE:
217  // Edges
218  // Start from the first localGidEdges
219  // Actually, this will be reset later for writing
220  currentVarData.writeStarts[dim_idx] = localGidEdgesOwned[0] - 1;
221  currentVarData.writeCounts[dim_idx] = localGidEdgesOwned.size();
222  break;
223  default:
224  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << varname );
225  }
226  dim_idx++;
227 
228  // Finally: layers or other optional levels, it is possible that there is no
229  // level dimension (numLev is 0) for this non-set variable
230  if( currentVarData.numLev > 0 )
231  {
232  // Non-set variables with levels
233  // 3 dimensions like (time, cells, layers)
234  // 2 dimensions like (cells, layers)
235  assert( 3 == varDims.size() || 2 == varDims.size() );
236 
237  currentVarData.writeStarts[dim_idx] = 0;
238  currentVarData.writeCounts[dim_idx] = currentVarData.numLev;
239  dim_idx++;
240  }
241  else
242  {
243  // Non-set variables without levels
244  // 2 dimensions like (time, cells)
245  // 1 dimension like (cells)
246  assert( 2 == varDims.size() || 1 == varDims.size() );
247  }
248 
249  // Get variable size
250  currentVarData.sz = 1;
251  for( std::size_t idx = 0; idx < dim_idx; idx++ )
252  currentVarData.sz *= currentVarData.writeCounts[idx];
253  } // for (size_t i = 0; i < var_names.size(); i++)
254 
255  return MB_SUCCESS;
256 }
257 
258 ErrorCode NCWriteGCRM::write_nonset_variables( std::vector< WriteNC::VarData >& vdatas, std::vector< int >& tstep_nums )
259 {
260  Interface*& mbImpl = _writeNC->mbImpl;
261 
262  int success;
263 
264  // For each indexed variable tag, write a time step data
265  for( unsigned int i = 0; i < vdatas.size(); i++ )
266  {
267  WriteNC::VarData& variableData = vdatas[i];
268 
269  // Skip edge variables, if there are no edges
270  if( localEdgesOwned.empty() && variableData.entLoc == WriteNC::ENTLOCEDGE ) continue;
271 
272  // Get local owned entities of this variable
273  Range* pLocalEntsOwned = NULL;
274  Range* pLocalGidEntsOwned = NULL;
275  switch( variableData.entLoc )
276  {
277  case WriteNC::ENTLOCVERT:
278  // Vertices
279  pLocalEntsOwned = &localVertsOwned;
280  pLocalGidEntsOwned = &localGidVertsOwned;
281  break;
282  case WriteNC::ENTLOCEDGE:
283  // Edges
284  pLocalEntsOwned = &localEdgesOwned;
285  pLocalGidEntsOwned = &localGidEdgesOwned;
286  break;
287  case WriteNC::ENTLOCFACE:
288  // Cells
289  pLocalEntsOwned = &localCellsOwned;
290  pLocalGidEntsOwned = &localGidCellsOwned;
291  break;
292  default:
293  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << variableData.varName );
294  }
295 
296  unsigned int num_timesteps;
297  unsigned int ents_idx = 0;
298  if( variableData.has_tsteps )
299  {
300  // Non-set variables with timesteps
301  // 3 dimensions like (time, cells, layers)
302  // 2 dimensions like (time, cells)
303  num_timesteps = tstep_nums.size();
304  ents_idx++;
305  }
306  else
307  {
308  // Non-set variables without timesteps
309  // 2 dimensions like (cells, layers)
310  // 1 dimension like (cells)
311  num_timesteps = 1;
312  }
313 
314  unsigned int num_lev;
315  if( variableData.numLev > 0 )
316  {
317  // Non-set variables with levels
318  // 3 dimensions like (time, cells, layers)
319  // 2 dimensions like (cells, layers)
320  num_lev = variableData.numLev;
321  }
322  else
323  {
324  // Non-set variables without levels
325  // 2 dimensions like (time, cells)
326  // 1 dimension like (cells)
327  num_lev = 1;
328  }
329 
330  for( unsigned int t = 0; t < num_timesteps; t++ )
331  {
332  // We will write one time step, and count will be one; start will be different
333  // Use tag_get_data instead of tag_iterate to copy tag data, as localEntsOwned
334  // might not be contiguous.
335  if( tDim == variableData.varDims[0] ) variableData.writeStarts[0] = t; // This is start for time
336  std::vector< double > tag_data( pLocalEntsOwned->size() * num_lev );
337  MB_CHK_SET_ERR( mbImpl->tag_get_data( variableData.varTags[t], *pLocalEntsOwned, &tag_data[0] ),
338  "Trouble getting tag data on owned entities" );
339 
340 #ifdef MOAB_HAVE_PNETCDF
341  size_t nb_writes = pLocalGidEntsOwned->psize();
342  std::vector< int > requests( nb_writes ), statuss( nb_writes );
343  size_t idxReq = 0;
344 #endif
345 
346  // Now write copied tag data
347  // Use nonblocking put (request aggregation)
348  switch( variableData.varDataType )
349  {
350  case NC_DOUBLE: {
351  size_t indexInDoubleArray = 0;
352  size_t ic = 0;
353  for( Range::pair_iterator pair_iter = pLocalGidEntsOwned->pair_begin();
354  pair_iter != pLocalGidEntsOwned->pair_end(); ++pair_iter, ic++ )
355  {
356  EntityHandle starth = pair_iter->first;
357  EntityHandle endh = pair_iter->second;
358  variableData.writeStarts[ents_idx] = (NCDF_SIZE)( starth - 1 );
359  variableData.writeCounts[ents_idx] = (NCDF_SIZE)( endh - starth + 1 );
360 
361  // Do a partial write, in each subrange
362 #ifdef MOAB_HAVE_PNETCDF
363  // Wait outside this loop
364  success =
365  NCFUNCREQP( _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
366  &( variableData.writeCounts[0] ),
367  &( tag_data[indexInDoubleArray] ), &requests[idxReq++] );
368 #else
369  success = NCFUNCAP(
370  _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
371  &( variableData.writeCounts[0] ), &( tag_data[indexInDoubleArray] ) );
372 #endif
373  if( success )
374  MB_SET_ERR( MB_FAILURE,
375  "Failed to write double data in a loop for variable " << variableData.varName );
376  // We need to increment the index in double array for the
377  // next subrange
378  indexInDoubleArray += ( endh - starth + 1 ) * num_lev;
379  }
380  assert( ic == pLocalGidEntsOwned->psize() );
381 #ifdef MOAB_HAVE_PNETCDF
382  success = ncmpi_wait_all( _fileId, requests.size(), &requests[0], &statuss[0] );
383  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
384 #endif
385  break;
386  }
387  default:
388  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double data is not implemented yet" );
389  }
390  }
391  }
392 
393  return MB_SUCCESS;
394 }
395 
396 } /* namespace moab */