Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
NCWriteHOMME.cpp
Go to the documentation of this file.
1 /*
2  * NCWriteHOMME.cpp
3  *
4  * Created on: April 9, 2014
5  */
6 
7 #include "NCWriteHOMME.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
30  {
31  MB_SET_ERR( MB_FAILURE, "Couldn't find 'time' dimension" );
32  }
33  nTimeSteps = dimLens[tDim];
34 
35  // Get number of levels
36  if( ( vecIt = std::find( dimNames.begin(), dimNames.end(), "lev" ) ) != dimNames.end() )
37  levDim = vecIt - dimNames.begin();
38  else
39  {
40  MB_SET_ERR( MB_FAILURE, "Couldn't find 'lev' dimension" );
41  }
42  nLevels = dimLens[levDim];
43 
44  // Get local vertices
46  "Trouble getting local vertices in current file set" );
47  assert( !localVertsOwned.empty() );
48 
49 #ifdef MOAB_HAVE_MPI
50  bool& isParallel = _writeNC->isParallel;
51  if( isParallel )
52  {
53  ParallelComm*& myPcomm = _writeNC->myPcomm;
54  int rank = myPcomm->proc_config().proc_rank();
55  int procs = myPcomm->proc_config().proc_size();
56  if( procs > 1 )
57  {
58 #ifndef NDEBUG
59  unsigned int num_local_verts = localVertsOwned.size();
60 #endif
62  "Trouble getting owned vertices in current set" );
63 
64  // Assume that PARALLEL_RESOLVE_SHARED_ENTS option is set
65  // Verify that not all local vertices are owned by the last processor
66  if( procs - 1 == rank )
67  assert( "PARALLEL_RESOLVE_SHARED_ENTS option is set" && localVertsOwned.size() < num_local_verts );
68  }
69  }
70 #endif
71 
72  std::vector< int > gids( localVertsOwned.size() );
73  MB_CHK_SET_ERR( mbImpl->tag_get_data( mGlobalIdTag, localVertsOwned, &gids[0] ),
74  "Trouble getting global IDs on local vertices" );
75 
76  // Get localGidVertsOwned
77  std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidVertsOwned ) );
78 
79  return MB_SUCCESS;
80 }
81 
82 ErrorCode NCWriteHOMME::collect_variable_data( std::vector< std::string >& var_names, std::vector< int >& tstep_nums )
83 {
84  NCWriteHelper::collect_variable_data( var_names, tstep_nums );
85 
86  std::map< std::string, WriteNC::VarData >& varInfo = _writeNC->varInfo;
87 
88  for( size_t i = 0; i < var_names.size(); i++ )
89  {
90  std::string varname = var_names[i];
91  std::map< std::string, WriteNC::VarData >::iterator vit = varInfo.find( varname );
92  if( vit == varInfo.end() ) MB_SET_ERR( MB_FAILURE, "Can't find variable " << varname );
93  ;
94 
95  WriteNC::VarData& currentVarData = vit->second;
96 #ifndef NDEBUG
97  std::vector< int >& varDims = currentVarData.varDims;
98 #endif
99 
100  // Skip set variables, which were already processed in
101  // NCWriteHelper::collect_variable_data()
102  if( WriteNC::ENTLOCSET == currentVarData.entLoc ) continue;
103 
104  // Set up writeStarts and writeCounts (maximum number of dimensions is 3)
105  currentVarData.writeStarts.resize( 3 );
106  currentVarData.writeCounts.resize( 3 );
107  unsigned int dim_idx = 0;
108 
109  // First: time
110  if( currentVarData.has_tsteps )
111  {
112  // Non-set variables with timesteps
113  // 3 dimensions like (time, lev, ncol)
114  // 2 dimensions like (time, ncol)
115  assert( 3 == varDims.size() || 2 == varDims.size() );
116 
117  // Time should be the first dimension
118  assert( tDim == varDims[0] );
119 
120  currentVarData.writeStarts[dim_idx] = 0; // This value is timestep dependent, will be set later
121  currentVarData.writeCounts[dim_idx] = 1;
122  dim_idx++;
123  }
124  else
125  {
126  // Non-set variables without timesteps
127  // 2 dimensions like (lev, ncol)
128  // 1 dimension like (ncol)
129  assert( 2 == varDims.size() || 1 == varDims.size() );
130  }
131 
132  // Next: lev
133  if( currentVarData.numLev > 0 )
134  {
135  // Non-set variables with levels
136  // 3 dimensions like (time, lev, ncol)
137  // 2 dimensions like (lev, ncol)
138  assert( 3 == varDims.size() || 2 == varDims.size() );
139 
140  currentVarData.writeStarts[dim_idx] = 0;
141  currentVarData.writeCounts[dim_idx] = currentVarData.numLev;
142  dim_idx++;
143  }
144  else
145  {
146  // Non-set variables without levels
147  // 2 dimensions like (time, ncol)
148  // 1 dimension like (ncol)
149  assert( 2 == varDims.size() || 1 == varDims.size() );
150  }
151 
152  // Finally: ncol
153  switch( currentVarData.entLoc )
154  {
155  case WriteNC::ENTLOCVERT:
156  // Vertices
157  // Start from the first localGidVerts
158  // Actually, this will be reset later for writing
159  currentVarData.writeStarts[dim_idx] = localGidVertsOwned[0] - 1;
160  currentVarData.writeCounts[dim_idx] = localGidVertsOwned.size();
161  break;
162  default:
163  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << varname );
164  }
165  dim_idx++;
166 
167  // Get variable size
168  currentVarData.sz = 1;
169  for( std::size_t idx = 0; idx < dim_idx; idx++ )
170  currentVarData.sz *= currentVarData.writeCounts[idx];
171  }
172 
173  return MB_SUCCESS;
174 }
175 
176 ErrorCode NCWriteHOMME::write_nonset_variables( std::vector< WriteNC::VarData >& vdatas,
177  std::vector< int >& tstep_nums )
178 {
179  Interface*& mbImpl = _writeNC->mbImpl;
180 
181  int success;
182  int num_local_verts_owned = localVertsOwned.size();
183 
184  // For each indexed variable tag, write a time step data
185  for( unsigned int i = 0; i < vdatas.size(); i++ )
186  {
187  WriteNC::VarData& variableData = vdatas[i];
188 
189  // Assume this variable is on vertices for the time being
190  switch( variableData.entLoc )
191  {
192  case WriteNC::ENTLOCVERT:
193  // Vertices
194  break;
195  default:
196  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << variableData.varName );
197  }
198 
199  unsigned int num_timesteps;
200  unsigned int ncol_idx = 0;
201  if( variableData.has_tsteps )
202  {
203  // Non-set variables with timesteps
204  // 3 dimensions like (time, lev, ncol)
205  // 2 dimensions like (time, ncol)
206  num_timesteps = tstep_nums.size();
207  ncol_idx++;
208  }
209  else
210  {
211  // Non-set variables without timesteps
212  // 2 dimensions like (lev, ncol)
213  // 1 dimension like (ncol)
214  num_timesteps = 1;
215  }
216 
217  unsigned int num_lev;
218  if( variableData.numLev > 0 )
219  {
220  // Non-set variables with levels
221  // 3 dimensions like (time, lev, ncol)
222  // 2 dimensions like (lev, ncol)
223  num_lev = variableData.numLev;
224  ncol_idx++;
225  }
226  else
227  {
228  // Non-set variables without levels
229  // 2 dimensions like (time, ncol)
230  // 1 dimension like (ncol)
231  num_lev = 1;
232  }
233 
234  // At each timestep, we need to transpose tag format (ncol, lev) back
235  // to NC format (lev, ncol) for writing
236  for( unsigned int t = 0; t < num_timesteps; t++ )
237  {
238  // We will write one time step, and count will be one; start will be different
239  // Use tag_get_data instead of tag_iterate to copy tag data, as localVertsOwned
240  // might not be contiguous. We should also transpose for level so that means
241  // deep copy for transpose
242  if( tDim == variableData.varDims[0] ) variableData.writeStarts[0] = t; // This is start for time
243  std::vector< double > tag_data( num_local_verts_owned * num_lev );
244  MB_CHK_SET_ERR( mbImpl->tag_get_data( variableData.varTags[t], localVertsOwned, &tag_data[0] ),
245  "Trouble getting tag data on owned vertices" );
246 
247 #ifdef MOAB_HAVE_PNETCDF
248  size_t nb_writes = localGidVertsOwned.psize();
249  std::vector< int > requests( nb_writes ), statuss( nb_writes );
250  size_t idxReq = 0;
251 #endif
252 
253  // Now transpose and write copied tag data
254  // Use nonblocking put (request aggregation)
255  switch( variableData.varDataType )
256  {
257  case NC_DOUBLE: {
258  std::vector< double > tmpdoubledata( num_local_verts_owned * num_lev );
259  if( num_lev > 1 )
260  {
261  // Transpose (ncol, lev) back to (lev, ncol)
262  // Note, num_local_verts_owned is not used by jik_to_kji_stride()
263  jik_to_kji_stride( num_local_verts_owned, 1, num_lev, &tmpdoubledata[0], &tag_data[0],
265  }
266 
267  size_t indexInDoubleArray = 0;
268  size_t ic = 0;
270  pair_iter != localGidVertsOwned.pair_end(); ++pair_iter, ic++ )
271  {
272  EntityHandle starth = pair_iter->first;
273  EntityHandle endh = pair_iter->second;
274  variableData.writeStarts[ncol_idx] = (NCDF_SIZE)( starth - 1 );
275  variableData.writeCounts[ncol_idx] = (NCDF_SIZE)( endh - starth + 1 );
276 
277  // Do a partial write, in each subrange
278 #ifdef MOAB_HAVE_PNETCDF
279  // Wait outside this loop
280  success =
281  NCFUNCREQP( _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
282  &( variableData.writeCounts[0] ),
283  &( tmpdoubledata[indexInDoubleArray] ), &requests[idxReq++] );
284 #else
285  success = NCFUNCAP(
286  _vara_double )( _fileId, variableData.varId, &( variableData.writeStarts[0] ),
287  &( variableData.writeCounts[0] ), &( tmpdoubledata[indexInDoubleArray] ) );
288 #endif
289  if( success )
290  MB_SET_ERR( MB_FAILURE,
291  "Failed to write double data in a loop for variable " << variableData.varName );
292  // We need to increment the index in double array for the
293  // next subrange
294  indexInDoubleArray += ( endh - starth + 1 ) * num_lev;
295  }
296  assert( ic == localGidVertsOwned.psize() );
297 #ifdef MOAB_HAVE_PNETCDF
298  success = ncmpi_wait_all( _fileId, requests.size(), &requests[0], &statuss[0] );
299  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
300 #endif
301  break;
302  }
303  default:
304  MB_SET_ERR( MB_NOT_IMPLEMENTED, "Writing non-double data is not implemented yet" );
305  }
306  }
307  }
308 
309  return MB_SUCCESS;
310 }
311 
312 } /* namespace moab */