Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
moab::NCWriteESMF Class Reference

#include <NCWriteESMF.hpp>

+ Inheritance diagram for moab::NCWriteESMF:
+ Collaboration diagram for moab::NCWriteESMF:

Public Member Functions

 NCWriteESMF (WriteNC *writeNC, int fileId, const FileOptions &opts, EntityHandle fileSet)
 
virtual ~NCWriteESMF () override
 
ErrorCode collect_mesh_info () override
 Collect necessary info about local mesh (implemented in child classes) More...
 
ErrorCode init_file (std::vector< std::string > &var_names, std::vector< std::string > &desired_names, bool _append) override
 Initialize file: this is where all defines are done. Virtual so that grid-output writers (NCWriteScrip / NCWriteESMF / NCWriteDomain) can synthesize a fresh schema from mesh state instead of going through the climate var_names plumbing. More...
 
ErrorCode write_values (std::vector< std::string > &var_names, std::vector< int > &tstep_nums) override
 Take the info from VarData and write first non-set variables, then set variables. Virtual for the same reason as init_file. More...
 
- Public Member Functions inherited from moab::NCWriteHelper
 NCWriteHelper (WriteNC *writeNC, int fileId, const FileOptions &opts, EntityHandle fileSet)
 
virtual ~NCWriteHelper ()
 
virtual ErrorCode collect_variable_data (std::vector< std::string > &var_names, std::vector< int > &tstep_nums)
 Collect data for specified variables (partially implemented in child classes) More...
 

Protected Member Functions

ErrorCode write_nonset_variables (std::vector< WriteNC::VarData > &vdatas, std::vector< int > &tstep_nums) override
 

Private Attributes

long mLocalCells
 
long mGlobalCells
 
long mGlobalNodes
 
int mMaxCornersGlobal
 
int mCoordDim
 
bool mHasAreas
 
bool mHasMask
 
std::vector< int > mLocalCellGids
 
std::vector< double > mNodeLon
 
std::vector< double > mNodeLat
 
std::vector< int > mNodeGids
 
std::vector< int > mElementConn
 
std::vector< int > mElementNumNodes
 
std::vector< double > mCenterLon
 
std::vector< double > mCenterLat
 
std::vector< double > mAreas
 
std::vector< int > mMask
 
int mDimNodeCount
 
int mDimElementCount
 
int mDimMaxNodePElement
 
int mDimCoordDim
 
int mVarNodeCoords
 
int mVarElementConn
 
int mVarNumElementConn
 
int mVarCenterCoords
 
int mVarElementArea
 
int mVarElementMask
 

Additional Inherited Members

- Static Public Member Functions inherited from moab::NCWriteHelper
static NCWriteHelperget_nc_helper (WriteNC *writeNC, int fileId, const FileOptions &opts, EntityHandle fileSet)
 Get appropriate helper instance for WriteNC class based on some info in the file set. More...
 
- Protected Attributes inherited from moab::NCWriteHelper
WriteNC_writeNC
 Allow NCWriteHelper to directly access members of WriteNC. More...
 
int _fileId
 Cache some information from WriteNC. More...
 
const FileOptions_opts
 
EntityHandle _fileSet
 
int nTimeSteps
 Dimensions of time and level. More...
 
int nLevels
 
int tDim
 Dimension numbers for time and level. More...
 
int levDim
 
Range localCellsOwned
 Local owned cells, edges and vertices. More...
 
Range localEdgesOwned
 
Range localVertsOwned
 
std::vector< double > timeStepVals
 Time values of output timesteps. More...
 

Detailed Description

Definition at line 36 of file NCWriteESMF.hpp.

Constructor & Destructor Documentation

◆ NCWriteESMF()

moab::NCWriteESMF::NCWriteESMF ( WriteNC writeNC,
int  fileId,
const FileOptions opts,
EntityHandle  fileSet 
)
inline

Definition at line 39 of file NCWriteESMF.hpp.

40  : NCWriteHelper( writeNC, fileId, opts, fileSet ),
42  mHasAreas( false ), mHasMask( false ),
46  {
47  }

◆ ~NCWriteESMF()

moab::NCWriteESMF::~NCWriteESMF ( )
overridevirtual

Definition at line 22 of file NCWriteESMF.cpp.

22 {}

Member Function Documentation

◆ collect_mesh_info()

ErrorCode moab::NCWriteESMF::collect_mesh_info ( )
overridevirtual

Collect necessary info about local mesh (implemented in child classes)

Implements moab::NCWriteHelper.

Definition at line 51 of file NCWriteESMF.cpp.

52 {
53  Interface*& mbImpl = _writeNC->mbImpl;
54  Tag& mGlobalIdTag = _writeNC->mGlobalIdTag;
55  DebugOutput& dbgOut = _writeNC->dbgOut;
56 
57  Range allCells;
58  MB_CHK_SET_ERR( mbImpl->get_entities_by_dimension( _fileSet, 2, allCells ),
59  "Failed to gather 2-D cells for ESMF write" );
60  if( allCells.empty() ) MB_SET_ERR( MB_FAILURE, "No 2-D cells in file set; cannot write ESMF grid" );
61 
62  localCellsOwned = allCells;
63 #ifdef MOAB_HAVE_MPI
64  bool& isParallel = _writeNC->isParallel;
65  if( isParallel )
66  {
67  ParallelComm*& myPcomm = _writeNC->myPcomm;
68  if( myPcomm && myPcomm->proc_config().proc_size() > 1 )
69  {
70  MB_CHK_SET_ERR( myPcomm->filter_pstatus( localCellsOwned, PSTATUS_NOT_OWNED, PSTATUS_NOT ),
71  "Failed to filter owned cells for ESMF write" );
72  }
73  }
74 #endif
75 
76  mLocalCells = static_cast< long >( localCellsOwned.size() );
77 
78  // Global max corners per cell.
79  int localMaxCorners = 0;
80  for( Range::iterator cit = localCellsOwned.begin(); cit != localCellsOwned.end(); ++cit )
81  {
82  const EntityHandle* conn = nullptr;
83  int numConn = 0;
84  if( MB_SUCCESS == mbImpl->get_connectivity( *cit, conn, numConn ) && numConn > localMaxCorners )
85  localMaxCorners = numConn;
86  }
87 #ifdef MOAB_HAVE_MPI
88  if( _writeNC->isParallel && _writeNC->myPcomm )
89  {
90  MPI_Allreduce( &localMaxCorners, &mMaxCornersGlobal, 1, MPI_INT, MPI_MAX,
91  _writeNC->myPcomm->proc_config().proc_comm() );
92  }
93  else
94 #endif
95  {
96  mMaxCornersGlobal = localMaxCorners;
97  }
98  if( mMaxCornersGlobal <= 0 ) MB_SET_ERR( MB_FAILURE, "Cells reported zero connectivity; cannot write ESMF" );
99 
100  // First pass: collect the set of vertex handles referenced by owned
101  // cells, plus per-cell (numNodes, connectivity-by-EntityHandle).
102  std::set< EntityHandle > usedVerts;
103  std::vector< std::vector< EntityHandle > > perCellConn( mLocalCells );
104  mElementNumNodes.assign( mLocalCells, 0 );
105  mLocalCellGids.assign( mLocalCells, 0 );
106  mCenterLat.assign( mLocalCells, 0.0 );
107  mCenterLon.assign( mLocalCells, 0.0 );
108 
109  long ci = 0;
110  for( Range::iterator cit = localCellsOwned.begin(); cit != localCellsOwned.end(); ++cit, ++ci )
111  {
112  int gid = 0;
113  if( mGlobalIdTag ) mbImpl->tag_get_data( mGlobalIdTag, &( *cit ), 1, &gid );
114  mLocalCellGids[ci] = gid;
115 
116  const EntityHandle* conn = nullptr;
117  int numConn = 0;
118  MB_CHK_SET_ERR( mbImpl->get_connectivity( *cit, conn, numConn ), "Cell connectivity lookup failed" );
119  mElementNumNodes[ci] = numConn;
120  perCellConn[ci].assign( conn, conn + numConn );
121 
122  // Compute the per-cell center directly from vertex coords.
123  double cx = 0.0, cy = 0.0, cz = 0.0;
124  for( int k = 0; k < numConn; ++k )
125  {
126  usedVerts.insert( conn[k] );
127  double vc[3] = { 0.0, 0.0, 0.0 };
128  MB_CHK_SET_ERR( mbImpl->get_coords( &conn[k], 1, vc ), "Vertex coordinate lookup failed" );
129  cx += vc[0];
130  cy += vc[1];
131  cz += vc[2];
132  }
133  cx /= numConn;
134  cy /= numConn;
135  cz /= numConn;
136  xyz_to_latlon_deg( cx, cy, cz, mCenterLat[ci], mCenterLon[ci] );
137  }
138 
139  // Build per-rank node arrays (vertex GID + lat/lon).
140  const size_t localNodeCount = usedVerts.size();
141  mNodeGids.assign( localNodeCount, 0 );
142  mNodeLon.assign( localNodeCount, 0.0 );
143  mNodeLat.assign( localNodeCount, 0.0 );
144  {
145  size_t ni = 0;
146  for( EntityHandle v : usedVerts )
147  {
148  int vgid = 0;
149  if( mGlobalIdTag ) mbImpl->tag_get_data( mGlobalIdTag, &v, 1, &vgid );
150  mNodeGids[ni] = vgid;
151  double vc[3] = { 0.0, 0.0, 0.0 };
152  mbImpl->get_coords( &v, 1, vc );
153  xyz_to_latlon_deg( vc[0], vc[1], vc[2], mNodeLat[ni], mNodeLon[ni] );
154  ++ni;
155  }
156  }
157 
158  // Build per-rank connectivity as vertex GIDs (1-based index will be
159  // assigned later at rank 0 after global dedup).
160  mElementConn.assign( static_cast< size_t >( mLocalCells ) * mMaxCornersGlobal, 0 );
161  for( long c = 0; c < mLocalCells; ++c )
162  {
163  const std::vector< EntityHandle >& cv = perCellConn[c];
164  int firstGid = 0;
165  for( int k = 0; k < (int)cv.size(); ++k )
166  {
167  int vgid = 0;
168  if( mGlobalIdTag ) mbImpl->tag_get_data( mGlobalIdTag, &cv[k], 1, &vgid );
169  mElementConn[c * mMaxCornersGlobal + k] = vgid;
170  if( k == 0 ) firstGid = vgid;
171  }
172  // Pad unused slots with first GID (writers convention; the
173  // numElementConn field tells the reader the real per-cell count).
174  for( int k = (int)cv.size(); k < mMaxCornersGlobal; ++k )
175  mElementConn[c * mMaxCornersGlobal + k] = firstGid;
176  }
177 
178  // Optional masks / areas from familiar tags (matches what NCHelperESMF
179  // would produce on read).
180  Tag maskTag = 0;
181  if( MB_SUCCESS == mbImpl->tag_get_handle( "ELEMENT_MASK", 1, MB_TYPE_INTEGER, maskTag ) && maskTag )
182  {
183  mMask.assign( mLocalCells, 1 );
184  if( MB_SUCCESS == mbImpl->tag_get_data( maskTag, localCellsOwned, mMask.data() ) )
185  mHasMask = true;
186  else
187  mMask.clear();
188  }
189  Tag areaTag = 0;
190  if( MB_SUCCESS == mbImpl->tag_get_handle( "GRID_AREA", 1, MB_TYPE_DOUBLE, areaTag ) && areaTag )
191  {
192  mAreas.assign( mLocalCells, 0.0 );
193  if( MB_SUCCESS == mbImpl->tag_get_data( areaTag, localCellsOwned, mAreas.data() ) )
194  mHasAreas = true;
195  else
196  mAreas.clear();
197  }
198 
199  // Global cell count.
201 #ifdef MOAB_HAVE_MPI
202  if( _writeNC->isParallel && _writeNC->myPcomm )
203  {
204  long localN = mLocalCells;
205  MPI_Allreduce( &localN, &mGlobalCells, 1, MPI_LONG, MPI_SUM,
206  _writeNC->myPcomm->proc_config().proc_comm() );
207  }
208 #endif
209  // Global node count is set after rank 0 does the dedup in write_values;
210  // here we just stash a lower bound for the init_file dim size.
211  mGlobalNodes = static_cast< long >( localNodeCount );
212 #ifdef MOAB_HAVE_MPI
213  if( _writeNC->isParallel && _writeNC->myPcomm )
214  {
215  // Worst-case (no sharing): sum local node counts. The reader
216  // doesn't care if we declare a slightly larger nodeCount than
217  // actually used, but for cleanliness we'll set the dim from the
218  // actual deduplicated count once we know it (init_file uses
219  // mGlobalNodes; we overwrite it before init_file runs).
220  long localN = static_cast< long >( localNodeCount );
221  MPI_Allreduce( &localN, &mGlobalNodes, 1, MPI_LONG, MPI_SUM,
222  _writeNC->myPcomm->proc_config().proc_comm() );
223  }
224 #endif
225 
226  dbgOut.tprintf( 1, " ESMF write: local_cells=%ld global_cells=%ld local_nodes=%zu max_corners=%d\n", mLocalCells,
227  mGlobalCells, localNodeCount, mMaxCornersGlobal );
228 
229  return MB_SUCCESS;
230 }

References moab::NCWriteHelper::_fileSet, moab::NCWriteHelper::_writeNC, moab::Range::begin(), moab::WriteNC::dbgOut, moab::Range::empty(), moab::Range::end(), moab::ParallelComm::filter_pstatus(), moab::Interface::get_connectivity(), moab::Interface::get_coords(), moab::Interface::get_entities_by_dimension(), moab::WriteNC::isParallel, moab::NCWriteHelper::localCellsOwned, mAreas, MB_CHK_SET_ERR, MB_SET_ERR, MB_SUCCESS, MB_TYPE_DOUBLE, MB_TYPE_INTEGER, moab::WriteNC::mbImpl, mCenterLat, mCenterLon, mElementConn, mElementNumNodes, mGlobalCells, moab::WriteNC::mGlobalIdTag, mGlobalNodes, mHasAreas, mHasMask, mLocalCellGids, mLocalCells, mMask, mMaxCornersGlobal, mNodeGids, mNodeLat, mNodeLon, moab::ParallelComm::proc_config(), moab::ProcConfig::proc_size(), PSTATUS_NOT, PSTATUS_NOT_OWNED, moab::Range::size(), moab::Interface::tag_get_data(), moab::Interface::tag_get_handle(), moab::DebugOutput::tprintf(), and moab::anonymous_namespace{NCWriteESMF.cpp}::xyz_to_latlon_deg().

◆ init_file()

ErrorCode moab::NCWriteESMF::init_file ( std::vector< std::string > &  var_names,
std::vector< std::string > &  desired_names,
bool  _append 
)
overridevirtual

Initialize file: this is where all defines are done. Virtual so that grid-output writers (NCWriteScrip / NCWriteESMF / NCWriteDomain) can synthesize a fresh schema from mesh state instead of going through the climate var_names plumbing.

Reimplemented from moab::NCWriteHelper.

Definition at line 238 of file NCWriteESMF.cpp.

241 {
242  // Dimensions
243  if( NCFUNC( def_dim )( _fileId, "nodeCount", static_cast< size_t >( mGlobalNodes ), &mDimNodeCount ) )
244  MB_SET_ERR( MB_FAILURE, "Failed to define nodeCount dim" );
245  if( NCFUNC( def_dim )( _fileId, "elementCount", static_cast< size_t >( mGlobalCells ), &mDimElementCount ) )
246  MB_SET_ERR( MB_FAILURE, "Failed to define elementCount dim" );
247  if( NCFUNC( def_dim )( _fileId, "maxNodePElement", static_cast< size_t >( mMaxCornersGlobal ),
249  MB_SET_ERR( MB_FAILURE, "Failed to define maxNodePElement dim" );
250  if( NCFUNC( def_dim )( _fileId, "coordDim", static_cast< size_t >( mCoordDim ), &mDimCoordDim ) )
251  MB_SET_ERR( MB_FAILURE, "Failed to define coordDim dim" );
252 
253  const int dimsNode[2] = { mDimNodeCount, mDimCoordDim };
254  const int dimsElem[2] = { mDimElementCount, mDimMaxNodePElement };
255  const int dimsCenter[2] = { mDimElementCount, mDimCoordDim };
256  const int dimsElem1[1] = { mDimElementCount };
257 
258  if( NCFUNC( def_var )( _fileId, "nodeCoords", NC_DOUBLE, 2, dimsNode, &mVarNodeCoords ) )
259  MB_SET_ERR( MB_FAILURE, "Failed to define nodeCoords var" );
260  if( NCFUNC( def_var )( _fileId, "elementConn", NC_INT, 2, dimsElem, &mVarElementConn ) )
261  MB_SET_ERR( MB_FAILURE, "Failed to define elementConn var" );
262  if( NCFUNC( def_var )( _fileId, "numElementConn", NC_INT, 1, dimsElem1, &mVarNumElementConn ) )
263  MB_SET_ERR( MB_FAILURE, "Failed to define numElementConn var" );
264  if( NCFUNC( def_var )( _fileId, "centerCoords", NC_DOUBLE, 2, dimsCenter, &mVarCenterCoords ) )
265  MB_SET_ERR( MB_FAILURE, "Failed to define centerCoords var" );
266 
267  if( mHasAreas )
268  {
269  if( NCFUNC( def_var )( _fileId, "elementArea", NC_DOUBLE, 1, dimsElem1, &mVarElementArea ) )
270  MB_SET_ERR( MB_FAILURE, "Failed to define elementArea var" );
271  }
272  if( mHasMask )
273  {
274  if( NCFUNC( def_var )( _fileId, "elementMask", NC_INT, 1, dimsElem1, &mVarElementMask ) )
275  MB_SET_ERR( MB_FAILURE, "Failed to define elementMask var" );
276  }
277 
278  const char* deg = "degrees";
279  NCFUNC( put_att_text )( _fileId, mVarNodeCoords, "units", 7, deg );
280  NCFUNC( put_att_text )( _fileId, mVarCenterCoords, "units", 7, deg );
281  if( mHasAreas )
282  {
283  const char* rad2 = "radians^2";
284  NCFUNC( put_att_text )( _fileId, mVarElementArea, "units", 9, rad2 );
285  }
286  const char* gridtype = "unstructured";
287  NCFUNC( put_att_text )( _fileId, NC_GLOBAL, "gridType", std::strlen( gridtype ), gridtype );
288  const char* title = "MOAB:NCWriteESMF generated ESMF unstructured grid file";
289  NCFUNC( put_att_text )( _fileId, NC_GLOBAL, "title", std::strlen( title ), title );
290 
291  if( NCFUNC( enddef )( _fileId ) ) MB_SET_ERR( MB_FAILURE, "enddef failed for ESMF write" );
292 
293  return MB_SUCCESS;
294 }

References moab::NCWriteHelper::_fileId, MB_SET_ERR, MB_SUCCESS, mCoordDim, mDimCoordDim, mDimElementCount, mDimMaxNodePElement, mDimNodeCount, mGlobalCells, mGlobalNodes, mHasAreas, mHasMask, mMaxCornersGlobal, mVarCenterCoords, mVarElementArea, mVarElementConn, mVarElementMask, mVarNodeCoords, mVarNumElementConn, and NCFUNC.

◆ write_nonset_variables()

ErrorCode moab::NCWriteESMF::write_nonset_variables ( std::vector< WriteNC::VarData > &  vdatas,
std::vector< int > &  tstep_nums 
)
overrideprotectedvirtual

Implements moab::NCWriteHelper.

Definition at line 530 of file NCWriteESMF.cpp.

532 {
533  return MB_SUCCESS;
534 }

References MB_SUCCESS.

◆ write_values()

ErrorCode moab::NCWriteESMF::write_values ( std::vector< std::string > &  var_names,
std::vector< int > &  tstep_nums 
)
overridevirtual

Take the info from VarData and write first non-set variables, then set variables. Virtual for the same reason as init_file.

Reimplemented from moab::NCWriteHelper.

Definition at line 303 of file NCWriteESMF.cpp.

305 {
306  DebugOutput& dbgOut = _writeNC->dbgOut;
307 
308  // Helper assembling the rank-0 unified arrays and writing the file.
309  auto writeAll = [&]( const std::vector< int >& allCellGids, const std::vector< int >& allNumNodes,
310  const std::vector< int >& allConnGid, const std::vector< double >& allCenterLat,
311  const std::vector< double >& allCenterLon, const std::vector< int >& allNodeGids,
312  const std::vector< double >& allNodeLat, const std::vector< double >& allNodeLon,
313  const std::vector< double >& allAreas, const std::vector< int >& allMask ) -> ErrorCode {
314  const int ncpc = mMaxCornersGlobal;
315  const long nCellsG = static_cast< long >( allCellGids.size() );
316  const long nNodesIn = static_cast< long >( allNodeGids.size() );
317 
318  // ---- Dedup nodes by GID ----------------------------------------
319  // Build a sorted, unique vertex-GID list and a map gid -> 1-based
320  // index for the elementConn rewrite.
321  std::vector< int > nodeOrder( nNodesIn );
322  for( long i = 0; i < nNodesIn; ++i )
323  nodeOrder[i] = static_cast< int >( i );
324  std::sort( nodeOrder.begin(), nodeOrder.end(),
325  [&]( int a, int b ) { return allNodeGids[a] < allNodeGids[b]; } );
326 
327  std::vector< int > uniqNodeGids;
328  std::vector< double > uniqNodeLat, uniqNodeLon;
329  std::map< int, int > gid2Idx; // global vertex GID -> 1-based unique index
330  uniqNodeGids.reserve( nNodesIn );
331  uniqNodeLat.reserve( nNodesIn );
332  uniqNodeLon.reserve( nNodesIn );
333  int prevGid = -1;
334  for( long i = 0; i < nNodesIn; ++i )
335  {
336  const int idx = nodeOrder[i];
337  const int g = allNodeGids[idx];
338  if( g != prevGid )
339  {
340  uniqNodeGids.push_back( g );
341  uniqNodeLat.push_back( allNodeLat[idx] );
342  uniqNodeLon.push_back( allNodeLon[idx] );
343  gid2Idx[g] = static_cast< int >( uniqNodeGids.size() ); // 1-based
344  prevGid = g;
345  }
346  }
347  const long nNodesU = static_cast< long >( uniqNodeGids.size() );
348 
349  // ---- Sort cells by GID for deterministic on-disk ordering ------
350  std::vector< long > cellOrder( nCellsG );
351  for( long i = 0; i < nCellsG; ++i )
352  cellOrder[i] = i;
353  std::sort( cellOrder.begin(), cellOrder.end(),
354  [&]( long a, long b ) { return allCellGids[a] < allCellGids[b]; } );
355 
356  // ---- Build the final writable arrays in cell-sorted order ------
357  std::vector< int > numNodes( nCellsG );
358  std::vector< int > connIdx( static_cast< size_t >( nCellsG ) * ncpc );
359  std::vector< double > centerLat( nCellsG ), centerLon( nCellsG );
360  std::vector< double > areas;
361  std::vector< int > mask;
362  if( !allAreas.empty() ) areas.resize( nCellsG );
363  if( !allMask.empty() ) mask.resize( nCellsG );
364 
365  for( long i = 0; i < nCellsG; ++i )
366  {
367  const long src = cellOrder[i];
368  numNodes[i] = allNumNodes[src];
369  centerLat[i] = allCenterLat[src];
370  centerLon[i] = allCenterLon[src];
371  if( !areas.empty() ) areas[i] = allAreas[src];
372  if( !mask.empty() ) mask[i] = allMask[src];
373 
374  for( int k = 0; k < ncpc; ++k )
375  {
376  const int g = allConnGid[src * ncpc + k];
377  auto it = gid2Idx.find( g );
378  connIdx[i * ncpc + k] = ( it == gid2Idx.end() ) ? 0 : it->second;
379  }
380  }
381 
382  // ---- Interleave node and center coords as [lon, lat] -----------
383  std::vector< double > nodeCoords( nNodesU * 2 ), centerCoords( nCellsG * 2 );
384  for( long i = 0; i < nNodesU; ++i )
385  {
386  nodeCoords[i * 2 + 0] = uniqNodeLon[i];
387  nodeCoords[i * 2 + 1] = uniqNodeLat[i];
388  }
389  for( long i = 0; i < nCellsG; ++i )
390  {
391  centerCoords[i * 2 + 0] = centerLon[i];
392  centerCoords[i * 2 + 1] = centerLat[i];
393  }
394 
395  // ---- Write to disk via the dispatch layer ----------------------
396  const size_t startN[2] = { 0, 0 };
397  const size_t countN[2] = { static_cast< size_t >( nNodesU ), static_cast< size_t >( mCoordDim ) };
398  if( NCFUNCAP( _vara_double )( _fileId, mVarNodeCoords, startN, countN, nodeCoords.data() ) )
399  MB_SET_ERR( MB_FAILURE, "Failed to write nodeCoords" );
400 
401  const size_t startE[2] = { 0, 0 };
402  const size_t countE[2] = { static_cast< size_t >( nCellsG ), static_cast< size_t >( ncpc ) };
403  if( NCFUNCAP( _vara_int )( _fileId, mVarElementConn, startE, countE, connIdx.data() ) )
404  MB_SET_ERR( MB_FAILURE, "Failed to write elementConn" );
405 
406  size_t s1 = 0, c1 = static_cast< size_t >( nCellsG );
407  if( NCFUNCAP( _vara_int )( _fileId, mVarNumElementConn, &s1, &c1, numNodes.data() ) )
408  MB_SET_ERR( MB_FAILURE, "Failed to write numElementConn" );
409 
410  const size_t startC[2] = { 0, 0 };
411  const size_t countC[2] = { static_cast< size_t >( nCellsG ), static_cast< size_t >( mCoordDim ) };
412  if( NCFUNCAP( _vara_double )( _fileId, mVarCenterCoords, startC, countC, centerCoords.data() ) )
413  MB_SET_ERR( MB_FAILURE, "Failed to write centerCoords" );
414 
415  if( !areas.empty() )
416  {
417  if( NCFUNCAP( _vara_double )( _fileId, mVarElementArea, &s1, &c1, areas.data() ) )
418  MB_SET_ERR( MB_FAILURE, "Failed to write elementArea" );
419  }
420  if( !mask.empty() )
421  {
422  if( NCFUNCAP( _vara_int )( _fileId, mVarElementMask, &s1, &c1, mask.data() ) )
423  MB_SET_ERR( MB_FAILURE, "Failed to write elementMask" );
424  }
425 
426  return MB_SUCCESS;
427  };
428 
429 #ifdef MOAB_HAVE_MPI
430  if( _writeNC->isParallel && _writeNC->myPcomm && _writeNC->myPcomm->proc_config().proc_size() > 1 )
431  {
432  MPI_Comm comm = _writeNC->myPcomm->proc_config().proc_comm();
433  const int rank = _writeNC->myPcomm->proc_config().proc_rank();
434  const int size = _writeNC->myPcomm->proc_config().proc_size();
435  const int ncpc = mMaxCornersGlobal;
436 
437  // Per-rank cell counts + displacements for gather.
438  int myCells = static_cast< int >( mLocalCells );
439  std::vector< int > cellCounts( size, 0 ), cellDispls( size, 0 );
440  MPI_Gather( &myCells, 1, MPI_INT, cellCounts.data(), 1, MPI_INT, 0, comm );
441 
442  // Per-rank node counts (these vary per rank — each rank reports
443  // its own local node count).
444  int myNodes = static_cast< int >( mNodeGids.size() );
445  std::vector< int > nodeCounts( size, 0 ), nodeDispls( size, 0 );
446  MPI_Gather( &myNodes, 1, MPI_INT, nodeCounts.data(), 1, MPI_INT, 0, comm );
447 
448  // Rank 0 sets up the displacement arrays.
449  std::vector< int > cellCountsC( size, 0 ), cellDisplsC( size, 0 );
450  if( rank == 0 )
451  {
452  int accC = 0, accCC = 0, accN = 0;
453  for( int i = 0; i < size; ++i )
454  {
455  cellDispls[i] = accC;
456  accC += cellCounts[i];
457  cellCountsC[i] = cellCounts[i] * ncpc;
458  cellDisplsC[i] = accCC;
459  accCC += cellCountsC[i];
460  nodeDispls[i] = accN;
461  accN += nodeCounts[i];
462  }
463  }
464 
465  long nCellsGlobal = mGlobalCells;
466  long nNodesGlobal = 0;
467  if( rank == 0 ) for( int i = 0; i < size; ++i ) nNodesGlobal += nodeCounts[i];
468 
469  // Per-rank gather targets on rank 0.
470  std::vector< int > allCellGids, allNumNodes, allConnGid, allNodeGids;
471  std::vector< double > allCenterLat, allCenterLon, allNodeLat, allNodeLon;
472  std::vector< double > allAreas;
473  std::vector< int > allMask;
474  if( rank == 0 )
475  {
476  allCellGids.resize( nCellsGlobal );
477  allNumNodes.resize( nCellsGlobal );
478  allConnGid.resize( static_cast< size_t >( nCellsGlobal ) * ncpc );
479  allCenterLat.resize( nCellsGlobal );
480  allCenterLon.resize( nCellsGlobal );
481  allNodeGids.resize( nNodesGlobal );
482  allNodeLat.resize( nNodesGlobal );
483  allNodeLon.resize( nNodesGlobal );
484  if( mHasAreas ) allAreas.resize( nCellsGlobal );
485  if( mHasMask ) allMask.resize( nCellsGlobal );
486  }
487 
488  MPI_Gatherv( mLocalCellGids.data(), myCells, MPI_INT, allCellGids.data(), cellCounts.data(),
489  cellDispls.data(), MPI_INT, 0, comm );
490  MPI_Gatherv( mElementNumNodes.data(), myCells, MPI_INT, allNumNodes.data(), cellCounts.data(),
491  cellDispls.data(), MPI_INT, 0, comm );
492  MPI_Gatherv( mCenterLat.data(), myCells, MPI_DOUBLE, allCenterLat.data(), cellCounts.data(), cellDispls.data(),
493  MPI_DOUBLE, 0, comm );
494  MPI_Gatherv( mCenterLon.data(), myCells, MPI_DOUBLE, allCenterLon.data(), cellCounts.data(), cellDispls.data(),
495  MPI_DOUBLE, 0, comm );
496  MPI_Gatherv( mElementConn.data(), myCells * ncpc, MPI_INT, allConnGid.data(), cellCountsC.data(),
497  cellDisplsC.data(), MPI_INT, 0, comm );
498 
499  MPI_Gatherv( mNodeGids.data(), myNodes, MPI_INT, allNodeGids.data(), nodeCounts.data(), nodeDispls.data(),
500  MPI_INT, 0, comm );
501  MPI_Gatherv( mNodeLat.data(), myNodes, MPI_DOUBLE, allNodeLat.data(), nodeCounts.data(), nodeDispls.data(),
502  MPI_DOUBLE, 0, comm );
503  MPI_Gatherv( mNodeLon.data(), myNodes, MPI_DOUBLE, allNodeLon.data(), nodeCounts.data(), nodeDispls.data(),
504  MPI_DOUBLE, 0, comm );
505 
506  if( mHasAreas )
507  MPI_Gatherv( mAreas.data(), myCells, MPI_DOUBLE, allAreas.data(), cellCounts.data(), cellDispls.data(),
508  MPI_DOUBLE, 0, comm );
509  if( mHasMask )
510  MPI_Gatherv( mMask.data(), myCells, MPI_INT, allMask.data(), cellCounts.data(), cellDispls.data(), MPI_INT,
511  0, comm );
512 
513  ErrorCode rc = MB_SUCCESS;
514  if( rank == 0 )
515  rc = writeAll( allCellGids, allNumNodes, allConnGid, allCenterLat, allCenterLon, allNodeGids, allNodeLat,
516  allNodeLon, allAreas, allMask );
517  int rcInt = static_cast< int >( rc );
518  MPI_Bcast( &rcInt, 1, MPI_INT, 0, comm );
519  if( rcInt != MB_SUCCESS ) MB_SET_ERR( MB_FAILURE, "ESMF write failed on rank 0" );
520 
521  dbgOut.tprintf( 1, " ESMF write: gathered+wrote %ld cells from %d ranks\n", mGlobalCells, size );
522  return MB_SUCCESS;
523  }
524 #endif
525 
527  mNodeLon, mAreas, mMask );
528 }

References moab::NCWriteHelper::_fileId, moab::NCWriteHelper::_writeNC, moab::WriteNC::dbgOut, ErrorCode, moab::WriteNC::isParallel, mAreas, MB_SET_ERR, MB_SUCCESS, mCenterLat, mCenterLon, mCoordDim, mElementConn, mElementNumNodes, mGlobalCells, mHasAreas, mHasMask, mLocalCellGids, mLocalCells, mMask, mMaxCornersGlobal, mNodeGids, mNodeLat, mNodeLon, mVarCenterCoords, mVarElementArea, mVarElementConn, mVarElementMask, mVarNodeCoords, mVarNumElementConn, NCFUNCAP, and moab::DebugOutput::tprintf().

Member Data Documentation

◆ mAreas

std::vector< double > moab::NCWriteESMF::mAreas
private

Definition at line 80 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mCenterLat

std::vector< double > moab::NCWriteESMF::mCenterLat
private

Definition at line 79 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mCenterLon

std::vector< double > moab::NCWriteESMF::mCenterLon
private

Definition at line 78 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mCoordDim

int moab::NCWriteESMF::mCoordDim
private

Definition at line 66 of file NCWriteESMF.hpp.

Referenced by init_file(), and write_values().

◆ mDimCoordDim

int moab::NCWriteESMF::mDimCoordDim
private

Definition at line 86 of file NCWriteESMF.hpp.

Referenced by init_file().

◆ mDimElementCount

int moab::NCWriteESMF::mDimElementCount
private

Definition at line 84 of file NCWriteESMF.hpp.

Referenced by init_file().

◆ mDimMaxNodePElement

int moab::NCWriteESMF::mDimMaxNodePElement
private

Definition at line 85 of file NCWriteESMF.hpp.

Referenced by init_file().

◆ mDimNodeCount

int moab::NCWriteESMF::mDimNodeCount
private

Definition at line 83 of file NCWriteESMF.hpp.

Referenced by init_file().

◆ mElementConn

std::vector< int > moab::NCWriteESMF::mElementConn
private

Definition at line 76 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mElementNumNodes

std::vector< int > moab::NCWriteESMF::mElementNumNodes
private

Definition at line 77 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mGlobalCells

long moab::NCWriteESMF::mGlobalCells
private

Definition at line 63 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), init_file(), and write_values().

◆ mGlobalNodes

long moab::NCWriteESMF::mGlobalNodes
private

Definition at line 64 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and init_file().

◆ mHasAreas

bool moab::NCWriteESMF::mHasAreas
private

Definition at line 67 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), init_file(), and write_values().

◆ mHasMask

bool moab::NCWriteESMF::mHasMask
private

Definition at line 68 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), init_file(), and write_values().

◆ mLocalCellGids

std::vector< int > moab::NCWriteESMF::mLocalCellGids
private

Definition at line 71 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mLocalCells

long moab::NCWriteESMF::mLocalCells
private

Definition at line 62 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mMask

std::vector< int > moab::NCWriteESMF::mMask
private

Definition at line 81 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mMaxCornersGlobal

int moab::NCWriteESMF::mMaxCornersGlobal
private

Definition at line 65 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), init_file(), and write_values().

◆ mNodeGids

std::vector< int > moab::NCWriteESMF::mNodeGids
private

Definition at line 74 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mNodeLat

std::vector< double > moab::NCWriteESMF::mNodeLat
private

Definition at line 73 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mNodeLon

std::vector< double > moab::NCWriteESMF::mNodeLon
private

Definition at line 72 of file NCWriteESMF.hpp.

Referenced by collect_mesh_info(), and write_values().

◆ mVarCenterCoords

int moab::NCWriteESMF::mVarCenterCoords
private

Definition at line 90 of file NCWriteESMF.hpp.

Referenced by init_file(), and write_values().

◆ mVarElementArea

int moab::NCWriteESMF::mVarElementArea
private

Definition at line 91 of file NCWriteESMF.hpp.

Referenced by init_file(), and write_values().

◆ mVarElementConn

int moab::NCWriteESMF::mVarElementConn
private

Definition at line 88 of file NCWriteESMF.hpp.

Referenced by init_file(), and write_values().

◆ mVarElementMask

int moab::NCWriteESMF::mVarElementMask
private

Definition at line 92 of file NCWriteESMF.hpp.

Referenced by init_file(), and write_values().

◆ mVarNodeCoords

int moab::NCWriteESMF::mVarNodeCoords
private

Definition at line 87 of file NCWriteESMF.hpp.

Referenced by init_file(), and write_values().

◆ mVarNumElementConn

int moab::NCWriteESMF::mVarNumElementConn
private

Definition at line 89 of file NCWriteESMF.hpp.

Referenced by init_file(), and write_values().


The documentation for this class was generated from the following files: