Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
NCHelperGCRM.cpp
Go to the documentation of this file.
1 #include "NCHelperGCRM.hpp"
2 #include "moab/ReadUtilIface.hpp"
3 #include "moab/FileOptions.hpp"
5 #include "MBTagConventions.hpp"
6 
7 #ifdef MOAB_HAVE_ZOLTAN
9 #endif
10 
11 #include <cmath>
12 
13 namespace moab
14 {
15 
16 // GCRM cells are either pentagons or hexagons, and pentagons are always padded to hexagons
17 const int EDGES_PER_CELL = 6;
18 
19 NCHelperGCRM::NCHelperGCRM( ReadNC* readNC, int fileId, const FileOptions& opts, EntityHandle fileSet )
20  : UcdNCHelper( readNC, fileId, opts, fileSet ), createGatherSet( false )
21 {
22  // Ignore variables containing topological information
23  ignoredVarNames.insert( "grid" );
24  ignoredVarNames.insert( "cell_corners" );
25  ignoredVarNames.insert( "cell_edges" );
26  ignoredVarNames.insert( "edge_corners" );
27  ignoredVarNames.insert( "cell_neighbors" );
28 }
29 
31 {
32  std::vector< std::string >& dimNames = readNC->dimNames;
33 
34  // If dimension name "cells" exists then it should be the GCRM grid
35  if( std::find( dimNames.begin(), dimNames.end(), std::string( "cells" ) ) != dimNames.end() ) return true;
36 
37  return false;
38 }
39 
41 {
42  std::vector< std::string >& dimNames = _readNC->dimNames;
43  std::vector< int >& dimLens = _readNC->dimLens;
44  std::map< std::string, ReadNC::VarData >& varInfo = _readNC->varInfo;
45 
46  unsigned int idx;
47  std::vector< std::string >::iterator vit;
48 
49  // Look for time dimension
50  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "Time" ) ) != dimNames.end() )
51  idx = vit - dimNames.begin();
52  else if( ( vit = std::find( dimNames.begin(), dimNames.end(), "time" ) ) != dimNames.end() )
53  idx = vit - dimNames.begin();
54  else
55  {
56  MB_SET_ERR( MB_FAILURE, "Couldn't find 'Time' or 'time' dimension" );
57  }
58  tDim = idx;
59  nTimeSteps = dimLens[idx];
60 
61  // Get number of cells
62  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "cells" ) ) != dimNames.end() )
63  idx = vit - dimNames.begin();
64  else
65  {
66  MB_SET_ERR( MB_FAILURE, "Couldn't find 'cells' dimension" );
67  }
68  cDim = idx;
69  nCells = dimLens[idx];
70 
71  // Get number of edges
72  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "edges" ) ) != dimNames.end() )
73  idx = vit - dimNames.begin();
74  else
75  {
76  MB_SET_ERR( MB_FAILURE, "Couldn't find 'edges' dimension" );
77  }
78  eDim = idx;
79  nEdges = dimLens[idx];
80 
81  // Get number of vertices
82  vDim = -1;
83  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "corners" ) ) != dimNames.end() )
84  idx = vit - dimNames.begin();
85  else
86  {
87  MB_SET_ERR( MB_FAILURE, "Couldn't find 'corners' dimension" );
88  }
89  vDim = idx;
90  nVertices = dimLens[idx];
91 
92  // Get number of layers
93  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "layers" ) ) != dimNames.end() )
94  idx = vit - dimNames.begin();
95  else
96  {
97  MB_SET_ERR( MB_FAILURE, "Couldn't find 'layers' dimension" );
98  }
99  levDim = idx;
100  nLevels = dimLens[idx];
101 
102  // Dimension indices for other optional levels
103  std::vector< unsigned int > opt_lev_dims;
104 
105  // Get index of interface levels
106  if( ( vit = std::find( dimNames.begin(), dimNames.end(), "interfaces" ) ) != dimNames.end() )
107  {
108  idx = vit - dimNames.begin();
109  opt_lev_dims.push_back( idx );
110  }
111 
112  std::map< std::string, ReadNC::VarData >::iterator vmit;
113 
114  // Store time coordinate values in tVals
115  if( nTimeSteps > 0 )
116  {
117  if( ( vmit = varInfo.find( "time" ) ) != varInfo.end() )
118  {
119  MB_CHK_SET_ERR( read_coordinate( "time", 0, nTimeSteps - 1, tVals ), "Trouble reading 'time' variable" );
120  }
121  else if( ( vmit = varInfo.find( "t" ) ) != varInfo.end() )
122  {
123  MB_CHK_SET_ERR( read_coordinate( "t", 0, nTimeSteps - 1, tVals ), "Trouble reading 't' variable" );
124  }
125  else
126  {
127  // If expected time variable is not available, set dummy time coordinate values to tVals
128  for( int t = 0; t < nTimeSteps; t++ )
129  tVals.push_back( (double)t );
130  }
131  }
132 
133  // For each variable, determine the entity location type and number of levels
134  for( vmit = varInfo.begin(); vmit != varInfo.end(); ++vmit )
135  {
136  ReadNC::VarData& vd = ( *vmit ).second;
137 
138  // Default entLoc is ENTLOCSET
139  if( std::find( vd.varDims.begin(), vd.varDims.end(), tDim ) != vd.varDims.end() )
140  {
141  if( std::find( vd.varDims.begin(), vd.varDims.end(), vDim ) != vd.varDims.end() )
143  else if( std::find( vd.varDims.begin(), vd.varDims.end(), eDim ) != vd.varDims.end() )
145  else if( std::find( vd.varDims.begin(), vd.varDims.end(), cDim ) != vd.varDims.end() )
147  }
148 
149  // Default numLev is 0
150  if( std::find( vd.varDims.begin(), vd.varDims.end(), levDim ) != vd.varDims.end() )
151  vd.numLev = nLevels;
152  else
153  {
154  // If layers dimension is not found, try other optional levels such as interfaces
155  for( unsigned int i = 0; i < opt_lev_dims.size(); i++ )
156  {
157  if( std::find( vd.varDims.begin(), vd.varDims.end(), opt_lev_dims[i] ) != vd.varDims.end() )
158  {
159  vd.numLev = dimLens[opt_lev_dims[i]];
160  break;
161  }
162  }
163  }
164  }
165 
166  // Hack: create dummy variables for dimensions (like cells) with no corresponding coordinate
167  // variables
168  MB_CHK_SET_ERR( create_dummy_variables(), "Failed to create dummy variables" );
169 
170  return MB_SUCCESS;
171 }
172 
173 // When noMesh option is used on this read, the old ReadNC class instance for last read can get out
174 // of scope (and deleted). The old instance initialized some variables properly when the mesh was
175 // created, but they are now lost. The new instance (will not create the mesh with noMesh option)
176 // has to restore them based on the existing mesh from last read
178 {
179  Interface*& mbImpl = _readNC->mbImpl;
180  Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
181  bool& noMesh = _readNC->noMesh;
182 
183  if( noMesh )
184  {
185  if( localGidVerts.empty() )
186  {
187  // Get all vertices from current file set (it is the input set in no_mesh scenario)
188  Range local_verts;
189  MB_CHK_SET_ERR( mbImpl->get_entities_by_dimension( _fileSet, 0, local_verts ),
190  "Trouble getting local vertices in current file set" );
191 
192  if( !local_verts.empty() )
193  {
194  std::vector< int > gids( local_verts.size() );
195 
196  // !IMPORTANT : this has to be the GLOBAL_ID tag
197  MB_CHK_SET_ERR( mbImpl->tag_get_data( mGlobalIdTag, local_verts, &gids[0] ),
198  "Trouble getting local gid values of vertices" );
199 
200  // Restore localGidVerts
201  std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidVerts ) );
203  }
204  }
205 
206  if( localGidEdges.empty() )
207  {
208  // Get all edges from current file set (it is the input set in no_mesh scenario)
209  Range local_edges;
210  MB_CHK_SET_ERR( mbImpl->get_entities_by_dimension( _fileSet, 1, local_edges ),
211  "Trouble getting local edges in current file set" );
212 
213  if( !local_edges.empty() )
214  {
215  std::vector< int > gids( local_edges.size() );
216 
217  // !IMPORTANT : this has to be the GLOBAL_ID tag
218  MB_CHK_SET_ERR( mbImpl->tag_get_data( mGlobalIdTag, local_edges, &gids[0] ),
219  "Trouble getting local gid values of edges" );
220 
221  // Restore localGidEdges
222  std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidEdges ) );
224  }
225  }
226 
227  if( localGidCells.empty() )
228  {
229  // Get all cells from current file set (it is the input set in no_mesh scenario)
230  Range local_cells;
231  MB_CHK_SET_ERR( mbImpl->get_entities_by_dimension( _fileSet, 2, local_cells ),
232  "Trouble getting local cells in current file set" );
233 
234  if( !local_cells.empty() )
235  {
236  std::vector< int > gids( local_cells.size() );
237 
238  // !IMPORTANT : this has to be the GLOBAL_ID tag
239  MB_CHK_SET_ERR( mbImpl->tag_get_data( mGlobalIdTag, local_cells, &gids[0] ),
240  "Trouble getting local gid values of cells" );
241 
242  // Restore localGidCells
243  std::copy( gids.rbegin(), gids.rend(), range_inserter( localGidCells ) );
245  }
246  }
247  }
248 
249  return MB_SUCCESS;
250 }
251 
253 {
254  bool& noEdges = _readNC->noEdges;
255  DebugOutput& dbgOut = _readNC->dbgOut;
256 
257 #ifdef MOAB_HAVE_MPI
258  int rank = 0;
259  int procs = 1;
260  bool& isParallel = _readNC->isParallel;
261  ParallelComm* myPcomm = NULL;
262  if( isParallel )
263  {
264  myPcomm = _readNC->myPcomm;
265  rank = myPcomm->proc_config().proc_rank();
266  procs = myPcomm->proc_config().proc_size();
267  }
268 
269  // Need to know whether we'll be creating gather mesh
270  if( rank == _readNC->gatherSetRank ) createGatherSet = true;
271 
272  if( procs >= 2 )
273  {
274  // Shift rank to obtain a rotated trivial partition
275  int shifted_rank = rank;
276  int& trivialPartitionShift = _readNC->trivialPartitionShift;
277  if( trivialPartitionShift > 0 ) shifted_rank = ( rank + trivialPartitionShift ) % procs;
278 
279  // Compute the number of local cells on this proc
280  nLocalCells = int( std::floor( 1.0 * nCells / procs ) );
281 
282  // The starting global cell index in the GCRM file for this proc
283  int start_cell_idx = shifted_rank * nLocalCells;
284 
285  // Number of extra cells after equal split over procs
286  int iextra = nCells % procs;
287 
288  // Allocate extra cells over procs
289  if( shifted_rank < iextra ) nLocalCells++;
290  start_cell_idx += std::min( shifted_rank, iextra );
291 
292  start_cell_idx++; // 0 based -> 1 based
293 
294  // Redistribute local cells after trivial partition (e.g. apply Zoltan partition)
295  MB_CHK_SET_ERR( redistribute_local_cells( start_cell_idx, myPcomm ),
296  "Failed to redistribute local cells after trivial partition" );
297  }
298  else
299  {
302  }
303 #else
306 #endif
307  dbgOut.tprintf( 1, " localGidCells.psize() = %d\n", (int)localGidCells.psize() );
308  dbgOut.tprintf( 1, " localGidCells.size() = %d\n", (int)localGidCells.size() );
309 
310  // Read vertices on each local cell, to get localGidVerts and cell connectivity later
311  int verticesOnCellVarId;
312  int success = NCFUNC( inq_varid )( _fileId, "cell_corners", &verticesOnCellVarId );
313  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of cell_corners" );
314  std::vector< int > vertices_on_local_cells( nLocalCells * EDGES_PER_CELL );
315  dbgOut.tprintf( 1, " nLocalCells = %d\n", (int)nLocalCells );
316  dbgOut.tprintf( 1, " vertices_on_local_cells.size() = %d\n", (int)vertices_on_local_cells.size() );
317 #ifdef MOAB_HAVE_PNETCDF
318  size_t nb_reads = localGidCells.psize();
319  std::vector< int > requests( nb_reads );
320  std::vector< int > statuss( nb_reads );
321  size_t idxReq = 0;
322 #endif
323  size_t indexInArray = 0;
324  for( Range::pair_iterator pair_iter = localGidCells.pair_begin(); pair_iter != localGidCells.pair_end();
325  ++pair_iter )
326  {
327  EntityHandle starth = pair_iter->first;
328  EntityHandle endh = pair_iter->second;
329  dbgOut.tprintf( 1, " cell_corners starth = %d\n", (int)starth );
330  dbgOut.tprintf( 1, " cell_corners endh = %d\n", (int)endh );
331  NCDF_SIZE read_starts[2] = { static_cast< NCDF_SIZE >( starth - 1 ), 0 };
332  NCDF_SIZE read_counts[2] = { static_cast< NCDF_SIZE >( endh - starth + 1 ),
333  static_cast< NCDF_SIZE >( EDGES_PER_CELL ) };
334 
335  // Do a partial read in each subrange
336 #ifdef MOAB_HAVE_PNETCDF
337  success = NCFUNCREQG( _vara_int )( _fileId, verticesOnCellVarId, read_starts, read_counts,
338  &( vertices_on_local_cells[indexInArray] ), &requests[idxReq++] );
339 #else
340  success = NCFUNCAG( _vara_int )( _fileId, verticesOnCellVarId, read_starts, read_counts,
341  &( vertices_on_local_cells[indexInArray] ) );
342 #endif
343  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read cell_corners data in a loop" );
344 
345  // Increment the index for next subrange
346  indexInArray += ( endh - starth + 1 ) * EDGES_PER_CELL;
347  }
348 
349 #ifdef MOAB_HAVE_PNETCDF
350  // Wait outside the loop
351  success = NCFUNC( wait_all )( _fileId, requests.size(), &requests[0], &statuss[0] );
352  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
353 #endif
354 
355  // Correct vertices_on_local_cells array. Pentagons as hexagons should have
356  // a connectivity like 123455 and not 122345
357  for( int local_cell_idx = 0; local_cell_idx < nLocalCells; local_cell_idx++ )
358  {
359  int* pvertex = &vertices_on_local_cells[local_cell_idx * EDGES_PER_CELL];
360  for( int k = 0; k < EDGES_PER_CELL - 2; k++ )
361  {
362  if( *( pvertex + k ) == *( pvertex + k + 1 ) )
363  {
364  // Shift the connectivity
365  for( int kk = k + 1; kk < EDGES_PER_CELL - 1; kk++ )
366  *( pvertex + kk ) = *( pvertex + kk + 1 );
367  // No need to try next k
368  break;
369  }
370  }
371  }
372 
373  // GCRM is 0 based, convert vertex indices from 0 to 1 based
374  for( std::size_t idx = 0; idx < vertices_on_local_cells.size(); idx++ )
375  vertices_on_local_cells[idx] += 1;
376 
377  // Create local vertices
378  EntityHandle start_vertex;
379  MB_CHK_SET_ERR( create_local_vertices( vertices_on_local_cells, start_vertex ),
380  "Failed to create local vertices for GCRM mesh" );
381 
382  // Create local edges (unless NO_EDGES read option is set)
383  if( !noEdges )
384  {
385  MB_CHK_SET_ERR( create_local_edges( start_vertex ), "Failed to create local edges for GCRM mesh" );
386  }
387 
388  // Create local cells, padded
389  MB_CHK_SET_ERR( create_padded_local_cells( vertices_on_local_cells, start_vertex, faces ),
390  "Failed to create padded local cells for GCRM mesh" );
391 
392  if( createGatherSet )
393  {
394  EntityHandle gather_set;
395  MB_CHK_SET_ERR( _readNC->readMeshIface->create_gather_set( gather_set ), "Failed to create gather set" );
396 
397  // Create gather set vertices
398  EntityHandle start_gather_set_vertex;
399  MB_CHK_SET_ERR( create_gather_set_vertices( gather_set, start_gather_set_vertex ),
400  "Failed to create gather set vertices for GCRM mesh" );
401 
402  // Create gather set edges (unless NO_EDGES read option is set)
403  if( !noEdges )
404  {
405  MB_CHK_SET_ERR( create_gather_set_edges( gather_set, start_gather_set_vertex ),
406  "Failed to create gather set edges for GCRM mesh" );
407  }
408 
409  // Create gather set cells with padding
410  MB_CHK_SET_ERR( create_padded_gather_set_cells( gather_set, start_gather_set_vertex ),
411  "Failed to create padded gather set cells for GCRM mesh" );
412  }
413 
414  return MB_SUCCESS;
415 }
416 
417 ErrorCode NCHelperGCRM::read_ucd_variables_to_nonset_allocate( std::vector< ReadNC::VarData >& vdatas,
418  std::vector< int >& tstep_nums )
419 {
420  Interface*& mbImpl = _readNC->mbImpl;
421  std::vector< int >& dimLens = _readNC->dimLens;
422  bool& noEdges = _readNC->noEdges;
423  DebugOutput& dbgOut = _readNC->dbgOut;
424 
425  Range* range = NULL;
426 
427  // Get vertices
428  Range verts;
429  MB_CHK_SET_ERR( mbImpl->get_entities_by_dimension( _fileSet, 0, verts ),
430  "Trouble getting vertices in current file set" );
431  assert( "Should only have a single vertex subrange, since they were read in one shot" && verts.psize() == 1 );
432 
433  // Get edges
434  Range edges;
435  MB_CHK_SET_ERR( mbImpl->get_entities_by_dimension( _fileSet, 1, edges ),
436  "Trouble getting edges in current file set" );
437 
438  // Get faces
439  Range faces;
440  MB_CHK_SET_ERR( mbImpl->get_entities_by_dimension( _fileSet, 2, faces ),
441  "Trouble getting faces in current file set" );
442  assert( "Should only have a single face subrange, since they were read in one shot" && faces.psize() == 1 );
443 
444 #ifdef MOAB_HAVE_MPI
445  bool& isParallel = _readNC->isParallel;
446  if( isParallel )
447  {
448  ParallelComm*& myPcomm = _readNC->myPcomm;
450  "Trouble getting owned faces in current file set" );
451  }
452  else
453  facesOwned = faces; // not running in parallel, but still with MPI
454 #else
455  facesOwned = faces;
456 #endif
457 
458  for( unsigned int i = 0; i < vdatas.size(); i++ )
459  {
460  // Skip edge variables, if specified by the read options
461  if( noEdges && vdatas[i].entLoc == ReadNC::ENTLOCEDGE ) continue;
462 
463  // Support non-set variables with 3 dimensions like (time, cells, layers), or
464  // 2 dimensions like (time, cells)
465  assert( 3 == vdatas[i].varDims.size() || 2 == vdatas[i].varDims.size() );
466 
467  // For a non-set variable, time should be the first dimension
468  assert( tDim == vdatas[i].varDims[0] );
469 
470  // Set up readStarts and readCounts
471  vdatas[i].readStarts.resize( 3 );
472  vdatas[i].readCounts.resize( 3 );
473 
474  // First: Time
475  vdatas[i].readStarts[0] = 0; // This value is timestep dependent, will be set later
476  vdatas[i].readCounts[0] = 1;
477 
478  // Next: nVertices / nCells / nEdges
479  switch( vdatas[i].entLoc )
480  {
481  case ReadNC::ENTLOCVERT:
482  // Vertices
483  // Start from the first localGidVerts
484  // Actually, this will be reset later on in a loop
485  vdatas[i].readStarts[1] = localGidVerts[0] - 1;
486  vdatas[i].readCounts[1] = nLocalVertices;
487  range = &verts;
488  break;
489  case ReadNC::ENTLOCFACE:
490  // Faces
491  // Start from the first localGidCells
492  // Actually, this will be reset later on in a loop
493  vdatas[i].readStarts[1] = localGidCells[0] - 1;
494  vdatas[i].readCounts[1] = nLocalCells;
495  range = &facesOwned;
496  break;
497  case ReadNC::ENTLOCEDGE:
498  // Edges
499  // Start from the first localGidEdges
500  // Actually, this will be reset later on in a loop
501  vdatas[i].readStarts[1] = localGidEdges[0] - 1;
502  vdatas[i].readCounts[1] = nLocalEdges;
503  range = &edges;
504  break;
505  default:
506  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << vdatas[i].varName );
507  }
508 
509  // Finally: layers or other optional levels, it is possible that there is no
510  // level dimension (numLev is 0) for this non-set variable
511  if( vdatas[i].numLev < 1 ) vdatas[i].numLev = 1;
512  vdatas[i].readStarts[2] = 0;
513  vdatas[i].readCounts[2] = vdatas[i].numLev;
514 
515  // Get variable size
516  vdatas[i].sz = 1;
517  for( std::size_t idx = 0; idx != 3; idx++ )
518  vdatas[i].sz *= vdatas[i].readCounts[idx];
519 
520  for( unsigned int t = 0; t < tstep_nums.size(); t++ )
521  {
522  dbgOut.tprintf( 2, "Reading variable %s, time step %d\n", vdatas[i].varName.c_str(), tstep_nums[t] );
523 
524  if( tstep_nums[t] >= dimLens[tDim] )
525  {
526  MB_SET_ERR( MB_INDEX_OUT_OF_RANGE, "Wrong value for timestep number " << tstep_nums[t] );
527  }
528 
529  // Get the tag to read into
530  if( !vdatas[i].varTags[t] )
531  {
532  MB_CHK_SET_ERR( get_tag_to_nonset( vdatas[i], tstep_nums[t], vdatas[i].varTags[t], vdatas[i].numLev ),
533  "Trouble getting tag for variable " << vdatas[i].varName );
534  }
535 
536  // Get ptr to tag space
537  assert( 1 == range->psize() );
538  void* data;
539  int count;
540  MB_CHK_SET_ERR( mbImpl->tag_iterate( vdatas[i].varTags[t], range->begin(), range->end(), count, data ),
541  "Failed to iterate tag for variable " << vdatas[i].varName );
542  assert( (unsigned)count == range->size() );
543  vdatas[i].varDatas[t] = data;
544  }
545  }
546 
547  return MB_SUCCESS;
548 }
549 
550 #ifdef MOAB_HAVE_PNETCDF
551 ErrorCode NCHelperGCRM::read_ucd_variables_to_nonset_async( std::vector< ReadNC::VarData >& vdatas,
552  std::vector< int >& tstep_nums )
553 {
554  bool& noEdges = _readNC->noEdges;
555  DebugOutput& dbgOut = _readNC->dbgOut;
556 
558  "Trouble allocating space to read non-set variables" );
559 
560  // Finally, read into that space
561  int success;
562  Range* pLocalGid = NULL;
563 
564  for( unsigned int i = 0; i < vdatas.size(); i++ )
565  {
566  // Skip edge variables, if specified by the read options
567  if( noEdges && vdatas[i].entLoc == ReadNC::ENTLOCEDGE ) continue;
568 
569  switch( vdatas[i].entLoc )
570  {
571  case ReadNC::ENTLOCVERT:
572  pLocalGid = &localGidVerts;
573  break;
574  case ReadNC::ENTLOCFACE:
575  pLocalGid = &localGidCells;
576  break;
577  case ReadNC::ENTLOCEDGE:
578  pLocalGid = &localGidEdges;
579  break;
580  default:
581  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << vdatas[i].varName );
582  }
583 
584  std::size_t sz = vdatas[i].sz;
585 
586  for( unsigned int t = 0; t < tstep_nums.size(); t++ )
587  {
588  // We will synchronize all these reads with the other processors,
589  // so the wait will be inside this double loop; is it too much?
590  size_t nb_reads = pLocalGid->psize();
591  std::vector< int > requests( nb_reads ), statuss( nb_reads );
592  size_t idxReq = 0;
593 
594  // Set readStart for each timestep along time dimension
595  vdatas[i].readStarts[0] = tstep_nums[t];
596 
597  switch( vdatas[i].varDataType )
598  {
599  case NC_FLOAT:
600  case NC_DOUBLE: {
601  // Read float as double
602  std::vector< double > tmpdoubledata( sz );
603 
604  // In the case of ucd mesh, and on multiple proc,
605  // we need to read as many times as subranges we have in the
606  // localGid range;
607  // basically, we have to give a different point
608  // for data to start, for every subrange :(
609  size_t indexInDoubleArray = 0;
610  size_t ic = 0;
611  for( Range::pair_iterator pair_iter = pLocalGid->pair_begin(); pair_iter != pLocalGid->pair_end();
612  ++pair_iter, ic++ )
613  {
614  EntityHandle starth = pair_iter->first;
615  EntityHandle endh = pair_iter->second; // inclusive
616  vdatas[i].readStarts[1] = (NCDF_SIZE)( starth - 1 );
617  vdatas[i].readCounts[1] = (NCDF_SIZE)( endh - starth + 1 );
618 
619  // Do a partial read, in each subrange
620  // wait outside this loop
621  success =
622  NCFUNCREQG( _vara_double )( _fileId, vdatas[i].varId, &( vdatas[i].readStarts[0] ),
623  &( vdatas[i].readCounts[0] ),
624  &( tmpdoubledata[indexInDoubleArray] ), &requests[idxReq++] );
625  if( success )
626  MB_SET_ERR( MB_FAILURE,
627  "Failed to read double data in a loop for variable " << vdatas[i].varName );
628  // We need to increment the index in double array for the
629  // next subrange
630  indexInDoubleArray += ( endh - starth + 1 ) * 1 * vdatas[i].numLev;
631  }
632  assert( ic == pLocalGid->psize() );
633 
634  success = NCFUNC( wait_all )( _fileId, requests.size(), &requests[0], &statuss[0] );
635  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
636 
637  void* data = vdatas[i].varDatas[t];
638  for( std::size_t idx = 0; idx != tmpdoubledata.size(); idx++ )
639  ( (double*)data )[idx] = tmpdoubledata[idx];
640 
641  break;
642  }
643  default:
644  MB_SET_ERR( MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName );
645  }
646  }
647  }
648 
649  // Debug output, if requested
650  if( 1 == dbgOut.get_verbosity() )
651  {
652  dbgOut.printf( 1, "Read variables: %s", vdatas.begin()->varName.c_str() );
653  for( unsigned int i = 1; i < vdatas.size(); i++ )
654  dbgOut.printf( 1, ", %s ", vdatas[i].varName.c_str() );
655  dbgOut.tprintf( 1, "\n" );
656  }
657 
658  return MB_SUCCESS;
659 }
660 #else
661 ErrorCode NCHelperGCRM::read_ucd_variables_to_nonset( std::vector< ReadNC::VarData >& vdatas,
662  std::vector< int >& tstep_nums )
663 {
664  bool& noEdges = _readNC->noEdges;
665  DebugOutput& dbgOut = _readNC->dbgOut;
666 
668  "Trouble allocating space to read non-set variables" );
669 
670  // Finally, read into that space
671  int success;
672  Range* pLocalGid = NULL;
673 
674  for( unsigned int i = 0; i < vdatas.size(); i++ )
675  {
676  // Skip edge variables, if specified by the read options
677  if( noEdges && vdatas[i].entLoc == ReadNC::ENTLOCEDGE ) continue;
678 
679  switch( vdatas[i].entLoc )
680  {
681  case ReadNC::ENTLOCVERT:
682  pLocalGid = &localGidVerts;
683  break;
684  case ReadNC::ENTLOCFACE:
685  pLocalGid = &localGidCells;
686  break;
687  case ReadNC::ENTLOCEDGE:
688  pLocalGid = &localGidEdges;
689  break;
690  default:
691  MB_SET_ERR( MB_FAILURE, "Unexpected entity location type for variable " << vdatas[i].varName );
692  }
693 
694  std::size_t sz = vdatas[i].sz;
695 
696  for( unsigned int t = 0; t < tstep_nums.size(); t++ )
697  {
698  // Set readStart for each timestep along time dimension
699  vdatas[i].readStarts[0] = tstep_nums[t];
700 
701  switch( vdatas[i].varDataType )
702  {
703  case NC_FLOAT:
704  case NC_DOUBLE: {
705  // Read float as double
706  std::vector< double > tmpdoubledata( sz );
707 
708  // In the case of ucd mesh, and on multiple proc,
709  // we need to read as many times as subranges we have in the
710  // localGid range;
711  // basically, we have to give a different point
712  // for data to start, for every subrange :(
713  size_t indexInDoubleArray = 0;
714  size_t ic = 0;
715  for( Range::pair_iterator pair_iter = pLocalGid->pair_begin(); pair_iter != pLocalGid->pair_end();
716  ++pair_iter, ic++ )
717  {
718  EntityHandle starth = pair_iter->first;
719  EntityHandle endh = pair_iter->second; // Inclusive
720  vdatas[i].readStarts[1] = (NCDF_SIZE)( starth - 1 );
721  vdatas[i].readCounts[1] = (NCDF_SIZE)( endh - starth + 1 );
722 
723  success = NCFUNCAG( _vara_double )( _fileId, vdatas[i].varId, &( vdatas[i].readStarts[0] ),
724  &( vdatas[i].readCounts[0] ),
725  &( tmpdoubledata[indexInDoubleArray] ) );
726  if( success )
727  MB_SET_ERR( MB_FAILURE,
728  "Failed to read double data in a loop for variable " << vdatas[i].varName );
729  // We need to increment the index in double array for the
730  // next subrange
731  indexInDoubleArray += ( endh - starth + 1 ) * 1 * vdatas[i].numLev;
732  }
733  assert( ic == pLocalGid->psize() );
734 
735  void* data = vdatas[i].varDatas[t];
736  for( std::size_t idx = 0; idx != tmpdoubledata.size(); idx++ )
737  ( (double*)data )[idx] = tmpdoubledata[idx];
738 
739  break;
740  }
741  default:
742  MB_SET_ERR( MB_FAILURE, "Unexpected data type for variable " << vdatas[i].varName );
743  }
744  }
745  }
746 
747  // Debug output, if requested
748  if( 1 == dbgOut.get_verbosity() )
749  {
750  dbgOut.printf( 1, "Read variables: %s", vdatas.begin()->varName.c_str() );
751  for( unsigned int i = 1; i < vdatas.size(); i++ )
752  dbgOut.printf( 1, ", %s ", vdatas[i].varName.c_str() );
753  dbgOut.tprintf( 1, "\n" );
754  }
755 
756  return MB_SUCCESS;
757 }
758 #endif
759 
760 #ifdef MOAB_HAVE_MPI
761 ErrorCode NCHelperGCRM::redistribute_local_cells( int start_cell_idx, ParallelComm* pco )
762 {
763  // If possible, apply Zoltan partition
764 #ifdef MOAB_HAVE_ZOLTAN
766  {
767  // Read lat/lon coordinates of cell centers, then convert spherical to
768  // Cartesian, and use them as input to Zoltan partition
769  int xCellVarId;
770  int success = NCFUNC( inq_varid )( _fileId, "grid_center_lat", &xCellVarId );
771  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of grid_center_lat" );
772  std::vector< double > xCell( nLocalCells );
773  NCDF_SIZE read_start = static_cast< NCDF_SIZE >( start_cell_idx - 1 );
774  NCDF_SIZE read_count = static_cast< NCDF_SIZE >( nLocalCells );
775  success = NCFUNCAG( _vara_double )( _fileId, xCellVarId, &read_start, &read_count, &xCell[0] );
776  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_center_lat data" );
777 
778  // Read y coordinates of cell centers
779  int yCellVarId;
780  success = NCFUNC( inq_varid )( _fileId, "grid_center_lon", &yCellVarId );
781  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of grid_center_lon" );
782  std::vector< double > yCell( nLocalCells );
783  success = NCFUNCAG( _vara_double )( _fileId, yCellVarId, &read_start, &read_count, &yCell[0] );
784  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_center_lon data" );
785 
786  // Convert lon/lat/rad to x/y/z
787  std::vector< double > zCell( nLocalCells );
788  double rad = 8000.0; // This is just a approximate radius
789  for( int i = 0; i < nLocalCells; i++ )
790  {
791  double cosphi = cos( xCell[i] );
792  double zmult = sin( xCell[i] );
793  double xmult = cosphi * cos( yCell[i] );
794  double ymult = cosphi * sin( yCell[i] );
795  xCell[i] = rad * xmult;
796  yCell[i] = rad * ymult;
797  zCell[i] = rad * zmult;
798  }
799 
800  // Zoltan partition using RCB; maybe more studies would be good, as to which partition
801  // is better
802  Interface*& mbImpl = _readNC->mbImpl;
803  DebugOutput& dbgOut = _readNC->dbgOut;
804  ZoltanPartitioner* mbZTool = new ZoltanPartitioner( mbImpl, pco, false, 0, NULL );
805  MB_CHK_SET_ERR( mbZTool->repartition( xCell, yCell, zCell, start_cell_idx, "RCB", localGidCells ),
806  "Error in Zoltan partitioning" );
807  delete mbZTool;
808 
809  dbgOut.tprintf( 1, "After Zoltan partitioning, localGidCells.psize() = %d\n", (int)localGidCells.psize() );
810  dbgOut.tprintf( 1, " localGidCells.size() = %d\n", (int)localGidCells.size() );
811 
812  // This is important: local cells are now redistributed, so nLocalCells might be different!
814 
815  return MB_SUCCESS;
816  }
817 #else
818  UNUSED( pco );
819 #endif
820 
821  // By default, apply trivial partition
822  localGidCells.insert( start_cell_idx, start_cell_idx + nLocalCells - 1 );
823 
824  return MB_SUCCESS;
825 }
826 #endif
827 
828 ErrorCode NCHelperGCRM::create_local_vertices( const std::vector< int >& vertices_on_local_cells,
829  EntityHandle& start_vertex )
830 {
831  Interface*& mbImpl = _readNC->mbImpl;
832  Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
833  const Tag*& mpFileIdTag = _readNC->mpFileIdTag;
834  DebugOutput& dbgOut = _readNC->dbgOut;
835  std::map< std::string, ReadNC::VarData >& varInfo = _readNC->varInfo;
836 
837  // Make a copy of vertices_on_local_cells for sorting (keep original one to set cell
838  // connectivity later)
839  std::vector< int > vertices_on_local_cells_sorted( vertices_on_local_cells );
840  std::sort( vertices_on_local_cells_sorted.begin(), vertices_on_local_cells_sorted.end() );
841  std::copy( vertices_on_local_cells_sorted.rbegin(), vertices_on_local_cells_sorted.rend(),
844 
845  dbgOut.tprintf( 1, " localGidVerts.psize() = %d\n", (int)localGidVerts.psize() );
846  dbgOut.tprintf( 1, " localGidVerts.size() = %d\n", (int)localGidVerts.size() );
847 
848  // Create local vertices
849  std::vector< double* > arrays;
851  _readNC->readMeshIface->get_node_coords( 3, nLocalVertices, 0, start_vertex, arrays,
852  // Might have to create gather mesh later
854  "Failed to create local vertices" );
855 
856  // Add local vertices to current file set
857  Range local_verts_range( start_vertex, start_vertex + nLocalVertices - 1 );
858  MB_CHK_SET_ERR( _readNC->mbImpl->add_entities( _fileSet, local_verts_range ),
859  "Failed to add local vertices to current file set" );
860 
861  // Get ptr to GID memory for local vertices
862  int count = 0;
863  void* data = NULL;
864  MB_CHK_SET_ERR( mbImpl->tag_iterate( mGlobalIdTag, local_verts_range.begin(), local_verts_range.end(), count,
865  data ),
866  "Failed to iterate global id tag on local vertices" );
867  assert( count == nLocalVertices );
868  int* gid_data = (int*)data;
869  std::copy( localGidVerts.begin(), localGidVerts.end(), gid_data );
870 
871  // Duplicate GID data, which will be used to resolve sharing
872  if( mpFileIdTag )
873  {
874  MB_CHK_SET_ERR( mbImpl->tag_iterate( *mpFileIdTag, local_verts_range.begin(), local_verts_range.end(), count,
875  data ),
876  "Failed to iterate file id tag on local vertices" );
877  assert( count == nLocalVertices );
878  int bytes_per_tag = 4;
879  MB_CHK_SET_ERR( mbImpl->tag_get_bytes( *mpFileIdTag, bytes_per_tag ),
880  "can't get number of bytes for file id tag" );
881  if( 4 == bytes_per_tag )
882  {
883  gid_data = (int*)data;
884  std::copy( localGidVerts.begin(), localGidVerts.end(), gid_data );
885  }
886  else if( 8 == bytes_per_tag )
887  { // Should be a handle tag on 64 bit machine?
888  long* handle_tag_data = (long*)data;
889  std::copy( localGidVerts.begin(), localGidVerts.end(), handle_tag_data );
890  }
891  }
892 
893 #ifdef MOAB_HAVE_PNETCDF
894  size_t nb_reads = localGidVerts.psize();
895  std::vector< int > requests( nb_reads );
896  std::vector< int > statuss( nb_reads );
897  size_t idxReq = 0;
898 #endif
899 
900  // Store lev values in levVals
901  std::map< std::string, ReadNC::VarData >::iterator vmit;
902  if( ( vmit = varInfo.find( "layers" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
903  {
904  MB_CHK_SET_ERR( read_coordinate( "layers", 0, nLevels - 1, levVals ), "Trouble reading 'layers' variable" );
905  }
906  else if( ( vmit = varInfo.find( "interfaces" ) ) != varInfo.end() && ( *vmit ).second.varDims.size() == 1 )
907  {
908  MB_CHK_SET_ERR( read_coordinate( "interfaces", 0, nLevels - 1, levVals ),
909  "Trouble reading 'interfaces' variable" );
910  }
911  else
912  {
913  MB_SET_ERR( MB_FAILURE, "Couldn't find 'layers' or 'interfaces' variable" );
914  }
915 
916  // Decide whether down is positive
917  char posval[10] = { 0 };
918  int success = NCFUNC( get_att_text )( _fileId, ( *vmit ).second.varId, "positive", posval );
919  if( 0 == success && !strncmp( posval, "down", 4 ) )
920  {
921  for( std::vector< double >::iterator dvit = levVals.begin(); dvit != levVals.end(); ++dvit )
922  ( *dvit ) *= -1.0;
923  }
924 
925  // Read x coordinates for local vertices
926  double* xptr = arrays[0];
927  int xVertexVarId;
928  success = NCFUNC( inq_varid )( _fileId, "grid_corner_lon", &xVertexVarId );
929  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of grid_corner_lon" );
930  size_t indexInArray = 0;
931  for( Range::pair_iterator pair_iter = localGidVerts.pair_begin(); pair_iter != localGidVerts.pair_end();
932  ++pair_iter )
933  {
934  EntityHandle starth = pair_iter->first;
935  EntityHandle endh = pair_iter->second;
936  NCDF_SIZE read_start = (NCDF_SIZE)( starth - 1 );
937  NCDF_SIZE read_count = (NCDF_SIZE)( endh - starth + 1 );
938 
939  // Do a partial read in each subrange
940 #ifdef MOAB_HAVE_PNETCDF
941  success = NCFUNCREQG( _vara_double )( _fileId, xVertexVarId, &read_start, &read_count, &( xptr[indexInArray] ),
942  &requests[idxReq++] );
943 #else
944  success = NCFUNCAG( _vara_double )( _fileId, xVertexVarId, &read_start, &read_count, &( xptr[indexInArray] ) );
945 #endif
946  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_corner_lon data in a loop" );
947 
948  // Increment the index for next subrange
949  indexInArray += ( endh - starth + 1 );
950  }
951 
952 #ifdef MOAB_HAVE_PNETCDF
953  // Wait outside the loop
954  success = NCFUNC( wait_all )( _fileId, requests.size(), &requests[0], &statuss[0] );
955  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
956 #endif
957 
958  // Read y coordinates for local vertices
959  double* yptr = arrays[1];
960  int yVertexVarId;
961  success = NCFUNC( inq_varid )( _fileId, "grid_corner_lat", &yVertexVarId );
962  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of grid_corner_lat" );
963 #ifdef MOAB_HAVE_PNETCDF
964  idxReq = 0;
965 #endif
966  indexInArray = 0;
967  for( Range::pair_iterator pair_iter = localGidVerts.pair_begin(); pair_iter != localGidVerts.pair_end();
968  ++pair_iter )
969  {
970  EntityHandle starth = pair_iter->first;
971  EntityHandle endh = pair_iter->second;
972  NCDF_SIZE read_start = (NCDF_SIZE)( starth - 1 );
973  NCDF_SIZE read_count = (NCDF_SIZE)( endh - starth + 1 );
974 
975  // Do a partial read in each subrange
976 #ifdef MOAB_HAVE_PNETCDF
977  success = NCFUNCREQG( _vara_double )( _fileId, yVertexVarId, &read_start, &read_count, &( yptr[indexInArray] ),
978  &requests[idxReq++] );
979 #else
980  success = NCFUNCAG( _vara_double )( _fileId, yVertexVarId, &read_start, &read_count, &( yptr[indexInArray] ) );
981 #endif
982  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_corner_lat data in a loop" );
983 
984  // Increment the index for next subrange
985  indexInArray += ( endh - starth + 1 );
986  }
987 
988 #ifdef MOAB_HAVE_PNETCDF
989  // Wait outside the loop
990  success = NCFUNC( wait_all )( _fileId, requests.size(), &requests[0], &statuss[0] );
991  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
992 #endif
993 
994  // Convert lon/lat/rad to x/y/z
995  double* zptr = arrays[2];
996  double rad = 8000.0 + levVals[0];
997  for( int i = 0; i < nLocalVertices; i++ )
998  {
999  double cosphi = cos( yptr[i] );
1000  double zmult = sin( yptr[i] );
1001  double xmult = cosphi * cos( xptr[i] );
1002  double ymult = cosphi * sin( xptr[i] );
1003  xptr[i] = rad * xmult;
1004  yptr[i] = rad * ymult;
1005  zptr[i] = rad * zmult;
1006  }
1007 
1008  return MB_SUCCESS;
1009 }
1010 
1012 {
1013  Interface*& mbImpl = _readNC->mbImpl;
1014  Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
1015  DebugOutput& dbgOut = _readNC->dbgOut;
1016 
1017  // Read edges on each local cell, to get localGidEdges
1018  int edgesOnCellVarId;
1019  int success = NCFUNC( inq_varid )( _fileId, "cell_edges", &edgesOnCellVarId );
1020  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of cell_edges" );
1021 
1022  std::vector< int > edges_on_local_cells( nLocalCells * EDGES_PER_CELL );
1023  dbgOut.tprintf( 1, " edges_on_local_cells.size() = %d\n", (int)edges_on_local_cells.size() );
1024 
1025 #ifdef MOAB_HAVE_PNETCDF
1026  size_t nb_reads = localGidCells.psize();
1027  std::vector< int > requests( nb_reads );
1028  std::vector< int > statuss( nb_reads );
1029  size_t idxReq = 0;
1030 #endif
1031  size_t indexInArray = 0;
1032  for( Range::pair_iterator pair_iter = localGidCells.pair_begin(); pair_iter != localGidCells.pair_end();
1033  ++pair_iter )
1034  {
1035  EntityHandle starth = pair_iter->first;
1036  EntityHandle endh = pair_iter->second;
1037  dbgOut.tprintf( 1, " starth = %d\n", (int)starth );
1038  dbgOut.tprintf( 1, " endh = %d\n", (int)endh );
1039  NCDF_SIZE read_starts[2] = { static_cast< NCDF_SIZE >( starth - 1 ), 0 };
1040  NCDF_SIZE read_counts[2] = { static_cast< NCDF_SIZE >( endh - starth + 1 ),
1041  static_cast< NCDF_SIZE >( EDGES_PER_CELL ) };
1042 
1043  // Do a partial read in each subrange
1044 #ifdef MOAB_HAVE_PNETCDF
1045  success = NCFUNCREQG( _vara_int )( _fileId, edgesOnCellVarId, read_starts, read_counts,
1046  &( edges_on_local_cells[indexInArray] ), &requests[idxReq++] );
1047 #else
1048  success = NCFUNCAG( _vara_int )( _fileId, edgesOnCellVarId, read_starts, read_counts,
1049  &( edges_on_local_cells[indexInArray] ) );
1050 #endif
1051  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read cell_edges data in a loop" );
1052 
1053  // Increment the index for next subrange
1054  indexInArray += ( endh - starth + 1 ) * EDGES_PER_CELL;
1055  }
1056 
1057 #ifdef MOAB_HAVE_PNETCDF
1058  // Wait outside the loop
1059  success = NCFUNC( wait_all )( _fileId, requests.size(), &requests[0], &statuss[0] );
1060  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
1061 #endif
1062 
1063  // GCRM is 0 based, convert edge indices from 0 to 1 based
1064  for( std::size_t idx = 0; idx < edges_on_local_cells.size(); idx++ )
1065  edges_on_local_cells[idx] += 1;
1066 
1067  // Collect local edges
1068  std::sort( edges_on_local_cells.begin(), edges_on_local_cells.end() );
1069  std::copy( edges_on_local_cells.rbegin(), edges_on_local_cells.rend(), range_inserter( localGidEdges ) );
1071 
1072  dbgOut.tprintf( 1, " localGidEdges.psize() = %d\n", (int)localGidEdges.psize() );
1073  dbgOut.tprintf( 1, " localGidEdges.size() = %d\n", (int)localGidEdges.size() );
1074 
1075  // Create local edges
1076  EntityHandle start_edge;
1077  EntityHandle* conn_arr_edges = NULL;
1079  _readNC->readMeshIface->get_element_connect( nLocalEdges, 2, MBEDGE, 0, start_edge, conn_arr_edges,
1080  // Might have to create gather mesh later
1082  "Failed to create local edges" );
1083 
1084  // Add local edges to current file set
1085  Range local_edges_range( start_edge, start_edge + nLocalEdges - 1 );
1086  MB_CHK_SET_ERR( _readNC->mbImpl->add_entities( _fileSet, local_edges_range ),
1087  "Failed to add local edges to current file set" );
1088 
1089  // Get ptr to GID memory for edges
1090  int count = 0;
1091  void* data = NULL;
1092  MB_CHK_SET_ERR( mbImpl->tag_iterate( mGlobalIdTag, local_edges_range.begin(), local_edges_range.end(), count,
1093  data ),
1094  "Failed to iterate global id tag on local edges" );
1095  assert( count == nLocalEdges );
1096  int* gid_data = (int*)data;
1097  std::copy( localGidEdges.begin(), localGidEdges.end(), gid_data );
1098 
1099  int verticesOnEdgeVarId;
1100 
1101  // Read vertices on each local edge, to get edge connectivity
1102  success = NCFUNC( inq_varid )( _fileId, "edge_corners", &verticesOnEdgeVarId );
1103  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of edge_corners" );
1104  // Utilize the memory storage pointed by conn_arr_edges
1105  int* vertices_on_local_edges = (int*)conn_arr_edges;
1106 #ifdef MOAB_HAVE_PNETCDF
1107  nb_reads = localGidEdges.psize();
1108  requests.resize( nb_reads );
1109  statuss.resize( nb_reads );
1110  idxReq = 0;
1111 #endif
1112  indexInArray = 0;
1113  for( Range::pair_iterator pair_iter = localGidEdges.pair_begin(); pair_iter != localGidEdges.pair_end();
1114  ++pair_iter )
1115  {
1116  EntityHandle starth = pair_iter->first;
1117  EntityHandle endh = pair_iter->second;
1118  NCDF_SIZE read_starts[2] = { static_cast< NCDF_SIZE >( starth - 1 ), 0 };
1119  NCDF_SIZE read_counts[2] = { static_cast< NCDF_SIZE >( endh - starth + 1 ), 2 };
1120 
1121  // Do a partial read in each subrange
1122 #ifdef MOAB_HAVE_PNETCDF
1123  success = NCFUNCREQG( _vara_int )( _fileId, verticesOnEdgeVarId, read_starts, read_counts,
1124  &( vertices_on_local_edges[indexInArray] ), &requests[idxReq++] );
1125 #else
1126  success = NCFUNCAG( _vara_int )( _fileId, verticesOnEdgeVarId, read_starts, read_counts,
1127  &( vertices_on_local_edges[indexInArray] ) );
1128 #endif
1129  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read edge_corners data in a loop" );
1130 
1131  // Increment the index for next subrange
1132  indexInArray += ( endh - starth + 1 ) * 2;
1133  }
1134 
1135 #ifdef MOAB_HAVE_PNETCDF
1136  // Wait outside the loop
1137  success = NCFUNC( wait_all )( _fileId, requests.size(), &requests[0], &statuss[0] );
1138  if( success ) MB_SET_ERR( MB_FAILURE, "Failed on wait_all" );
1139 #endif
1140 
1141  // Populate connectivity data for local edges
1142  // Convert in-place from int (stored in the first half) to EntityHandle
1143  // Reading backward is the trick
1144  for( int edge_vert = nLocalEdges * 2 - 1; edge_vert >= 0; edge_vert-- )
1145  {
1146  // Note, indices stored in vertices_on_local_edges are 0 based
1147  int global_vert_idx = vertices_on_local_edges[edge_vert] + 1; // Global vertex index, 1 based
1148  int local_vert_idx = localGidVerts.index( global_vert_idx ); // Local vertex index, 0 based
1149  assert( local_vert_idx != -1 );
1150  conn_arr_edges[edge_vert] = start_vertex + local_vert_idx;
1151  }
1152 
1153  return MB_SUCCESS;
1154 }
1155 
1156 ErrorCode NCHelperGCRM::create_padded_local_cells( const std::vector< int >& vertices_on_local_cells,
1157  EntityHandle start_vertex,
1158  Range& faces )
1159 {
1160  Interface*& mbImpl = _readNC->mbImpl;
1161  Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
1162 
1163  // Create cells
1164  EntityHandle start_element;
1165  EntityHandle* conn_arr_local_cells = NULL;
1167  nLocalCells, EDGES_PER_CELL, MBPOLYGON, 0, start_element, conn_arr_local_cells,
1168  // Might have to create gather mesh later
1170  "Failed to create local cells" );
1171  faces.insert( start_element, start_element + nLocalCells - 1 );
1172 
1173  // Add local cells to current file set
1174  Range local_cells_range( start_element, start_element + nLocalCells - 1 );
1175  MB_CHK_SET_ERR( _readNC->mbImpl->add_entities( _fileSet, local_cells_range ),
1176  "Failed to add local cells to current file set" );
1177 
1178  // Get ptr to GID memory for local cells
1179  int count = 0;
1180  void* data = NULL;
1181  MB_CHK_SET_ERR( mbImpl->tag_iterate( mGlobalIdTag, local_cells_range.begin(), local_cells_range.end(), count,
1182  data ),
1183  "Failed to iterate global id tag on local cells" );
1184  assert( count == nLocalCells );
1185  int* gid_data = (int*)data;
1186  std::copy( localGidCells.begin(), localGidCells.end(), gid_data );
1187 
1188  // Set connectivity array with proper local vertices handles
1189  // vertices_on_local_cells array was already corrected to have
1190  // the last vertices repeated for pentagons, e.g. 122345 => 123455
1191  for( int local_cell_idx = 0; local_cell_idx < nLocalCells; local_cell_idx++ )
1192  {
1193  for( int i = 0; i < EDGES_PER_CELL; i++ )
1194  {
1195  // Note, indices stored in vertices_on_local_cells are 1 based
1196  EntityHandle global_vert_idx =
1197  vertices_on_local_cells[local_cell_idx * EDGES_PER_CELL + i]; // Global vertex index, 1 based
1198  int local_vert_idx = localGidVerts.index( global_vert_idx ); // Local vertex index, 0 based
1199  assert( local_vert_idx != -1 );
1200  conn_arr_local_cells[local_cell_idx * EDGES_PER_CELL + i] = start_vertex + local_vert_idx;
1201  }
1202  }
1203 
1204  return MB_SUCCESS;
1205 }
1206 
1208 {
1209  Interface*& mbImpl = _readNC->mbImpl;
1210  Tag& mGlobalIdTag = _readNC->mGlobalIdTag;
1211  const Tag*& mpFileIdTag = _readNC->mpFileIdTag;
1212 
1213  // Create gather set vertices
1214  std::vector< double* > arrays;
1215  // Don't need to specify allocation number here, because we know enough vertices were created
1216  // before
1217  MB_CHK_SET_ERR( _readNC->readMeshIface->get_node_coords( 3, nVertices, 0, gather_set_start_vertex, arrays ),
1218  "Failed to create gather set vertices" );
1219 
1220  // Add vertices to the gather set
1221  Range gather_set_verts_range( gather_set_start_vertex, gather_set_start_vertex + nVertices - 1 );
1222  MB_CHK_SET_ERR( mbImpl->add_entities( gather_set, gather_set_verts_range ),
1223  "Failed to add vertices to the gather set" );
1224 
1225  // Read x coordinates for gather set vertices
1226  double* xptr = arrays[0];
1227  int xVertexVarId;
1228  int success = NCFUNC( inq_varid )( _fileId, "grid_corner_lon", &xVertexVarId );
1229  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of grid_corner_lon" );
1230  NCDF_SIZE read_start = 0;
1231  NCDF_SIZE read_count = static_cast< NCDF_SIZE >( nVertices );
1232 #ifdef MOAB_HAVE_PNETCDF
1233  // Enter independent I/O mode, since this read is only for the gather processor
1234  success = NCFUNC( begin_indep_data )( _fileId );
1235  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to begin independent I/O mode" );
1236  success = NCFUNCG( _vara_double )( _fileId, xVertexVarId, &read_start, &read_count, xptr );
1237  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_corner_lon data" );
1238  success = NCFUNC( end_indep_data )( _fileId );
1239  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to end independent I/O mode" );
1240 #else
1241  success = NCFUNCG( _vara_double )( _fileId, xVertexVarId, &read_start, &read_count, xptr );
1242  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_corner_lon data" );
1243 #endif
1244 
1245  // Read y coordinates for gather set vertices
1246  double* yptr = arrays[1];
1247  int yVertexVarId;
1248  success = NCFUNC( inq_varid )( _fileId, "grid_corner_lat", &yVertexVarId );
1249  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of grid_corner_lat" );
1250 #ifdef MOAB_HAVE_PNETCDF
1251  // Enter independent I/O mode, since this read is only for the gather processor
1252  success = NCFUNC( begin_indep_data )( _fileId );
1253  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to begin independent I/O mode" );
1254  success = NCFUNCG( _vara_double )( _fileId, yVertexVarId, &read_start, &read_count, yptr );
1255  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_corner_lat data" );
1256  success = NCFUNC( end_indep_data )( _fileId );
1257  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to end independent I/O mode" );
1258 #else
1259  success = NCFUNCG( _vara_double )( _fileId, yVertexVarId, &read_start, &read_count, yptr );
1260  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read grid_corner_lat data" );
1261 #endif
1262 
1263  // Convert lon/lat/rad to x/y/z
1264  double* zptr = arrays[2];
1265  double rad = 8000.0 + levVals[0];
1266  for( int i = 0; i < nVertices; i++ )
1267  {
1268  double cosphi = cos( yptr[i] );
1269  double zmult = sin( yptr[i] );
1270  double xmult = cosphi * cos( xptr[i] );
1271  double ymult = cosphi * sin( xptr[i] );
1272  xptr[i] = rad * xmult;
1273  yptr[i] = rad * ymult;
1274  zptr[i] = rad * zmult;
1275  }
1276 
1277  // Get ptr to GID memory for gather set vertices
1278  int count = 0;
1279  void* data = NULL;
1280  MB_CHK_SET_ERR( mbImpl->tag_iterate( mGlobalIdTag, gather_set_verts_range.begin(), gather_set_verts_range.end(),
1281  count, data ),
1282  "Failed to iterate global id tag on gather set vertices" );
1283  assert( count == nVertices );
1284  int* gid_data = (int*)data;
1285  for( int j = 1; j <= nVertices; j++ )
1286  gid_data[j - 1] = j;
1287 
1288  // Set the file id tag too, it should be bigger something not interfering with global id
1289  if( mpFileIdTag )
1290  {
1291  MB_CHK_SET_ERR( mbImpl->tag_iterate( *mpFileIdTag, gather_set_verts_range.begin(), gather_set_verts_range.end(),
1292  count, data ),
1293  "Failed to iterate file id tag on gather set vertices" );
1294  assert( count == nVertices );
1295  int bytes_per_tag = 4;
1296  MB_CHK_SET_ERR( mbImpl->tag_get_bytes( *mpFileIdTag, bytes_per_tag ),
1297  "Can't get number of bytes for file id tag" );
1298  if( 4 == bytes_per_tag )
1299  {
1300  gid_data = (int*)data;
1301  for( int j = 1; j <= nVertices; j++ )
1302  gid_data[j - 1] = nVertices + j; // Bigger than global id tag
1303  }
1304  else if( 8 == bytes_per_tag )
1305  { // Should be a handle tag on 64 bit machine?
1306  long* handle_tag_data = (long*)data;
1307  for( int j = 1; j <= nVertices; j++ )
1308  handle_tag_data[j - 1] = nVertices + j; // Bigger than global id tag
1309  }
1310  }
1311 
1312  return MB_SUCCESS;
1313 }
1314 
1316 {
1317  Interface*& mbImpl = _readNC->mbImpl;
1318 
1319  // Create gather set edges
1320  EntityHandle start_edge;
1321  EntityHandle* conn_arr_gather_set_edges = NULL;
1322  // Don't need to specify allocation number here, because we know enough edges were created
1323  // before
1325  conn_arr_gather_set_edges ),
1326  "Failed to create gather set edges" );
1327 
1328  // Add edges to the gather set
1329  Range gather_set_edges_range( start_edge, start_edge + nEdges - 1 );
1330  MB_CHK_SET_ERR( mbImpl->add_entities( gather_set, gather_set_edges_range ),
1331  "Failed to add edges to the gather set" );
1332 
1333  // Read vertices on each edge
1334  int verticesOnEdgeVarId;
1335  int success = NCFUNC( inq_varid )( _fileId, "edge_corners", &verticesOnEdgeVarId );
1336  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of edge_corners" );
1337  // Utilize the memory storage pointed by conn_arr_gather_set_edges
1338  int* vertices_on_gather_set_edges = (int*)conn_arr_gather_set_edges;
1339  NCDF_SIZE read_starts[2] = { 0, 0 };
1340  NCDF_SIZE read_counts[2] = { static_cast< NCDF_SIZE >( nEdges ), 2 };
1341 #ifdef MOAB_HAVE_PNETCDF
1342  // Enter independent I/O mode, since this read is only for the gather processor
1343  success = NCFUNC( begin_indep_data )( _fileId );
1344  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to begin independent I/O mode" );
1345  success =
1346  NCFUNCG( _vara_int )( _fileId, verticesOnEdgeVarId, read_starts, read_counts, vertices_on_gather_set_edges );
1347  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read edge_corners data" );
1348  success = NCFUNC( end_indep_data )( _fileId );
1349  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to end independent I/O mode" );
1350 #else
1351  success =
1352  NCFUNCG( _vara_int )( _fileId, verticesOnEdgeVarId, read_starts, read_counts, vertices_on_gather_set_edges );
1353  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read edge_corners data" );
1354 #endif
1355 
1356  // Populate connectivity data for gather set edges
1357  // Convert in-place from int (stored in the first half) to EntityHandle
1358  // Reading backward is the trick
1359  for( int edge_vert = nEdges * 2 - 1; edge_vert >= 0; edge_vert-- )
1360  {
1361  // Note, indices stored in vertices_on_gather_set_edges are 0 based
1362  int gather_set_vert_idx = vertices_on_gather_set_edges[edge_vert]; // Global vertex index, 0 based
1363  // Connectivity array is shifted by where the gather set vertices start
1364  conn_arr_gather_set_edges[edge_vert] = gather_set_start_vertex + gather_set_vert_idx;
1365  }
1366 
1367  return MB_SUCCESS;
1368 }
1369 
1371 {
1372  Interface*& mbImpl = _readNC->mbImpl;
1373 
1374  // Create gather set cells
1375  EntityHandle start_element;
1376  EntityHandle* conn_arr_gather_set_cells = NULL;
1377  // Don't need to specify allocation number here, because we know enough cells were created
1378  // before
1380  conn_arr_gather_set_cells ),
1381  "Failed to create gather set cells" );
1382 
1383  // Add cells to the gather set
1384  Range gather_set_cells_range( start_element, start_element + nCells - 1 );
1385  MB_CHK_SET_ERR( mbImpl->add_entities( gather_set, gather_set_cells_range ),
1386  "Failed to add cells to the gather set" );
1387 
1388  // Read vertices on each gather set cell (connectivity)
1389  int verticesOnCellVarId;
1390  int success = NCFUNC( inq_varid )( _fileId, "cell_corners", &verticesOnCellVarId );
1391  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to get variable id of cell_corners" );
1392  // Utilize the memory storage pointed by conn_arr_gather_set_cells
1393  int* vertices_on_gather_set_cells = (int*)conn_arr_gather_set_cells;
1394  NCDF_SIZE read_starts[2] = { 0, 0 };
1395  NCDF_SIZE read_counts[2] = { static_cast< NCDF_SIZE >( nCells ), static_cast< NCDF_SIZE >( EDGES_PER_CELL ) };
1396 #ifdef MOAB_HAVE_PNETCDF
1397  // Enter independent I/O mode, since this read is only for the gather processor
1398  success = NCFUNC( begin_indep_data )( _fileId );
1399  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to begin independent I/O mode" );
1400  success =
1401  NCFUNCG( _vara_int )( _fileId, verticesOnCellVarId, read_starts, read_counts, vertices_on_gather_set_cells );
1402  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read cell_corners data" );
1403  success = NCFUNC( end_indep_data )( _fileId );
1404  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to end independent I/O mode" );
1405 #else
1406  success =
1407  NCFUNCG( _vara_int )( _fileId, verticesOnCellVarId, read_starts, read_counts, vertices_on_gather_set_cells );
1408  if( success ) MB_SET_ERR( MB_FAILURE, "Failed to read cell_corners data" );
1409 #endif
1410 
1411  // Correct gather set cell vertices array in the same way as local cell vertices array
1412  // Pentagons as hexagons should have a connectivity like 123455 and not 122345
1413  for( int gather_set_cell_idx = 0; gather_set_cell_idx < nCells; gather_set_cell_idx++ )
1414  {
1415  int* pvertex = vertices_on_gather_set_cells + gather_set_cell_idx * EDGES_PER_CELL;
1416  for( int k = 0; k < EDGES_PER_CELL - 2; k++ )
1417  {
1418  if( *( pvertex + k ) == *( pvertex + k + 1 ) )
1419  {
1420  // Shift the connectivity
1421  for( int kk = k + 1; kk < EDGES_PER_CELL - 1; kk++ )
1422  *( pvertex + kk ) = *( pvertex + kk + 1 );
1423  // No need to try next k
1424  break;
1425  }
1426  }
1427  }
1428 
1429  // Populate connectivity data for gather set cells
1430  // Convert in-place from int (stored in the first half) to EntityHandle
1431  // Reading backward is the trick
1432  for( int cell_vert = nCells * EDGES_PER_CELL - 1; cell_vert >= 0; cell_vert-- )
1433  {
1434  // Note, indices stored in vertices_on_gather_set_cells are 0 based
1435  int gather_set_vert_idx = vertices_on_gather_set_cells[cell_vert]; // Global vertex index, 0 based
1436  // Connectivity array is shifted by where the gather set vertices start
1437  conn_arr_gather_set_cells[cell_vert] = gather_set_start_vertex + gather_set_vert_idx;
1438  }
1439 
1440  return MB_SUCCESS;
1441 }
1442 
1443 } // namespace moab