Mesh Oriented datABase  (version 5.5.0)
An array-based unstructured mesh library
TempestOnlineMapIO.cpp
Go to the documentation of this file.
1 /*
2  * =====================================================================================
3  *
4  * Filename: TempestOnlineMapIO.cpp
5  *
6  * Description: All I/O implementations related to TempestOnlineMap
7  *
8  * Version: 1.0
9  * Created: 02/06/2021 02:35:41
10  *
11  * Author: Vijay S. Mahadevan (vijaysm), [email protected]
12  * Company: Argonne National Lab
13  *
14  * =====================================================================================
15  */
16 
17 #include "FiniteElementTools.h"
19 #include "moab/TupleList.hpp"
20 
21 #ifdef MOAB_HAVE_NETCDFPAR
22 #include "netcdfcpp_par.hpp"
23 #else
24 #include "netcdfcpp.h"
25 #endif
26 
27 #ifdef MOAB_HAVE_PNETCDF
28 #include <pnetcdf.h>
29 
30 #define ERR_PARNC( err ) \
31  if( err != NC_NOERR ) \
32  { \
33  fprintf( stderr, "Error at line %d: %s\n", __LINE__, ncmpi_strerror( err ) ); \
34  MPI_Abort( MPI_COMM_WORLD, 1 ); \
35  }
36 
37 #endif
38 
39 #ifdef MOAB_HAVE_MPI
40 
41 #define MPI_CHK_ERR( err ) \
42  if( err ) \
43  { \
44  std::cout << "MPI Failure. ErrorCode (" << ( err ) << ") "; \
45  std::cout << "\nMPI Aborting... \n"; \
46  return moab::MB_FAILURE; \
47  }
48 
49 int moab::TempestOnlineMap::rearrange_arrays_by_dofs( const std::vector< unsigned int >& gdofmap,
50  DataArray1D< double >& vecFaceArea,
51  DataArray1D< double >& dCenterLon,
52  DataArray1D< double >& dCenterLat,
53  DataArray2D< double >& dVertexLon,
54  DataArray2D< double >& dVertexLat,
55  std::vector< int >& masks,
56  unsigned& N, // will have the local, after
57  int nv,
58  int& maxdof )
59 {
60  // first decide maxdof, for partitioning
61  unsigned int localmax = 0;
62  for( unsigned i = 0; i < N; i++ )
63  if( gdofmap[i] > localmax ) localmax = gdofmap[i];
64 
65  // decide partitioning based on maxdof/size
66  MPI_Allreduce( &localmax, &maxdof, 1, MPI_INT, MPI_MAX, m_pcomm->comm() );
67  // maxdof is 0 based, so actual number is +1
68  // maxdof
69  int size_per_task = ( maxdof + 1 ) / size; // based on this, processor to process dof x is x/size_per_task
70  // so we decide to reorder by actual dof, such that task 0 has dofs from [0 to size_per_task), etc
71  moab::TupleList tl;
72  unsigned numr = 2 * nv + 3; // doubles: area, centerlon, center lat, nv (vertex lon, vertex lat)
73  tl.initialize( 3, 0, 0, numr, N ); // to proc, dof, then
74  tl.enableWriteAccess();
75  // populate
76  for( unsigned i = 0; i < N; i++ )
77  {
78  int gdof = gdofmap[i];
79  int to_proc = gdof / size_per_task;
80  int mask = masks[i];
81  if( to_proc >= size ) to_proc = size - 1; // the last ones go to last proc
82  int n = tl.get_n();
83  tl.vi_wr[3 * n] = to_proc;
84  tl.vi_wr[3 * n + 1] = gdof;
85  tl.vi_wr[3 * n + 2] = mask;
86  tl.vr_wr[n * numr] = vecFaceArea[i];
87  tl.vr_wr[n * numr + 1] = dCenterLon[i];
88  tl.vr_wr[n * numr + 2] = dCenterLat[i];
89  for( int j = 0; j < nv; j++ )
90  {
91  tl.vr_wr[n * numr + 3 + j] = dVertexLon[i][j];
92  tl.vr_wr[n * numr + 3 + nv + j] = dVertexLat[i][j];
93  }
94  tl.inc_n();
95  }
96 
97  // now do the heavy communication
98  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tl, 0 );
99 
100  // after communication, on each processor we should have tuples coming in
101  // still need to order by global dofs; then rearrange input vectors
102  moab::TupleList::buffer sort_buffer;
103  sort_buffer.buffer_init( tl.get_n() );
104  tl.sort( 1, &sort_buffer );
105  // count how many are unique, and collapse
106  int nb_unique = 1;
107  for( unsigned i = 0; i < tl.get_n() - 1; i++ )
108  {
109  if( tl.vi_wr[3 * i + 1] != tl.vi_wr[3 * i + 4] ) nb_unique++;
110  }
111  vecFaceArea.Allocate( nb_unique );
112  dCenterLon.Allocate( nb_unique );
113  dCenterLat.Allocate( nb_unique );
114  dVertexLon.Allocate( nb_unique, nv );
115  dVertexLat.Allocate( nb_unique, nv );
116  masks.resize( nb_unique );
117  int current_size = 1;
118  vecFaceArea[0] = tl.vr_wr[0];
119  dCenterLon[0] = tl.vr_wr[1];
120  dCenterLat[0] = tl.vr_wr[2];
121  masks[0] = tl.vi_wr[2];
122  for( int j = 0; j < nv; j++ )
123  {
124  dVertexLon[0][j] = tl.vr_wr[3 + j];
125  dVertexLat[0][j] = tl.vr_wr[3 + nv + j];
126  }
127  for( unsigned i = 0; i < tl.get_n() - 1; i++ )
128  {
129  int i1 = i + 1;
130  if( tl.vi_wr[3 * i + 1] != tl.vi_wr[3 * i + 4] )
131  {
132  vecFaceArea[current_size] = tl.vr_wr[i1 * numr];
133  dCenterLon[current_size] = tl.vr_wr[i1 * numr + 1];
134  dCenterLat[current_size] = tl.vr_wr[i1 * numr + 2];
135  for( int j = 0; j < nv; j++ )
136  {
137  dVertexLon[current_size][j] = tl.vr_wr[i1 * numr + 3 + j];
138  dVertexLat[current_size][j] = tl.vr_wr[i1 * numr + 3 + nv + j];
139  }
140  masks[current_size] = tl.vi_wr[3 * i1 + 2];
141  current_size++;
142  }
143  else
144  {
145  vecFaceArea[current_size - 1] += tl.vr_wr[i1 * numr]; // accumulate areas; will come here only for cgll ?
146  }
147  }
148 
149  N = current_size; // or nb_unique, should be the same
150  return 0;
151 }
152 #endif
153 
154 ///////////////////////////////////////////////////////////////////////////////
155 
157  const std::map< std::string, std::string >& attrMap )
158 {
159  moab::ErrorCode rval;
160 
161  size_t lastindex = strFilename.find_last_of( "." );
162  std::string extension = strFilename.substr( lastindex + 1, strFilename.size() );
163 
164  // Write the map file to disk in parallel
165  if( extension == "nc" )
166  {
167  /* Invoke the actual call to write the parallel map to disk in SCRIP format */
168  rval = this->WriteSCRIPMapFile( strFilename.c_str(), attrMap );MB_CHK_ERR( rval );
169  }
170  else
171  {
172  /* Write to the parallel H5M format */
173  rval = this->WriteHDF5MapFile( strFilename.c_str() );MB_CHK_ERR( rval );
174  }
175 
176  return rval;
177 }
178 
179 ///////////////////////////////////////////////////////////////////////////////
180 
182  const std::map< std::string, std::string >& attrMap )
183 {
184  NcError error( NcError::silent_nonfatal );
185 
186 #ifdef MOAB_HAVE_NETCDFPAR
187  bool is_independent = true;
188  ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcFile::Replace, NcFile::Netcdf4 );
189  // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 );
190 #else
191  NcFile ncMap( strFilename.c_str(), NcFile::Replace );
192 #endif
193 
194  if( !ncMap.is_valid() )
195  {
196  _EXCEPTION1( "Unable to open output map file \"%s\"", strFilename.c_str() );
197  }
198 
199  // Attributes
200  // ncMap.add_att( "Title", "MOAB-TempestRemap Online Regridding Weight Generator" );
201  auto it = attrMap.begin();
202  while( it != attrMap.end() )
203  {
204  // set the map attributes
205  ncMap.add_att( it->first.c_str(), it->second.c_str() );
206  // increment iterator
207  it++;
208  }
209 
210  /**
211  * Need to get the global maximum of number of vertices per element
212  * Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for
213  *dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However,
214  *when writing this out, other processes may have a different size for the same array. This is
215  *hence a mess to consolidate in h5mtoscrip eventually.
216  **/
217 
218  /* Let us compute all relevant data for the current original source mesh on the process */
219  DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea;
220  DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat;
221  DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat;
222  if( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD )
223  {
224  this->InitializeCoordinatesFromMeshFV(
225  *m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat,
226  ( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ), /* fLatLon = false */
227  m_remapper->max_source_edges );
228 
229  vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() );
230  for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i )
231  vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i];
232  }
233  else
234  {
235  DataArray3D< double > dataGLLJacobianSrc;
236  this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon,
237  dSourceCenterLat, dSourceVertexLon, dSourceVertexLat );
238 
239  // Generate the continuous Jacobian for input mesh
240  GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc );
241 
242  if( m_srcDiscType == DiscretizationType_CGLL )
243  {
244  GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, vecSourceFaceArea );
245  }
246  else
247  {
248  GenerateDiscontinuousJacobian( dataGLLJacobianSrc, vecSourceFaceArea );
249  }
250  }
251 
252  if( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD )
253  {
254  this->InitializeCoordinatesFromMeshFV(
255  *m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat,
256  ( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ), /* fLatLon = false */
257  m_remapper->max_target_edges );
258 
259  vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() );
260  for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i )
261  {
262  vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i];
263  }
264  }
265  else
266  {
267  DataArray3D< double > dataGLLJacobianDest;
268  this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon,
269  dTargetCenterLat, dTargetVertexLon, dTargetVertexLat );
270 
271  // Generate the continuous Jacobian for input mesh
272  GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest );
273 
274  if( m_destDiscType == DiscretizationType_CGLL )
275  {
276  GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, vecTargetFaceArea );
277  }
278  else
279  {
280  GenerateDiscontinuousJacobian( dataGLLJacobianDest, vecTargetFaceArea );
281  }
282  }
283 
284  // Map dimensions
285  unsigned nA = ( vecSourceFaceArea.GetRows() );
286  unsigned nB = ( vecTargetFaceArea.GetRows() );
287 
288  std::vector< int > masksA, masksB;
289  ErrorCode rval = m_remapper->GetIMasks( moab::Remapper::SourceMesh, masksA );MB_CHK_SET_ERR( rval, "Trouble getting masks for source" );
290  rval = m_remapper->GetIMasks( moab::Remapper::TargetMesh, masksB );MB_CHK_SET_ERR( rval, "Trouble getting masks for target" );
291 
292  // Number of nodes per Face
293  int nSourceNodesPerFace = dSourceVertexLon.GetColumns();
294  int nTargetNodesPerFace = dTargetVertexLon.GetColumns();
295 
296  // if source or target cells have triangles at poles, center of those triangles need to come from
297  // the original quad, not from center in 3d, converted to 2d again
298  // start copy OnlineMap.cpp tempestremap
299  // right now, do this only for source mesh; copy the logic for target mesh
300  for( unsigned i = 0; i < nA; i++ )
301  {
302  const Face& face = m_meshInput->faces[i];
303 
304  int nNodes = face.edges.size();
305  int indexNodeAtPole = -1;
306  if( 3 == nNodes ) // check if one node at the poles
307  {
308  for( int j = 0; j < nNodes; j++ )
309  if( fabs( fabs( dSourceVertexLat[i][j] ) - 90.0 ) < 1.0e-12 )
310  {
311  indexNodeAtPole = j;
312  break;
313  }
314  }
315  if( indexNodeAtPole < 0 ) continue; // continue i loop, do nothing
316  // recompute center of cell, from 3d data; add one 2 nodes at pole, and average
317  int nodeAtPole = face[indexNodeAtPole]; // use the overloaded operator
318  Node nodePole = m_meshInput->nodes[nodeAtPole];
319  Node newCenter = nodePole * 2;
320  for( int j = 1; j < nNodes; j++ )
321  {
322  int indexi = ( indexNodeAtPole + j ) % nNodes; // nNodes is 3 !
323  const Node& node = m_meshInput->nodes[face[indexi]];
324  newCenter = newCenter + node;
325  }
326  newCenter = newCenter * 0.25;
327  newCenter = newCenter.Normalized();
328 
329 #ifdef VERBOSE
330  double iniLon = dSourceCenterLon[i], iniLat = dSourceCenterLat[i];
331 #endif
332  // dSourceCenterLon, dSourceCenterLat
333  XYZtoRLL_Deg( newCenter.x, newCenter.y, newCenter.z, dSourceCenterLon[i], dSourceCenterLat[i] );
334 #ifdef VERBOSE
335  std::cout << " modify center of triangle from " << iniLon << " " << iniLat << " to " << dSourceCenterLon[i]
336  << " " << dSourceCenterLat[i] << "\n";
337 #endif
338  }
339 
340  // first move data if in parallel
341 #if defined( MOAB_HAVE_MPI )
342  int max_row_dof, max_col_dof; // output; arrays will be re-distributed in chunks [maxdof/size]
343  // if (size > 1)
344  {
345  int ierr = rearrange_arrays_by_dofs( srccol_gdofmap, vecSourceFaceArea, dSourceCenterLon, dSourceCenterLat,
346  dSourceVertexLon, dSourceVertexLat, masksA, nA, nSourceNodesPerFace,
347  max_col_dof ); // now nA will be close to maxdof/size
348  if( ierr != 0 )
349  {
350  _EXCEPTION1( "Unable to arrange source data %d ", nA );
351  }
352  // rearrange target data: (nB)
353  //
354  ierr = rearrange_arrays_by_dofs( row_gdofmap, vecTargetFaceArea, dTargetCenterLon, dTargetCenterLat,
355  dTargetVertexLon, dTargetVertexLat, masksB, nB, nTargetNodesPerFace,
356  max_row_dof ); // now nA will be close to maxdof/size
357  if( ierr != 0 )
358  {
359  _EXCEPTION1( "Unable to arrange target data %d ", nB );
360  }
361  }
362 #endif
363 
364  // Number of non-zeros in the remap matrix operator
365  int nS = m_weightMatrix.nonZeros();
366 
367 #if defined( MOAB_HAVE_MPI ) && defined( MOAB_HAVE_NETCDFPAR )
368  int locbuf[5] = { (int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace };
369  int offbuf[3] = { 0, 0, 0 };
370  int globuf[5] = { 0, 0, 0, 0, 0 };
371  MPI_Scan( locbuf, offbuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() );
372  MPI_Allreduce( locbuf, globuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() );
373  MPI_Allreduce( &locbuf[3], &globuf[3], 2, MPI_INT, MPI_MAX, m_pcomm->comm() );
374 
375  // MPI_Scan is inclusive of data in current rank; modify accordingly.
376  offbuf[0] -= nA;
377  offbuf[1] -= nB;
378  offbuf[2] -= nS;
379 
380 #else
381  int offbuf[3] = { 0, 0, 0 };
382  int globuf[5] = { (int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace };
383 #endif
384 
385  std::vector< std::string > srcdimNames, tgtdimNames;
386  std::vector< int > srcdimSizes, tgtdimSizes;
387  {
388  if( m_remapper->m_source_type == moab::TempestRemapper::RLL && m_remapper->m_source_metadata.size() )
389  {
390  srcdimNames.push_back( "lat" );
391  srcdimNames.push_back( "lon" );
392  srcdimSizes.resize( 2, 0 );
393  srcdimSizes[0] = m_remapper->m_source_metadata[0];
394  srcdimSizes[1] = m_remapper->m_source_metadata[1];
395  }
396  else
397  {
398  srcdimNames.push_back( "num_elem" );
399  srcdimSizes.push_back( globuf[0] );
400  }
401 
402  if( m_remapper->m_target_type == moab::TempestRemapper::RLL && m_remapper->m_target_metadata.size() )
403  {
404  tgtdimNames.push_back( "lat" );
405  tgtdimNames.push_back( "lon" );
406  tgtdimSizes.resize( 2, 0 );
407  tgtdimSizes[0] = m_remapper->m_target_metadata[0];
408  tgtdimSizes[1] = m_remapper->m_target_metadata[1];
409  }
410  else
411  {
412  tgtdimNames.push_back( "num_elem" );
413  tgtdimSizes.push_back( globuf[1] );
414  }
415  }
416 
417  // Write output dimensions entries
418  unsigned nSrcGridDims = ( srcdimSizes.size() );
419  unsigned nDstGridDims = ( tgtdimSizes.size() );
420 
421  NcDim* dimSrcGridRank = ncMap.add_dim( "src_grid_rank", nSrcGridDims );
422  NcDim* dimDstGridRank = ncMap.add_dim( "dst_grid_rank", nDstGridDims );
423 
424  NcVar* varSrcGridDims = ncMap.add_var( "src_grid_dims", ncInt, dimSrcGridRank );
425  NcVar* varDstGridDims = ncMap.add_var( "dst_grid_dims", ncInt, dimDstGridRank );
426 
427 #ifdef MOAB_HAVE_NETCDFPAR
428  ncMap.enable_var_par_access( varSrcGridDims, is_independent );
429  ncMap.enable_var_par_access( varDstGridDims, is_independent );
430 #endif
431 
432  // write dimension names
433  {
434  char szDim[64];
435  for( unsigned i = 0; i < srcdimSizes.size(); i++ )
436  {
437  varSrcGridDims->set_cur( nSrcGridDims - i - 1 );
438  varSrcGridDims->put( &( srcdimSizes[nSrcGridDims - i - 1] ), 1 );
439  }
440 
441  for( unsigned i = 0; i < srcdimSizes.size(); i++ )
442  {
443  snprintf( szDim, 64, "name%i", i );
444  varSrcGridDims->add_att( szDim, srcdimNames[nSrcGridDims - i - 1].c_str() );
445  }
446 
447  for( unsigned i = 0; i < tgtdimSizes.size(); i++ )
448  {
449  varDstGridDims->set_cur( nDstGridDims - i - 1 );
450  varDstGridDims->put( &( tgtdimSizes[nDstGridDims - i - 1] ), 1 );
451  }
452 
453  for( unsigned i = 0; i < tgtdimSizes.size(); i++ )
454  {
455  snprintf( szDim, 64, "name%i", i );
456  varDstGridDims->add_att( szDim, tgtdimNames[nDstGridDims - i - 1].c_str() );
457  }
458  }
459 
460  // Source and Target mesh resolutions
461  NcDim* dimNA = ncMap.add_dim( "n_a", globuf[0] );
462  NcDim* dimNB = ncMap.add_dim( "n_b", globuf[1] );
463 
464  // Number of nodes per Face
465  NcDim* dimNVA = ncMap.add_dim( "nv_a", globuf[3] );
466  NcDim* dimNVB = ncMap.add_dim( "nv_b", globuf[4] );
467 
468  // Write coordinates
469  NcVar* varYCA = ncMap.add_var( "yc_a", ncDouble, dimNA );
470  NcVar* varYCB = ncMap.add_var( "yc_b", ncDouble, dimNB );
471 
472  NcVar* varXCA = ncMap.add_var( "xc_a", ncDouble, dimNA );
473  NcVar* varXCB = ncMap.add_var( "xc_b", ncDouble, dimNB );
474 
475  NcVar* varYVA = ncMap.add_var( "yv_a", ncDouble, dimNA, dimNVA );
476  NcVar* varYVB = ncMap.add_var( "yv_b", ncDouble, dimNB, dimNVB );
477 
478  NcVar* varXVA = ncMap.add_var( "xv_a", ncDouble, dimNA, dimNVA );
479  NcVar* varXVB = ncMap.add_var( "xv_b", ncDouble, dimNB, dimNVB );
480 
481  // Write masks
482  NcVar* varMaskA = ncMap.add_var( "mask_a", ncInt, dimNA );
483  NcVar* varMaskB = ncMap.add_var( "mask_b", ncInt, dimNB );
484 
485 #ifdef MOAB_HAVE_NETCDFPAR
486  ncMap.enable_var_par_access( varYCA, is_independent );
487  ncMap.enable_var_par_access( varYCB, is_independent );
488  ncMap.enable_var_par_access( varXCA, is_independent );
489  ncMap.enable_var_par_access( varXCB, is_independent );
490  ncMap.enable_var_par_access( varYVA, is_independent );
491  ncMap.enable_var_par_access( varYVB, is_independent );
492  ncMap.enable_var_par_access( varXVA, is_independent );
493  ncMap.enable_var_par_access( varXVB, is_independent );
494  ncMap.enable_var_par_access( varMaskA, is_independent );
495  ncMap.enable_var_par_access( varMaskB, is_independent );
496 #endif
497 
498  varYCA->add_att( "units", "degrees" );
499  varYCB->add_att( "units", "degrees" );
500 
501  varXCA->add_att( "units", "degrees" );
502  varXCB->add_att( "units", "degrees" );
503 
504  varYVA->add_att( "units", "degrees" );
505  varYVB->add_att( "units", "degrees" );
506 
507  varXVA->add_att( "units", "degrees" );
508  varXVB->add_att( "units", "degrees" );
509 
510  // Verify dimensionality
511  if( dSourceCenterLon.GetRows() != nA )
512  {
513  _EXCEPTIONT( "Mismatch between dSourceCenterLon and nA" );
514  }
515  if( dSourceCenterLat.GetRows() != nA )
516  {
517  _EXCEPTIONT( "Mismatch between dSourceCenterLat and nA" );
518  }
519  if( dTargetCenterLon.GetRows() != nB )
520  {
521  _EXCEPTIONT( "Mismatch between dTargetCenterLon and nB" );
522  }
523  if( dTargetCenterLat.GetRows() != nB )
524  {
525  _EXCEPTIONT( "Mismatch between dTargetCenterLat and nB" );
526  }
527  if( dSourceVertexLon.GetRows() != nA )
528  {
529  _EXCEPTIONT( "Mismatch between dSourceVertexLon and nA" );
530  }
531  if( dSourceVertexLat.GetRows() != nA )
532  {
533  _EXCEPTIONT( "Mismatch between dSourceVertexLat and nA" );
534  }
535  if( dTargetVertexLon.GetRows() != nB )
536  {
537  _EXCEPTIONT( "Mismatch between dTargetVertexLon and nB" );
538  }
539  if( dTargetVertexLat.GetRows() != nB )
540  {
541  _EXCEPTIONT( "Mismatch between dTargetVertexLat and nB" );
542  }
543 
544  varYCA->set_cur( (long)offbuf[0] );
545  varYCA->put( &( dSourceCenterLat[0] ), nA );
546  varYCB->set_cur( (long)offbuf[1] );
547  varYCB->put( &( dTargetCenterLat[0] ), nB );
548 
549  varXCA->set_cur( (long)offbuf[0] );
550  varXCA->put( &( dSourceCenterLon[0] ), nA );
551  varXCB->set_cur( (long)offbuf[1] );
552  varXCB->put( &( dTargetCenterLon[0] ), nB );
553 
554  varYVA->set_cur( (long)offbuf[0] );
555  varYVA->put( &( dSourceVertexLat[0][0] ), nA, nSourceNodesPerFace );
556  varYVB->set_cur( (long)offbuf[1] );
557  varYVB->put( &( dTargetVertexLat[0][0] ), nB, nTargetNodesPerFace );
558 
559  varXVA->set_cur( (long)offbuf[0] );
560  varXVA->put( &( dSourceVertexLon[0][0] ), nA, nSourceNodesPerFace );
561  varXVB->set_cur( (long)offbuf[1] );
562  varXVB->put( &( dTargetVertexLon[0][0] ), nB, nTargetNodesPerFace );
563 
564  varMaskA->set_cur( (long)offbuf[0] );
565  varMaskA->put( &( masksA[0] ), nA );
566  varMaskB->set_cur( (long)offbuf[1] );
567  varMaskB->put( &( masksB[0] ), nB );
568 
569  // Write areas
570  NcVar* varAreaA = ncMap.add_var( "area_a", ncDouble, dimNA );
571 #ifdef MOAB_HAVE_NETCDFPAR
572  ncMap.enable_var_par_access( varAreaA, is_independent );
573 #endif
574  varAreaA->set_cur( (long)offbuf[0] );
575  varAreaA->put( &( vecSourceFaceArea[0] ), nA );
576 
577  NcVar* varAreaB = ncMap.add_var( "area_b", ncDouble, dimNB );
578 #ifdef MOAB_HAVE_NETCDFPAR
579  ncMap.enable_var_par_access( varAreaB, is_independent );
580 #endif
581  varAreaB->set_cur( (long)offbuf[1] );
582  varAreaB->put( &( vecTargetFaceArea[0] ), nB );
583 
584  // Write SparseMatrix entries
585  DataArray1D< int > vecRow( nS );
586  DataArray1D< int > vecCol( nS );
587  DataArray1D< double > vecS( nS );
588  DataArray1D< double > dFracA( nA );
589  DataArray1D< double > dFracB( nB );
590 
591  moab::TupleList tlValRow, tlValCol;
592  unsigned numr = 1; //
593  // value has to be sent to processor row/nB for for fracA and col/nA for fracB
594  // vecTargetArea (indexRow ) has to be sent for fracA (index col?)
595  // vecTargetFaceArea will have to be sent to col index, with its index !
596  tlValRow.initialize( 2, 0, 0, numr, nS ); // to proc(row), global row , value
597  tlValCol.initialize( 3, 0, 0, numr, nS ); // to proc(col), global row / col, value
598  tlValRow.enableWriteAccess();
599  tlValCol.enableWriteAccess();
600  /*
601  *
602  dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
603  dFracB[ row ] += val ;
604  */
605  int offset = 0;
606 #if defined( MOAB_HAVE_MPI )
607  int nAbase = ( max_col_dof + 1 ) / size; // it is nA, except last rank ( == size - 1 )
608  int nBbase = ( max_row_dof + 1 ) / size; // it is nB, except last rank ( == size - 1 )
609 #endif
610  for( int i = 0; i < m_weightMatrix.outerSize(); ++i )
611  {
612  for( WeightMatrix::InnerIterator it( m_weightMatrix, i ); it; ++it )
613  {
614  vecRow[offset] = 1 + this->GetRowGlobalDoF( it.row() ); // row index
615  vecCol[offset] = 1 + this->GetColGlobalDoF( it.col() ); // col index
616  vecS[offset] = it.value(); // value
617 
618 #if defined( MOAB_HAVE_MPI )
619  {
620  // value M(row, col) will contribute to procRow and procCol values for fracA and fracB
621  int procRow = ( vecRow[offset] - 1 ) / nBbase;
622  if( procRow >= size ) procRow = size - 1;
623  int procCol = ( vecCol[offset] - 1 ) / nAbase;
624  if( procCol >= size ) procCol = size - 1;
625  int nrInd = tlValRow.get_n();
626  tlValRow.vi_wr[2 * nrInd] = procRow;
627  tlValRow.vi_wr[2 * nrInd + 1] = vecRow[offset] - 1;
628  tlValRow.vr_wr[nrInd] = vecS[offset];
629  tlValRow.inc_n();
630  int ncInd = tlValCol.get_n();
631  tlValCol.vi_wr[3 * ncInd] = procCol;
632  tlValCol.vi_wr[3 * ncInd + 1] = vecRow[offset] - 1;
633  tlValCol.vi_wr[3 * ncInd + 2] = vecCol[offset] - 1; // this is column
634  tlValCol.vr_wr[ncInd] = vecS[offset];
635  tlValCol.inc_n();
636  }
637 
638 #endif
639  offset++;
640  }
641  }
642 #if defined( MOAB_HAVE_MPI )
643  // need to send values for their row and col processors, to compute fractions there
644  // now do the heavy communication
645  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValCol, 0 );
646  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValRow, 0 );
647 
648  // we have now, for example, dFracB[ row ] += val ;
649  // so we know that on current task, we received tlValRow
650  // reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
651  // dFracB[ row ] += val ;
652  for( unsigned i = 0; i < tlValRow.get_n(); i++ )
653  {
654  // int fromProc = tlValRow.vi_wr[2 * i];
655  int gRowInd = tlValRow.vi_wr[2 * i + 1];
656  int localIndexRow = gRowInd - nBbase * rank; // modulo nBbase rank is from 0 to size - 1;
657  double wgt = tlValRow.vr_wr[i];
658  assert( localIndexRow >= 0 );
659  assert( nB - localIndexRow > 0 );
660  dFracB[localIndexRow] += wgt;
661  }
662  // to compute dFracA we need vecTargetFaceArea[ row ]; we know the row, and we can get the proc we need it from
663 
664  std::set< int > neededRows;
665  for( unsigned i = 0; i < tlValCol.get_n(); i++ )
666  {
667  int rRowInd = tlValCol.vi_wr[3 * i + 1];
668  neededRows.insert( rRowInd );
669  // we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow
670  }
671  moab::TupleList tgtAreaReq;
672  tgtAreaReq.initialize( 2, 0, 0, 0, neededRows.size() );
673  tgtAreaReq.enableWriteAccess();
674  for( std::set< int >::iterator sit = neededRows.begin(); sit != neededRows.end(); sit++ )
675  {
676  int neededRow = *sit;
677  int procRow = neededRow / nBbase;
678  if( procRow >= size ) procRow = size - 1;
679  int nr = tgtAreaReq.get_n();
680  tgtAreaReq.vi_wr[2 * nr] = procRow;
681  tgtAreaReq.vi_wr[2 * nr + 1] = neededRow;
682  tgtAreaReq.inc_n();
683  }
684 
685  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaReq, 0 );
686  // we need to send back the tgtArea corresponding to row
687  moab::TupleList tgtAreaInfo; // load it with tgtArea at row
688  tgtAreaInfo.initialize( 2, 0, 0, 1, tgtAreaReq.get_n() );
689  tgtAreaInfo.enableWriteAccess();
690  for( unsigned i = 0; i < tgtAreaReq.get_n(); i++ )
691  {
692  int from_proc = tgtAreaReq.vi_wr[2 * i];
693  int row = tgtAreaReq.vi_wr[2 * i + 1];
694  int locaIndexRow = row - rank * nBbase;
695  double areaToSend = vecTargetFaceArea[locaIndexRow];
696  // int remoteIndex = tgtAreaReq.vi_wr[3*i + 2] ;
697 
698  tgtAreaInfo.vi_wr[2 * i] = from_proc; // send back requested info
699  tgtAreaInfo.vi_wr[2 * i + 1] = row;
700  tgtAreaInfo.vr_wr[i] = areaToSend; // this will be tgt area at row
701  tgtAreaInfo.inc_n();
702  }
703  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaInfo, 0 );
704 
705  std::map< int, double > areaAtRow;
706  for( unsigned i = 0; i < tgtAreaInfo.get_n(); i++ )
707  {
708  // we have received from proc, value for row !
709  int row = tgtAreaInfo.vi_wr[2 * i + 1];
710  areaAtRow[row] = tgtAreaInfo.vr_wr[i];
711  }
712 
713  // we have now for rows the
714  // it is ordered by index, so:
715  // now compute reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
716  // tgtAreaInfo will have at index i the area we need (from row)
717  // there should be an easier way :(
718  for( unsigned i = 0; i < tlValCol.get_n(); i++ )
719  {
720  int rRowInd = tlValCol.vi_wr[3 * i + 1];
721  int colInd = tlValCol.vi_wr[3 * i + 2];
722  double val = tlValCol.vr_wr[i];
723  int localColInd = colInd - rank * nAbase; // < local nA
724  // we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow
725  auto itMap = areaAtRow.find( rRowInd ); // it should be different from end
726  if( itMap != areaAtRow.end() )
727  {
728  double areaRow = itMap->second; // we fished a lot for this !
729  dFracA[localColInd] += val / vecSourceFaceArea[localColInd] * areaRow;
730  }
731  }
732 
733 #endif
734  // Load in data
735  NcDim* dimNS = ncMap.add_dim( "n_s", globuf[2] );
736 
737  NcVar* varRow = ncMap.add_var( "row", ncInt, dimNS );
738  NcVar* varCol = ncMap.add_var( "col", ncInt, dimNS );
739  NcVar* varS = ncMap.add_var( "S", ncDouble, dimNS );
740 #ifdef MOAB_HAVE_NETCDFPAR
741  ncMap.enable_var_par_access( varRow, is_independent );
742  ncMap.enable_var_par_access( varCol, is_independent );
743  ncMap.enable_var_par_access( varS, is_independent );
744 #endif
745 
746  varRow->set_cur( (long)offbuf[2] );
747  varRow->put( vecRow, nS );
748 
749  varCol->set_cur( (long)offbuf[2] );
750  varCol->put( vecCol, nS );
751 
752  varS->set_cur( (long)offbuf[2] );
753  varS->put( &( vecS[0] ), nS );
754 
755  // Calculate and write fractional coverage arrays
756  NcVar* varFracA = ncMap.add_var( "frac_a", ncDouble, dimNA );
757 #ifdef MOAB_HAVE_NETCDFPAR
758  ncMap.enable_var_par_access( varFracA, is_independent );
759 #endif
760  varFracA->add_att( "name", "fraction of target coverage of source dof" );
761  varFracA->add_att( "units", "unitless" );
762  varFracA->set_cur( (long)offbuf[0] );
763  varFracA->put( &( dFracA[0] ), nA );
764 
765  NcVar* varFracB = ncMap.add_var( "frac_b", ncDouble, dimNB );
766 #ifdef MOAB_HAVE_NETCDFPAR
767  ncMap.enable_var_par_access( varFracB, is_independent );
768 #endif
769  varFracB->add_att( "name", "fraction of source coverage of target dof" );
770  varFracB->add_att( "units", "unitless" );
771  varFracB->set_cur( (long)offbuf[1] );
772  varFracB->put( &( dFracB[0] ), nB );
773 
774  // Add global attributes
775  // std::map<std::string, std::string>::const_iterator iterAttributes =
776  // mapAttributes.begin();
777  // for (; iterAttributes != mapAttributes.end(); iterAttributes++) {
778  // ncMap.add_att(
779  // iterAttributes->first.c_str(),
780  // iterAttributes->second.c_str());
781  // }
782 
783  ncMap.close();
784 
785  return moab::MB_SUCCESS;
786 }
787 
788 ///////////////////////////////////////////////////////////////////////////////
789 
791 {
792  moab::ErrorCode rval;
793 
794  /**
795  * Need to get the global maximum of number of vertices per element
796  * Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for
797  *dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However,
798  *when writing this out, other processes may have a different size for the same array. This is
799  *hence a mess to consolidate in h5mtoscrip eventually.
800  **/
801 
802  /* Let us compute all relevant data for the current original source mesh on the process */
803  DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea;
804  DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat;
805  DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat;
806  if( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD )
807  {
808  this->InitializeCoordinatesFromMeshFV(
809  *m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat,
810  ( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ) /* fLatLon = false */,
811  m_remapper->max_source_edges );
812 
813  vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() );
814  for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i )
815  vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i];
816  }
817  else
818  {
819  DataArray3D< double > dataGLLJacobianSrc;
820  this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon,
821  dSourceCenterLat, dSourceVertexLon, dSourceVertexLat );
822 
823  // Generate the continuous Jacobian for input mesh
824  GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc );
825 
826  if( m_srcDiscType == DiscretizationType_CGLL )
827  {
828  GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, m_meshInput->vecFaceArea );
829  }
830  else
831  {
832  GenerateDiscontinuousJacobian( dataGLLJacobianSrc, m_meshInput->vecFaceArea );
833  }
834 
835  vecSourceFaceArea.Allocate( m_meshInput->faces.size() * m_nDofsPEl_Src * m_nDofsPEl_Src );
836  int offset = 0;
837  for( size_t e = 0; e < m_meshInput->faces.size(); e++ )
838  {
839  for( int s = 0; s < m_nDofsPEl_Src; s++ )
840  {
841  for( int t = 0; t < m_nDofsPEl_Src; t++ )
842  {
843  vecSourceFaceArea[srccol_dtoc_dofmap[offset + s * m_nDofsPEl_Src + t]] =
844  dataGLLJacobianSrc[s][t][e];
845  }
846  }
847  offset += m_nDofsPEl_Src * m_nDofsPEl_Src;
848  }
849  }
850 
851  if( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD )
852  {
853  this->InitializeCoordinatesFromMeshFV(
854  *m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat,
855  ( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ) /* fLatLon = false */,
856  m_remapper->max_target_edges );
857 
858  vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() );
859  for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i )
860  vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i];
861  }
862  else
863  {
864  DataArray3D< double > dataGLLJacobianDest;
865  this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon,
866  dTargetCenterLat, dTargetVertexLon, dTargetVertexLat );
867 
868  // Generate the continuous Jacobian for input mesh
869  GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest );
870 
871  if( m_destDiscType == DiscretizationType_CGLL )
872  {
873  GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, m_meshOutput->vecFaceArea );
874  }
875  else
876  {
877  GenerateDiscontinuousJacobian( dataGLLJacobianDest, m_meshOutput->vecFaceArea );
878  }
879 
880  vecTargetFaceArea.Allocate( m_meshOutput->faces.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest );
881  int offset = 0;
882  for( size_t e = 0; e < m_meshOutput->faces.size(); e++ )
883  {
884  for( int s = 0; s < m_nDofsPEl_Dest; s++ )
885  {
886  for( int t = 0; t < m_nDofsPEl_Dest; t++ )
887  {
888  vecTargetFaceArea[row_dtoc_dofmap[offset + s * m_nDofsPEl_Dest + t]] = dataGLLJacobianDest[s][t][e];
889  }
890  }
891  offset += m_nDofsPEl_Dest * m_nDofsPEl_Dest;
892  }
893  }
894 
895  moab::EntityHandle& m_meshOverlapSet = m_remapper->m_overlap_set;
896  int tot_src_ents = m_remapper->m_source_entities.size();
897  int tot_tgt_ents = m_remapper->m_target_entities.size();
898  int tot_src_size = dSourceCenterLon.GetRows();
899  int tot_tgt_size = m_dTargetCenterLon.GetRows();
900  int tot_vsrc_size = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns();
901  int tot_vtgt_size = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns();
902 
903  const int weightMatNNZ = m_weightMatrix.nonZeros();
904  moab::Tag tagMapMetaData, tagMapIndexRow, tagMapIndexCol, tagMapValues, srcEleIDs, tgtEleIDs;
905  rval = m_interface->tag_get_handle( "SMAT_DATA", 13, moab::MB_TYPE_INTEGER, tagMapMetaData,
906  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
907  rval = m_interface->tag_get_handle( "SMAT_ROWS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexRow,
908  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
909  rval = m_interface->tag_get_handle( "SMAT_COLS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexCol,
910  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
911  rval = m_interface->tag_get_handle( "SMAT_VALS", weightMatNNZ, moab::MB_TYPE_DOUBLE, tagMapValues,
912  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
913  rval = m_interface->tag_get_handle( "SourceGIDS", tot_src_size, moab::MB_TYPE_INTEGER, srcEleIDs,
914  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
915  rval = m_interface->tag_get_handle( "TargetGIDS", tot_tgt_size, moab::MB_TYPE_INTEGER, tgtEleIDs,
916  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
917  moab::Tag srcAreaValues, tgtAreaValues;
918  rval = m_interface->tag_get_handle( "SourceAreas", tot_src_size, moab::MB_TYPE_DOUBLE, srcAreaValues,
919  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
920  rval = m_interface->tag_get_handle( "TargetAreas", tot_tgt_size, moab::MB_TYPE_DOUBLE, tgtAreaValues,
921  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
922  moab::Tag tagSrcCoordsCLon, tagSrcCoordsCLat, tagTgtCoordsCLon, tagTgtCoordsCLat;
923  rval = m_interface->tag_get_handle( "SourceCoordCenterLon", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLon,
924  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
925  rval = m_interface->tag_get_handle( "SourceCoordCenterLat", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLat,
926  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
927  rval = m_interface->tag_get_handle( "TargetCoordCenterLon", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLon,
928  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
929  rval = m_interface->tag_get_handle( "TargetCoordCenterLat", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLat,
930  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
931  moab::Tag tagSrcCoordsVLon, tagSrcCoordsVLat, tagTgtCoordsVLon, tagTgtCoordsVLat;
932  rval = m_interface->tag_get_handle( "SourceCoordVertexLon", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLon,
933  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
934  rval = m_interface->tag_get_handle( "SourceCoordVertexLat", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLat,
935  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
936  rval = m_interface->tag_get_handle( "TargetCoordVertexLon", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLon,
937  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
938  rval = m_interface->tag_get_handle( "TargetCoordVertexLat", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLat,
939  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
940  moab::Tag srcMaskValues, tgtMaskValues;
941  if( m_iSourceMask.IsAttached() )
942  {
943  rval = m_interface->tag_get_handle( "SourceMask", m_iSourceMask.GetRows(), moab::MB_TYPE_INTEGER, srcMaskValues,
944  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
945  }
946  if( m_iTargetMask.IsAttached() )
947  {
948  rval = m_interface->tag_get_handle( "TargetMask", m_iTargetMask.GetRows(), moab::MB_TYPE_INTEGER, tgtMaskValues,
949  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
950  }
951 
952  std::vector< int > smatrowvals( weightMatNNZ ), smatcolvals( weightMatNNZ );
953  std::vector< double > smatvals( weightMatNNZ );
954  // const double* smatvals = m_weightMatrix.valuePtr();
955  // Loop over the matrix entries and find the max global ID for rows and columns
956  for( int k = 0, offset = 0; k < m_weightMatrix.outerSize(); ++k )
957  {
958  for( moab::TempestOnlineMap::WeightMatrix::InnerIterator it( m_weightMatrix, k ); it; ++it, ++offset )
959  {
960  smatrowvals[offset] = this->GetRowGlobalDoF( it.row() );
961  smatcolvals[offset] = this->GetColGlobalDoF( it.col() );
962  smatvals[offset] = it.value();
963  }
964  }
965 
966  /* Set the global IDs for the DoFs */
967  ////
968  // col_gdofmap [ col_ldofmap [ 0 : local_ndofs ] ] = GDOF
969  // row_gdofmap [ row_ldofmap [ 0 : local_ndofs ] ] = GDOF
970  ////
971  int maxrow = 0, maxcol = 0;
972  std::vector< int > src_global_dofs( tot_src_size ), tgt_global_dofs( tot_tgt_size );
973  for( int i = 0; i < tot_src_size; ++i )
974  {
975  src_global_dofs[i] = srccol_gdofmap[i];
976  maxcol = ( src_global_dofs[i] > maxcol ) ? src_global_dofs[i] : maxcol;
977  }
978 
979  for( int i = 0; i < tot_tgt_size; ++i )
980  {
981  tgt_global_dofs[i] = row_gdofmap[i];
982  maxrow = ( tgt_global_dofs[i] > maxrow ) ? tgt_global_dofs[i] : maxrow;
983  }
984 
985  ///////////////////////////////////////////////////////////////////////////
986  // The metadata in H5M file contains the following data:
987  //
988  // 1. n_a: Total source entities: (number of elements in source mesh)
989  // 2. n_b: Total target entities: (number of elements in target mesh)
990  // 3. nv_a: Max edge size of elements in source mesh
991  // 4. nv_b: Max edge size of elements in target mesh
992  // 5. maxrows: Number of rows in remap weight matrix
993  // 6. maxcols: Number of cols in remap weight matrix
994  // 7. nnz: Number of total nnz in sparse remap weight matrix
995  // 8. np_a: The order of the field description on the source mesh: >= 1
996  // 9. np_b: The order of the field description on the target mesh: >= 1
997  // 10. method_a: The type of discretization for field on source mesh: [0 = FV, 1 = cGLL, 2 =
998  // dGLL]
999  // 11. method_b: The type of discretization for field on target mesh: [0 = FV, 1 = cGLL, 2 =
1000  // dGLL]
1001  // 12. conserved: Flag to specify whether the remap operator has conservation constraints: [0,
1002  // 1]
1003  // 13. monotonicity: Flags to specify whether the remap operator has monotonicity constraints:
1004  // [0, 1, 2]
1005  //
1006  ///////////////////////////////////////////////////////////////////////////
1007  int map_disc_details[6];
1008  map_disc_details[0] = m_nDofsPEl_Src;
1009  map_disc_details[1] = m_nDofsPEl_Dest;
1010  map_disc_details[2] = ( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD
1011  ? 0
1012  : ( m_srcDiscType == DiscretizationType_CGLL ? 1 : 2 ) );
1013  map_disc_details[3] = ( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD
1014  ? 0
1015  : ( m_destDiscType == DiscretizationType_CGLL ? 1 : 2 ) );
1016  map_disc_details[4] = ( m_bConserved ? 1 : 0 );
1017  map_disc_details[5] = m_iMonotonicity;
1018 
1019 #ifdef MOAB_HAVE_MPI
1020  int loc_smatmetadata[13] = { tot_src_ents,
1021  tot_tgt_ents,
1022  m_remapper->max_source_edges,
1023  m_remapper->max_target_edges,
1024  maxrow + 1,
1025  maxcol + 1,
1026  weightMatNNZ,
1027  map_disc_details[0],
1028  map_disc_details[1],
1029  map_disc_details[2],
1030  map_disc_details[3],
1031  map_disc_details[4],
1032  map_disc_details[5] };
1033  rval = m_interface->tag_set_data( tagMapMetaData, &m_meshOverlapSet, 1, &loc_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1034  int glb_smatmetadata[13] = { 0,
1035  0,
1036  0,
1037  0,
1038  0,
1039  0,
1040  0,
1041  map_disc_details[0],
1042  map_disc_details[1],
1043  map_disc_details[2],
1044  map_disc_details[3],
1045  map_disc_details[4],
1046  map_disc_details[5] };
1047  int loc_buf[7] = {
1048  tot_src_ents, tot_tgt_ents, weightMatNNZ, m_remapper->max_source_edges, m_remapper->max_target_edges,
1049  maxrow, maxcol };
1050  int glb_buf[4] = { 0, 0, 0, 0 };
1051  MPI_Reduce( &loc_buf[0], &glb_buf[0], 3, MPI_INT, MPI_SUM, 0, m_pcomm->comm() );
1052  glb_smatmetadata[0] = glb_buf[0];
1053  glb_smatmetadata[1] = glb_buf[1];
1054  glb_smatmetadata[6] = glb_buf[2];
1055  MPI_Reduce( &loc_buf[3], &glb_buf[0], 4, MPI_INT, MPI_MAX, 0, m_pcomm->comm() );
1056  glb_smatmetadata[2] = glb_buf[0];
1057  glb_smatmetadata[3] = glb_buf[1];
1058  glb_smatmetadata[4] = glb_buf[2];
1059  glb_smatmetadata[5] = glb_buf[3];
1060 #else
1061  int glb_smatmetadata[13] = { tot_src_ents,
1062  tot_tgt_ents,
1063  m_remapper->max_source_edges,
1064  m_remapper->max_target_edges,
1065  maxrow,
1066  maxcol,
1067  weightMatNNZ,
1068  map_disc_details[0],
1069  map_disc_details[1],
1070  map_disc_details[2],
1071  map_disc_details[3],
1072  map_disc_details[4],
1073  map_disc_details[5] };
1074 #endif
1075  // These values represent number of rows and columns. So should be 1-based.
1076  glb_smatmetadata[4]++;
1077  glb_smatmetadata[5]++;
1078 
1079  if( this->is_root )
1080  {
1081  std::cout << " " << this->rank << " Writing remap weights with size [" << glb_smatmetadata[4] << " X "
1082  << glb_smatmetadata[5] << "] and NNZ = " << glb_smatmetadata[6] << std::endl;
1083  EntityHandle root_set = 0;
1084  rval = m_interface->tag_set_data( tagMapMetaData, &root_set, 1, &glb_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1085  }
1086 
1087  int dsize;
1088  const int numval = weightMatNNZ;
1089  const void* smatrowvals_d = smatrowvals.data();
1090  const void* smatcolvals_d = smatcolvals.data();
1091  const void* smatvals_d = smatvals.data();
1092  rval = m_interface->tag_set_by_ptr( tagMapIndexRow, &m_meshOverlapSet, 1, &smatrowvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1093  rval = m_interface->tag_set_by_ptr( tagMapIndexCol, &m_meshOverlapSet, 1, &smatcolvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1094  rval = m_interface->tag_set_by_ptr( tagMapValues, &m_meshOverlapSet, 1, &smatvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1095 
1096  /* Set the global IDs for the DoFs */
1097  const void* srceleidvals_d = src_global_dofs.data();
1098  const void* tgteleidvals_d = tgt_global_dofs.data();
1099  dsize = src_global_dofs.size();
1100  rval = m_interface->tag_set_by_ptr( srcEleIDs, &m_meshOverlapSet, 1, &srceleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1101  dsize = tgt_global_dofs.size();
1102  rval = m_interface->tag_set_by_ptr( tgtEleIDs, &m_meshOverlapSet, 1, &tgteleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1103 
1104  /* Set the source and target areas */
1105  const void* srcareavals_d = vecSourceFaceArea;
1106  const void* tgtareavals_d = vecTargetFaceArea;
1107  dsize = tot_src_size;
1108  rval = m_interface->tag_set_by_ptr( srcAreaValues, &m_meshOverlapSet, 1, &srcareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1109  dsize = tot_tgt_size;
1110  rval = m_interface->tag_set_by_ptr( tgtAreaValues, &m_meshOverlapSet, 1, &tgtareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1111 
1112  /* Set the coordinates for source and target center vertices */
1113  const void* srccoordsclonvals_d = &dSourceCenterLon[0];
1114  const void* srccoordsclatvals_d = &dSourceCenterLat[0];
1115  dsize = dSourceCenterLon.GetRows();
1116  rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLon, &m_meshOverlapSet, 1, &srccoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1117  rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLat, &m_meshOverlapSet, 1, &srccoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1118  const void* tgtcoordsclonvals_d = &m_dTargetCenterLon[0];
1119  const void* tgtcoordsclatvals_d = &m_dTargetCenterLat[0];
1120  dsize = vecTargetFaceArea.GetRows();
1121  rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLon, &m_meshOverlapSet, 1, &tgtcoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1122  rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLat, &m_meshOverlapSet, 1, &tgtcoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1123 
1124  /* Set the coordinates for source and target element vertices */
1125  const void* srccoordsvlonvals_d = &( dSourceVertexLon[0][0] );
1126  const void* srccoordsvlatvals_d = &( dSourceVertexLat[0][0] );
1127  dsize = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns();
1128  rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLon, &m_meshOverlapSet, 1, &srccoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1129  rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLat, &m_meshOverlapSet, 1, &srccoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1130  const void* tgtcoordsvlonvals_d = &( m_dTargetVertexLon[0][0] );
1131  const void* tgtcoordsvlatvals_d = &( m_dTargetVertexLat[0][0] );
1132  dsize = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns();
1133  rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLon, &m_meshOverlapSet, 1, &tgtcoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1134  rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLat, &m_meshOverlapSet, 1, &tgtcoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1135 
1136  /* Set the masks for source and target meshes if available */
1137  if( m_iSourceMask.IsAttached() )
1138  {
1139  const void* srcmaskvals_d = m_iSourceMask;
1140  dsize = m_iSourceMask.GetRows();
1141  rval = m_interface->tag_set_by_ptr( srcMaskValues, &m_meshOverlapSet, 1, &srcmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1142  }
1143 
1144  if( m_iTargetMask.IsAttached() )
1145  {
1146  const void* tgtmaskvals_d = m_iTargetMask;
1147  dsize = m_iTargetMask.GetRows();
1148  rval = m_interface->tag_set_by_ptr( tgtMaskValues, &m_meshOverlapSet, 1, &tgtmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1149  }
1150 
1151 #ifdef MOAB_HAVE_MPI
1152  const char* writeOptions = ( this->size > 1 ? "PARALLEL=WRITE_PART" : "" );
1153 #else
1154  const char* writeOptions = "";
1155 #endif
1156 
1157  // EntityHandle sets[3] = {m_remapper->m_source_set, m_remapper->m_target_set, m_remapper->m_overlap_set};
1158  EntityHandle sets[1] = { m_remapper->m_overlap_set };
1159  rval = m_interface->write_file( strOutputFile.c_str(), NULL, writeOptions, sets, 1 );MB_CHK_ERR( rval );
1160 
1161 #ifdef WRITE_SCRIP_FILE
1162  sstr.str( "" );
1163  sstr << ctx.outFilename.substr( 0, lastindex ) << "_" << proc_id << ".nc";
1164  std::map< std::string, std::string > mapAttributes;
1165  mapAttributes["Creator"] = "MOAB mbtempest workflow";
1166  if( !ctx.proc_id ) std::cout << "Writing offline map to file: " << sstr.str() << std::endl;
1167  this->Write( strOutputFile.c_str(), mapAttributes, NcFile::Netcdf4 );
1168  sstr.str( "" );
1169 #endif
1170 
1171  return moab::MB_SUCCESS;
1172 }
1173 
1174 ///////////////////////////////////////////////////////////////////////////////
1175 
1176 void print_progress( const int barWidth, const float progress, const char* message )
1177 {
1178  std::cout << message << " [";
1179  int pos = barWidth * progress;
1180  for( int i = 0; i < barWidth; ++i )
1181  {
1182  if( i < pos )
1183  std::cout << "=";
1184  else if( i == pos )
1185  std::cout << ">";
1186  else
1187  std::cout << " ";
1188  }
1189  std::cout << "] " << int( progress * 100.0 ) << " %\r";
1190  std::cout.flush();
1191 }
1192 
1193 ///////////////////////////////////////////////////////////////////////////////
1194 
1196  const std::vector< int >& owned_dof_ids,
1197  bool row_partition )
1198 {
1199  NcError error( NcError::silent_nonfatal );
1200 
1201  NcVar *varRow = NULL, *varCol = NULL, *varS = NULL;
1202  int nS = 0, nA = 0, nB = 0;
1203 #ifdef MOAB_HAVE_PNETCDF
1204  // some variables will be used just in the case netcdfpar reader fails
1205  int ncfile = -1, ret = 0;
1206  int ndims, nvars, ngatts, unlimited;
1207 #endif
1208 #ifdef MOAB_HAVE_NETCDFPAR
1209  bool is_independent = true;
1210  ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 );
1211  // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 );
1212 #else
1213  NcFile ncMap( strSource, NcFile::ReadOnly );
1214 #endif
1215 
1216 #define CHECK_EXCEPTION( obj, type, varstr ) \
1217  { \
1218  if( obj == NULL ) \
1219  { \
1220  _EXCEPTION3( "Map file \"%s\" does not contain %s \"%s\"", strSource, type, varstr ); \
1221  } \
1222  }
1223 
1224  // Read SparseMatrix entries
1225 
1226  if( ncMap.is_valid() )
1227  {
1228  NcDim* dimNS = ncMap.get_dim( "n_s" );
1229  CHECK_EXCEPTION( dimNS, "dimension", "n_s" );
1230 
1231  NcDim* dimNA = ncMap.get_dim( "n_a" );
1232  CHECK_EXCEPTION( dimNA, "dimension", "n_a" );
1233 
1234  NcDim* dimNB = ncMap.get_dim( "n_b" );
1235  CHECK_EXCEPTION( dimNB, "dimension", "n_b" );
1236 
1237  // store total number of nonzeros
1238  nS = dimNS->size();
1239  nA = dimNA->size();
1240  nB = dimNB->size();
1241 
1242  varRow = ncMap.get_var( "row" );
1243  CHECK_EXCEPTION( varRow, "variable", "row" );
1244 
1245  varCol = ncMap.get_var( "col" );
1246  CHECK_EXCEPTION( varCol, "variable", "col" );
1247 
1248  varS = ncMap.get_var( "S" );
1249  CHECK_EXCEPTION( varS, "variable", "S" );
1250 
1251 #ifdef MOAB_HAVE_NETCDFPAR
1252  ncMap.enable_var_par_access( varRow, is_independent );
1253  ncMap.enable_var_par_access( varCol, is_independent );
1254  ncMap.enable_var_par_access( varS, is_independent );
1255 #endif
1256  }
1257  else
1258  {
1259 #ifdef MOAB_HAVE_PNETCDF
1260  // read the file using pnetcdf directly, in parallel; need to have MPI, we do not check that anymore
1261  // why build wth pnetcdf without MPI ?
1262  // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 );
1263  ret = ncmpi_open( m_pcomm->comm(), strSource, NC_NOWRITE, MPI_INFO_NULL, &ncfile );
1264  ERR_PARNC( ret ); // bail out completely
1265  ret = ncmpi_inq( ncfile, &ndims, &nvars, &ngatts, &unlimited );
1266  ERR_PARNC( ret );
1267  // find dimension ids for n_S
1268  int ins;
1269  ret = ncmpi_inq_dimid( ncfile, "n_s", &ins );
1270  ERR_PARNC( ret );
1271  MPI_Offset leng;
1272  ret = ncmpi_inq_dimlen( ncfile, ins, &leng );
1273  ERR_PARNC( ret );
1274  nS = (int)leng;
1275  ret = ncmpi_inq_dimid( ncfile, "n_b", &ins );
1276  ERR_PARNC( ret );
1277  ret = ncmpi_inq_dimlen( ncfile, ins, &leng );
1278  ERR_PARNC( ret );
1279  nB = (int)leng;
1280 #else
1281  _EXCEPTION1( "cannot read the file %s", strSource );
1282 #endif
1283  }
1284 
1285  // Let us declare the map object for every process
1286  SparseMatrix< double >& sparseMatrix = this->GetSparseMatrix();
1287 
1288  int localSize = nS / size;
1289  long offsetRead = rank * localSize;
1290  // leftovers on last rank
1291  if( rank == size - 1 )
1292  {
1293  localSize += nS % size;
1294  }
1295 
1296  std::vector< int > vecRow, vecCol;
1297  std::vector< double > vecS;
1298  vecRow.resize( localSize );
1299  vecCol.resize( localSize );
1300  vecS.resize( localSize );
1301 
1302  if( ncMap.is_valid() )
1303  {
1304  varRow->set_cur( (long)( offsetRead ) );
1305  varRow->get( &( vecRow[0] ), localSize );
1306 
1307  varCol->set_cur( (long)( offsetRead ) );
1308  varCol->get( &( vecCol[0] ), localSize );
1309 
1310  varS->set_cur( (long)( offsetRead ) );
1311  varS->get( &( vecS[0] ), localSize );
1312 
1313  ncMap.close();
1314  }
1315  else
1316  {
1317 #ifdef MOAB_HAVE_PNETCDF
1318  // fill the local vectors with the variables from pnetcdf file; first inquire, then fill
1319  MPI_Offset start = (MPI_Offset)offsetRead;
1320  MPI_Offset count = (MPI_Offset)localSize;
1321  int varid;
1322  ret = ncmpi_inq_varid( ncfile, "S", &varid );
1323  ERR_PARNC( ret );
1324  ret = ncmpi_get_vara_double_all( ncfile, varid, &start, &count, &vecS[0] );
1325  ERR_PARNC( ret );
1326  ret = ncmpi_inq_varid( ncfile, "row", &varid );
1327  ERR_PARNC( ret );
1328  ret = ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecRow[0] );
1329  ERR_PARNC( ret );
1330  ret = ncmpi_inq_varid( ncfile, "col", &varid );
1331  ERR_PARNC( ret );
1332  ret = ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecCol[0] );
1333  ERR_PARNC( ret );
1334  ret = ncmpi_close( ncfile );
1335  ERR_PARNC( ret );
1336 #endif
1337  }
1338 
1339  // Now let us set the necessary global-to-local ID maps so that A*x operations
1340  // can be performed cleanly as if map was computed online
1341  row_dtoc_dofmap.clear();
1342  // row_dtoc_dofmap.reserve( nB / size );
1343  col_dtoc_dofmap.clear();
1344  rowMap.clear();
1345  colMap.clear();
1346  // col_dtoc_dofmap.reserve( 2 * nA / size );
1347  // row_dtoc_dofmap.resize( m_nTotDofs_Dest, UINT_MAX );
1348  // col_dtoc_dofmap.resize( m_nTotDofs_SrcCov, UINT_MAX );
1349 
1350 #ifdef MOAB_HAVE_MPI
1351  // bother with tuple list only if size > 1
1352  // otherwise, just fill the sparse matrix
1353  if( size > 1 )
1354  {
1355  std::vector< int > ownership;
1356  // the default trivial partitioning scheme
1357  int nDofs = nB; // this is for row partitioning
1358  if( !row_partition ) nDofs = nA; // column partitioning
1359 
1360  // assert(row_major_ownership == true); // this block is valid only for row-based partitioning
1361  ownership.resize( size );
1362  int nPerPart = nDofs / size;
1363  int nRemainder = nDofs % size; // Keep the remainder in root
1364  ownership[0] = nPerPart + nRemainder;
1365  for( int ip = 1, roffset = ownership[0]; ip < size; ++ip )
1366  {
1367  roffset += nPerPart;
1368  ownership[ip] = roffset;
1369  }
1370  moab::TupleList* tl = new moab::TupleList;
1371  unsigned numr = 1; //
1372  tl->initialize( 3, 0, 0, numr, localSize ); // to proc, row, col, value
1373  tl->enableWriteAccess();
1374  // populate
1375  for( int i = 0; i < localSize; i++ )
1376  {
1377  int rowval = vecRow[i] - 1; // dofs are 1 based in the file
1378  int colval = vecCol[i] - 1;
1379  int to_proc = -1;
1380  int dof_val = colval;
1381  if( row_partition ) dof_val = rowval;
1382 
1383  if( ownership[0] > dof_val )
1384  to_proc = 0;
1385  else
1386  {
1387  for( int ip = 1; ip < size; ++ip )
1388  {
1389  if( ownership[ip - 1] <= dof_val && ownership[ip] > dof_val )
1390  {
1391  to_proc = ip;
1392  break;
1393  }
1394  }
1395  }
1396 
1397  int n = tl->get_n();
1398  tl->vi_wr[3 * n] = to_proc;
1399  tl->vi_wr[3 * n + 1] = rowval;
1400  tl->vi_wr[3 * n + 2] = colval;
1401  tl->vr_wr[n] = vecS[i];
1402  tl->inc_n();
1403  }
1404  // heavy communication
1405  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl, 0 );
1406 
1407  if( owned_dof_ids.size() > 0 )
1408  {
1409  // we need to send desired dof to the rendez_vous point
1410  moab::TupleList tl_re; //
1411  tl_re.initialize( 2, 0, 0, 0, owned_dof_ids.size() ); // to proc, value
1412  tl_re.enableWriteAccess();
1413  // send first to rendez_vous point, decided by trivial partitioning
1414 
1415  for( size_t i = 0; i < owned_dof_ids.size(); i++ )
1416  {
1417  int to_proc = -1;
1418  int dof_val = owned_dof_ids[i] - 1; // dofs are 1 based in the file, partition from 0 ?
1419 
1420  if( ownership[0] > dof_val )
1421  to_proc = 0;
1422  else
1423  {
1424  for( int ip = 1; ip < size; ++ip )
1425  {
1426  if( ownership[ip - 1] <= dof_val && ownership[ip] > dof_val )
1427  {
1428  to_proc = ip;
1429  break;
1430  }
1431  }
1432  }
1433 
1434  int n = tl_re.get_n();
1435  tl_re.vi_wr[2 * n] = to_proc;
1436  tl_re.vi_wr[2 * n + 1] = dof_val;
1437 
1438  tl_re.inc_n();
1439  }
1440  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tl_re, 0 );
1441  // now we know in tl_re where do we need to send back dof_val
1442  moab::TupleList::buffer sort_buffer;
1443  sort_buffer.buffer_init( tl_re.get_n() );
1444  tl_re.sort( 1, &sort_buffer ); // so now we order by value
1445 
1446  sort_buffer.buffer_init( tl->get_n() );
1447  int indexOrder = 2; // colVal
1448  if( row_partition ) indexOrder = 1; // rowVal
1449  //tl->sort( indexOrder, &sort_buffer );
1450 
1451  std::map< int, int > startDofIndex, endDofIndex; // indices in tl_re for values we want
1452  int dofVal = -1;
1453  if( tl_re.get_n() > 0 ) dofVal = tl_re.vi_rd[1]; // first dof val on this rank
1454  startDofIndex[dofVal] = 0;
1455  endDofIndex[dofVal] = 0; // start and end
1456  for( unsigned k = 1; k < tl_re.get_n(); k++ )
1457  {
1458  int newDof = tl_re.vi_rd[2 * k + 1];
1459  if( dofVal == newDof )
1460  {
1461  endDofIndex[dofVal] = k; // increment by 1 actually
1462  }
1463  else
1464  {
1465  dofVal = newDof;
1466  startDofIndex[dofVal] = k;
1467  endDofIndex[dofVal] = k;
1468  }
1469  }
1470 
1471  // basically, for each value we are interested in, index in tl_re with those values are
1472  // tl_re.vi_rd[2*startDofIndex+1] == valDof == tl_re.vi_rd[2*endDofIndex+1]
1473  // so now we have ordered
1474  // tl_re shows to what proc do we need to send the tuple (row, col, val)
1475  moab::TupleList* tl_back = new moab::TupleList;
1476  unsigned numr = 1; //
1477  // localSize is a good guess, but maybe it should be bigger ?
1478  // this could be bigger for repeated dofs
1479  tl_back->initialize( 3, 0, 0, numr, tl->get_n() ); // to proc, row, col, value
1480  tl_back->enableWriteAccess();
1481  // now loop over tl and tl_re to see where to send
1482  // form the new tuple, which will contain the desired dofs per task, per row or column distribution
1483 
1484  for( unsigned k = 0; k < tl->get_n(); k++ )
1485  {
1486  int valDof = tl->vi_rd[3 * k + indexOrder]; // 1 for row, 2 for column // first value, it should be
1487  for( int ire = startDofIndex[valDof]; ire <= endDofIndex[valDof]; ire++ )
1488  {
1489  int to_proc = tl_re.vi_rd[2 * ire];
1490  int n = tl_back->get_n();
1491  tl_back->vi_wr[3 * n] = to_proc;
1492  tl_back->vi_wr[3 * n + 1] = tl->vi_rd[3 * k + 1]; // row
1493  tl_back->vi_wr[3 * n + 2] = tl->vi_rd[3 * k + 2]; // col
1494  tl_back->vr_wr[n] = tl->vr_rd[k];
1495  tl_back->inc_n();
1496  }
1497  }
1498 
1499  // now communicate to the desired tasks:
1500  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl_back, 0 );
1501 
1502  tl_re.reset(); // clear memory, although this will go out of scope
1503  tl->reset();
1504  tl = tl_back;
1505  }
1506 
1507  int rindexMax = 0, cindexMax = 0;
1508  // populate the sparsematrix, using rowMap and colMap
1509  int n = tl->get_n();
1510  for( int i = 0; i < n; i++ )
1511  {
1512  int rindex, cindex;
1513  const int& vecRowValue = tl->vi_wr[3 * i + 1];
1514  const int& vecColValue = tl->vi_wr[3 * i + 2];
1515 
1516  std::map< int, int >::iterator riter = rowMap.find( vecRowValue );
1517  if( riter == rowMap.end() )
1518  {
1519  rowMap[vecRowValue] = rindexMax;
1520  rindex = rindexMax;
1521  row_gdofmap.push_back( vecRowValue );
1522  // row_dtoc_dofmap.push_back( vecRowValue );
1523  rindexMax++;
1524  }
1525  else
1526  rindex = riter->second;
1527 
1528  std::map< int, int >::iterator citer = colMap.find( vecColValue );
1529  if( citer == colMap.end() )
1530  {
1531  colMap[vecColValue] = cindexMax;
1532  cindex = cindexMax;
1533  col_gdofmap.push_back( vecColValue );
1534  // col_dtoc_dofmap.push_back( vecColValue );
1535  cindexMax++;
1536  }
1537  else
1538  cindex = citer->second;
1539 
1540  sparseMatrix( rindex, cindex ) = tl->vr_wr[i];
1541  }
1542  tl->reset();
1543  }
1544  else
1545 #endif
1546  {
1547  int rindexMax = 0, cindexMax = 0;
1548 
1549  for( int i = 0; i < nS; i++ )
1550  {
1551  int rindex, cindex;
1552  const int& vecRowValue = vecRow[i] - 1; // the rows, cols are 1 based in the file
1553  const int& vecColValue = vecCol[i] - 1;
1554 
1555  std::map< int, int >::iterator riter = rowMap.find( vecRowValue );
1556  if( riter == rowMap.end() )
1557  {
1558  rowMap[vecRowValue] = rindexMax;
1559  rindex = rindexMax;
1560  row_gdofmap.push_back( vecRowValue );
1561  // row_dtoc_dofmap.push_back( vecRowValue );
1562  rindexMax++;
1563  }
1564  else
1565  rindex = riter->second;
1566 
1567  std::map< int, int >::iterator citer = colMap.find( vecColValue );
1568  if( citer == colMap.end() )
1569  {
1570  colMap[vecColValue] = cindexMax;
1571  cindex = cindexMax;
1572  col_gdofmap.push_back( vecColValue );
1573  // col_dtoc_dofmap.push_back( vecColValue );
1574  cindexMax++;
1575  }
1576  else
1577  cindex = citer->second;
1578 
1579  sparseMatrix( rindex, cindex ) = vecS[i];
1580  }
1581  }
1582 
1583  m_nTotDofs_SrcCov = sparseMatrix.GetColumns();
1584  m_nTotDofs_Dest = sparseMatrix.GetRows();
1585 
1586 #ifdef MOAB_HAVE_EIGEN3
1587  this->copy_tempest_sparsemat_to_eigen3();
1588 #endif
1589 
1590  // Reset the source and target data first
1591  m_rowVector.setZero();
1592  m_colVector.setZero();
1593 
1594  return moab::MB_SUCCESS;
1595 }
1596 
1597 ///////////////////////////////////////////////////////////////////////////////