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

An offline map between two Meshes. More...

#include <TempestOnlineMap.hpp>

+ Inheritance diagram for moab::TempestOnlineMap:
+ Collaboration diagram for moab::TempestOnlineMap:

Public Types

enum  DiscretizationType { DiscretizationType_FV = 0 , DiscretizationType_CGLL = 1 , DiscretizationType_DGLL = 2 , DiscretizationType_PCLOUD = 3 }
 
enum  CAASType {
  CAAS_NONE = 0 , CAAS_GLOBAL = 1 , CAAS_LOCAL = 2 , CAAS_LOCAL_ADJACENT = 3 ,
  CAAS_QLT = 4
}
 
typedef double(* sample_function) (double, double)
 

Public Member Functions

 TempestOnlineMap (moab::TempestRemapper *remapper)
 Generate the metadata associated with the offline map. More...
 
virtual ~TempestOnlineMap ()
 Define a virtual destructor. More...
 
moab::ErrorCode GenerateRemappingWeights (std::string strInputType, std::string strOutputType, const GenerateOfflineMapAlgorithmOptions &mapOptions, const std::string &srcDofTagName="GLOBAL_ID", const std::string &tgtDofTagName="GLOBAL_ID")
 Generate the offline map, given the source and target mesh and discretization details. This method generates the mapping between the two meshes based on the overlap and stores the result in the SparseMatrix. More...
 
moab::ErrorCode ReadParallelMap (const char *strSource, const std::vector< int > &tgt_dof_ids, std::vector< double > &areaA, int &nA, std::vector< double > &areaB, int &nB)
 Generate the metadata associated with the offline map. More...
 
moab::ErrorCode WriteParallelMap (const std::string &strTarget, const std::map< std::string, std::string > &attrMap)
 Write the TempestOnlineMap to a parallel NetCDF file. More...
 
virtual int IsConsistent (double dTolerance)
 Determine if the map is first-order accurate. More...
 
virtual int IsConservative (double dTolerance)
 Determine if the map is conservative. More...
 
virtual int IsMonotone (double dTolerance)
 Determine if the map is monotone. More...
 
const DataArray1D< double > & GetGlobalSourceAreas () const
 If we computed the reduction, get the vector representing the source areas for all entities in the mesh More...
 
const DataArray1D< double > & GetGlobalTargetAreas () const
 If we computed the reduction, get the vector representing the target areas for all entities in the mesh More...
 
void PrintMapStatistics ()
 Print information and metadata about the remapping weights. More...
 
moab::ErrorCode SetDOFmapTags (const std::string srcDofTagName, const std::string tgtDofTagName)
 Store the tag names associated with global DoF ids for source and target meshes to be used for mapping.

Parameters
srcDofTagNameThe tag name associated with global DoF ids for the source mesh
tgtDofTagNameThe tag name associated with global DoF ids for the target mesh
More...
 
moab::ErrorCode SetDOFmapAssociation (DiscretizationType srcType, int srcOrder, bool isSrcContinuous, DataArray3D< int > *srcdataGLLNodes, DataArray3D< int > *srcdataGLLNodesSrc, DiscretizationType destType, int destOrder, bool isTgtContinuous, DataArray3D< int > *tgtdataGLLNodes)
 
std::pair< double, double > ApplyBoundsLimiting (std::vector< double > &dataInDouble, std::vector< double > &dataOutDouble, CAASType caasType=CAAS_GLOBAL, int caasIteration=0, double mismatch=0.0)
 
void ComputeAdjacencyRelations (std::vector< std::unordered_set< int > > &vecAdjFaces, int nrings, const Range &entities, bool useMOABAdjacencies=true, Mesh *trMesh=nullptr)
 
int GetSourceGlobalNDofs ()
 Get the number of total Degrees-Of-Freedom defined on the source mesh. More...
 
int GetDestinationGlobalNDofs ()
 Get the number of total Degrees-Of-Freedom defined on the destination mesh. More...
 
int GetSourceLocalNDofs ()
 Get the number of local Degrees-Of-Freedom defined on the source mesh. More...
 
int GetDestinationLocalNDofs ()
 Get the number of local Degrees-Of-Freedom defined on the destination mesh. More...
 
int GetSourceNDofsPerElement ()
 Get the number of Degrees-Of-Freedom per element on the source mesh. More...
 
int GetDestinationNDofsPerElement ()
 Get the number of Degrees-Of-Freedom per element on the destination mesh. More...
 
void SetSourceNDofsPerElement (int ns)
 Set the number of Degrees-Of-Freedom per element on the source mesh. More...
 
void SetDestinationNDofsPerElement (int nt)
 Get the number of Degrees-Of-Freedom per element on the destination mesh. More...
 
int GetRowGlobalDoF (int localID) const
 Get the global Degrees-Of-Freedom ID on the destination mesh. More...
 
int GetIndexOfRowGlobalDoF (int globalRowDoF) const
 Get the index of globaRowDoF. More...
 
int GetColGlobalDoF (int localID) const
 Get the global Degrees-Of-Freedom ID on the source mesh. More...
 
int GetIndexOfColGlobalDoF (int globalColDoF) const
 Get the index of globaColDoF. More...
 
moab::ErrorCode ApplyWeights (moab::Tag srcSolutionTag, moab::Tag tgtSolutionTag, bool transpose=false, CAASType caasType=CAAS_NONE, double default_projection=0.0)
 Apply the weight matrix onto the source vector (tag) provided as input, and return the column vector (solution projection) in a tag, after the map application Compute: tgtVals = A(S->T) * \srcVals, or if (transpose) tgtVals = [A(T->S)]^T * \srcVals More...
 
moab::ErrorCode DefineAnalyticalSolution (moab::Tag &exactSolnTag, const std::string &solnName, Remapper::IntersectionContext ctx, sample_function testFunction, moab::Tag *clonedSolnTag=NULL, std::string cloneSolnName="")
 Define an analytical solution over the given (source or target) mesh, as specificed in the context. This routine will define a tag that is compatible with the specified discretization method type and order and sample the solution exactly using the analytical function provided by the user. More...
 
moab::ErrorCode ComputeMetrics (Remapper::IntersectionContext ctx, moab::Tag &exactTag, moab::Tag &approxTag, std::map< std::string, double > &metrics, bool verbose=true)
 Compute the error between a sampled (exact) solution and a projected solution in various error norms. More...
 
moab::ErrorCode fill_col_ids (std::vector< int > &ids_of_interest)
 
moab::ErrorCode set_col_dc_dofs (std::vector< int > &values_entities)
 
moab::ErrorCode set_row_dc_dofs (std::vector< int > &values_entities)
 
void SetMeshInput (Mesh *imesh)
 

Private Member Functions

moab::ErrorCode LinearRemapNN_MOAB (bool use_GID_matching=false, bool strict_check=false)
 Compute the remapping weights as a permutation matrix that relates DoFs on the source mesh to DoFs on the target mesh. More...
 
void LinearRemapFVtoFV_Tempest_MOAB (int nOrder)
 Compute the remapping weights for a FV field defined on the source to a FV field defined on the target mesh. More...
 
void LinearRemapSE0_Tempest_MOAB (const DataArray3D< int > &dataGLLNodes, const DataArray3D< double > &dataGLLJacobian)
 Generate the OfflineMap for linear conserative element-average spectral element to element average remapping. More...
 
void LinearRemapSE4_Tempest_MOAB (const DataArray3D< int > &dataGLLNodes, const DataArray3D< double > &dataGLLJacobian, int nMonotoneType, bool fContinuousIn, bool fNoConservation)
 Generate the OfflineMap for cubic conserative element-average spectral element to element average remapping. More...
 
void LinearRemapFVtoGLL_MOAB (const DataArray3D< int > &dataGLLNodes, const DataArray3D< double > &dataGLLJacobian, const DataArray1D< double > &dataGLLNodalArea, int nOrder, int nMonotoneType, bool fContinuous, bool fNoConservation)
 Generate the OfflineMap for remapping from finite volumes to finite elements. More...
 
void LinearRemapGLLtoGLL2_MOAB (const DataArray3D< int > &dataGLLNodesIn, const DataArray3D< double > &dataGLLJacobianIn, const DataArray3D< int > &dataGLLNodesOut, const DataArray3D< double > &dataGLLJacobianOut, const DataArray1D< double > &dataNodalAreaOut, int nPin, int nPout, int nMonotoneType, bool fContinuousIn, bool fContinuousOut, bool fNoConservation)
 Generate the OfflineMap for remapping from finite elements to finite elements. More...
 
void LinearRemapGLLtoGLL2_Pointwise_MOAB (const DataArray3D< int > &dataGLLNodesIn, const DataArray3D< double > &dataGLLJacobianIn, const DataArray3D< int > &dataGLLNodesOut, const DataArray3D< double > &dataGLLJacobianOut, const DataArray1D< double > &dataNodalAreaOut, int nPin, int nPout, int nMonotoneType, bool fContinuousIn, bool fContinuousOut)
 Generate the OfflineMap for remapping from finite elements to finite elements (pointwise interpolation). More...
 
moab::ErrorCode WriteSCRIPMapFile (const std::string &strOutputFile, const std::map< std::string, std::string > &attrMap)
 Copy the local matrix from Tempest SparseMatrix representation (ELL) to the parallel CSR Eigen Matrix for scalable application of matvec needed for projections. More...
 
moab::ErrorCode WriteHDF5MapFile (const std::string &filename)
 Parallel I/O with NetCDF to write out the SCRIP file from multiple processors. More...
 
template<typename SparseMatrixType >
void serializeSparseMatrix (const SparseMatrixType &mat, const std::string &filename)
 
void setup_sizes_dimensions ()
 
void CAASLimiter (std::vector< double > &dataCorrectedField, std::vector< double > &dataLowerBound, std::vector< double > &dataUpperBound, double &dMass)
 
double QLTLimiter (int caasIteration, std::vector< double > &dataCorrectedField, std::vector< double > &dataLowerBound, std::vector< double > &dataUpperBound, std::vector< double > &dMassDefect)
 
moab::ErrorCode ApplyWeights (std::vector< double > &srcVals, std::vector< double > &tgtVals, bool transpose=false)
 Apply the weight matrix onto the source vector provided as input, and return the column vector (solution projection) after the map application Compute: tgtVals = A(S->T) * \srcVals, or if (transpose) tgtVals = [A(T->S)]^T * \srcVals More...
 

Private Attributes

moab::TempestRemapperm_remapper
 The fundamental remapping operator object. More...
 
moab::Interfacem_interface
 The reference to the moab::Core object that contains source/target and overlap sets. More...
 
moab::Tag m_dofTagSrc
 The original tag data and local to global DoF mapping to associate matrix values to solution More...
 
moab::Tag m_dofTagDest
 
std::vector< unsigned > row_gdofmap
 
std::vector< unsigned > col_gdofmap
 
std::vector< unsigned > srccol_gdofmap
 
std::vector< int > row_dtoc_dofmap
 
std::vector< int > col_dtoc_dofmap
 
std::vector< int > srccol_dtoc_dofmap
 
std::map< int, int > rowMap
 
std::map< int, int > colMap
 
int m_input_order
 
int m_output_order
 
DataArray3D< int > dataGLLNodesSrc
 
DataArray3D< int > dataGLLNodesSrcCov
 
DataArray3D< int > dataGLLNodesDest
 
DiscretizationType m_srcDiscType
 
DiscretizationType m_destDiscType
 
int m_nTotDofs_Src
 
int m_nTotDofs_SrcCov
 
int m_nTotDofs_Dest
 
int m_nDofsPEl_Src
 
int m_nDofsPEl_Dest
 
DiscretizationType m_eInputType
 
DiscretizationType m_eOutputType
 
bool m_bConserved
 
int m_iMonotonicity
 
Mesh * m_meshInput
 
Mesh * m_meshInputCov
 
Mesh * m_meshOutput
 
Mesh * m_meshOverlap
 
bool is_parallel
 
bool is_root
 
int rank
 
int size
 

Detailed Description

An offline map between two Meshes.

Definition at line 61 of file TempestOnlineMap.hpp.

Member Typedef Documentation

◆ sample_function

typedef double( * moab::TempestOnlineMap::sample_function) (double, double)

Definition at line 414 of file TempestOnlineMap.hpp.

Member Enumeration Documentation

◆ CAASType

Enumerator
CAAS_NONE 
CAAS_GLOBAL 
CAAS_LOCAL 
CAAS_LOCAL_ADJACENT 
CAAS_QLT 

Definition at line 86 of file TempestOnlineMap.hpp.

87  {
88  CAAS_NONE = 0,
89  CAAS_GLOBAL = 1,
90  CAAS_LOCAL = 2,
92  CAAS_QLT = 4
93  };

◆ DiscretizationType

Enumerator
DiscretizationType_FV 
DiscretizationType_CGLL 
DiscretizationType_DGLL 
DiscretizationType_PCLOUD 

Definition at line 77 of file TempestOnlineMap.hpp.

Constructor & Destructor Documentation

◆ TempestOnlineMap()

moab::TempestOnlineMap::TempestOnlineMap ( moab::TempestRemapper remapper)

Generate the metadata associated with the offline map.

Definition at line 64 of file TempestOnlineMap.cpp.

64  : OfflineMap(), m_remapper( remapper )
65 {
66  // Get the references for the MOAB core objects
68 #ifdef MOAB_HAVE_MPI
69  m_pcomm = m_remapper->get_parallel_communicator();
70 #endif
71 
72  // now let us re-update the reference to the input source mesh
74  // now let us re-update the reference to the covering mesh
76  // now let us re-update the reference to the output target mesh
78  // now let us re-update the reference to the output target mesh
80 
81  is_parallel = remapper->is_parallel;
82  is_root = remapper->is_root;
83  rank = remapper->rank;
84  size = remapper->size;
85 
86  // set default order
88 
89  // Initialize dimension information from file
90  this->setup_sizes_dimensions();
91 }

References moab::Remapper::get_interface(), moab::TempestRemapper::GetCoveringMesh(), moab::TempestRemapper::GetMesh(), is_parallel, moab::TempestRemapper::is_parallel, is_root, moab::TempestRemapper::is_root, m_input_order, m_interface, m_meshInput, m_meshInputCov, m_meshOutput, m_meshOverlap, m_output_order, m_remapper, moab::Remapper::OverlapMesh, rank, moab::TempestRemapper::rank, setup_sizes_dimensions(), size, moab::TempestRemapper::size, moab::Remapper::SourceMesh, and moab::Remapper::TargetMesh.

◆ ~TempestOnlineMap()

moab::TempestOnlineMap::~TempestOnlineMap ( )
virtual

Define a virtual destructor.

Definition at line 118 of file TempestOnlineMap.cpp.

119 {
120  m_interface = nullptr;
121 #ifdef MOAB_HAVE_MPI
122  m_pcomm = nullptr;
123 #endif
124  m_meshInput = nullptr;
125  m_meshOutput = nullptr;
126  m_meshOverlap = nullptr;
127 }

Member Function Documentation

◆ ApplyBoundsLimiting()

std::pair< double, double > moab::TempestOnlineMap::ApplyBoundsLimiting ( std::vector< double > &  dataInDouble,
std::vector< double > &  dataOutDouble,
CAASType  caasType = CAAS_GLOBAL,
int  caasIteration = 0,
double  mismatch = 0.0 
)

ApplyBoundsLimiting - Apply bounds limiting to the data field

Parameters
dataInDouble- input data field
dataOutDouble- output data field
caasType- type of limiter
caasIteration- iteration number of limiter
Returns
- pair of mass defect pre and post limiter application

◆ ApplyWeights() [1/2]

moab::ErrorCode moab::TempestOnlineMap::ApplyWeights ( moab::Tag  srcSolutionTag,
moab::Tag  tgtSolutionTag,
bool  transpose = false,
CAASType  caasType = CAAS_NONE,
double  default_projection = 0.0 
)

Apply the weight matrix onto the source vector (tag) provided as input, and return the column vector (solution projection) in a tag, after the map application Compute: tgtVals = A(S->T) * \srcVals, or if (transpose) tgtVals = [A(T->S)]^T * \srcVals

Definition at line 1415 of file TempestOnlineMap.cpp.

1420 {
1421  std::vector< double > solSTagVals;
1422  std::vector< double > solTTagVals;
1423 
1424  moab::Range sents, tents;
1426  {
1428  {
1430  solSTagVals.resize( covSrcEnts.size(), default_projection );
1431  sents = covSrcEnts;
1432  }
1433  else
1434  {
1436  solSTagVals.resize( covSrcEnts.size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1437  default_projection );
1438  sents = covSrcEnts;
1439  }
1441  {
1443  solTTagVals.resize( tgtEnts.size(), default_projection );
1444  tents = tgtEnts;
1445  }
1446  else
1447  {
1449  solTTagVals.resize( tgtEnts.size() * this->GetDestinationNDofsPerElement() *
1450  this->GetDestinationNDofsPerElement(),
1451  default_projection );
1452  tents = tgtEnts;
1453  }
1454  }
1455  else
1456  {
1459  solSTagVals.resize( covSrcEnts.size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
1460  default_projection );
1461  solTTagVals.resize( tgtEnts.size() * this->GetDestinationNDofsPerElement() *
1462  this->GetDestinationNDofsPerElement(),
1463  default_projection );
1464 
1465  sents = covSrcEnts;
1466  tents = tgtEnts;
1467  }
1468 
1469  // The tag data is np*np*n_el_src
1470  MB_CHK_SET_ERR( m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] ),
1471  "Getting local tag data failed" );
1472 
1473  // Compute the application of weights on the suorce solution data and store it in the
1474  // destination solution vector data Optionally, can also perform the transpose application of
1475  // the weight matrix. Set the 3rd argument to true if this is needed
1476  MB_CHK_SET_ERR( this->ApplyWeights( solSTagVals, solTTagVals, transpose ),
1477  "Applying remap operator onto source vector data failed" );
1478 
1479  // The tag data is np*np*n_el_dest
1480  MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1481  "Setting target tag data failed" );
1482 
1483  if( caasType != CAAS_NONE )
1484  {
1485  std::string tgtSolutionTagName;
1486  MB_CHK_SET_ERR( m_interface->tag_get_name( tgtSolutionTag, tgtSolutionTagName ), "Getting tag name failed" );
1487 
1488  // Perform CAAS iterations iteratively until convergence
1489  constexpr int nmax_caas_iterations = 10;
1490  double mismatch = 1.0;
1491  int caasIteration = 0;
1492  double initialMismatch = 0.0;
1493  while( ( fabs( mismatch / initialMismatch ) > 1e-15 && fabs( mismatch ) > 1e-15 ) &&
1494  caasIteration++ < nmax_caas_iterations ) // iterate until convergence or a maximum of 5 iterations
1495  {
1496  double dMassDiffPostGlobal;
1497  std::pair< double, double > mDefect =
1498  this->ApplyBoundsLimiting( solSTagVals, solTTagVals, caasType, caasIteration, mismatch );
1499 #ifdef MOAB_HAVE_MPI
1500  double dMassDiffPost = mDefect.second;
1501  MPI_Allreduce( &dMassDiffPost, &dMassDiffPostGlobal, 1, MPI_DOUBLE, MPI_SUM, m_pcomm->comm() );
1502 #else
1503  dMassDiffPostGlobal = mDefect.second;
1504 #endif
1505  if( caasIteration == 1 ) initialMismatch = mDefect.first;
1506  if( m_remapper->verbose && is_root )
1507  {
1508  printf( "Field {%s} -> CAAS iteration: %d, mass defect: %3.4e, post-CAAS: %3.4e\n",
1509  tgtSolutionTagName.c_str(), caasIteration, mDefect.first, dMassDiffPostGlobal );
1510  }
1511  mismatch = dMassDiffPostGlobal;
1512 
1513  // The tag data is np*np*n_el_dest
1514  MB_CHK_SET_ERR( m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] ),
1515  "Setting local tag data failed" );
1516  }
1517  }
1518 
1519  return moab::MB_SUCCESS;
1520 }

References moab::Remapper::CoveringMesh, MB_CHK_SET_ERR, MB_SUCCESS, moab::Range::size(), and moab::Remapper::TargetMesh.

Referenced by main().

◆ ApplyWeights() [2/2]

moab::ErrorCode moab::TempestOnlineMap::ApplyWeights ( std::vector< double > &  srcVals,
std::vector< double > &  tgtVals,
bool  transpose = false 
)
private

Apply the weight matrix onto the source vector provided as input, and return the column vector (solution projection) after the map application Compute: tgtVals = A(S->T) * \srcVals, or if (transpose) tgtVals = [A(T->S)]^T * \srcVals

◆ CAASLimiter()

void moab::TempestOnlineMap::CAASLimiter ( std::vector< double > &  dataCorrectedField,
std::vector< double > &  dataLowerBound,
std::vector< double > &  dataUpperBound,
double &  dMass 
)
private

◆ ComputeAdjacencyRelations()

void moab::TempestOnlineMap::ComputeAdjacencyRelations ( std::vector< std::unordered_set< int > > &  vecAdjFaces,
int  nrings,
const Range entities,
bool  useMOABAdjacencies = true,
Mesh *  trMesh = nullptr 
)
Parameters
vecAdjFaces
nrings
entities
useMOABAdjacencies
trMesh
Returns

Vector storing adjacent Faces.

Definition at line 1366 of file TempestOnlineMap.cpp.

1371 {
1372  assert( nrings > 0 );
1373  assert( useMOABAdjacencies || trMesh != nullptr );
1374 
1375  const size_t nrows = vecAdjFaces.size();
1377  for( size_t index = 0; index < nrows; index++ )
1378  {
1379  vecAdjFaces[index].insert( index ); // add self target face first
1380  {
1381  // Compute the adjacent faces to the target face
1382  if( useMOABAdjacencies )
1383  {
1384  moab::Range ents;
1385  // ents.insert( entities.index( entities[index] ) );
1386  ents.insert( entities[index] );
1387  moab::Range adjEnts;
1388  moab::ErrorCode rval = mtu.get_bridge_adjacencies( ents, 0, 2, adjEnts, nrings );MB_CHK_SET_ERR_CONT( rval, "Failed to get adjacent faces" );
1389  for( moab::Range::iterator it = adjEnts.begin(); it != adjEnts.end(); ++it )
1390  {
1391  // int adjIndex = m_interface->id_from_handle(*it)-1;
1392  int adjIndex = entities.index( *it );
1393  // printf("rank: %d, Element %lu, entity: %lu, adjIndex %d\n", rank, index, *it, adjIndex);
1394  if( adjIndex >= 0 ) vecAdjFaces[index].insert( adjIndex );
1395  }
1396  }
1397  else
1398  {
1399  /// Vector storing adjacent Faces.
1400  typedef std::pair< int, int > FaceDistancePair;
1401  typedef std::vector< FaceDistancePair > AdjacentFaceVector;
1402  AdjacentFaceVector adjFaces;
1403  Face& face = trMesh->faces[index];
1404  GetAdjacentFaceVectorByEdge( *trMesh, index, nrings * face.edges.size(), adjFaces );
1405 
1406  // Add the adjacent faces to the target face list
1407  for( auto adjFace : adjFaces )
1408  if( adjFace.first >= 0 )
1409  vecAdjFaces[index].insert( adjFace.first ); // map target face to source face
1410  }
1411  }
1412  }
1413 }

References moab::Range::begin(), moab::Range::end(), entities, ErrorCode, moab::MeshTopoUtil::get_bridge_adjacencies(), moab::Range::insert(), and MB_CHK_SET_ERR_CONT.

◆ ComputeMetrics()

moab::ErrorCode moab::TempestOnlineMap::ComputeMetrics ( Remapper::IntersectionContext  ctx,
moab::Tag exactTag,
moab::Tag approxTag,
std::map< std::string, double > &  metrics,
bool  verbose = true 
)

Compute the error between a sampled (exact) solution and a projected solution in various error norms.

Definition at line 1884 of file TempestOnlineMap.cpp.

1889 {
1890  moab::ErrorCode rval;
1891  const bool outputEnabled = ( is_root );
1892  int discOrder;
1893  // DiscretizationType discMethod;
1894  // moab::EntityHandle meshset;
1896  // Mesh* trmesh;
1897  switch( ctx )
1898  {
1899  case Remapper::SourceMesh:
1900  // meshset = m_remapper->m_covering_source_set;
1901  // trmesh = m_remapper->m_covering_source;
1904  discOrder = m_nDofsPEl_Src;
1905  // discMethod = m_eInputType;
1906  break;
1907 
1908  case Remapper::TargetMesh:
1909  // meshset = m_remapper->m_target_set;
1910  // trmesh = m_remapper->m_target;
1911  entities =
1913  discOrder = m_nDofsPEl_Dest;
1914  // discMethod = m_eOutputType;
1915  break;
1916 
1917  default:
1918  if( outputEnabled )
1919  std::cout << "Invalid context specified for defining an analytical solution tag" << std::endl;
1920  return moab::MB_FAILURE;
1921  }
1922 
1923  // Let us create teh solution tag with appropriate information for name, discretization order
1924  // (DoF space)
1925  std::string exactTagName, projTagName;
1926  const int ntotsize = entities.size() * discOrder * discOrder;
1927  std::vector< double > exactSolution( ntotsize, 0.0 ), projSolution( ntotsize, 0.0 );
1928  rval = m_interface->tag_get_name( exactTag, exactTagName );MB_CHK_ERR( rval );
1929  rval = m_interface->tag_get_data( exactTag, entities, &exactSolution[0] );MB_CHK_ERR( rval );
1930  rval = m_interface->tag_get_name( approxTag, projTagName );MB_CHK_ERR( rval );
1931  rval = m_interface->tag_get_data( approxTag, entities, &projSolution[0] );MB_CHK_ERR( rval );
1932 
1933  const auto& ovents = m_remapper->m_overlap_entities;
1934 
1935  std::vector< double > errnorms( 4, 0.0 ), globerrnorms( 4, 0.0 ); // L1Err, L2Err, LinfErr
1936  double sumarea = 0.0;
1937  for( size_t i = 0; i < ovents.size(); ++i )
1938  {
1939  const int srcidx = m_remapper->m_overlap->vecSourceFaceIx[i];
1940  if( srcidx < 0 ) continue; // Skip non-overlapping entities
1941  const int tgtidx = m_remapper->m_overlap->vecTargetFaceIx[i];
1942  if( tgtidx < 0 ) continue; // skip ghost target faces
1943  const double ovarea = m_remapper->m_overlap->vecFaceArea[i];
1944  const double error = fabs( exactSolution[tgtidx] - projSolution[tgtidx] );
1945  errnorms[0] += ovarea * error;
1946  errnorms[1] += ovarea * error * error;
1947  errnorms[3] = ( error > errnorms[3] ? error : errnorms[3] );
1948  sumarea += ovarea;
1949  }
1950  errnorms[2] = sumarea;
1951 #ifdef MOAB_HAVE_MPI
1952  if( m_pcomm )
1953  {
1954  MPI_Reduce( &errnorms[0], &globerrnorms[0], 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
1955  MPI_Reduce( &errnorms[3], &globerrnorms[3], 1, MPI_DOUBLE, MPI_MAX, 0, m_pcomm->comm() );
1956  }
1957 #else
1958  for( int i = 0; i < 4; ++i )
1959  globerrnorms[i] = errnorms[i];
1960 #endif
1961 
1962  globerrnorms[0] = ( globerrnorms[0] / globerrnorms[2] );
1963  globerrnorms[1] = std::sqrt( globerrnorms[1] / globerrnorms[2] );
1964 
1965  metrics.clear();
1966  metrics["L1Error"] = globerrnorms[0];
1967  metrics["L2Error"] = globerrnorms[1];
1968  metrics["LinfError"] = globerrnorms[3];
1969 
1970  if( verbose && is_root )
1971  {
1972  std::cout << "Error metrics when comparing " << projTagName << " against " << exactTagName << std::endl;
1973  std::cout << "\t Total Intersection area = " << globerrnorms[2] << std::endl;
1974  std::cout << "\t L_1 error = " << globerrnorms[0] << std::endl;
1975  std::cout << "\t L_2 error = " << globerrnorms[1] << std::endl;
1976  std::cout << "\t L_inf error = " << globerrnorms[3] << std::endl;
1977  }
1978 
1979  return moab::MB_SUCCESS;
1980 }

References entities, moab::error(), ErrorCode, MB_CHK_ERR, MB_SUCCESS, moab::Remapper::SourceMesh, moab::Remapper::TargetMesh, and verbose.

Referenced by main().

◆ DefineAnalyticalSolution()

moab::ErrorCode moab::TempestOnlineMap::DefineAnalyticalSolution ( moab::Tag exactSolnTag,
const std::string &  solnName,
Remapper::IntersectionContext  ctx,
sample_function  testFunction,
moab::Tag clonedSolnTag = NULL,
std::string  cloneSolnName = "" 
)

Define an analytical solution over the given (source or target) mesh, as specificed in the context. This routine will define a tag that is compatible with the specified discretization method type and order and sample the solution exactly using the analytical function provided by the user.

Definition at line 1522 of file TempestOnlineMap.cpp.

1528 {
1529  moab::ErrorCode rval;
1530  const bool outputEnabled = ( is_root );
1531  int discOrder;
1532  DiscretizationType discMethod;
1533  // moab::EntityHandle meshset;
1535  Mesh* trmesh;
1536  switch( ctx )
1537  {
1538  case Remapper::SourceMesh:
1539  // meshset = m_remapper->m_covering_source_set;
1540  trmesh = m_remapper->m_covering_source;
1543  discOrder = m_nDofsPEl_Src;
1544  discMethod = m_eInputType;
1545  break;
1546 
1547  case Remapper::TargetMesh:
1548  // meshset = m_remapper->m_target_set;
1549  trmesh = m_remapper->m_target;
1550  entities =
1552  discOrder = m_nDofsPEl_Dest;
1553  discMethod = m_eOutputType;
1554  break;
1555 
1556  default:
1557  if( outputEnabled )
1558  std::cout << "Invalid context specified for defining an analytical solution tag" << std::endl;
1559  return moab::MB_FAILURE;
1560  }
1561 
1562  // Let us create teh solution tag with appropriate information for name, discretization order
1563  // (DoF space)
1564  rval = m_interface->tag_get_handle( solnName.c_str(), discOrder * discOrder, MB_TYPE_DOUBLE, solnTag,
1565  MB_TAG_DENSE | MB_TAG_CREAT );MB_CHK_ERR( rval );
1566  if( clonedSolnTag != nullptr )
1567  {
1568  if( cloneSolnName.size() == 0 )
1569  {
1570  cloneSolnName = solnName + std::string( "Cloned" );
1571  }
1572  rval = m_interface->tag_get_handle( cloneSolnName.c_str(), discOrder * discOrder, MB_TYPE_DOUBLE,
1573  *clonedSolnTag, MB_TAG_DENSE | MB_TAG_CREAT );MB_CHK_ERR( rval );
1574  }
1575 
1576  // Triangular quadrature rule
1577  const int TriQuadratureOrder = 10;
1578 
1579  if( outputEnabled ) std::cout << "Using triangular quadrature of order " << TriQuadratureOrder << std::endl;
1580 
1581  TriangularQuadratureRule triquadrule( TriQuadratureOrder );
1582 
1583  const int TriQuadraturePoints = triquadrule.GetPoints();
1584 
1585  const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
1586  const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
1587 
1588  // Output data
1589  DataArray1D< double > dVar;
1590  DataArray1D< double > dVarMB; // re-arranged local MOAB vector
1591 
1592  // Nodal geometric area
1593  DataArray1D< double > dNodeArea;
1594 
1595  // Calculate element areas
1596  // trmesh->CalculateFaceAreas(fContainsConcaveFaces);
1597 
1598  if( discMethod == DiscretizationType_CGLL || discMethod == DiscretizationType_DGLL )
1599  {
1600  /* Get the spectral points and sample the functionals accordingly */
1601  const bool fGLL = true;
1602  const bool fGLLIntegrate = false;
1603 
1604  // Generate grid metadata
1605  DataArray3D< int > dataGLLNodes;
1606  DataArray3D< double > dataGLLJacobian;
1607 
1608  GenerateMetaData( *trmesh, discOrder, false, dataGLLNodes, dataGLLJacobian );
1609 
1610  // Number of elements
1611  int nElements = trmesh->faces.size();
1612 
1613  // Verify all elements are quadrilaterals
1614  for( int k = 0; k < nElements; k++ )
1615  {
1616  const Face& face = trmesh->faces[k];
1617 
1618  if( face.edges.size() != 4 )
1619  {
1620  _EXCEPTIONT( "Non-quadrilateral face detected; "
1621  "incompatible with --gll" );
1622  }
1623  }
1624 
1625  // Number of unique nodes
1626  int iMaxNode = 0;
1627  for( int i = 0; i < discOrder; i++ )
1628  {
1629  for( int j = 0; j < discOrder; j++ )
1630  {
1631  for( int k = 0; k < nElements; k++ )
1632  {
1633  if( dataGLLNodes[i][j][k] > iMaxNode )
1634  {
1635  iMaxNode = dataGLLNodes[i][j][k];
1636  }
1637  }
1638  }
1639  }
1640 
1641  // Get Gauss-Lobatto quadrature nodes
1642  DataArray1D< double > dG;
1643  DataArray1D< double > dW;
1644 
1645  GaussLobattoQuadrature::GetPoints( discOrder, 0.0, 1.0, dG, dW );
1646 
1647  // Get Gauss quadrature nodes
1648  const int nGaussP = 10;
1649 
1650  DataArray1D< double > dGaussG;
1651  DataArray1D< double > dGaussW;
1652 
1653  GaussQuadrature::GetPoints( nGaussP, 0.0, 1.0, dGaussG, dGaussW );
1654 
1655  // Allocate data
1656  dVar.Allocate( iMaxNode );
1657  dVarMB.Allocate( discOrder * discOrder * nElements );
1658  dNodeArea.Allocate( iMaxNode );
1659 
1660  // Sample data
1661  for( int k = 0; k < nElements; k++ )
1662  {
1663  const Face& face = trmesh->faces[k];
1664 
1665  // Sample data at GLL nodes
1666  if( fGLL )
1667  {
1668  for( int i = 0; i < discOrder; i++ )
1669  {
1670  for( int j = 0; j < discOrder; j++ )
1671  {
1672 
1673  // Apply local map
1674  Node node;
1675  Node dDx1G;
1676  Node dDx2G;
1677 
1678  ApplyLocalMap( face, trmesh->nodes, dG[i], dG[j], node, dDx1G, dDx2G );
1679 
1680  // Sample data at this point
1681  double dNodeLon = atan2( node.y, node.x );
1682  if( dNodeLon < 0.0 )
1683  {
1684  dNodeLon += 2.0 * M_PI;
1685  }
1686  double dNodeLat = asin( node.z );
1687 
1688  double dSample = ( *testFunction )( dNodeLon, dNodeLat );
1689 
1690  dVar[dataGLLNodes[j][i][k] - 1] = dSample;
1691  }
1692  }
1693  // High-order Gaussian integration over basis function
1694  }
1695  else
1696  {
1697  DataArray2D< double > dCoeff( discOrder, discOrder );
1698 
1699  for( int p = 0; p < nGaussP; p++ )
1700  {
1701  for( int q = 0; q < nGaussP; q++ )
1702  {
1703 
1704  // Apply local map
1705  Node node;
1706  Node dDx1G;
1707  Node dDx2G;
1708 
1709  ApplyLocalMap( face, trmesh->nodes, dGaussG[p], dGaussG[q], node, dDx1G, dDx2G );
1710 
1711  // Cross product gives local Jacobian
1712  Node nodeCross = CrossProduct( dDx1G, dDx2G );
1713 
1714  double dJacobian =
1715  sqrt( nodeCross.x * nodeCross.x + nodeCross.y * nodeCross.y + nodeCross.z * nodeCross.z );
1716 
1717  // Find components of quadrature point in basis
1718  // of the first Face
1719  SampleGLLFiniteElement( 0, discOrder, dGaussG[p], dGaussG[q], dCoeff );
1720 
1721  // Sample data at this point
1722  double dNodeLon = atan2( node.y, node.x );
1723  if( dNodeLon < 0.0 )
1724  {
1725  dNodeLon += 2.0 * M_PI;
1726  }
1727  double dNodeLat = asin( node.z );
1728 
1729  double dSample = ( *testFunction )( dNodeLon, dNodeLat );
1730 
1731  // Integrate
1732  for( int i = 0; i < discOrder; i++ )
1733  {
1734  for( int j = 0; j < discOrder; j++ )
1735  {
1736 
1737  double dNodalArea = dCoeff[i][j] * dGaussW[p] * dGaussW[q] * dJacobian;
1738 
1739  dVar[dataGLLNodes[i][j][k] - 1] += dSample * dNodalArea;
1740 
1741  dNodeArea[dataGLLNodes[i][j][k] - 1] += dNodalArea;
1742  }
1743  }
1744  }
1745  }
1746  }
1747  }
1748 
1749  // Divide by area
1750  if( fGLLIntegrate )
1751  {
1752  for( size_t i = 0; i < dVar.GetRows(); i++ )
1753  {
1754  dVar[i] /= dNodeArea[i];
1755  }
1756  }
1757 
1758  // Let us rearrange the data based on DoF ID specification
1759  if( ctx == Remapper::SourceMesh )
1760  {
1761  for( unsigned j = 0; j < entities.size(); j++ )
1762  for( int p = 0; p < discOrder; p++ )
1763  for( int q = 0; q < discOrder; q++ )
1764  {
1765  const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
1766  dVarMB[offsetDOF] = dVar[col_dtoc_dofmap[offsetDOF]];
1767  }
1768  }
1769  else
1770  {
1771  for( unsigned j = 0; j < entities.size(); j++ )
1772  for( int p = 0; p < discOrder; p++ )
1773  for( int q = 0; q < discOrder; q++ )
1774  {
1775  const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
1776  dVarMB[offsetDOF] = dVar[row_dtoc_dofmap[offsetDOF]];
1777  }
1778  }
1779 
1780  // Set the tag data
1781  rval = m_interface->tag_set_data( solnTag, entities, &dVarMB[0] );MB_CHK_ERR( rval );
1782  }
1783  else
1784  {
1785  // assert( discOrder == 1 );
1786  if( discMethod == DiscretizationType_FV )
1787  {
1788  /* Compute an element-wise integral to store the sampled solution based on Quadrature
1789  * rules */
1790  // Resize the array
1791  dVar.Allocate( trmesh->faces.size() );
1792 
1793  std::vector< Node >& nodes = trmesh->nodes;
1794 
1795  // Loop through all Faces
1796  for( size_t i = 0; i < trmesh->faces.size(); i++ )
1797  {
1798  const Face& face = trmesh->faces[i];
1799 
1800  // Loop through all sub-triangles
1801  for( size_t j = 0; j < face.edges.size() - 2; j++ )
1802  {
1803 
1804  const Node& node0 = nodes[face[0]];
1805  const Node& node1 = nodes[face[j + 1]];
1806  const Node& node2 = nodes[face[j + 2]];
1807 
1808  // Triangle area
1809  Face faceTri( 3 );
1810  faceTri.SetNode( 0, face[0] );
1811  faceTri.SetNode( 1, face[j + 1] );
1812  faceTri.SetNode( 2, face[j + 2] );
1813 
1814  double dTriangleArea = CalculateFaceArea( faceTri, nodes );
1815 
1816  // Calculate the element average
1817  double dTotalSample = 0.0;
1818 
1819  // Loop through all quadrature points
1820  for( int k = 0; k < TriQuadraturePoints; k++ )
1821  {
1822  Node node( TriQuadratureG[k][0] * node0.x + TriQuadratureG[k][1] * node1.x +
1823  TriQuadratureG[k][2] * node2.x,
1824  TriQuadratureG[k][0] * node0.y + TriQuadratureG[k][1] * node1.y +
1825  TriQuadratureG[k][2] * node2.y,
1826  TriQuadratureG[k][0] * node0.z + TriQuadratureG[k][1] * node1.z +
1827  TriQuadratureG[k][2] * node2.z );
1828 
1829  double dMagnitude = node.Magnitude();
1830  node.x /= dMagnitude;
1831  node.y /= dMagnitude;
1832  node.z /= dMagnitude;
1833 
1834  double dLon = atan2( node.y, node.x );
1835  if( dLon < 0.0 )
1836  {
1837  dLon += 2.0 * M_PI;
1838  }
1839  double dLat = asin( node.z );
1840 
1841  double dSample = ( *testFunction )( dLon, dLat );
1842 
1843  dTotalSample += dSample * TriQuadratureW[k] * dTriangleArea;
1844  }
1845 
1846  dVar[i] += dTotalSample / trmesh->vecFaceArea[i];
1847  }
1848  }
1849  rval = m_interface->tag_set_data( solnTag, entities, &dVar[0] );MB_CHK_ERR( rval );
1850  }
1851  else /* discMethod == DiscretizationType_PCLOUD */
1852  {
1853  /* Get the coordinates of the vertices and sample the functionals accordingly */
1854  std::vector< Node >& nodes = trmesh->nodes;
1855 
1856  // Resize the array
1857  dVar.Allocate( nodes.size() );
1858 
1859  for( size_t j = 0; j < nodes.size(); j++ )
1860  {
1861  Node& node = nodes[j];
1862  double dMagnitude = node.Magnitude();
1863  node.x /= dMagnitude;
1864  node.y /= dMagnitude;
1865  node.z /= dMagnitude;
1866  double dLon = atan2( node.y, node.x );
1867  if( dLon < 0.0 )
1868  {
1869  dLon += 2.0 * M_PI;
1870  }
1871  double dLat = asin( node.z );
1872 
1873  double dSample = ( *testFunction )( dLon, dLat );
1874  dVar[j] = dSample;
1875  }
1876 
1877  rval = m_interface->tag_set_data( solnTag, entities, &dVar[0] );MB_CHK_ERR( rval );
1878  }
1879  }
1880 
1881  return moab::MB_SUCCESS;
1882 }

References entities, ErrorCode, MB_CHK_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_DOUBLE, moab::Remapper::SourceMesh, and moab::Remapper::TargetMesh.

Referenced by main().

◆ fill_col_ids()

moab::ErrorCode moab::TempestOnlineMap::fill_col_ids ( std::vector< int > &  ids_of_interest)
inline

Definition at line 439 of file TempestOnlineMap.hpp.

440  {
441  ids_of_interest.reserve( col_gdofmap.size() );
442  // need to add 1
443  for( auto it = col_gdofmap.begin(); it != col_gdofmap.end(); it++ )
444  ids_of_interest.push_back( *it + 1 );
445  return moab::MB_SUCCESS;
446  }

References col_gdofmap, and MB_SUCCESS.

◆ GenerateRemappingWeights()

moab::ErrorCode moab::TempestOnlineMap::GenerateRemappingWeights ( std::string  strInputType,
std::string  strOutputType,
const GenerateOfflineMapAlgorithmOptions &  mapOptions,
const std::string &  srcDofTagName = "GLOBAL_ID",
const std::string &  tgtDofTagName = "GLOBAL_ID" 
)

Generate the offline map, given the source and target mesh and discretization details. This method generates the mapping between the two meshes based on the overlap and stores the result in the SparseMatrix.

the tag should be created already in the e3sm workflow; if not, create it here

Definition at line 431 of file TempestOnlineMap.cpp.

436 {
437  NcError error( NcError::silent_nonfatal );
438 
439  moab::DebugOutput dbgprint( std::cout, rank, 0 );
440  dbgprint.set_prefix( "[TempestOnlineMap]: " );
441  moab::ErrorCode rval;
442 
443  const bool m_bPointCloudSource = ( m_remapper->point_cloud_source );
444  const bool m_bPointCloudTarget = ( m_remapper->point_cloud_target );
445  const bool m_bPointCloud = m_bPointCloudSource || m_bPointCloudTarget;
446 
447  // Build a matrix of source and target discretization so that we know how
448  // to assign the global DoFs in parallel for the mapping weights.
449  // For example,
450  // for FV->FV: the rows represented target DoFs and cols represent source DoFs
451  try
452  {
453  // Check command line parameters (data type arguments)
454  STLStringHelper::ToLower( strInputType );
455  STLStringHelper::ToLower( strOutputType );
456 
457  DiscretizationType eInputType;
458  DiscretizationType eOutputType;
459 
460  if( strInputType == "fv" )
461  {
462  eInputType = DiscretizationType_FV;
463  }
464  else if( strInputType == "cgll" )
465  {
466  eInputType = DiscretizationType_CGLL;
467  }
468  else if( strInputType == "dgll" )
469  {
470  eInputType = DiscretizationType_DGLL;
471  }
472  else if( strInputType == "pcloud" )
473  {
474  eInputType = DiscretizationType_PCLOUD;
475  }
476  else
477  {
478  _EXCEPTION1( "Invalid \"in_type\" value (%s), expected [fv|cgll|dgll]", strInputType.c_str() );
479  }
480 
481  if( strOutputType == "fv" )
482  {
483  eOutputType = DiscretizationType_FV;
484  }
485  else if( strOutputType == "cgll" )
486  {
487  eOutputType = DiscretizationType_CGLL;
488  }
489  else if( strOutputType == "dgll" )
490  {
491  eOutputType = DiscretizationType_DGLL;
492  }
493  else if( strOutputType == "pcloud" )
494  {
495  eOutputType = DiscretizationType_PCLOUD;
496  }
497  else
498  {
499  _EXCEPTION1( "Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]", strOutputType.c_str() );
500  }
501 
502  // set all required input params
503  m_bConserved = !mapOptions.fNoConservation;
504  m_eInputType = eInputType;
505  m_eOutputType = eOutputType;
506 
507  // Method flags
508  std::string strMapAlgorithm( "" );
509  int nMonotoneType = ( mapOptions.fMonotone ) ? ( 1 ) : ( 0 );
510 
511  // Make an index of method arguments
512  std::set< std::string > setMethodStrings;
513  {
514  int iLast = 0;
515  for( size_t i = 0; i <= mapOptions.strMethod.length(); i++ )
516  {
517  if( ( i == mapOptions.strMethod.length() ) || ( mapOptions.strMethod[i] == ';' ) )
518  {
519  std::string strMethodString = mapOptions.strMethod.substr( iLast, i - iLast );
520  STLStringHelper::RemoveWhitespaceInPlace( strMethodString );
521  if( strMethodString.length() > 0 )
522  {
523  setMethodStrings.insert( strMethodString );
524  }
525  iLast = i + 1;
526  }
527  }
528  }
529 
530  for( auto it : setMethodStrings )
531  {
532  // Piecewise constant monotonicity
533  if( it == "mono2" )
534  {
535  if( nMonotoneType != 0 )
536  {
537  _EXCEPTIONT( "Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
538  }
540  {
541  _EXCEPTIONT( "--method \"mono2\" is only used when remapping to/from CGLL or DGLL grids" );
542  }
543  nMonotoneType = 2;
544 
545  // Piecewise linear monotonicity
546  }
547  else if( it == "mono3" )
548  {
549  if( nMonotoneType != 0 )
550  {
551  _EXCEPTIONT( "Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
552  }
554  {
555  _EXCEPTIONT( "--method \"mono3\" is only used when remapping to/from CGLL or DGLL grids" );
556  }
557  nMonotoneType = 3;
558 
559  // Volumetric remapping from FV to GLL
560  }
561  else if( it == "volumetric" )
562  {
564  {
565  _EXCEPTIONT( "--method \"volumetric\" may only be used for FV->CGLL or FV->DGLL remapping" );
566  }
567  strMapAlgorithm = "volumetric";
568 
569  // Inverse distance mapping
570  }
571  else if( it == "invdist" )
572  {
574  {
575  _EXCEPTIONT( "--method \"invdist\" may only be used for FV->FV remapping" );
576  }
577  strMapAlgorithm = "invdist";
578 
579  // Delaunay triangulation mapping
580  }
581  else if( it == "delaunay" )
582  {
584  {
585  _EXCEPTIONT( "--method \"delaunay\" may only be used for FV->FV remapping" );
586  }
587  strMapAlgorithm = "delaunay";
588 
589  // Bilinear
590  }
591  else if( it == "bilin" )
592  {
594  {
595  _EXCEPTIONT( "--method \"bilin\" may only be used for FV->FV remapping" );
596  }
597  strMapAlgorithm = "fvbilin";
598 
599  // Integrated bilinear (same as mono3 when source grid is CGLL/DGLL)
600  }
601  else if( it == "intbilin" )
602  {
604  {
605  _EXCEPTIONT( "--method \"intbilin\" may only be used when mapping to FV." );
606  }
608  {
609  strMapAlgorithm = "fvintbilin";
610  }
611  else
612  {
613  strMapAlgorithm = "mono3";
614  }
615 
616  // Integrated bilinear with generalized Barycentric coordinates
617  }
618  else if( it == "intbilingb" )
619  {
621  {
622  _EXCEPTIONT( "--method \"intbilingb\" may only be used for FV->FV remapping" );
623  }
624  strMapAlgorithm = "fvintbilingb";
625  }
626  else
627  {
628  _EXCEPTION1( "Invalid --method argument \"%s\"", it.c_str() );
629  }
630  }
631 
634  : mapOptions.nPin );
637  : mapOptions.nPout );
638 
639  // Set the source and target mesh objects
640  MB_CHK_ERR( SetDOFmapTags( srcDofTagName, tgtDofTagName ) );
641 
642  /// the tag should be created already in the e3sm workflow; if not, create it here
643  Tag areaTag;
644  rval = m_interface->tag_get_handle( "aream", 1, MB_TYPE_DOUBLE, areaTag,
646  if( MB_ALREADY_ALLOCATED == rval )
647  {
648  if( is_root ) dbgprint.printf( 0, "aream tag already defined \n" );
649  }
650 
651  double local_areas[3] = { 0.0, 0.0, 0.0 }, global_areas[3] = { 0.0, 0.0, 0.0 };
652  if( !m_bPointCloudSource )
653  {
654  // Calculate Input Mesh Face areas
655  if( is_root ) dbgprint.printf( 0, "Calculating input mesh Face areas\n" );
656  local_areas[0] = m_meshInput->CalculateFaceAreas( mapOptions.fSourceConcave );
657  // Set source element areas as tag on the source mesh
659 
660  // Update coverage source mesh areas as well.
661  m_meshInputCov->CalculateFaceAreas( mapOptions.fSourceConcave );
662  }
663 
664  if( !m_bPointCloudTarget )
665  {
666  // Calculate Output Mesh Face areas
667  if( is_root ) dbgprint.printf( 0, "Calculating output mesh Face areas\n" );
668  local_areas[1] = m_meshOutput->CalculateFaceAreas( mapOptions.fTargetConcave );
669  // Set target element areas as tag on the target mesh
671  }
672 
673  if( !m_bPointCloud )
674  {
675  // Verify that overlap mesh is in the correct order (sanity check)
676  assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->vecTargetFaceIx.size() );
677 
678  // Calculate Face areas
679  if( is_root ) dbgprint.printf( 0, "Calculating overlap mesh Face areas\n" );
680  local_areas[2] =
681  m_meshOverlap->CalculateFaceAreas( mapOptions.fSourceConcave || mapOptions.fTargetConcave );
682 
683  // store it as global output for now - used later in reduction
684  std::copy( local_areas, local_areas + 3, global_areas );
685 #ifdef MOAB_HAVE_MPI
686  // reduce the local source, target and overlap mesh areas to global areas
687  if( m_pcomm && is_parallel )
688  MPI_Reduce( local_areas, global_areas, 3, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
689 #endif
690  if( is_root )
691  {
692  dbgprint.printf( 0, "Input Mesh Geometric Area: %1.15e\n", global_areas[0] );
693  dbgprint.printf( 0, "Output Mesh Geometric Area: %1.15e\n", global_areas[1] );
694  dbgprint.printf( 0, "Overlap Mesh Recovered Area: %1.15e\n", global_areas[2] );
695  }
696 
697  // Correct areas to match the areas calculated in the overlap mesh
698  constexpr bool fCorrectAreas = true;
699  if( fCorrectAreas ) // In MOAB-TempestRemap, we will always keep this to be true
700  {
701  if( is_root ) dbgprint.printf( 0, "Correcting source/target areas to overlap mesh areas\n" );
702  DataArray1D< double > dSourceArea( m_meshInputCov->faces.size() );
703  DataArray1D< double > dTargetArea( m_meshOutput->faces.size() );
704 
705  assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->faces.size() );
706  assert( m_meshOverlap->vecTargetFaceIx.size() == m_meshOverlap->faces.size() );
707  assert( m_meshOverlap->vecFaceArea.GetRows() == m_meshOverlap->faces.size() );
708 
709  assert( m_meshInputCov->vecFaceArea.GetRows() == m_meshInputCov->faces.size() );
710  assert( m_meshOutput->vecFaceArea.GetRows() == m_meshOutput->faces.size() );
711 
712  for( size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
713  {
714  if( m_meshOverlap->vecSourceFaceIx[i] < 0 || m_meshOverlap->vecTargetFaceIx[i] < 0 )
715  continue; // skip this cell since it is ghosted
716 
717  // let us recompute the source/target areas based on overlap mesh areas
718  assert( static_cast< size_t >( m_meshOverlap->vecSourceFaceIx[i] ) < m_meshInputCov->faces.size() );
719  dSourceArea[m_meshOverlap->vecSourceFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
720  assert( static_cast< size_t >( m_meshOverlap->vecTargetFaceIx[i] ) < m_meshOutput->faces.size() );
721  dTargetArea[m_meshOverlap->vecTargetFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
722  }
723 
724  for( size_t i = 0; i < m_meshInputCov->faces.size(); i++ )
725  {
726  if( fabs( dSourceArea[i] - m_meshInputCov->vecFaceArea[i] ) < 1.0e-10 )
727  {
728  m_meshInputCov->vecFaceArea[i] = dSourceArea[i];
729  }
730  }
731  for( size_t i = 0; i < m_meshOutput->faces.size(); i++ )
732  {
733  if( fabs( dTargetArea[i] - m_meshOutput->vecFaceArea[i] ) < 1.0e-10 )
734  {
735  m_meshOutput->vecFaceArea[i] = dTargetArea[i];
736  }
737  }
738  }
739 
740  // Set source mesh areas in map
741  if( !m_bPointCloudSource && eInputType == DiscretizationType_FV )
742  {
743  this->SetSourceAreas( m_meshInputCov->vecFaceArea );
744  if( m_meshInputCov->vecMask.size() )
745  {
746  this->SetSourceMask( m_meshInputCov->vecMask );
747  }
748  }
749 
750  // Set target mesh areas in map
751  if( !m_bPointCloudTarget && eOutputType == DiscretizationType_FV )
752  {
753  this->SetTargetAreas( m_meshOutput->vecFaceArea );
754  if( m_meshOutput->vecMask.size() )
755  {
756  this->SetTargetMask( m_meshOutput->vecMask );
757  }
758  }
759 
760  /*
761  // Recalculate input mesh area from overlap mesh
762  if (fabs(dTotalAreaOverlap - dTotalAreaInput) > 1.0e-10) {
763  dbgprint.printf(0, "Overlap mesh only covers a sub-area of the sphere\n");
764  dbgprint.printf(0, "Recalculating source mesh areas\n");
765  dTotalAreaInput = m_meshInput->CalculateFaceAreasFromOverlap(m_meshOverlap);
766  dbgprint.printf(0, "New Input Mesh Geometric Area: %1.15e\n", dTotalAreaInput);
767  }
768  */
769  }
770 
771  // Finite volume input / Finite volume output
772  if( ( eInputType == DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
773  {
774  // Generate reverse node array and edge map
775  if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
776  if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap( false );
777 
778  // Initialize coordinates for map
779  this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
780  this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
781 
782  this->m_pdataGLLNodesIn = nullptr;
783  this->m_pdataGLLNodesOut = nullptr;
784 
785  // Finite volume input / Finite element output
786  rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin, false, nullptr, nullptr, eOutputType,
787  mapOptions.nPout, false, nullptr );MB_CHK_ERR( rval );
788 
789  // Construct remap for FV-FV
790  if( is_root ) dbgprint.printf( 0, "Calculating remap weights\n" );
791 
792  // Construct OfflineMap
793  if( strMapAlgorithm == "invdist" )
794  {
795  if( is_root ) dbgprint.printf( 0, "Calculating map (invdist)\n" );
796  if( m_meshInputCov->faces.size() )
797  LinearRemapFVtoFVInvDist( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
798  }
799  else if( strMapAlgorithm == "delaunay" )
800  {
801  if( is_root ) dbgprint.printf( 0, "Calculating map (delaunay)\n" );
802  if( m_meshInputCov->faces.size() )
803  LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
804  }
805  else if( strMapAlgorithm == "fvintbilin" )
806  {
807  if( is_root ) dbgprint.printf( 0, "Calculating map (intbilin)\n" );
808  if( m_meshInputCov->faces.size() )
809  LinearRemapIntegratedBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
810  }
811  else if( strMapAlgorithm == "fvintbilingb" )
812  {
813  if( is_root ) dbgprint.printf( 0, "Calculating map (intbilingb)\n" );
814  if( m_meshInputCov->faces.size() )
815  LinearRemapIntegratedGeneralizedBarycentric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
816  *this );
817  }
818  else if( strMapAlgorithm == "fvbilin" )
819  {
820 #ifdef VERBOSE
821  if( is_root )
822  {
823  m_meshInputCov->Write( "SourceMeshMBTR.g" );
824  m_meshOutput->Write( "TargetMeshMBTR.g" );
825  }
826  else
827  {
828  m_meshInputCov->Write( "SourceMeshMBTR" + std::to_string( rank ) + ".g" );
829  m_meshOutput->Write( "TargetMeshMBTR" + std::to_string( rank ) + ".g" );
830  }
831 #endif
832  if( is_root ) dbgprint.printf( 0, "Calculating map (bilin)\n" );
833  if( m_meshInputCov->faces.size() )
834  LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
835  }
836  else
837  {
838  if( is_root ) dbgprint.printf( 0, "Calculating conservative FV-FV map\n" );
839  if( m_meshInputCov->faces.size() )
840  {
841 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
842  LinearRemapFVtoFV( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
843  ( mapOptions.fMonotone ) ? ( 1 ) : ( mapOptions.nPin ), *this );
844 #else
845  LinearRemapFVtoFV_Tempest_MOAB( ( mapOptions.fMonotone ? 1 : mapOptions.nPin ) );
846 #endif
847  }
848  }
849  }
850  else if( eInputType == DiscretizationType_FV )
851  {
852  DataArray3D< double > dataGLLJacobian;
853 
854  if( is_root ) dbgprint.printf( 0, "Generating output mesh meta data\n" );
855  double dNumericalArea_loc = GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble,
856  dataGLLNodesDest, dataGLLJacobian );
857 
858  double dNumericalArea = dNumericalArea_loc;
859 #ifdef MOAB_HAVE_MPI
860  if( m_pcomm )
861  MPI_Reduce( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
862 #endif
863  if( is_root ) dbgprint.printf( 0, "Output Mesh Numerical Area: %1.15e\n", dNumericalArea );
864 
865  // Initialize coordinates for map
866  this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
867  this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
868 
869  this->m_pdataGLLNodesIn = nullptr;
870  this->m_pdataGLLNodesOut = &dataGLLNodesDest;
871 
872  // Generate the continuous Jacobian
873  bool fContinuous = ( eOutputType == DiscretizationType_CGLL );
874 
875  if( eOutputType == DiscretizationType_CGLL )
876  {
877  GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobian, this->GetTargetAreas() );
878  }
879  else
880  {
881  GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetTargetAreas() );
882  }
883 
884  // Generate reverse node array and edge map
885  if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
886  if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap( false );
887 
888  // Finite volume input / Finite element output
889  rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin, false, nullptr, nullptr, eOutputType,
890  mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
891  &dataGLLNodesDest );MB_CHK_ERR( rval );
892 
893  // Generate remap weights
894  if( strMapAlgorithm == "volumetric" )
895  {
896  if( is_root ) dbgprint.printf( 0, "Calculating remapping weights for FV->GLL (volumetric)\n" );
897  LinearRemapFVtoGLL_Volumetric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest,
898  dataGLLJacobian, this->GetTargetAreas(), mapOptions.nPin, *this,
899  nMonotoneType, fContinuous, mapOptions.fNoConservation );
900  }
901  else
902  {
903  if( is_root ) dbgprint.printf( 0, "Calculating remapping weights for FV->GLL\n" );
904  LinearRemapFVtoGLL( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest, dataGLLJacobian,
905  this->GetTargetAreas(), mapOptions.nPin, *this, nMonotoneType, fContinuous,
906  mapOptions.fNoConservation );
907  }
908  }
909  else if( ( eInputType == DiscretizationType_PCLOUD ) || ( eOutputType == DiscretizationType_PCLOUD ) )
910  {
911  DataArray3D< double > dataGLLJacobian;
912  if( !m_bPointCloudSource )
913  {
914  // Generate reverse node array and edge map
915  if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
916  if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap( false );
917 
918  // Initialize coordinates for map
919  if( eInputType == DiscretizationType_FV )
920  {
921  this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
922  }
923  else
924  {
925  if( is_root ) dbgprint.printf( 0, "Generating input mesh meta data\n" );
926  DataArray3D< double > dataGLLJacobianSrc;
927  GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
928  dataGLLJacobian );
929  GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
930  dataGLLJacobianSrc );
931  }
932  }
933  // else { /* Source is a point cloud dataset */ }
934 
935  if( !m_bPointCloudTarget )
936  {
937  // Generate reverse node array and edge map
938  if( m_meshOutput->revnodearray.size() == 0 ) m_meshOutput->ConstructReverseNodeArray();
939  if( m_meshOutput->edgemap.size() == 0 ) m_meshOutput->ConstructEdgeMap( false );
940 
941  // Initialize coordinates for map
942  if( eOutputType == DiscretizationType_FV )
943  {
944  this->InitializeSourceCoordinatesFromMeshFV( *m_meshOutput );
945  }
946  else
947  {
948  if( is_root ) dbgprint.printf( 0, "Generating output mesh meta data\n" );
949  GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
950  dataGLLJacobian );
951  }
952  }
953  // else { /* Target is a point cloud dataset */ }
954 
955  // Finite volume input / Finite element output
956  rval = this->SetDOFmapAssociation(
957  eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
958  ( m_bPointCloudSource || eInputType == DiscretizationType_FV ? nullptr : &dataGLLNodesSrcCov ),
959  ( m_bPointCloudSource || eInputType == DiscretizationType_FV ? nullptr : &dataGLLNodesSrc ),
960  eOutputType, mapOptions.nPout, ( eOutputType == DiscretizationType_CGLL ),
961  ( m_bPointCloudTarget ? nullptr : &dataGLLNodesDest ) );MB_CHK_ERR( rval );
962 
963  // Construct remap
964  if( is_root ) dbgprint.printf( 0, "Calculating remap weights with Nearest-Neighbor method\n" );
965  rval = LinearRemapNN_MOAB( true /*use_GID_matching*/, false /*strict_check*/ );MB_CHK_ERR( rval );
966  }
967  else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
968  {
969  DataArray3D< double > dataGLLJacobianSrc, dataGLLJacobian;
970 
971  if( is_root ) dbgprint.printf( 0, "Generating input mesh meta data\n" );
972  // generate metadata for the input meshes (both source and covering source)
973  GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
974  dataGLLJacobianSrc );
975  GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
976  dataGLLJacobian );
977 
978  if( dataGLLNodesSrcCov.GetSubColumns() != m_meshInputCov->faces.size() )
979  {
980  _EXCEPTIONT( "Number of element does not match between metadata and "
981  "input mesh" );
982  }
983 
984  // Initialize coordinates for map
985  this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
986  this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
987 
988  // Generate the continuous Jacobian for input mesh
989  bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
990 
991  if( eInputType == DiscretizationType_CGLL )
992  {
993  GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobian, this->GetSourceAreas() );
994  }
995  else
996  {
997  GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetSourceAreas() );
998  }
999 
1000  // Finite element input / Finite volume output
1001  rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
1002  &dataGLLNodesSrcCov, &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
1003  false, nullptr );MB_CHK_ERR( rval );
1004 
1005  // Generate remap
1006  if( is_root ) dbgprint.printf( 0, "Calculating remap weights\n" );
1007 
1008  if( strMapAlgorithm == "volumetric" )
1009  {
1010  _EXCEPTIONT( "Unimplemented: Volumetric currently unavailable for"
1011  "GLL input mesh" );
1012  }
1013 
1014  this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1015  this->m_pdataGLLNodesOut = nullptr;
1016 
1017 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1018  LinearRemapSE4( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov, dataGLLJacobian,
1019  nMonotoneType, fContinuousIn, mapOptions.fNoConservation, mapOptions.fSparseConstraints,
1020  *this );
1021 #else
1022  LinearRemapSE4_Tempest_MOAB( dataGLLNodesSrcCov, dataGLLJacobian, nMonotoneType, fContinuousIn,
1023  mapOptions.fNoConservation );
1024 #endif
1025  }
1026  else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType != DiscretizationType_FV ) )
1027  {
1028  DataArray3D< double > dataGLLJacobianIn, dataGLLJacobianSrc;
1029  DataArray3D< double > dataGLLJacobianOut;
1030 
1031  // Input metadata
1032  if( is_root ) dbgprint.printf( 0, "Generating input mesh meta data\n" );
1033  // generate metadata for the input meshes (both source and covering source)
1034  GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
1035  dataGLLJacobianSrc );
1036  // now coverage
1037  GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
1038  dataGLLJacobianIn );
1039  // Output metadata
1040  if( is_root ) dbgprint.printf( 0, "Generating output mesh meta data\n" );
1041  GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
1042  dataGLLJacobianOut );
1043 
1044  // Initialize coordinates for map
1045  this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
1046  this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
1047 
1048  // Generate the continuous Jacobian for input mesh
1049  bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
1050 
1051  if( eInputType == DiscretizationType_CGLL )
1052  {
1053  GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobianIn, this->GetSourceAreas() );
1054  }
1055  else
1056  {
1057  GenerateDiscontinuousJacobian( dataGLLJacobianIn, this->GetSourceAreas() );
1058  }
1059 
1060  // Generate the continuous Jacobian for output mesh
1061  bool fContinuousOut = ( eOutputType == DiscretizationType_CGLL );
1062 
1063  if( eOutputType == DiscretizationType_CGLL )
1064  {
1065  GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianOut, this->GetTargetAreas() );
1066  }
1067  else
1068  {
1069  GenerateDiscontinuousJacobian( dataGLLJacobianOut, this->GetTargetAreas() );
1070  }
1071 
1072  // Input Finite Element to Output Finite Element
1073  rval = this->SetDOFmapAssociation( eInputType, mapOptions.nPin, ( eInputType == DiscretizationType_CGLL ),
1074  &dataGLLNodesSrcCov, &dataGLLNodesSrc, eOutputType, mapOptions.nPout,
1075  ( eOutputType == DiscretizationType_CGLL ), &dataGLLNodesDest );MB_CHK_ERR( rval );
1076 
1077  this->m_pdataGLLNodesIn = &dataGLLNodesSrcCov;
1078  this->m_pdataGLLNodesOut = &dataGLLNodesDest;
1079 
1080  // Generate remap
1081  if( is_root ) dbgprint.printf( 0, "Calculating remap weights\n" );
1082 
1083 #ifdef USE_NATIVE_TEMPESTREMAP_ROUTINES
1084  LinearRemapGLLtoGLL_Integrated( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesSrcCov,
1085  dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1086  this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1087  fContinuousIn, fContinuousOut, mapOptions.fSparseConstraints, *this );
1088 #else
1089  LinearRemapGLLtoGLL2_MOAB( dataGLLNodesSrcCov, dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
1090  this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
1091  fContinuousIn, fContinuousOut, mapOptions.fNoConservation );
1092 #endif
1093  }
1094  else
1095  {
1096  _EXCEPTIONT( "Not implemented" );
1097  }
1098 
1099 #ifdef MOAB_HAVE_EIGEN3
1100  copy_tempest_sparsemat_to_eigen3();
1101 #endif
1102 
1103 #ifdef MOAB_HAVE_MPI
1104  {
1105  // Remove ghosted entities from overlap set
1106  moab::Range ghostedEnts;
1107  rval = m_remapper->GetOverlapAugmentedEntities( ghostedEnts );MB_CHK_ERR( rval );
1109  rval = m_interface->remove_entities( m_meshOverlapSet, ghostedEnts );MB_CHK_SET_ERR( rval, "Deleting ghosted entities failed" );
1110  }
1111 #endif
1112  // Verify consistency, conservation and monotonicity, globally
1113  if( !mapOptions.fNoCheck )
1114  {
1115  if( is_root ) dbgprint.printf( 0, "Verifying map" );
1116  this->IsConsistent( 1.0e-8 );
1117  if( !mapOptions.fNoConservation ) this->IsConservative( 1.0e-8 );
1118 
1119  if( nMonotoneType != 0 )
1120  {
1121  this->IsMonotone( 1.0e-12 );
1122  }
1123  }
1124  }
1125  catch( Exception& e )
1126  {
1127  dbgprint.printf( 0, "%s", e.ToString().c_str() );
1128  return ( moab::MB_FAILURE );
1129  }
1130  catch( ... )
1131  {
1132  return ( moab::MB_FAILURE );
1133  }
1134  return moab::MB_SUCCESS;
1135 }

References dbgprint, moab::error(), ErrorCode, MB_ALREADY_ALLOCATED, MB_CHK_ERR, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TAG_EXCL, MB_TYPE_DOUBLE, and moab::Remapper::OverlapMesh.

Referenced by main().

◆ GetColGlobalDoF()

int moab::TempestOnlineMap::GetColGlobalDoF ( int  localID) const
inline

Get the global Degrees-Of-Freedom ID on the source mesh.

Definition at line 567 of file TempestOnlineMap.hpp.

568 {
569  return col_gdofmap[localColID];
570 }

◆ GetDestinationGlobalNDofs()

int moab::TempestOnlineMap::GetDestinationGlobalNDofs ( )

Get the number of total Degrees-Of-Freedom defined on the destination mesh.

◆ GetDestinationLocalNDofs()

int moab::TempestOnlineMap::GetDestinationLocalNDofs ( )

Get the number of local Degrees-Of-Freedom defined on the destination mesh.

◆ GetDestinationNDofsPerElement()

int moab::TempestOnlineMap::GetDestinationNDofsPerElement ( )
inline

Get the number of Degrees-Of-Freedom per element on the destination mesh.

Definition at line 585 of file TempestOnlineMap.hpp.

586 {
587  return m_nDofsPEl_Dest;
588 }

◆ GetGlobalSourceAreas()

const DataArray1D< double >& moab::TempestOnlineMap::GetGlobalSourceAreas ( ) const

If we computed the reduction, get the vector representing the source areas for all entities in the mesh

◆ GetGlobalTargetAreas()

const DataArray1D< double >& moab::TempestOnlineMap::GetGlobalTargetAreas ( ) const

If we computed the reduction, get the vector representing the target areas for all entities in the mesh

◆ GetIndexOfColGlobalDoF()

int moab::TempestOnlineMap::GetIndexOfColGlobalDoF ( int  globalColDoF) const
inline

Get the index of globaColDoF.

Definition at line 572 of file TempestOnlineMap.hpp.

573 {
574  return globalColDoF + 1; // temporary
575 }

◆ GetIndexOfRowGlobalDoF()

int moab::TempestOnlineMap::GetIndexOfRowGlobalDoF ( int  globalRowDoF) const
inline

Get the index of globaRowDoF.

Definition at line 561 of file TempestOnlineMap.hpp.

562 {
563  return globalRowDoF + 1;
564 }

◆ GetRowGlobalDoF()

int moab::TempestOnlineMap::GetRowGlobalDoF ( int  localID) const
inline

Get the global Degrees-Of-Freedom ID on the destination mesh.

Definition at line 556 of file TempestOnlineMap.hpp.

557 {
558  return row_gdofmap[localRowID];
559 }

◆ GetSourceGlobalNDofs()

int moab::TempestOnlineMap::GetSourceGlobalNDofs ( )

Get the number of total Degrees-Of-Freedom defined on the source mesh.

◆ GetSourceLocalNDofs()

int moab::TempestOnlineMap::GetSourceLocalNDofs ( )

Get the number of local Degrees-Of-Freedom defined on the source mesh.

◆ GetSourceNDofsPerElement()

int moab::TempestOnlineMap::GetSourceNDofsPerElement ( )
inline

Get the number of Degrees-Of-Freedom per element on the source mesh.

Definition at line 578 of file TempestOnlineMap.hpp.

579 {
580  return m_nDofsPEl_Src;
581 }

◆ IsConservative()

int moab::TempestOnlineMap::IsConservative ( double  dTolerance)
virtual

Determine if the map is conservative.

Definition at line 1185 of file TempestOnlineMap.cpp.

1186 {
1187 #ifndef MOAB_HAVE_MPI
1188 
1189  return OfflineMap::IsConservative( dTolerance );
1190 
1191 #else
1192  // return OfflineMap::IsConservative(dTolerance);
1193 
1194  int ierr;
1195  // Get map entries
1196  DataArray1D< int > dataRows;
1197  DataArray1D< int > dataCols;
1198  DataArray1D< double > dataEntries;
1199  const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
1200  const DataArray1D< double >& dSourceAreas = this->GetSourceAreas();
1201 
1202  // Calculate column sums
1203  std::vector< int > dColumnsUnique;
1204  std::vector< double > dColumnSums;
1205 
1206  int nColumns = m_mapRemap.GetColumns();
1207  m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1208  dColumnSums.resize( m_nTotDofs_SrcCov, 0.0 );
1209  dColumnsUnique.resize( m_nTotDofs_SrcCov, -1 );
1210 
1211  for( unsigned i = 0; i < dataEntries.GetRows(); i++ )
1212  {
1213  dColumnSums[dataCols[i]] += dataEntries[i] * dTargetAreas[dataRows[i]] / dSourceAreas[dataCols[i]];
1214 
1215  assert( dataCols[i] < m_nTotDofs_SrcCov );
1216 
1217  // GID for column DoFs: col_gdofmap[ col_ldofmap [ dataCols[i] ] ]
1218  int colGID = this->GetColGlobalDoF( dataCols[i] ); // col_gdofmap[ col_ldofmap [ dataCols[i] ] ];
1219  // int colGID = col_gdofmap[ col_ldofmap [ dataCols[i] ] ];
1220  dColumnsUnique[dataCols[i]] = colGID;
1221 
1222  // std::cout << "Column dataCols[i]=" << dataCols[i] << " with GID = " << colGID <<
1223  // std::endl;
1224  }
1225 
1226  int rootProc = 0;
1227  std::vector< int > nElementsInProc;
1228  const int nDATA = 3;
1229  nElementsInProc.resize( size * nDATA );
1230  int senddata[nDATA] = { nColumns, m_nTotDofs_SrcCov, m_nTotDofs_Src };
1231  ierr = MPI_Gather( senddata, nDATA, MPI_INT, nElementsInProc.data(), nDATA, MPI_INT, rootProc, m_pcomm->comm() );
1232  if( ierr != MPI_SUCCESS ) return -1;
1233 
1234  int nTotVals = 0, nTotColumns = 0, nTotColumnsUnq = 0;
1235  std::vector< int > dColumnIndices;
1236  std::vector< double > dColumnSourceAreas;
1237  std::vector< double > dColumnSumsTotal;
1238  std::vector< int > displs, rcount;
1239  if( rank == rootProc )
1240  {
1241  displs.resize( size + 1, 0 );
1242  rcount.resize( size, 0 );
1243  int gsum = 0;
1244  for( int ir = 0; ir < size; ++ir )
1245  {
1246  nTotVals += nElementsInProc[ir * nDATA];
1247  nTotColumns += nElementsInProc[ir * nDATA + 1];
1248  nTotColumnsUnq += nElementsInProc[ir * nDATA + 2];
1249 
1250  displs[ir] = gsum;
1251  rcount[ir] = nElementsInProc[ir * nDATA + 1];
1252  gsum += rcount[ir];
1253 
1254  // printf( "%d: nTotColumns: %d, Displs: %d, rcount: %d, gsum = %d\n", ir, nTotColumns, displs[ir], rcount[ir], gsum );
1255  }
1256 
1257  printf( "Total nnz: %d, global source elements = %d\n", nTotVals, gsum );
1258 
1259  dColumnIndices.resize( nTotColumns, -1 );
1260  dColumnSumsTotal.resize( nTotColumns, 0.0 );
1261  // dColumnSourceAreas.resize ( nTotColumns, 0.0 );
1262  }
1263 
1264  // Gather all ColumnSums to root process and accumulate
1265  // We expect that the sums of all columns equate to 1.0 within user specified tolerance
1266  // Need to do a gatherv here since different processes have different number of elements
1267  // MPI_Reduce(&dColumnSums[0], &dColumnSumsTotal[0], m_mapRemap.GetColumns(), MPI_DOUBLE,
1268  // MPI_SUM, 0, m_pcomm->comm());
1269  ierr = MPI_Gatherv( &dColumnsUnique[0], m_nTotDofs_SrcCov, MPI_INT, &dColumnIndices[0], rcount.data(),
1270  displs.data(), MPI_INT, rootProc, m_pcomm->comm() );
1271  if( ierr != MPI_SUCCESS ) return -1;
1272  ierr = MPI_Gatherv( &dColumnSums[0], m_nTotDofs_SrcCov, MPI_DOUBLE, &dColumnSumsTotal[0], rcount.data(),
1273  displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() );
1274  if( ierr != MPI_SUCCESS ) return -1;
1275  // ierr = MPI_Gatherv ( &dSourceAreas[0], m_nTotDofs_SrcCov, MPI_DOUBLE, &dColumnSourceAreas[0],
1276  // rcount.data(), displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() ); if ( ierr !=
1277  // MPI_SUCCESS ) return -1;
1278 
1279  // Clean out unwanted arrays now
1280  dColumnSums.clear();
1281  dColumnsUnique.clear();
1282 
1283  // Verify all column sums equal the input Jacobian
1284  int fConservative = 0;
1285  if( rank == rootProc )
1286  {
1287  displs[size] = ( nTotColumns );
1288  // std::vector<double> dColumnSumsOnRoot(nTotColumnsUnq, 0.0);
1289  std::map< int, double > dColumnSumsOnRoot;
1290  // std::map<int, double> dColumnSourceAreasOnRoot;
1291  for( int ir = 0; ir < size; ir++ )
1292  {
1293  for( int ips = displs[ir]; ips < displs[ir + 1]; ips++ )
1294  {
1295  if( dColumnIndices[ips] < 0 ) continue;
1296  // printf("%d, %d: dColumnIndices[ips]: %d\n", ir, ips, dColumnIndices[ips]);
1297  assert( dColumnIndices[ips] < nTotColumnsUnq );
1298  dColumnSumsOnRoot[dColumnIndices[ips]] += dColumnSumsTotal[ips]; // / dColumnSourceAreas[ips];
1299  // dColumnSourceAreasOnRoot[ dColumnIndices[ips] ] = dColumnSourceAreas[ips];
1300  // dColumnSourceAreas[ dColumnIndices[ips] ]
1301  }
1302  }
1303 
1304  for( std::map< int, double >::iterator it = dColumnSumsOnRoot.begin(); it != dColumnSumsOnRoot.end(); ++it )
1305  {
1306  // if ( fabs ( it->second - dColumnSourceAreasOnRoot[it->first] ) > dTolerance )
1307  if( fabs( it->second - 1.0 ) > dTolerance )
1308  {
1309  fConservative++;
1310  Announce( "TempestOnlineMap is not conservative in column "
1311  // "%i (%1.15e)", it->first, it->second );
1312  "%i (%1.15e)",
1313  it->first, it->second /* / dColumnSourceAreasOnRoot[it->first] */ );
1314  }
1315  }
1316  }
1317 
1318  // TODO: Just do a broadcast from root instead of a reduction
1319  ierr = MPI_Bcast( &fConservative, 1, MPI_INT, rootProc, m_pcomm->comm() );
1320  if( ierr != MPI_SUCCESS ) return -1;
1321 
1322  return fConservative;
1323 #endif
1324 }

References size.

◆ IsConsistent()

int moab::TempestOnlineMap::IsConsistent ( double  dTolerance)
virtual

Determine if the map is first-order accurate.

Definition at line 1139 of file TempestOnlineMap.cpp.

1140 {
1141 #ifndef MOAB_HAVE_MPI
1142 
1143  return OfflineMap::IsConsistent( dTolerance );
1144 
1145 #else
1146 
1147  // Get map entries
1148  DataArray1D< int > dataRows;
1149  DataArray1D< int > dataCols;
1150  DataArray1D< double > dataEntries;
1151 
1152  // Calculate row sums
1153  DataArray1D< double > dRowSums;
1154  m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1155  dRowSums.Allocate( m_mapRemap.GetRows() );
1156 
1157  for( unsigned i = 0; i < dataRows.GetRows(); i++ )
1158  {
1159  dRowSums[dataRows[i]] += dataEntries[i];
1160  }
1161 
1162  // Verify all row sums are equal to 1
1163  int fConsistent = 0;
1164  for( unsigned i = 0; i < dRowSums.GetRows(); i++ )
1165  {
1166  if( fabs( dRowSums[i] - 1.0 ) > dTolerance )
1167  {
1168  fConsistent++;
1169  int rowGID = row_gdofmap[i];
1170  Announce( "TempestOnlineMap is not consistent in row %i (%1.15e)", rowGID, dRowSums[i] );
1171  }
1172  }
1173 
1174  int ierr;
1175  int fConsistentGlobal = 0;
1176  ierr = MPI_Allreduce( &fConsistent, &fConsistentGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1177  if( ierr != MPI_SUCCESS ) return -1;
1178 
1179  return fConsistentGlobal;
1180 #endif
1181 }

◆ IsMonotone()

int moab::TempestOnlineMap::IsMonotone ( double  dTolerance)
virtual

Determine if the map is monotone.

Definition at line 1328 of file TempestOnlineMap.cpp.

1329 {
1330 #ifndef MOAB_HAVE_MPI
1331 
1332  return OfflineMap::IsMonotone( dTolerance );
1333 
1334 #else
1335 
1336  // Get map entries
1337  DataArray1D< int > dataRows;
1338  DataArray1D< int > dataCols;
1339  DataArray1D< double > dataEntries;
1340 
1341  m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
1342 
1343  // Verify all entries are in the range [0,1]
1344  int fMonotone = 0;
1345  for( unsigned i = 0; i < dataRows.GetRows(); i++ )
1346  {
1347  if( ( dataEntries[i] < -dTolerance ) || ( dataEntries[i] > 1.0 + dTolerance ) )
1348  {
1349  fMonotone++;
1350 
1351  Announce( "TempestOnlineMap is not monotone in entry (%i): %1.15e", i, dataEntries[i] );
1352  }
1353  }
1354 
1355  int ierr;
1356  int fMonotoneGlobal = 0;
1357  ierr = MPI_Allreduce( &fMonotone, &fMonotoneGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
1358  if( ierr != MPI_SUCCESS ) return -1;
1359 
1360  return fMonotoneGlobal;
1361 #endif
1362 }

◆ LinearRemapFVtoFV_Tempest_MOAB()

void moab::TempestOnlineMap::LinearRemapFVtoFV_Tempest_MOAB ( int  nOrder)
private

Compute the remapping weights for a FV field defined on the source to a FV field defined on the target mesh.

Definition at line 121 of file TempestLinearRemap.cpp.

122 {
123  // Order of triangular quadrature rule
124  const int TriQuadRuleOrder = 4;
125 
126  // Verify ReverseNodeArray has been calculated
127  if( m_meshInputCov->faces.size() > 0 && m_meshInputCov->revnodearray.size() == 0 )
128  {
129  _EXCEPTIONT( "ReverseNodeArray has not been calculated for m_meshInputCov" );
130  }
131 
132  // Triangular quadrature rule
133  TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
134 
135  // Number of coefficients needed at this order
136 #ifdef RECTANGULAR_TRUNCATION
137  int nCoefficients = nOrder * nOrder;
138 #endif
139 #ifdef TRIANGULAR_TRUNCATION
140  int nCoefficients = nOrder * ( nOrder + 1 ) / 2;
141 #endif
142 
143  // Number of faces you need
144  const int nRequiredFaceSetSize = nCoefficients;
145 
146  // Fit weight exponent
147  const int nFitWeightsExponent = nOrder + 2;
148 
149  // Announcements
150  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
151  dbgprint.set_prefix( "[LinearRemapFVtoFV_Tempest_MOAB]: " );
152  if( is_root )
153  {
154  dbgprint.printf( 0, "Finite Volume to Finite Volume Projection\n" );
155  dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
156  dbgprint.printf( 0, "Number of coefficients: %i\n", nCoefficients );
157  dbgprint.printf( 0, "Required adjacency set size: %i\n", nRequiredFaceSetSize );
158  dbgprint.printf( 0, "Fit weights exponent: %i\n", nFitWeightsExponent );
159  }
160 
161  // Current overlap face
162  int ixOverlap = 0;
163 #ifdef VERBOSE
164  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
165 #endif
166  DataArray2D< double > dIntArray;
167  DataArray1D< double > dConstraint( nCoefficients );
168 
169  // Loop through all faces on m_meshInputCov
170  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
171  {
172  // Output every 1000 elements
173 #ifdef VERBOSE
174  if( ixFirst % outputFrequency == 0 && is_root )
175  {
176  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
177  }
178 #endif
179  // Find the set of Faces that overlap faceFirst
180  int ixOverlapBegin = ixOverlap;
181  unsigned ixOverlapEnd = ixOverlapBegin;
182 
183  for( ; ixOverlapEnd < m_meshOverlap->faces.size(); ixOverlapEnd++ )
184  {
185  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapEnd] != 0 ) break;
186  }
187 
188  unsigned nOverlapFaces = ixOverlapEnd - ixOverlapBegin;
189 
190  if( nOverlapFaces == 0 ) continue;
191 
192  // Build integration array
193  BuildIntegrationArray( *m_meshInputCov, *m_meshOverlap, triquadrule, ixFirst, ixOverlapBegin, ixOverlapEnd,
194  nOrder, dIntArray );
195 
196  // Set of Faces to use in building the reconstruction and associated
197  // distance metric.
198  AdjacentFaceVector vecAdjFaces;
199 
200  GetAdjacentFaceVectorByEdge( *m_meshInputCov, ixFirst, nRequiredFaceSetSize, vecAdjFaces );
201 
202  // Number of adjacent Faces
203  int nAdjFaces = vecAdjFaces.size();
204 
205  // Determine the conservative constraint equation
206  double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];
207  dConstraint.Zero();
208  for( int p = 0; p < nCoefficients; p++ )
209  {
210  for( unsigned j = 0; j < nOverlapFaces; j++ )
211  {
212  dConstraint[p] += dIntArray[p][j];
213  }
214  dConstraint[p] /= dFirstArea;
215  }
216 
217  // Build the fit array from the integration operator
218  DataArray2D< double > dFitArray;
219  DataArray1D< double > dFitWeights;
220  DataArray2D< double > dFitArrayPlus;
221 
222  BuildFitArray( *m_meshInputCov, triquadrule, ixFirst, vecAdjFaces, nOrder, nFitWeightsExponent, dConstraint,
223  dFitArray, dFitWeights );
224 
225  // Compute the inverse fit array
226  bool fSuccess = InvertFitArray_Corrected( dConstraint, dFitArray, dFitWeights, dFitArrayPlus );
227 
228  // Multiply integration array and fit array
229  DataArray2D< double > dComposedArray( nAdjFaces, nOverlapFaces );
230  if( fSuccess )
231  {
232  // Multiply integration array and inverse fit array
233  for( int i = 0; i < nAdjFaces; i++ )
234  {
235  for( size_t j = 0; j < nOverlapFaces; j++ )
236  {
237  for( int k = 0; k < nCoefficients; k++ )
238  {
239  dComposedArray( i, j ) += dIntArray( k, j ) * dFitArrayPlus( i, k );
240  }
241  }
242  }
243 
244  // Unable to invert fit array, drop to 1st order. In this case
245  // dFitArrayPlus(0,0) = 1 and all other entries are zero.
246  }
247  else
248  {
249  dComposedArray.Zero();
250  for( size_t j = 0; j < nOverlapFaces; j++ )
251  {
252  dComposedArray( 0, j ) += dIntArray( 0, j );
253  }
254  }
255 
256  // Put composed array into map
257  for( unsigned i = 0; i < vecAdjFaces.size(); i++ )
258  {
259  for( unsigned j = 0; j < nOverlapFaces; j++ )
260  {
261  int& ixFirstFaceLoc = vecAdjFaces[i].first;
262  int& ixSecondFaceLoc = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
263  // int ixFirstFaceGlob = m_remapper->GetGlobalID(moab::Remapper::SourceMesh,
264  // ixFirstFaceLoc); int ixSecondFaceGlob =
265  // m_remapper->GetGlobalID(moab::Remapper::TargetMesh, ixSecondFaceLoc);
266 
267  // signal to not participate, because it is a ghost target
268  if( ixSecondFaceLoc < 0 ) continue; // do not do anything
269 
270  m_mapRemap( ixSecondFaceLoc, ixFirstFaceLoc ) +=
271  dComposedArray[i][j] / m_meshOutput->vecFaceArea[ixSecondFaceLoc];
272  }
273  }
274 
275  // Increment the current overlap index
276  ixOverlap += nOverlapFaces;
277  }
278 
279  return;
280 }

References dbgprint.

◆ LinearRemapFVtoGLL_MOAB()

void moab::TempestOnlineMap::LinearRemapFVtoGLL_MOAB ( const DataArray3D< int > &  dataGLLNodes,
const DataArray3D< double > &  dataGLLJacobian,
const DataArray1D< double > &  dataGLLNodalArea,
int  nOrder,
int  nMonotoneType,
bool  fContinuous,
bool  fNoConservation 
)
private

Generate the OfflineMap for remapping from finite volumes to finite elements.

◆ LinearRemapGLLtoGLL2_MOAB()

void moab::TempestOnlineMap::LinearRemapGLLtoGLL2_MOAB ( const DataArray3D< int > &  dataGLLNodesIn,
const DataArray3D< double > &  dataGLLJacobianIn,
const DataArray3D< int > &  dataGLLNodesOut,
const DataArray3D< double > &  dataGLLJacobianOut,
const DataArray1D< double > &  dataNodalAreaOut,
int  nPin,
int  nPout,
int  nMonotoneType,
bool  fContinuousIn,
bool  fContinuousOut,
bool  fNoConservation 
)
private

Generate the OfflineMap for remapping from finite elements to finite elements.

Definition at line 1583 of file TempestLinearRemap.cpp.

1594 {
1595  // Triangular quadrature rule
1596  TriangularQuadratureRule triquadrule( 8 );
1597 
1598  const DataArray2D< double >& dG = triquadrule.GetG();
1599  const DataArray1D< double >& dW = triquadrule.GetW();
1600 
1601  // Get SparseMatrix represntation of the OfflineMap
1602  SparseMatrix< double >& smatMap = this->GetSparseMatrix();
1603 
1604  // Sample coefficients
1605  DataArray2D< double > dSampleCoeffIn( nPin, nPin );
1606  DataArray2D< double > dSampleCoeffOut( nPout, nPout );
1607 
1608  // Announcemnets
1609  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
1610  dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_MOAB]: " );
1611  if( is_root )
1612  {
1613  dbgprint.printf( 0, "Finite Element to Finite Element Projection\n" );
1614  dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
1615  dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
1616  }
1617 
1618  // Build the integration array for each element on m_meshOverlap
1619  DataArray3D< double > dGlobalIntArray( nPin * nPin, m_meshOverlap->faces.size(), nPout * nPout );
1620 
1621  // Number of overlap Faces per source Face
1622  DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
1623 
1624  int ixOverlap = 0;
1625  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1626  {
1627  // Determine how many overlap Faces and triangles are present
1628  int nOverlapFaces = 0;
1629  size_t ixOverlapTemp = ixOverlap;
1630  for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
1631  {
1632  // const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
1633  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 )
1634  {
1635  break;
1636  }
1637 
1638  nOverlapFaces++;
1639  }
1640 
1641  nAllOverlapFaces[ixFirst] = nOverlapFaces;
1642 
1643  // Increment the current overlap index
1644  ixOverlap += nAllOverlapFaces[ixFirst];
1645  }
1646 
1647  // Geometric area of each output node
1648  DataArray2D< double > dGeometricOutputArea( m_meshOutput->faces.size(), nPout * nPout );
1649 
1650  // Area of each overlap element in the output basis
1651  DataArray2D< double > dOverlapOutputArea( m_meshOverlap->faces.size(), nPout * nPout );
1652 
1653  // Loop through all faces on m_meshInputCov
1654  ixOverlap = 0;
1655 #ifdef VERBOSE
1656  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
1657 #endif
1658  if( is_root ) dbgprint.printf( 0, "Building conservative distribution maps\n" );
1659 
1660  // generic triangle used for area computation, for triangles around the center of overlap face;
1661  // used for overlap faces with more than 4 edges;
1662  // nodes array will be set for each triangle;
1663  // these triangles are not part of the mesh structure, they are just temporary during
1664  // aforementioned decomposition.
1665  Face faceTri( 3 );
1666  NodeVector nodes( 3 );
1667  faceTri.SetNode( 0, 0 );
1668  faceTri.SetNode( 1, 1 );
1669  faceTri.SetNode( 2, 2 );
1670 
1671  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1672  {
1673 #ifdef VERBOSE
1674  // Announce computation progress
1675  if( ixFirst % outputFrequency == 0 && is_root )
1676  {
1677  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
1678  }
1679 #endif
1680  // Quantities from the First Mesh
1681  const Face& faceFirst = m_meshInputCov->faces[ixFirst];
1682 
1683  const NodeVector& nodesFirst = m_meshInputCov->nodes;
1684 
1685  // Number of overlapping Faces and triangles
1686  int nOverlapFaces = nAllOverlapFaces[ixFirst];
1687 
1688  if( !nOverlapFaces ) continue;
1689 
1690  // // Calculate total element Jacobian
1691  // double dTotalJacobian = 0.0;
1692  // for (int s = 0; s < nPin; s++) {
1693  // for (int t = 0; t < nPin; t++) {
1694  // dTotalJacobian += dataGLLJacobianIn[s][t][ixFirst];
1695  // }
1696  // }
1697 
1698  // Loop through all Overlap Faces
1699  for( int i = 0; i < nOverlapFaces; i++ )
1700  {
1701  // Quantities from the overlap Mesh
1702  const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + i];
1703 
1704  const NodeVector& nodesOverlap = m_meshOverlap->nodes;
1705 
1706  // Quantities from the Second Mesh
1707  int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1708 
1709  // signal to not participate, because it is a ghost target
1710  if( ixSecond < 0 ) continue; // do not do anything
1711 
1712  const NodeVector& nodesSecond = m_meshOutput->nodes;
1713 
1714  const Face& faceSecond = m_meshOutput->faces[ixSecond];
1715 
1716  int nbEdges = faceOverlap.edges.size();
1717  int nOverlapTriangles = 1;
1718  Node center; // not used if nbEdges == 3
1719  if( nbEdges > 3 )
1720  { // decompose from center in this case
1721  nOverlapTriangles = nbEdges;
1722  for( int k = 0; k < nbEdges; k++ )
1723  {
1724  const Node& node = nodesOverlap[faceOverlap[k]];
1725  center = center + node;
1726  }
1727  center = center / nbEdges;
1728  center = center.Normalized(); // project back on sphere of radius 1
1729  }
1730 
1731  Node node0, node1, node2;
1732  double dTriArea;
1733 
1734  // Loop over all sub-triangles of this Overlap Face
1735  for( int j = 0; j < nOverlapTriangles; j++ )
1736  {
1737  if( nbEdges == 3 ) // will come here only once, nOverlapTriangles == 1 in this case
1738  {
1739  node0 = nodesOverlap[faceOverlap[0]];
1740  node1 = nodesOverlap[faceOverlap[1]];
1741  node2 = nodesOverlap[faceOverlap[2]];
1742  dTriArea = CalculateFaceArea( faceOverlap, nodesOverlap );
1743  }
1744  else // decompose polygon in triangles around the center
1745  {
1746  node0 = center;
1747  node1 = nodesOverlap[faceOverlap[j]];
1748  int j1 = ( j + 1 ) % nbEdges;
1749  node2 = nodesOverlap[faceOverlap[j1]];
1750  nodes[0] = center;
1751  nodes[1] = node1;
1752  nodes[2] = node2;
1753  dTriArea = CalculateFaceArea( faceTri, nodes );
1754  }
1755 
1756  for( int k = 0; k < triquadrule.GetPoints(); k++ )
1757  {
1758  // Get the nodal location of this point
1759  double dX[3];
1760 
1761  dX[0] = dG( k, 0 ) * node0.x + dG( k, 1 ) * node1.x + dG( k, 2 ) * node2.x;
1762  dX[1] = dG( k, 0 ) * node0.y + dG( k, 1 ) * node1.y + dG( k, 2 ) * node2.y;
1763  dX[2] = dG( k, 0 ) * node0.z + dG( k, 1 ) * node1.z + dG( k, 2 ) * node2.z;
1764 
1765  double dMag = sqrt( dX[0] * dX[0] + dX[1] * dX[1] + dX[2] * dX[2] );
1766 
1767  dX[0] /= dMag;
1768  dX[1] /= dMag;
1769  dX[2] /= dMag;
1770 
1771  Node nodeQuadrature( dX[0], dX[1], dX[2] );
1772 
1773  // Find the components of this quadrature point in the basis
1774  // of the first Face.
1775  double dAlphaIn;
1776  double dBetaIn;
1777 
1778  ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlphaIn, dBetaIn );
1779 
1780  // Find the components of this quadrature point in the basis
1781  // of the second Face.
1782  double dAlphaOut;
1783  double dBetaOut;
1784 
1785  ApplyInverseMap( faceSecond, nodesSecond, nodeQuadrature, dAlphaOut, dBetaOut );
1786 
1787  /*
1788  // Check inverse map value
1789  if ((dAlphaIn < 0.0) || (dAlphaIn > 1.0) ||
1790  (dBetaIn < 0.0) || (dBetaIn > 1.0)
1791  ) {
1792  _EXCEPTION2("Inverse Map out of range (%1.5e %1.5e)",
1793  dAlphaIn, dBetaIn);
1794  }
1795 
1796  // Check inverse map value
1797  if ((dAlphaOut < 0.0) || (dAlphaOut > 1.0) ||
1798  (dBetaOut < 0.0) || (dBetaOut > 1.0)
1799  ) {
1800  _EXCEPTION2("Inverse Map out of range (%1.5e %1.5e)",
1801  dAlphaOut, dBetaOut);
1802  }
1803  */
1804  // Sample the First finite element at this point
1805  SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
1806 
1807  // Sample the Second finite element at this point
1808  SampleGLLFiniteElement( nMonotoneType, nPout, dAlphaOut, dBetaOut, dSampleCoeffOut );
1809 
1810  // Overlap output area
1811  for( int s = 0; s < nPout; s++ )
1812  {
1813  for( int t = 0; t < nPout; t++ )
1814  {
1815  double dNodeArea = dSampleCoeffOut[s][t] * dW[k] * dTriArea;
1816 
1817  dOverlapOutputArea[ixOverlap + i][s * nPout + t] += dNodeArea;
1818 
1819  dGeometricOutputArea[ixSecond][s * nPout + t] += dNodeArea;
1820  }
1821  }
1822 
1823  // Compute overlap integral
1824  int ixp = 0;
1825  for( int p = 0; p < nPin; p++ )
1826  {
1827  for( int q = 0; q < nPin; q++ )
1828  {
1829  int ixs = 0;
1830  for( int s = 0; s < nPout; s++ )
1831  {
1832  for( int t = 0; t < nPout; t++ )
1833  {
1834  // Sample the Second finite element at this point
1835  dGlobalIntArray[ixp][ixOverlap + i][ixs] +=
1836  dSampleCoeffOut[s][t] * dSampleCoeffIn[p][q] * dW[k] * dTriArea;
1837 
1838  ixs++;
1839  }
1840  }
1841 
1842  ixp++;
1843  }
1844  }
1845  }
1846  }
1847  }
1848 
1849  // Coefficients
1850  DataArray2D< double > dCoeff( nOverlapFaces * nPout * nPout, nPin * nPin );
1851 
1852  for( int i = 0; i < nOverlapFaces; i++ )
1853  {
1854  // int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1855 
1856  int ixp = 0;
1857  for( int p = 0; p < nPin; p++ )
1858  {
1859  for( int q = 0; q < nPin; q++ )
1860  {
1861  int ixs = 0;
1862  for( int s = 0; s < nPout; s++ )
1863  {
1864  for( int t = 0; t < nPout; t++ )
1865  {
1866  dCoeff[i * nPout * nPout + ixs][ixp] = dGlobalIntArray[ixp][ixOverlap + i][ixs] /
1867  dOverlapOutputArea[ixOverlap + i][s * nPout + t];
1868 
1869  ixs++;
1870  }
1871  }
1872 
1873  ixp++;
1874  }
1875  }
1876  }
1877 
1878  // Source areas
1879  DataArray1D< double > vecSourceArea( nPin * nPin );
1880 
1881  for( int p = 0; p < nPin; p++ )
1882  {
1883  for( int q = 0; q < nPin; q++ )
1884  {
1885  vecSourceArea[p * nPin + q] = dataGLLJacobianIn[p][q][ixFirst];
1886  }
1887  }
1888 
1889  // Target areas
1890  DataArray1D< double > vecTargetArea( nOverlapFaces * nPout * nPout );
1891 
1892  for( int i = 0; i < nOverlapFaces; i++ )
1893  {
1894  // int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
1895  int ixs = 0;
1896  for( int s = 0; s < nPout; s++ )
1897  {
1898  for( int t = 0; t < nPout; t++ )
1899  {
1900  vecTargetArea[i * nPout * nPout + ixs] = dOverlapOutputArea[ixOverlap + i][nPout * s + t];
1901 
1902  ixs++;
1903  }
1904  }
1905  }
1906 
1907  // Force consistency and conservation
1908  if( !fNoConservation )
1909  {
1910  ForceIntArrayConsistencyConservation( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType != 0 ) );
1911  }
1912 
1913  // Update global coefficients
1914  for( int i = 0; i < nOverlapFaces; i++ )
1915  {
1916  int ixp = 0;
1917  for( int p = 0; p < nPin; p++ )
1918  {
1919  for( int q = 0; q < nPin; q++ )
1920  {
1921  int ixs = 0;
1922  for( int s = 0; s < nPout; s++ )
1923  {
1924  for( int t = 0; t < nPout; t++ )
1925  {
1926  dGlobalIntArray[ixp][ixOverlap + i][ixs] =
1927  dCoeff[i * nPout * nPout + ixs][ixp] * dOverlapOutputArea[ixOverlap + i][s * nPout + t];
1928 
1929  ixs++;
1930  }
1931  }
1932 
1933  ixp++;
1934  }
1935  }
1936  }
1937 
1938 #ifdef VVERBOSE
1939  // Check column sums (conservation)
1940  for( int i = 0; i < nPin * nPin; i++ )
1941  {
1942  double dColSum = 0.0;
1943  for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
1944  {
1945  dColSum += dCoeff[j][i] * vecTargetArea[j];
1946  }
1947  printf( "Col %i: %1.15e\n", i, dColSum / vecSourceArea[i] );
1948  }
1949 
1950  // Check row sums (consistency)
1951  for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
1952  {
1953  double dRowSum = 0.0;
1954  for( int i = 0; i < nPin * nPin; i++ )
1955  {
1956  dRowSum += dCoeff[j][i];
1957  }
1958  printf( "Row %i: %1.15e\n", j, dRowSum );
1959  }
1960 #endif
1961 
1962  // Increment the current overlap index
1963  ixOverlap += nOverlapFaces;
1964  }
1965 
1966  // Build redistribution map within target element
1967  if( is_root ) dbgprint.printf( 0, "Building redistribution maps on target mesh\n" );
1968  DataArray1D< double > dRedistSourceArea( nPout * nPout );
1969  DataArray1D< double > dRedistTargetArea( nPout * nPout );
1970  std::vector< DataArray2D< double > > dRedistributionMaps;
1971  dRedistributionMaps.resize( m_meshOutput->faces.size() );
1972 
1973  for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
1974  {
1975  dRedistributionMaps[ixSecond].Allocate( nPout * nPout, nPout * nPout );
1976 
1977  for( int i = 0; i < nPout * nPout; i++ )
1978  {
1979  dRedistributionMaps[ixSecond][i][i] = 1.0;
1980  }
1981 
1982  for( int s = 0; s < nPout * nPout; s++ )
1983  {
1984  dRedistSourceArea[s] = dGeometricOutputArea[ixSecond][s];
1985  }
1986 
1987  for( int s = 0; s < nPout * nPout; s++ )
1988  {
1989  dRedistTargetArea[s] = dataGLLJacobianOut[s / nPout][s % nPout][ixSecond];
1990  }
1991 
1992  if( !fNoConservation )
1993  {
1994  ForceIntArrayConsistencyConservation( dRedistSourceArea, dRedistTargetArea, dRedistributionMaps[ixSecond],
1995  ( nMonotoneType != 0 ) );
1996 
1997  for( int s = 0; s < nPout * nPout; s++ )
1998  {
1999  for( int t = 0; t < nPout * nPout; t++ )
2000  {
2001  dRedistributionMaps[ixSecond][s][t] *= dRedistTargetArea[s] / dRedistSourceArea[t];
2002  }
2003  }
2004  }
2005  }
2006 
2007  // Construct the total geometric area
2008  DataArray1D< double > dTotalGeometricArea( dataNodalAreaOut.GetRows() );
2009  for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
2010  {
2011  for( int s = 0; s < nPout; s++ )
2012  {
2013  for( int t = 0; t < nPout; t++ )
2014  {
2015  dTotalGeometricArea[dataGLLNodesOut[s][t][ixSecond] - 1] +=
2016  dGeometricOutputArea[ixSecond][s * nPout + t];
2017  }
2018  }
2019  }
2020 
2021  // Compose the integration operator with the output map
2022  ixOverlap = 0;
2023 
2024  if( is_root ) dbgprint.printf( 0, "Assembling map\n" );
2025 
2026  // Map from source DOFs to target DOFs with redistribution applied
2027  DataArray2D< double > dRedistributedOp( nPin * nPin, nPout * nPout );
2028 
2029  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
2030  {
2031 #ifdef VERBOSE
2032  // Announce computation progress
2033  if( ixFirst % outputFrequency == 0 && is_root )
2034  {
2035  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
2036  }
2037 #endif
2038  // Number of overlapping Faces and triangles
2039  int nOverlapFaces = nAllOverlapFaces[ixFirst];
2040 
2041  if( !nOverlapFaces ) continue;
2042 
2043  // Put composed array into map
2044  for( int j = 0; j < nOverlapFaces; j++ )
2045  {
2046  int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
2047 
2048  // signal to not participate, because it is a ghost target
2049  if( ixSecondFace < 0 ) continue; // do not do anything
2050 
2051  dRedistributedOp.Zero();
2052  for( int p = 0; p < nPin * nPin; p++ )
2053  {
2054  for( int s = 0; s < nPout * nPout; s++ )
2055  {
2056  for( int t = 0; t < nPout * nPout; t++ )
2057  {
2058  dRedistributedOp[p][s] +=
2059  dRedistributionMaps[ixSecondFace][s][t] * dGlobalIntArray[p][ixOverlap + j][t];
2060  }
2061  }
2062  }
2063 
2064  int ixp = 0;
2065  for( int p = 0; p < nPin; p++ )
2066  {
2067  for( int q = 0; q < nPin; q++ )
2068  {
2069  int ixFirstNode;
2070  if( fContinuousIn )
2071  {
2072  ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
2073  }
2074  else
2075  {
2076  ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
2077  }
2078 
2079  int ixs = 0;
2080  for( int s = 0; s < nPout; s++ )
2081  {
2082  for( int t = 0; t < nPout; t++ )
2083  {
2084  int ixSecondNode;
2085  if( fContinuousOut )
2086  {
2087  ixSecondNode = dataGLLNodesOut[s][t][ixSecondFace] - 1;
2088 
2089  if( !fNoConservation )
2090  {
2091  smatMap( ixSecondNode, ixFirstNode ) +=
2092  dRedistributedOp[ixp][ixs] / dataNodalAreaOut[ixSecondNode];
2093  }
2094  else
2095  {
2096  smatMap( ixSecondNode, ixFirstNode ) +=
2097  dRedistributedOp[ixp][ixs] / dTotalGeometricArea[ixSecondNode];
2098  }
2099  }
2100  else
2101  {
2102  ixSecondNode = ixSecondFace * nPout * nPout + s * nPout + t;
2103 
2104  if( !fNoConservation )
2105  {
2106  smatMap( ixSecondNode, ixFirstNode ) +=
2107  dRedistributedOp[ixp][ixs] / dataGLLJacobianOut[s][t][ixSecondFace];
2108  }
2109  else
2110  {
2111  smatMap( ixSecondNode, ixFirstNode ) +=
2112  dRedistributedOp[ixp][ixs] / dGeometricOutputArea[ixSecondFace][s * nPout + t];
2113  }
2114  }
2115 
2116  ixs++;
2117  }
2118  }
2119 
2120  ixp++;
2121  }
2122  }
2123  }
2124 
2125  // Increment the current overlap index
2126  ixOverlap += nOverlapFaces;
2127  }
2128 
2129  return;
2130 }

References center(), dbgprint, and ForceIntArrayConsistencyConservation().

◆ LinearRemapGLLtoGLL2_Pointwise_MOAB()

void moab::TempestOnlineMap::LinearRemapGLLtoGLL2_Pointwise_MOAB ( const DataArray3D< int > &  dataGLLNodesIn,
const DataArray3D< double > &  dataGLLJacobianIn,
const DataArray3D< int > &  dataGLLNodesOut,
const DataArray3D< double > &  dataGLLJacobianOut,
const DataArray1D< double > &  dataNodalAreaOut,
int  nPin,
int  nPout,
int  nMonotoneType,
bool  fContinuousIn,
bool  fContinuousOut 
)
private

Generate the OfflineMap for remapping from finite elements to finite elements (pointwise interpolation).

Definition at line 2134 of file TempestLinearRemap.cpp.

2144 {
2145  // Gauss-Lobatto quadrature within Faces
2146  DataArray1D< double > dGL;
2147  DataArray1D< double > dWL;
2148 
2149  GaussLobattoQuadrature::GetPoints( nPout, 0.0, 1.0, dGL, dWL );
2150 
2151  // Get SparseMatrix represntation of the OfflineMap
2152  SparseMatrix< double >& smatMap = this->GetSparseMatrix();
2153 
2154  // Sample coefficients
2155  DataArray2D< double > dSampleCoeffIn( nPin, nPin );
2156 
2157  // Announcemnets
2158  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
2159  dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_Pointwise_MOAB]: " );
2160  if( is_root )
2161  {
2162  dbgprint.printf( 0, "Finite Element to Finite Element (Pointwise) Projection\n" );
2163  dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
2164  dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
2165  }
2166 
2167  // Number of overlap Faces per source Face
2168  DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
2169 
2170  int ixOverlap = 0;
2171 
2172  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
2173  {
2174  size_t ixOverlapTemp = ixOverlap;
2175  for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
2176  {
2177  // const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
2178 
2179  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 ) break;
2180 
2181  nAllOverlapFaces[ixFirst]++;
2182  }
2183 
2184  // Increment the current overlap index
2185  ixOverlap += nAllOverlapFaces[ixFirst];
2186  }
2187 
2188  // Number of times this point was found
2189  DataArray1D< bool > fSecondNodeFound( dataNodalAreaOut.GetRows() );
2190 
2191  ixOverlap = 0;
2192 #ifdef VERBOSE
2193  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
2194 #endif
2195  // Loop through all faces on m_meshInputCov
2196  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
2197  {
2198 #ifdef VERBOSE
2199  // Announce computation progress
2200  if( ixFirst % outputFrequency == 0 && is_root )
2201  {
2202  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
2203  }
2204 #endif
2205  // Quantities from the First Mesh
2206  const Face& faceFirst = m_meshInputCov->faces[ixFirst];
2207 
2208  const NodeVector& nodesFirst = m_meshInputCov->nodes;
2209 
2210  // Number of overlapping Faces and triangles
2211  int nOverlapFaces = nAllOverlapFaces[ixFirst];
2212 
2213  // Loop through all Overlap Faces
2214  for( int i = 0; i < nOverlapFaces; i++ )
2215  {
2216  // Quantities from the Second Mesh
2217  int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
2218 
2219  // signal to not participate, because it is a ghost target
2220  if( ixSecond < 0 ) continue; // do not do anything
2221 
2222  const NodeVector& nodesSecond = m_meshOutput->nodes;
2223  const Face& faceSecond = m_meshOutput->faces[ixSecond];
2224 
2225  // Loop through all nodes on the second face
2226  for( int s = 0; s < nPout; s++ )
2227  {
2228  for( int t = 0; t < nPout; t++ )
2229  {
2230  size_t ixSecondNode;
2231  if( fContinuousOut )
2232  {
2233  ixSecondNode = dataGLLNodesOut[s][t][ixSecond] - 1;
2234  }
2235  else
2236  {
2237  ixSecondNode = ixSecond * nPout * nPout + s * nPout + t;
2238  }
2239 
2240  if( ixSecondNode >= fSecondNodeFound.GetRows() ) _EXCEPTIONT( "Logic error" );
2241 
2242  // Check if this node has been found already
2243  if( fSecondNodeFound[ixSecondNode] ) continue;
2244 
2245  // Check this node
2246  Node node;
2247  Node dDx1G;
2248  Node dDx2G;
2249 
2250  ApplyLocalMap( faceSecond, nodesSecond, dGL[t], dGL[s], node, dDx1G, dDx2G );
2251 
2252  // Find the components of this quadrature point in the basis
2253  // of the first Face.
2254  double dAlphaIn;
2255  double dBetaIn;
2256 
2257  ApplyInverseMap( faceFirst, nodesFirst, node, dAlphaIn, dBetaIn );
2258 
2259  // Check if this node is within the first Face
2260  if( ( dAlphaIn < -1.0e-10 ) || ( dAlphaIn > 1.0 + 1.0e-10 ) || ( dBetaIn < -1.0e-10 ) ||
2261  ( dBetaIn > 1.0 + 1.0e-10 ) )
2262  continue;
2263 
2264  // Node is within the overlap region, mark as found
2265  fSecondNodeFound[ixSecondNode] = true;
2266 
2267  // Sample the First finite element at this point
2268  SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
2269 
2270  // Add to map
2271  for( int p = 0; p < nPin; p++ )
2272  {
2273  for( int q = 0; q < nPin; q++ )
2274  {
2275  int ixFirstNode;
2276  if( fContinuousIn )
2277  {
2278  ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
2279  }
2280  else
2281  {
2282  ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
2283  }
2284 
2285  smatMap( ixSecondNode, ixFirstNode ) += dSampleCoeffIn[p][q];
2286  }
2287  }
2288  }
2289  }
2290  }
2291 
2292  // Increment the current overlap index
2293  ixOverlap += nOverlapFaces;
2294  }
2295 
2296  // Check for missing samples
2297  for( size_t i = 0; i < fSecondNodeFound.GetRows(); i++ )
2298  {
2299  if( !fSecondNodeFound[i] )
2300  {
2301  _EXCEPTION1( "Can't sample point %i", i );
2302  }
2303  }
2304 
2305  return;
2306 }

References dbgprint.

◆ LinearRemapNN_MOAB()

moab::ErrorCode moab::TempestOnlineMap::LinearRemapNN_MOAB ( bool  use_GID_matching = false,
bool  strict_check = false 
)
private

Compute the remapping weights as a permutation matrix that relates DoFs on the source mesh to DoFs on the target mesh.

Definition at line 58 of file TempestLinearRemap.cpp.

59 {
60  /* m_mapRemap size = (m_nTotDofs_Dest X m_nTotDofs_SrcCov) */
61 
62 #ifdef VVERBOSE
63  {
64  std::ofstream output_file( "rowcolindices.txt", std::ios::out );
65  output_file << m_nTotDofs_Dest << " " << m_nTotDofs_SrcCov << " " << row_gdofmap.size() << " "
66  << row_ldofmap.size() << " " << col_gdofmap.size() << " " << col_ldofmap.size() << "\n";
67  output_file << "Rows \n";
68  for( unsigned iv = 0; iv < row_gdofmap.size(); iv++ )
69  output_file << row_gdofmap[iv] << " " << row_dofmap[iv] << "\n";
70  output_file << "Cols \n";
71  for( unsigned iv = 0; iv < col_gdofmap.size(); iv++ )
72  output_file << col_gdofmap[iv] << " " << col_dofmap[iv] << "\n";
73  output_file.flush(); // required here
74  output_file.close();
75  }
76 #endif
77 
78  if( use_GID_matching )
79  {
80  std::map< unsigned, unsigned > src_gl;
81  for( unsigned it = 0; it < col_gdofmap.size(); ++it )
82  src_gl[col_gdofmap[it]] = it;
83 
84  std::map< unsigned, unsigned >::iterator iter;
85  for( unsigned it = 0; it < row_gdofmap.size(); ++it )
86  {
87  unsigned row = row_gdofmap[it];
88  iter = src_gl.find( row );
89  if( strict_check && iter == src_gl.end() )
90  {
91  std::cout << "Searching for global target DOF " << row
92  << " but could not find correspondence in source mesh.\n";
93  assert( false );
94  }
95  else if( iter == src_gl.end() )
96  {
97  continue;
98  }
99  else
100  {
101  unsigned icol = src_gl[row];
102  unsigned irow = it;
103 
104  // Set the permutation matrix in local space
105  m_mapRemap( irow, icol ) = 1.0;
106  }
107  }
108 
109  return moab::MB_SUCCESS;
110  }
111  else
112  {
113  /* Create a Kd-tree to perform local queries to find nearest neighbors */
114 
115  return moab::MB_FAILURE;
116  }
117 }

References col_gdofmap, m_nTotDofs_Dest, m_nTotDofs_SrcCov, MB_SUCCESS, and row_gdofmap.

◆ LinearRemapSE0_Tempest_MOAB()

void moab::TempestOnlineMap::LinearRemapSE0_Tempest_MOAB ( const DataArray3D< int > &  dataGLLNodes,
const DataArray3D< double > &  dataGLLJacobian 
)
private

Generate the OfflineMap for linear conserative element-average spectral element to element average remapping.

◆ LinearRemapSE4_Tempest_MOAB()

void moab::TempestOnlineMap::LinearRemapSE4_Tempest_MOAB ( const DataArray3D< int > &  dataGLLNodes,
const DataArray3D< double > &  dataGLLJacobian,
int  nMonotoneType,
bool  fContinuousIn,
bool  fNoConservation 
)
private

Generate the OfflineMap for cubic conserative element-average spectral element to element average remapping.

Definition at line 1162 of file TempestLinearRemap.cpp.

1167 {
1168  // Order of the polynomial interpolant
1169  int nP = dataGLLNodes.GetRows();
1170 
1171  // Order of triangular quadrature rule
1172  const int TriQuadRuleOrder = 4;
1173 
1174  // Triangular quadrature rule
1175  TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
1176 
1177  int TriQuadraturePoints = triquadrule.GetPoints();
1178 
1179  const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
1180 
1181  const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
1182 
1183  // Sample coefficients
1184  DataArray2D< double > dSampleCoeff( nP, nP );
1185 
1186  // GLL Quadrature nodes on quadrilateral elements
1187  DataArray1D< double > dG;
1188  DataArray1D< double > dW;
1189  GaussLobattoQuadrature::GetPoints( nP, 0.0, 1.0, dG, dW );
1190 
1191  // Announcements
1192  moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
1193  dbgprint.set_prefix( "[LinearRemapSE4_Tempest_MOAB]: " );
1194  if( is_root )
1195  {
1196  dbgprint.printf( 0, "Finite Element to Finite Volume Projection\n" );
1197  dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
1198  dbgprint.printf( 0, "Order of the FE polynomial interpolant: %i\n", nP );
1199  }
1200 
1201  // Get SparseMatrix represntation of the OfflineMap
1202  SparseMatrix< double >& smatMap = this->GetSparseMatrix();
1203 
1204  // NodeVector from m_meshOverlap
1205  const NodeVector& nodesOverlap = m_meshOverlap->nodes;
1206  const NodeVector& nodesFirst = m_meshInputCov->nodes;
1207 
1208  // Vector of source areas
1209  DataArray1D< double > vecSourceArea( nP * nP );
1210 
1211  DataArray1D< double > vecTargetArea;
1212  DataArray2D< double > dCoeff;
1213 
1214 #ifdef VERBOSE
1215  std::stringstream sstr;
1216  sstr << "remapdata_" << rank << ".txt";
1217  std::ofstream output_file( sstr.str() );
1218 #endif
1219 
1220  // Current Overlap Face
1221  int ixOverlap = 0;
1222 #ifdef VERBOSE
1223  const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
1224 #endif
1225  // generic triangle used for area computation, for triangles around the center of overlap face;
1226  // used for overlap faces with more than 4 edges;
1227  // nodes array will be set for each triangle;
1228  // these triangles are not part of the mesh structure, they are just temporary during
1229  // aforementioned decomposition.
1230  Face faceTri( 3 );
1231  NodeVector nodes( 3 );
1232  faceTri.SetNode( 0, 0 );
1233  faceTri.SetNode( 1, 1 );
1234  faceTri.SetNode( 2, 2 );
1235 
1236  // Loop over all input Faces
1237  for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
1238  {
1239  const Face& faceFirst = m_meshInputCov->faces[ixFirst];
1240 
1241  if( faceFirst.edges.size() != 4 )
1242  {
1243  _EXCEPTIONT( "Only quadrilateral elements allowed for SE remapping" );
1244  }
1245 #ifdef VERBOSE
1246  // Announce computation progress
1247  if( ixFirst % outputFrequency == 0 && is_root )
1248  {
1249  dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
1250  }
1251 #endif
1252  // Need to re-number the overlap elements such that vecSourceFaceIx[a:b] = 0, then 1 and so
1253  // on wrt the input mesh data Then the overlap_end and overlap_begin will be correct.
1254  // However, the relation with MOAB and Tempest will go out of the roof
1255 
1256  // Determine how many overlap Faces and triangles are present
1257  int nOverlapFaces = 0;
1258  size_t ixOverlapTemp = ixOverlap;
1259  for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
1260  {
1261  // if( m_meshOverlap->vecTargetFaceIx[ixOverlapTemp] < 0 ) continue; // skip ghost target faces
1262  // const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
1263  if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 ) break;
1264 
1265  nOverlapFaces++;
1266  }
1267 
1268  // No overlaps
1269  if( nOverlapFaces == 0 ) continue;
1270 
1271  // Allocate remap coefficients array for meshFirst Face
1272  DataArray3D< double > dRemapCoeff( nP, nP, nOverlapFaces );
1273 
1274  // Find the local remap coefficients
1275  for( int j = 0; j < nOverlapFaces; j++ )
1276  {
1277  const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + j];
1278  if( m_meshOverlap->vecFaceArea[ixOverlap + j] < 1.e-16 ) // machine precision
1279  {
1280  Announce( "Very small overlap at index %i area polygon: (%1.10e )", ixOverlap + j,
1281  m_meshOverlap->vecFaceArea[ixOverlap + j] );
1282  int n = faceOverlap.edges.size();
1283  Announce( "Number nodes: %d", n );
1284  for( int k = 0; k < n; k++ )
1285  {
1286  Node nd = nodesOverlap[faceOverlap[k]];
1287  Announce( "Node %d %d : %1.10e %1.10e %1.10e ", k, faceOverlap[k], nd.x, nd.y, nd.z );
1288  }
1289  continue;
1290  }
1291 
1292  // #ifdef VERBOSE
1293  // if ( is_root )
1294  // Announce ( "\tLocal ID: %i/%i = %i, areas = %2.8e", j + ixOverlap, nOverlapFaces,
1295  // m_remapper->lid_to_gid_covsrc[m_meshOverlap->vecSourceFaceIx[ixOverlap + j]],
1296  // m_meshOverlap->vecFaceArea[ixOverlap + j] );
1297  // #endif
1298 
1299  int nbEdges = faceOverlap.edges.size();
1300  int nOverlapTriangles = 1;
1301  Node center; // not used if nbEdges == 3
1302  if( nbEdges > 3 )
1303  { // decompose from center in this case
1304  nOverlapTriangles = nbEdges;
1305  for( int k = 0; k < nbEdges; k++ )
1306  {
1307  const Node& node = nodesOverlap[faceOverlap[k]];
1308  center = center + node;
1309  }
1310  center = center / nbEdges;
1311  center = center.Normalized(); // project back on sphere of radius 1
1312  }
1313 
1314  Node node0, node1, node2;
1315  double dTriangleArea;
1316 
1317  // Loop over all sub-triangles of this Overlap Face
1318  for( int k = 0; k < nOverlapTriangles; k++ )
1319  {
1320  if( nbEdges == 3 ) // will come here only once, nOverlapTriangles == 1 in this case
1321  {
1322  node0 = nodesOverlap[faceOverlap[0]];
1323  node1 = nodesOverlap[faceOverlap[1]];
1324  node2 = nodesOverlap[faceOverlap[2]];
1325  dTriangleArea = CalculateFaceArea( faceOverlap, nodesOverlap );
1326  }
1327  else // decompose polygon in triangles around the center
1328  {
1329  node0 = center;
1330  node1 = nodesOverlap[faceOverlap[k]];
1331  int k1 = ( k + 1 ) % nbEdges;
1332  node2 = nodesOverlap[faceOverlap[k1]];
1333  nodes[0] = center;
1334  nodes[1] = node1;
1335  nodes[2] = node2;
1336  dTriangleArea = CalculateFaceArea( faceTri, nodes );
1337  }
1338  // Coordinates of quadrature Node
1339  for( int l = 0; l < TriQuadraturePoints; l++ )
1340  {
1341  Node nodeQuadrature;
1342  nodeQuadrature.x = TriQuadratureG[l][0] * node0.x + TriQuadratureG[l][1] * node1.x +
1343  TriQuadratureG[l][2] * node2.x;
1344 
1345  nodeQuadrature.y = TriQuadratureG[l][0] * node0.y + TriQuadratureG[l][1] * node1.y +
1346  TriQuadratureG[l][2] * node2.y;
1347 
1348  nodeQuadrature.z = TriQuadratureG[l][0] * node0.z + TriQuadratureG[l][1] * node1.z +
1349  TriQuadratureG[l][2] * node2.z;
1350 
1351  nodeQuadrature = nodeQuadrature.Normalized();
1352 
1353  // Find components of quadrature point in basis
1354  // of the first Face
1355  double dAlpha;
1356  double dBeta;
1357 
1358  ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlpha, dBeta );
1359 
1360  // Check inverse map value
1361  if( ( dAlpha < -1.0e-13 ) || ( dAlpha > 1.0 + 1.0e-13 ) || ( dBeta < -1.0e-13 ) ||
1362  ( dBeta > 1.0 + 1.0e-13 ) )
1363  {
1364  _EXCEPTION4( "Inverse Map for element %d and subtriangle %d out of range "
1365  "(%1.5e %1.5e)",
1366  j, l, dAlpha, dBeta );
1367  }
1368 
1369  // Sample the finite element at this point
1370  SampleGLLFiniteElement( nMonotoneType, nP, dAlpha, dBeta, dSampleCoeff );
1371 
1372  // Add sample coefficients to the map if m_meshOverlap->vecFaceArea[ixOverlap + j] > 0
1373  for( int p = 0; p < nP; p++ )
1374  {
1375  for( int q = 0; q < nP; q++ )
1376  {
1377  dRemapCoeff[p][q][j] += TriQuadratureW[l] * dTriangleArea * dSampleCoeff[p][q] /
1378  m_meshOverlap->vecFaceArea[ixOverlap + j];
1379  }
1380  }
1381  }
1382  }
1383  }
1384 
1385 #ifdef VERBOSE
1386  output_file << "[" << m_remapper->lid_to_gid_covsrc[ixFirst] << "] \t";
1387  for( int j = 0; j < nOverlapFaces; j++ )
1388  {
1389  for( int p = 0; p < nP; p++ )
1390  {
1391  for( int q = 0; q < nP; q++ )
1392  {
1393  output_file << dRemapCoeff[p][q][j] << " ";
1394  }
1395  }
1396  }
1397  output_file << std::endl;
1398 #endif
1399 
1400  // Force consistency and conservation
1401  if( !fNoConservation )
1402  {
1403  double dTargetArea = 0.0;
1404  for( int j = 0; j < nOverlapFaces; j++ )
1405  {
1406  dTargetArea += m_meshOverlap->vecFaceArea[ixOverlap + j];
1407  }
1408 
1409  for( int p = 0; p < nP; p++ )
1410  {
1411  for( int q = 0; q < nP; q++ )
1412  {
1413  vecSourceArea[p * nP + q] = dataGLLJacobian[p][q][ixFirst];
1414  }
1415  }
1416 
1417  const double areaTolerance = 1e-10;
1418  // Source elements are completely covered by target volumes
1419  if( fabs( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea ) <= areaTolerance )
1420  {
1421  vecTargetArea.Allocate( nOverlapFaces );
1422  for( int j = 0; j < nOverlapFaces; j++ )
1423  {
1424  vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
1425  }
1426 
1427  dCoeff.Allocate( nOverlapFaces, nP * nP );
1428 
1429  for( int j = 0; j < nOverlapFaces; j++ )
1430  {
1431  for( int p = 0; p < nP; p++ )
1432  {
1433  for( int q = 0; q < nP; q++ )
1434  {
1435  dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
1436  }
1437  }
1438  }
1439 
1440  // Target volumes only partially cover source elements
1441  }
1442  else if( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea > areaTolerance )
1443  {
1444  double dExtraneousArea = m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea;
1445 
1446  vecTargetArea.Allocate( nOverlapFaces + 1 );
1447  for( int j = 0; j < nOverlapFaces; j++ )
1448  {
1449  vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
1450  }
1451  vecTargetArea[nOverlapFaces] = dExtraneousArea;
1452 
1453 #ifdef VERBOSE
1454  Announce( "Partial volume: %i (%1.10e / %1.10e)", ixFirst, dTargetArea,
1455  m_meshInputCov->vecFaceArea[ixFirst] );
1456 #endif
1457  if( dTargetArea > m_meshInputCov->vecFaceArea[ixFirst] )
1458  {
1459  _EXCEPTIONT( "Partial element area exceeds total element area" );
1460  }
1461 
1462  dCoeff.Allocate( nOverlapFaces + 1, nP * nP );
1463 
1464  for( int j = 0; j < nOverlapFaces; j++ )
1465  {
1466  for( int p = 0; p < nP; p++ )
1467  {
1468  for( int q = 0; q < nP; q++ )
1469  {
1470  dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
1471  }
1472  }
1473  }
1474  for( int p = 0; p < nP; p++ )
1475  {
1476  for( int q = 0; q < nP; q++ )
1477  {
1478  dCoeff[nOverlapFaces][p * nP + q] = dataGLLJacobian[p][q][ixFirst];
1479  }
1480  }
1481  for( int j = 0; j < nOverlapFaces; j++ )
1482  {
1483  for( int p = 0; p < nP; p++ )
1484  {
1485  for( int q = 0; q < nP; q++ )
1486  {
1487  dCoeff[nOverlapFaces][p * nP + q] -=
1488  dRemapCoeff[p][q][j] * m_meshOverlap->vecFaceArea[ixOverlap + j];
1489  }
1490  }
1491  }
1492  for( int p = 0; p < nP; p++ )
1493  {
1494  for( int q = 0; q < nP; q++ )
1495  {
1496  dCoeff[nOverlapFaces][p * nP + q] /= dExtraneousArea;
1497  }
1498  }
1499 
1500  // Source elements only partially cover target volumes
1501  }
1502  else
1503  {
1504  Announce( "Coverage area: %1.10e, and target element area: %1.10e)", ixFirst,
1505  m_meshInputCov->vecFaceArea[ixFirst], dTargetArea );
1506  _EXCEPTIONT( "Target grid must be a subset of source grid" );
1507  }
1508 
1509  ForceConsistencyConservation3( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType > 0 )
1510  /*, m_remapper->lid_to_gid_covsrc[ixFirst]*/ );
1511 
1512  for( int j = 0; j < nOverlapFaces; j++ )
1513  {
1514  for( int p = 0; p < nP; p++ )
1515  {
1516  for( int q = 0; q < nP; q++ )
1517  {
1518  dRemapCoeff[p][q][j] = dCoeff[j][p * nP + q];
1519  }
1520  }
1521  }
1522  }
1523 
1524 #ifdef VERBOSE
1525  // output_file << "[" << m_remapper->lid_to_gid_covsrc[ixFirst] << "] \t";
1526  // for ( int j = 0; j < nOverlapFaces; j++ )
1527  // {
1528  // for ( int p = 0; p < nP; p++ )
1529  // {
1530  // for ( int q = 0; q < nP; q++ )
1531  // {
1532  // output_file << dRemapCoeff[p][q][j] << " ";
1533  // }
1534  // }
1535  // }
1536  // output_file << std::endl;
1537 #endif
1538 
1539  // Put these remap coefficients into the SparseMatrix map
1540  for( int j = 0; j < nOverlapFaces; j++ )
1541  {
1542  int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
1543 
1544  // signal to not participate, because it is a ghost target
1545  if( ixSecondFace < 0 ) continue; // do not do anything
1546 
1547  for( int p = 0; p < nP; p++ )
1548  {
1549  for( int q = 0; q < nP; q++ )
1550  {
1551  if( fContinuousIn )
1552  {
1553  int ixFirstNode = dataGLLNodes[p][q][ixFirst] - 1;
1554 
1555  smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
1556  m_meshOverlap->vecFaceArea[ixOverlap + j] /
1557  m_meshOutput->vecFaceArea[ixSecondFace];
1558  }
1559  else
1560  {
1561  int ixFirstNode = ixFirst * nP * nP + p * nP + q;
1562 
1563  smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
1564  m_meshOverlap->vecFaceArea[ixOverlap + j] /
1565  m_meshOutput->vecFaceArea[ixSecondFace];
1566  }
1567  }
1568  }
1569  }
1570  // Increment the current overlap index
1571  ixOverlap += nOverlapFaces;
1572  }
1573 #ifdef VERBOSE
1574  output_file.flush(); // required here
1575  output_file.close();
1576 #endif
1577 
1578  return;
1579 }

References center(), dbgprint, and ForceConsistencyConservation3().

◆ PrintMapStatistics()

void moab::TempestOnlineMap::PrintMapStatistics ( )

Print information and metadata about the remapping weights.

Definition at line 284 of file TempestLinearRemap.cpp.

285 {
286  int nrows = m_weightMatrix.rows(); // Number of rows
287  int ncols = m_weightMatrix.cols(); // Number of columns
288  int NNZ = m_weightMatrix.nonZeros(); // Number of non zero values
289 #ifdef MOAB_HAVE_MPI
290  // find out min/max for NNZ, ncols, nrows
291  // should work on std c++ 11
292  int arr3[6] = { NNZ, nrows, ncols, -NNZ, -nrows, -ncols };
293  int rarr3[6];
294  MPI_Reduce( arr3, rarr3, 6, MPI_INT, MPI_MIN, 0, m_pcomm->comm() );
295 
296  int total[3];
297  MPI_Reduce( arr3, total, 3, MPI_INT, MPI_SUM, 0, m_pcomm->comm() );
298  if( !rank )
299  std::cout << "-> Rows (min/max/sum): (" << rarr3[1] << " / " << -rarr3[4] << " / " << total[1] << "), "
300  << " Cols (min/max/sum): (" << rarr3[2] << " / " << -rarr3[5] << " / " << total[2] << "), "
301  << " NNZ (min/max/sum): (" << rarr3[0] << " / " << -rarr3[3] << " / " << total[0] << ")\n";
302 #else
303  std::cout << "-> Rows: " << nrows << ", Cols: " << ncols << ", NNZ: " << NNZ << "\n";
304 #endif
305 }

Referenced by main().

◆ QLTLimiter()

double moab::TempestOnlineMap::QLTLimiter ( int  caasIteration,
std::vector< double > &  dataCorrectedField,
std::vector< double > &  dataLowerBound,
std::vector< double > &  dataUpperBound,
std::vector< double > &  dMassDefect 
)
private

◆ ReadParallelMap()

moab::ErrorCode moab::TempestOnlineMap::ReadParallelMap ( const char *  strSource,
const std::vector< int > &  tgt_dof_ids,
std::vector< double > &  areaA,
int &  nA,
std::vector< double > &  areaB,
int &  nB 
)

Generate the metadata associated with the offline map.

Read the OfflineMap from a NetCDF file.

Definition at line 1205 of file TempestOnlineMapIO.cpp.

1211 {
1212  NcError error( NcError::silent_nonfatal );
1213 
1214  NcVar *varRow = NULL, *varCol = NULL, *varS = NULL;
1215  NcVar *varAreaA = NULL, *varAreaB = NULL;
1216  int nS = 0;
1217 #ifdef MOAB_HAVE_PNETCDF
1218  // some variables will be used just in the case netcdfpar reader fails
1219  int ncfile = -1;
1220  int ndims, nvars, ngatts, unlimited;
1221 #endif
1222 #ifdef MOAB_HAVE_NETCDFPAR
1223  bool is_independent = true;
1224  ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 );
1225  // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 );
1226 #else
1227  NcFile ncMap( strSource, NcFile::ReadOnly );
1228 #endif
1229 
1230 #define CHECK_EXCEPTION( obj, type, varstr ) \
1231  { \
1232  if( obj == nullptr ) \
1233  { \
1234  _EXCEPTION3( "Map file \"%s\" does not contain %s \"%s\"", strSource, type, varstr ); \
1235  } \
1236  }
1237 
1238  // Read SparseMatrix entries
1239 
1240  if( ncMap.is_valid() )
1241  {
1242  NcDim* dimNS = ncMap.get_dim( "n_s" );
1243  CHECK_EXCEPTION( dimNS, "dimension", "n_s" );
1244 
1245  NcDim* dimNA = ncMap.get_dim( "n_a" );
1246  CHECK_EXCEPTION( dimNA, "dimension", "n_a" );
1247 
1248  NcDim* dimNB = ncMap.get_dim( "n_b" );
1249  CHECK_EXCEPTION( dimNB, "dimension", "n_b" );
1250 
1251  // store total number of nonzeros
1252  nS = dimNS->size();
1253  nA = dimNA->size();
1254  nB = dimNB->size();
1255 
1256  varRow = ncMap.get_var( "row" );
1257  CHECK_EXCEPTION( varRow, "variable", "row" );
1258 
1259  varCol = ncMap.get_var( "col" );
1260  CHECK_EXCEPTION( varCol, "variable", "col" );
1261 
1262  varS = ncMap.get_var( "S" );
1263  CHECK_EXCEPTION( varS, "variable", "S" );
1264 
1265  varAreaA = ncMap.get_var( "area_a" );
1266  CHECK_EXCEPTION( varAreaA, "variable", "area_a" );
1267 
1268  varAreaB = ncMap.get_var( "area_b" );
1269  CHECK_EXCEPTION( varAreaB, "variable", "area_b" );
1270 
1271 #ifdef MOAB_HAVE_NETCDFPAR
1272  ncMap.enable_var_par_access( varRow, is_independent );
1273  ncMap.enable_var_par_access( varCol, is_independent );
1274  ncMap.enable_var_par_access( varS, is_independent );
1275  ncMap.enable_var_par_access( varAreaA, is_independent );
1276  ncMap.enable_var_par_access( varAreaB, is_independent );
1277 #endif
1278  }
1279  else
1280  {
1281 #ifdef MOAB_HAVE_PNETCDF
1282  // read the file using pnetcdf directly, in parallel; need to have MPI, we do not check that anymore
1283  // why build wth pnetcdf without MPI ?
1284  // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 );
1285  ERR_PARNC(
1286  ncmpi_open( m_pcomm->comm(), strSource, NC_NOWRITE, MPI_INFO_NULL, &ncfile ) ); // bail out completely
1287  ERR_PARNC( ncmpi_inq( ncfile, &ndims, &nvars, &ngatts, &unlimited ) );
1288  // find dimension ids for n_S
1289  int ins;
1290  ERR_PARNC( ncmpi_inq_dimid( ncfile, "n_s", &ins ) );
1291  MPI_Offset leng;
1292  ERR_PARNC( ncmpi_inq_dimlen( ncfile, ins, &leng ) );
1293  nS = (int)leng;
1294  ERR_PARNC( ncmpi_inq_dimid( ncfile, "n_a", &ins ) );
1295  ERR_PARNC( ncmpi_inq_dimlen( ncfile, ins, &leng ) );
1296  nA = (int)leng;
1297  ERR_PARNC( ncmpi_inq_dimid( ncfile, "n_b", &ins ) );
1298  ERR_PARNC( ncmpi_inq_dimlen( ncfile, ins, &leng ) );
1299  nB = (int)leng;
1300 #else
1301  _EXCEPTION1( "cannot read the file %s", strSource );
1302 #endif
1303  }
1304 
1305  // Let us declare the map object for every process
1306  SparseMatrix< double >& sparseMatrix = this->GetSparseMatrix();
1307 
1308  int localSize = nS / size;
1309  long offsetRead = rank * localSize;
1310  // leftovers on last rank
1311  if( rank == size - 1 )
1312  {
1313  localSize += nS % size;
1314  }
1315 
1316  int localSizeA = nA / size;
1317  long offsetReadA = rank * localSizeA;
1318  // leftovers on last rank
1319  if( rank == size - 1 )
1320  {
1321  localSizeA += nA % size;
1322  }
1323 
1324  int localSizeB = nB / size;
1325  long offsetReadB = rank * localSizeB;
1326  // leftovers on last rank
1327  if( rank == size - 1 )
1328  {
1329  localSizeB += nB % size;
1330  }
1331 
1332  std::vector< int > vecRow, vecCol;
1333  std::vector< double > vecS;
1334  vecRow.resize( localSize );
1335  vecCol.resize( localSize );
1336  vecS.resize( localSize );
1337  vecAreaA.resize( localSizeA );
1338  vecAreaB.resize( localSizeB );
1339 
1340  if( ncMap.is_valid() )
1341  {
1342  varRow->set_cur( (long)( offsetRead ) );
1343  varRow->get( &( vecRow[0] ), localSize );
1344 
1345  varCol->set_cur( (long)( offsetRead ) );
1346  varCol->get( &( vecCol[0] ), localSize );
1347 
1348  varS->set_cur( (long)( offsetRead ) );
1349  varS->get( &( vecS[0] ), localSize );
1350 
1351  varAreaA->set_cur( (long)( offsetReadA ) );
1352  varAreaA->get( &( vecAreaA[0] ), localSizeA );
1353 
1354  varAreaB->set_cur( (long)( offsetReadB ) );
1355  varAreaB->get( &( vecAreaB[0] ), localSizeB );
1356 
1357  ncMap.close();
1358  }
1359  else
1360  {
1361 #ifdef MOAB_HAVE_PNETCDF
1362  // fill the local vectors with the variables from pnetcdf file; first inquire, then fill
1363  MPI_Offset start = (MPI_Offset)offsetRead;
1364  MPI_Offset count = (MPI_Offset)localSize;
1365  int varid;
1366  // get the sparse matrix values, row and column indices
1367  ERR_PARNC( ncmpi_inq_varid( ncfile, "S", &varid ) );
1368  ERR_PARNC( ncmpi_get_vara_double_all( ncfile, varid, &start, &count, &vecS[0] ) );
1369  ERR_PARNC( ncmpi_inq_varid( ncfile, "row", &varid ) );
1370  ERR_PARNC( ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecRow[0] ) );
1371  ERR_PARNC( ncmpi_inq_varid( ncfile, "col", &varid ) );
1372  ERR_PARNC( ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecCol[0] ) );
1373 
1374  ERR_PARNC( ncmpi_inq_varid( ncfile, "area_a", &varid ) );
1375  MPI_Offset startA = (MPI_Offset)offsetReadA;
1376  MPI_Offset countA = (MPI_Offset)localSizeA;
1377  ERR_PARNC( ncmpi_get_vara_double_all( ncfile, varid, &startA, &countA, &vecAreaA[0] ) );
1378 
1379  ERR_PARNC( ncmpi_inq_varid( ncfile, "area_b", &varid ) );
1380  MPI_Offset startB = (MPI_Offset)offsetReadB;
1381  MPI_Offset countB = (MPI_Offset)localSizeB;
1382  ERR_PARNC( ncmpi_get_vara_double_all( ncfile, varid, &startB, &countB, &vecAreaB[0] ) );
1383 
1384  ERR_PARNC( ncmpi_close( ncfile ) );
1385 #endif
1386  }
1387 
1388  // NOTE: we can check if the following workflow would help here.
1389  // Initial experiments did not show same index map.
1390  // Might be useful to understand why that is the case.
1391  // First, ensure that all local and global indices are computed
1392  // this->m_remapper->ComputeGlobalLocalMaps();
1393  // Next, reuse the global to local map
1394  // const auto& rowMap = m_remapper->gid_to_lid_tgt;
1395  // const auto& colMap = m_remapper->gid_to_lid_covsrc;
1396 #ifdef MOAB_HAVE_EIGEN3
1397 
1398  typedef Eigen::Triplet< double > Triplet;
1399  std::vector< Triplet > tripletList;
1400 
1401 #ifdef MOAB_HAVE_MPI
1402  // bother with tuple list only if size > 1
1403  // otherwise, just fill the sparse matrix
1404  if( size > 1 )
1405  {
1406  std::vector< int > ownership;
1407  // the default trivial partitioning scheme
1408  int nDofs = nB; // this is for row partitioning
1409 
1410  int nPerPart = nDofs / size;
1411  moab::TupleList* tl = new moab::TupleList;
1412  unsigned numr = 1; //
1413  tl->initialize( 3, 0, 0, numr, localSize ); // to proc, row, col, value
1414  tl->enableWriteAccess();
1415  // populate
1416  for( int i = 0; i < localSize; i++ )
1417  {
1418  int rowval = vecRow[i] - 1; // dofs are 1 based in the file; sparse matrix is 0 based
1419  int colval = vecCol[i] - 1;
1420  int to_proc = -1;
1421 
1422  to_proc = rowval / nPerPart;
1423  if( to_proc == size ) to_proc = size - 1;
1424 
1425  int n = tl->get_n();
1426  tl->vi_wr[3 * n] = to_proc;
1427  tl->vi_wr[3 * n + 1] = rowval;
1428  tl->vi_wr[3 * n + 2] = colval;
1429  tl->vr_wr[n] = vecS[i];
1430  tl->inc_n();
1431  }
1432  // heavy communication
1433  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl, 0 );
1434 
1435  if( owned_dof_ids.size() > 0 )
1436  {
1437  // we need to send desired dof to the rendezvous point
1438  moab::TupleList tl_re; //
1439  tl_re.initialize( 2, 0, 0, 0, owned_dof_ids.size() ); // to proc, value
1440  tl_re.enableWriteAccess();
1441  // send first to rendez_vous point, decided by trivial partitioning
1442 
1443  for( size_t i = 0; i < owned_dof_ids.size(); i++ )
1444  {
1445  int to_proc = -1;
1446  int dof_val = owned_dof_ids[i] - 1; // dofs are 1 based in the file, partition from 0 ?
1447  to_proc = dof_val / nPerPart;
1448  if( to_proc == size ) to_proc = size - 1;
1449 
1450  int n = tl_re.get_n();
1451  tl_re.vi_wr[2 * n] = to_proc;
1452  tl_re.vi_wr[2 * n + 1] = dof_val;
1453 
1454  tl_re.inc_n();
1455  }
1456  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tl_re, 0 );
1457  // now we know in tl_re where do we need to send back dof_val
1458  moab::TupleList::buffer sort_buffer;
1459  sort_buffer.buffer_init( tl_re.get_n() );
1460  tl_re.sort( 1, &sort_buffer ); // so now we order by value
1461 
1462  //sort_buffer.buffer_init( tl->get_n() );
1463 
1464  std::map< int, int > startDofIndex, endDofIndex; // indices in tl_re for values we want
1465  int dofVal = -1;
1466  if( tl_re.get_n() > 0 )
1467  {
1468  dofVal = tl_re.vi_rd[1]; // first dof val on this rank tl_re.vi_rd[2 * 0 + 1];
1469 
1470  startDofIndex[dofVal] = 0;
1471  endDofIndex[dofVal] = 0; // start and end
1472  for( unsigned k = 1; k < tl_re.get_n(); k++ )
1473  {
1474  int newDof = tl_re.vi_rd[2 * k + 1];
1475  if( dofVal == newDof )
1476  {
1477  endDofIndex[dofVal] = k; // increment by 1 actually
1478  }
1479  else
1480  {
1481  dofVal = newDof;
1482  startDofIndex[dofVal] = k;
1483  endDofIndex[dofVal] = k;
1484  }
1485  }
1486  }
1487  // basically, for each value we are interested in, index in tl_re with those values are
1488  // tl_re.vi_rd[2*startDofIndex+1] == valDof == tl_re.vi_rd[2*endDofIndex+1]
1489  // so now we have ordered
1490  // tl_re shows to what proc do we need to send the tuple (row, col, val)
1491  moab::TupleList* tl_back = new moab::TupleList;
1492  unsigned numr = 1; //
1493  // localSize is a good guess, but maybe it should be bigger ?
1494  // this could be bigger for repeated dofs
1495  tl_back->initialize( 3, 0, 0, numr, tl->get_n() ); // to proc, row, col, value
1496  tl_back->enableWriteAccess();
1497  // now loop over tl and tl_re to see where to send
1498  // form the new tuple, which will contain the desired dofs per task, per row or column distribution
1499 
1500  for( unsigned k = 0; k < tl->get_n(); k++ )
1501  {
1502  int valDof = tl->vi_rd[3 * k + 1]; // 1 for row, 2 for column // first value, it should be
1503  if (startDofIndex.find(valDof)==startDofIndex.end())
1504  continue;
1505  for( int ire = startDofIndex[valDof]; ire <= endDofIndex[valDof]; ire++ )
1506  {
1507  int to_proc = tl_re.vi_rd[2 * ire];
1508  int n = tl_back->get_n();
1509  tl_back->vi_wr[3 * n] = to_proc;
1510  tl_back->vi_wr[3 * n + 1] = tl->vi_rd[3 * k + 1]; // row
1511  tl_back->vi_wr[3 * n + 2] = tl->vi_rd[3 * k + 2]; // col
1512  tl_back->vr_wr[n] = tl->vr_rd[k];
1513  tl_back->inc_n();
1514  }
1515  }
1516 
1517  // now communicate to the desired tasks:
1518  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl_back, 0 );
1519 
1520  tl_re.reset(); // clear memory, although this will go out of scope
1521  tl->reset();
1522  tl = tl_back;
1523  }
1524 
1525  // set of row and col used on this task
1526  std::set< int > rowSet;
1527  std::set< int > colSet;
1528  // populate the sparsematrix, using rowMap and colMap
1529  int n = tl->get_n();
1530  for( int i = 0; i < n; i++ )
1531  {
1532  const int vecRowValue = tl->vi_wr[3 * i + 1];
1533  const int vecColValue = tl->vi_wr[3 * i + 2];
1534  rowSet.insert( vecRowValue );
1535  colSet.insert( vecColValue );
1536  }
1537  int index = 0;
1538  row_gdofmap.resize( rowSet.size() );
1539  for( auto setIt : rowSet )
1540  {
1541  row_gdofmap[index] = setIt;
1542  rowMap[setIt] = index++;
1543  }
1544  m_nTotDofs_Dest = index;
1545  index = 0;
1546  col_gdofmap.resize( colSet.size() );
1547  for( auto setIt : colSet )
1548  {
1549  col_gdofmap[index] = setIt;
1550  colMap[setIt] = index++;
1551  }
1552  m_nTotDofs_SrcCov = index;
1553 
1554  tripletList.reserve( n );
1555  for( int i = 0; i < n; i++ )
1556  {
1557  const int vecRowValue = tl->vi_wr[3 * i + 1];
1558  const int vecColValue = tl->vi_wr[3 * i + 2];
1559  double value = tl->vr_wr[i];
1560  tripletList.emplace_back( rowMap[vecRowValue], colMap[vecColValue], value );
1561  }
1562  tl->reset();
1563  }
1564  else
1565 #endif
1566  {
1567  // set of row and col used on this task
1568  std::set< int > rowSet;
1569  std::set< int > colSet;
1570  // populate the sparsematrix, using rowMap and colMap
1571  for( int i = 0; i < nS; i++ )
1572  {
1573  const int vecRowValue = vecRow[i] - 1;
1574  const int vecColValue = vecCol[i] - 1;
1575  rowSet.insert( vecRowValue );
1576  colSet.insert( vecColValue );
1577  }
1578 
1579  int index = 0;
1580  row_gdofmap.resize( rowSet.size() );
1581  for( auto setIt : rowSet )
1582  {
1583  row_gdofmap[index] = setIt;
1584  rowMap[setIt] = index++;
1585  }
1586  m_nTotDofs_Dest = index;
1587  index = 0;
1588  col_gdofmap.resize( colSet.size() );
1589  for( auto setIt : colSet )
1590  {
1591  col_gdofmap[index] = setIt;
1592  colMap[setIt] = index++;
1593  }
1594  m_nTotDofs_SrcCov = index;
1595 
1596  tripletList.reserve( nS );
1597  for( int i = 0; i < nS; i++ )
1598  {
1599  const int vecRowValue = vecRow[i] - 1; // the rows, cols are 1 based in the file
1600  const int vecColValue = vecCol[i] - 1; // sparse matrix will be 0 based
1601  double value = vecS[i];
1602  tripletList.emplace_back( rowMap[vecRowValue], colMap[vecColValue], value );
1603  }
1604  }
1605 
1606  m_weightMatrix.resize( m_nTotDofs_Dest, m_nTotDofs_SrcCov );
1607  m_rowVector.resize( m_nTotDofs_Dest );
1608  m_colVector.resize( m_nTotDofs_SrcCov );
1609  m_nTotDofs_Src = m_nTotDofs_SrcCov; // do we need both?
1610  m_weightMatrix.setFromTriplets( tripletList.begin(), tripletList.end() );
1611  // Reset the source and target data first
1612  m_rowVector.setZero();
1613  m_colVector.setZero();
1614 #ifdef VERBOSE
1615  serializeSparseMatrix( m_weightMatrix, "map_operator_" + std::to_string( rank ) + ".txt" );
1616 #endif
1617 // #ifdef MOAB_HAVE_EIGEN3
1618 #endif
1619  // TODO: make this flexible and read the order from map with help of metadata
1620  m_nDofsPEl_Src = 1; // always assume FV-FV maps are read from file
1621  m_nDofsPEl_Dest = 1; // always assume FV-FV maps are read from file
1622 
1623  return moab::MB_SUCCESS;
1624 }

References CHECK_EXCEPTION, moab::TupleList::enableWriteAccess(), moab::error(), moab::TupleList::get_n(), moab::TupleList::inc_n(), moab::TupleList::initialize(), MB_SUCCESS, moab::TupleList::reset(), size, moab::TupleList::sort(), moab::TupleList::vi_rd, moab::TupleList::vi_wr, moab::TupleList::vr_rd, and moab::TupleList::vr_wr.

◆ serializeSparseMatrix()

template<typename SparseMatrixType >
void moab::TempestOnlineMap::serializeSparseMatrix ( const SparseMatrixType &  mat,
const std::string &  filename 
)
private

◆ set_col_dc_dofs()

moab::ErrorCode moab::TempestOnlineMap::set_col_dc_dofs ( std::vector< int > &  values_entities)

Definition at line 397 of file TempestOnlineMap.cpp.

398 {
399  // col_gdofmap has global dofs , that should be in the list of values, such that
400  // row_dtoc_dofmap[offsetDOF] = localDOF;
401  // we need to find col_dtoc_dofmap such that: col_gdofmap[ col_dtoc_dofmap[i] ] == values_entities [i];
402  // we know that col_gdofmap[0..(nbcols-1)] = global_col_dofs -> in values_entities
403  // form first inverse
404  //
405  // resize and initialize to -1 to signal that this value should not be used, if not set below
406  col_dtoc_dofmap.resize( values_entities.size(), -1 );
407  for( size_t j = 0; j < values_entities.size(); j++ )
408  {
409  // values are 1 based, but rowMap, colMap are not
410  const auto it = colMap.find( values_entities[j] - 1 );
411  if( it != colMap.end() ) col_dtoc_dofmap[j] = it->second;
412  }
413  return moab::MB_SUCCESS;
414 }

References MB_SUCCESS.

◆ set_row_dc_dofs()

moab::ErrorCode moab::TempestOnlineMap::set_row_dc_dofs ( std::vector< int > &  values_entities)

Definition at line 416 of file TempestOnlineMap.cpp.

417 {
418  // we need to find row_dtoc_dofmap such that: row_gdofmap[ row_dtoc_dofmap[i] ] == values_entities [i];
419  // resize and initialize to -1 to signal that this value should not be used, if not set below
420  row_dtoc_dofmap.resize( values_entities.size(), -1 );
421  for( size_t j = 0; j < values_entities.size(); j++ )
422  {
423  // values are 1 based, but rowMap, colMap are not
424  const auto it = rowMap.find( values_entities[j] - 1 );
425  if( it != rowMap.end() ) row_dtoc_dofmap[j] = it->second;
426  }
427  return moab::MB_SUCCESS;
428 }

References MB_SUCCESS.

◆ SetDestinationNDofsPerElement()

void moab::TempestOnlineMap::SetDestinationNDofsPerElement ( int  nt)
inline

Get the number of Degrees-Of-Freedom per element on the destination mesh.

Definition at line 596 of file TempestOnlineMap.hpp.

597 {
598  m_nDofsPEl_Dest = nt;
599 }

◆ SetDOFmapAssociation()

moab::ErrorCode moab::TempestOnlineMap::SetDOFmapAssociation ( DiscretizationType  srcType,
int  srcOrder,
bool  isSrcContinuous,
DataArray3D< int > *  srcdataGLLNodes,
DataArray3D< int > *  srcdataGLLNodesSrc,
DiscretizationType  destType,
int  destOrder,
bool  isTgtContinuous,
DataArray3D< int > *  tgtdataGLLNodes 
)

Compute the association between the solution tag global DoF numbering and the local matrix numbering so that matvec operations can be performed consistently.

Parameters
srcTypeThe discretization type of the source mesh
srcOrderThe order of the discretization on the source mesh
isSrcContinuousThe continuity of the discretization on the source mesh
srcdataGLLNodesThe GLL nodes on the source mesh
srcdataGLLNodesSrcThe GLL nodes on the source mesh
destTypeThe discretization type of the destination mesh
destOrderThe order of the discretization on the destination mesh
isTgtContinuousThe continuity of the discretization on the destination mesh
tgtdataGLLNodesThe GLL nodes on the destination mesh

Definition at line 163 of file TempestOnlineMap.cpp.

172 {
173  std::vector< bool > dgll_cgll_row_ldofmap, dgll_cgll_col_ldofmap, dgll_cgll_covcol_ldofmap;
174  std::vector< int > src_soln_gdofs, locsrc_soln_gdofs, tgt_soln_gdofs;
175 
176  // We are assuming that these are element based tags that are sized: np * np
177  m_srcDiscType = srcType;
178  m_destDiscType = destType;
179  m_input_order = srcOrder;
180  m_output_order = destOrder;
181 
182  bool vprint = is_root && false;
183 
184  // Compute and store the total number of source and target DoFs corresponding
185  // to number of rows and columns in the mapping.
186  // Now compute the mapping and store it for the covering mesh
187  int srcTagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
189  {
190  assert( m_nDofsPEl_Src == 1 );
191  col_gdofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
193  src_soln_gdofs.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
195  srcTagSize = 1;
196  }
197  else
198  {
199  col_gdofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
200  col_dtoc_dofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
201  src_soln_gdofs.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
203  }
204 
205  m_nTotDofs_SrcCov = 0;
206  if( srcdataGLLNodes == nullptr )
207  {
208  /* we only have a mapping for elements as DoFs */
209  for( unsigned i = 0; i < col_gdofmap.size(); ++i )
210  {
211  auto gdof = src_soln_gdofs[i];
212  assert( gdof > 0 );
213  col_gdofmap[i] = gdof - 1;
214  col_dtoc_dofmap[i] = i;
215  if( vprint ) std::cout << "Col: " << i << ", " << col_gdofmap[i] << "\n";
217  }
218  }
219  else
220  {
221  if( isSrcContinuous )
222  dgll_cgll_covcol_ldofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, false );
223  // Put these remap coefficients into the SparseMatrix map
224  for( unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
225  {
226  for( int p = 0; p < m_nDofsPEl_Src; p++ )
227  {
228  for( int q = 0; q < m_nDofsPEl_Src; q++ )
229  {
230  const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
231  const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
232  if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
233  {
235  dgll_cgll_covcol_ldofmap[localDOF] = true;
236  }
237  if( !isSrcContinuous ) m_nTotDofs_SrcCov++;
238  assert( src_soln_gdofs[offsetDOF] > 0 );
239  col_gdofmap[localDOF] = src_soln_gdofs[offsetDOF] - 1;
240  col_dtoc_dofmap[offsetDOF] = localDOF;
241  if( vprint )
242  std::cout << "Col: " << offsetDOF << ", " << localDOF << ", " << col_gdofmap[offsetDOF] << ", "
243  << m_nTotDofs_SrcCov << "\n";
244  }
245  }
246  }
247  }
248 
250  {
251  assert( m_nDofsPEl_Src == 1 );
252  srccol_gdofmap.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
254  locsrc_soln_gdofs.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
256  }
257  else
258  {
259  srccol_gdofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
260  srccol_dtoc_dofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
261  locsrc_soln_gdofs.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
263  }
264 
265  // Now compute the mapping and store it for the original source mesh
266  m_nTotDofs_Src = 0;
267  if( srcdataGLLNodesSrc == nullptr )
268  {
269  /* we only have a mapping for elements as DoFs */
270  for( unsigned i = 0; i < srccol_gdofmap.size(); ++i )
271  {
272  auto gdof = locsrc_soln_gdofs[i];
273  assert( gdof > 0 );
274  srccol_gdofmap[i] = gdof - 1;
275  srccol_dtoc_dofmap[i] = i;
276  m_nTotDofs_Src++;
277  }
278  }
279  else
280  {
281  if( isSrcContinuous ) dgll_cgll_col_ldofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, false );
282  // Put these remap coefficients into the SparseMatrix map
283  for( unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
284  {
285  for( int p = 0; p < m_nDofsPEl_Src; p++ )
286  {
287  for( int q = 0; q < m_nDofsPEl_Src; q++ )
288  {
289  const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
290  const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
291  if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
292  {
293  m_nTotDofs_Src++;
294  dgll_cgll_col_ldofmap[localDOF] = true;
295  }
296  if( !isSrcContinuous ) m_nTotDofs_Src++;
297  assert( locsrc_soln_gdofs[offsetDOF] > 0 );
298  srccol_gdofmap[localDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
299  srccol_dtoc_dofmap[offsetDOF] = localDOF;
300  }
301  }
302  }
303  }
304 
305  int tgtTagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
307  {
308  assert( m_nDofsPEl_Dest == 1 );
309  row_gdofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
310  row_dtoc_dofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
311  tgt_soln_gdofs.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
313  tgtTagSize = 1;
314  }
315  else
316  {
317  row_gdofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
318  row_dtoc_dofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
319  tgt_soln_gdofs.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
321  }
322 
323  // Now compute the mapping and store it for the target mesh
324  // To access the GID for each row: row_gdofmap [ row_ldofmap [ 0 : local_ndofs ] ] = GDOF
325  m_nTotDofs_Dest = 0;
326  if( tgtdataGLLNodes == nullptr )
327  {
328  /* we only have a mapping for elements as DoFs */
329  for( unsigned i = 0; i < row_gdofmap.size(); ++i )
330  {
331  auto gdof = tgt_soln_gdofs[i];
332  assert( gdof > 0 );
333  row_gdofmap[i] = gdof - 1;
334  row_dtoc_dofmap[i] = i;
335  if( vprint ) std::cout << "Row: " << i << ", " << row_gdofmap[i] << "\n";
336  m_nTotDofs_Dest++;
337  }
338  }
339  else
340  {
341  if( isTgtContinuous ) dgll_cgll_row_ldofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, false );
342  // Put these remap coefficients into the SparseMatrix map
343  for( unsigned j = 0; j < m_remapper->m_target_entities.size(); j++ )
344  {
345  for( int p = 0; p < m_nDofsPEl_Dest; p++ )
346  {
347  for( int q = 0; q < m_nDofsPEl_Dest; q++ )
348  {
349  const int localDOF = ( *tgtdataGLLNodes )[p][q][j] - 1;
350  const int offsetDOF = j * tgtTagSize + p * m_nDofsPEl_Dest + q;
351  if( isTgtContinuous && !dgll_cgll_row_ldofmap[localDOF] )
352  {
353  m_nTotDofs_Dest++;
354  dgll_cgll_row_ldofmap[localDOF] = true;
355  }
356  if( !isTgtContinuous ) m_nTotDofs_Dest++;
357  assert( tgt_soln_gdofs[offsetDOF] > 0 );
358  row_gdofmap[localDOF] = tgt_soln_gdofs[offsetDOF] - 1;
359  row_dtoc_dofmap[offsetDOF] = localDOF;
360  if( vprint )
361  std::cout << "Row: " << offsetDOF << ", " << localDOF << ", " << row_gdofmap[offsetDOF] << ", "
362  << m_nTotDofs_Dest << "\n";
363  }
364  }
365  }
366  }
367 
368  // Let us also allocate the local representation of the sparse matrix
369 #if defined( MOAB_HAVE_EIGEN3 ) && defined( VERBOSE )
370  if( vprint )
371  {
372  std::cout << "[" << rank << "]" << "DoFs: row = " << m_nTotDofs_Dest << ", " << row_gdofmap.size()
373  << ", col = " << m_nTotDofs_Src << ", " << m_nTotDofs_SrcCov << ", " << col_gdofmap.size() << "\n";
374  // std::cout << "Max col_dofmap: " << maxcol << ", Min col_dofmap" << mincol << "\n";
375  }
376 #endif
377 
378  // check monotonicity of row_gdofmap and col_gdofmap
379 #ifdef CHECK_INCREASING_DOF
380  for( size_t i = 0; i < row_gdofmap.size() - 1; i++ )
381  {
382  if( row_gdofmap[i] > row_gdofmap[i + 1] )
383  std::cout << " on rank " << rank << " in row_gdofmap[" << i << "]=" << row_gdofmap[i] << " > row_gdofmap["
384  << i + 1 << "]=" << row_gdofmap[i + 1] << " \n";
385  }
386  for( size_t i = 0; i < col_gdofmap.size() - 1; i++ )
387  {
388  if( col_gdofmap[i] > col_gdofmap[i + 1] )
389  std::cout << " on rank " << rank << " in col_gdofmap[" << i << "]=" << col_gdofmap[i] << " > col_gdofmap["
390  << i + 1 << "]=" << col_gdofmap[i + 1] << " \n";
391  }
392 #endif
393 
394  return moab::MB_SUCCESS;
395 }

References MB_CHK_ERR, and MB_SUCCESS.

◆ SetDOFmapTags()

moab::ErrorCode moab::TempestOnlineMap::SetDOFmapTags ( const std::string  srcDofTagName,
const std::string  tgtDofTagName 
)

Store the tag names associated with global DoF ids for source and target meshes to be used for mapping.

Parameters
srcDofTagNameThe tag name associated with global DoF ids for the source mesh
tgtDofTagNameThe tag name associated with global DoF ids for the target mesh

Definition at line 131 of file TempestOnlineMap.cpp.

133 {
134  moab::ErrorCode rval;
135 
136  int tagSize = 0;
138  rval =
139  m_interface->tag_get_handle( srcDofTagName.c_str(), tagSize, MB_TYPE_INTEGER, this->m_dofTagSrc, MB_TAG_ANY );
140 
142  {
143  MB_CHK_SET_ERR( MB_FAILURE, "DoF tag is not set correctly for source mesh." );
144  }
145  else
146  MB_CHK_ERR( rval );
147 
149  rval =
150  m_interface->tag_get_handle( tgtDofTagName.c_str(), tagSize, MB_TYPE_INTEGER, this->m_dofTagDest, MB_TAG_ANY );
152  {
153  MB_CHK_SET_ERR( MB_FAILURE, "DoF tag is not set correctly for target mesh." );
154  }
155  else
156  MB_CHK_ERR( rval );
157 
158  return moab::MB_SUCCESS;
159 }

References ErrorCode, MB_CHK_ERR, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_ANY, MB_TAG_NOT_FOUND, and MB_TYPE_INTEGER.

◆ SetMeshInput()

void moab::TempestOnlineMap::SetMeshInput ( Mesh *  imesh)
inline

Definition at line 453 of file TempestOnlineMap.hpp.

454  {
455  m_meshInput = imesh;
456  };

References m_meshInput.

◆ SetSourceNDofsPerElement()

void moab::TempestOnlineMap::SetSourceNDofsPerElement ( int  ns)
inline

Set the number of Degrees-Of-Freedom per element on the source mesh.

Definition at line 591 of file TempestOnlineMap.hpp.

592 {
593  m_nDofsPEl_Src = ns;
594 }

◆ setup_sizes_dimensions()

void moab::TempestOnlineMap::setup_sizes_dimensions ( )
private

Definition at line 93 of file TempestOnlineMap.cpp.

94 {
95  if( m_meshInputCov )
96  {
97  std::vector< std::string > dimNames;
98  std::vector< int > dimSizes;
99  dimNames.push_back( "num_elem" );
100  dimSizes.push_back( m_meshInputCov->faces.size() );
101 
102  this->InitializeSourceDimensions( dimNames, dimSizes );
103  }
104 
105  if( m_meshOutput )
106  {
107  std::vector< std::string > dimNames;
108  std::vector< int > dimSizes;
109  dimNames.push_back( "num_elem" );
110  dimSizes.push_back( m_meshOutput->faces.size() );
111 
112  this->InitializeTargetDimensions( dimNames, dimSizes );
113  }
114 }

Referenced by TempestOnlineMap().

◆ WriteHDF5MapFile()

moab::ErrorCode moab::TempestOnlineMap::WriteHDF5MapFile ( const std::string &  filename)
private

Parallel I/O with NetCDF to write out the SCRIP file from multiple processors.

Need to get the global maximum of number of vertices per element Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However, when writing this out, other processes may have a different size for the same array. This is hence a mess to consolidate in h5mtoscrip eventually.

Definition at line 829 of file TempestOnlineMapIO.cpp.

830 {
831  moab::ErrorCode rval;
832 
833  /**
834  * Need to get the global maximum of number of vertices per element
835  * Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for
836  *dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However,
837  *when writing this out, other processes may have a different size for the same array. This is
838  *hence a mess to consolidate in h5mtoscrip eventually.
839  **/
840 
841  /* Let us compute all relevant data for the current original source mesh on the process */
842  DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea;
843  DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat;
844  DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat;
846  {
847  this->InitializeCoordinatesFromMeshFV(
848  *m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat,
849  ( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ) /* fLatLon = false */,
851 
852  vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() );
853  for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i )
854  vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i];
855  }
856  else
857  {
858  DataArray3D< double > dataGLLJacobianSrc;
859  this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon,
860  dSourceCenterLat, dSourceVertexLon, dSourceVertexLat );
861 
862  // Generate the continuous Jacobian for input mesh
863  GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc );
864 
866  {
867  GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, vecSourceFaceArea );
868  }
869  else
870  {
871  GenerateDiscontinuousJacobian( dataGLLJacobianSrc, vecSourceFaceArea );
872  }
873  }
874 
876  {
877  this->InitializeCoordinatesFromMeshFV(
878  *m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat,
879  ( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ) /* fLatLon = false */,
881 
882  vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() );
883  for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i )
884  vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i];
885  }
886  else
887  {
888  DataArray3D< double > dataGLLJacobianDest;
889  this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon,
890  dTargetCenterLat, dTargetVertexLon, dTargetVertexLat );
891 
892  // Generate the continuous Jacobian for input mesh
893  GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest );
894 
896  {
897  GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, vecTargetFaceArea );
898  }
899  else
900  {
901  GenerateDiscontinuousJacobian( dataGLLJacobianDest, vecTargetFaceArea );
902  }
903  }
904 
905  moab::EntityHandle& m_meshOverlapSet = m_remapper->m_overlap_set;
906  int tot_src_ents = m_remapper->m_source_entities.size();
907  int tot_tgt_ents = m_remapper->m_target_entities.size();
908  int tot_src_size = dSourceCenterLon.GetRows();
909  int tot_tgt_size = m_dTargetCenterLon.GetRows();
910  int tot_vsrc_size = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns();
911  int tot_vtgt_size = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns();
912 
913  const int weightMatNNZ = m_weightMatrix.nonZeros();
914  moab::Tag tagMapMetaData, tagMapIndexRow, tagMapIndexCol, tagMapValues, srcEleIDs, tgtEleIDs;
915  rval = m_interface->tag_get_handle( "SMAT_DATA", 13, moab::MB_TYPE_INTEGER, tagMapMetaData,
916  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
917  rval = m_interface->tag_get_handle( "SMAT_ROWS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexRow,
918  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
919  rval = m_interface->tag_get_handle( "SMAT_COLS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexCol,
920  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
921  rval = m_interface->tag_get_handle( "SMAT_VALS", weightMatNNZ, moab::MB_TYPE_DOUBLE, tagMapValues,
922  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
923  rval = m_interface->tag_get_handle( "SourceGIDS", tot_src_size, moab::MB_TYPE_INTEGER, srcEleIDs,
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( "TargetGIDS", tot_tgt_size, moab::MB_TYPE_INTEGER, tgtEleIDs,
926  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
927  moab::Tag srcAreaValues, tgtAreaValues;
928  rval = m_interface->tag_get_handle( "SourceAreas", tot_src_size, moab::MB_TYPE_DOUBLE, srcAreaValues,
929  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
930  rval = m_interface->tag_get_handle( "TargetAreas", tot_tgt_size, moab::MB_TYPE_DOUBLE, tgtAreaValues,
931  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
932  moab::Tag tagSrcCoordsCLon, tagSrcCoordsCLat, tagTgtCoordsCLon, tagTgtCoordsCLat;
933  rval = m_interface->tag_get_handle( "SourceCoordCenterLon", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLon,
934  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
935  rval = m_interface->tag_get_handle( "SourceCoordCenterLat", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLat,
936  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
937  rval = m_interface->tag_get_handle( "TargetCoordCenterLon", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLon,
938  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
939  rval = m_interface->tag_get_handle( "TargetCoordCenterLat", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLat,
940  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
941  moab::Tag tagSrcCoordsVLon, tagSrcCoordsVLat, tagTgtCoordsVLon, tagTgtCoordsVLat;
942  rval = m_interface->tag_get_handle( "SourceCoordVertexLon", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLon,
943  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
944  rval = m_interface->tag_get_handle( "SourceCoordVertexLat", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLat,
945  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
946  rval = m_interface->tag_get_handle( "TargetCoordVertexLon", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLon,
947  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
948  rval = m_interface->tag_get_handle( "TargetCoordVertexLat", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLat,
949  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
950  moab::Tag srcMaskValues, tgtMaskValues;
951  if( m_iSourceMask.IsAttached() )
952  {
953  rval = m_interface->tag_get_handle( "SourceMask", m_iSourceMask.GetRows(), moab::MB_TYPE_INTEGER, srcMaskValues,
954  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
955  }
956  if( m_iTargetMask.IsAttached() )
957  {
958  rval = m_interface->tag_get_handle( "TargetMask", m_iTargetMask.GetRows(), moab::MB_TYPE_INTEGER, tgtMaskValues,
959  moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
960  }
961 
962  std::vector< int > smatrowvals( weightMatNNZ ), smatcolvals( weightMatNNZ );
963  std::vector< double > smatvals( weightMatNNZ );
964  // const double* smatvals = m_weightMatrix.valuePtr();
965  // Loop over the matrix entries and find the max global ID for rows and columns
966  for( int k = 0, offset = 0; k < m_weightMatrix.outerSize(); ++k )
967  {
968  for( moab::TempestOnlineMap::WeightMatrix::InnerIterator it( m_weightMatrix, k ); it; ++it, ++offset )
969  {
970  smatrowvals[offset] = this->GetRowGlobalDoF( it.row() );
971  smatcolvals[offset] = this->GetColGlobalDoF( it.col() );
972  smatvals[offset] = it.value();
973  }
974  }
975 
976  /* Set the global IDs for the DoFs */
977  ////
978  // col_gdofmap [ col_ldofmap [ 0 : local_ndofs ] ] = GDOF
979  // row_gdofmap [ row_ldofmap [ 0 : local_ndofs ] ] = GDOF
980  ////
981  int maxrow = 0, maxcol = 0;
982  std::vector< int > src_global_dofs( tot_src_size ), tgt_global_dofs( tot_tgt_size );
983  for( int i = 0; i < tot_src_size; ++i )
984  {
985  src_global_dofs[i] = srccol_gdofmap[i];
986  maxcol = ( src_global_dofs[i] > maxcol ) ? src_global_dofs[i] : maxcol;
987  }
988 
989  for( int i = 0; i < tot_tgt_size; ++i )
990  {
991  tgt_global_dofs[i] = row_gdofmap[i];
992  maxrow = ( tgt_global_dofs[i] > maxrow ) ? tgt_global_dofs[i] : maxrow;
993  }
994 
995  ///////////////////////////////////////////////////////////////////////////
996  // The metadata in H5M file contains the following data:
997  //
998  // 1. n_a: Total source entities: (number of elements in source mesh)
999  // 2. n_b: Total target entities: (number of elements in target mesh)
1000  // 3. nv_a: Max edge size of elements in source mesh
1001  // 4. nv_b: Max edge size of elements in target mesh
1002  // 5. maxrows: Number of rows in remap weight matrix
1003  // 6. maxcols: Number of cols in remap weight matrix
1004  // 7. nnz: Number of total nnz in sparse remap weight matrix
1005  // 8. np_a: The order of the field description on the source mesh: >= 1
1006  // 9. np_b: The order of the field description on the target mesh: >= 1
1007  // 10. method_a: The type of discretization for field on source mesh: [0 = FV, 1 = cGLL, 2 =
1008  // dGLL]
1009  // 11. method_b: The type of discretization for field on target mesh: [0 = FV, 1 = cGLL, 2 =
1010  // dGLL]
1011  // 12. conserved: Flag to specify whether the remap operator has conservation constraints: [0,
1012  // 1]
1013  // 13. monotonicity: Flags to specify whether the remap operator has monotonicity constraints:
1014  // [0, 1, 2]
1015  //
1016  ///////////////////////////////////////////////////////////////////////////
1017  int map_disc_details[6];
1018  map_disc_details[0] = m_nDofsPEl_Src;
1019  map_disc_details[1] = m_nDofsPEl_Dest;
1021  ? 0
1022  : ( m_srcDiscType == DiscretizationType_CGLL ? 1 : 2 ) );
1024  ? 0
1025  : ( m_destDiscType == DiscretizationType_CGLL ? 1 : 2 ) );
1026  map_disc_details[4] = ( m_bConserved ? 1 : 0 );
1027  map_disc_details[5] = m_iMonotonicity;
1028 
1029 #ifdef MOAB_HAVE_MPI
1030  int loc_smatmetadata[13] = { tot_src_ents,
1031  tot_tgt_ents,
1034  maxrow + 1,
1035  maxcol + 1,
1036  weightMatNNZ,
1037  map_disc_details[0],
1038  map_disc_details[1],
1039  map_disc_details[2],
1040  map_disc_details[3],
1041  map_disc_details[4],
1042  map_disc_details[5] };
1043  rval = m_interface->tag_set_data( tagMapMetaData, &m_meshOverlapSet, 1, &loc_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1044  int glb_smatmetadata[13] = { 0,
1045  0,
1046  0,
1047  0,
1048  0,
1049  0,
1050  0,
1051  map_disc_details[0],
1052  map_disc_details[1],
1053  map_disc_details[2],
1054  map_disc_details[3],
1055  map_disc_details[4],
1056  map_disc_details[5] };
1057  int loc_buf[7] = {
1058  tot_src_ents, tot_tgt_ents, weightMatNNZ, m_remapper->max_source_edges, m_remapper->max_target_edges,
1059  maxrow, maxcol };
1060  int glb_buf[4] = { 0, 0, 0, 0 };
1061  MPI_Reduce( &loc_buf[0], &glb_buf[0], 3, MPI_INT, MPI_SUM, 0, m_pcomm->comm() );
1062  glb_smatmetadata[0] = glb_buf[0];
1063  glb_smatmetadata[1] = glb_buf[1];
1064  glb_smatmetadata[6] = glb_buf[2];
1065  MPI_Reduce( &loc_buf[3], &glb_buf[0], 4, MPI_INT, MPI_MAX, 0, m_pcomm->comm() );
1066  glb_smatmetadata[2] = glb_buf[0];
1067  glb_smatmetadata[3] = glb_buf[1];
1068  glb_smatmetadata[4] = glb_buf[2];
1069  glb_smatmetadata[5] = glb_buf[3];
1070 #else
1071  int glb_smatmetadata[13] = { tot_src_ents,
1072  tot_tgt_ents,
1075  maxrow,
1076  maxcol,
1077  weightMatNNZ,
1078  map_disc_details[0],
1079  map_disc_details[1],
1080  map_disc_details[2],
1081  map_disc_details[3],
1082  map_disc_details[4],
1083  map_disc_details[5] };
1084 #endif
1085  // These values represent number of rows and columns. So should be 1-based.
1086  glb_smatmetadata[4]++;
1087  glb_smatmetadata[5]++;
1088 
1089  if( this->is_root )
1090  {
1091  std::cout << " " << this->rank << " Writing remap weights with size [" << glb_smatmetadata[4] << " X "
1092  << glb_smatmetadata[5] << "] and NNZ = " << glb_smatmetadata[6] << std::endl;
1093  EntityHandle root_set = 0;
1094  rval = m_interface->tag_set_data( tagMapMetaData, &root_set, 1, &glb_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1095  }
1096 
1097  int dsize;
1098  const int numval = weightMatNNZ;
1099  const void* smatrowvals_d = smatrowvals.data();
1100  const void* smatcolvals_d = smatcolvals.data();
1101  const void* smatvals_d = smatvals.data();
1102  rval = m_interface->tag_set_by_ptr( tagMapIndexRow, &m_meshOverlapSet, 1, &smatrowvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1103  rval = m_interface->tag_set_by_ptr( tagMapIndexCol, &m_meshOverlapSet, 1, &smatcolvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1104  rval = m_interface->tag_set_by_ptr( tagMapValues, &m_meshOverlapSet, 1, &smatvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1105 
1106  /* Set the global IDs for the DoFs */
1107  const void* srceleidvals_d = src_global_dofs.data();
1108  const void* tgteleidvals_d = tgt_global_dofs.data();
1109  dsize = src_global_dofs.size();
1110  rval = m_interface->tag_set_by_ptr( srcEleIDs, &m_meshOverlapSet, 1, &srceleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1111  dsize = tgt_global_dofs.size();
1112  rval = m_interface->tag_set_by_ptr( tgtEleIDs, &m_meshOverlapSet, 1, &tgteleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1113 
1114  /* Set the source and target areas */
1115  const void* srcareavals_d = vecSourceFaceArea;
1116  const void* tgtareavals_d = vecTargetFaceArea;
1117  dsize = tot_src_size;
1118  rval = m_interface->tag_set_by_ptr( srcAreaValues, &m_meshOverlapSet, 1, &srcareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1119  dsize = tot_tgt_size;
1120  rval = m_interface->tag_set_by_ptr( tgtAreaValues, &m_meshOverlapSet, 1, &tgtareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1121 
1122  /* Set the coordinates for source and target center vertices */
1123  const void* srccoordsclonvals_d = &dSourceCenterLon[0];
1124  const void* srccoordsclatvals_d = &dSourceCenterLat[0];
1125  dsize = dSourceCenterLon.GetRows();
1126  rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLon, &m_meshOverlapSet, 1, &srccoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1127  rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLat, &m_meshOverlapSet, 1, &srccoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1128  const void* tgtcoordsclonvals_d = &m_dTargetCenterLon[0];
1129  const void* tgtcoordsclatvals_d = &m_dTargetCenterLat[0];
1130  dsize = vecTargetFaceArea.GetRows();
1131  rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLon, &m_meshOverlapSet, 1, &tgtcoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1132  rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLat, &m_meshOverlapSet, 1, &tgtcoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1133 
1134  /* Set the coordinates for source and target element vertices */
1135  const void* srccoordsvlonvals_d = &( dSourceVertexLon[0][0] );
1136  const void* srccoordsvlatvals_d = &( dSourceVertexLat[0][0] );
1137  dsize = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns();
1138  rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLon, &m_meshOverlapSet, 1, &srccoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1139  rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLat, &m_meshOverlapSet, 1, &srccoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1140  const void* tgtcoordsvlonvals_d = &( m_dTargetVertexLon[0][0] );
1141  const void* tgtcoordsvlatvals_d = &( m_dTargetVertexLat[0][0] );
1142  dsize = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns();
1143  rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLon, &m_meshOverlapSet, 1, &tgtcoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1144  rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLat, &m_meshOverlapSet, 1, &tgtcoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1145 
1146  /* Set the masks for source and target meshes if available */
1147  if( m_iSourceMask.IsAttached() )
1148  {
1149  const void* srcmaskvals_d = m_iSourceMask;
1150  dsize = m_iSourceMask.GetRows();
1151  rval = m_interface->tag_set_by_ptr( srcMaskValues, &m_meshOverlapSet, 1, &srcmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1152  }
1153 
1154  if( m_iTargetMask.IsAttached() )
1155  {
1156  const void* tgtmaskvals_d = m_iTargetMask;
1157  dsize = m_iTargetMask.GetRows();
1158  rval = m_interface->tag_set_by_ptr( tgtMaskValues, &m_meshOverlapSet, 1, &tgtmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
1159  }
1160 
1161 #ifdef MOAB_HAVE_MPI
1162  const char* writeOptions = ( this->size > 1 ? "PARALLEL=WRITE_PART" : "" );
1163 #else
1164  const char* writeOptions = "";
1165 #endif
1166 
1167  // EntityHandle sets[3] = {m_remapper->m_source_set, m_remapper->m_target_set, m_remapper->m_overlap_set};
1168  EntityHandle sets[1] = { m_remapper->m_overlap_set };
1169  rval = m_interface->write_file( strOutputFile.c_str(), NULL, writeOptions, sets, 1 );MB_CHK_ERR( rval );
1170 
1171 #ifdef WRITE_SCRIP_FILE
1172  sstr.str( "" );
1173  sstr << ctx.outFilename.substr( 0, lastindex ) << "_" << proc_id << ".nc";
1174  std::map< std::string, std::string > mapAttributes;
1175  mapAttributes["Creator"] = "MOAB mbtempest workflow";
1176  if( !ctx.proc_id ) std::cout << "Writing offline map to file: " << sstr.str() << std::endl;
1177  this->Write( strOutputFile.c_str(), mapAttributes, NcFile::Netcdf4 );
1178  sstr.str( "" );
1179 #endif
1180 
1181  return moab::MB_SUCCESS;
1182 }

References ErrorCode, MB_CHK_ERR, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_SPARSE, MB_TAG_VARLEN, MB_TYPE_DOUBLE, MB_TYPE_INTEGER, moab::TempestRemapper::RLL, and size.

◆ WriteParallelMap()

moab::ErrorCode moab::TempestOnlineMap::WriteParallelMap ( const std::string &  strTarget,
const std::map< std::string, std::string > &  attrMap 
)

Write the TempestOnlineMap to a parallel NetCDF file.

Definition at line 193 of file TempestOnlineMapIO.cpp.

195 {
196  moab::ErrorCode rval;
197 
198  size_t lastindex = strFilename.find_last_of( "." );
199  std::string extension = strFilename.substr( lastindex + 1, strFilename.size() );
200 
201  // Write the map file to disk in parallel
202  if( extension == "nc" )
203  {
204  /* Invoke the actual call to write the parallel map to disk in SCRIP format */
205  rval = this->WriteSCRIPMapFile( strFilename.c_str(), attrMap );MB_CHK_ERR( rval );
206  }
207  else
208  {
209  /* Write to the parallel H5M format */
210  rval = this->WriteHDF5MapFile( strFilename.c_str() );MB_CHK_ERR( rval );
211  }
212 
213  return rval;
214 }

References ErrorCode, and MB_CHK_ERR.

Referenced by main().

◆ WriteSCRIPMapFile()

moab::ErrorCode moab::TempestOnlineMap::WriteSCRIPMapFile ( const std::string &  strOutputFile,
const std::map< std::string, std::string > &  attrMap 
)
private

Copy the local matrix from Tempest SparseMatrix representation (ELL) to the parallel CSR Eigen Matrix for scalable application of matvec needed for projections.

Parallel I/O with HDF5 to write out the remapping weights from multiple processors.

Need to get the global maximum of number of vertices per element Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However, when writing this out, other processes may have a different size for the same array. This is hence a mess to consolidate in h5mtoscrip eventually.

Definition at line 218 of file TempestOnlineMapIO.cpp.

220 {
221  NcError error( NcError::silent_nonfatal );
222 
223 #ifdef MOAB_HAVE_NETCDFPAR
224  bool is_independent = true;
225  ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcFile::Replace, NcFile::Netcdf4 );
226  // ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 );
227 #else
228  NcFile ncMap( strFilename.c_str(), NcFile::Replace );
229 #endif
230 
231  if( !ncMap.is_valid() )
232  {
233  _EXCEPTION1( "Unable to open output map file \"%s\"", strFilename.c_str() );
234  }
235 
236  // Attributes
237  // ncMap.add_att( "Title", "MOAB-TempestRemap Online Regridding Weight Generator" );
238  auto it = attrMap.begin();
239  while( it != attrMap.end() )
240  {
241  // set the map attributes
242  ncMap.add_att( it->first.c_str(), it->second.c_str() );
243  // increment iterator
244  it++;
245  }
246 
247  /**
248  * Need to get the global maximum of number of vertices per element
249  * Key issue is that when calling InitializeCoordinatesFromMeshFV, the allocation for
250  *dVertexLon/dVertexLat are made based on the maximum vertices in the current process. However,
251  *when writing this out, other processes may have a different size for the same array. This is
252  *hence a mess to consolidate in h5mtoscrip eventually.
253  **/
254 
255  /* Let us compute all relevant data for the current original source mesh on the process */
256  DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea;
257  DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat;
258  DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat;
260  {
261  this->InitializeCoordinatesFromMeshFV(
262  *m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat,
263  ( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ), /* fLatLon = false */
265 
266  vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() );
267  for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i )
268  vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i];
269  }
270  else
271  {
272  DataArray3D< double > dataGLLJacobianSrc;
273  this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon,
274  dSourceCenterLat, dSourceVertexLon, dSourceVertexLat );
275 
276  // Generate the continuous Jacobian for input mesh
277  GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc );
278 
280  {
281  GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, vecSourceFaceArea );
282  }
283  else
284  {
285  GenerateDiscontinuousJacobian( dataGLLJacobianSrc, vecSourceFaceArea );
286  }
287  }
288 
290  {
291  this->InitializeCoordinatesFromMeshFV(
292  *m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat,
293  ( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ), /* fLatLon = false */
295 
296  vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() );
297  for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i )
298  {
299  vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i];
300  }
301  }
302  else
303  {
304  DataArray3D< double > dataGLLJacobianDest;
305  this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon,
306  dTargetCenterLat, dTargetVertexLon, dTargetVertexLat );
307 
308  // Generate the continuous Jacobian for input mesh
309  GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest );
310 
312  {
313  GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, vecTargetFaceArea );
314  }
315  else
316  {
317  GenerateDiscontinuousJacobian( dataGLLJacobianDest, vecTargetFaceArea );
318  }
319  }
320 
321  // Map dimensions
322  unsigned nA = ( vecSourceFaceArea.GetRows() );
323  unsigned nB = ( vecTargetFaceArea.GetRows() );
324 
325  std::vector< int > masksA, masksB;
326  ErrorCode rval = m_remapper->GetIMasks( moab::Remapper::SourceMesh, masksA );MB_CHK_SET_ERR( rval, "Trouble getting masks for source" );
327  rval = m_remapper->GetIMasks( moab::Remapper::TargetMesh, masksB );MB_CHK_SET_ERR( rval, "Trouble getting masks for target" );
328 
329  // Number of nodes per Face
330  int nSourceNodesPerFace = dSourceVertexLon.GetColumns();
331  int nTargetNodesPerFace = dTargetVertexLon.GetColumns();
332 
333  // if source or target cells have triangles at poles, center of those triangles need to come from
334  // the original quad, not from center in 3d, converted to 2d again
335  // start copy OnlineMap.cpp tempestremap
336  // right now, do this only for source mesh; copy the logic for target mesh
337  for( unsigned i = 0; i < nA; i++ )
338  {
339  const Face& face = m_meshInput->faces[i];
340 
341  int nNodes = face.edges.size();
342  int indexNodeAtPole = -1;
343  if( 3 == nNodes ) // check if one node at the poles
344  {
345  for( int j = 0; j < nNodes; j++ )
346  if( fabs( fabs( dSourceVertexLat[i][j] ) - 90.0 ) < 1.0e-12 )
347  {
348  indexNodeAtPole = j;
349  break;
350  }
351  }
352  if( indexNodeAtPole < 0 ) continue; // continue i loop, do nothing
353  // recompute center of cell, from 3d data; add one 2 nodes at pole, and average
354  int nodeAtPole = face[indexNodeAtPole]; // use the overloaded operator
355  Node nodePole = m_meshInput->nodes[nodeAtPole];
356  Node newCenter = nodePole * 2;
357  for( int j = 1; j < nNodes; j++ )
358  {
359  int indexi = ( indexNodeAtPole + j ) % nNodes; // nNodes is 3 !
360  const Node& node = m_meshInput->nodes[face[indexi]];
361  newCenter = newCenter + node;
362  }
363  newCenter = newCenter * 0.25;
364  newCenter = newCenter.Normalized();
365 
366 #ifdef VERBOSE
367  double iniLon = dSourceCenterLon[i], iniLat = dSourceCenterLat[i];
368 #endif
369  // dSourceCenterLon, dSourceCenterLat
370  XYZtoRLL_Deg( newCenter.x, newCenter.y, newCenter.z, dSourceCenterLon[i], dSourceCenterLat[i] );
371 #ifdef VERBOSE
372  std::cout << " modify center of triangle from " << iniLon << " " << iniLat << " to " << dSourceCenterLon[i]
373  << " " << dSourceCenterLat[i] << "\n";
374 #endif
375  }
376 
377  // first move data if in parallel
378 #if defined( MOAB_HAVE_MPI )
379  int max_row_dof, max_col_dof; // output; arrays will be re-distributed in chunks [maxdof/size]
380  // if (size > 1)
381  {
382  int ierr = rearrange_arrays_by_dofs( srccol_gdofmap, vecSourceFaceArea, dSourceCenterLon, dSourceCenterLat,
383  dSourceVertexLon, dSourceVertexLat, masksA, nA, nSourceNodesPerFace,
384  max_col_dof ); // now nA will be close to maxdof/size
385  if( ierr != 0 )
386  {
387  _EXCEPTION1( "Unable to arrange source data %d ", nA );
388  }
389  // rearrange target data: (nB)
390  //
391  ierr = rearrange_arrays_by_dofs( row_gdofmap, vecTargetFaceArea, dTargetCenterLon, dTargetCenterLat,
392  dTargetVertexLon, dTargetVertexLat, masksB, nB, nTargetNodesPerFace,
393  max_row_dof ); // now nA will be close to maxdof/size
394  if( ierr != 0 )
395  {
396  _EXCEPTION1( "Unable to arrange target data %d ", nB );
397  }
398  }
399 #endif
400 
401  // Number of non-zeros in the remap matrix operator
402  int nS = m_weightMatrix.nonZeros();
403 
404 #if defined( MOAB_HAVE_MPI ) && defined( MOAB_HAVE_NETCDFPAR )
405  int locbuf[5] = { (int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace };
406  int offbuf[3] = { 0, 0, 0 };
407  int globuf[5] = { 0, 0, 0, 0, 0 };
408  MPI_Scan( locbuf, offbuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() );
409  MPI_Allreduce( locbuf, globuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() );
410  MPI_Allreduce( &locbuf[3], &globuf[3], 2, MPI_INT, MPI_MAX, m_pcomm->comm() );
411 
412  // MPI_Scan is inclusive of data in current rank; modify accordingly.
413  offbuf[0] -= nA;
414  offbuf[1] -= nB;
415  offbuf[2] -= nS;
416 
417 #else
418  int offbuf[3] = { 0, 0, 0 };
419  int globuf[5] = { (int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace };
420 #endif
421 
422  std::vector< std::string > srcdimNames, tgtdimNames;
423  std::vector< int > srcdimSizes, tgtdimSizes;
424  {
426  {
427  srcdimNames.push_back( "lat" );
428  srcdimNames.push_back( "lon" );
429  srcdimSizes.resize( 2, 0 );
430  srcdimSizes[0] = m_remapper->m_source_metadata[0];
431  srcdimSizes[1] = m_remapper->m_source_metadata[1];
432  }
433  else
434  {
435  srcdimNames.push_back( "num_elem" );
436  srcdimSizes.push_back( globuf[0] );
437  }
438 
440  {
441  tgtdimNames.push_back( "lat" );
442  tgtdimNames.push_back( "lon" );
443  tgtdimSizes.resize( 2, 0 );
444  tgtdimSizes[0] = m_remapper->m_target_metadata[0];
445  tgtdimSizes[1] = m_remapper->m_target_metadata[1];
446  }
447  else
448  {
449  tgtdimNames.push_back( "num_elem" );
450  tgtdimSizes.push_back( globuf[1] );
451  }
452  }
453 
454  // Write output dimensions entries
455  unsigned nSrcGridDims = ( srcdimSizes.size() );
456  unsigned nDstGridDims = ( tgtdimSizes.size() );
457 
458  NcDim* dimSrcGridRank = ncMap.add_dim( "src_grid_rank", nSrcGridDims );
459  NcDim* dimDstGridRank = ncMap.add_dim( "dst_grid_rank", nDstGridDims );
460 
461  NcVar* varSrcGridDims = ncMap.add_var( "src_grid_dims", ncInt, dimSrcGridRank );
462  NcVar* varDstGridDims = ncMap.add_var( "dst_grid_dims", ncInt, dimDstGridRank );
463 
464 #ifdef MOAB_HAVE_NETCDFPAR
465  ncMap.enable_var_par_access( varSrcGridDims, is_independent );
466  ncMap.enable_var_par_access( varDstGridDims, is_independent );
467 #endif
468 
469  // write dimension names
470  {
471  char szDim[64];
472  for( unsigned i = 0; i < srcdimSizes.size(); i++ )
473  {
474  varSrcGridDims->set_cur( nSrcGridDims - i - 1 );
475  varSrcGridDims->put( &( srcdimSizes[nSrcGridDims - i - 1] ), 1 );
476  }
477 
478  for( unsigned i = 0; i < srcdimSizes.size(); i++ )
479  {
480  snprintf( szDim, 64, "name%i", i );
481  varSrcGridDims->add_att( szDim, srcdimNames[nSrcGridDims - i - 1].c_str() );
482  }
483 
484  for( unsigned i = 0; i < tgtdimSizes.size(); i++ )
485  {
486  varDstGridDims->set_cur( nDstGridDims - i - 1 );
487  varDstGridDims->put( &( tgtdimSizes[nDstGridDims - i - 1] ), 1 );
488  }
489 
490  for( unsigned i = 0; i < tgtdimSizes.size(); i++ )
491  {
492  snprintf( szDim, 64, "name%i", i );
493  varDstGridDims->add_att( szDim, tgtdimNames[nDstGridDims - i - 1].c_str() );
494  }
495  }
496 
497  // Source and Target mesh resolutions
498  NcDim* dimNA = ncMap.add_dim( "n_a", globuf[0] );
499  NcDim* dimNB = ncMap.add_dim( "n_b", globuf[1] );
500 
501  // Number of nodes per Face
502  NcDim* dimNVA = ncMap.add_dim( "nv_a", globuf[3] );
503  NcDim* dimNVB = ncMap.add_dim( "nv_b", globuf[4] );
504 
505  // Write coordinates
506  NcVar* varYCA = ncMap.add_var( "yc_a", ncDouble, dimNA );
507  NcVar* varYCB = ncMap.add_var( "yc_b", ncDouble, dimNB );
508 
509  NcVar* varXCA = ncMap.add_var( "xc_a", ncDouble, dimNA );
510  NcVar* varXCB = ncMap.add_var( "xc_b", ncDouble, dimNB );
511 
512  NcVar* varYVA = ncMap.add_var( "yv_a", ncDouble, dimNA, dimNVA );
513  NcVar* varYVB = ncMap.add_var( "yv_b", ncDouble, dimNB, dimNVB );
514 
515  NcVar* varXVA = ncMap.add_var( "xv_a", ncDouble, dimNA, dimNVA );
516  NcVar* varXVB = ncMap.add_var( "xv_b", ncDouble, dimNB, dimNVB );
517 
518  // Write masks
519  NcVar* varMaskA = ncMap.add_var( "mask_a", ncInt, dimNA );
520  NcVar* varMaskB = ncMap.add_var( "mask_b", ncInt, dimNB );
521 
522 #ifdef MOAB_HAVE_NETCDFPAR
523  ncMap.enable_var_par_access( varYCA, is_independent );
524  ncMap.enable_var_par_access( varYCB, is_independent );
525  ncMap.enable_var_par_access( varXCA, is_independent );
526  ncMap.enable_var_par_access( varXCB, is_independent );
527  ncMap.enable_var_par_access( varYVA, is_independent );
528  ncMap.enable_var_par_access( varYVB, is_independent );
529  ncMap.enable_var_par_access( varXVA, is_independent );
530  ncMap.enable_var_par_access( varXVB, is_independent );
531  ncMap.enable_var_par_access( varMaskA, is_independent );
532  ncMap.enable_var_par_access( varMaskB, is_independent );
533 #endif
534 
535  varYCA->add_att( "units", "degrees" );
536  varYCB->add_att( "units", "degrees" );
537 
538  varXCA->add_att( "units", "degrees" );
539  varXCB->add_att( "units", "degrees" );
540 
541  varYVA->add_att( "units", "degrees" );
542  varYVB->add_att( "units", "degrees" );
543 
544  varXVA->add_att( "units", "degrees" );
545  varXVB->add_att( "units", "degrees" );
546 
547  // Verify dimensionality
548  if( dSourceCenterLon.GetRows() != nA )
549  {
550  _EXCEPTIONT( "Mismatch between dSourceCenterLon and nA" );
551  }
552  if( dSourceCenterLat.GetRows() != nA )
553  {
554  _EXCEPTIONT( "Mismatch between dSourceCenterLat and nA" );
555  }
556  if( dTargetCenterLon.GetRows() != nB )
557  {
558  _EXCEPTIONT( "Mismatch between dTargetCenterLon and nB" );
559  }
560  if( dTargetCenterLat.GetRows() != nB )
561  {
562  _EXCEPTIONT( "Mismatch between dTargetCenterLat and nB" );
563  }
564  if( dSourceVertexLon.GetRows() != nA )
565  {
566  _EXCEPTIONT( "Mismatch between dSourceVertexLon and nA" );
567  }
568  if( dSourceVertexLat.GetRows() != nA )
569  {
570  _EXCEPTIONT( "Mismatch between dSourceVertexLat and nA" );
571  }
572  if( dTargetVertexLon.GetRows() != nB )
573  {
574  _EXCEPTIONT( "Mismatch between dTargetVertexLon and nB" );
575  }
576  if( dTargetVertexLat.GetRows() != nB )
577  {
578  _EXCEPTIONT( "Mismatch between dTargetVertexLat and nB" );
579  }
580 
581  varYCA->set_cur( (long)offbuf[0] );
582  varYCA->put( &( dSourceCenterLat[0] ), nA );
583  varYCB->set_cur( (long)offbuf[1] );
584  varYCB->put( &( dTargetCenterLat[0] ), nB );
585 
586  varXCA->set_cur( (long)offbuf[0] );
587  varXCA->put( &( dSourceCenterLon[0] ), nA );
588  varXCB->set_cur( (long)offbuf[1] );
589  varXCB->put( &( dTargetCenterLon[0] ), nB );
590 
591  varYVA->set_cur( (long)offbuf[0] );
592  varYVA->put( &( dSourceVertexLat[0][0] ), nA, nSourceNodesPerFace );
593  varYVB->set_cur( (long)offbuf[1] );
594  varYVB->put( &( dTargetVertexLat[0][0] ), nB, nTargetNodesPerFace );
595 
596  varXVA->set_cur( (long)offbuf[0] );
597  varXVA->put( &( dSourceVertexLon[0][0] ), nA, nSourceNodesPerFace );
598  varXVB->set_cur( (long)offbuf[1] );
599  varXVB->put( &( dTargetVertexLon[0][0] ), nB, nTargetNodesPerFace );
600 
601  varMaskA->set_cur( (long)offbuf[0] );
602  varMaskA->put( &( masksA[0] ), nA );
603  varMaskB->set_cur( (long)offbuf[1] );
604  varMaskB->put( &( masksB[0] ), nB );
605 
606  // Write areas
607  NcVar* varAreaA = ncMap.add_var( "area_a", ncDouble, dimNA );
608 #ifdef MOAB_HAVE_NETCDFPAR
609  ncMap.enable_var_par_access( varAreaA, is_independent );
610 #endif
611  varAreaA->set_cur( (long)offbuf[0] );
612  varAreaA->put( &( vecSourceFaceArea[0] ), nA );
613 
614  NcVar* varAreaB = ncMap.add_var( "area_b", ncDouble, dimNB );
615 #ifdef MOAB_HAVE_NETCDFPAR
616  ncMap.enable_var_par_access( varAreaB, is_independent );
617 #endif
618  varAreaB->set_cur( (long)offbuf[1] );
619  varAreaB->put( &( vecTargetFaceArea[0] ), nB );
620 
621  // Write SparseMatrix entries
622  DataArray1D< int > vecRow( nS );
623  DataArray1D< int > vecCol( nS );
624  DataArray1D< double > vecS( nS );
625  DataArray1D< double > dFracA( nA );
626  DataArray1D< double > dFracB( nB );
627 
628  moab::TupleList tlValRow, tlValCol;
629  unsigned numr = 1; //
630  // value has to be sent to processor row/nB for for fracA and col/nA for fracB
631  // vecTargetArea (indexRow ) has to be sent for fracA (index col?)
632  // vecTargetFaceArea will have to be sent to col index, with its index !
633  tlValRow.initialize( 2, 0, 0, numr, nS ); // to proc(row), global row , value
634  tlValCol.initialize( 3, 0, 0, numr, nS ); // to proc(col), global row / col, value
635  tlValRow.enableWriteAccess();
636  tlValCol.enableWriteAccess();
637  /*
638  dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
639  dFracB[ row ] += val ;
640  */
641  int offset = 0;
642 #if defined( MOAB_HAVE_MPI )
643  int nAbase = ( max_col_dof + 1 ) / size; // it is nA, except last rank ( == size - 1 )
644  int nBbase = ( max_row_dof + 1 ) / size; // it is nB, except last rank ( == size - 1 )
645 #endif
646  for( int i = 0; i < m_weightMatrix.outerSize(); ++i )
647  {
648  for( WeightMatrix::InnerIterator it( m_weightMatrix, i ); it; ++it )
649  {
650  vecRow[offset] = 1 + this->GetRowGlobalDoF( it.row() ); // row index
651  vecCol[offset] = 1 + this->GetColGlobalDoF( it.col() ); // col index
652  vecS[offset] = it.value(); // value
653 
654 #if defined( MOAB_HAVE_MPI )
655  {
656  // value M(row, col) will contribute to procRow and procCol values for fracA and fracB
657  int procRow = ( vecRow[offset] - 1 ) / nBbase;
658  if( procRow >= size ) procRow = size - 1;
659  int procCol = ( vecCol[offset] - 1 ) / nAbase;
660  if( procCol >= size ) procCol = size - 1;
661  int nrInd = tlValRow.get_n();
662  tlValRow.vi_wr[2 * nrInd] = procRow;
663  tlValRow.vi_wr[2 * nrInd + 1] = vecRow[offset] - 1;
664  tlValRow.vr_wr[nrInd] = vecS[offset];
665  tlValRow.inc_n();
666  int ncInd = tlValCol.get_n();
667  tlValCol.vi_wr[3 * ncInd] = procCol;
668  tlValCol.vi_wr[3 * ncInd + 1] = vecRow[offset] - 1;
669  tlValCol.vi_wr[3 * ncInd + 2] = vecCol[offset] - 1; // this is column
670  tlValCol.vr_wr[ncInd] = vecS[offset];
671  tlValCol.inc_n();
672  }
673 
674 #endif
675  offset++;
676  }
677  }
678 #if defined( MOAB_HAVE_MPI )
679  // need to send values for their row and col processors, to compute fractions there
680  // now do the heavy communication
681  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValCol, 0 );
682  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValRow, 0 );
683 
684  // we have now, for example, dFracB[ row ] += val ;
685  // so we know that on current task, we received tlValRow
686  // reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
687  // dFracB[ row ] += val ;
688  for( unsigned i = 0; i < tlValRow.get_n(); i++ )
689  {
690  // int fromProc = tlValRow.vi_wr[2 * i];
691  int gRowInd = tlValRow.vi_wr[2 * i + 1];
692  int localIndexRow = gRowInd - nBbase * rank; // modulo nBbase rank is from 0 to size - 1;
693  double wgt = tlValRow.vr_wr[i];
694  assert( localIndexRow >= 0 );
695  assert( nB - localIndexRow > 0 );
696  dFracB[localIndexRow] += wgt;
697  }
698  // to compute dFracA we need vecTargetFaceArea[ row ]; we know the row, and we can get the proc we need it from
699 
700  std::set< int > neededRows;
701  for( unsigned i = 0; i < tlValCol.get_n(); i++ )
702  {
703  int rRowInd = tlValCol.vi_wr[3 * i + 1];
704  neededRows.insert( rRowInd );
705  // we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow
706  }
707  moab::TupleList tgtAreaReq;
708  tgtAreaReq.initialize( 2, 0, 0, 0, neededRows.size() );
709  tgtAreaReq.enableWriteAccess();
710  for( std::set< int >::iterator sit = neededRows.begin(); sit != neededRows.end(); sit++ )
711  {
712  int neededRow = *sit;
713  int procRow = neededRow / nBbase;
714  if( procRow >= size ) procRow = size - 1;
715  int nr = tgtAreaReq.get_n();
716  tgtAreaReq.vi_wr[2 * nr] = procRow;
717  tgtAreaReq.vi_wr[2 * nr + 1] = neededRow;
718  tgtAreaReq.inc_n();
719  }
720 
721  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaReq, 0 );
722  // we need to send back the tgtArea corresponding to row
723  moab::TupleList tgtAreaInfo; // load it with tgtArea at row
724  tgtAreaInfo.initialize( 2, 0, 0, 1, tgtAreaReq.get_n() );
725  tgtAreaInfo.enableWriteAccess();
726  for( unsigned i = 0; i < tgtAreaReq.get_n(); i++ )
727  {
728  int from_proc = tgtAreaReq.vi_wr[2 * i];
729  int row = tgtAreaReq.vi_wr[2 * i + 1];
730  int locaIndexRow = row - rank * nBbase;
731  double areaToSend = vecTargetFaceArea[locaIndexRow];
732  // int remoteIndex = tgtAreaReq.vi_wr[3*i + 2] ;
733 
734  tgtAreaInfo.vi_wr[2 * i] = from_proc; // send back requested info
735  tgtAreaInfo.vi_wr[2 * i + 1] = row;
736  tgtAreaInfo.vr_wr[i] = areaToSend; // this will be tgt area at row
737  tgtAreaInfo.inc_n();
738  }
739  ( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaInfo, 0 );
740 
741  std::map< int, double > areaAtRow;
742  for( unsigned i = 0; i < tgtAreaInfo.get_n(); i++ )
743  {
744  // we have received from proc, value for row !
745  int row = tgtAreaInfo.vi_wr[2 * i + 1];
746  areaAtRow[row] = tgtAreaInfo.vr_wr[i];
747  }
748 
749  // we have now for rows the
750  // it is ordered by index, so:
751  // now compute reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
752  // tgtAreaInfo will have at index i the area we need (from row)
753  // there should be an easier way :(
754  for( unsigned i = 0; i < tlValCol.get_n(); i++ )
755  {
756  int rRowInd = tlValCol.vi_wr[3 * i + 1];
757  int colInd = tlValCol.vi_wr[3 * i + 2];
758  double val = tlValCol.vr_wr[i];
759  int localColInd = colInd - rank * nAbase; // < local nA
760  // we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow
761  auto itMap = areaAtRow.find( rRowInd ); // it should be different from end
762  if( itMap != areaAtRow.end() )
763  {
764  double areaRow = itMap->second; // we fished a lot for this !
765  dFracA[localColInd] += val / vecSourceFaceArea[localColInd] * areaRow;
766  }
767  }
768 
769 #endif
770  // Load in data
771  NcDim* dimNS = ncMap.add_dim( "n_s", globuf[2] );
772 
773  NcVar* varRow = ncMap.add_var( "row", ncInt, dimNS );
774  NcVar* varCol = ncMap.add_var( "col", ncInt, dimNS );
775  NcVar* varS = ncMap.add_var( "S", ncDouble, dimNS );
776 #ifdef MOAB_HAVE_NETCDFPAR
777  ncMap.enable_var_par_access( varRow, is_independent );
778  ncMap.enable_var_par_access( varCol, is_independent );
779  ncMap.enable_var_par_access( varS, is_independent );
780 #endif
781 
782  varRow->set_cur( (long)offbuf[2] );
783  varRow->put( vecRow, nS );
784 
785  varCol->set_cur( (long)offbuf[2] );
786  varCol->put( vecCol, nS );
787 
788  varS->set_cur( (long)offbuf[2] );
789  varS->put( &( vecS[0] ), nS );
790 
791  // Calculate and write fractional coverage arrays
792  NcVar* varFracA = ncMap.add_var( "frac_a", ncDouble, dimNA );
793 #ifdef MOAB_HAVE_NETCDFPAR
794  ncMap.enable_var_par_access( varFracA, is_independent );
795 #endif
796  varFracA->add_att( "name", "fraction of target coverage of source dof" );
797  varFracA->add_att( "units", "unitless" );
798  varFracA->set_cur( (long)offbuf[0] );
799  varFracA->put( &( dFracA[0] ), nA );
800 
801  NcVar* varFracB = ncMap.add_var( "frac_b", ncDouble, dimNB );
802 #ifdef MOAB_HAVE_NETCDFPAR
803  ncMap.enable_var_par_access( varFracB, is_independent );
804 #endif
805  varFracB->add_att( "name", "fraction of source coverage of target dof" );
806  varFracB->add_att( "units", "unitless" );
807  varFracB->set_cur( (long)offbuf[1] );
808  varFracB->put( &( dFracB[0] ), nB );
809 
810  // Add global attributes
811  // std::map<std::string, std::string>::const_iterator iterAttributes =
812  // mapAttributes.begin();
813  // for (; iterAttributes != mapAttributes.end(); iterAttributes++) {
814  // ncMap.add_att(
815  // iterAttributes->first.c_str(),
816  // iterAttributes->second.c_str());
817  // }
818 
819  ncMap.close();
820 
821 #ifdef VERBOSE
822  serializeSparseMatrix( m_weightMatrix, "map_operator_" + std::to_string( rank ) + ".txt" );
823 #endif
824  return moab::MB_SUCCESS;
825 }

References moab::TupleList::enableWriteAccess(), moab::error(), ErrorCode, moab::TupleList::get_n(), moab::TupleList::inc_n(), moab::TupleList::initialize(), MB_CHK_SET_ERR, MB_SUCCESS, nr, moab::TempestRemapper::RLL, size, moab::Remapper::SourceMesh, moab::Remapper::TargetMesh, moab::TupleList::vi_wr, and moab::TupleList::vr_wr.

Member Data Documentation

◆ col_dtoc_dofmap

std::vector< int > moab::TempestOnlineMap::col_dtoc_dofmap
private

Definition at line 530 of file TempestOnlineMap.hpp.

◆ col_gdofmap

std::vector< unsigned > moab::TempestOnlineMap::col_gdofmap
private

Definition at line 527 of file TempestOnlineMap.hpp.

Referenced by fill_col_ids(), and LinearRemapNN_MOAB().

◆ colMap

std::map< int, int > moab::TempestOnlineMap::colMap
private

Definition at line 532 of file TempestOnlineMap.hpp.

◆ dataGLLNodesDest

DataArray3D< int > moab::TempestOnlineMap::dataGLLNodesDest
private

Definition at line 535 of file TempestOnlineMap.hpp.

◆ dataGLLNodesSrc

DataArray3D< int > moab::TempestOnlineMap::dataGLLNodesSrc
private

Definition at line 535 of file TempestOnlineMap.hpp.

◆ dataGLLNodesSrcCov

DataArray3D< int > moab::TempestOnlineMap::dataGLLNodesSrcCov
private

Definition at line 535 of file TempestOnlineMap.hpp.

◆ is_parallel

bool moab::TempestOnlineMap::is_parallel
private

Definition at line 550 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ is_root

bool moab::TempestOnlineMap::is_root
private

Definition at line 550 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_bConserved

bool moab::TempestOnlineMap::m_bConserved
private

Definition at line 542 of file TempestOnlineMap.hpp.

◆ m_destDiscType

DiscretizationType moab::TempestOnlineMap::m_destDiscType
private

Definition at line 536 of file TempestOnlineMap.hpp.

◆ m_dofTagDest

moab::Tag moab::TempestOnlineMap::m_dofTagDest
private

Definition at line 526 of file TempestOnlineMap.hpp.

◆ m_dofTagSrc

moab::Tag moab::TempestOnlineMap::m_dofTagSrc
private

The original tag data and local to global DoF mapping to associate matrix values to solution

Definition at line 526 of file TempestOnlineMap.hpp.

◆ m_eInputType

DiscretizationType moab::TempestOnlineMap::m_eInputType
private

Definition at line 541 of file TempestOnlineMap.hpp.

◆ m_eOutputType

DiscretizationType moab::TempestOnlineMap::m_eOutputType
private

Definition at line 541 of file TempestOnlineMap.hpp.

◆ m_iMonotonicity

int moab::TempestOnlineMap::m_iMonotonicity
private

Definition at line 543 of file TempestOnlineMap.hpp.

◆ m_input_order

int moab::TempestOnlineMap::m_input_order
private

Definition at line 533 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_interface

moab::Interface* moab::TempestOnlineMap::m_interface
private

The reference to the moab::Core object that contains source/target and overlap sets.

Definition at line 514 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_meshInput

Mesh* moab::TempestOnlineMap::m_meshInput
private

Definition at line 545 of file TempestOnlineMap.hpp.

Referenced by SetMeshInput(), and TempestOnlineMap().

◆ m_meshInputCov

Mesh* moab::TempestOnlineMap::m_meshInputCov
private

Definition at line 546 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_meshOutput

Mesh* moab::TempestOnlineMap::m_meshOutput
private

Definition at line 547 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_meshOverlap

Mesh* moab::TempestOnlineMap::m_meshOverlap
private

Definition at line 548 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_nDofsPEl_Dest

int moab::TempestOnlineMap::m_nDofsPEl_Dest
private

Definition at line 540 of file TempestOnlineMap.hpp.

◆ m_nDofsPEl_Src

int moab::TempestOnlineMap::m_nDofsPEl_Src
private

Definition at line 540 of file TempestOnlineMap.hpp.

◆ m_nTotDofs_Dest

int moab::TempestOnlineMap::m_nTotDofs_Dest
private

Definition at line 537 of file TempestOnlineMap.hpp.

Referenced by LinearRemapNN_MOAB().

◆ m_nTotDofs_Src

int moab::TempestOnlineMap::m_nTotDofs_Src
private

Definition at line 537 of file TempestOnlineMap.hpp.

◆ m_nTotDofs_SrcCov

int moab::TempestOnlineMap::m_nTotDofs_SrcCov
private

Definition at line 537 of file TempestOnlineMap.hpp.

Referenced by LinearRemapNN_MOAB().

◆ m_output_order

int moab::TempestOnlineMap::m_output_order
private

Definition at line 533 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_remapper

moab::TempestRemapper* moab::TempestOnlineMap::m_remapper
private

The fundamental remapping operator object.

Definition at line 500 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ m_srcDiscType

DiscretizationType moab::TempestOnlineMap::m_srcDiscType
private

Definition at line 536 of file TempestOnlineMap.hpp.

◆ rank

int moab::TempestOnlineMap::rank
private

Definition at line 551 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ row_dtoc_dofmap

std::vector< int > moab::TempestOnlineMap::row_dtoc_dofmap
private

Definition at line 530 of file TempestOnlineMap.hpp.

◆ row_gdofmap

std::vector< unsigned > moab::TempestOnlineMap::row_gdofmap
private

Definition at line 527 of file TempestOnlineMap.hpp.

Referenced by LinearRemapNN_MOAB().

◆ rowMap

std::map< int, int > moab::TempestOnlineMap::rowMap
private

Definition at line 532 of file TempestOnlineMap.hpp.

◆ size

int moab::TempestOnlineMap::size
private

Definition at line 551 of file TempestOnlineMap.hpp.

Referenced by TempestOnlineMap().

◆ srccol_dtoc_dofmap

std::vector< int > moab::TempestOnlineMap::srccol_dtoc_dofmap
private

Definition at line 530 of file TempestOnlineMap.hpp.

◆ srccol_gdofmap

std::vector< unsigned > moab::TempestOnlineMap::srccol_gdofmap
private

Definition at line 527 of file TempestOnlineMap.hpp.


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