![]() |
Mesh Oriented datABase
(version 5.4.1)
Array-based unstructured mesh datastructure
|
An offline map between two Meshes. More...
#include <TempestOnlineMap.hpp>
Public Types | |
enum | DiscretizationType { DiscretizationType_FV, DiscretizationType_CGLL, DiscretizationType_DGLL, DiscretizationType_PCLOUD } |
typedef double(* | sample_function )(double, double) |
Public Member Functions | |
TempestOnlineMap (moab::TempestRemapper *remapper) | |
Generate the metadata associated with the offline map. | |
virtual | ~TempestOnlineMap () |
Define a virtual destructor. | |
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. | |
moab::ErrorCode | ReadParallelMap (const char *strSource, const std::vector< int > &owned_dof_ids, bool row_major_ownership=true) |
Generate the metadata associated with the offline map. | |
moab::ErrorCode | WriteParallelMap (const std::string &strTarget) |
Write the TempestOnlineMap to a parallel NetCDF file. | |
virtual int | IsConsistent (double dTolerance) |
Determine if the map is first-order accurate. | |
virtual int | IsConservative (double dTolerance) |
Determine if the map is conservative. | |
virtual int | IsMonotone (double dTolerance) |
Determine if the map is monotone. | |
const DataArray1D< double > & | GetGlobalSourceAreas () const |
If we computed the reduction, get the vector representing the source areas for all entities in the mesh. | |
const DataArray1D< double > & | GetGlobalTargetAreas () const |
If we computed the reduction, get the vector representing the target areas for all entities in the mesh. | |
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. | |
moab::ErrorCode | SetDOFmapAssociation (DiscretizationType srcType, bool isSrcContinuous, DataArray3D< int > *srcdataGLLNodes, DataArray3D< int > *srcdataGLLNodesSrc, DiscretizationType destType, bool isDestContinuous, 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. | |
int | GetSourceGlobalNDofs () |
Get the number of total Degrees-Of-Freedom defined on the source mesh. | |
int | GetDestinationGlobalNDofs () |
Get the number of total Degrees-Of-Freedom defined on the destination mesh. | |
int | GetSourceLocalNDofs () |
Get the number of local Degrees-Of-Freedom defined on the source mesh. | |
int | GetDestinationLocalNDofs () |
Get the number of local Degrees-Of-Freedom defined on the destination mesh. | |
int | GetSourceNDofsPerElement () |
Get the number of Degrees-Of-Freedom per element on the source mesh. | |
int | GetDestinationNDofsPerElement () |
Get the number of Degrees-Of-Freedom per element on the destination mesh. | |
void | SetSourceNDofsPerElement (int ns) |
Set the number of Degrees-Of-Freedom per element on the source mesh. | |
void | SetDestinationNDofsPerElement (int nt) |
Get the number of Degrees-Of-Freedom per element on the destination mesh. | |
int | GetRowGlobalDoF (int localID) const |
Get the global Degrees-Of-Freedom ID on the destination mesh. | |
int | GetIndexOfRowGlobalDoF (int globalRowDoF) const |
Get the index of globaRowDoF. | |
int | GetColGlobalDoF (int localID) const |
Get the global Degrees-Of-Freedom ID on the source mesh. | |
int | GetIndexOfColGlobalDoF (int globalColDoF) const |
Get the index of globaColDoF. | |
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) * , or if (transpose) tgtVals = [A(T->S)]^T * . | |
moab::ErrorCode | ApplyWeights (moab::Tag srcSolutionTag, moab::Tag tgtSolutionTag, bool transpose=false) |
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) * , or if (transpose) tgtVals = [A(T->S)]^T * . | |
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. | |
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. | |
moab::ErrorCode | fill_row_ids (std::vector< int > &ids_of_interest) |
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) |
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. | |
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. | |
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. | |
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. | |
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. | |
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. | |
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). | |
moab::ErrorCode | WriteSCRIPMapFile (const std::string &strOutputFile) |
Copy the local matrix from Tempest SparseMatrix representation (ELL) to the parallel CSR Eigen Matrix for scalable application of matvec needed for projections. | |
moab::ErrorCode | WriteHDF5MapFile (const std::string &filename) |
Parallel I/O with NetCDF to write out the SCRIP file from multiple processors. | |
void | setup_sizes_dimensions () |
Private Attributes | |
moab::TempestRemapper * | m_remapper |
The fundamental remapping operator object. | |
moab::Interface * | m_interface |
The reference to the moab::Core object that contains source/target and overlap sets. | |
moab::Tag | m_dofTagSrc |
The original tag data and local to global DoF mapping to associate matrix values to solution. | |
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 |
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 |
int | root_proc |
An offline map between two Meshes.
Definition at line 48 of file TempestOnlineMap.hpp.
typedef double( * moab::TempestOnlineMap::sample_function)(double, double) |
Definition at line 347 of file TempestOnlineMap.hpp.
DiscretizationType_FV | |
DiscretizationType_CGLL | |
DiscretizationType_DGLL | |
DiscretizationType_PCLOUD |
Definition at line 64 of file TempestOnlineMap.hpp.
{
DiscretizationType_FV,
DiscretizationType_CGLL,
DiscretizationType_DGLL,
DiscretizationType_PCLOUD
};
Generate the metadata associated with the offline map.
Definition at line 55 of file TempestOnlineMap.cpp.
References moab::Remapper::get_interface(), moab::TempestRemapper::GetCoveringMesh(), moab::TempestRemapper::GetMesh(), is_parallel, is_root, m_interface, m_meshInput, m_meshInputCov, m_meshOutput, m_meshOverlap, m_remapper, moab::Remapper::OverlapMesh, rank, root_proc, setup_sizes_dimensions(), size, moab::Remapper::SourceMesh, and moab::Remapper::TargetMesh.
: OfflineMap(), m_remapper( remapper )
{
// Get the references for the MOAB core objects
m_interface = m_remapper->get_interface();
#ifdef MOAB_HAVE_MPI
m_pcomm = m_remapper->get_parallel_communicator();
#endif
// Update the references to the meshes
m_meshInput = remapper->GetMesh( moab::Remapper::SourceMesh );
m_meshInputCov = remapper->GetCoveringMesh();
m_meshOutput = remapper->GetMesh( moab::Remapper::TargetMesh );
m_meshOverlap = remapper->GetMesh( moab::Remapper::OverlapMesh );
is_parallel = false;
is_root = true;
rank = 0;
root_proc = rank;
size = 1;
#ifdef MOAB_HAVE_MPI
int flagInit;
MPI_Initialized( &flagInit );
if( flagInit )
{
is_parallel = true;
assert( m_pcomm != NULL );
rank = m_pcomm->rank();
size = m_pcomm->size();
is_root = ( rank == 0 );
}
#endif
// Compute and store the total number of source and target DoFs corresponding
// to number of rows and columns in the mapping.
// Initialize dimension information from file
this->setup_sizes_dimensions();
// Build a matrix of source and target discretization so that we know how to assign
// the global DoFs in parallel for the mapping weights
// For example, FV->FV: rows X cols = faces_source X faces_target
}
moab::TempestOnlineMap::~TempestOnlineMap | ( | ) | [virtual] |
Define a virtual destructor.
Definition at line 145 of file TempestOnlineMap.cpp.
{
m_interface = NULL;
#ifdef MOAB_HAVE_MPI
m_pcomm = NULL;
#endif
m_meshInput = NULL;
m_meshOutput = NULL;
m_meshOverlap = NULL;
}
moab::ErrorCode moab::TempestOnlineMap::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) * , or if (transpose) tgtVals
= [A(T->S)]^T * .
Referenced by main().
moab::ErrorCode moab::TempestOnlineMap::ApplyWeights | ( | moab::Tag | srcSolutionTag, |
moab::Tag | tgtSolutionTag, | ||
bool | transpose = false |
||
) |
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) * , or if (transpose) tgtVals
= [A(T->S)]^T * .
Definition at line 1658 of file TempestOnlineMap.cpp.
References moab::Remapper::CoveringMesh, ErrorCode, MB_CHK_SET_ERR, MB_SUCCESS, moab::Range::size(), and moab::Remapper::TargetMesh.
{
moab::ErrorCode rval;
std::vector< double > solSTagVals;
std::vector< double > solTTagVals;
moab::Range sents, tents;
if( m_remapper->point_cloud_source || m_remapper->point_cloud_target )
{
if( m_remapper->point_cloud_source )
{
moab::Range& covSrcEnts = m_remapper->GetMeshVertices( moab::Remapper::CoveringMesh );
solSTagVals.resize( covSrcEnts.size(), -1.0 );
sents = covSrcEnts;
}
else
{
moab::Range& covSrcEnts = m_remapper->GetMeshEntities( moab::Remapper::CoveringMesh );
solSTagVals.resize( covSrcEnts.size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
-1.0 );
sents = covSrcEnts;
}
if( m_remapper->point_cloud_target )
{
moab::Range& tgtEnts = m_remapper->GetMeshVertices( moab::Remapper::TargetMesh );
solTTagVals.resize( tgtEnts.size(), -1.0 );
tents = tgtEnts;
}
else
{
moab::Range& tgtEnts = m_remapper->GetMeshEntities( moab::Remapper::TargetMesh );
solTTagVals.resize(
tgtEnts.size() * this->GetDestinationNDofsPerElement() * this->GetDestinationNDofsPerElement(), -1.0 );
tents = tgtEnts;
}
}
else
{
moab::Range& covSrcEnts = m_remapper->GetMeshEntities( moab::Remapper::CoveringMesh );
moab::Range& tgtEnts = m_remapper->GetMeshEntities( moab::Remapper::TargetMesh );
solSTagVals.resize( covSrcEnts.size() * this->GetSourceNDofsPerElement() * this->GetSourceNDofsPerElement(),
-1.0 );
solTTagVals.resize(
tgtEnts.size() * this->GetDestinationNDofsPerElement() * this->GetDestinationNDofsPerElement(), -1.0 );
sents = covSrcEnts;
tents = tgtEnts;
}
// The tag data is np*np*n_el_src
rval = m_interface->tag_get_data( srcSolutionTag, sents, &solSTagVals[0] );MB_CHK_SET_ERR( rval, "Getting local tag data failed" );
// Compute the application of weights on the suorce solution data and store it in the
// destination solution vector data Optionally, can also perform the transpose application of
// the weight matrix. Set the 3rd argument to true if this is needed
rval = this->ApplyWeights( solSTagVals, solTTagVals, transpose );MB_CHK_SET_ERR( rval, "Applying remap operator onto source vector data failed" );
// The tag data is np*np*n_el_dest
rval = m_interface->tag_set_data( tgtSolutionTag, tents, &solTTagVals[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
return moab::MB_SUCCESS;
}
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 2086 of file TempestOnlineMap.cpp.
References entities, moab::error(), ErrorCode, MB_CHK_ERR, MB_SUCCESS, moab::Range::size(), moab::Remapper::SourceMesh, and moab::Remapper::TargetMesh.
Referenced by main().
{
moab::ErrorCode rval;
const bool outputEnabled = ( is_root );
int discOrder;
DiscretizationType discMethod;
moab::EntityHandle meshset;
moab::Range entities;
Mesh* trmesh;
switch( ctx )
{
case Remapper::SourceMesh:
meshset = m_remapper->m_covering_source_set;
trmesh = m_remapper->m_covering_source;
entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
: m_remapper->m_covering_source_entities );
discOrder = m_nDofsPEl_Src;
discMethod = m_eInputType;
break;
case Remapper::TargetMesh:
meshset = m_remapper->m_target_set;
trmesh = m_remapper->m_target;
entities =
( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
discOrder = m_nDofsPEl_Dest;
discMethod = m_eOutputType;
break;
default:
if( outputEnabled )
std::cout << "Invalid context specified for defining an analytical solution tag" << std::endl;
return moab::MB_FAILURE;
}
// Let us create teh solution tag with appropriate information for name, discretization order
// (DoF space)
std::string exactTagName, projTagName;
const int ntotsize = entities.size() * discOrder * discOrder;
int ntotsize_glob = 0;
std::vector< double > exactSolution( ntotsize, 0.0 ), projSolution( ntotsize, 0.0 );
rval = m_interface->tag_get_name( exactTag, exactTagName );MB_CHK_ERR( rval );
rval = m_interface->tag_get_data( exactTag, entities, &exactSolution[0] );MB_CHK_ERR( rval );
rval = m_interface->tag_get_name( approxTag, projTagName );MB_CHK_ERR( rval );
rval = m_interface->tag_get_data( approxTag, entities, &projSolution[0] );MB_CHK_ERR( rval );
std::vector< double > errnorms( 3, 0.0 ), globerrnorms( 3, 0.0 ); // L1Err, L2Err, LinfErr
for( int i = 0; i < ntotsize; ++i )
{
const double error = fabs( exactSolution[i] - projSolution[i] );
errnorms[0] += error;
errnorms[1] += error * error;
errnorms[2] = ( error > errnorms[2] ? error : errnorms[2] );
}
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
{
MPI_Reduce( &ntotsize, &ntotsize_glob, 1, MPI_INT, MPI_SUM, 0, m_pcomm->comm() );
MPI_Reduce( &errnorms[0], &globerrnorms[0], 2, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
MPI_Reduce( &errnorms[2], &globerrnorms[2], 1, MPI_DOUBLE, MPI_MAX, 0, m_pcomm->comm() );
}
#else
ntotsize_glob = ntotsize;
globerrnorms = errnorms;
#endif
globerrnorms[0] = ( globerrnorms[0] / ntotsize_glob );
globerrnorms[1] = std::sqrt( globerrnorms[1] / ntotsize_glob );
metrics.clear();
metrics["L1Error"] = globerrnorms[0];
metrics["L2Error"] = globerrnorms[1];
metrics["LinfError"] = globerrnorms[2];
if( verbose && is_root )
{
std::cout << "Error metrics when comparing " << projTagName << " against " << exactTagName << std::endl;
std::cout << "\t L_1 error = " << globerrnorms[0] << std::endl;
std::cout << "\t L_2 error = " << globerrnorms[1] << std::endl;
std::cout << "\t L_inf error = " << globerrnorms[2] << std::endl;
}
return moab::MB_SUCCESS;
}
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 1724 of file TempestOnlineMap.cpp.
References entities, ErrorCode, MB_CHK_ERR, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_DOUBLE, moab::Range::size(), moab::Remapper::SourceMesh, and moab::Remapper::TargetMesh.
Referenced by main().
{
moab::ErrorCode rval;
const bool outputEnabled = ( is_root );
int discOrder;
DiscretizationType discMethod;
moab::EntityHandle meshset;
moab::Range entities;
Mesh* trmesh;
switch( ctx )
{
case Remapper::SourceMesh:
meshset = m_remapper->m_covering_source_set;
trmesh = m_remapper->m_covering_source;
entities = ( m_remapper->point_cloud_source ? m_remapper->m_covering_source_vertices
: m_remapper->m_covering_source_entities );
discOrder = m_nDofsPEl_Src;
discMethod = m_eInputType;
break;
case Remapper::TargetMesh:
meshset = m_remapper->m_target_set;
trmesh = m_remapper->m_target;
entities =
( m_remapper->point_cloud_target ? m_remapper->m_target_vertices : m_remapper->m_target_entities );
discOrder = m_nDofsPEl_Dest;
discMethod = m_eOutputType;
break;
default:
if( outputEnabled )
std::cout << "Invalid context specified for defining an analytical solution tag" << std::endl;
return moab::MB_FAILURE;
}
// Let us create teh solution tag with appropriate information for name, discretization order
// (DoF space)
rval = m_interface->tag_get_handle( solnName.c_str(), discOrder * discOrder, MB_TYPE_DOUBLE, solnTag,
MB_TAG_DENSE | MB_TAG_CREAT );MB_CHK_ERR( rval );
if( clonedSolnTag != NULL )
{
if( cloneSolnName.size() == 0 )
{
cloneSolnName = solnName + std::string( "Cloned" );
}
rval = m_interface->tag_get_handle( cloneSolnName.c_str(), discOrder * discOrder, MB_TYPE_DOUBLE,
*clonedSolnTag, MB_TAG_DENSE | MB_TAG_CREAT );MB_CHK_ERR( rval );
}
// Triangular quadrature rule
const int TriQuadratureOrder = 10;
if( outputEnabled ) std::cout << "Using triangular quadrature of order " << TriQuadratureOrder << std::endl;
TriangularQuadratureRule triquadrule( TriQuadratureOrder );
const int TriQuadraturePoints = triquadrule.GetPoints();
const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
// Output data
DataArray1D< double > dVar;
DataArray1D< double > dVarMB; // re-arranged local MOAB vector
// Nodal geometric area
DataArray1D< double > dNodeArea;
// Calculate element areas
// trmesh->CalculateFaceAreas(fContainsConcaveFaces);
if( discMethod == DiscretizationType_CGLL || discMethod == DiscretizationType_DGLL )
{
/* Get the spectral points and sample the functionals accordingly */
const bool fGLL = true;
const bool fGLLIntegrate = false;
// Generate grid metadata
DataArray3D< int > dataGLLNodes;
DataArray3D< double > dataGLLJacobian;
GenerateMetaData( *trmesh, discOrder, false, dataGLLNodes, dataGLLJacobian );
// Number of elements
int nElements = trmesh->faces.size();
// Verify all elements are quadrilaterals
for( int k = 0; k < nElements; k++ )
{
const Face& face = trmesh->faces[k];
if( face.edges.size() != 4 )
{
_EXCEPTIONT( "Non-quadrilateral face detected; "
"incompatible with --gll" );
}
}
// Number of unique nodes
int iMaxNode = 0;
for( int i = 0; i < discOrder; i++ )
{
for( int j = 0; j < discOrder; j++ )
{
for( int k = 0; k < nElements; k++ )
{
if( dataGLLNodes[i][j][k] > iMaxNode )
{
iMaxNode = dataGLLNodes[i][j][k];
}
}
}
}
// Get Gauss-Lobatto quadrature nodes
DataArray1D< double > dG;
DataArray1D< double > dW;
GaussLobattoQuadrature::GetPoints( discOrder, 0.0, 1.0, dG, dW );
// Get Gauss quadrature nodes
const int nGaussP = 10;
DataArray1D< double > dGaussG;
DataArray1D< double > dGaussW;
GaussQuadrature::GetPoints( nGaussP, 0.0, 1.0, dGaussG, dGaussW );
// Allocate data
dVar.Allocate( iMaxNode );
dVarMB.Allocate( discOrder * discOrder * nElements );
dNodeArea.Allocate( iMaxNode );
// Sample data
for( int k = 0; k < nElements; k++ )
{
const Face& face = trmesh->faces[k];
// Sample data at GLL nodes
if( fGLL )
{
for( int i = 0; i < discOrder; i++ )
{
for( int j = 0; j < discOrder; j++ )
{
// Apply local map
Node node;
Node dDx1G;
Node dDx2G;
ApplyLocalMap( face, trmesh->nodes, dG[i], dG[j], node, dDx1G, dDx2G );
// Sample data at this point
double dNodeLon = atan2( node.y, node.x );
if( dNodeLon < 0.0 )
{
dNodeLon += 2.0 * M_PI;
}
double dNodeLat = asin( node.z );
double dSample = ( *testFunction )( dNodeLon, dNodeLat );
dVar[dataGLLNodes[j][i][k] - 1] = dSample;
}
}
// High-order Gaussian integration over basis function
}
else
{
DataArray2D< double > dCoeff( discOrder, discOrder );
for( int p = 0; p < nGaussP; p++ )
{
for( int q = 0; q < nGaussP; q++ )
{
// Apply local map
Node node;
Node dDx1G;
Node dDx2G;
ApplyLocalMap( face, trmesh->nodes, dGaussG[p], dGaussG[q], node, dDx1G, dDx2G );
// Cross product gives local Jacobian
Node nodeCross = CrossProduct( dDx1G, dDx2G );
double dJacobian =
sqrt( nodeCross.x * nodeCross.x + nodeCross.y * nodeCross.y + nodeCross.z * nodeCross.z );
// Find components of quadrature point in basis
// of the first Face
SampleGLLFiniteElement( 0, discOrder, dGaussG[p], dGaussG[q], dCoeff );
// Sample data at this point
double dNodeLon = atan2( node.y, node.x );
if( dNodeLon < 0.0 )
{
dNodeLon += 2.0 * M_PI;
}
double dNodeLat = asin( node.z );
double dSample = ( *testFunction )( dNodeLon, dNodeLat );
// Integrate
for( int i = 0; i < discOrder; i++ )
{
for( int j = 0; j < discOrder; j++ )
{
double dNodalArea = dCoeff[i][j] * dGaussW[p] * dGaussW[q] * dJacobian;
dVar[dataGLLNodes[i][j][k] - 1] += dSample * dNodalArea;
dNodeArea[dataGLLNodes[i][j][k] - 1] += dNodalArea;
}
}
}
}
}
}
// Divide by area
if( fGLLIntegrate )
{
for( size_t i = 0; i < dVar.GetRows(); i++ )
{
dVar[i] /= dNodeArea[i];
}
}
// Let us rearrange the data based on DoF ID specification
if( ctx == Remapper::SourceMesh )
{
for( unsigned j = 0; j < entities.size(); j++ )
for( int p = 0; p < discOrder; p++ )
for( int q = 0; q < discOrder; q++ )
{
const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
dVarMB[offsetDOF] = dVar[col_dtoc_dofmap[offsetDOF]];
}
}
else
{
for( unsigned j = 0; j < entities.size(); j++ )
for( int p = 0; p < discOrder; p++ )
for( int q = 0; q < discOrder; q++ )
{
const int offsetDOF = j * discOrder * discOrder + p * discOrder + q;
dVarMB[offsetDOF] = dVar[row_dtoc_dofmap[offsetDOF]];
}
}
// Set the tag data
rval = m_interface->tag_set_data( solnTag, entities, &dVarMB[0] );MB_CHK_ERR( rval );
}
else
{
// assert( discOrder == 1 );
if( discMethod == DiscretizationType_FV )
{
/* Compute an element-wise integral to store the sampled solution based on Quadrature
* rules */
// Resize the array
dVar.Allocate( trmesh->faces.size() );
std::vector< Node >& nodes = trmesh->nodes;
// Loop through all Faces
for( size_t i = 0; i < trmesh->faces.size(); i++ )
{
const Face& face = trmesh->faces[i];
// Loop through all sub-triangles
for( size_t j = 0; j < face.edges.size() - 2; j++ )
{
const Node& node0 = nodes[face[0]];
const Node& node1 = nodes[face[j + 1]];
const Node& node2 = nodes[face[j + 2]];
// Triangle area
Face faceTri( 3 );
faceTri.SetNode( 0, face[0] );
faceTri.SetNode( 1, face[j + 1] );
faceTri.SetNode( 2, face[j + 2] );
double dTriangleArea = CalculateFaceArea( faceTri, nodes );
// Calculate the element average
double dTotalSample = 0.0;
// Loop through all quadrature points
for( int k = 0; k < TriQuadraturePoints; k++ )
{
Node node( TriQuadratureG[k][0] * node0.x + TriQuadratureG[k][1] * node1.x +
TriQuadratureG[k][2] * node2.x,
TriQuadratureG[k][0] * node0.y + TriQuadratureG[k][1] * node1.y +
TriQuadratureG[k][2] * node2.y,
TriQuadratureG[k][0] * node0.z + TriQuadratureG[k][1] * node1.z +
TriQuadratureG[k][2] * node2.z );
double dMagnitude = node.Magnitude();
node.x /= dMagnitude;
node.y /= dMagnitude;
node.z /= dMagnitude;
double dLon = atan2( node.y, node.x );
if( dLon < 0.0 )
{
dLon += 2.0 * M_PI;
}
double dLat = asin( node.z );
double dSample = ( *testFunction )( dLon, dLat );
dTotalSample += dSample * TriQuadratureW[k] * dTriangleArea;
}
dVar[i] += dTotalSample / trmesh->vecFaceArea[i];
}
}
rval = m_interface->tag_set_data( solnTag, entities, &dVar[0] );MB_CHK_ERR( rval );
}
else /* discMethod == DiscretizationType_PCLOUD */
{
/* Get the coordinates of the vertices and sample the functionals accordingly */
std::vector< Node >& nodes = trmesh->nodes;
// Resize the array
dVar.Allocate( nodes.size() );
for( size_t j = 0; j < nodes.size(); j++ )
{
Node& node = nodes[j];
double dMagnitude = node.Magnitude();
node.x /= dMagnitude;
node.y /= dMagnitude;
node.z /= dMagnitude;
double dLon = atan2( node.y, node.x );
if( dLon < 0.0 )
{
dLon += 2.0 * M_PI;
}
double dLat = asin( node.z );
double dSample = ( *testFunction )( dLon, dLat );
dVar[j] = dSample;
}
rval = m_interface->tag_set_data( solnTag, entities, &dVar[0] );MB_CHK_ERR( rval );
}
}
return moab::MB_SUCCESS;
}
moab::ErrorCode moab::TempestOnlineMap::fill_col_ids | ( | std::vector< int > & | ids_of_interest | ) | [inline] |
Definition at line 382 of file TempestOnlineMap.hpp.
References col_gdofmap, and MB_SUCCESS.
{
ids_of_interest.reserve( col_gdofmap.size() );
// need to add 1
for( auto it = col_gdofmap.begin(); it != col_gdofmap.end(); it++ )
ids_of_interest.push_back( *it + 1 );
return moab::MB_SUCCESS;
}
moab::ErrorCode moab::TempestOnlineMap::fill_row_ids | ( | std::vector< int > & | ids_of_interest | ) | [inline] |
Definition at line 372 of file TempestOnlineMap.hpp.
References MB_SUCCESS, and row_gdofmap.
{
ids_of_interest.reserve( row_gdofmap.size() );
// need to add 1
for( auto it = row_gdofmap.begin(); it != row_gdofmap.end(); it++ )
ids_of_interest.push_back( *it + 1 );
return moab::MB_SUCCESS;
}
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 731 of file TempestOnlineMap.cpp.
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, moab::Remapper::OverlapMesh, moab::DebugOutput::printf(), and moab::DebugOutput::set_prefix().
Referenced by main().
{
NcError error( NcError::silent_nonfatal );
moab::DebugOutput dbgprint( std::cout, rank, 0 );
dbgprint.set_prefix( "[TempestOnlineMap]: " );
moab::ErrorCode rval;
const bool m_bPointCloudSource = ( m_remapper->point_cloud_source );
const bool m_bPointCloudTarget = ( m_remapper->point_cloud_target );
const bool m_bPointCloud = m_bPointCloudSource || m_bPointCloudTarget;
try
{
// Check command line parameters (data type arguments)
STLStringHelper::ToLower( strInputType );
STLStringHelper::ToLower( strOutputType );
DiscretizationType eInputType;
DiscretizationType eOutputType;
if( strInputType == "fv" )
{
eInputType = DiscretizationType_FV;
}
else if( strInputType == "cgll" )
{
eInputType = DiscretizationType_CGLL;
}
else if( strInputType == "dgll" )
{
eInputType = DiscretizationType_DGLL;
}
else if( strInputType == "pcloud" )
{
eInputType = DiscretizationType_PCLOUD;
}
else
{
_EXCEPTION1( "Invalid \"in_type\" value (%s), expected [fv|cgll|dgll]", strInputType.c_str() );
}
if( strOutputType == "fv" )
{
eOutputType = DiscretizationType_FV;
}
else if( strOutputType == "cgll" )
{
eOutputType = DiscretizationType_CGLL;
}
else if( strOutputType == "dgll" )
{
eOutputType = DiscretizationType_DGLL;
}
else if( strOutputType == "pcloud" )
{
eOutputType = DiscretizationType_PCLOUD;
}
else
{
_EXCEPTION1( "Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]", strOutputType.c_str() );
}
// set all required input params
m_bConserved = !mapOptions.fNoConservation;
m_eInputType = eInputType;
m_eOutputType = eOutputType;
// Method flags
std::string strMapAlgorithm( "" );
int nMonotoneType = ( mapOptions.fMonotone ) ? ( 1 ) : ( 0 );
// Make an index of method arguments
std::set< std::string > setMethodStrings;
{
int iLast = 0;
for( size_t i = 0; i <= mapOptions.strMethod.length(); i++ )
{
if( ( i == mapOptions.strMethod.length() ) || ( mapOptions.strMethod[i] == ';' ) )
{
std::string strMethodString = mapOptions.strMethod.substr( iLast, i - iLast );
STLStringHelper::RemoveWhitespaceInPlace( strMethodString );
if( strMethodString.length() > 0 )
{
setMethodStrings.insert( strMethodString );
}
iLast = i + 1;
}
}
}
for( auto it : setMethodStrings )
{
// Piecewise constant monotonicity
if( it == "mono2" )
{
if( nMonotoneType != 0 )
{
_EXCEPTIONT( "Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
}
if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
{
_EXCEPTIONT( "--method \"mono2\" is only used when remapping to/from CGLL or DGLL grids" );
}
nMonotoneType = 2;
// Piecewise linear monotonicity
}
else if( it == "mono3" )
{
if( nMonotoneType != 0 )
{
_EXCEPTIONT( "Multiple monotonicity specifications found (--mono) or (--method \"mono#\")" );
}
if( ( m_eInputType == DiscretizationType_FV ) && ( m_eOutputType == DiscretizationType_FV ) )
{
_EXCEPTIONT( "--method \"mono3\" is only used when remapping to/from CGLL or DGLL grids" );
}
nMonotoneType = 3;
// Volumetric remapping from FV to GLL
}
else if( it == "volumetric" )
{
if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType == DiscretizationType_FV ) )
{
_EXCEPTIONT( "--method \"volumetric\" may only be used for FV->CGLL or FV->DGLL remapping" );
}
strMapAlgorithm = "volumetric";
// Inverse distance mapping
}
else if( it == "invdist" )
{
if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
{
_EXCEPTIONT( "--method \"invdist\" may only be used for FV->FV remapping" );
}
strMapAlgorithm = "invdist";
// Delaunay triangulation mapping
}
else if( it == "delaunay" )
{
if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
{
_EXCEPTIONT( "--method \"delaunay\" may only be used for FV->FV remapping" );
}
strMapAlgorithm = "delaunay";
// Bilinear
}
else if( it == "bilin" )
{
if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
{
_EXCEPTIONT( "--method \"bilin\" may only be used for FV->FV remapping" );
}
strMapAlgorithm = "fvbilin";
// Integrated bilinear (same as mono3 when source grid is CGLL/DGLL)
}
else if( it == "intbilin" )
{
if( m_eOutputType != DiscretizationType_FV )
{
_EXCEPTIONT( "--method \"intbilin\" may only be used when mapping to FV." );
}
if( m_eInputType == DiscretizationType_FV )
{
strMapAlgorithm = "fvintbilin";
}
else
{
strMapAlgorithm = "mono3";
}
// Integrated bilinear with generalized Barycentric coordinates
}
else if( it == "intbilingb" )
{
if( ( m_eInputType != DiscretizationType_FV ) || ( m_eOutputType != DiscretizationType_FV ) )
{
_EXCEPTIONT( "--method \"intbilingb\" may only be used for FV->FV remapping" );
}
strMapAlgorithm = "fvintbilingb";
}
else
{
_EXCEPTION1( "Invalid --method argument \"%s\"", it.c_str() );
}
}
m_nDofsPEl_Src =
( m_eInputType == DiscretizationType_FV || m_eInputType == DiscretizationType_PCLOUD ? 1
: mapOptions.nPin );
m_nDofsPEl_Dest =
( m_eOutputType == DiscretizationType_FV || m_eOutputType == DiscretizationType_PCLOUD ? 1
: mapOptions.nPout );
rval = SetDOFmapTags( srcDofTagName, tgtDofTagName );MB_CHK_ERR( rval );
/// the tag should be created already in the e3sm workflow; if not, create it here
Tag areaTag;
rval = m_interface->tag_get_handle( "aream", 1, MB_TYPE_DOUBLE, areaTag,
MB_TAG_DENSE | MB_TAG_EXCL | MB_TAG_CREAT );
if ( MB_ALREADY_ALLOCATED == rval )
{
if( is_root ) dbgprint.printf( 0, "aream tag already defined \n" );
}
double dTotalAreaInput = 0.0, dTotalAreaOutput = 0.0;
if( !m_bPointCloudSource )
{
// Calculate Input Mesh Face areas
if( is_root ) dbgprint.printf( 0, "Calculating input mesh Face areas\n" );
double dTotalAreaInput_loc = m_meshInput->CalculateFaceAreas( mapOptions.fSourceConcave );
rval = m_interface->tag_set_data( areaTag, m_remapper->m_source_entities, m_meshInput->vecFaceArea );MB_CHK_ERR( rval );
dTotalAreaInput = dTotalAreaInput_loc;
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
MPI_Reduce( &dTotalAreaInput_loc, &dTotalAreaInput, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
#endif
if( is_root ) dbgprint.printf( 0, "Input Mesh Geometric Area: %1.15e\n", dTotalAreaInput );
// Input mesh areas
m_meshInputCov->CalculateFaceAreas( mapOptions.fSourceConcave );
// we do not need to set the area on coverage mesh, only on source and target meshes
// rval = m_interface->tag_set_data( areaTag, m_remapper->m_covering_source_entities, m_meshInputCov->vecFaceArea );MB_CHK_ERR( rval );
}
if( !m_bPointCloudTarget )
{
// Calculate Output Mesh Face areas
if( is_root ) dbgprint.printf( 0, "Calculating output mesh Face areas\n" );
double dTotalAreaOutput_loc = m_meshOutput->CalculateFaceAreas( mapOptions.fTargetConcave );
dTotalAreaOutput = dTotalAreaOutput_loc;
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
MPI_Reduce( &dTotalAreaOutput_loc, &dTotalAreaOutput, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
#endif
if( is_root ) dbgprint.printf( 0, "Output Mesh Geometric Area: %1.15e\n", dTotalAreaOutput );
rval = m_interface->tag_set_data( areaTag, m_remapper->m_target_entities, m_meshOutput->vecFaceArea );MB_CHK_ERR( rval );
}
if( !m_bPointCloud )
{
// Calculate Face areas
if( is_root ) dbgprint.printf( 0, "Calculating overlap mesh Face areas\n" );
double dTotalAreaOverlap_loc = m_meshOverlap->CalculateFaceAreas( false );
double dTotalAreaOverlap = dTotalAreaOverlap_loc;
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
MPI_Reduce( &dTotalAreaOverlap_loc, &dTotalAreaOverlap, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
#endif
if( is_root ) dbgprint.printf( 0, "Overlap Mesh Area: %1.15e\n", dTotalAreaOverlap );
// Correct areas to match the areas calculated in the overlap mesh
// if (fCorrectAreas) // In MOAB-TempestRemap, we will always keep this to be true
{
if( is_root ) dbgprint.printf( 0, "Correcting source/target areas to overlap mesh areas\n" );
DataArray1D< double > dSourceArea( m_meshInputCov->faces.size() );
DataArray1D< double > dTargetArea( m_meshOutput->faces.size() );
assert( m_meshOverlap->vecSourceFaceIx.size() == m_meshOverlap->faces.size() );
assert( m_meshOverlap->vecTargetFaceIx.size() == m_meshOverlap->faces.size() );
assert( m_meshOverlap->vecFaceArea.GetRows() == m_meshOverlap->faces.size() );
assert( m_meshInputCov->vecFaceArea.GetRows() == m_meshInputCov->faces.size() );
assert( m_meshOutput->vecFaceArea.GetRows() == m_meshOutput->faces.size() );
for( size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
{
if( m_meshOverlap->vecSourceFaceIx[i] < 0 || m_meshOverlap->vecTargetFaceIx[i] < 0 )
continue; // skip this cell since it is ghosted
// let us recompute the source/target areas based on overlap mesh areas
assert( static_cast< size_t >( m_meshOverlap->vecSourceFaceIx[i] ) < m_meshInputCov->faces.size() );
dSourceArea[m_meshOverlap->vecSourceFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
assert( static_cast< size_t >( m_meshOverlap->vecTargetFaceIx[i] ) < m_meshOutput->faces.size() );
dTargetArea[m_meshOverlap->vecTargetFaceIx[i]] += m_meshOverlap->vecFaceArea[i];
}
for( size_t i = 0; i < m_meshInputCov->faces.size(); i++ )
{
if( fabs( dSourceArea[i] - m_meshInputCov->vecFaceArea[i] ) < 1.0e-10 )
{
m_meshInputCov->vecFaceArea[i] = dSourceArea[i];
}
}
for( size_t i = 0; i < m_meshOutput->faces.size(); i++ )
{
if( fabs( dTargetArea[i] - m_meshOutput->vecFaceArea[i] ) < 1.0e-10 )
{
m_meshOutput->vecFaceArea[i] = dTargetArea[i];
}
}
}
// Set source mesh areas in map
if( !m_bPointCloudSource && eInputType == DiscretizationType_FV )
{
this->SetSourceAreas( m_meshInputCov->vecFaceArea );
if( m_meshInputCov->vecMask.size() )
{
this->SetSourceMask( m_meshInputCov->vecMask );
}
}
// Set target mesh areas in map
if( !m_bPointCloudTarget && eOutputType == DiscretizationType_FV )
{
this->SetTargetAreas( m_meshOutput->vecFaceArea );
if( m_meshOutput->vecMask.size() )
{
this->SetTargetMask( m_meshOutput->vecMask );
}
}
/*
// Recalculate input mesh area from overlap mesh
if (fabs(dTotalAreaOverlap - dTotalAreaInput) > 1.0e-10) {
dbgprint.printf(0, "Overlap mesh only covers a sub-area of the sphere\n");
dbgprint.printf(0, "Recalculating source mesh areas\n");
dTotalAreaInput = m_meshInput->CalculateFaceAreasFromOverlap(m_meshOverlap);
dbgprint.printf(0, "New Input Mesh Geometric Area: %1.15e\n", dTotalAreaInput);
}
*/
}
// Finite volume input / Finite volume output
if( ( eInputType == DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
{
// Generate reverse node array and edge map
if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap( false );
// Initialize coordinates for map
this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
// Finite volume input / Finite element output
rval = this->SetDOFmapAssociation( eInputType, false, NULL, NULL, eOutputType, false, NULL );MB_CHK_ERR( rval );
// Construct remap for FV-FV
if( is_root ) dbgprint.printf( 0, "Calculating remap weights\n" );
// Construct OfflineMap
if( strMapAlgorithm == "invdist" )
{
if( is_root ) AnnounceStartBlock( "Calculating map (invdist)" );
LinearRemapFVtoFVInvDist( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
}
else if( strMapAlgorithm == "delaunay" )
{
if( is_root ) AnnounceStartBlock( "Calculating map (delaunay)" );
LinearRemapTriangulation( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
}
else if( strMapAlgorithm == "fvintbilin" )
{
if( is_root ) AnnounceStartBlock( "Calculating map (intbilin)" );
LinearRemapIntegratedBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
}
else if( strMapAlgorithm == "fvintbilingb" )
{
if( is_root ) AnnounceStartBlock( "Calculating map (intbilingb)" );
LinearRemapIntegratedGeneralizedBarycentric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
}
else if( strMapAlgorithm == "fvbilin" )
{
if( is_root ) AnnounceStartBlock( "Calculating map (bilin)" );
LinearRemapBilinear( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, *this );
}
else
{
if( is_root ) AnnounceStartBlock( "Calculating map (default)" );
// LinearRemapFVtoFV( *m_meshInputCov, *m_meshOutput, *m_meshOverlap,
// ( mapOptions.fMonotone ) ? ( 1 ) : ( mapOptions.nPin ), *this );
LinearRemapFVtoFV_Tempest_MOAB( ( mapOptions.fMonotone ? 1 : mapOptions.nPin ) );
}
}
else if( eInputType == DiscretizationType_FV )
{
DataArray3D< double > dataGLLJacobian;
if( is_root ) dbgprint.printf( 0, "Generating output mesh meta data\n" );
double dNumericalArea_loc = GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble,
dataGLLNodesDest, dataGLLJacobian );
double dNumericalArea = dNumericalArea_loc;
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
MPI_Reduce( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
#endif
if( is_root ) dbgprint.printf( 0, "Output Mesh Numerical Area: %1.15e\n", dNumericalArea );
// Initialize coordinates for map
this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
// Generate the continuous Jacobian
bool fContinuous = ( eOutputType == DiscretizationType_CGLL );
if( eOutputType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobian, this->GetTargetAreas() );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetTargetAreas() );
}
// Generate reverse node array and edge map
if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap( false );
// Finite volume input / Finite element output
rval = this->SetDOFmapAssociation( eInputType, false, NULL, NULL, eOutputType,
( eOutputType == DiscretizationType_CGLL ), &dataGLLNodesDest );MB_CHK_ERR( rval );
// Generate remap weights
if( strMapAlgorithm == "volumetric" )
{
if( is_root ) dbgprint.printf( 0, "Calculating remapping weights for FV->GLL (volumetric)\n" );
LinearRemapFVtoGLL_Volumetric( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest,
dataGLLJacobian, this->GetTargetAreas(), mapOptions.nPin, *this,
nMonotoneType, fContinuous, mapOptions.fNoConservation );
}
else
{
if( is_root ) dbgprint.printf( 0, "Calculating remapping weights for FV->GLL\n" );
LinearRemapFVtoGLL( *m_meshInputCov, *m_meshOutput, *m_meshOverlap, dataGLLNodesDest, dataGLLJacobian,
this->GetTargetAreas(), mapOptions.nPin, *this, nMonotoneType, fContinuous,
mapOptions.fNoConservation );
}
}
else if( ( eInputType == DiscretizationType_PCLOUD ) || ( eOutputType == DiscretizationType_PCLOUD ) )
{
DataArray3D< double > dataGLLJacobian;
if( !m_bPointCloudSource )
{
// Generate reverse node array and edge map
if( m_meshInputCov->revnodearray.size() == 0 ) m_meshInputCov->ConstructReverseNodeArray();
if( m_meshInputCov->edgemap.size() == 0 ) m_meshInputCov->ConstructEdgeMap( false );
// Initialize coordinates for map
if( eInputType == DiscretizationType_FV )
{
this->InitializeSourceCoordinatesFromMeshFV( *m_meshInputCov );
}
else
{
if( is_root ) dbgprint.printf( 0, "Generating input mesh meta data\n" );
DataArray3D< double > dataGLLJacobianSrc;
GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
dataGLLJacobian );
GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrc,
dataGLLJacobianSrc );
}
}
// else { /* Source is a point cloud dataset */ }
if( !m_bPointCloudTarget )
{
// Generate reverse node array and edge map
if( m_meshOutput->revnodearray.size() == 0 ) m_meshOutput->ConstructReverseNodeArray();
if( m_meshOutput->edgemap.size() == 0 ) m_meshOutput->ConstructEdgeMap( false );
// Initialize coordinates for map
if( eOutputType == DiscretizationType_FV )
{
this->InitializeSourceCoordinatesFromMeshFV( *m_meshOutput );
}
else
{
if( is_root ) dbgprint.printf( 0, "Generating output mesh meta data\n" );
GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble, dataGLLNodesDest,
dataGLLJacobian );
}
}
// else { /* Target is a point cloud dataset */ }
// Finite volume input / Finite element output
rval = this->SetDOFmapAssociation(
eInputType, ( eInputType == DiscretizationType_CGLL ),
( m_bPointCloudSource || eInputType == DiscretizationType_FV ? NULL : &dataGLLNodesSrcCov ),
( m_bPointCloudSource || eInputType == DiscretizationType_FV ? NULL : &dataGLLNodesSrc ), eOutputType,
( eOutputType == DiscretizationType_CGLL ), ( m_bPointCloudTarget ? NULL : &dataGLLNodesDest ) );MB_CHK_ERR( rval );
// Construct remap
if( is_root ) dbgprint.printf( 0, "Calculating remap weights with Nearest-Neighbor method\n" );
rval = LinearRemapNN_MOAB( true /*use_GID_matching*/, false /*strict_check*/ );MB_CHK_ERR( rval );
}
else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType == DiscretizationType_FV ) )
{
DataArray3D< double > dataGLLJacobianSrc, dataGLLJacobian;
if( is_root ) dbgprint.printf( 0, "Generating input mesh meta data\n" );
// double dNumericalAreaCov_loc =
GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
dataGLLJacobian );
double dNumericalArea_loc = GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble,
dataGLLNodesSrc, dataGLLJacobianSrc );
// if ( is_root ) dbgprint.printf ( 0, "Input Mesh: Coverage Area: %1.15e, Output Area:
// %1.15e\n", dNumericalAreaCov_loc, dTotalAreaOutput_loc );
// assert(dNumericalAreaCov_loc >= dTotalAreaOutput_loc);
double dNumericalArea = dNumericalArea_loc;
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
MPI_Reduce( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
#endif
if( is_root )
{
dbgprint.printf( 0, "Input Mesh Numerical Area: %1.15e\n", dNumericalArea );
if( fabs( dNumericalArea - dTotalAreaInput ) > 1.0e-12 )
{
dbgprint.printf( 0, "WARNING: Significant mismatch between input mesh "
"numerical area and geometric area\n" );
}
}
if( dataGLLNodesSrcCov.GetSubColumns() != m_meshInputCov->faces.size() )
{
_EXCEPTIONT( "Number of element does not match between metadata and "
"input mesh" );
}
// Initialize coordinates for map
this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
this->InitializeTargetCoordinatesFromMeshFV( *m_meshOutput );
// Generate the continuous Jacobian for input mesh
bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
if( eInputType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobian, this->GetSourceAreas() );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobian, this->GetSourceAreas() );
}
// Finite element input / Finite volume output
rval = this->SetDOFmapAssociation( eInputType, ( eInputType == DiscretizationType_CGLL ),
&dataGLLNodesSrcCov, &dataGLLNodesSrc, eOutputType, false, NULL );MB_CHK_ERR( rval );
// Generate remap
if( is_root ) dbgprint.printf( 0, "Calculating remap weights\n" );
if( strMapAlgorithm == "volumetric" )
{
_EXCEPTIONT( "Unimplemented: Volumetric currently unavailable for"
"GLL input mesh" );
}
LinearRemapSE4_Tempest_MOAB( dataGLLNodesSrcCov, dataGLLJacobian, nMonotoneType, fContinuousIn,
mapOptions.fNoConservation );
}
else if( ( eInputType != DiscretizationType_FV ) && ( eOutputType != DiscretizationType_FV ) )
{
DataArray3D< double > dataGLLJacobianIn, dataGLLJacobianSrc;
DataArray3D< double > dataGLLJacobianOut;
// Input metadata
if( is_root ) dbgprint.printf( 0, "Generating input mesh meta data\n" );
GenerateMetaData( *m_meshInputCov, mapOptions.nPin, mapOptions.fNoBubble, dataGLLNodesSrcCov,
dataGLLJacobianIn );
double dNumericalAreaSrc_loc = GenerateMetaData( *m_meshInput, mapOptions.nPin, mapOptions.fNoBubble,
dataGLLNodesSrc, dataGLLJacobianSrc );
double dNumericalAreaIn = dNumericalAreaSrc_loc;
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
MPI_Reduce( &dNumericalAreaSrc_loc, &dNumericalAreaIn, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
#endif
if( is_root )
{
dbgprint.printf( 0, "Input Mesh Numerical Area: %1.15e\n", dNumericalAreaIn );
if( fabs( dNumericalAreaIn - dTotalAreaInput ) > 1.0e-12 )
{
dbgprint.printf( 0, "WARNING: Significant mismatch between input mesh "
"numerical area and geometric area\n" );
}
}
// Output metadata
if( is_root ) dbgprint.printf( 0, "Generating output mesh meta data\n" );
double dNumericalAreaOut_loc = GenerateMetaData( *m_meshOutput, mapOptions.nPout, mapOptions.fNoBubble,
dataGLLNodesDest, dataGLLJacobianOut );
double dNumericalAreaOut = dNumericalAreaOut_loc;
#ifdef MOAB_HAVE_MPI
if( m_pcomm )
MPI_Reduce( &dNumericalAreaOut_loc, &dNumericalAreaOut, 1, MPI_DOUBLE, MPI_SUM, 0, m_pcomm->comm() );
#endif
if( is_root )
{
dbgprint.printf( 0, "Output Mesh Numerical Area: %1.15e\n", dNumericalAreaOut );
if( fabs( dNumericalAreaOut - dTotalAreaOutput ) > 1.0e-12 )
{
if( is_root )
dbgprint.printf( 0, "WARNING: Significant mismatch between output mesh "
"numerical area and geometric area\n" );
}
}
// Initialize coordinates for map
this->InitializeSourceCoordinatesFromMeshFE( *m_meshInputCov, mapOptions.nPin, dataGLLNodesSrcCov );
this->InitializeTargetCoordinatesFromMeshFE( *m_meshOutput, mapOptions.nPout, dataGLLNodesDest );
// Generate the continuous Jacobian for input mesh
bool fContinuousIn = ( eInputType == DiscretizationType_CGLL );
if( eInputType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesSrcCov, dataGLLJacobianIn, this->GetSourceAreas() );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobianIn, this->GetSourceAreas() );
}
// Generate the continuous Jacobian for output mesh
bool fContinuousOut = ( eOutputType == DiscretizationType_CGLL );
if( eOutputType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianOut, this->GetTargetAreas() );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobianOut, this->GetTargetAreas() );
}
// Input Finite Element to Output Finite Element
rval = this->SetDOFmapAssociation( eInputType, ( eInputType == DiscretizationType_CGLL ),
&dataGLLNodesSrcCov, &dataGLLNodesSrc, eOutputType,
( eOutputType == DiscretizationType_CGLL ), &dataGLLNodesDest );MB_CHK_ERR( rval );
// Generate remap
if( is_root ) dbgprint.printf( 0, "Calculating remap weights\n" );
LinearRemapGLLtoGLL2_MOAB( dataGLLNodesSrcCov, dataGLLJacobianIn, dataGLLNodesDest, dataGLLJacobianOut,
this->GetTargetAreas(), mapOptions.nPin, mapOptions.nPout, nMonotoneType,
fContinuousIn, fContinuousOut, mapOptions.fNoConservation );
}
else
{
_EXCEPTIONT( "Not implemented" );
}
#ifdef MOAB_HAVE_EIGEN3
copy_tempest_sparsemat_to_eigen3();
#endif
#ifdef MOAB_HAVE_MPI
{
// Remove ghosted entities from overlap set
moab::Range ghostedEnts;
rval = m_remapper->GetOverlapAugmentedEntities( ghostedEnts );MB_CHK_ERR( rval );
moab::EntityHandle m_meshOverlapSet = m_remapper->GetMeshSet( moab::Remapper::OverlapMesh );
rval = m_interface->remove_entities( m_meshOverlapSet, ghostedEnts );MB_CHK_SET_ERR( rval, "Deleting ghosted entities failed" );
}
#endif
// Verify consistency, conservation and monotonicity, globally
if( !mapOptions.fNoCheck )
{
if( is_root ) dbgprint.printf( 0, "Verifying map" );
this->IsConsistent( 1.0e-8 );
if( !mapOptions.fNoConservation ) this->IsConservative( 1.0e-8 );
if( nMonotoneType != 0 )
{
this->IsMonotone( 1.0e-12 );
}
}
}
catch( Exception& e )
{
dbgprint.printf( 0, "%s", e.ToString().c_str() );
return ( moab::MB_FAILURE );
}
catch( ... )
{
return ( moab::MB_FAILURE );
}
return moab::MB_SUCCESS;
}
int moab::TempestOnlineMap::GetColGlobalDoF | ( | int | localID | ) | const [inline] |
Get the global Degrees-Of-Freedom ID on the source mesh.
Definition at line 480 of file TempestOnlineMap.hpp.
{
return col_gdofmap[localColID];
}
Get the number of total Degrees-Of-Freedom defined on the destination mesh.
Get the number of local Degrees-Of-Freedom defined on the destination mesh.
int moab::TempestOnlineMap::GetDestinationNDofsPerElement | ( | ) | [inline] |
Get the number of Degrees-Of-Freedom per element on the destination mesh.
Definition at line 498 of file TempestOnlineMap.hpp.
{
return m_nDofsPEl_Dest;
}
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.
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.
int moab::TempestOnlineMap::GetIndexOfColGlobalDoF | ( | int | globalColDoF | ) | const [inline] |
Get the index of globaColDoF.
Definition at line 485 of file TempestOnlineMap.hpp.
{
return globalColDoF + 1; // temporary
}
int moab::TempestOnlineMap::GetIndexOfRowGlobalDoF | ( | int | globalRowDoF | ) | const [inline] |
Get the index of globaRowDoF.
Definition at line 474 of file TempestOnlineMap.hpp.
{
return globalRowDoF + 1;
}
int moab::TempestOnlineMap::GetRowGlobalDoF | ( | int | localID | ) | const [inline] |
Get the global Degrees-Of-Freedom ID on the destination mesh.
Definition at line 469 of file TempestOnlineMap.hpp.
{
return row_gdofmap[localRowID];
}
Get the number of total Degrees-Of-Freedom defined on the source mesh.
Get the number of local Degrees-Of-Freedom defined on the source mesh.
int moab::TempestOnlineMap::GetSourceNDofsPerElement | ( | ) | [inline] |
Get the number of Degrees-Of-Freedom per element on the source mesh.
Definition at line 491 of file TempestOnlineMap.hpp.
{
return m_nDofsPEl_Src;
}
int moab::TempestOnlineMap::IsConservative | ( | double | dTolerance | ) | [virtual] |
Determine if the map is conservative.
Definition at line 1478 of file TempestOnlineMap.cpp.
References size.
{
#ifndef MOAB_HAVE_MPI
return OfflineMap::IsConservative( dTolerance );
#else
// return OfflineMap::IsConservative(dTolerance);
int ierr;
// Get map entries
DataArray1D< int > dataRows;
DataArray1D< int > dataCols;
DataArray1D< double > dataEntries;
const DataArray1D< double >& dTargetAreas = this->GetTargetAreas();
const DataArray1D< double >& dSourceAreas = this->GetSourceAreas();
// Calculate column sums
std::vector< int > dColumnsUnique;
std::vector< double > dColumnSums;
int nColumns = m_mapRemap.GetColumns();
m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
dColumnSums.resize( m_nTotDofs_SrcCov, 0.0 );
dColumnsUnique.resize( m_nTotDofs_SrcCov, -1 );
for( unsigned i = 0; i < dataEntries.GetRows(); i++ )
{
dColumnSums[dataCols[i]] += dataEntries[i] * dTargetAreas[dataRows[i]] / dSourceAreas[dataCols[i]];
assert( dataCols[i] < m_nTotDofs_SrcCov );
// GID for column DoFs: col_gdofmap[ col_ldofmap [ dataCols[i] ] ]
int colGID = this->GetColGlobalDoF( dataCols[i] ); // col_gdofmap[ col_ldofmap [ dataCols[i] ] ];
// int colGID = col_gdofmap[ col_ldofmap [ dataCols[i] ] ];
dColumnsUnique[dataCols[i]] = colGID;
// std::cout << "Column dataCols[i]=" << dataCols[i] << " with GID = " << colGID <<
// std::endl;
}
int rootProc = 0;
std::vector< int > nElementsInProc;
const int nDATA = 3;
if( !rank ) nElementsInProc.resize( size * nDATA );
int senddata[nDATA] = {nColumns, m_nTotDofs_SrcCov, m_nTotDofs_Src};
ierr = MPI_Gather( senddata, nDATA, MPI_INT, nElementsInProc.data(), nDATA, MPI_INT, rootProc, m_pcomm->comm() );
if( ierr != MPI_SUCCESS ) return -1;
int nTotVals = 0, nTotColumns = 0, nTotColumnsUnq = 0;
std::vector< int > dColumnIndices;
std::vector< double > dColumnSourceAreas;
std::vector< double > dColumnSumsTotal;
std::vector< int > displs, rcount;
if( rank == rootProc )
{
displs.resize( size + 1, 0 );
rcount.resize( size, 0 );
int gsum = 0;
for( int ir = 0; ir < size; ++ir )
{
nTotVals += nElementsInProc[ir * nDATA];
nTotColumns += nElementsInProc[ir * nDATA + 1];
nTotColumnsUnq += nElementsInProc[ir * nDATA + 2];
displs[ir] = gsum;
rcount[ir] = nElementsInProc[ir * nDATA + 1];
gsum += rcount[ir];
// printf("%d: nTotColumns: %d, Displs: %d, rcount: %d, gsum = %d\n", ir, nTotColumns,
// displs[ir], rcount[ir], gsum);
}
dColumnIndices.resize( nTotColumns, -1 );
dColumnSumsTotal.resize( nTotColumns, 0.0 );
// dColumnSourceAreas.resize ( nTotColumns, 0.0 );
}
// Gather all ColumnSums to root process and accumulate
// We expect that the sums of all columns equate to 1.0 within user specified tolerance
// Need to do a gatherv here since different processes have different number of elements
// MPI_Reduce(&dColumnSums[0], &dColumnSumsTotal[0], m_mapRemap.GetColumns(), MPI_DOUBLE,
// MPI_SUM, 0, m_pcomm->comm());
ierr = MPI_Gatherv( &dColumnsUnique[0], m_nTotDofs_SrcCov, MPI_INT, &dColumnIndices[0], rcount.data(),
displs.data(), MPI_INT, rootProc, m_pcomm->comm() );
if( ierr != MPI_SUCCESS ) return -1;
ierr = MPI_Gatherv( &dColumnSums[0], m_nTotDofs_SrcCov, MPI_DOUBLE, &dColumnSumsTotal[0], rcount.data(),
displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() );
if( ierr != MPI_SUCCESS ) return -1;
// ierr = MPI_Gatherv ( &dSourceAreas[0], m_nTotDofs_SrcCov, MPI_DOUBLE, &dColumnSourceAreas[0],
// rcount.data(), displs.data(), MPI_DOUBLE, rootProc, m_pcomm->comm() ); if ( ierr !=
// MPI_SUCCESS ) return -1;
// Clean out unwanted arrays now
dColumnSums.clear();
dColumnsUnique.clear();
// Verify all column sums equal the input Jacobian
int fConservative = 0;
if( rank == rootProc )
{
displs[size] = ( nTotColumns );
// std::vector dColumnSumsOnRoot(nTotColumnsUnq, 0.0);
std::map< int, double > dColumnSumsOnRoot;
// std::map dColumnSourceAreasOnRoot;
for( int ir = 0; ir < size; ir++ )
{
for( int ips = displs[ir]; ips < displs[ir + 1]; ips++ )
{
if( dColumnIndices[ips] < 0 ) continue;
// printf("%d, %d: dColumnIndices[ips]: %d\n", ir, ips, dColumnIndices[ips]);
assert( dColumnIndices[ips] < nTotColumnsUnq );
dColumnSumsOnRoot[dColumnIndices[ips]] += dColumnSumsTotal[ips]; // / dColumnSourceAreas[ips];
// dColumnSourceAreasOnRoot[ dColumnIndices[ips] ] = dColumnSourceAreas[ips];
// dColumnSourceAreas[ dColumnIndices[ips] ]
}
}
for( std::map< int, double >::iterator it = dColumnSumsOnRoot.begin(); it != dColumnSumsOnRoot.end(); ++it )
{
// if ( fabs ( it->second - dColumnSourceAreasOnRoot[it->first] ) > dTolerance )
if( fabs( it->second - 1.0 ) > dTolerance )
{
fConservative++;
Announce( "TempestOnlineMap is not conservative in column "
// "%i (%1.15e)", it->first, it->second );
"%i (%1.15e)",
it->first, it->second /* / dColumnSourceAreasOnRoot[it->first] */ );
}
}
}
// TODO: Just do a broadcast from root instead of a reduction
ierr = MPI_Bcast( &fConservative, 1, MPI_INT, rootProc, m_pcomm->comm() );
if( ierr != MPI_SUCCESS ) return -1;
return fConservative;
#endif
}
int moab::TempestOnlineMap::IsConsistent | ( | double | dTolerance | ) | [virtual] |
Determine if the map is first-order accurate.
Definition at line 1432 of file TempestOnlineMap.cpp.
{
#ifndef MOAB_HAVE_MPI
return OfflineMap::IsConsistent( dTolerance );
#else
// Get map entries
DataArray1D< int > dataRows;
DataArray1D< int > dataCols;
DataArray1D< double > dataEntries;
// Calculate row sums
DataArray1D< double > dRowSums;
m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
dRowSums.Allocate( m_mapRemap.GetRows() );
for( unsigned i = 0; i < dataRows.GetRows(); i++ )
{
dRowSums[dataRows[i]] += dataEntries[i];
}
// Verify all row sums are equal to 1
int fConsistent = 0;
for( unsigned i = 0; i < dRowSums.GetRows(); i++ )
{
if( fabs( dRowSums[i] - 1.0 ) > dTolerance )
{
fConsistent++;
int rowGID = row_gdofmap[i];
Announce( "TempestOnlineMap is not consistent in row %i (%1.15e)", rowGID, dRowSums[i] );
}
}
int ierr;
int fConsistentGlobal = 0;
ierr = MPI_Allreduce( &fConsistent, &fConsistentGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
if( ierr != MPI_SUCCESS ) return -1;
return fConsistentGlobal;
#endif
}
int moab::TempestOnlineMap::IsMonotone | ( | double | dTolerance | ) | [virtual] |
Determine if the map is monotone.
Definition at line 1620 of file TempestOnlineMap.cpp.
{
#ifndef MOAB_HAVE_MPI
return OfflineMap::IsMonotone( dTolerance );
#else
// Get map entries
DataArray1D< int > dataRows;
DataArray1D< int > dataCols;
DataArray1D< double > dataEntries;
m_mapRemap.GetEntries( dataRows, dataCols, dataEntries );
// Verify all entries are in the range [0,1]
int fMonotone = 0;
for( unsigned i = 0; i < dataRows.GetRows(); i++ )
{
if( ( dataEntries[i] < -dTolerance ) || ( dataEntries[i] > 1.0 + dTolerance ) )
{
fMonotone++;
Announce( "TempestOnlineMap is not monotone in entry (%i): %1.15e", i, dataEntries[i] );
}
}
int ierr;
int fMonotoneGlobal = 0;
ierr = MPI_Allreduce( &fMonotone, &fMonotoneGlobal, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
if( ierr != MPI_SUCCESS ) return -1;
return fMonotoneGlobal;
#endif
}
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 115 of file TempestLinearRemap.cpp.
References moab::Remapper::CoveringMesh, dbgprint, moab::DebugOutput::printf(), and moab::DebugOutput::set_prefix().
{
// Order of triangular quadrature rule
const int TriQuadRuleOrder = 4;
// Verify ReverseNodeArray has been calculated
if( m_meshInputCov->faces.size() > 0 && m_meshInputCov->revnodearray.size() == 0 )
{
_EXCEPTIONT( "ReverseNodeArray has not been calculated for m_meshInput" );
}
// Triangular quadrature rule
TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
// Number of coefficients needed at this order
#ifdef RECTANGULAR_TRUNCATION
int nCoefficients = nOrder * nOrder;
#endif
#ifdef TRIANGULAR_TRUNCATION
int nCoefficients = nOrder * ( nOrder + 1 ) / 2;
#endif
// Number of faces you need
const int nRequiredFaceSetSize = nCoefficients;
// Fit weight exponent
const int nFitWeightsExponent = nOrder + 2;
// Announcemnets
moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
dbgprint.set_prefix( "[LinearRemapFVtoFV_Tempest_MOAB]: " );
if( is_root )
{
dbgprint.printf( 0, "Finite Volume to Finite Volume Projection\n" );
dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
dbgprint.printf( 0, "Number of coefficients: %i\n", nCoefficients );
dbgprint.printf( 0, "Required adjacency set size: %i\n", nRequiredFaceSetSize );
dbgprint.printf( 0, "Fit weights exponent: %i\n", nFitWeightsExponent );
}
// Current overlap face
int ixOverlap = 0;
const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
DataArray2D< double > dIntArray;
DataArray1D< double > dConstraint( nCoefficients );
// Loop through all faces on m_meshInput
for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
{
// Output every 1000 elements
#ifdef VERBOSE
if( ixFirst % outputFrequency == 0 && is_root )
{
dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
}
#endif
// Find the set of Faces that overlap faceFirst
int ixOverlapBegin = ixOverlap;
unsigned ixOverlapEnd = ixOverlapBegin;
for( ; ixOverlapEnd < m_meshOverlap->faces.size(); ixOverlapEnd++ )
{
if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapEnd] != 0 ) break;
}
unsigned nOverlapFaces = ixOverlapEnd - ixOverlapBegin;
if( nOverlapFaces == 0 )
{
{
std::cout << "rank:" << rank << " " << m_remapper->GetGlobalID( Remapper::CoveringMesh, ixFirst )
<< "\n";
}
continue;
}
// Build integration array
BuildIntegrationArray( *m_meshInputCov, *m_meshOverlap, triquadrule, ixFirst, ixOverlapBegin, ixOverlapEnd,
nOrder, dIntArray );
// Set of Faces to use in building the reconstruction and associated
// distance metric.
AdjacentFaceVector vecAdjFaces;
GetAdjacentFaceVectorByEdge( *m_meshInputCov, ixFirst, nRequiredFaceSetSize, vecAdjFaces );
// Number of adjacent Faces
int nAdjFaces = vecAdjFaces.size();
// Determine the conservative constraint equation
double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];
dConstraint.Zero();
for( int p = 0; p < nCoefficients; p++ )
{
for( unsigned j = 0; j < nOverlapFaces; j++ )
{
dConstraint[p] += dIntArray[p][j];
}
dConstraint[p] /= dFirstArea;
}
// Build the fit array from the integration operator
DataArray2D< double > dFitArray;
DataArray1D< double > dFitWeights;
DataArray2D< double > dFitArrayPlus;
BuildFitArray( *m_meshInputCov, triquadrule, ixFirst, vecAdjFaces, nOrder, nFitWeightsExponent, dConstraint,
dFitArray, dFitWeights );
// Compute the inverse fit array
bool fSuccess = InvertFitArray_Corrected( dConstraint, dFitArray, dFitWeights, dFitArrayPlus );
// Multiply integration array and fit array
DataArray2D< double > dComposedArray( nAdjFaces, nOverlapFaces );
if( fSuccess )
{
// Multiply integration array and inverse fit array
for( int i = 0; i < nAdjFaces; i++ )
{
for( size_t j = 0; j < nOverlapFaces; j++ )
{
for( int k = 0; k < nCoefficients; k++ )
{
dComposedArray( i, j ) += dIntArray( k, j ) * dFitArrayPlus( i, k );
}
}
}
// Unable to invert fit array, drop to 1st order. In this case
// dFitArrayPlus(0,0) = 1 and all other entries are zero.
}
else
{
dComposedArray.Zero();
for( size_t j = 0; j < nOverlapFaces; j++ )
{
dComposedArray( 0, j ) += dIntArray( 0, j );
}
}
// Put composed array into map
for( unsigned i = 0; i < vecAdjFaces.size(); i++ )
{
for( unsigned j = 0; j < nOverlapFaces; j++ )
{
int& ixFirstFaceLoc = vecAdjFaces[i].first;
int& ixSecondFaceLoc = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
// int ixFirstFaceGlob = m_remapper->GetGlobalID(moab::Remapper::SourceMesh,
// ixFirstFaceLoc); int ixSecondFaceGlob =
// m_remapper->GetGlobalID(moab::Remapper::TargetMesh, ixSecondFaceLoc);
// signal to not participate, because it is a ghost target
if( ixSecondFaceLoc < 0 ) continue; // do not do anything
m_mapRemap( ixSecondFaceLoc, ixFirstFaceLoc ) +=
dComposedArray[i][j] / m_meshOutput->vecFaceArea[ixSecondFaceLoc];
}
}
// Increment the current overlap index
ixOverlap += nOverlapFaces;
}
return;
}
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.
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 900 of file TempestLinearRemap.cpp.
References center(), dbgprint, ForceIntArrayConsistencyConservation(), moab::DebugOutput::printf(), moab::DebugOutput::set_prefix(), and t.
{
// Triangular quadrature rule
TriangularQuadratureRule triquadrule( 8 );
const DataArray2D< double >& dG = triquadrule.GetG();
const DataArray1D< double >& dW = triquadrule.GetW();
// Get SparseMatrix represntation of the OfflineMap
SparseMatrix< double >& smatMap = this->GetSparseMatrix();
// Sample coefficients
DataArray2D< double > dSampleCoeffIn( nPin, nPin );
DataArray2D< double > dSampleCoeffOut( nPout, nPout );
// Announcemnets
moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_MOAB]: " );
if( is_root )
{
dbgprint.printf( 0, "Finite Element to Finite Element Projection\n" );
dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
}
// Build the integration array for each element on m_meshOverlap
DataArray3D< double > dGlobalIntArray( nPin * nPin, m_meshOverlap->faces.size(), nPout * nPout );
// Number of overlap Faces per source Face
DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
int ixOverlap = 0;
for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
{
// Determine how many overlap Faces and triangles are present
int nOverlapFaces = 0;
size_t ixOverlapTemp = ixOverlap;
for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
{
// const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 )
{
break;
}
nOverlapFaces++;
}
nAllOverlapFaces[ixFirst] = nOverlapFaces;
// Increment the current overlap index
ixOverlap += nAllOverlapFaces[ixFirst];
}
// Geometric area of each output node
DataArray2D< double > dGeometricOutputArea( m_meshOutput->faces.size(), nPout * nPout );
// Area of each overlap element in the output basis
DataArray2D< double > dOverlapOutputArea( m_meshOverlap->faces.size(), nPout * nPout );
// Loop through all faces on m_meshInput
ixOverlap = 0;
const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
if( is_root ) dbgprint.printf( 0, "Building conservative distribution maps\n" );
// generic triangle used for area computation, for triangles around the center of overlap face;
// used for overlap faces with more than 4 edges;
// nodes array will be set for each triangle;
// these triangles are not part of the mesh structure, they are just temporary during
// aforementioned decomposition.
Face faceTri( 3 );
NodeVector nodes( 3 );
faceTri.SetNode( 0, 0 );
faceTri.SetNode( 1, 1 );
faceTri.SetNode( 2, 2 );
for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
{
#ifdef VERBOSE
// Announce computation progress
if( ixFirst % outputFrequency == 0 && is_root )
{
dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
}
#endif
// Quantities from the First Mesh
const Face& faceFirst = m_meshInputCov->faces[ixFirst];
const NodeVector& nodesFirst = m_meshInputCov->nodes;
// Number of overlapping Faces and triangles
int nOverlapFaces = nAllOverlapFaces[ixFirst];
if( !nOverlapFaces ) continue;
// // Calculate total element Jacobian
// double dTotalJacobian = 0.0;
// for (int s = 0; s < nPin; s++) {
// for (int t = 0; t < nPin; t++) {
// dTotalJacobian += dataGLLJacobianIn[s][t][ixFirst];
// }
// }
// Loop through all Overlap Faces
for( int i = 0; i < nOverlapFaces; i++ )
{
// Quantities from the overlap Mesh
const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + i];
const NodeVector& nodesOverlap = m_meshOverlap->nodes;
// Quantities from the Second Mesh
int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
// signal to not participate, because it is a ghost target
if( ixSecond < 0 ) continue; // do not do anything
const NodeVector& nodesSecond = m_meshOutput->nodes;
const Face& faceSecond = m_meshOutput->faces[ixSecond];
int nbEdges = faceOverlap.edges.size();
int nOverlapTriangles = 1;
Node center; // not used if nbEdges == 3
if( nbEdges > 3 )
{ // decompose from center in this case
nOverlapTriangles = nbEdges;
for( int k = 0; k < nbEdges; k++ )
{
const Node& node = nodesOverlap[faceOverlap[k]];
center = center + node;
}
center = center / nbEdges;
center = center.Normalized(); // project back on sphere of radius 1
}
Node node0, node1, node2;
double dTriArea;
// Loop over all sub-triangles of this Overlap Face
for( int j = 0; j < nOverlapTriangles; j++ )
{
if( nbEdges == 3 ) // will come here only once, nOverlapTriangles == 1 in this case
{
node0 = nodesOverlap[faceOverlap[0]];
node1 = nodesOverlap[faceOverlap[1]];
node2 = nodesOverlap[faceOverlap[2]];
dTriArea = CalculateFaceArea( faceOverlap, nodesOverlap );
}
else // decompose polygon in triangles around the center
{
node0 = center;
node1 = nodesOverlap[faceOverlap[j]];
int j1 = ( j + 1 ) % nbEdges;
node2 = nodesOverlap[faceOverlap[j1]];
nodes[0] = center;
nodes[1] = node1;
nodes[2] = node2;
dTriArea = CalculateFaceArea( faceTri, nodes );
}
for( int k = 0; k < triquadrule.GetPoints(); k++ )
{
// Get the nodal location of this point
double dX[3];
dX[0] = dG( k, 0 ) * node0.x + dG( k, 1 ) * node1.x + dG( k, 2 ) * node2.x;
dX[1] = dG( k, 0 ) * node0.y + dG( k, 1 ) * node1.y + dG( k, 2 ) * node2.y;
dX[2] = dG( k, 0 ) * node0.z + dG( k, 1 ) * node1.z + dG( k, 2 ) * node2.z;
double dMag = sqrt( dX[0] * dX[0] + dX[1] * dX[1] + dX[2] * dX[2] );
dX[0] /= dMag;
dX[1] /= dMag;
dX[2] /= dMag;
Node nodeQuadrature( dX[0], dX[1], dX[2] );
// Find the components of this quadrature point in the basis
// of the first Face.
double dAlphaIn;
double dBetaIn;
ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlphaIn, dBetaIn );
// Find the components of this quadrature point in the basis
// of the second Face.
double dAlphaOut;
double dBetaOut;
ApplyInverseMap( faceSecond, nodesSecond, nodeQuadrature, dAlphaOut, dBetaOut );
/*
// Check inverse map value
if ((dAlphaIn < 0.0) || (dAlphaIn > 1.0) ||
(dBetaIn < 0.0) || (dBetaIn > 1.0)
) {
_EXCEPTION2("Inverse Map out of range (%1.5e %1.5e)",
dAlphaIn, dBetaIn);
}
// Check inverse map value
if ((dAlphaOut < 0.0) || (dAlphaOut > 1.0) ||
(dBetaOut < 0.0) || (dBetaOut > 1.0)
) {
_EXCEPTION2("Inverse Map out of range (%1.5e %1.5e)",
dAlphaOut, dBetaOut);
}
*/
// Sample the First finite element at this point
SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
// Sample the Second finite element at this point
SampleGLLFiniteElement( nMonotoneType, nPout, dAlphaOut, dBetaOut, dSampleCoeffOut );
// Overlap output area
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
double dNodeArea = dSampleCoeffOut[s][t] * dW[k] * dTriArea;
dOverlapOutputArea[ixOverlap + i][s * nPout + t] += dNodeArea;
dGeometricOutputArea[ixSecond][s * nPout + t] += dNodeArea;
}
}
// Compute overlap integral
int ixp = 0;
for( int p = 0; p < nPin; p++ )
{
for( int q = 0; q < nPin; q++ )
{
int ixs = 0;
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
// Sample the Second finite element at this point
dGlobalIntArray[ixp][ixOverlap + i][ixs] +=
dSampleCoeffOut[s][t] * dSampleCoeffIn[p][q] * dW[k] * dTriArea;
ixs++;
}
}
ixp++;
}
}
}
}
}
// Coefficients
DataArray2D< double > dCoeff( nOverlapFaces * nPout * nPout, nPin * nPin );
for( int i = 0; i < nOverlapFaces; i++ )
{
// int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
int ixp = 0;
for( int p = 0; p < nPin; p++ )
{
for( int q = 0; q < nPin; q++ )
{
int ixs = 0;
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
dCoeff[i * nPout * nPout + ixs][ixp] = dGlobalIntArray[ixp][ixOverlap + i][ixs] /
dOverlapOutputArea[ixOverlap + i][s * nPout + t];
ixs++;
}
}
ixp++;
}
}
}
// Source areas
DataArray1D< double > vecSourceArea( nPin * nPin );
for( int p = 0; p < nPin; p++ )
{
for( int q = 0; q < nPin; q++ )
{
vecSourceArea[p * nPin + q] = dataGLLJacobianIn[p][q][ixFirst];
}
}
// Target areas
DataArray1D< double > vecTargetArea( nOverlapFaces * nPout * nPout );
for( int i = 0; i < nOverlapFaces; i++ )
{
// int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
int ixs = 0;
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
vecTargetArea[i * nPout * nPout + ixs] = dOverlapOutputArea[ixOverlap + i][nPout * s + t];
ixs++;
}
}
}
// Force consistency and conservation
if( !fNoConservation )
{
ForceIntArrayConsistencyConservation( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType != 0 ) );
}
// Update global coefficients
for( int i = 0; i < nOverlapFaces; i++ )
{
int ixp = 0;
for( int p = 0; p < nPin; p++ )
{
for( int q = 0; q < nPin; q++ )
{
int ixs = 0;
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
dGlobalIntArray[ixp][ixOverlap + i][ixs] =
dCoeff[i * nPout * nPout + ixs][ixp] * dOverlapOutputArea[ixOverlap + i][s * nPout + t];
ixs++;
}
}
ixp++;
}
}
}
#ifdef VVERBOSE
// Check column sums (conservation)
for( int i = 0; i < nPin * nPin; i++ )
{
double dColSum = 0.0;
for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
{
dColSum += dCoeff[j][i] * vecTargetArea[j];
}
printf( "Col %i: %1.15e\n", i, dColSum / vecSourceArea[i] );
}
// Check row sums (consistency)
for( int j = 0; j < nOverlapFaces * nPout * nPout; j++ )
{
double dRowSum = 0.0;
for( int i = 0; i < nPin * nPin; i++ )
{
dRowSum += dCoeff[j][i];
}
printf( "Row %i: %1.15e\n", j, dRowSum );
}
#endif
// Increment the current overlap index
ixOverlap += nOverlapFaces;
}
// Build redistribution map within target element
if( is_root ) dbgprint.printf( 0, "Building redistribution maps on target mesh\n" );
DataArray1D< double > dRedistSourceArea( nPout * nPout );
DataArray1D< double > dRedistTargetArea( nPout * nPout );
std::vector< DataArray2D< double > > dRedistributionMaps;
dRedistributionMaps.resize( m_meshOutput->faces.size() );
for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
{
dRedistributionMaps[ixSecond].Allocate( nPout * nPout, nPout * nPout );
for( int i = 0; i < nPout * nPout; i++ )
{
dRedistributionMaps[ixSecond][i][i] = 1.0;
}
for( int s = 0; s < nPout * nPout; s++ )
{
dRedistSourceArea[s] = dGeometricOutputArea[ixSecond][s];
}
for( int s = 0; s < nPout * nPout; s++ )
{
dRedistTargetArea[s] = dataGLLJacobianOut[s / nPout][s % nPout][ixSecond];
}
if( !fNoConservation )
{
ForceIntArrayConsistencyConservation( dRedistSourceArea, dRedistTargetArea, dRedistributionMaps[ixSecond],
( nMonotoneType != 0 ) );
for( int s = 0; s < nPout * nPout; s++ )
{
for( int t = 0; t < nPout * nPout; t++ )
{
dRedistributionMaps[ixSecond][s][t] *= dRedistTargetArea[s] / dRedistSourceArea[t];
}
}
}
}
// Construct the total geometric area
DataArray1D< double > dTotalGeometricArea( dataNodalAreaOut.GetRows() );
for( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
{
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
dTotalGeometricArea[dataGLLNodesOut[s][t][ixSecond] - 1] +=
dGeometricOutputArea[ixSecond][s * nPout + t];
}
}
}
// Compose the integration operator with the output map
ixOverlap = 0;
if( is_root ) dbgprint.printf( 0, "Assembling map\n" );
// Map from source DOFs to target DOFs with redistribution applied
DataArray2D< double > dRedistributedOp( nPin * nPin, nPout * nPout );
for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
{
#ifdef VERBOSE
// Announce computation progress
if( ixFirst % outputFrequency == 0 && is_root )
{
dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
}
#endif
// Number of overlapping Faces and triangles
int nOverlapFaces = nAllOverlapFaces[ixFirst];
if( !nOverlapFaces ) continue;
// Put composed array into map
for( int j = 0; j < nOverlapFaces; j++ )
{
int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
// signal to not participate, because it is a ghost target
if( ixSecondFace < 0 ) continue; // do not do anything
dRedistributedOp.Zero();
for( int p = 0; p < nPin * nPin; p++ )
{
for( int s = 0; s < nPout * nPout; s++ )
{
for( int t = 0; t < nPout * nPout; t++ )
{
dRedistributedOp[p][s] +=
dRedistributionMaps[ixSecondFace][s][t] * dGlobalIntArray[p][ixOverlap + j][t];
}
}
}
int ixp = 0;
for( int p = 0; p < nPin; p++ )
{
for( int q = 0; q < nPin; q++ )
{
int ixFirstNode;
if( fContinuousIn )
{
ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
}
else
{
ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
}
int ixs = 0;
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
int ixSecondNode;
if( fContinuousOut )
{
ixSecondNode = dataGLLNodesOut[s][t][ixSecondFace] - 1;
if( !fNoConservation )
{
smatMap( ixSecondNode, ixFirstNode ) +=
dRedistributedOp[ixp][ixs] / dataNodalAreaOut[ixSecondNode];
}
else
{
smatMap( ixSecondNode, ixFirstNode ) +=
dRedistributedOp[ixp][ixs] / dTotalGeometricArea[ixSecondNode];
}
}
else
{
ixSecondNode = ixSecondFace * nPout * nPout + s * nPout + t;
if( !fNoConservation )
{
smatMap( ixSecondNode, ixFirstNode ) +=
dRedistributedOp[ixp][ixs] / dataGLLJacobianOut[s][t][ixSecondFace];
}
else
{
smatMap( ixSecondNode, ixFirstNode ) +=
dRedistributedOp[ixp][ixs] / dGeometricOutputArea[ixSecondFace][s * nPout + t];
}
}
ixs++;
}
}
ixp++;
}
}
}
// Increment the current overlap index
ixOverlap += nOverlapFaces;
}
return;
}
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 1450 of file TempestLinearRemap.cpp.
References dbgprint, moab::DebugOutput::printf(), moab::DebugOutput::set_prefix(), and t.
{
// Gauss-Lobatto quadrature within Faces
DataArray1D< double > dGL;
DataArray1D< double > dWL;
GaussLobattoQuadrature::GetPoints( nPout, 0.0, 1.0, dGL, dWL );
// Get SparseMatrix represntation of the OfflineMap
SparseMatrix< double >& smatMap = this->GetSparseMatrix();
// Sample coefficients
DataArray2D< double > dSampleCoeffIn( nPin, nPin );
// Announcemnets
moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
dbgprint.set_prefix( "[LinearRemapGLLtoGLL2_Pointwise_MOAB]: " );
if( is_root )
{
dbgprint.printf( 0, "Finite Element to Finite Element (Pointwise) Projection\n" );
dbgprint.printf( 0, "Order of the input FE polynomial interpolant: %i\n", nPin );
dbgprint.printf( 0, "Order of the output FE polynomial interpolant: %i\n", nPout );
}
// Number of overlap Faces per source Face
DataArray1D< int > nAllOverlapFaces( m_meshInputCov->faces.size() );
int ixOverlap = 0;
for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
{
size_t ixOverlapTemp = ixOverlap;
for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
{
// const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 ) break;
nAllOverlapFaces[ixFirst]++;
}
// Increment the current overlap index
ixOverlap += nAllOverlapFaces[ixFirst];
}
// Number of times this point was found
DataArray1D< bool > fSecondNodeFound( dataNodalAreaOut.GetRows() );
ixOverlap = 0;
const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
// Loop through all faces on m_meshInputCov
for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
{
#ifdef VERBOSE
// Announce computation progress
if( ixFirst % outputFrequency == 0 && is_root )
{
dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
}
#endif
// Quantities from the First Mesh
const Face& faceFirst = m_meshInputCov->faces[ixFirst];
const NodeVector& nodesFirst = m_meshInputCov->nodes;
// Number of overlapping Faces and triangles
int nOverlapFaces = nAllOverlapFaces[ixFirst];
// Loop through all Overlap Faces
for( int i = 0; i < nOverlapFaces; i++ )
{
// Quantities from the Second Mesh
int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];
// signal to not participate, because it is a ghost target
if( ixSecond < 0 ) continue; // do not do anything
const NodeVector& nodesSecond = m_meshOutput->nodes;
const Face& faceSecond = m_meshOutput->faces[ixSecond];
// Loop through all nodes on the second face
for( int s = 0; s < nPout; s++ )
{
for( int t = 0; t < nPout; t++ )
{
size_t ixSecondNode;
if( fContinuousOut )
{
ixSecondNode = dataGLLNodesOut[s][t][ixSecond] - 1;
}
else
{
ixSecondNode = ixSecond * nPout * nPout + s * nPout + t;
}
if( ixSecondNode >= fSecondNodeFound.GetRows() )
{
_EXCEPTIONT( "Logic error" );
}
// Check if this node has been found already
if( fSecondNodeFound[ixSecondNode] )
{
continue;
}
// Check this node
Node node;
Node dDx1G;
Node dDx2G;
ApplyLocalMap( faceSecond, nodesSecond, dGL[t], dGL[s], node, dDx1G, dDx2G );
// Find the components of this quadrature point in the basis
// of the first Face.
double dAlphaIn;
double dBetaIn;
ApplyInverseMap( faceFirst, nodesFirst, node, dAlphaIn, dBetaIn );
// Check if this node is within the first Face
if( ( dAlphaIn < -1.0e-10 ) || ( dAlphaIn > 1.0 + 1.0e-10 ) || ( dBetaIn < -1.0e-10 ) ||
( dBetaIn > 1.0 + 1.0e-10 ) )
{
continue;
}
// Node is within the overlap region, mark as found
fSecondNodeFound[ixSecondNode] = true;
// Sample the First finite element at this point
SampleGLLFiniteElement( nMonotoneType, nPin, dAlphaIn, dBetaIn, dSampleCoeffIn );
// Add to map
for( int p = 0; p < nPin; p++ )
{
for( int q = 0; q < nPin; q++ )
{
int ixFirstNode;
if( fContinuousIn )
{
ixFirstNode = dataGLLNodesIn[p][q][ixFirst] - 1;
}
else
{
ixFirstNode = ixFirst * nPin * nPin + p * nPin + q;
}
smatMap( ixSecondNode, ixFirstNode ) += dSampleCoeffIn[p][q];
}
}
}
}
}
// Increment the current overlap index
ixOverlap += nOverlapFaces;
}
// Check for missing samples
for( size_t i = 0; i < fSecondNodeFound.GetRows(); i++ )
{
if( !fSecondNodeFound[i] )
{
_EXCEPTION1( "Can't sample point %i", i );
}
}
return;
}
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 52 of file TempestLinearRemap.cpp.
References col_gdofmap, m_nTotDofs_Dest, m_nTotDofs_SrcCov, MB_SUCCESS, and row_gdofmap.
{
/* m_mapRemap size = (m_nTotDofs_Dest X m_nTotDofs_SrcCov) */
#ifdef VVERBOSE
{
std::ofstream output_file( "rowcolindices.txt", std::ios::out );
output_file << m_nTotDofs_Dest << " " << m_nTotDofs_SrcCov << " " << row_gdofmap.size() << " "
<< row_ldofmap.size() << " " << col_gdofmap.size() << " " << col_ldofmap.size() << "\n";
output_file << "Rows \n";
for( unsigned iv = 0; iv < row_gdofmap.size(); iv++ )
output_file << row_gdofmap[iv] << " " << row_dofmap[iv] << "\n";
output_file << "Cols \n";
for( unsigned iv = 0; iv < col_gdofmap.size(); iv++ )
output_file << col_gdofmap[iv] << " " << col_dofmap[iv] << "\n";
output_file.flush(); // required here
output_file.close();
}
#endif
if( use_GID_matching )
{
std::map< unsigned, unsigned > src_gl;
for( unsigned it = 0; it < col_gdofmap.size(); ++it )
src_gl[col_gdofmap[it]] = it;
std::map< unsigned, unsigned >::iterator iter;
for( unsigned it = 0; it < row_gdofmap.size(); ++it )
{
unsigned row = row_gdofmap[it];
iter = src_gl.find( row );
if( strict_check && iter == src_gl.end() )
{
std::cout << "Searching for global target DOF " << row
<< " but could not find correspondence in source mesh.\n";
assert( false );
}
else if( iter == src_gl.end() )
{
continue;
}
else
{
unsigned icol = src_gl[row];
unsigned irow = it;
// Set the permutation matrix in local space
m_mapRemap( irow, icol ) = 1.0;
}
}
return moab::MB_SUCCESS;
}
else
{
/* Create a Kd-tree to perform local queries to find nearest neighbors */
return moab::MB_SUCCESS;
}
}
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.
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 475 of file TempestLinearRemap.cpp.
References center(), dbgprint, ForceConsistencyConservation3(), moab::DebugOutput::printf(), and moab::DebugOutput::set_prefix().
{
// Order of the polynomial interpolant
int nP = dataGLLNodes.GetRows();
// Order of triangular quadrature rule
const int TriQuadRuleOrder = 4;
// Triangular quadrature rule
TriangularQuadratureRule triquadrule( TriQuadRuleOrder );
int TriQuadraturePoints = triquadrule.GetPoints();
const DataArray2D< double >& TriQuadratureG = triquadrule.GetG();
const DataArray1D< double >& TriQuadratureW = triquadrule.GetW();
// Sample coefficients
DataArray2D< double > dSampleCoeff( nP, nP );
// GLL Quadrature nodes on quadrilateral elements
DataArray1D< double > dG;
DataArray1D< double > dW;
GaussLobattoQuadrature::GetPoints( nP, 0.0, 1.0, dG, dW );
// Announcements
moab::DebugOutput dbgprint( std::cout, this->rank, 0 );
dbgprint.set_prefix( "[LinearRemapSE4_Tempest_MOAB]: " );
if( is_root )
{
dbgprint.printf( 0, "Finite Element to Finite Volume Projection\n" );
dbgprint.printf( 0, "Triangular quadrature rule order %i\n", TriQuadRuleOrder );
dbgprint.printf( 0, "Order of the FE polynomial interpolant: %i\n", nP );
}
// Get SparseMatrix represntation of the OfflineMap
SparseMatrix< double >& smatMap = this->GetSparseMatrix();
// NodeVector from m_meshOverlap
const NodeVector& nodesOverlap = m_meshOverlap->nodes;
const NodeVector& nodesFirst = m_meshInputCov->nodes;
// Vector of source areas
DataArray1D< double > vecSourceArea( nP * nP );
DataArray1D< double > vecTargetArea;
DataArray2D< double > dCoeff;
#ifdef VERBOSE
std::stringstream sstr;
sstr << "remapdata_" << rank << ".txt";
std::ofstream output_file( sstr.str() );
#endif
// Current Overlap Face
int ixOverlap = 0;
const unsigned outputFrequency = ( m_meshInputCov->faces.size() / 10 ) + 1;
// generic triangle used for area computation, for triangles around the center of overlap face;
// used for overlap faces with more than 4 edges;
// nodes array will be set for each triangle;
// these triangles are not part of the mesh structure, they are just temporary during
// aforementioned decomposition.
Face faceTri( 3 );
NodeVector nodes( 3 );
faceTri.SetNode( 0, 0 );
faceTri.SetNode( 1, 1 );
faceTri.SetNode( 2, 2 );
// Loop over all input Faces
for( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
{
const Face& faceFirst = m_meshInputCov->faces[ixFirst];
if( faceFirst.edges.size() != 4 )
{
_EXCEPTIONT( "Only quadrilateral elements allowed for SE remapping" );
}
#ifdef VERBOSE
// Announce computation progress
if( ixFirst % outputFrequency == 0 && is_root )
{
dbgprint.printf( 0, "Element %zu/%lu\n", ixFirst, m_meshInputCov->faces.size() );
}
#endif
// Need to re-number the overlap elements such that vecSourceFaceIx[a:b] = 0, then 1 and so
// on wrt the input mesh data Then the overlap_end and overlap_begin will be correct.
// However, the relation with MOAB and Tempest will go out of the roof
// Determine how many overlap Faces and triangles are present
int nOverlapFaces = 0;
size_t ixOverlapTemp = ixOverlap;
for( ; ixOverlapTemp < m_meshOverlap->faces.size(); ixOverlapTemp++ )
{
// const Face & faceOverlap = m_meshOverlap->faces[ixOverlapTemp];
if( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapTemp] != 0 )
{
break;
}
nOverlapFaces++;
}
// No overlaps
if( nOverlapFaces == 0 )
{
continue;
}
// Allocate remap coefficients array for meshFirst Face
DataArray3D< double > dRemapCoeff( nP, nP, nOverlapFaces );
// Find the local remap coefficients
for( int j = 0; j < nOverlapFaces; j++ )
{
const Face& faceOverlap = m_meshOverlap->faces[ixOverlap + j];
if( m_meshOverlap->vecFaceArea[ixOverlap + j] < 1.e-16 ) // machine precision
{
Announce( "Very small overlap at index %i area polygon: (%1.10e )", ixOverlap + j,
m_meshOverlap->vecFaceArea[ixOverlap + j] );
int n = faceOverlap.edges.size();
Announce( "Number nodes: %d", n );
for( int k = 0; k < n; k++ )
{
Node nd = nodesOverlap[faceOverlap[k]];
Announce( "Node %d %d : %1.10e %1.10e %1.10e ", k, faceOverlap[k], nd.x, nd.y, nd.z );
}
continue;
}
// #ifdef VERBOSE
// if ( is_root )
// Announce ( "\tLocal ID: %i/%i = %i, areas = %2.8e", j + ixOverlap, nOverlapFaces,
// m_remapper->lid_to_gid_covsrc[m_meshOverlap->vecSourceFaceIx[ixOverlap + j]],
// m_meshOverlap->vecFaceArea[ixOverlap + j] );
// #endif
int nbEdges = faceOverlap.edges.size();
int nOverlapTriangles = 1;
Node center; // not used if nbEdges == 3
if( nbEdges > 3 )
{ // decompose from center in this case
nOverlapTriangles = nbEdges;
for( int k = 0; k < nbEdges; k++ )
{
const Node& node = nodesOverlap[faceOverlap[k]];
center = center + node;
}
center = center / nbEdges;
center = center.Normalized(); // project back on sphere of radius 1
}
Node node0, node1, node2;
double dTriangleArea;
// Loop over all sub-triangles of this Overlap Face
for( int k = 0; k < nOverlapTriangles; k++ )
{
if( nbEdges == 3 ) // will come here only once, nOverlapTriangles == 1 in this case
{
node0 = nodesOverlap[faceOverlap[0]];
node1 = nodesOverlap[faceOverlap[1]];
node2 = nodesOverlap[faceOverlap[2]];
dTriangleArea = CalculateFaceArea( faceOverlap, nodesOverlap );
}
else // decompose polygon in triangles around the center
{
node0 = center;
node1 = nodesOverlap[faceOverlap[k]];
int k1 = ( k + 1 ) % nbEdges;
node2 = nodesOverlap[faceOverlap[k1]];
nodes[0] = center;
nodes[1] = node1;
nodes[2] = node2;
dTriangleArea = CalculateFaceArea( faceTri, nodes );
}
// Coordinates of quadrature Node
for( int l = 0; l < TriQuadraturePoints; l++ )
{
Node nodeQuadrature;
nodeQuadrature.x = TriQuadratureG[l][0] * node0.x + TriQuadratureG[l][1] * node1.x +
TriQuadratureG[l][2] * node2.x;
nodeQuadrature.y = TriQuadratureG[l][0] * node0.y + TriQuadratureG[l][1] * node1.y +
TriQuadratureG[l][2] * node2.y;
nodeQuadrature.z = TriQuadratureG[l][0] * node0.z + TriQuadratureG[l][1] * node1.z +
TriQuadratureG[l][2] * node2.z;
nodeQuadrature = nodeQuadrature.Normalized();
// Find components of quadrature point in basis
// of the first Face
double dAlpha;
double dBeta;
ApplyInverseMap( faceFirst, nodesFirst, nodeQuadrature, dAlpha, dBeta );
// Check inverse map value
if( ( dAlpha < -1.0e-13 ) || ( dAlpha > 1.0 + 1.0e-13 ) || ( dBeta < -1.0e-13 ) ||
( dBeta > 1.0 + 1.0e-13 ) )
{
_EXCEPTION4( "Inverse Map for element %d and subtriangle %d out of range "
"(%1.5e %1.5e)",
j, l, dAlpha, dBeta );
}
// Sample the finite element at this point
SampleGLLFiniteElement( nMonotoneType, nP, dAlpha, dBeta, dSampleCoeff );
// Add sample coefficients to the map if m_meshOverlap->vecFaceArea[ixOverlap + j] > 0
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
dRemapCoeff[p][q][j] += TriQuadratureW[l] * dTriangleArea * dSampleCoeff[p][q] /
m_meshOverlap->vecFaceArea[ixOverlap + j];
}
}
}
}
}
#ifdef VERBOSE
output_file << "[" << m_remapper->lid_to_gid_covsrc[ixFirst] << "] \t";
for( int j = 0; j < nOverlapFaces; j++ )
{
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
output_file << dRemapCoeff[p][q][j] << " ";
}
}
}
output_file << std::endl;
#endif
// Force consistency and conservation
if( !fNoConservation )
{
double dTargetArea = 0.0;
for( int j = 0; j < nOverlapFaces; j++ )
{
dTargetArea += m_meshOverlap->vecFaceArea[ixOverlap + j];
}
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
vecSourceArea[p * nP + q] = dataGLLJacobian[p][q][ixFirst];
}
}
const double areaTolerance = 1e-10;
// Source elements are completely covered by target volumes
if( fabs( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea ) <= areaTolerance )
{
vecTargetArea.Allocate( nOverlapFaces );
for( int j = 0; j < nOverlapFaces; j++ )
{
vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
}
dCoeff.Allocate( nOverlapFaces, nP * nP );
for( int j = 0; j < nOverlapFaces; j++ )
{
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
}
}
}
// Target volumes only partially cover source elements
}
else if( m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea > areaTolerance )
{
double dExtraneousArea = m_meshInputCov->vecFaceArea[ixFirst] - dTargetArea;
vecTargetArea.Allocate( nOverlapFaces + 1 );
for( int j = 0; j < nOverlapFaces; j++ )
{
vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
}
vecTargetArea[nOverlapFaces] = dExtraneousArea;
#ifdef VERBOSE
Announce( "Partial volume: %i (%1.10e / %1.10e)", ixFirst, dTargetArea,
m_meshInputCov->vecFaceArea[ixFirst] );
#endif
if( dTargetArea > m_meshInputCov->vecFaceArea[ixFirst] )
{
_EXCEPTIONT( "Partial element area exceeds total element area" );
}
dCoeff.Allocate( nOverlapFaces + 1, nP * nP );
for( int j = 0; j < nOverlapFaces; j++ )
{
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
dCoeff[j][p * nP + q] = dRemapCoeff[p][q][j];
}
}
}
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
dCoeff[nOverlapFaces][p * nP + q] = dataGLLJacobian[p][q][ixFirst];
}
}
for( int j = 0; j < nOverlapFaces; j++ )
{
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
dCoeff[nOverlapFaces][p * nP + q] -=
dRemapCoeff[p][q][j] * m_meshOverlap->vecFaceArea[ixOverlap + j];
}
}
}
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
dCoeff[nOverlapFaces][p * nP + q] /= dExtraneousArea;
}
}
// Source elements only partially cover target volumes
}
else
{
Announce( "Coverage area: %1.10e, and target element area: %1.10e)", ixFirst,
m_meshInputCov->vecFaceArea[ixFirst], dTargetArea );
_EXCEPTIONT( "Target grid must be a subset of source grid" );
}
ForceConsistencyConservation3( vecSourceArea, vecTargetArea, dCoeff, ( nMonotoneType > 0 )
/*, m_remapper->lid_to_gid_covsrc[ixFirst]*/ );
for( int j = 0; j < nOverlapFaces; j++ )
{
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
dRemapCoeff[p][q][j] = dCoeff[j][p * nP + q];
}
}
}
}
#ifdef VERBOSE
// output_file << "[" << m_remapper->lid_to_gid_covsrc[ixFirst] << "] \t";
// for ( int j = 0; j < nOverlapFaces; j++ )
// {
// for ( int p = 0; p < nP; p++ )
// {
// for ( int q = 0; q < nP; q++ )
// {
// output_file << dRemapCoeff[p][q][j] << " ";
// }
// }
// }
// output_file << std::endl;
#endif
// Put these remap coefficients into the SparseMatrix map
for( int j = 0; j < nOverlapFaces; j++ )
{
int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];
// signal to not participate, because it is a ghost target
if( ixSecondFace < 0 ) continue; // do not do anything
for( int p = 0; p < nP; p++ )
{
for( int q = 0; q < nP; q++ )
{
if( fContinuousIn )
{
int ixFirstNode = dataGLLNodes[p][q][ixFirst] - 1;
smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
m_meshOverlap->vecFaceArea[ixOverlap + j] /
m_meshOutput->vecFaceArea[ixSecondFace];
}
else
{
int ixFirstNode = ixFirst * nP * nP + p * nP + q;
smatMap( ixSecondFace, ixFirstNode ) += dRemapCoeff[p][q][j] *
m_meshOverlap->vecFaceArea[ixOverlap + j] /
m_meshOutput->vecFaceArea[ixSecondFace];
}
}
}
}
// Increment the current overlap index
ixOverlap += nOverlapFaces;
}
#ifdef VERBOSE
output_file.flush(); // required here
output_file.close();
#endif
return;
}
moab::ErrorCode moab::TempestOnlineMap::ReadParallelMap | ( | const char * | strSource, |
const std::vector< int > & | owned_dof_ids, | ||
bool | row_major_ownership = true |
||
) |
Generate the metadata associated with the offline map.
Read the OfflineMap from a NetCDF file.
Definition at line 1181 of file TempestOnlineMapIO.cpp.
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.
{
NcError error( NcError::silent_nonfatal );
NcVar *varRow = NULL, *varCol = NULL, *varS = NULL;
int nS = 0, nA = 0, nB = 0;
#ifdef MOAB_HAVE_PNETCDF
// some variables will be used just in the case netcdfpar reader fails
int ncfile = -1, ret = 0;
int ndims, nvars, ngatts, unlimited;
#endif
#ifdef MOAB_HAVE_NETCDFPAR
bool is_independent = true;
ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 );
// ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 );
#else
NcFile ncMap( strSource, NcFile::ReadOnly );
#endif
#define CHECK_EXCEPTION( obj, type, varstr ) \
{ \
if( obj == NULL ) \
{ \
_EXCEPTION3( "Map file \"%s\" does not contain %s \"%s\"", strSource, type, varstr ); \
} \
}
// Read SparseMatrix entries
if( ncMap.is_valid() )
{
NcDim* dimNS = ncMap.get_dim( "n_s" );
CHECK_EXCEPTION( dimNS, "dimension", "n_s" );
NcDim* dimNA = ncMap.get_dim( "n_a" );
CHECK_EXCEPTION( dimNA, "dimension", "n_a" );
NcDim* dimNB = ncMap.get_dim( "n_b" );
CHECK_EXCEPTION( dimNB, "dimension", "n_b" );
// store total number of nonzeros
nS = dimNS->size();
nA = dimNA->size();
nB = dimNB->size();
varRow = ncMap.get_var( "row" );
CHECK_EXCEPTION( varRow, "variable", "row" );
varCol = ncMap.get_var( "col" );
CHECK_EXCEPTION( varCol, "variable", "col" );
varS = ncMap.get_var( "S" );
CHECK_EXCEPTION( varS, "variable", "S" );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varRow, is_independent );
ncMap.enable_var_par_access( varCol, is_independent );
ncMap.enable_var_par_access( varS, is_independent );
#endif
}
else
{
#ifdef MOAB_HAVE_PNETCDF
// read the file using pnetcdf directly, in parallel; need to have MPI, we do not check that anymore
// why build wth pnetcdf without MPI ?
// ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strSource, NcFile::ReadOnly, NcFile::Netcdf4 );
ret = ncmpi_open( m_pcomm->comm(), strSource, NC_NOWRITE, MPI_INFO_NULL, &ncfile );
ERR_PARNC( ret ); // bail out completely
ret = ncmpi_inq( ncfile, &ndims, &nvars, &ngatts, &unlimited );
ERR_PARNC( ret );
// find dimension ids for n_S
int ins;
ret = ncmpi_inq_dimid( ncfile, "n_s", &ins );
ERR_PARNC( ret );
MPI_Offset leng;
ret = ncmpi_inq_dimlen( ncfile, ins, &leng );
ERR_PARNC( ret );
nS = (int)leng;
ret = ncmpi_inq_dimid( ncfile, "n_b", &ins );
ERR_PARNC( ret );
ret = ncmpi_inq_dimlen( ncfile, ins, &leng );
ERR_PARNC( ret );
nB = (int)leng;
#else
_EXCEPTION1( "cannot read the file %s", strSource );
#endif
}
// Let us declare the map object for every process
SparseMatrix< double >& sparseMatrix = this->GetSparseMatrix();
int localSize = nS / size;
long offsetRead = rank * localSize;
// leftovers on last rank
if( rank == size - 1 )
{
localSize += nS % size;
}
std::vector< int > vecRow, vecCol;
std::vector< double > vecS;
vecRow.resize( localSize );
vecCol.resize( localSize );
vecS.resize( localSize );
if( ncMap.is_valid() )
{
varRow->set_cur( (long)( offsetRead ) );
varRow->get( &( vecRow[0] ), localSize );
varCol->set_cur( (long)( offsetRead ) );
varCol->get( &( vecCol[0] ), localSize );
varS->set_cur( (long)( offsetRead ) );
varS->get( &( vecS[0] ), localSize );
ncMap.close();
}
else
{
#ifdef MOAB_HAVE_PNETCDF
// fill the local vectors with the variables from pnetcdf file; first inquire, then fill
MPI_Offset start = (MPI_Offset)offsetRead;
MPI_Offset count = (MPI_Offset)localSize;
int varid;
ret = ncmpi_inq_varid( ncfile, "S", &varid );
ERR_PARNC( ret );
ret = ncmpi_get_vara_double_all( ncfile, varid, &start, &count, &vecS[0] );
ERR_PARNC( ret );
ret = ncmpi_inq_varid( ncfile, "row", &varid );
ERR_PARNC( ret );
ret = ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecRow[0] );
ERR_PARNC( ret );
ret = ncmpi_inq_varid( ncfile, "col", &varid );
ERR_PARNC( ret );
ret = ncmpi_get_vara_int_all( ncfile, varid, &start, &count, &vecCol[0] );
ERR_PARNC( ret );
ret = ncmpi_close( ncfile );
ERR_PARNC( ret );
#endif
}
// Now let us set the necessary global-to-local ID maps so that A*x operations
// can be performed cleanly as if map was computed online
row_dtoc_dofmap.clear();
// row_dtoc_dofmap.reserve( nB / size );
col_dtoc_dofmap.clear();
rowMap.clear();
colMap.clear();
// col_dtoc_dofmap.reserve( 2 * nA / size );
// row_dtoc_dofmap.resize( m_nTotDofs_Dest, UINT_MAX );
// col_dtoc_dofmap.resize( m_nTotDofs_SrcCov, UINT_MAX );
#ifdef MOAB_HAVE_MPI
// bother with tuple list only if size > 1
// otherwise, just fill the sparse matrix
if( size > 1 )
{
std::vector< int > ownership;
// the default trivial partitioning scheme
int nDofs = nB; // this is for row partitioning
if( !row_partition ) nDofs = nA; // column partitioning
// assert(row_major_ownership == true); // this block is valid only for row-based partitioning
ownership.resize( size );
int nPerPart = nDofs / size;
int nRemainder = nDofs % size; // Keep the remainder in root
ownership[0] = nPerPart + nRemainder;
for( int ip = 1, roffset = ownership[0]; ip < size; ++ip )
{
roffset += nPerPart;
ownership[ip] = roffset;
}
moab::TupleList* tl = new moab::TupleList;
unsigned numr = 1; //
tl->initialize( 3, 0, 0, numr, localSize ); // to proc, row, col, value
tl->enableWriteAccess();
// populate
for( int i = 0; i < localSize; i++ )
{
int rowval = vecRow[i] - 1; // dofs are 1 based in the file
int colval = vecCol[i] - 1;
int to_proc = -1;
int dof_val = colval;
if( row_partition ) dof_val = rowval;
if( ownership[0] > dof_val )
to_proc = 0;
else
{
for( int ip = 1; ip < size; ++ip )
{
if( ownership[ip - 1] <= dof_val && ownership[ip] > dof_val )
{
to_proc = ip;
break;
}
}
}
int n = tl->get_n();
tl->vi_wr[3 * n] = to_proc;
tl->vi_wr[3 * n + 1] = rowval;
tl->vi_wr[3 * n + 2] = colval;
tl->vr_wr[n] = vecS[i];
tl->inc_n();
}
// heavy communication
( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl, 0 );
if( owned_dof_ids.size() > 0 )
{
// we need to send desired dof to the rendez_vous point
moab::TupleList tl_re; //
tl_re.initialize( 2, 0, 0, 0, owned_dof_ids.size() ); // to proc, value
tl_re.enableWriteAccess();
// send first to rendez_vous point, decided by trivial partitioning
for( size_t i = 0; i < owned_dof_ids.size(); i++ )
{
int to_proc = -1;
int dof_val = owned_dof_ids[i] - 1; // dofs are 1 based in the file, partition from 0 ?
if( ownership[0] > dof_val )
to_proc = 0;
else
{
for( int ip = 1; ip < size; ++ip )
{
if( ownership[ip - 1] <= dof_val && ownership[ip] > dof_val )
{
to_proc = ip;
break;
}
}
}
int n = tl_re.get_n();
tl_re.vi_wr[2 * n] = to_proc;
tl_re.vi_wr[2 * n + 1] = dof_val;
tl_re.inc_n();
}
( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tl_re, 0 );
// now we know in tl_re where do we need to send back dof_val
moab::TupleList::buffer sort_buffer;
sort_buffer.buffer_init( tl_re.get_n() );
tl_re.sort( 1, &sort_buffer ); // so now we order by value
sort_buffer.buffer_init( tl->get_n() );
int indexOrder = 2; // colVal
if( row_partition ) indexOrder = 1; // rowVal
//tl->sort( indexOrder, &sort_buffer );
std::map< int, int > startDofIndex, endDofIndex; // indices in tl_re for values we want
int dofVal = -1;
if( tl_re.get_n() > 0 ) dofVal = tl_re.vi_rd[1]; // first dof val on this rank
startDofIndex[dofVal] = 0;
endDofIndex[dofVal] = 0; // start and end
for( unsigned k = 1; k < tl_re.get_n(); k++ )
{
int newDof = tl_re.vi_rd[2 * k + 1];
if( dofVal == newDof )
{
endDofIndex[dofVal] = k; // increment by 1 actually
}
else
{
dofVal = newDof;
startDofIndex[dofVal] = k;
endDofIndex[dofVal] = k;
}
}
// basically, for each value we are interested in, index in tl_re with those values are
// tl_re.vi_rd[2*startDofIndex+1] == valDof == tl_re.vi_rd[2*endDofIndex+1]
// so now we have ordered
// tl_re shows to what proc do we need to send the tuple (row, col, val)
moab::TupleList* tl_back = new moab::TupleList;
unsigned numr = 1; //
// localSize is a good guess, but maybe it should be bigger ?
// this could be bigger for repeated dofs
tl_back->initialize( 3, 0, 0, numr, tl->get_n() ); // to proc, row, col, value
tl_back->enableWriteAccess();
// now loop over tl and tl_re to see where to send
// form the new tuple, which will contain the desired dofs per task, per row or column distribution
for( unsigned k = 0; k < tl->get_n(); k++ )
{
int valDof = tl->vi_rd[3 * k + indexOrder]; // 1 for row, 2 for column // first value, it should be
for( int ire = startDofIndex[valDof]; ire <= endDofIndex[valDof]; ire++ )
{
int to_proc = tl_re.vi_rd[2 * ire];
int n = tl_back->get_n();
tl_back->vi_wr[3 * n] = to_proc;
tl_back->vi_wr[3 * n + 1] = tl->vi_rd[3 * k + 1]; // row
tl_back->vi_wr[3 * n + 2] = tl->vi_rd[3 * k + 2]; // col
tl_back->vr_wr[n] = tl->vr_rd[k];
tl_back->inc_n();
}
}
// now communicate to the desired tasks:
( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, *tl_back, 0 );
tl_re.reset(); // clear memory, although this will go out of scope
tl->reset();
tl = tl_back;
}
int rindexMax = 0, cindexMax = 0;
// populate the sparsematrix, using rowMap and colMap
int n = tl->get_n();
for( int i = 0; i < n; i++ )
{
int rindex, cindex;
const int& vecRowValue = tl->vi_wr[3 * i + 1];
const int& vecColValue = tl->vi_wr[3 * i + 2];
std::map< int, int >::iterator riter = rowMap.find( vecRowValue );
if( riter == rowMap.end() )
{
rowMap[vecRowValue] = rindexMax;
rindex = rindexMax;
row_gdofmap.push_back( vecRowValue );
// row_dtoc_dofmap.push_back( vecRowValue );
rindexMax++;
}
else
rindex = riter->second;
std::map< int, int >::iterator citer = colMap.find( vecColValue );
if( citer == colMap.end() )
{
colMap[vecColValue] = cindexMax;
cindex = cindexMax;
col_gdofmap.push_back( vecColValue );
// col_dtoc_dofmap.push_back( vecColValue );
cindexMax++;
}
else
cindex = citer->second;
sparseMatrix( rindex, cindex ) = tl->vr_wr[i];
}
tl->reset();
}
else
#endif
{
int rindexMax = 0, cindexMax = 0;
for( int i = 0; i < nS; i++ )
{
int rindex, cindex;
const int& vecRowValue = vecRow[i] - 1; // the rows, cols are 1 based in the file
const int& vecColValue = vecCol[i] - 1;
std::map< int, int >::iterator riter = rowMap.find( vecRowValue );
if( riter == rowMap.end() )
{
rowMap[vecRowValue] = rindexMax;
rindex = rindexMax;
row_gdofmap.push_back( vecRowValue );
// row_dtoc_dofmap.push_back( vecRowValue );
rindexMax++;
}
else
rindex = riter->second;
std::map< int, int >::iterator citer = colMap.find( vecColValue );
if( citer == colMap.end() )
{
colMap[vecColValue] = cindexMax;
cindex = cindexMax;
col_gdofmap.push_back( vecColValue );
// col_dtoc_dofmap.push_back( vecColValue );
cindexMax++;
}
else
cindex = citer->second;
sparseMatrix( rindex, cindex ) = vecS[i];
}
}
m_nTotDofs_SrcCov = sparseMatrix.GetColumns();
m_nTotDofs_Dest = sparseMatrix.GetRows();
#ifdef MOAB_HAVE_EIGEN3
this->copy_tempest_sparsemat_to_eigen3();
#endif
// Reset the source and target data first
m_rowVector.setZero();
m_colVector.setZero();
return moab::MB_SUCCESS;
}
moab::ErrorCode moab::TempestOnlineMap::set_col_dc_dofs | ( | std::vector< int > & | values_entities | ) |
Definition at line 687 of file TempestOnlineMap.cpp.
References MB_SUCCESS.
{
// col_gdofmap has global dofs , that should be in the list of values, such that
// row_dtoc_dofmap[offsetDOF] = localDOF;
// // we need to find col_dtoc_dofmap such that: col_gdofmap[ col_dtoc_dofmap[i] ] == values_entities [i];
// we know that col_gdofmap[0..(nbcols-1)] = global_col_dofs -> in values_entities
// form first inverse
col_dtoc_dofmap.resize( values_entities.size() );
for( int j = 0; j < (int)values_entities.size(); j++ )
{
if( colMap.find( values_entities[j] - 1 ) != colMap.end() )
col_dtoc_dofmap[j] = colMap[values_entities[j] - 1];
else
{
col_dtoc_dofmap[j] = -1; // signal that this value should not be used in
// std::cout <<"values_entities[j] - 1: " << values_entities[j] - 1 <<" at index j = " << j << " not
// found in colMap \n";
}
}
return moab::MB_SUCCESS;
}
moab::ErrorCode moab::TempestOnlineMap::set_row_dc_dofs | ( | std::vector< int > & | values_entities | ) |
Definition at line 710 of file TempestOnlineMap.cpp.
References MB_SUCCESS.
{
// row_dtoc_dofmap = values_entities; // needs to point to local
// we need to find row_dtoc_dofmap such that: row_gdofmap[ row_dtoc_dofmap[i] ] == values_entities [i];
row_dtoc_dofmap.resize( values_entities.size() );
for( int j = 0; j < (int)values_entities.size(); j++ )
{
if( rowMap.find( values_entities[j] - 1 ) != rowMap.end() )
row_dtoc_dofmap[j] = rowMap[values_entities[j] - 1]; // values are 1 based, but rowMap, colMap are not
else
{
row_dtoc_dofmap[j] = -1; // not all values are used
// std::cout <<"values_entities[j] - 1: " << values_entities[j] - 1 <<" at index j = " << j << " not
// found in rowMap \n";
}
}
return moab::MB_SUCCESS;
}
void moab::TempestOnlineMap::SetDestinationNDofsPerElement | ( | int | nt | ) | [inline] |
Get the number of Degrees-Of-Freedom per element on the destination mesh.
Definition at line 509 of file TempestOnlineMap.hpp.
{
m_nDofsPEl_Dest = nt;
}
moab::ErrorCode moab::TempestOnlineMap::SetDOFmapAssociation | ( | DiscretizationType | srcType, |
bool | isSrcContinuous, | ||
DataArray3D< int > * | srcdataGLLNodes, | ||
DataArray3D< int > * | srcdataGLLNodesSrc, | ||
DiscretizationType | destType, | ||
bool | isDestContinuous, | ||
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.
Definition at line 214 of file TempestOnlineMap.cpp.
References ErrorCode, MB_CHK_ERR, and MB_SUCCESS.
{
moab::ErrorCode rval;
std::vector< bool > dgll_cgll_row_ldofmap, dgll_cgll_col_ldofmap, dgll_cgll_covcol_ldofmap;
std::vector< int > src_soln_gdofs, locsrc_soln_gdofs, tgt_soln_gdofs;
// We are assuming that these are element based tags that are sized: np * np
m_srcDiscType = srcType;
m_destDiscType = destType;
bool vprint = is_root && false;
#ifdef VVERBOSE
{
src_soln_gdofs.resize( m_remapper->m_covering_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, -1 );
rval = m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_entities, &src_soln_gdofs[0] );MB_CHK_ERR( rval );
locsrc_soln_gdofs.resize( m_remapper->m_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src );
rval = m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_entities, &locsrc_soln_gdofs[0] );MB_CHK_ERR( rval );
tgt_soln_gdofs.resize( m_remapper->m_target_entities.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest );
rval = m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_entities, &tgt_soln_gdofs[0] );MB_CHK_ERR( rval );
if( is_root )
{
{
std::ofstream output_file( "sourcecov-gids-0.txt" );
output_file << "I, GDOF\n";
for( unsigned i = 0; i < src_soln_gdofs.size(); ++i )
output_file << i << ", " << src_soln_gdofs[i] << "\n";
output_file << "ELEMID, IDOF, LDOF, GDOF, NDOF\n";
m_nTotDofs_SrcCov = 0;
if( isSrcContinuous )
dgll_cgll_covcol_ldofmap.resize(
m_remapper->m_covering_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, false );
for( unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
{
for( int p = 0; p < m_nDofsPEl_Src; p++ )
{
for( int q = 0; q < m_nDofsPEl_Src; q++ )
{
const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
const int offsetDOF = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
{
m_nTotDofs_SrcCov++;
dgll_cgll_covcol_ldofmap[localDOF] = true;
}
output_file << m_remapper->lid_to_gid_covsrc[j] << ", " << offsetDOF << ", " << localDOF
<< ", " << src_soln_gdofs[offsetDOF] << ", " << m_nTotDofs_SrcCov << "\n";
}
}
}
output_file.flush(); // required here
output_file.close();
dgll_cgll_covcol_ldofmap.clear();
}
{
std::ofstream output_file( "source-gids-0.txt" );
output_file << "I, GDOF\n";
for( unsigned i = 0; i < locsrc_soln_gdofs.size(); ++i )
output_file << i << ", " << locsrc_soln_gdofs[i] << "\n";
output_file << "ELEMID, IDOF, LDOF, GDOF, NDOF\n";
m_nTotDofs_Src = 0;
if( isSrcContinuous )
dgll_cgll_col_ldofmap.resize(
m_remapper->m_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, false );
for( unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
{
for( int p = 0; p < m_nDofsPEl_Src; p++ )
{
for( int q = 0; q < m_nDofsPEl_Src; q++ )
{
const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
const int offsetDOF = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
{
m_nTotDofs_Src++;
dgll_cgll_col_ldofmap[localDOF] = true;
}
output_file << m_remapper->lid_to_gid_src[j] << ", " << offsetDOF << ", " << localDOF
<< ", " << locsrc_soln_gdofs[offsetDOF] << ", " << m_nTotDofs_Src << "\n";
}
}
}
output_file.flush(); // required here
output_file.close();
dgll_cgll_col_ldofmap.clear();
}
{
std::ofstream output_file( "target-gids-0.txt" );
output_file << "I, GDOF\n";
for( unsigned i = 0; i < tgt_soln_gdofs.size(); ++i )
output_file << i << ", " << tgt_soln_gdofs[i] << "\n";
output_file << "ELEMID, IDOF, GDOF, NDOF\n";
m_nTotDofs_Dest = 0;
for( unsigned i = 0; i < tgt_soln_gdofs.size(); ++i )
{
output_file << m_remapper->lid_to_gid_tgt[i] << ", " << i << ", " << tgt_soln_gdofs[i] << ", "
<< m_nTotDofs_Dest << "\n";
m_nTotDofs_Dest++;
}
output_file.flush(); // required here
output_file.close();
}
}
else
{
{
std::ofstream output_file( "sourcecov-gids-1.txt" );
output_file << "I, GDOF\n";
for( unsigned i = 0; i < src_soln_gdofs.size(); ++i )
output_file << i << ", " << src_soln_gdofs[i] << "\n";
output_file << "ELEMID, IDOF, LDOF, GDOF, NDOF\n";
m_nTotDofs_SrcCov = 0;
if( isSrcContinuous )
dgll_cgll_covcol_ldofmap.resize(
m_remapper->m_covering_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, false );
for( unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
{
for( int p = 0; p < m_nDofsPEl_Src; p++ )
{
for( int q = 0; q < m_nDofsPEl_Src; q++ )
{
const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
const int offsetDOF = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
{
m_nTotDofs_SrcCov++;
dgll_cgll_covcol_ldofmap[localDOF] = true;
}
output_file << m_remapper->lid_to_gid_covsrc[j] << ", " << offsetDOF << ", " << localDOF
<< ", " << src_soln_gdofs[offsetDOF] << ", " << m_nTotDofs_SrcCov << "\n";
}
}
}
output_file.flush(); // required here
output_file.close();
dgll_cgll_covcol_ldofmap.clear();
}
{
std::ofstream output_file( "source-gids-1.txt" );
output_file << "I, GDOF\n";
for( unsigned i = 0; i < locsrc_soln_gdofs.size(); ++i )
output_file << i << ", " << locsrc_soln_gdofs[i] << "\n";
output_file << "ELEMID, IDOF, LDOF, GDOF, NDOF\n";
m_nTotDofs_Src = 0;
if( isSrcContinuous )
dgll_cgll_col_ldofmap.resize(
m_remapper->m_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, false );
for( unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
{
for( int p = 0; p < m_nDofsPEl_Src; p++ )
{
for( int q = 0; q < m_nDofsPEl_Src; q++ )
{
const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
const int offsetDOF = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
{
m_nTotDofs_Src++;
dgll_cgll_col_ldofmap[localDOF] = true;
}
output_file << m_remapper->lid_to_gid_src[j] << ", " << offsetDOF << ", " << localDOF
<< ", " << locsrc_soln_gdofs[offsetDOF] << ", " << m_nTotDofs_Src << "\n";
}
}
}
output_file.flush(); // required here
output_file.close();
dgll_cgll_col_ldofmap.clear();
}
{
std::ofstream output_file( "target-gids-1.txt" );
output_file << "I, GDOF\n";
for( unsigned i = 0; i < tgt_soln_gdofs.size(); ++i )
output_file << i << ", " << tgt_soln_gdofs[i] << "\n";
output_file << "ELEMID, IDOF, GDOF, NDOF\n";
m_nTotDofs_Dest = 0;
for( unsigned i = 0; i < tgt_soln_gdofs.size(); ++i )
{
output_file << m_remapper->lid_to_gid_tgt[i] << ", " << i << ", " << tgt_soln_gdofs[i] << ", "
<< m_nTotDofs_Dest << "\n";
m_nTotDofs_Dest++;
}
output_file.flush(); // required here
output_file.close();
}
}
}
#endif
// Now compute the mapping and store it for the covering mesh
int srcTagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
if( m_remapper->point_cloud_source )
{
assert( m_nDofsPEl_Src == 1 );
col_gdofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
col_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
src_soln_gdofs.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
rval = m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_vertices, &src_soln_gdofs[0] );MB_CHK_ERR( rval );
srcTagSize = 1;
}
else
{
col_gdofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
col_dtoc_dofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
src_soln_gdofs.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, UINT_MAX );
rval = m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_covering_source_entities, &src_soln_gdofs[0] );MB_CHK_ERR( rval );
}
// std::cout << "TOnlineMap: Process: " << rank << " and covering entities = [" <<
// col_dofmap.size() << ", " << src_soln_gdofs.size() << "]\n"; MPI_Barrier(MPI_COMM_WORLD);
#ifdef ALTERNATE_NUMBERING_IMPLEMENTATION
unsigned maxSrcIndx = 0;
// for ( unsigned j = 0; j < m_covering_source_entities.size(); j++ )
std::vector< int > locdofs( srcTagSize );
std::map< Node, moab::EntityHandle > mapLocalMBNodes;
double elcoords[3];
for( unsigned iel = 0; iel < m_remapper->m_covering_source_entities.size(); ++iel )
{
EntityHandle eh = m_remapper->m_covering_source_entities[iel];
rval = m_interface->get_coords( &eh, 1, elcoords );MB_CHK_ERR( rval );
Node elCentroid( elcoords[0], elcoords[1], elcoords[2] );
mapLocalMBNodes.insert( std::pair< Node, moab::EntityHandle >( elCentroid, eh ) );
}
const NodeVector& nodes = m_remapper->m_covering_source->nodes;
for( unsigned j = 0; j < m_remapper->m_covering_source->faces.size(); j++ )
{
const Face& face = m_remapper->m_covering_source->faces[j];
Node centroid;
centroid.x = centroid.y = centroid.z = 0.0;
for( unsigned l = 0; l < face.edges.size(); ++l )
{
centroid.x += nodes[face[l]].x;
centroid.y += nodes[face[l]].y;
centroid.z += nodes[face[l]].z;
}
const double factor = 1.0 / face.edges.size();
centroid.x *= factor;
centroid.y *= factor;
centroid.z *= factor;
EntityHandle current_eh;
if( mapLocalMBNodes.find( centroid ) != mapLocalMBNodes.end() )
{
current_eh = mapLocalMBNodes[centroid];
}
rval = m_interface->tag_get_data( m_dofTagSrc, ¤t_eh, 1, &locdofs[0] );MB_CHK_ERR( rval );
for( int p = 0; p < m_nDofsPEl_Src; p++ )
{
for( int q = 0; q < m_nDofsPEl_Src; q++ )
{
const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
const int offsetDOF = p * m_nDofsPEl_Src + q;
maxSrcIndx = ( localDOF > maxSrcIndx ? localDOF : maxSrcIndx );
std::cout << "Col: " << current_eh << ", " << m_remapper->lid_to_gid_covsrc[j] << ", " << offsetDOF
<< ", " << localDOF << ", " << locdofs[offsetDOF] - 1 << ", " << maxSrcIndx << "\n";
}
}
}
#endif
m_nTotDofs_SrcCov = 0;
if( srcdataGLLNodes == NULL )
{ /* we only have a mapping for elements as DoFs */
for( unsigned i = 0; i < col_gdofmap.size(); ++i )
{
assert( src_soln_gdofs[i] > 0 );
col_gdofmap[i] = src_soln_gdofs[i] - 1;
col_dtoc_dofmap[i] = i;
if( vprint ) std::cout << "Col: " << i << ", " << col_gdofmap[i] << "\n";
m_nTotDofs_SrcCov++;
}
}
else
{
if( isSrcContinuous )
dgll_cgll_covcol_ldofmap.resize( m_remapper->m_covering_source_entities.size() * srcTagSize, false );
// Put these remap coefficients into the SparseMatrix map
for( unsigned j = 0; j < m_remapper->m_covering_source_entities.size(); j++ )
{
for( int p = 0; p < m_nDofsPEl_Src; p++ )
{
for( int q = 0; q < m_nDofsPEl_Src; q++ )
{
const int localDOF = ( *srcdataGLLNodes )[p][q][j] - 1;
const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
if( isSrcContinuous && !dgll_cgll_covcol_ldofmap[localDOF] )
{
m_nTotDofs_SrcCov++;
dgll_cgll_covcol_ldofmap[localDOF] = true;
}
if( !isSrcContinuous ) m_nTotDofs_SrcCov++;
assert( src_soln_gdofs[offsetDOF] > 0 );
col_gdofmap[localDOF] = src_soln_gdofs[offsetDOF] - 1;
col_dtoc_dofmap[offsetDOF] = localDOF;
if( vprint )
std::cout << "Col: " << m_remapper->lid_to_gid_covsrc[j] << ", " << offsetDOF << ", "
<< localDOF << ", " << col_gdofmap[offsetDOF] << ", " << m_nTotDofs_SrcCov << "\n";
}
}
}
}
if( m_remapper->point_cloud_source )
{
assert( m_nDofsPEl_Src == 1 );
srccol_gdofmap.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
srccol_dtoc_dofmap.resize( m_remapper->m_covering_source_vertices.size(), UINT_MAX );
locsrc_soln_gdofs.resize( m_remapper->m_source_vertices.size(), UINT_MAX );
rval = m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_vertices, &locsrc_soln_gdofs[0] );MB_CHK_ERR( rval );
}
else
{
srccol_gdofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
srccol_dtoc_dofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
locsrc_soln_gdofs.resize( m_remapper->m_source_entities.size() * srcTagSize, UINT_MAX );
rval = m_interface->tag_get_data( m_dofTagSrc, m_remapper->m_source_entities, &locsrc_soln_gdofs[0] );MB_CHK_ERR( rval );
}
// Now compute the mapping and store it for the original source mesh
m_nTotDofs_Src = 0;
if( srcdataGLLNodesSrc == NULL )
{ /* we only have a mapping for elements as DoFs */
for( unsigned i = 0; i < srccol_gdofmap.size(); ++i )
{
assert( locsrc_soln_gdofs[i] > 0 );
srccol_gdofmap[i] = locsrc_soln_gdofs[i] - 1;
srccol_dtoc_dofmap[i] = i;
m_nTotDofs_Src++;
}
}
else
{
if( isSrcContinuous ) dgll_cgll_col_ldofmap.resize( m_remapper->m_source_entities.size() * srcTagSize, false );
// Put these remap coefficients into the SparseMatrix map
for( unsigned j = 0; j < m_remapper->m_source_entities.size(); j++ )
{
for( int p = 0; p < m_nDofsPEl_Src; p++ )
{
for( int q = 0; q < m_nDofsPEl_Src; q++ )
{
const int localDOF = ( *srcdataGLLNodesSrc )[p][q][j] - 1;
const int offsetDOF = j * srcTagSize + p * m_nDofsPEl_Src + q;
if( isSrcContinuous && !dgll_cgll_col_ldofmap[localDOF] )
{
m_nTotDofs_Src++;
dgll_cgll_col_ldofmap[localDOF] = true;
}
if( !isSrcContinuous ) m_nTotDofs_Src++;
assert( locsrc_soln_gdofs[offsetDOF] > 0 );
srccol_gdofmap[localDOF] = locsrc_soln_gdofs[offsetDOF] - 1;
srccol_dtoc_dofmap[offsetDOF] = localDOF;
}
}
}
}
int tgtTagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
if( m_remapper->point_cloud_target )
{
assert( m_nDofsPEl_Dest == 1 );
row_gdofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
row_dtoc_dofmap.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
tgt_soln_gdofs.resize( m_remapper->m_target_vertices.size(), UINT_MAX );
rval = m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_vertices, &tgt_soln_gdofs[0] );MB_CHK_ERR( rval );
tgtTagSize = 1;
}
else
{
row_gdofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
row_dtoc_dofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
tgt_soln_gdofs.resize( m_remapper->m_target_entities.size() * tgtTagSize, UINT_MAX );
rval = m_interface->tag_get_data( m_dofTagDest, m_remapper->m_target_entities, &tgt_soln_gdofs[0] );MB_CHK_ERR( rval );
}
// Now compute the mapping and store it for the target mesh
// To access the GID for each row: row_gdofmap [ row_ldofmap [ 0 : local_ndofs ] ] = GDOF
m_nTotDofs_Dest = 0;
if( tgtdataGLLNodes == NULL )
{ /* we only have a mapping for elements as DoFs */
for( unsigned i = 0; i < row_gdofmap.size(); ++i )
{
assert( tgt_soln_gdofs[i] > 0 );
row_gdofmap[i] = tgt_soln_gdofs[i] - 1;
row_dtoc_dofmap[i] = i;
if( vprint ) std::cout << "Row: " << i << ", " << row_gdofmap[i] << "\n";
m_nTotDofs_Dest++;
}
}
else
{
if( isTgtContinuous ) dgll_cgll_row_ldofmap.resize( m_remapper->m_target_entities.size() * tgtTagSize, false );
// Put these remap coefficients into the SparseMatrix map
for( unsigned j = 0; j < m_remapper->m_target_entities.size(); j++ )
{
for( int p = 0; p < m_nDofsPEl_Dest; p++ )
{
for( int q = 0; q < m_nDofsPEl_Dest; q++ )
{
const int localDOF = ( *tgtdataGLLNodes )[p][q][j] - 1;
const int offsetDOF = j * tgtTagSize + p * m_nDofsPEl_Dest + q;
if( isTgtContinuous && !dgll_cgll_row_ldofmap[localDOF] )
{
m_nTotDofs_Dest++;
dgll_cgll_row_ldofmap[localDOF] = true;
}
if( !isTgtContinuous ) m_nTotDofs_Dest++;
assert( tgt_soln_gdofs[offsetDOF] > 0 );
row_gdofmap[localDOF] = tgt_soln_gdofs[offsetDOF] - 1;
row_dtoc_dofmap[offsetDOF] = localDOF;
if( vprint )
std::cout << "Row: " << m_remapper->lid_to_gid_tgt[j] << ", " << offsetDOF << ", " << localDOF
<< ", " << row_gdofmap[offsetDOF] << ", " << m_nTotDofs_Dest << "\n";
}
}
}
}
// Let us also allocate the local representation of the sparse matrix
#if defined( MOAB_HAVE_EIGEN3 ) && defined( VERBOSE )
if( vprint )
{
std::cout << "[" << rank << "]"
<< "DoFs: row = " << m_nTotDofs_Dest << ", " << row_gdofmap.size() << ", col = " << m_nTotDofs_Src
<< ", " << m_nTotDofs_SrcCov << ", " << col_gdofmap.size() << "\n";
// std::cout << "Max col_dofmap: " << maxcol << ", Min col_dofmap" << mincol << "\n";
}
#endif
// check monotonicity of row_gdofmap and col_gdofmap
#ifdef CHECK_INCREASING_DOF
for( size_t i = 0; i < row_gdofmap.size() - 1; i++ )
{
if( row_gdofmap[i] > row_gdofmap[i + 1] )
std::cout << " on rank " << rank << " in row_gdofmap[" << i << "]=" << row_gdofmap[i] << " > row_gdofmap["
<< i + 1 << "]=" << row_gdofmap[i + 1] << " \n";
}
for( size_t i = 0; i < col_gdofmap.size() - 1; i++ )
{
if( col_gdofmap[i] > col_gdofmap[i + 1] )
std::cout << " on rank " << rank << " in col_gdofmap[" << i << "]=" << col_gdofmap[i] << " > col_gdofmap["
<< i + 1 << "]=" << col_gdofmap[i + 1] << " \n";
}
#endif
return moab::MB_SUCCESS;
}
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.
Definition at line 158 of file TempestOnlineMap.cpp.
References ErrorCode, MB_CHK_ERR, MB_CHK_SET_ERR, MB_SUCCESS, MB_TAG_ANY, MB_TAG_NOT_FOUND, and MB_TYPE_INTEGER.
{
moab::ErrorCode rval;
int tagSize = 0;
tagSize = ( m_eInputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Src * m_nDofsPEl_Src );
rval =
m_interface->tag_get_handle( srcDofTagName.c_str(), tagSize, MB_TYPE_INTEGER, this->m_dofTagSrc, MB_TAG_ANY );
if( rval == moab::MB_TAG_NOT_FOUND && m_eInputType != DiscretizationType_FV )
{
int ntot_elements = 0, nelements = m_remapper->m_source_entities.size();
#ifdef MOAB_HAVE_MPI
int ierr = MPI_Allreduce( &nelements, &ntot_elements, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
if( ierr != 0 ) MB_CHK_SET_ERR( MB_FAILURE, "MPI_Allreduce failed to get total source elements" );
#else
ntot_elements = nelements;
#endif
rval = m_remapper->GenerateCSMeshMetadata( ntot_elements, m_remapper->m_covering_source_entities,
&m_remapper->m_source_entities, srcDofTagName, m_nDofsPEl_Src );MB_CHK_ERR( rval );
rval = m_interface->tag_get_handle( srcDofTagName.c_str(), m_nDofsPEl_Src * m_nDofsPEl_Src, MB_TYPE_INTEGER,
this->m_dofTagSrc, MB_TAG_ANY );MB_CHK_ERR( rval );
}
else
MB_CHK_ERR( rval );
tagSize = ( m_eOutputType == DiscretizationType_FV ? 1 : m_nDofsPEl_Dest * m_nDofsPEl_Dest );
rval =
m_interface->tag_get_handle( tgtDofTagName.c_str(), tagSize, MB_TYPE_INTEGER, this->m_dofTagDest, MB_TAG_ANY );
if( rval == moab::MB_TAG_NOT_FOUND && m_eOutputType != DiscretizationType_FV )
{
int ntot_elements = 0, nelements = m_remapper->m_target_entities.size();
#ifdef MOAB_HAVE_MPI
int ierr = MPI_Allreduce( &nelements, &ntot_elements, 1, MPI_INT, MPI_SUM, m_pcomm->comm() );
if( ierr != 0 ) MB_CHK_SET_ERR( MB_FAILURE, "MPI_Allreduce failed to get total source elements" );
#else
ntot_elements = nelements;
#endif
rval = m_remapper->GenerateCSMeshMetadata( ntot_elements, m_remapper->m_target_entities, NULL, tgtDofTagName,
m_nDofsPEl_Dest );MB_CHK_ERR( rval );
rval = m_interface->tag_get_handle( tgtDofTagName.c_str(), m_nDofsPEl_Dest * m_nDofsPEl_Dest, MB_TYPE_INTEGER,
this->m_dofTagDest, MB_TAG_ANY );MB_CHK_ERR( rval );
}
else
MB_CHK_ERR( rval );
return moab::MB_SUCCESS;
}
void moab::TempestOnlineMap::SetSourceNDofsPerElement | ( | int | ns | ) | [inline] |
Set the number of Degrees-Of-Freedom per element on the source mesh.
Definition at line 504 of file TempestOnlineMap.hpp.
{
m_nDofsPEl_Src = ns;
}
void moab::TempestOnlineMap::setup_sizes_dimensions | ( | ) | [private] |
Definition at line 98 of file TempestOnlineMap.cpp.
References moab::TempestRemapper::RLL.
Referenced by TempestOnlineMap().
{
if( m_meshInputCov )
{
std::vector< std::string > dimNames;
std::vector< int > dimSizes;
if( m_remapper->m_source_type == moab::TempestRemapper::RLL && m_remapper->m_source_metadata.size() )
{
dimNames.push_back( "lat" );
dimNames.push_back( "lon" );
dimSizes.resize( 2, 0 );
dimSizes[0] = m_remapper->m_source_metadata[1];
dimSizes[1] = m_remapper->m_source_metadata[2];
}
else
{
dimNames.push_back( "num_elem" );
dimSizes.push_back( m_meshInputCov->faces.size() );
}
this->InitializeSourceDimensions( dimNames, dimSizes );
}
if( m_meshOutput )
{
std::vector< std::string > dimNames;
std::vector< int > dimSizes;
if( m_remapper->m_target_type == moab::TempestRemapper::RLL && m_remapper->m_target_metadata.size() )
{
dimNames.push_back( "lat" );
dimNames.push_back( "lon" );
dimSizes.resize( 2, 0 );
dimSizes[0] = m_remapper->m_target_metadata[1];
dimSizes[1] = m_remapper->m_target_metadata[2];
}
else
{
dimNames.push_back( "num_elem" );
dimSizes.push_back( m_meshOutput->faces.size() );
}
this->InitializeTargetDimensions( dimNames, dimSizes );
}
}
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 776 of file TempestOnlineMapIO.cpp.
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, root_set, size, and t.
{
moab::ErrorCode rval;
/**
* 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.
**/
/* Let us compute all relevant data for the current original source mesh on the process */
DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea;
DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat;
DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat;
if( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD )
{
this->InitializeCoordinatesFromMeshFV(
*m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat,
( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ) /* fLatLon = false */,
m_remapper->max_source_edges );
vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() );
for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i )
vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i];
}
else
{
DataArray3D< double > dataGLLJacobianSrc;
this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon,
dSourceCenterLat, dSourceVertexLon, dSourceVertexLat );
// Generate the continuous Jacobian for input mesh
GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc );
if( m_srcDiscType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, m_meshInput->vecFaceArea );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobianSrc, m_meshInput->vecFaceArea );
}
vecSourceFaceArea.Allocate( m_meshInput->faces.size() * m_nDofsPEl_Src * m_nDofsPEl_Src );
int offset = 0;
for( size_t e = 0; e < m_meshInput->faces.size(); e++ )
{
for( int s = 0; s < m_nDofsPEl_Src; s++ )
{
for( int t = 0; t < m_nDofsPEl_Src; t++ )
{
vecSourceFaceArea[srccol_dtoc_dofmap[offset + s * m_nDofsPEl_Src + t]] =
dataGLLJacobianSrc[s][t][e];
}
}
offset += m_nDofsPEl_Src * m_nDofsPEl_Src;
}
}
if( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD )
{
this->InitializeCoordinatesFromMeshFV(
*m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat,
( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ) /* fLatLon = false */,
m_remapper->max_target_edges );
vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() );
for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i )
vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i];
}
else
{
DataArray3D< double > dataGLLJacobianDest;
this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon,
dTargetCenterLat, dTargetVertexLon, dTargetVertexLat );
// Generate the continuous Jacobian for input mesh
GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest );
if( m_destDiscType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, m_meshOutput->vecFaceArea );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobianDest, m_meshOutput->vecFaceArea );
}
vecTargetFaceArea.Allocate( m_meshOutput->faces.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest );
int offset = 0;
for( size_t e = 0; e < m_meshOutput->faces.size(); e++ )
{
for( int s = 0; s < m_nDofsPEl_Dest; s++ )
{
for( int t = 0; t < m_nDofsPEl_Dest; t++ )
{
vecTargetFaceArea[row_dtoc_dofmap[offset + s * m_nDofsPEl_Dest + t]] = dataGLLJacobianDest[s][t][e];
}
}
offset += m_nDofsPEl_Dest * m_nDofsPEl_Dest;
}
}
moab::EntityHandle& m_meshOverlapSet = m_remapper->m_overlap_set;
int tot_src_ents = m_remapper->m_source_entities.size();
int tot_tgt_ents = m_remapper->m_target_entities.size();
int tot_src_size = dSourceCenterLon.GetRows();
int tot_tgt_size = m_dTargetCenterLon.GetRows();
int tot_vsrc_size = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns();
int tot_vtgt_size = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns();
const int weightMatNNZ = m_weightMatrix.nonZeros();
moab::Tag tagMapMetaData, tagMapIndexRow, tagMapIndexCol, tagMapValues, srcEleIDs, tgtEleIDs;
rval = m_interface->tag_get_handle( "SMAT_DATA", 13, moab::MB_TYPE_INTEGER, tagMapMetaData,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "SMAT_ROWS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexRow,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "SMAT_COLS", weightMatNNZ, moab::MB_TYPE_INTEGER, tagMapIndexCol,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "SMAT_VALS", weightMatNNZ, moab::MB_TYPE_DOUBLE, tagMapValues,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "SourceGIDS", tot_src_size, moab::MB_TYPE_INTEGER, srcEleIDs,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "TargetGIDS", tot_tgt_size, moab::MB_TYPE_INTEGER, tgtEleIDs,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
moab::Tag srcAreaValues, tgtAreaValues;
rval = m_interface->tag_get_handle( "SourceAreas", tot_src_size, moab::MB_TYPE_DOUBLE, srcAreaValues,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "TargetAreas", tot_tgt_size, moab::MB_TYPE_DOUBLE, tgtAreaValues,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
moab::Tag tagSrcCoordsCLon, tagSrcCoordsCLat, tagTgtCoordsCLon, tagTgtCoordsCLat;
rval = m_interface->tag_get_handle( "SourceCoordCenterLon", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLon,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "SourceCoordCenterLat", tot_src_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsCLat,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "TargetCoordCenterLon", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLon,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "TargetCoordCenterLat", tot_tgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsCLat,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
moab::Tag tagSrcCoordsVLon, tagSrcCoordsVLat, tagTgtCoordsVLon, tagTgtCoordsVLat;
rval = m_interface->tag_get_handle( "SourceCoordVertexLon", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLon,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "SourceCoordVertexLat", tot_vsrc_size, moab::MB_TYPE_DOUBLE, tagSrcCoordsVLat,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "TargetCoordVertexLon", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLon,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
rval = m_interface->tag_get_handle( "TargetCoordVertexLat", tot_vtgt_size, moab::MB_TYPE_DOUBLE, tagTgtCoordsVLat,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
moab::Tag srcMaskValues, tgtMaskValues;
if( m_iSourceMask.IsAttached() )
{
rval = m_interface->tag_get_handle( "SourceMask", m_iSourceMask.GetRows(), moab::MB_TYPE_INTEGER, srcMaskValues,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
}
if( m_iTargetMask.IsAttached() )
{
rval = m_interface->tag_get_handle( "TargetMask", m_iTargetMask.GetRows(), moab::MB_TYPE_INTEGER, tgtMaskValues,
moab::MB_TAG_CREAT | moab::MB_TAG_SPARSE | moab::MB_TAG_VARLEN );MB_CHK_SET_ERR( rval, "Retrieving tag handles failed" );
}
std::vector< int > smatrowvals( weightMatNNZ ), smatcolvals( weightMatNNZ );
std::vector< double > smatvals( weightMatNNZ );
// const double* smatvals = m_weightMatrix.valuePtr();
// Loop over the matrix entries and find the max global ID for rows and columns
for( int k = 0, offset = 0; k < m_weightMatrix.outerSize(); ++k )
{
for( moab::TempestOnlineMap::WeightMatrix::InnerIterator it( m_weightMatrix, k ); it; ++it, ++offset )
{
smatrowvals[offset] = this->GetRowGlobalDoF( it.row() );
smatcolvals[offset] = this->GetColGlobalDoF( it.col() );
smatvals[offset] = it.value();
}
}
/* Set the global IDs for the DoFs */
////
// col_gdofmap [ col_ldofmap [ 0 : local_ndofs ] ] = GDOF
// row_gdofmap [ row_ldofmap [ 0 : local_ndofs ] ] = GDOF
////
int maxrow = 0, maxcol = 0;
std::vector< int > src_global_dofs( tot_src_size ), tgt_global_dofs( tot_tgt_size );
for( int i = 0; i < tot_src_size; ++i )
{
src_global_dofs[i] = srccol_gdofmap[i];
maxcol = ( src_global_dofs[i] > maxcol ) ? src_global_dofs[i] : maxcol;
}
for( int i = 0; i < tot_tgt_size; ++i )
{
tgt_global_dofs[i] = row_gdofmap[i];
maxrow = ( tgt_global_dofs[i] > maxrow ) ? tgt_global_dofs[i] : maxrow;
}
///////////////////////////////////////////////////////////////////////////
// The metadata in H5M file contains the following data:
//
// 1. n_a: Total source entities: (number of elements in source mesh)
// 2. n_b: Total target entities: (number of elements in target mesh)
// 3. nv_a: Max edge size of elements in source mesh
// 4. nv_b: Max edge size of elements in target mesh
// 5. maxrows: Number of rows in remap weight matrix
// 6. maxcols: Number of cols in remap weight matrix
// 7. nnz: Number of total nnz in sparse remap weight matrix
// 8. np_a: The order of the field description on the source mesh: >= 1
// 9. np_b: The order of the field description on the target mesh: >= 1
// 10. method_a: The type of discretization for field on source mesh: [0 = FV, 1 = cGLL, 2 =
// dGLL]
// 11. method_b: The type of discretization for field on target mesh: [0 = FV, 1 = cGLL, 2 =
// dGLL]
// 12. conserved: Flag to specify whether the remap operator has conservation constraints: [0,
// 1]
// 13. monotonicity: Flags to specify whether the remap operator has monotonicity constraints:
// [0, 1, 2]
//
///////////////////////////////////////////////////////////////////////////
int map_disc_details[6];
map_disc_details[0] = m_nDofsPEl_Src;
map_disc_details[1] = m_nDofsPEl_Dest;
map_disc_details[2] = ( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD
? 0
: ( m_srcDiscType == DiscretizationType_CGLL ? 1 : 2 ) );
map_disc_details[3] = ( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD
? 0
: ( m_destDiscType == DiscretizationType_CGLL ? 1 : 2 ) );
map_disc_details[4] = ( m_bConserved ? 1 : 0 );
map_disc_details[5] = m_iMonotonicity;
#ifdef MOAB_HAVE_MPI
int loc_smatmetadata[13] = {tot_src_ents,
tot_tgt_ents,
m_remapper->max_source_edges,
m_remapper->max_target_edges,
maxrow + 1,
maxcol + 1,
weightMatNNZ,
map_disc_details[0],
map_disc_details[1],
map_disc_details[2],
map_disc_details[3],
map_disc_details[4],
map_disc_details[5]};
rval = m_interface->tag_set_data( tagMapMetaData, &m_meshOverlapSet, 1, &loc_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
int glb_smatmetadata[13] = {0,
0,
0,
0,
0,
0,
0,
map_disc_details[0],
map_disc_details[1],
map_disc_details[2],
map_disc_details[3],
map_disc_details[4],
map_disc_details[5]};
int loc_buf[7] = {
tot_src_ents, tot_tgt_ents, weightMatNNZ, m_remapper->max_source_edges, m_remapper->max_target_edges,
maxrow, maxcol};
int glb_buf[4] = {0, 0, 0, 0};
MPI_Reduce( &loc_buf[0], &glb_buf[0], 3, MPI_INT, MPI_SUM, 0, m_pcomm->comm() );
glb_smatmetadata[0] = glb_buf[0];
glb_smatmetadata[1] = glb_buf[1];
glb_smatmetadata[6] = glb_buf[2];
MPI_Reduce( &loc_buf[3], &glb_buf[0], 4, MPI_INT, MPI_MAX, 0, m_pcomm->comm() );
glb_smatmetadata[2] = glb_buf[0];
glb_smatmetadata[3] = glb_buf[1];
glb_smatmetadata[4] = glb_buf[2];
glb_smatmetadata[5] = glb_buf[3];
#else
int glb_smatmetadata[13] = {tot_src_ents,
tot_tgt_ents,
m_remapper->max_source_edges,
m_remapper->max_target_edges,
maxrow,
maxcol,
weightMatNNZ,
map_disc_details[0],
map_disc_details[1],
map_disc_details[2],
map_disc_details[3],
map_disc_details[4],
map_disc_details[5]};
#endif
// These values represent number of rows and columns. So should be 1-based.
glb_smatmetadata[4]++;
glb_smatmetadata[5]++;
if( this->is_root )
{
std::cout << " " << this->rank << " Writing remap weights with size [" << glb_smatmetadata[4] << " X "
<< glb_smatmetadata[5] << "] and NNZ = " << glb_smatmetadata[6] << std::endl;
EntityHandle root_set = 0;
rval = m_interface->tag_set_data( tagMapMetaData, &root_set, 1, &glb_smatmetadata[0] );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
}
int dsize;
const int numval = weightMatNNZ;
const void* smatrowvals_d = smatrowvals.data();
const void* smatcolvals_d = smatcolvals.data();
const void* smatvals_d = smatvals.data();
rval = m_interface->tag_set_by_ptr( tagMapIndexRow, &m_meshOverlapSet, 1, &smatrowvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
rval = m_interface->tag_set_by_ptr( tagMapIndexCol, &m_meshOverlapSet, 1, &smatcolvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
rval = m_interface->tag_set_by_ptr( tagMapValues, &m_meshOverlapSet, 1, &smatvals_d, &numval );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
/* Set the global IDs for the DoFs */
const void* srceleidvals_d = src_global_dofs.data();
const void* tgteleidvals_d = tgt_global_dofs.data();
dsize = src_global_dofs.size();
rval = m_interface->tag_set_by_ptr( srcEleIDs, &m_meshOverlapSet, 1, &srceleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
dsize = tgt_global_dofs.size();
rval = m_interface->tag_set_by_ptr( tgtEleIDs, &m_meshOverlapSet, 1, &tgteleidvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
/* Set the source and target areas */
const void* srcareavals_d = vecSourceFaceArea;
const void* tgtareavals_d = vecTargetFaceArea;
dsize = tot_src_size;
rval = m_interface->tag_set_by_ptr( srcAreaValues, &m_meshOverlapSet, 1, &srcareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
dsize = tot_tgt_size;
rval = m_interface->tag_set_by_ptr( tgtAreaValues, &m_meshOverlapSet, 1, &tgtareavals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
/* Set the coordinates for source and target center vertices */
const void* srccoordsclonvals_d = &dSourceCenterLon[0];
const void* srccoordsclatvals_d = &dSourceCenterLat[0];
dsize = dSourceCenterLon.GetRows();
rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLon, &m_meshOverlapSet, 1, &srccoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
rval = m_interface->tag_set_by_ptr( tagSrcCoordsCLat, &m_meshOverlapSet, 1, &srccoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
const void* tgtcoordsclonvals_d = &m_dTargetCenterLon[0];
const void* tgtcoordsclatvals_d = &m_dTargetCenterLat[0];
dsize = vecTargetFaceArea.GetRows();
rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLon, &m_meshOverlapSet, 1, &tgtcoordsclonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
rval = m_interface->tag_set_by_ptr( tagTgtCoordsCLat, &m_meshOverlapSet, 1, &tgtcoordsclatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
/* Set the coordinates for source and target element vertices */
const void* srccoordsvlonvals_d = &( dSourceVertexLon[0][0] );
const void* srccoordsvlatvals_d = &( dSourceVertexLat[0][0] );
dsize = dSourceVertexLon.GetRows() * dSourceVertexLon.GetColumns();
rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLon, &m_meshOverlapSet, 1, &srccoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
rval = m_interface->tag_set_by_ptr( tagSrcCoordsVLat, &m_meshOverlapSet, 1, &srccoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
const void* tgtcoordsvlonvals_d = &( m_dTargetVertexLon[0][0] );
const void* tgtcoordsvlatvals_d = &( m_dTargetVertexLat[0][0] );
dsize = m_dTargetVertexLon.GetRows() * m_dTargetVertexLon.GetColumns();
rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLon, &m_meshOverlapSet, 1, &tgtcoordsvlonvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
rval = m_interface->tag_set_by_ptr( tagTgtCoordsVLat, &m_meshOverlapSet, 1, &tgtcoordsvlatvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
/* Set the masks for source and target meshes if available */
if( m_iSourceMask.IsAttached() )
{
const void* srcmaskvals_d = m_iSourceMask;
dsize = m_iSourceMask.GetRows();
rval = m_interface->tag_set_by_ptr( srcMaskValues, &m_meshOverlapSet, 1, &srcmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
}
if( m_iTargetMask.IsAttached() )
{
const void* tgtmaskvals_d = m_iTargetMask;
dsize = m_iTargetMask.GetRows();
rval = m_interface->tag_set_by_ptr( tgtMaskValues, &m_meshOverlapSet, 1, &tgtmaskvals_d, &dsize );MB_CHK_SET_ERR( rval, "Setting local tag data failed" );
}
#ifdef MOAB_HAVE_MPI
const char* writeOptions = ( this->size > 1 ? "PARALLEL=WRITE_PART" : "" );
#else
const char* writeOptions = "";
#endif
// EntityHandle sets[3] = {m_remapper->m_source_set, m_remapper->m_target_set, m_remapper->m_overlap_set};
EntityHandle sets[1] = {m_remapper->m_overlap_set};
rval = m_interface->write_file( strOutputFile.c_str(), NULL, writeOptions, sets, 1 );MB_CHK_ERR( rval );
#ifdef WRITE_SCRIP_FILE
sstr.str( "" );
sstr << ctx.outFilename.substr( 0, lastindex ) << "_" << proc_id << ".nc";
std::map< std::string, std::string > mapAttributes;
mapAttributes["Creator"] = "MOAB mbtempest workflow";
if( !ctx.proc_id ) std::cout << "Writing offline map to file: " << sstr.str() << std::endl;
this->Write( strOutputFile.c_str(), mapAttributes, NcFile::Netcdf4 );
sstr.str( "" );
#endif
return moab::MB_SUCCESS;
}
moab::ErrorCode moab::TempestOnlineMap::WriteParallelMap | ( | const std::string & | strTarget | ) |
Write the TempestOnlineMap to a parallel NetCDF file.
Definition at line 168 of file TempestOnlineMapIO.cpp.
References ErrorCode, and MB_CHK_ERR.
Referenced by main().
{
moab::ErrorCode rval;
size_t lastindex = strFilename.find_last_of( "." );
std::string extension = strFilename.substr( lastindex + 1, strFilename.size() );
// Write the map file to disk in parallel
if( extension == "nc" )
{
/* Invoke the actual call to write the parallel map to disk in SCRIP format */
rval = this->WriteSCRIPMapFile( strFilename.c_str() );MB_CHK_ERR( rval );
}
else
{
/* Write to the parallel H5M format */
rval = this->WriteHDF5MapFile( strFilename.c_str() );MB_CHK_ERR( rval );
}
return rval;
}
moab::ErrorCode moab::TempestOnlineMap::WriteSCRIPMapFile | ( | const std::string & | strOutputFile | ) | [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 192 of file TempestOnlineMapIO.cpp.
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.
{
NcError error( NcError::silent_nonfatal );
#ifdef MOAB_HAVE_NETCDFPAR
bool is_independent = true;
ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcFile::Replace, NcFile::Netcdf4 );
// ParNcFile ncMap( m_pcomm->comm(), MPI_INFO_NULL, strFilename.c_str(), NcmpiFile::replace, NcmpiFile::classic5 );
#else
NcFile ncMap( strFilename.c_str(), NcFile::Replace );
#endif
if( !ncMap.is_valid() )
{
_EXCEPTION1( "Unable to open output map file \"%s\"", strFilename.c_str() );
}
// Attributes
ncMap.add_att( "Title", "MOAB-TempestRemap Online Regridding Weight Generator" );
/**
* 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.
**/
/* Let us compute all relevant data for the current original source mesh on the process */
DataArray1D< double > vecSourceFaceArea, vecTargetFaceArea;
DataArray1D< double > dSourceCenterLon, dSourceCenterLat, dTargetCenterLon, dTargetCenterLat;
DataArray2D< double > dSourceVertexLon, dSourceVertexLat, dTargetVertexLon, dTargetVertexLat;
if( m_srcDiscType == DiscretizationType_FV || m_srcDiscType == DiscretizationType_PCLOUD )
{
this->InitializeCoordinatesFromMeshFV(
*m_meshInput, dSourceCenterLon, dSourceCenterLat, dSourceVertexLon, dSourceVertexLat,
( this->m_remapper->m_source_type == moab::TempestRemapper::RLL ), /* fLatLon = false */
m_remapper->max_source_edges );
vecSourceFaceArea.Allocate( m_meshInput->vecFaceArea.GetRows() );
for( unsigned i = 0; i < m_meshInput->vecFaceArea.GetRows(); ++i )
vecSourceFaceArea[i] = m_meshInput->vecFaceArea[i];
}
else
{
DataArray3D< double > dataGLLJacobianSrc;
this->InitializeCoordinatesFromMeshFE( *m_meshInput, m_nDofsPEl_Src, dataGLLNodesSrc, dSourceCenterLon,
dSourceCenterLat, dSourceVertexLon, dSourceVertexLat );
// Generate the continuous Jacobian for input mesh
GenerateMetaData( *m_meshInput, m_nDofsPEl_Src, false /* fBubble */, dataGLLNodesSrc, dataGLLJacobianSrc );
if( m_srcDiscType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesSrc, dataGLLJacobianSrc, vecSourceFaceArea );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobianSrc, vecSourceFaceArea );
}
}
if( m_destDiscType == DiscretizationType_FV || m_destDiscType == DiscretizationType_PCLOUD )
{
this->InitializeCoordinatesFromMeshFV(
*m_meshOutput, dTargetCenterLon, dTargetCenterLat, dTargetVertexLon, dTargetVertexLat,
( this->m_remapper->m_target_type == moab::TempestRemapper::RLL ), /* fLatLon = false */
m_remapper->max_target_edges );
vecTargetFaceArea.Allocate( m_meshOutput->vecFaceArea.GetRows() );
for( unsigned i = 0; i < m_meshOutput->vecFaceArea.GetRows(); ++i )
{
vecTargetFaceArea[i] = m_meshOutput->vecFaceArea[i];
}
}
else
{
DataArray3D< double > dataGLLJacobianDest;
this->InitializeCoordinatesFromMeshFE( *m_meshOutput, m_nDofsPEl_Dest, dataGLLNodesDest, dTargetCenterLon,
dTargetCenterLat, dTargetVertexLon, dTargetVertexLat );
// Generate the continuous Jacobian for input mesh
GenerateMetaData( *m_meshOutput, m_nDofsPEl_Dest, false /* fBubble */, dataGLLNodesDest, dataGLLJacobianDest );
if( m_destDiscType == DiscretizationType_CGLL )
{
GenerateUniqueJacobian( dataGLLNodesDest, dataGLLJacobianDest, vecTargetFaceArea );
}
else
{
GenerateDiscontinuousJacobian( dataGLLJacobianDest, vecTargetFaceArea );
}
}
// Map dimensions
unsigned nA = ( vecSourceFaceArea.GetRows() );
unsigned nB = ( vecTargetFaceArea.GetRows() );
std::vector< int > masksA, masksB;
ErrorCode rval = m_remapper->GetIMasks( moab::Remapper::SourceMesh, masksA );MB_CHK_SET_ERR( rval, "Trouble getting masks for source" );
rval = m_remapper->GetIMasks( moab::Remapper::TargetMesh, masksB );MB_CHK_SET_ERR( rval, "Trouble getting masks for target" );
// Number of nodes per Face
int nSourceNodesPerFace = dSourceVertexLon.GetColumns();
int nTargetNodesPerFace = dTargetVertexLon.GetColumns();
// if source or target cells have triangles at poles, center of those triangles need to come from
// the original quad, not from center in 3d, converted to 2d again
// start copy OnlineMap.cpp tempestremap
// right now, do this only for source mesh; copy the logic for target mesh
for( unsigned i = 0; i < nA; i++ )
{
const Face& face = m_meshInput->faces[i];
int nNodes = face.edges.size();
int indexNodeAtPole = -1;
if( 3 == nNodes ) // check if one node at the poles
{
for( int j = 0; j < nNodes; j++ )
if( fabs( fabs( dSourceVertexLat[i][j] ) - 90.0 ) < 1.0e-12 )
{
indexNodeAtPole = j;
break;
}
}
if( indexNodeAtPole < 0 ) continue; // continue i loop, do nothing
// recompute center of cell, from 3d data; add one 2 nodes at pole, and average
int nodeAtPole = face[indexNodeAtPole]; // use the overloaded operator
Node nodePole = m_meshInput->nodes[nodeAtPole];
Node newCenter = nodePole * 2;
for( int j = 1; j < nNodes; j++ )
{
int indexi = ( indexNodeAtPole + j ) % nNodes; // nNodes is 3 !
const Node& node = m_meshInput->nodes[face[indexi]];
newCenter = newCenter + node;
}
newCenter = newCenter * 0.25;
newCenter = newCenter.Normalized();
#ifdef VERBOSE
double iniLon = dSourceCenterLon[i], iniLat = dSourceCenterLat[i];
#endif
// dSourceCenterLon, dSourceCenterLat
XYZtoRLL_Deg( newCenter.x, newCenter.y, newCenter.z, dSourceCenterLon[i], dSourceCenterLat[i] );
#ifdef VERBOSE
std::cout << " modify center of triangle from " << iniLon << " " << iniLat << " to " << dSourceCenterLon[i]
<< " " << dSourceCenterLat[i] << "\n";
#endif
}
// first move data if in parallel
#if defined( MOAB_HAVE_MPI )
int max_row_dof, max_col_dof; // output; arrays will be re-distributed in chunks [maxdof/size]
// if (size > 1)
{
int ierr = rearrange_arrays_by_dofs( srccol_gdofmap, vecSourceFaceArea, dSourceCenterLon, dSourceCenterLat,
dSourceVertexLon, dSourceVertexLat, masksA, nA, nSourceNodesPerFace,
max_col_dof ); // now nA will be close to maxdof/size
if( ierr != 0 )
{
_EXCEPTION1( "Unable to arrange source data %d ", nA );
}
// rearrange target data: (nB)
//
ierr = rearrange_arrays_by_dofs( row_gdofmap, vecTargetFaceArea, dTargetCenterLon, dTargetCenterLat,
dTargetVertexLon, dTargetVertexLat, masksB, nB, nTargetNodesPerFace,
max_row_dof ); // now nA will be close to maxdof/size
if( ierr != 0 )
{
_EXCEPTION1( "Unable to arrange target data %d ", nB );
}
}
#endif
// Number of non-zeros in the remap matrix operator
int nS = m_weightMatrix.nonZeros();
#if defined( MOAB_HAVE_MPI ) && defined( MOAB_HAVE_NETCDFPAR )
int locbuf[5] = {(int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace};
int offbuf[3] = {0, 0, 0};
int globuf[5] = {0, 0, 0, 0, 0};
MPI_Scan( locbuf, offbuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() );
MPI_Allreduce( locbuf, globuf, 3, MPI_INT, MPI_SUM, m_pcomm->comm() );
MPI_Allreduce( &locbuf[3], &globuf[3], 2, MPI_INT, MPI_MAX, m_pcomm->comm() );
// MPI_Scan is inclusive of data in current rank; modify accordingly.
offbuf[0] -= nA;
offbuf[1] -= nB;
offbuf[2] -= nS;
#else
int offbuf[3] = {0, 0, 0};
int globuf[5] = {(int)nA, (int)nB, nS, nSourceNodesPerFace, nTargetNodesPerFace};
#endif
// Write output dimensions entries
unsigned nSrcGridDims = ( m_vecSourceDimSizes.size() );
unsigned nDstGridDims = ( m_vecTargetDimSizes.size() );
NcDim* dimSrcGridRank = ncMap.add_dim( "src_grid_rank", nSrcGridDims );
NcDim* dimDstGridRank = ncMap.add_dim( "dst_grid_rank", nDstGridDims );
NcVar* varSrcGridDims = ncMap.add_var( "src_grid_dims", ncInt, dimSrcGridRank );
NcVar* varDstGridDims = ncMap.add_var( "dst_grid_dims", ncInt, dimDstGridRank );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varSrcGridDims, is_independent );
ncMap.enable_var_par_access( varDstGridDims, is_independent );
#endif
char szDim[64];
if( ( nSrcGridDims == 1 ) && ( m_vecSourceDimSizes[0] != (int)nA ) )
{
varSrcGridDims->put( &globuf[0], 1 );
varSrcGridDims->add_att( "name0", "num_dof" );
}
else
{
for( unsigned i = 0; i < m_vecSourceDimSizes.size(); i++ )
{
int tmp = ( i == 0 ? globuf[0] : m_vecSourceDimSizes[i] );
varSrcGridDims->set_cur( nSrcGridDims - i - 1 );
varSrcGridDims->put( &( tmp ), 1 );
}
for( unsigned i = 0; i < m_vecSourceDimSizes.size(); i++ )
{
sprintf( szDim, "name%i", i );
varSrcGridDims->add_att( szDim, m_vecSourceDimNames[nSrcGridDims - i - 1].c_str() );
}
}
if( ( nDstGridDims == 1 ) && ( m_vecTargetDimSizes[0] != (int)nB ) )
{
varDstGridDims->put( &globuf[1], 1 );
varDstGridDims->add_att( "name0", "num_dof" );
}
else
{
for( unsigned i = 0; i < m_vecTargetDimSizes.size(); i++ )
{
int tmp = ( i == 0 ? globuf[1] : m_vecTargetDimSizes[i] );
varDstGridDims->set_cur( nDstGridDims - i - 1 );
varDstGridDims->put( &( tmp ), 1 );
}
for( unsigned i = 0; i < m_vecTargetDimSizes.size(); i++ )
{
sprintf( szDim, "name%i", i );
varDstGridDims->add_att( szDim, m_vecTargetDimNames[nDstGridDims - i - 1].c_str() );
}
}
// Source and Target mesh resolutions
NcDim* dimNA = ncMap.add_dim( "n_a", globuf[0] );
NcDim* dimNB = ncMap.add_dim( "n_b", globuf[1] );
// Number of nodes per Face
NcDim* dimNVA = ncMap.add_dim( "nv_a", globuf[3] );
NcDim* dimNVB = ncMap.add_dim( "nv_b", globuf[4] );
// Write coordinates
NcVar* varYCA = ncMap.add_var( "yc_a", ncDouble, dimNA );
NcVar* varYCB = ncMap.add_var( "yc_b", ncDouble, dimNB );
NcVar* varXCA = ncMap.add_var( "xc_a", ncDouble, dimNA );
NcVar* varXCB = ncMap.add_var( "xc_b", ncDouble, dimNB );
NcVar* varYVA = ncMap.add_var( "yv_a", ncDouble, dimNA, dimNVA );
NcVar* varYVB = ncMap.add_var( "yv_b", ncDouble, dimNB, dimNVB );
NcVar* varXVA = ncMap.add_var( "xv_a", ncDouble, dimNA, dimNVA );
NcVar* varXVB = ncMap.add_var( "xv_b", ncDouble, dimNB, dimNVB );
// Write masks
NcVar* varMaskA = ncMap.add_var( "mask_a", ncInt, dimNA );
NcVar* varMaskB = ncMap.add_var( "mask_b", ncInt, dimNB );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varYCA, is_independent );
ncMap.enable_var_par_access( varYCB, is_independent );
ncMap.enable_var_par_access( varXCA, is_independent );
ncMap.enable_var_par_access( varXCB, is_independent );
ncMap.enable_var_par_access( varYVA, is_independent );
ncMap.enable_var_par_access( varYVB, is_independent );
ncMap.enable_var_par_access( varXVA, is_independent );
ncMap.enable_var_par_access( varXVB, is_independent );
ncMap.enable_var_par_access( varMaskA, is_independent );
ncMap.enable_var_par_access( varMaskB, is_independent );
#endif
varYCA->add_att( "units", "degrees" );
varYCB->add_att( "units", "degrees" );
varXCA->add_att( "units", "degrees" );
varXCB->add_att( "units", "degrees" );
varYVA->add_att( "units", "degrees" );
varYVB->add_att( "units", "degrees" );
varXVA->add_att( "units", "degrees" );
varXVB->add_att( "units", "degrees" );
// Verify dimensionality
if( dSourceCenterLon.GetRows() != nA )
{
_EXCEPTIONT( "Mismatch between dSourceCenterLon and nA" );
}
if( dSourceCenterLat.GetRows() != nA )
{
_EXCEPTIONT( "Mismatch between dSourceCenterLat and nA" );
}
if( dTargetCenterLon.GetRows() != nB )
{
_EXCEPTIONT( "Mismatch between dTargetCenterLon and nB" );
}
if( dTargetCenterLat.GetRows() != nB )
{
_EXCEPTIONT( "Mismatch between dTargetCenterLat and nB" );
}
if( dSourceVertexLon.GetRows() != nA )
{
_EXCEPTIONT( "Mismatch between dSourceVertexLon and nA" );
}
if( dSourceVertexLat.GetRows() != nA )
{
_EXCEPTIONT( "Mismatch between dSourceVertexLat and nA" );
}
if( dTargetVertexLon.GetRows() != nB )
{
_EXCEPTIONT( "Mismatch between dTargetVertexLon and nB" );
}
if( dTargetVertexLat.GetRows() != nB )
{
_EXCEPTIONT( "Mismatch between dTargetVertexLat and nB" );
}
varYCA->set_cur( (long)offbuf[0] );
varYCA->put( &( dSourceCenterLat[0] ), nA );
varYCB->set_cur( (long)offbuf[1] );
varYCB->put( &( dTargetCenterLat[0] ), nB );
varXCA->set_cur( (long)offbuf[0] );
varXCA->put( &( dSourceCenterLon[0] ), nA );
varXCB->set_cur( (long)offbuf[1] );
varXCB->put( &( dTargetCenterLon[0] ), nB );
varYVA->set_cur( (long)offbuf[0] );
varYVA->put( &( dSourceVertexLat[0][0] ), nA, nSourceNodesPerFace );
varYVB->set_cur( (long)offbuf[1] );
varYVB->put( &( dTargetVertexLat[0][0] ), nB, nTargetNodesPerFace );
varXVA->set_cur( (long)offbuf[0] );
varXVA->put( &( dSourceVertexLon[0][0] ), nA, nSourceNodesPerFace );
varXVB->set_cur( (long)offbuf[1] );
varXVB->put( &( dTargetVertexLon[0][0] ), nB, nTargetNodesPerFace );
varMaskA->set_cur( (long)offbuf[0] );
varMaskA->put( &( masksA[0] ), nA );
varMaskB->set_cur( (long)offbuf[1] );
varMaskB->put( &( masksB[0] ), nB );
// Write areas
NcVar* varAreaA = ncMap.add_var( "area_a", ncDouble, dimNA );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varAreaA, is_independent );
#endif
varAreaA->set_cur( (long)offbuf[0] );
varAreaA->put( &( vecSourceFaceArea[0] ), nA );
NcVar* varAreaB = ncMap.add_var( "area_b", ncDouble, dimNB );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varAreaB, is_independent );
#endif
varAreaB->set_cur( (long)offbuf[1] );
varAreaB->put( &( vecTargetFaceArea[0] ), nB );
// Write SparseMatrix entries
DataArray1D< int > vecRow( nS );
DataArray1D< int > vecCol( nS );
DataArray1D< double > vecS( nS );
DataArray1D< double > dFracA( nA );
DataArray1D< double > dFracB( nB );
moab::TupleList tlValRow, tlValCol;
unsigned numr = 1; //
// value has to be sent to processor row/nB for for fracA and col/nA for fracB
// vecTargetArea (indexRow ) has to be sent for fracA (index col?)
// vecTargetFaceArea will have to be sent to col index, with its index !
tlValRow.initialize( 2, 0, 0, numr, nS ); // to proc(row), global row , value
tlValCol.initialize( 3, 0, 0, numr, nS ); // to proc(col), global row / col, value
tlValRow.enableWriteAccess();
tlValCol.enableWriteAccess();
/*
*
dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
dFracB[ row ] += val ;
*/
int offset = 0;
#if defined( MOAB_HAVE_MPI )
int nAbase = ( max_col_dof + 1 ) / size; // it is nA, except last rank ( == size - 1 )
int nBbase = ( max_row_dof + 1 ) / size; // it is nB, except last rank ( == size - 1 )
#endif
for( int i = 0; i < m_weightMatrix.outerSize(); ++i )
{
for( WeightMatrix::InnerIterator it( m_weightMatrix, i ); it; ++it )
{
vecRow[offset] = 1 + this->GetRowGlobalDoF( it.row() ); // row index
vecCol[offset] = 1 + this->GetColGlobalDoF( it.col() ); // col index
vecS[offset] = it.value(); // value
#if defined( MOAB_HAVE_MPI )
{
// value M(row, col) will contribute to procRow and procCol values for fracA and fracB
int procRow = ( vecRow[offset] - 1 ) / nBbase;
if( procRow >= size ) procRow = size - 1;
int procCol = ( vecCol[offset] - 1 ) / nAbase;
if( procCol >= size ) procCol = size - 1;
int nrInd = tlValRow.get_n();
tlValRow.vi_wr[2 * nrInd] = procRow;
tlValRow.vi_wr[2 * nrInd + 1] = vecRow[offset] - 1;
tlValRow.vr_wr[nrInd] = vecS[offset];
tlValRow.inc_n();
int ncInd = tlValCol.get_n();
tlValCol.vi_wr[3 * ncInd] = procCol;
tlValCol.vi_wr[3 * ncInd + 1] = vecRow[offset] - 1;
tlValCol.vi_wr[3 * ncInd + 2] = vecCol[offset] - 1; // this is column
tlValCol.vr_wr[ncInd] = vecS[offset];
tlValCol.inc_n();
}
#endif
offset++;
}
}
#if defined( MOAB_HAVE_MPI )
// need to send values for their row and col processors, to compute fractions there
// now do the heavy communication
( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValCol, 0 );
( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tlValRow, 0 );
// we have now, for example, dFracB[ row ] += val ;
// so we know that on current task, we received tlValRow
// reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
// dFracB[ row ] += val ;
for( unsigned i = 0; i < tlValRow.get_n(); i++ )
{
// int fromProc = tlValRow.vi_wr[2 * i];
int gRowInd = tlValRow.vi_wr[2 * i + 1];
int localIndexRow = gRowInd - nBbase * rank; // modulo nBbase rank is from 0 to size - 1;
double wgt = tlValRow.vr_wr[i];
assert( localIndexRow >= 0 );
assert( nB - localIndexRow > 0 );
dFracB[localIndexRow] += wgt;
}
// to compute dFracA we need vecTargetFaceArea[ row ]; we know the row, and we can get the proc we need it from
std::set< int > neededRows;
for( unsigned i = 0; i < tlValCol.get_n(); i++ )
{
int rRowInd = tlValCol.vi_wr[3 * i + 1];
neededRows.insert( rRowInd );
// we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow
}
moab::TupleList tgtAreaReq;
tgtAreaReq.initialize( 2, 0, 0, 0, neededRows.size() );
tgtAreaReq.enableWriteAccess();
for( std::set< int >::iterator sit = neededRows.begin(); sit != neededRows.end(); sit++ )
{
int neededRow = *sit;
int procRow = neededRow / nBbase;
if( procRow >= size ) procRow = size - 1;
int nr = tgtAreaReq.get_n();
tgtAreaReq.vi_wr[2 * nr] = procRow;
tgtAreaReq.vi_wr[2 * nr + 1] = neededRow;
tgtAreaReq.inc_n();
}
( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaReq, 0 );
// we need to send back the tgtArea corresponding to row
moab::TupleList tgtAreaInfo; // load it with tgtArea at row
tgtAreaInfo.initialize( 2, 0, 0, 1, tgtAreaReq.get_n() );
tgtAreaInfo.enableWriteAccess();
for( unsigned i = 0; i < tgtAreaReq.get_n(); i++ )
{
int from_proc = tgtAreaReq.vi_wr[2 * i];
int row = tgtAreaReq.vi_wr[2 * i + 1];
int locaIndexRow = row - rank * nBbase;
double areaToSend = vecTargetFaceArea[locaIndexRow];
// int remoteIndex = tgtAreaReq.vi_wr[3*i + 2] ;
tgtAreaInfo.vi_wr[2 * i] = from_proc; // send back requested info
tgtAreaInfo.vi_wr[2 * i + 1] = row;
tgtAreaInfo.vr_wr[i] = areaToSend; // this will be tgt area at row
tgtAreaInfo.inc_n();
}
( m_pcomm->proc_config().crystal_router() )->gs_transfer( 1, tgtAreaInfo, 0 );
std::map< int, double > areaAtRow;
for( unsigned i = 0; i < tgtAreaInfo.get_n(); i++ )
{
// we have received from proc, value for row !
int row = tgtAreaInfo.vi_wr[2 * i + 1];
areaAtRow[row] = tgtAreaInfo.vr_wr[i];
}
// we have now for rows the
// it is ordered by index, so:
// now compute reminder dFracA[ col ] += val / vecSourceFaceArea[ col ] * vecTargetFaceArea[ row ];
// tgtAreaInfo will have at index i the area we need (from row)
// there should be an easier way :(
for( unsigned i = 0; i < tlValCol.get_n(); i++ )
{
int rRowInd = tlValCol.vi_wr[3 * i + 1];
int colInd = tlValCol.vi_wr[3 * i + 2];
double val = tlValCol.vr_wr[i];
int localColInd = colInd - rank * nAbase; // < local nA
// we need vecTargetFaceAreaGlobal[ rRowInd ]; this exists on proc procRow
auto itMap = areaAtRow.find( rRowInd ); // it should be different from end
if( itMap != areaAtRow.end() )
{
double areaRow = itMap->second; // we fished a lot for this !
assert( localColInd < vecSourceFaceArea.GetRows() );
dFracA[localColInd] += val / vecSourceFaceArea[localColInd] * areaRow;
}
}
#endif
// Load in data
NcDim* dimNS = ncMap.add_dim( "n_s", globuf[2] );
NcVar* varRow = ncMap.add_var( "row", ncInt, dimNS );
NcVar* varCol = ncMap.add_var( "col", ncInt, dimNS );
NcVar* varS = ncMap.add_var( "S", ncDouble, dimNS );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varRow, is_independent );
ncMap.enable_var_par_access( varCol, is_independent );
ncMap.enable_var_par_access( varS, is_independent );
#endif
varRow->set_cur( (long)offbuf[2] );
varRow->put( &( vecRow[0] ), nS );
varCol->set_cur( (long)offbuf[2] );
varCol->put( &( vecCol[0] ), nS );
varS->set_cur( (long)offbuf[2] );
varS->put( &( vecS[0] ), nS );
// Calculate and write fractional coverage arrays
NcVar* varFracA = ncMap.add_var( "frac_a", ncDouble, dimNA );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varFracA, is_independent );
#endif
varFracA->add_att( "name", "fraction of target coverage of source dof" );
varFracA->add_att( "units", "unitless" );
varFracA->set_cur( (long)offbuf[0] );
varFracA->put( &( dFracA[0] ), nA );
NcVar* varFracB = ncMap.add_var( "frac_b", ncDouble, dimNB );
#ifdef MOAB_HAVE_NETCDFPAR
ncMap.enable_var_par_access( varFracB, is_independent );
#endif
varFracB->add_att( "name", "fraction of source coverage of target dof" );
varFracB->add_att( "units", "unitless" );
varFracB->set_cur( (long)offbuf[1] );
varFracB->put( &( dFracB[0] ), nB );
// Add global attributes
// std::map::const_iterator iterAttributes =
// mapAttributes.begin();
// for (; iterAttributes != mapAttributes.end(); iterAttributes++) {
// ncMap.add_att(
// iterAttributes->first.c_str(),
// iterAttributes->second.c_str());
// }
ncMap.close();
return moab::MB_SUCCESS;
}
std::vector< int > moab::TempestOnlineMap::col_dtoc_dofmap [private] |
Definition at line 444 of file TempestOnlineMap.hpp.
std::vector< unsigned > moab::TempestOnlineMap::col_gdofmap [private] |
Definition at line 441 of file TempestOnlineMap.hpp.
Referenced by fill_col_ids(), and LinearRemapNN_MOAB().
std::map< int, int > moab::TempestOnlineMap::colMap [private] |
Definition at line 446 of file TempestOnlineMap.hpp.
DataArray3D< int > moab::TempestOnlineMap::dataGLLNodesDest [private] |
Definition at line 448 of file TempestOnlineMap.hpp.
DataArray3D< int > moab::TempestOnlineMap::dataGLLNodesSrc [private] |
Definition at line 448 of file TempestOnlineMap.hpp.
DataArray3D< int > moab::TempestOnlineMap::dataGLLNodesSrcCov [private] |
Definition at line 448 of file TempestOnlineMap.hpp.
bool moab::TempestOnlineMap::is_parallel [private] |
Definition at line 463 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
bool moab::TempestOnlineMap::is_root [private] |
Definition at line 463 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
bool moab::TempestOnlineMap::m_bConserved [private] |
Definition at line 455 of file TempestOnlineMap.hpp.
Definition at line 449 of file TempestOnlineMap.hpp.
Definition at line 440 of file TempestOnlineMap.hpp.
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 440 of file TempestOnlineMap.hpp.
Definition at line 454 of file TempestOnlineMap.hpp.
Definition at line 454 of file TempestOnlineMap.hpp.
int moab::TempestOnlineMap::m_iMonotonicity [private] |
Definition at line 456 of file TempestOnlineMap.hpp.
The reference to the moab::Core object that contains source/target and overlap sets.
Definition at line 428 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
Mesh* moab::TempestOnlineMap::m_meshInput [private] |
Definition at line 458 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
Mesh* moab::TempestOnlineMap::m_meshInputCov [private] |
Definition at line 459 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
Mesh* moab::TempestOnlineMap::m_meshOutput [private] |
Definition at line 460 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
Mesh* moab::TempestOnlineMap::m_meshOverlap [private] |
Definition at line 461 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
int moab::TempestOnlineMap::m_nDofsPEl_Dest [private] |
Definition at line 453 of file TempestOnlineMap.hpp.
int moab::TempestOnlineMap::m_nDofsPEl_Src [private] |
Definition at line 453 of file TempestOnlineMap.hpp.
int moab::TempestOnlineMap::m_nTotDofs_Dest [private] |
Definition at line 450 of file TempestOnlineMap.hpp.
Referenced by LinearRemapNN_MOAB().
int moab::TempestOnlineMap::m_nTotDofs_Src [private] |
Definition at line 450 of file TempestOnlineMap.hpp.
int moab::TempestOnlineMap::m_nTotDofs_SrcCov [private] |
Definition at line 450 of file TempestOnlineMap.hpp.
Referenced by LinearRemapNN_MOAB().
The fundamental remapping operator object.
Definition at line 415 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
Definition at line 449 of file TempestOnlineMap.hpp.
int moab::TempestOnlineMap::rank [private] |
Definition at line 464 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
int moab::TempestOnlineMap::root_proc [private] |
Definition at line 464 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
std::vector< int > moab::TempestOnlineMap::row_dtoc_dofmap [private] |
Definition at line 444 of file TempestOnlineMap.hpp.
std::vector< unsigned > moab::TempestOnlineMap::row_gdofmap [private] |
Definition at line 441 of file TempestOnlineMap.hpp.
Referenced by fill_row_ids(), and LinearRemapNN_MOAB().
std::map< int, int > moab::TempestOnlineMap::rowMap [private] |
Definition at line 446 of file TempestOnlineMap.hpp.
int moab::TempestOnlineMap::size [private] |
Definition at line 464 of file TempestOnlineMap.hpp.
Referenced by TempestOnlineMap().
std::vector< int > moab::TempestOnlineMap::srccol_dtoc_dofmap [private] |
Definition at line 444 of file TempestOnlineMap.hpp.
std::vector< unsigned > moab::TempestOnlineMap::srccol_gdofmap [private] |
Definition at line 441 of file TempestOnlineMap.hpp.