MOAB: Mesh Oriented datABase  (version 5.1.1)
moab::TempestOfflineMap Class Reference

An offline map between two Meshes. More...

#include <TempestOfflineMap.hpp>

+ Collaboration diagram for moab::TempestOfflineMap:

Public Types

enum  DiscretizationType { DiscretizationType_FV, DiscretizationType_CGLL, DiscretizationType_DGLL }

Public Member Functions

 TempestOfflineMap (moab::TempestRemapper *remapper)
 Generate the metadata associated with the offline map.
virtual ~TempestOfflineMap ()
 Define a virtual destructor.
moab::ErrorCode GenerateOfflineMap (std::string strInputType="fv", std::string strOutputType="fv", const int nPin=1, const int nPout=1, bool fBubble=false, int fMonotoneTypeID=0, bool fVolumetric=false, bool fNoConservation=false, bool fNoCheck=false, const std::string srcDofTagName="GLOBAL_ID", const std::string tgtDofTagName="GLOBAL_ID", const std::string strVariables="", const std::string strInputData="", const std::string strOutputData="", const std::string strNColName="", const bool fOutputDouble=false, const std::string strPreserveVariables="", const bool fPreserveAll=false, const double dFillValueOverride=0.0, const bool fInputConcave=false, const bool fOutputConcave=false)
 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.
virtual bool IsConsistent (double dTolerance)
 Generate the metadata associated with the offline map.
virtual bool IsConservative (double dTolerance)
 Determine if the map is conservative.
virtual bool IsMonotone (double dTolerance)
 Determine if the map is monotone.
const DataVector< double > & GetGlobalSourceAreas () const
 If we computed the reduction, get the vector representing the source areas for all entities in the mesh.
const DataVector< double > & GetGlobalTargetAreas () const
 If we computed the reduction, get the vector representing the target areas for all entities in the mesh.

Public Attributes

moab::TempestRemapperm_remapper
 Copy the local matrix from Tempest SparseMatrix representation (ELL) to the parallel CSR Eigen Matrix for scalable application of matvec needed for projections.
OfflineMap * m_weightMapGlobal
 The SparseMatrix representing this operator.
bool m_globalMapAvailable
 The boolean flag representing whether the root process has the updated global view.
moab::InterfacembCore
 The DataVector that stores the global (GID-based) areas of the source mesh.
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 long > row_dofmap
std::vector< unsigned long > col_dofmap
std::vector< unsigned long > srccol_dofmap
std::vector< unsigned long > row_gdofmap
std::vector< unsigned long > col_gdofmap
std::vector< unsigned long > srccol_gdofmap
std::vector< unsigned long > row_ldofmap
std::vector< unsigned long > col_ldofmap
std::vector< unsigned long > srccol_ldofmap
DataMatrix3D< int > dataGLLNodesSrc
DataMatrix3D< int > dataGLLNodesSrcCov
DataMatrix3D< 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
Mesh * m_meshInput
Mesh * m_meshInputCov
Mesh * m_meshOutput
Mesh * m_meshOverlap
bool is_parallel
bool is_root
int rank
int size

Private Member Functions

moab::ErrorCode GatherAllToRoot ()
 Gather the mapping matrix that was computed in different processors and accumulate the data on the root so that OfflineMap can be generated in parallel.
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 DataMatrix3D< int > &dataGLLNodes, const DataMatrix3D< double > &dataGLLJacobian)
 Generate the OfflineMap for linear conserative element-average spectral element to element average remapping.
void LinearRemapSE4_Tempest_MOAB (const DataMatrix3D< int > &dataGLLNodes, const DataMatrix3D< double > &dataGLLJacobian, int nMonotoneType, bool fContinuousIn, bool fNoConservation)
 Generate the OfflineMap for cubic conserative element-average spectral element to element average remapping.
void LinearRemapFVtoGLL_Simple_MOAB (const DataMatrix3D< int > &dataGLLNodes, const DataMatrix3D< double > &dataGLLJacobian, const DataVector< double > &dataGLLNodalArea, int nOrder, int nMonotoneType, bool fContinuous, bool fNoConservation)
 Generate the OfflineMap for remapping from finite volumes to finite elements using simple sampling of the FV reconstruction.
void LinearRemapFVtoGLL_Volumetric_MOAB (const DataMatrix3D< int > &dataGLLNodes, const DataMatrix3D< double > &dataGLLJacobian, const DataVector< double > &dataGLLNodalArea, int nOrder, int nMonotoneType, bool fContinuous, bool fNoConservation)
 Generate the OfflineMap for remapping from finite volumes to finite elements using a new experimental method.
void LinearRemapFVtoGLL_MOAB (const DataMatrix3D< int > &dataGLLNodes, const DataMatrix3D< double > &dataGLLJacobian, const DataVector< 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 DataMatrix3D< int > &dataGLLNodesIn, const DataMatrix3D< double > &dataGLLJacobianIn, const DataMatrix3D< int > &dataGLLNodesOut, const DataMatrix3D< double > &dataGLLJacobianOut, const DataVector< 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 DataMatrix3D< int > &dataGLLNodesIn, const DataMatrix3D< double > &dataGLLJacobianIn, const DataMatrix3D< int > &dataGLLNodesOut, const DataMatrix3D< double > &dataGLLJacobianOut, const DataVector< 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 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, DataMatrix3D< int > *srcdataGLLNodes, DataMatrix3D< int > *srcdataGLLNodesSrc, DiscretizationType destType, bool isDestContinuous, DataMatrix3D< 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.

Detailed Description

An offline map between two Meshes.

Definition at line 54 of file TempestOfflineMap.hpp.


Member Enumeration Documentation

Enumerator:
DiscretizationType_FV 
DiscretizationType_CGLL 
DiscretizationType_DGLL 

Definition at line 71 of file TempestOfflineMap.hpp.


Constructor & Destructor Documentation

Generate the metadata associated with the offline map.

Definition at line 35 of file TempestOfflineMap.cpp.

References dbgprint, moab::Remapper::get_interface(), moab::TempestRemapper::GetCoveringMesh(), moab::TempestRemapper::GetMesh(), moab::Remapper::IntersectedMesh, is_parallel, is_root, m_globalMapAvailable, m_meshInput, m_meshInputCov, m_meshOutput, m_meshOverlap, m_remapper, m_weightMapGlobal, mbCore, moab::DebugOutput::printf(), rank, size, moab::Remapper::SourceMesh, and moab::Remapper::TargetMesh.

                                                                         : OfflineMap(), m_remapper ( remapper )
{
    // Get the references for the MOAB core objects
    mbCore = m_remapper->get_interface();
#ifdef MOAB_HAVE_MPI
    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::IntersectedMesh );
    m_globalMapAvailable = false;

    is_parallel = false;
    is_root = true;
    rank = 0;
    size = 1;
#ifdef MOAB_HAVE_MPI
    int flagInit;
    MPI_Initialized( &flagInit );
    if (flagInit) {
        is_parallel = true;
        assert(pcomm != NULL);
        rank = pcomm->rank();
        size = pcomm->size();
        is_root = (rank == 0);
    }
#endif

    moab::DebugOutput dbgprint ( std::cout, rank );

    // 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
    std::vector<std::string> dimNames(1);
    std::vector<int> dimSizes(1);
    dimNames[0] = "num_elem";

    dbgprint.printf ( 0, "Initializing dimensions of map\n" );
    dbgprint.printf ( 0, "Input mesh\n" );
    dimSizes[0] = m_meshInputCov->faces.size();
    this->InitializeSourceDimensions(dimNames, dimSizes);
    dbgprint.printf ( 0, "Output mesh\n" );
    dimSizes[0] = m_meshOutput->faces.size();
    this->InitializeTargetDimensions(dimNames, dimSizes);

    m_weightMapGlobal = NULL;

    // 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
}

Define a virtual destructor.

Definition at line 93 of file TempestOfflineMap.cpp.

{
    delete m_weightMapGlobal;
    mbCore = NULL;
#ifdef MOAB_HAVE_MPI
    pcomm = NULL;
#endif
    m_meshInput = NULL;
    m_meshOutput = NULL;
    m_meshOverlap = NULL;
}

Member Function Documentation

Gather the mapping matrix that was computed in different processors and accumulate the data on the root so that OfflineMap can be generated in parallel.

moab::ErrorCode moab::TempestOfflineMap::GenerateOfflineMap ( std::string  strInputType = "fv",
std::string  strOutputType = "fv",
const int  nPin = 1,
const int  nPout = 1,
bool  fBubble = false,
int  fMonotoneTypeID = 0,
bool  fVolumetric = false,
bool  fNoConservation = false,
bool  fNoCheck = false,
const std::string  srcDofTagName = "GLOBAL_ID",
const std::string  tgtDofTagName = "GLOBAL_ID",
const std::string  strVariables = "",
const std::string  strInputData = "",
const std::string  strOutputData = "",
const std::string  strNColName = "",
const bool  fOutputDouble = false,
const std::string  strPreserveVariables = "",
const bool  fPreserveAll = false,
const double  dFillValueOverride = 0.0,
const bool  fInputConcave = false,
const bool  fOutputConcave = false 
)

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.

Definition at line 481 of file TempestOfflineMap.cpp.

References dbgprint, moab::error(), MB_CHK_ERR, MB_FAILURE, MB_SUCCESS, ParseVariableList(), moab::DebugOutput::printf(), rank, and size.

Referenced by main().

{
    NcError error ( NcError::silent_nonfatal );

    moab::DebugOutput dbgprint ( std::cout, ( rank ) );
    moab::ErrorCode rval;

    try
    {
        // Check command line parameters (data arguments)
        if ( ( strInputData != "" ) && ( strOutputData == "" ) )
        {
            _EXCEPTIONT ( "--in_data specified without --out_data" );
        }
        if ( ( strInputData == "" ) && ( strOutputData != "" ) )
        {
            _EXCEPTIONT ( "--out_data specified without --in_data" );
        }

        // 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
        {
            _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
        {
            _EXCEPTION1 ( "Invalid \"out_type\" value (%s), expected [fv|cgll|dgll]",
                          strOutputType.c_str() );
        }

        // Monotonicity flags
        int nMonotoneType = fMonotoneTypeID;

        // Parse variable list
        std::vector< std::string > vecVariableStrings;
        ParseVariableList ( strVariables, vecVariableStrings );

        // Parse preserve variable list
        std::vector< std::string > vecPreserveVariableStrings;
        ParseVariableList ( strPreserveVariables, vecPreserveVariableStrings );

        if ( fPreserveAll && ( vecPreserveVariableStrings.size() != 0 ) )
        {
            _EXCEPTIONT ( "--preserveall and --preserve cannot both be specified" );
        }

        m_nDofsPEl_Src = nPin;
        m_nDofsPEl_Dest = nPout;

        rval = SetDofMapTags(srcDofTagName, tgtDofTagName);

        // Calculate Face areas
        if ( is_root ) dbgprint.printf ( 0, "Calculating input mesh Face areas\n" );
        double dTotalAreaInput_loc = m_meshInput->CalculateFaceAreas(fInputConcave);
        double dTotalAreaInput = dTotalAreaInput_loc;
#ifdef MOAB_HAVE_MPI
        if (pcomm) MPI_Allreduce ( &dTotalAreaInput_loc, &dTotalAreaInput, 1, MPI_DOUBLE, MPI_SUM, pcomm->comm() );
#endif
        if ( is_root ) dbgprint.printf ( 0, "Input Mesh Geometric Area: %1.15e\n", dTotalAreaInput );

        // Input mesh areas
        m_meshInputCov->CalculateFaceAreas(fInputConcave);
        if ( eInputType == DiscretizationType_FV )
        {
            this->SetSourceAreas ( m_meshInputCov->vecFaceArea );
        }

        // Calculate Face areas
        if ( is_root ) dbgprint.printf ( 0, "Calculating output mesh Face areas\n" );
        double dTotalAreaOutput_loc = m_meshOutput->CalculateFaceAreas(fOutputConcave);
        double dTotalAreaOutput = dTotalAreaOutput_loc;
#ifdef MOAB_HAVE_MPI
        if (pcomm) MPI_Allreduce ( &dTotalAreaOutput_loc, &dTotalAreaOutput, 1, MPI_DOUBLE, MPI_SUM, pcomm->comm() );
#endif
        if ( is_root ) dbgprint.printf ( 0, "Output Mesh Geometric Area: %1.15e\n", dTotalAreaOutput );

        // Output mesh areas
        if ( eOutputType == DiscretizationType_FV )
        {
            this->SetTargetAreas ( m_meshOutput->vecFaceArea );
        }

        // Verify that overlap mesh is in the correct order
        int ixSourceFaceMax = ( -1 );
        int ixTargetFaceMax = ( -1 );

        if ( m_meshOverlap->vecSourceFaceIx.size() !=
                m_meshOverlap->vecTargetFaceIx.size()
           )
        {
            _EXCEPTIONT ( "Invalid overlap mesh:\n"
                          "    Possible mesh file corruption?" );
        }

        for ( unsigned i = 0; i < m_meshOverlap->vecSourceFaceIx.size(); i++ )
        {
            if ( m_meshOverlap->vecSourceFaceIx[i] + 1 > ixSourceFaceMax )
            {
                ixSourceFaceMax = m_meshOverlap->vecSourceFaceIx[i] + 1;
            }
            if ( m_meshOverlap->vecTargetFaceIx[i] + 1 > ixTargetFaceMax )
            {
                ixTargetFaceMax = m_meshOverlap->vecTargetFaceIx[i] + 1;
            }
        }

        /*
        // Check for forward correspondence in overlap mesh
        if ( // m_meshInputCov->faces.size() - ixSourceFaceMax == 0 //&&
            ( m_meshOutput->faces.size() - ixTargetFaceMax == 0 )
        )
        {
            if ( is_root ) dbgprint.printf ( 0, "Overlap mesh forward correspondence found\n" );
        }
        else if (
            // m_meshOutput->faces.size() - ixSourceFaceMax == 0 //&&
            ( m_meshInputCov->faces.size() - ixTargetFaceMax == 0 )
        )
        {   // Check for reverse correspondence in overlap mesh
            if ( is_root ) dbgprint.printf ( 0, "Overlap mesh reverse correspondence found (reversing)\n" );

            // Reorder overlap mesh
            m_meshOverlap->ExchangeFirstAndSecondMesh();
        }
        else
        {   // No correspondence found
            _EXCEPTION4 ( "Invalid overlap mesh:\n"
                          "    No correspondence found with input and output meshes (%i,%i) vs (%i,%i)",
                          m_meshInputCov->faces.size(), m_meshOutput->faces.size(), ixSourceFaceMax, ixTargetFaceMax );
        }
        */

        // 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 (pcomm) MPI_Allreduce ( &dTotalAreaOverlap_loc, &dTotalAreaOverlap, 1, MPI_DOUBLE, MPI_SUM, pcomm->comm() );
#endif
        if ( is_root ) dbgprint.printf ( 0, "Overlap Mesh Area: %1.15e\n", dTotalAreaOverlap );

        // Partial cover
        if ( fabs ( dTotalAreaOverlap - dTotalAreaInput ) > 1.0e-10 )
        {
            if ( !fNoCheck )
            {
                if ( is_root ) dbgprint.printf ( 0, "WARNING: Significant mismatch between overlap mesh area "
                                                            "and input mesh area.\n  Automatically enabling --nocheck\n" );
                fNoCheck = true;
            }
        }

        /*
            // 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
            m_meshInputCov->ConstructReverseNodeArray();
            m_meshInputCov->ConstructEdgeMap();

            // 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 OfflineMap
            if ( is_root ) dbgprint.printf ( 0, "Calculating offline map\n" );
            LinearRemapFVtoFV_Tempest_MOAB ( nPin );
        }
        else if ( eInputType == DiscretizationType_FV )
        {
            DataMatrix3D<double> dataGLLJacobian;

            if ( is_root ) dbgprint.printf ( 0, "Generating output mesh meta data\n" );
            double dNumericalArea_loc =
                GenerateMetaData (
                    *m_meshOutput,
                    nPout,
                    fBubble,
                    dataGLLNodesDest,
                    dataGLLJacobian );

            double dNumericalArea = dNumericalArea_loc;
#ifdef MOAB_HAVE_MPI
            if (pcomm) MPI_Allreduce ( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 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, 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
            m_meshInputCov->ConstructReverseNodeArray();
            m_meshInputCov->ConstructEdgeMap();

            // 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 ( is_root ) dbgprint.printf ( 0, "Calculating offline map\n" );

            if ( fVolumetric )
            {
                LinearRemapFVtoGLL_Volumetric_MOAB (
                    dataGLLNodesDest,
                    dataGLLJacobian,
                    this->GetTargetAreas(),
                    nPin,
                    nMonotoneType,
                    fContinuous,
                    fNoConservation );
            }
            else
            {
                LinearRemapFVtoGLL_MOAB (
                    dataGLLNodesDest,
                    dataGLLJacobian,
                    this->GetTargetAreas(),
                    nPin,
                    nMonotoneType,
                    fContinuous,
                    fNoConservation );
            }
        }
        else if (
            ( eInputType != DiscretizationType_FV ) &&
            ( eOutputType == DiscretizationType_FV )
        )
        {
            DataMatrix3D<double> dataGLLJacobianSrc, dataGLLJacobian;

            if ( is_root ) dbgprint.printf ( 0, "Generating input mesh meta data\n" );
            // double dNumericalAreaCov_loc =
                GenerateMetaData (
                    *m_meshInputCov,
                    nPin,
                    fBubble,
                    dataGLLNodesSrcCov,
                    dataGLLJacobian );

            double dNumericalArea_loc =
                GenerateMetaData (
                    *m_meshInput,
                    nPin,
                    fBubble,
                    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 (pcomm) MPI_Allreduce ( &dNumericalArea_loc, &dNumericalArea, 1, MPI_DOUBLE, MPI_SUM, 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, nPin, dataGLLNodesSrcCov );
            this->InitializeSourceCoordinatesFromMeshFE (
                *m_meshInput, nPin, dataGLLNodesSrc );
            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 offline map
            if ( is_root ) dbgprint.printf ( 0, "Calculating offline map\n" );

            if ( fVolumetric )
            {
                _EXCEPTIONT ( "Unimplemented: Volumetric currently unavailable for"
                              "GLL input mesh" );
            }

            LinearRemapSE4_Tempest_MOAB (
                dataGLLNodesSrcCov,
                dataGLLJacobian,
                nMonotoneType,
                fContinuousIn,
                fNoConservation
            );

        }
        else if (
            ( eInputType  != DiscretizationType_FV ) &&
            ( eOutputType != DiscretizationType_FV )
        )
        {
            DataMatrix3D<double> dataGLLJacobianIn, dataGLLJacobianSrc;
            DataMatrix3D<double> dataGLLJacobianOut;

            // Input metadata
            if ( is_root ) dbgprint.printf ( 0, "Generating input mesh meta data" );
            double dNumericalAreaIn_loc =
                GenerateMetaData (
                    *m_meshInputCov,
                    nPin,
                    fBubble,
                    dataGLLNodesSrcCov,
                    dataGLLJacobianIn );

            double dNumericalAreaSrc_loc =
                GenerateMetaData (
                    *m_meshInput,
                    nPin,
                    fBubble,
                    dataGLLNodesSrc,
                    dataGLLJacobianSrc );

            assert(dNumericalAreaIn_loc >= dNumericalAreaSrc_loc);

            double dNumericalAreaIn = dNumericalAreaSrc_loc;
#ifdef MOAB_HAVE_MPI
            if (pcomm) MPI_Allreduce ( &dNumericalAreaSrc_loc, &dNumericalAreaIn, 1, MPI_DOUBLE, MPI_SUM, pcomm->comm() );
#endif
            if ( is_root ) dbgprint.printf ( 0, "Input Mesh Numerical Area: %1.15e", dNumericalAreaIn );

            if ( fabs ( dNumericalAreaIn - dTotalAreaInput ) > 1.0e-12 )
            {
                dbgprint.printf ( 0, "WARNING: Significant mismatch between input mesh "
                                  "numerical area and geometric area" );
            }

            // Output metadata
            if ( is_root ) dbgprint.printf ( 0, "Generating output mesh meta data" );
            double dNumericalAreaOut_loc =
                GenerateMetaData (
                    *m_meshOutput,
                    nPout,
                    fBubble,
                    dataGLLNodesDest,
                    dataGLLJacobianOut );

            double dNumericalAreaOut = dNumericalAreaOut_loc;
#ifdef MOAB_HAVE_MPI
            if (pcomm) MPI_Allreduce ( &dNumericalAreaOut_loc, &dNumericalAreaOut, 1, MPI_DOUBLE, MPI_SUM, pcomm->comm() );
#endif
            if ( is_root ) dbgprint.printf ( 0, "Output Mesh Numerical Area: %1.15e", 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" );
            }

            // Initialize coordinates for map
            this->InitializeSourceCoordinatesFromMeshFE (
                *m_meshInputCov, nPin, dataGLLNodesSrcCov );
            this->InitializeSourceCoordinatesFromMeshFE (
                *m_meshInput, nPin, dataGLLNodesSrc );
            this->InitializeTargetCoordinatesFromMeshFE (
                *m_meshOutput, 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 offline map
            if ( is_root ) dbgprint.printf ( 0, "Calculating offline map" );

            LinearRemapGLLtoGLL2_MOAB (
                dataGLLNodesSrcCov,
                dataGLLJacobianIn,
                dataGLLNodesDest,
                dataGLLJacobianOut,
                this->GetTargetAreas(),
                nPin,
                nPout,
                nMonotoneType,
                fContinuousIn,
                fContinuousOut,
                fNoConservation
            );

        }
        else
        {
            _EXCEPTIONT ( "Not implemented" );
        }

#ifdef MOAB_HAVE_EIGEN
        CopyTempestSparseMat_Eigen();
#endif

        // Verify consistency, conservation and monotonicity
        // gather weights to root process to perform consistency/conservation checks
        if ( !fNoCheck && false)
        {
            if ( !m_globalMapAvailable && size > 1 ) {
                // gather weights to root process to perform consistency/conservation checks
                rval = this->GatherAllToRoot();MB_CHK_ERR(rval);
            }

            if ( is_root ) dbgprint.printf ( 0, "Verifying map" );
            this->IsConsistent ( 1.0e-8 );
            if ( !fNoConservation ) this->IsConservative ( 1.0e-8 );

            if ( nMonotoneType != 0 )
            {
                this->IsMonotone ( 1.0e-12 );
            }
        }

        // Apply Offline Map to data
        if ( strInputData != "" )
        {
            if ( is_root ) dbgprint.printf ( 0, "Applying offline map to data\n" );

            this->SetFillValueOverride ( static_cast<float> ( dFillValueOverride ) );
            this->Apply (
                strInputData,
                strOutputData,
                vecVariableStrings,
                strNColName,
                fOutputDouble,
                false );
        }

        // Copy variables from input file to output file
        if ( ( strInputData != "" ) && ( strOutputData != "" ) )
        {
            if ( fPreserveAll )
            {
                if ( is_root ) dbgprint.printf ( 0, "Preserving variables" );
                this->PreserveAllVariables ( strInputData, strOutputData );

            }
            else if ( vecPreserveVariableStrings.size() != 0 )
            {
                if ( is_root ) dbgprint.printf ( 0, "Preserving variables" );
                this->PreserveVariables (
                    strInputData,
                    strOutputData,
                    vecPreserveVariableStrings );
            }
        }

    }
    catch ( Exception & e )
    {
        dbgprint.printf ( 0, "%s", e.ToString().c_str() );
        return ( moab::MB_FAILURE );

    }
    catch ( ... )
    {
        return ( moab::MB_FAILURE );
    }
    return moab::MB_SUCCESS;
}
const DataVector< double > & moab::TempestOfflineMap::GetGlobalSourceAreas ( ) const [inline]

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

Definition at line 432 of file TempestOfflineMap.hpp.

References m_weightMapGlobal.

                                                                        {
#ifdef MOAB_HAVE_MPI
  if (pcomm->size() > 1) {
        return m_weightMapGlobal->GetSourceAreas();
    }
    else {
        return this->GetSourceAreas();
    }
#else
  return this->GetSourceAreas();
#endif
}
const DataVector< double > & moab::TempestOfflineMap::GetGlobalTargetAreas ( ) const [inline]

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

Definition at line 446 of file TempestOfflineMap.hpp.

References m_weightMapGlobal.

                                                                        {
#ifdef MOAB_HAVE_MPI
  if (pcomm->size() > 1) {
        return m_weightMapGlobal->GetTargetAreas();
    }
    else {
        return this->GetTargetAreas();
    }
#else
  return this->GetTargetAreas();
#endif
}
bool moab::TempestOfflineMap::IsConservative ( double  dTolerance) [virtual]

Determine if the map is conservative.

Definition at line 1192 of file TempestOfflineMap.cpp.

References rank, and size.

{
    // Get map entries
    DataVector<int> dataRows;
    DataVector<int> dataCols;
    DataVector<double> dataEntries;
    const DataVector<double>& dTargetAreas = this->GetGlobalTargetAreas();
    const DataVector<double>& dSourceAreas = this->GetGlobalSourceAreas();

    // Calculate column sums
    DataVector<double> dColumnSums;
    if ( size > 1 )
    {
        if ( rank ) return true;
        SparseMatrix<double>& m_mapRemapGlobal = m_weightMapGlobal->GetSparseMatrix();
        m_mapRemapGlobal.GetEntries ( dataRows, dataCols, dataEntries );
        dColumnSums.Initialize ( m_mapRemapGlobal.GetColumns() );
    }
    else
    {
        m_mapRemap.GetEntries ( dataRows, dataCols, dataEntries );
        dColumnSums.Initialize ( m_mapRemap.GetColumns() );
    }

    for ( unsigned i = 0; i < dataRows.GetRows(); i++ )
    {
        dColumnSums[dataCols[i]] +=
            dataEntries[i] * dTargetAreas[dataRows[i]];
    }

    // Verify all column sums equal the input Jacobian
    bool fConservative = true;
    for ( unsigned i = 0; i < dColumnSums.GetRows(); i++ )
    {
        if ( fabs ( dColumnSums[i] - dSourceAreas[i] ) > dTolerance )
        {
            fConservative = false;
            Announce ( "TempestOfflineMap is not conservative in column "
                       "%i (%1.15e / %1.15e)",
                       i, dColumnSums[i], dSourceAreas[i] );
        }
    }

    return fConservative;
}
bool moab::TempestOfflineMap::IsConsistent ( double  dTolerance) [virtual]

Generate the metadata associated with the offline map.

Read the OfflineMap from a NetCDF file. Write the TempestOfflineMap to a parallel NetCDF file. Determine if the map is first-order accurate.

Definition at line 1146 of file TempestOfflineMap.cpp.

References rank, and size.

{
    // Get map entries
    DataVector<int> dataRows;
    DataVector<int> dataCols;
    DataVector<double> dataEntries;

    // Calculate row sums
    DataVector<double> dRowSums;
    if ( size > 1 )
    {
        if ( rank ) return true;
        SparseMatrix<double>& m_mapRemapGlobal = m_weightMapGlobal->GetSparseMatrix();
        m_mapRemapGlobal.GetEntries ( dataRows, dataCols, dataEntries );
        dRowSums.Initialize ( m_mapRemapGlobal.GetRows() );
    }
    else
    {
        m_mapRemap.GetEntries ( dataRows, dataCols, dataEntries );
        dRowSums.Initialize ( m_mapRemap.GetRows() );
    }

    for ( unsigned i = 0; i < dataRows.GetRows(); i++ )
    {
        dRowSums[dataRows[i]] += dataEntries[i];
    }

    // Verify all row sums are equal to 1
    bool fConsistent = true;
    for ( unsigned i = 0; i < dRowSums.GetRows(); i++ )
    {
        if ( fabs ( dRowSums[i] - 1.0 ) > dTolerance )
        {
            fConsistent = false;
            Announce ( "TempestOfflineMap is not consistent in row %i (%1.15e)",
                       i, dRowSums[i] );
        }
    }

    return fConsistent;
}
bool moab::TempestOfflineMap::IsMonotone ( double  dTolerance) [virtual]

Determine if the map is monotone.

Definition at line 1242 of file TempestOfflineMap.cpp.

References rank, and size.

{
    // Get map entries
    DataVector<int> dataRows;
    DataVector<int> dataCols;
    DataVector<double> dataEntries;

    if ( size > 1 )
    {
        if ( rank ) return true;
        SparseMatrix<double>& m_mapRemapGlobal = m_weightMapGlobal->GetSparseMatrix();
        m_mapRemapGlobal.GetEntries ( dataRows, dataCols, dataEntries );
    }
    else
        m_mapRemap.GetEntries ( dataRows, dataCols, dataEntries );

    // Verify all entries are in the range [0,1]
    bool fMonotone = true;
    for ( unsigned i = 0; i < dataRows.GetRows(); i++ )
    {
        if ( ( dataEntries[i] < -dTolerance ) ||
                ( dataEntries[i] > 1.0 + dTolerance )
           )
        {
            fMonotone = false;

            Announce ( "TempestOfflineMap is not monotone in entry (%i): %1.15e",
                       i, dataEntries[i] );
        }
    }

    return fMonotone;
}

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

Definition at line 251 of file TempestLinearRemap.cpp.

References BuildFitArray(), BuildIntegrationArray(), GetAdjacentFaceVectorByEdge(), InvertFitArray_Corrected(), is_root, ixOverlap, m_meshInputCov, m_meshOutput, and m_meshOverlap.

{
    // Order of triangular quadrature rule
    const int TriQuadRuleOrder = 4;

    // Verify ReverseNodeArray has been calculated
    if ( 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
    if ( is_root )
    {
        Announce ( "[moab::TempestOfflineMap::LinearRemapFVtoFV_Tempest_MOAB] Finite Volume to Finite Volume Projection" );
        Announce ( "Triangular quadrature rule order %i", TriQuadRuleOrder );
        Announce ( "Number of coefficients: %i", nCoefficients );
        Announce ( "Required adjacency set size: %i", nRequiredFaceSetSize );
        Announce ( "Fit weights exponent: %i", nFitWeightsExponent );
    }

    // Current overlap face
    int ixOverlap = 0;

#ifdef VERBOSE
    const unsigned outputFrequency = (m_meshInputCov->faces.size()/10);
#endif
    // Loop through all faces on m_meshInput
    for ( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
    {
#ifdef VERBOSE
        // Output every 1000 elements
        if ( ixFirst % outputFrequency == 0 )
        {
            Announce ( "Element %i/%i", ixFirst, m_meshInputCov->faces.size() );
        }
#endif
        // This Face

        // 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 ( is_root ) Announce ( "Element %i / %i :: [%i, %i]", ixFirst, m_meshInputCov->faces.size(), ixOverlapBegin, ixOverlapEnd );

        if ( nOverlapFaces == 0 ) continue;

        // Build integration array
        DataMatrix<double> dIntArray;

        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
        DataVector<double> dConstraint;

        dConstraint.Initialize ( nCoefficients );

        double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];

        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
        DataMatrix<double> dFitArray;
        DataVector<double> dFitWeights;
        DataMatrix<double> dFitArrayPlus;

        BuildFitArray (
            *m_meshInputCov,
            triquadrule,
            ixFirst,
            vecAdjFaces,
            nOrder,
            nFitWeightsExponent,
            dConstraint,
            dFitArray,
            dFitWeights
        );

        // Compute the inverse fit array
        InvertFitArray_Corrected (
            dConstraint,
            dFitArray,
            dFitWeights,
            dFitArrayPlus
        );

        // Multiply integration array and fit array
        DataMatrix<double> dComposedArray;
        dComposedArray.Initialize ( nAdjFaces, nOverlapFaces );

        for ( int i = 0; i < nAdjFaces; i++ )
        {
            for ( unsigned j = 0; j < nOverlapFaces; j++ )
            {
                for ( int k = 0; k < nCoefficients; k++ )
                {
                    dComposedArray[i][j] += dIntArray[k][j] * dFitArrayPlus[i][k];
                }
            }
        }

        // 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);

                m_mapRemap ( ixSecondFaceLoc, ixFirstFaceLoc ) +=
                    dComposedArray[i][j]
                    / m_meshOutput->vecFaceArea[ixSecondFaceLoc];
            }
        }

        // Increment the current overlap index
        ixOverlap += nOverlapFaces;
    }

    return;
}
void moab::TempestOfflineMap::LinearRemapFVtoGLL_MOAB ( const DataMatrix3D< int > &  dataGLLNodes,
const DataMatrix3D< double > &  dataGLLJacobian,
const DataVector< double > &  dataGLLNodalArea,
int  nOrder,
int  nMonotoneType,
bool  fContinuous,
bool  fNoConservation 
) [private]

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

Definition at line 2026 of file TempestLinearRemap.cpp.

References BuildFitArray(), dgesv_(), moab::GeomUtil::first(), ForceIntArrayConsistencyConservation(), GetAdjacentFaceVectorByEdge(), GetReferenceNode_MOAB(), InvertFitArray_Corrected(), ixOverlap, n, size, and t.

{
    // NOTE: Reducing this quadrature rule order greatly affects error norms
    // Order of triangular quadrature rule
    const int TriQuadRuleOrder = 8;

    // Verify ReverseNodeArray has been calculated
    if ( m_meshInputCov->revnodearray.size() == 0 )
    {
        _EXCEPTIONT ( "ReverseNodeArray has not been calculated for m_meshInput" );
    }
    if ( m_meshInputCov->edgemap.size() == 0 )
    {
        _EXCEPTIONT ( "EdgeMap has not been calculated for m_meshInput" );
    }

    // Triangular quadrature rule
    TriangularQuadratureRule triquadrule ( TriQuadRuleOrder );

    const DataMatrix<double> & dG = triquadrule.GetG();
    const DataVector<double> & dW = triquadrule.GetW();

    // Get SparseMatrix represntation of the OfflineMap
    SparseMatrix<double> & smatMap = this->GetSparseMatrix();

    // Fit weight exponent
    int nFitWeightsExponent = nOrder + 2;

    // Order of the finite element method
    int nP = dataGLLNodes.GetRows();

    // Sample coefficients
    DataMatrix<double> dSampleCoeff;
    dSampleCoeff.Initialize ( nP, nP );

    // Number of elements needed
#ifdef RECTANGULAR_TRUNCATION
    int nCoefficients = nOrder * nOrder;
#endif
#ifdef TRIANGULAR_TRUNCATION
    int nCoefficients = nOrder * ( nOrder + 1 ) / 2;
#endif

    int nRequiredFaceSetSize = nCoefficients;

    // Announcemnets
    if ( is_root )
    {
        Announce ( "[moab::TempestOfflineMap::LinearRemapFVtoGLL_MOAB] Finite Volume to Finite Element Projection" );
        Announce ( "Triangular quadrature rule order %i", TriQuadRuleOrder );
        Announce ( "Order of the FE polynomial interpolant: %i", nP );
        Announce ( "Number of coefficients: %i", nCoefficients );
        Announce ( "Required adjacency set size: %i", nRequiredFaceSetSize );
        Announce ( "Fit weights exponent: %i", nFitWeightsExponent );
    }

    // Current overlap face
    int ixOverlap = 0;

    // Build the integration array for each element on m_meshOverlap
    DataMatrix3D<double> dGlobalIntArray;
    dGlobalIntArray.Initialize (
        nCoefficients,
        m_meshOverlap->faces.size(),
        nP * nP );

    // Number of overlap Faces per source Face
    DataVector<int> nAllOverlapFaces;
    nAllOverlapFaces.Initialize ( m_meshInputCov->faces.size() );

    // DataVector<int> nAllTotalOverlapTriangles;
    // nAllTotalOverlapTriangles.Initialize ( m_meshInputCov->faces.size() );

    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]++;
            // nAllTotalOverlapTriangles[ixFirst] += faceOverlap.edges.size() - 2;
        }

        // Increment the current overlap index
        ixOverlap += nAllOverlapFaces[ixFirst];
    }

    // Loop through all faces on m_meshInput
    ixOverlap = 0;
#ifdef VERBOSE
    const unsigned outputFrequency = (m_meshInputCov->faces.size()/10);
#endif

    for ( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
    {
#ifdef VERBOSE
        // Announce computation progress
        if ( ixFirst % outputFrequency == 0 && is_root )
        {
            Announce ( "Element %i/%i", ixFirst, m_meshInputCov->faces.size() );
        }
#endif

        // This Face
        const Face & faceFirst = m_meshInputCov->faces[ixFirst];

        // Area of the First Face
        // double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];

        // Coordinate axes
        Node nodeRef = GetReferenceNode_MOAB ( faceFirst, m_meshInputCov->nodes );

        Node nodeA1 = m_meshInputCov->nodes[faceFirst[1]] - nodeRef;
        Node nodeA2 = m_meshInputCov->nodes[faceFirst[2]] - nodeRef;

        Node nodeC = CrossProduct ( nodeA1, nodeA2 );

        // Fit matrix
        DataMatrix<double> dFit;
        dFit.Initialize ( 3, 3 );

        dFit[0][0] = nodeA1.x; dFit[0][1] = nodeA1.y; dFit[0][2] = nodeA1.z;
        dFit[1][0] = nodeA2.x; dFit[1][1] = nodeA2.y; dFit[1][2] = nodeA2.z;
        dFit[2][0] = nodeC.x;  dFit[2][1] = nodeC.y;  dFit[2][2] = nodeC.z;

        // Number of overlapping Faces and triangles
        int nOverlapFaces = nAllOverlapFaces[ixFirst];
        // int nTotalOverlapTriangles = nAllTotalOverlapTriangles[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;

            int nOverlapTriangles = faceOverlap.edges.size() - 2;

            // Quantities from the Second Mesh
            int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];

            const NodeVector & nodesSecond = m_meshOutput->nodes;

            const Face & faceSecond = m_meshOutput->faces[ixSecond];

            // Loop over all sub-triangles of this Overlap Face
            for ( int j = 0; j < nOverlapTriangles; j++ )
            {
                // Cornerpoints of triangle
                const Node & node0 = nodesOverlap[faceOverlap[0]];
                const Node & node1 = nodesOverlap[faceOverlap[j + 1]];
                const Node & node2 = nodesOverlap[faceOverlap[j + 2]];

                // Calculate the area of the modified Face
                Face faceTri ( 3 );
                faceTri.SetNode ( 0, faceOverlap[0] );
                faceTri.SetNode ( 1, faceOverlap[j + 1] );
                faceTri.SetNode ( 2, faceOverlap[j + 2] );

                double dTriArea =
                    CalculateFaceArea ( faceTri, nodesOverlap );

                for ( int k = 0; k < triquadrule.GetPoints(); k++ )
                {
                    double * dGL = dG[k];

                    // Get the nodal location of this point
                    double dX[3];

                    dX[0] = dGL[0] * node0.x + dGL[1] * node1.x + dGL[2] * node2.x;
                    dX[1] = dGL[0] * node0.y + dGL[1] * node1.y + dGL[2] * node2.y;
                    dX[2] = dGL[0] * node0.z + dGL[1] * node1.z + dGL[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] );

                    dX[0] -= nodeRef.x;
                    dX[1] -= nodeRef.y;
                    dX[2] -= nodeRef.z;

                    // Find the coefficients for this point of the polynomial
                    int n = 3;
                    int nrhs = 1;
                    int lda = 3;
                    int ipiv[3];
                    int ldb = 3;
                    int info;

                    DataMatrix<double> dFitTemp;
                    dFitTemp = dFit;
                    dgesv_ (
                        &n, &nrhs, & ( dFitTemp[0][0] ), &lda, ipiv, dX, &ldb, &info );

                    // Find the components of this quadrature point in the basis
                    // of the finite element.
                    double dAlpha;
                    double dBeta;

                    ApplyInverseMap (
                        faceSecond,
                        nodesSecond,
                        nodeQuadrature,
                        dAlpha,
                        dBeta );
                    /*
                        // Check inverse map value
                        if ((dAlpha < -1.0e-12) || (dAlpha > 1.0 + 1.0e-12) ||
                            (dBeta  < -1.0e-12) || (dBeta  > 1.0 + 1.0e-12)
                        ) {
                            _EXCEPTION2("Inverse Map out of range (%1.5e %1.5e)",
                                dAlpha, dBeta);
                        }
                    */
                    // Sample the finite element at this point
                    SampleGLLFiniteElement (
                        nMonotoneType,
                        nP,
                        dAlpha,
                        dBeta,
                        dSampleCoeff );

                    // Sample this point in the GLL element
                    int ixs = 0;
                    for ( int s = 0; s < nP; s++ )
                    {
                        for ( int t = 0; t < nP; t++ )
                        {
                            int ixp = 0;

                            for ( int p = 0; p < nOrder; p++ )
                            {
#ifdef TRIANGULAR_TRUNCATION
                                const int redOrder = p;
#else
                                const int redOrder = 0;
#endif
                                for ( int q = 0; q < nOrder - redOrder; q++ )
                                {
                                    dGlobalIntArray[ixp][ixOverlap + i][ixs] +=
                                        dSampleCoeff[s][t]
                                        * IPow ( dX[0], p )
                                        * IPow ( dX[1], q )
                                        * dW[k]
                                        * dTriArea
                                        / dataGLLJacobian[s][t][ixSecond];

                                    ixp++;
                                }
                            }
                            ixs++;
                        }
                    }
                }
            }
        }

        // Increment the current overlap index
        ixOverlap += nOverlapFaces;
    }

    // Reverse map
    std::vector< std::vector<int> > vecReverseFaceIx;
    vecReverseFaceIx.resize ( m_meshOutput->faces.size() );
    for ( size_t i = 0; i < m_meshOverlap->faces.size(); i++ )
    {
        int ixSecond = m_meshOverlap->vecTargetFaceIx[i];

        vecReverseFaceIx[ixSecond].push_back ( i );
    }

    // Force consistency and conservation
    for ( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
    {
        if ( vecReverseFaceIx[ixSecond].size() == 0 )
            continue;

        DataMatrix<double> dCoeff;
        dCoeff.Initialize (
            nP * nP,
            vecReverseFaceIx[ixSecond].size() );

        for ( size_t i = 0; i < vecReverseFaceIx[ixSecond].size(); i++ )
        {
            int ijxOverlap = vecReverseFaceIx[ixSecond][i];

            for ( int s = 0; s < nP * nP; s++ )
            {
                dCoeff[s][i] = dGlobalIntArray[0][ijxOverlap][s];
            }
        }

        // Target areas
        DataVector<double> vecTargetArea;
        vecTargetArea.Initialize ( nP * nP );

        for ( int s = 0; s < nP * nP; s++ )
        {
            vecTargetArea[s] =
                dataGLLJacobian[s / nP][s % nP][ixSecond];
        }

        // Source areas
        DataVector<double> vecSourceArea;
        vecSourceArea.Initialize ( vecReverseFaceIx[ixSecond].size() );

        for ( size_t i = 0; i < vecReverseFaceIx[ixSecond].size(); i++ )
        {
            int ijxOverlap = vecReverseFaceIx[ixSecond][i];
            vecSourceArea[i] = m_meshOverlap->vecFaceArea[ijxOverlap];
        }

        if ( !fNoConservation )
        {
            ForceIntArrayConsistencyConservation (
                vecSourceArea,
                vecTargetArea,
                dCoeff,
                ( nMonotoneType != 0 ) );
        }

        for ( size_t i = 0; i < vecReverseFaceIx[ixSecond].size(); i++ )
        {
            int ijxOverlap = vecReverseFaceIx[ixSecond][i];

            for ( int s = 0; s < nP * nP; s++ )
            {
                //printf("%1.15e %1.15e\n", dGlobalIntArray[0][ixOverlap][s], dCoeff[s][i]);
                dGlobalIntArray[0][ijxOverlap][s] = dCoeff[s][i];
            }
        }

    }

    // Construct finite-volume fit matrix and compose with integration operator
    ixOverlap = 0;

    for ( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
    {
#ifdef VERBOSE
        // Announce computation progress
        if ( ixFirst % outputFrequency == 0 )
        {
            Announce ( "Element %i", ixFirst );
        }
#endif

        // Area of the First Face
        double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];

        // Number of overlapping Faces and triangles
        int nOverlapFaces = nAllOverlapFaces[ixFirst];

        // Determine the conservative constraint equation
        DataVector<double> dConstraint;

        dConstraint.Initialize ( nCoefficients );

        for ( int p = 0; p < nCoefficients; p++ )
        {
            for ( int i = 0; i < nOverlapFaces; i++ )
            {
                int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];

                for ( int s = 0; s < nP * nP; s++ )
                {
                    dConstraint[p] += dGlobalIntArray[p][ixOverlap + i][s]
                                      * dataGLLJacobian[s / nP][s % nP][ixSecond]
                                      / dFirstArea;
                }
            }
        }

        // 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();

        for ( int x = 0; x < nAdjFaces; x++ )
        {
            if ( vecAdjFaces[x].first == ( -1 ) )
            {
                _EXCEPTION();
            }
        }

        // Build the fit operator
        DataMatrix<double> dFitArray;
        DataVector<double> dFitWeights;
        DataMatrix<double> dFitArrayPlus;

        BuildFitArray (
            *m_meshInputCov,
            triquadrule,
            ixFirst,
            vecAdjFaces,
            nOrder,
            nFitWeightsExponent,
            dConstraint,
            dFitArray,
            dFitWeights
        );

        // Compute the inverse fit array
        InvertFitArray_Corrected (
            dConstraint,
            dFitArray,
            dFitWeights,
            dFitArrayPlus
        );

        // Multiply integration array and fit array
        DataMatrix<double> dComposedArray;
        dComposedArray.Initialize ( nAdjFaces, nOverlapFaces * nP * nP );

        for ( int j = 0; j < nOverlapFaces; j++ )
        {
            // int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];

            for ( int i = 0; i < nAdjFaces; i++ )
            {
                for ( int s = 0; s < nP * nP; s++ )
                {
                    for ( int k = 0; k < nCoefficients; k++ )
                    {
                        dComposedArray[i][j * nP * nP + s] +=
                            dGlobalIntArray[k][ixOverlap + j][s]
                            * dFitArrayPlus[i][k];
                    }
                }
            }
        }

        // Put composed array into map
        for ( size_t i = 0; i < vecAdjFaces.size(); i++ )
        {
            for ( int j = 0; j < nOverlapFaces; j++ )
            {
                int ixFirstFace = vecAdjFaces[i].first;
                int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];

                for ( int s = 0; s < nP; s++ )
                {
                    for ( int t = 0; t < nP; t++ )
                    {

                        int jx = j * nP * nP + s * nP + t;

                        if ( fContinuous )
                        {
                            int ixSecondNode = dataGLLNodes[s][t][ixSecondFace] - 1;

                            smatMap ( ixSecondNode, ixFirstFace ) +=
                                dComposedArray[i][jx]
                                * dataGLLJacobian[s][t][ixSecondFace]
                                / dataGLLNodalArea[ixSecondNode];
                        }
                        else
                        {
                            int ixSecondNode = ixSecondFace * nP * nP + s * nP + t;

                            smatMap ( ixSecondNode, ixFirstFace ) +=
                                dComposedArray[i][jx];
                        }
                    }
                }
            }
        }

        ixOverlap += nOverlapFaces;
    }

    return;
}
void moab::TempestOfflineMap::LinearRemapFVtoGLL_Simple_MOAB ( const DataMatrix3D< int > &  dataGLLNodes,
const DataMatrix3D< double > &  dataGLLJacobian,
const DataVector< double > &  dataGLLNodalArea,
int  nOrder,
int  nMonotoneType,
bool  fContinuous,
bool  fNoConservation 
) [private]

Generate the OfflineMap for remapping from finite volumes to finite elements using simple sampling of the FV reconstruction.

Definition at line 1307 of file TempestLinearRemap.cpp.

References BuildFitArray(), dgesv_(), GetAdjacentFaceVectorByEdge(), GetReferenceNode_MOAB(), InvertFitArray_Corrected(), ixOverlap, n, and t.

{
    // Order of triangular quadrature rule
    const int TriQuadRuleOrder = 8;

    // Verify ReverseNodeArray has been calculated
    if ( m_meshInputCov->revnodearray.size() == 0 )
    {
        _EXCEPTIONT ( "ReverseNodeArray has not been calculated for m_meshInput" );
    }
    if ( m_meshInputCov->edgemap.size() == 0 )
    {
        _EXCEPTIONT ( "EdgeMap has not been calculated for m_meshInput" );
    }

    // Get SparseMatrix represntation of the OfflineMap
    SparseMatrix<double> & smatMap = this->GetSparseMatrix();

    // Fit weight exponent
    int nFitWeightsExponent = nOrder + 2;

    // Order of the finite element method
    int nP = dataGLLNodes.GetRows();

    // Announcemnets
    if ( is_root )
    {
        Announce ( "[moab::TempestOfflineMap::LinearRemapFVtoGLL_Simple_MOAB] Finite Volume to Finite Element (Simple) Projection" );
        Announce ( "Triangular quadrature rule order %i", TriQuadRuleOrder );
        Announce ( "Order of the FE polynomial interpolant: %i", nP );
    }

    // Mesh utilities
    MeshUtilitiesFuzzy meshutil;

    // GLL nodes
    DataVector<double> dG;
    DataVector<double> dW;

    GaussLobattoQuadrature::GetPoints ( nP, 0.0, 1.0, dG, dW );

    // Triangular quadrature rule
    TriangularQuadratureRule triquadrule ( TriQuadRuleOrder );

    // Number of elements needed
#ifdef RECTANGULAR_TRUNCATION
    int nCoefficients = nOrder * nOrder;
#endif
#ifdef TRIANGULAR_TRUNCATION
    int nCoefficients = nOrder * ( nOrder + 1 ) / 2;
#endif

    int nRequiredFaceSetSize = nCoefficients;

    // Set of found nodes
    std::set<int> setFoundNodes;

    // Loop through all faces on m_meshInput
    int ixOverlap = 0;
#ifdef VERBOSE
    const unsigned outputFrequency = (m_meshInputCov->faces.size()/10);
#endif

    for ( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
    {
#ifdef VERBOSE
        // Announce computation progress
        if ( ixFirst % outputFrequency == 0 )
        {
            Announce ( "Element %i", ixFirst );
        }
#endif

        // This Face
        const Face & faceFirst = m_meshInputCov->faces[ixFirst];

        // Coordinate axes
        Node nodeRef = GetReferenceNode_MOAB ( faceFirst, m_meshInputCov->nodes );

        Node nodeA1 = m_meshInputCov->nodes[faceFirst[1]] - nodeRef;
        Node nodeA2 = m_meshInputCov->nodes[faceFirst[2]] - nodeRef;

        Node nodeC = CrossProduct ( nodeA1, nodeA2 );

        // Fit matrix
        DataMatrix<double> dFit;
        dFit.Initialize ( 3, 3 );

        dFit[0][0] = nodeA1.x; dFit[0][1] = nodeA1.y; dFit[0][2] = nodeA1.z;
        dFit[1][0] = nodeA2.x; dFit[1][1] = nodeA2.y; dFit[1][2] = nodeA2.z;
        dFit[2][0] = nodeC.x;  dFit[2][1] = nodeC.y;  dFit[2][2] = nodeC.z;

        // Set of Faces to use in building the reconstruction and associated
        // distance metric.
        AdjacentFaceVector vecAdjFaces;

        GetAdjacentFaceVectorByEdge (
            *m_meshInputCov,
            ixFirst,
            nRequiredFaceSetSize,
            vecAdjFaces );

        // Blank constraint
        DataVector<double> dConstraint;

        // Least squares arrays
        DataMatrix<double> dFitArray;
        DataVector<double> dFitWeights;
        DataMatrix<double> dFitArrayPlus;

        BuildFitArray (
            *m_meshInputCov,
            triquadrule,
            ixFirst,
            vecAdjFaces,
            nOrder,
            nFitWeightsExponent,
            dConstraint,
            dFitArray,
            dFitWeights
        );

        // Compute the inverse fit array
        InvertFitArray_Corrected (
            dConstraint,
            dFitArray,
            dFitWeights,
            dFitArrayPlus
        );

        // Number of overlapping Faces
        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++;
        }

        // 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];

            // Quantities from the Second Mesh
            int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];

            // const NodeVector & nodesSecond = m_meshOutput->nodes;

            const Face & faceSecond = m_meshOutput->faces[ixSecondFace];

            for ( int s = 0; s < nP; s++ )
            {
                for ( int t = 0; t < nP; t++ )
                {
                    // Determine if this Node is in faceFirst
                    Node node;
                    Node dDx1G;
                    Node dDx2G;

                    ApplyLocalMap (
                        faceSecond,
                        m_meshOutput->nodes,
                        dG[s],
                        dG[t],
                        node,
                        dDx1G,
                        dDx2G );

                    Face::NodeLocation loc;
                    int ixLocation;

                    meshutil.ContainsNode (
                        faceFirst,
                        m_meshInputCov->nodes,
                        node,
                        loc,
                        ixLocation );

                    if ( loc == Face::NodeLocation_Exterior )
                    {
                        continue;
                    }

                    // Second node index
                    int ixSecondNode;

                    if ( fContinuous )
                    {
                        ixSecondNode = dataGLLNodes[t][s][ixSecondFace] - 1;
                    }
                    else
                    {
                        ixSecondNode = ixSecondFace * nP * nP + s * nP + t;
                    }

                    // Avoid duplicates
                    if ( setFoundNodes.find ( ixSecondNode ) != setFoundNodes.end() )
                    {
                        continue;
                    }

                    setFoundNodes.insert ( ixSecondNode );

                    // Find the coefficients for this point
                    double dX[3];
                    dX[0] = node.x - nodeRef.x;
                    dX[1] = node.y - nodeRef.y;
                    dX[2] = node.z - nodeRef.z;

                    // if (ixSecondNode < 10) {

                    //  double dLon = atan2(node.y, node.x);
                    //  if (dLon < 0.0) {
                    //      dLon += 2.0 * M_PI;
                    //  }
                    //  double dLat = asin(node.z);

                    //  dLon *= 180.0 / M_PI;
                    //  dLat *= 180.0 / M_PI;

                    //  printf("%i %1.15e %1.15e\n", ixSecondNode, dLon, dLat);
                    // }

                    int n = 3;
                    int nrhs = 1;
                    int lda = 3;
                    int ipiv[3];
                    int ldb = 3;
                    int info;

                    DataMatrix<double> dFitTemp;
                    dFitTemp = dFit;
                    dgesv_ (
                        &n, &nrhs, & ( dFitTemp[0][0] ), &lda, ipiv, dX, &ldb, &info );

                    // Sample the reconstruction at this point
                    int ixp = 0;

#ifdef RECTANGULAR_TRUNCATION
                    for ( int p = 0; p < nOrder; p++ )
                    {
                        for ( int q = 0; q < nOrder; q++ )
                        {
#endif
#ifdef TRIANGULAR_TRUNCATION
                    for ( int p = 0; p < nOrder; p++ )
                    {
                        for ( int q = 0; q < nOrder - p; q++ )
                        {
#endif

                            for ( size_t nx = 0; nx < vecAdjFaces.size(); nx++ )
                            {
                                int ixAdjFace = vecAdjFaces[nx].first;

                                smatMap ( ixSecondNode, ixAdjFace ) +=
                                    IPow ( dX[0], p )
                                    * IPow ( dX[1], q )
                                    * dFitArrayPlus[nx][ixp];
                            }

                            ixp++;
                        }
                    }
                }
            }
        }
void moab::TempestOfflineMap::LinearRemapFVtoGLL_Volumetric_MOAB ( const DataMatrix3D< int > &  dataGLLNodes,
const DataMatrix3D< double > &  dataGLLJacobian,
const DataVector< double > &  dataGLLNodalArea,
int  nOrder,
int  nMonotoneType,
bool  fContinuous,
bool  fNoConservation 
) [private]

Generate the OfflineMap for remapping from finite volumes to finite elements using a new experimental method.

Definition at line 1601 of file TempestLinearRemap.cpp.

References BuildFitArray(), BuildIntegrationArray(), ForceIntArrayConsistencyConservation(), GetAdjacentFaceVectorByEdge(), InvertFitArray_Corrected(), ixOverlap, and n.

{
    // Order of triangular quadrature rule
    const int TriQuadRuleOrder = 4;

    // Verify ReverseNodeArray has been calculated
    if ( m_meshInputCov->revnodearray.size() == 0 )
    {
        _EXCEPTIONT ( "ReverseNodeArray has not been calculated for m_meshInput" );
    }

    // Triangular quadrature rule
    TriangularQuadratureRule triquadrule ( TriQuadRuleOrder );

    // Fit weight exponent
    int nFitWeightsExponent = nOrder + 2;

    // Order of the finite element method
    int nP = dataGLLNodes.GetRows();

    // Announcemnets
    if ( is_root )
    {
        Announce ( "[moab::TempestOfflineMap::LinearRemapFVtoGLL_Volumetric_MOAB] Finite Volume to Finite Element (Volumetric) Projection" );
        Announce ( "Triangular quadrature rule order %i", TriQuadRuleOrder );
        Announce ( "Order of the FE polynomial interpolant: %i", nP );
    }

    // Gauss-Lobatto quadrature nodes and weights
    DataVector<double> dG;
    DataVector<double> dW;

    GaussLobattoQuadrature::GetPoints ( nP, 0.0, 1.0, dG, dW );

    // Get SparseMatrix represntation of the OfflineMap
    SparseMatrix<double> & smatMap = this->GetSparseMatrix();

    // Number of elements needed
#ifdef RECTANGULAR_TRUNCATION
    int nCoefficients = nOrder * nOrder;
#endif
#ifdef TRIANGULAR_TRUNCATION
    int nCoefficients = nOrder * ( nOrder + 1 ) / 2;
#endif

// #pragma message "This should be a command-line parameter"
    int nRequiredFaceSetSize = nCoefficients;

    // Accumulated weight vector
    DataVector<double> dAccumW ( nP + 1 );
    dAccumW[0] = 0.0;
    for ( int i = 1; i < nP + 1; i++ )
    {
        dAccumW[i] = dAccumW[i - 1] + dW[i - 1];
    }
    if ( fabs ( dAccumW[dAccumW.GetRows() - 1] - 1.0 ) > 1.0e-14 )
    {
        _EXCEPTIONT ( "Logic error in accumulated weight" );
    }

    // Create sub-element mesh and redistribution map
    Announce ( "Generating sub-element mesh" );
    Mesh meshTargetSubElement;

    DataVector<double> dFiniteVolumeArea ( nP * nP );
    DataVector<double> dQuadratureArea ( nP * nP );
    std::vector< DataMatrix<double> > dRedistributionMaps;
    dRedistributionMaps.resize ( m_meshOutput->faces.size() );

    for ( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
    {

        const Face & faceSecond = m_meshOutput->faces[ixSecond];

        const Node & nodeOutput0 = m_meshOutput->nodes[faceSecond[0]];
        const Node & nodeOutput1 = m_meshOutput->nodes[faceSecond[1]];
        const Node & nodeOutput2 = m_meshOutput->nodes[faceSecond[2]];
        const Node & nodeOutput3 = m_meshOutput->nodes[faceSecond[3]];

        for ( int q = 0; q < nP; q++ )
        {
            for ( int p = 0; p < nP; p++ )
            {

                Node node0 =
                    InterpolateQuadrilateralNode (
                        nodeOutput0, nodeOutput1, nodeOutput2, nodeOutput3,
                        dAccumW[p], dAccumW[q] );

                Node node1 =
                    InterpolateQuadrilateralNode (
                        nodeOutput0, nodeOutput1, nodeOutput2, nodeOutput3,
                        dAccumW[p + 1], dAccumW[q] );

                Node node2 =
                    InterpolateQuadrilateralNode (
                        nodeOutput0, nodeOutput1, nodeOutput2, nodeOutput3,
                        dAccumW[p + 1], dAccumW[q + 1] );

                Node node3 =
                    InterpolateQuadrilateralNode (
                        nodeOutput0, nodeOutput1, nodeOutput2, nodeOutput3,
                        dAccumW[p], dAccumW[q + 1] );

                int nNodeStart = meshTargetSubElement.nodes.size();
                meshTargetSubElement.nodes.push_back ( node0 );
                meshTargetSubElement.nodes.push_back ( node1 );
                meshTargetSubElement.nodes.push_back ( node2 );
                meshTargetSubElement.nodes.push_back ( node3 );

                Face faceNew ( 4 );
                faceNew.SetNode ( 0, nNodeStart );
                faceNew.SetNode ( 1, nNodeStart + 1 );
                faceNew.SetNode ( 2, nNodeStart + 2 );
                faceNew.SetNode ( 3, nNodeStart + 3 );

                meshTargetSubElement.faces.push_back ( faceNew );

                dFiniteVolumeArea[q * nP + p] =
                    CalculateFaceArea (
                        faceNew, meshTargetSubElement.nodes );

                dQuadratureArea[q * nP + p] =
                    dataGLLJacobian[q][p][ixSecond];
            }
        }

        dRedistributionMaps[ixSecond].Initialize ( nP * nP, nP * nP );
        for ( int i = 0; i < nP * nP; i++ )
        {
            dRedistributionMaps[ixSecond][i][i] = 1.0;
        }

        if ( !fNoConservation )
        {
            ForceIntArrayConsistencyConservation (
                dFiniteVolumeArea,
                dQuadratureArea,
                dRedistributionMaps[ixSecond],
                ( nMonotoneType != 0 ) );
        }
        /*
                double dSumQuadArea = 0.0;
                double dSumFVArea = 0.0;
                for (int i = 0; i < nP * nP; i++) {
                    dSumQuadArea += dQuadratureArea[i];
                    dSumFVArea += dFiniteVolumeArea[i];
                }
                if (fabs(dSumQuadArea - dSumFVArea) > 1.0e-14) {
                    printf("%1.15e\n", dSumQuadArea - dSumFVArea);
                    _EXCEPTION();
                }
        */
        for ( int i = 0; i < nP * nP; i++ )
        {
            for ( int j = 0; j < nP * nP; j++ )
            {
                dRedistributionMaps[ixSecond][i][j] *=
                    dQuadratureArea[i] / dFiniteVolumeArea[j];
            }
        }
        /*
                for (int i = 0; i < nP * nP; i++) {
                    double dSum = 0.0;
                    for (int j = 0; j < nP * nP; j++) {
                        dSum += dRedistributionMaps[ixSecond][i][j] * dFiniteVolumeArea[j];
                    }
                    printf("%i %1.15e %1.15e\n", i, dSum, dQuadratureArea[i]);
                }
                _EXCEPTION();
        */
        /*
                for (int i = 0; i < nP * nP; i++) {
                for (int j = 0; j < nP * nP; j++) {
                    printf("%i %i %1.15e\n", i, j, dRedistributionMaps[ixSecond][i][j]);
                }
                }
                _EXCEPTION();
        */
    }

    // Current overlap face
    int ixOverlap = 0;
#ifdef VERBOSE
    const unsigned outputFrequency = (m_meshInputCov->faces.size()/10);
#endif

    // Loop through all faces on m_meshInput
    for ( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
    {
#ifdef VERBOSE
        // Announce computation progress
        if ( ixFirst % outputFrequency == 0 )
        {
            Announce ( "Element %i", ixFirst );
        }
#endif

        // This Face
        // const Face & faceFirst = m_meshInputCov->faces[ixFirst];

        // Find the set of Faces that overlap faceFirst
        size_t ixOverlapBegin = ixOverlap;
        size_t ixOverlapEnd = ixOverlapBegin;

        for ( ; ixOverlapEnd < m_meshOverlap->faces.size(); ixOverlapEnd++ )
        {
            if ( ixFirst - m_meshOverlap->vecSourceFaceIx[ixOverlapEnd] != 0 )
                break;
        }

        size_t nOverlapFaces = ixOverlapEnd - ixOverlapBegin;

        // Create a new Mesh representing the division of target finite
        // elements associated with this finite volume.
        Mesh meshThisElement;
        meshThisElement.faces.reserve ( nOverlapFaces * nP * nP );
        meshThisElement.vecTargetFaceIx.reserve ( nOverlapFaces * nP * nP );

        for ( size_t i = ixOverlapBegin; i < ixOverlapEnd; i++ )
        {

            int iTargetFace = m_meshOverlap->vecTargetFaceIx[i];

            int iSubElementBegin =  iTargetFace      * nP * nP;
            // int iSubElementEnd   = ( iTargetFace + 1 ) * nP * nP;

            int iSubElement = iSubElementBegin;
            for ( int p = 0; p < nP; p++ )
            {
                for ( int q = 0; q < nP; q++ )
                {

                    // Calculate overlap polygon between sub-element
                    // and finite volume
                    NodeVector nodevecOutput;

                    GenerateOverlapFace<MeshUtilitiesFuzzy, Node> (
                        *m_meshInputCov,
                        meshTargetSubElement,
                        ixFirst,
                        iSubElementBegin + p * nP + q,
                        nodevecOutput );
                    /*
                                    if (nodevecOutput.size() < 3) {
                                        continue;
                                    }

                                    Face faceNew(nodevecOutput.size());
                                    for (int n = 0; n < nodevecOutput.size(); n++) {
                                        faceNew.SetNode(n, n);
                                    }
                                    Real dArea = CalculateFaceArea(faceNew, nodevecOutput);

                                    if (dArea < 1.0e-13) {
                                        continue;
                                    }
                    */
                    /*
                                    if (dataGLLNodes[p][q][iTargetFace] - 1 == 3) {
                                        printf("%1.15e %1.15e %1.15e\n", dArea, dataGLLJacobian[p][q][iTargetFace], dataGLLNodalArea[dataGLLNodes[p][q][iTargetFace] - 1]);
                                    }
                    */
                    Face faceNew ( nodevecOutput.size() );
                    for ( size_t n = 0; n < nodevecOutput.size(); n++ )
                    {
                        meshThisElement.nodes.push_back ( nodevecOutput[n] );
                        faceNew.SetNode ( n, meshThisElement.nodes.size() - 1 );
                    }

                    meshThisElement.faces.push_back ( faceNew );

                    meshThisElement.vecTargetFaceIx.push_back (
                        dataGLLNodes[p][q][iTargetFace] - 1 );

                    iSubElement++;
                }
            }
        }

        if ( meshThisElement.faces.size() != nOverlapFaces * nP * nP )
        {
            _EXCEPTIONT ( "Logic error" );
        }

        // Build integration array
        DataMatrix<double> dIntArray;

        BuildIntegrationArray (
            *m_meshInputCov,
            meshThisElement,
            triquadrule,
            ixFirst,
            0,
            meshThisElement.faces.size(),
            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
        DataVector<double> dConstraint;

        dConstraint.Initialize ( nCoefficients );

        double dFirstArea = m_meshInputCov->vecFaceArea[ixFirst];

        for ( int p = 0; p < nCoefficients; p++ )
        {
            for ( size_t j = 0; j < meshThisElement.faces.size(); j++ )
            {
                dConstraint[p] += dIntArray[p][j];
            }
            dConstraint[p] /= dFirstArea;
        }

        // Least squares arrays
        DataMatrix<double> dFitArray;
        DataVector<double> dFitWeights;
        DataMatrix<double> dFitArrayPlus;

        BuildFitArray (
            *m_meshInputCov,
            triquadrule,
            ixFirst,
            vecAdjFaces,
            nOrder,
            nFitWeightsExponent,
            dConstraint,
            dFitArray,
            dFitWeights
        );

        // Compute the inverse fit array
        InvertFitArray_Corrected (
            dConstraint,
            dFitArray,
            dFitWeights,
            dFitArrayPlus
        );

        // Multiply integration array and fit array
        DataMatrix<double> dComposedArray;
        dComposedArray.Initialize ( nAdjFaces, meshThisElement.faces.size() );

        for ( int i = 0; i < nAdjFaces; i++ )
        {
            for ( size_t j = 0; j < meshThisElement.faces.size(); j++ )
            {
                for ( int k = 0; k < nCoefficients; k++ )
                {
                    dComposedArray[i][j] += dIntArray[k][j] * dFitArrayPlus[i][k];
                }
            }
        }

        // Apply redistribution operator
        DataMatrix<double> dRedistributedArray;
        dRedistributedArray.Initialize ( nAdjFaces, meshThisElement.faces.size() );

        for ( int i = 0; i < nAdjFaces; i++ )
        {
            for ( size_t j = 0; j < meshThisElement.faces.size(); j++ )
            {
                int ixSubElement = j % ( nP * nP );
                int ixElement = j / ( nP * nP );

                int ixSecondFace =
                    m_meshOverlap->vecTargetFaceIx[ixOverlap + ixElement];

                for ( int k = 0; k < nP * nP; k++ )
                {
                    dRedistributedArray[i][j] +=
                        dComposedArray[i][ixElement * nP * nP + k]
                        * dRedistributionMaps[ixSecondFace][ixSubElement][k];
                }
            }
        }

        // Put composed array into map
        for ( size_t i = 0; i < vecAdjFaces.size(); i++ )
        {
            for ( size_t j = 0; j < meshThisElement.faces.size(); j++ )
            {
                int ixFirstFace = vecAdjFaces[i].first;
                int ixSecondNode = meshThisElement.vecTargetFaceIx[j];

                smatMap ( ixSecondNode, ixFirstFace ) +=
                    dRedistributedArray[i][j]
                    / dataGLLNodalArea[ixSecondNode];
                // meshThisElement.vecFaceArea[j];
                // dataGLLJacobian[ixS][ixT][ixSecondElement];
            }
        }

        // Increment the current overlap index
        ixOverlap += nOverlapFaces;

        //_EXCEPTION();
    }

    return;
}
void moab::TempestOfflineMap::LinearRemapGLLtoGLL2_MOAB ( const DataMatrix3D< int > &  dataGLLNodesIn,
const DataMatrix3D< double > &  dataGLLJacobianIn,
const DataMatrix3D< int > &  dataGLLNodesOut,
const DataMatrix3D< double > &  dataGLLJacobianOut,
const DataVector< 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 2531 of file TempestLinearRemap.cpp.

References ForceIntArrayConsistencyConservation(), ixOverlap, and t.

{
    // Triangular quadrature rule
    TriangularQuadratureRule triquadrule ( 8 );

    const DataMatrix<double> & dG = triquadrule.GetG();
    const DataVector<double> & dW = triquadrule.GetW();

    // Get SparseMatrix represntation of the OfflineMap
    SparseMatrix<double> & smatMap = this->GetSparseMatrix();

    // Sample coefficients
    DataMatrix<double> dSampleCoeffIn;
    dSampleCoeffIn.Initialize ( nPin, nPin );

    DataMatrix<double> dSampleCoeffOut;
    dSampleCoeffOut.Initialize ( nPout, nPout );

    // Announcemnets
    if ( is_root )
    {
        Announce ( "[moab::TempestOfflineMap::LinearRemapGLLtoGLL2_MOAB] Finite Element to Finite Element Projection" );
        Announce ( "Order of the input FE polynomial interpolant: %i", nPin );
        Announce ( "Order of the output FE polynomial interpolant: %i", nPout );
    }

    // Build the integration array for each element on m_meshOverlap
    DataMatrix3D<double> dGlobalIntArray;
    dGlobalIntArray.Initialize (
        nPin * nPin,
        m_meshOverlap->faces.size(),
        nPout * nPout );

    // Number of overlap Faces per source Face
    DataVector<int> nAllOverlapFaces;
    nAllOverlapFaces.Initialize ( 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];
    }

    // Geometric area of each output node
    DataMatrix<double> dGeometricOutputArea;
    dGeometricOutputArea.Initialize (
        m_meshOutput->faces.size(), nPout * nPout );

    // Area of each overlap element in the output basis
    DataMatrix<double> dOverlapOutputArea;
    dOverlapOutputArea.Initialize (
        m_meshOverlap->faces.size(), nPout * nPout );

    // Loop through all faces on m_meshInput
    ixOverlap = 0;
#ifdef VERBOSE
    const unsigned outputFrequency = (m_meshInputCov->faces.size()/10);
#endif

    if ( is_root )
        Announce ( "Building conservative distribution maps" );
    for ( size_t ixFirst = 0; ixFirst < m_meshInputCov->faces.size(); ixFirst++ )
    {
#ifdef VERBOSE
        // Announce computation progress
        if ( ixFirst % outputFrequency == 0 && is_root )
        {
            Announce ( "Element %i", ixFirst );
        }
#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;

            int nOverlapTriangles = faceOverlap.edges.size() - 2;

            // Quantities from the Second Mesh
            int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];

            const NodeVector & nodesSecond = m_meshOutput->nodes;

            const Face & faceSecond = m_meshOutput->faces[ixSecond];

            // Loop over all sub-triangles of this Overlap Face
            for ( int j = 0; j < nOverlapTriangles; j++ )
            {

                // Cornerpoints of triangle
                const Node & node0 = nodesOverlap[faceOverlap[0]];
                const Node & node1 = nodesOverlap[faceOverlap[j + 1]];
                const Node & node2 = nodesOverlap[faceOverlap[j + 2]];

                // Calculate the area of the modified Face
                Face faceTri ( 3 );
                faceTri.SetNode ( 0, faceOverlap[0] );
                faceTri.SetNode ( 1, faceOverlap[j + 1] );
                faceTri.SetNode ( 2, faceOverlap[j + 2] );

                double dTriArea =
                    CalculateFaceArea ( faceTri, nodesOverlap );

                for ( int k = 0; k < triquadrule.GetPoints(); k++ )
                {
                    double * dGL = dG[k];

                    // Get the nodal location of this point
                    double dX[3];

                    dX[0] = dGL[0] * node0.x + dGL[1] * node1.x + dGL[2] * node2.x;
                    dX[1] = dGL[0] * node0.y + dGL[1] * node1.y + dGL[2] * node2.y;
                    dX[2] = dGL[0] * node0.z + dGL[1] * node1.z + dGL[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
        DataMatrix<double> dCoeff;
        dCoeff.Initialize ( 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
        DataVector<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
        DataVector<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++;
                }
            }
        }
        /*
                // 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);
                }
                _EXCEPTION();
        */

        // Increment the current overlap index
        ixOverlap += nOverlapFaces;
    }

    // Build redistribution map within target element
    Announce ( "Building redistribution maps on target mesh" );
    DataVector<double> dRedistSourceArea ( nPout * nPout );
    DataVector<double> dRedistTargetArea ( nPout * nPout );
    std::vector< DataMatrix<double> > dRedistributionMaps;
    dRedistributionMaps.resize ( m_meshOutput->faces.size() );

    for ( size_t ixSecond = 0; ixSecond < m_meshOutput->faces.size(); ixSecond++ )
    {
        dRedistributionMaps[ixSecond].Initialize (
            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
    DataVector<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;

    Announce ( "Assembling map" );

    // Map from source DOFs to target DOFs with redistribution applied
    DataMatrix<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 )
        {
            Announce ( "Element %i", ixFirst );
        }
#endif

        // Number of overlapping Faces and triangles
        int nOverlapFaces = nAllOverlapFaces[ixFirst];

        // Put composed array into map
        for ( int j = 0; j < nOverlapFaces; j++ )
        {
            int ixSecondFace = m_meshOverlap->vecTargetFaceIx[ixOverlap + j];

            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::TempestOfflineMap::LinearRemapGLLtoGLL2_Pointwise_MOAB ( const DataMatrix3D< int > &  dataGLLNodesIn,
const DataMatrix3D< double > &  dataGLLJacobianIn,
const DataMatrix3D< int > &  dataGLLNodesOut,
const DataMatrix3D< double > &  dataGLLJacobianOut,
const DataVector< 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 3117 of file TempestLinearRemap.cpp.

References ixOverlap, and t.

{
    // Gauss-Lobatto quadrature within Faces
    DataVector<double> dGL;
    DataVector<double> dWL;

    GaussLobattoQuadrature::GetPoints ( nPout, 0.0, 1.0, dGL, dWL );

    // Utilities
    MeshUtilitiesFuzzy utils;

    // Get SparseMatrix represntation of the OfflineMap
    SparseMatrix<double> & smatMap = this->GetSparseMatrix();

    // Sample coefficients
    DataMatrix<double> dSampleCoeffIn;
    dSampleCoeffIn.Initialize ( nPin, nPin );

    // Announcemnets
    if ( is_root )
    {
        Announce ( "[moab::TempestOfflineMap::LinearRemapGLLtoGLL2_Pointwise_MOAB] Finite Element to Finite Element (Pointwise) Projection" );
        Announce ( "Order of the input FE polynomial interpolant: %i", nPin );
        Announce ( "Order of the output FE polynomial interpolant: %i", nPout );
    }

    // Number of overlap Faces per source Face
    DataVector<int> nAllOverlapFaces;
    nAllOverlapFaces.Initialize ( 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
    DataVector<bool> fSecondNodeFound ( dataNodalAreaOut.GetRows() );

    ixOverlap = 0;
#ifdef VERBOSE
    const unsigned outputFrequency = (m_meshInputCov->faces.size()/10);
#endif

    // 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 )
        {
            Announce ( "Element %i", ixFirst );
        }
#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 overlap Mesh
            // const Face & faceOverlap = m_meshOverlap->faces[ixOverlap + i];

            // const NodeVector & nodesOverlap = m_meshOverlap->nodes;

            // size_t nOverlapTriangles = faceOverlap.edges.size() - 2;

            // Quantities from the Second Mesh
            int ixSecond = m_meshOverlap->vecTargetFaceIx[ixOverlap + i];

            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;
}
void moab::TempestOfflineMap::LinearRemapSE0_Tempest_MOAB ( const DataMatrix3D< int > &  dataGLLNodes,
const DataMatrix3D< double > &  dataGLLJacobian 
) [private]

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

void moab::TempestOfflineMap::LinearRemapSE4_Tempest_MOAB ( const DataMatrix3D< int > &  dataGLLNodes,
const DataMatrix3D< 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 862 of file TempestLinearRemap.cpp.

References ForceConsistencyConservation3(), ixOverlap, and l.

{
    // 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 DataMatrix<double> & TriQuadratureG = triquadrule.GetG();

    const DataVector<double> & TriQuadratureW = triquadrule.GetW();

    // Sample coefficients
    DataMatrix<double> dSampleCoeff;
    dSampleCoeff.Initialize ( nP, nP );

    // GLL Quadrature nodes on quadrilateral elements
    DataVector<double> dG;
    DataVector<double> dW;
    GaussLobattoQuadrature::GetPoints ( nP, 0.0, 1.0, dG, dW );

    // Announcemnets
    if ( is_root )
    {
        Announce ( "[moab::TempestOfflineMap::LinearRemapSE4_Tempest_MOAB] Finite Element to Finite Volume Projection" );
        Announce ( "Triangular quadrature rule order %i", TriQuadRuleOrder );
        Announce ( "Order of the FE polynomial interpolant: %i", 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
    DataVector<double> vecSourceArea;
    vecSourceArea.Initialize ( nP * nP );

    DataVector<double> vecTargetArea;
    DataMatrix<double> dCoeff;

#ifdef VERBOSE
    std::stringstream sstr;
    sstr << "remapdata_" << rank << ".txt";
    std::ofstream output_file ( sstr.str() );
#endif

    // Current Overlap Face
    int ixOverlap = 0;
#ifdef VERBOSE
    const unsigned outputFrequency = (m_meshInputCov->faces.size()/10);
#endif

    // 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 )
        {
            Announce ( "Element %i/%i", 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
        DataMatrix3D<double> dRemapCoeff;
        dRemapCoeff.Initialize ( nP, nP, nOverlapFaces );

        // Find the local remap coefficients
        for ( int j = 0; j < nOverlapFaces; j++ )
        {
            const Face & faceOverlap = m_meshOverlap->faces[ixOverlap + j];

// #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 nOverlapTriangles = faceOverlap.edges.size() - 2;

// #define USE_MININDEX

#ifdef USE_MININDEX
            // first find out the minimum node, start there the triangle decomposition
            int minIndex = 0;
            int nnodes = faceOverlap.edges.size();
            for (int j1=1; j1<nnodes; j1++)
            {
              if ( nodesOverlap[faceOverlap[j1]] < nodesOverlap[faceOverlap[minIndex]] )
              {
                minIndex = j1;
              }
            }
#endif

            // Loop over all sub-triangles of this Overlap Face
            for ( int k = 0; k < nOverlapTriangles; k++ )
            {
#ifdef USE_MININDEX
                // Cornerpoints of triangle, they start at the minimal Node, for consistency
                const Node & node0 = nodesOverlap[faceOverlap[minIndex]];
                const Node & node1 = nodesOverlap[faceOverlap[(minIndex + k + 1)%nnodes]];
                const Node & node2 = nodesOverlap[faceOverlap[(minIndex + k + 2)%nnodes]];

                // Calculate the area of the modified Face
                Face faceTri ( 3 );
                faceTri.SetNode ( 0, faceOverlap[minIndex] );
                faceTri.SetNode ( 1, faceOverlap[(minIndex + k + 1)%nnodes] );
                faceTri.SetNode ( 2, faceOverlap[(minIndex + k + 2)%nnodes] );
#else
                // Cornerpoints of triangle
                const Node & node0 = nodesOverlap[faceOverlap[0]];
                const Node & node1 = nodesOverlap[faceOverlap[k+1]];
                const Node & node2 = nodesOverlap[faceOverlap[k+2]];

                // Calculate the area of the modified Face
                Face faceTri(3);
                faceTri.SetNode(0, faceOverlap[0]);
                faceTri.SetNode(1, faceOverlap[k+1]);
                faceTri.SetNode(2, faceOverlap[k+2]);
#endif

                double dTriangleArea =
                    CalculateFaceArea ( faceTri, nodesOverlap );

                // 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;

                    double dMag = sqrt (
                                      nodeQuadrature.x * nodeQuadrature.x
                                      + nodeQuadrature.y * nodeQuadrature.y
                                      + nodeQuadrature.z * nodeQuadrature.z );

                    nodeQuadrature.x /= dMag;
                    nodeQuadrature.y /= dMag;
                    nodeQuadrature.z /= dMag;

                    // 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 )
                       )
                    {
                        _EXCEPTION2 ( "Inverse Map out of range (%1.5e %1.5e)",
                                      dAlpha, dBeta );
                    }

                    // Sample the finite element at this point
                    SampleGLLFiniteElement (
                        nMonotoneType,
                        nP,
                        dAlpha,
                        dBeta,
                        dSampleCoeff );

                    // Add sample coefficients to the map
                    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.Initialize ( nOverlapFaces );
                for ( int j = 0; j < nOverlapFaces; j++ )
                {
                    vecTargetArea[j] = m_meshOverlap->vecFaceArea[ixOverlap + j];
                }

                dCoeff.Initialize ( 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.Initialize ( 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.Initialize ( 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];
            if (ixSecondFace < 0) // signal to not participate, because it is a ghost target
              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::TempestOfflineMap::SetDofMapAssociation ( DiscretizationType  srcType,
bool  isSrcContinuous,
DataMatrix3D< int > *  srcdataGLLNodes,
DataMatrix3D< int > *  srcdataGLLNodesSrc,
DiscretizationType  destType,
bool  isDestContinuous,
DataMatrix3D< int > *  tgtdataGLLNodes 
) [private]

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 158 of file TempestOfflineMap.cpp.

References MB_CHK_ERR, MB_SUCCESS, and rank.

{
    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 = mbCore->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 = mbCore->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 = mbCore->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 ldof = (*srcdataGLLNodes)[p][q][j] - 1;
                            const int idof = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
                            if ( isSrcContinuous && !dgll_cgll_covcol_ldofmap[ldof] ) {
                                m_nTotDofs_SrcCov++;
                                dgll_cgll_covcol_ldofmap[ldof] = true;
                            }
                            output_file << m_remapper->lid_to_gid_covsrc[j] << ", " <<  idof << ", " << ldof << ", " << src_soln_gdofs[idof] << ", " << 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 ldof = (*srcdataGLLNodesSrc)[p][q][j] - 1;
                            const int idof = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
                            if ( isSrcContinuous && !dgll_cgll_col_ldofmap[ldof] ) {
                                m_nTotDofs_Src++;
                                dgll_cgll_col_ldofmap[ldof] = true;
                            }
                            output_file << m_remapper->lid_to_gid_src[j] << ", " <<  idof << ", " << ldof << ", " << locsrc_soln_gdofs[idof] << ", " << 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 ldof = (*srcdataGLLNodes)[p][q][j] - 1;
                            const int idof = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
                            if ( isSrcContinuous && !dgll_cgll_covcol_ldofmap[ldof] ) {
                                m_nTotDofs_SrcCov++;
                                dgll_cgll_covcol_ldofmap[ldof] = true;
                            }
                            output_file << m_remapper->lid_to_gid_covsrc[j] << ", " <<  idof << ", " << ldof << ", " << src_soln_gdofs[idof] << ", " << 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 ldof = (*srcdataGLLNodesSrc)[p][q][j] - 1;
                            const int idof = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
                            if ( isSrcContinuous && !dgll_cgll_col_ldofmap[ldof] ) {
                                m_nTotDofs_Src++;
                                dgll_cgll_col_ldofmap[ldof] = true;
                            }
                            output_file << m_remapper->lid_to_gid_src[j] << ", " <<  idof << ", " << ldof << ", " << locsrc_soln_gdofs[idof] << ", " << 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
    col_dofmap.resize (m_remapper->m_covering_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, ULONG_MAX);
    col_ldofmap.resize (m_remapper->m_covering_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, ULONG_MAX);
    col_gdofmap.resize (m_remapper->m_covering_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, ULONG_MAX);
    src_soln_gdofs.resize(m_remapper->m_covering_source_entities.size()*m_nDofsPEl_Src*m_nDofsPEl_Src, INT_MAX);
    rval = mbCore->tag_get_data ( m_dofTagSrc, m_remapper->m_covering_source_entities, &src_soln_gdofs[0] );MB_CHK_ERR(rval);
    m_nTotDofs_SrcCov = 0;
    if (srcdataGLLNodes == NULL || srcType == DiscretizationType_FV) { /* we only have a mapping for elements as DoFs */
        for (unsigned i=0; i < col_dofmap.size(); ++i) {
            col_dofmap[i] = i;
            col_ldofmap[i] = i;
            col_gdofmap[i] = src_soln_gdofs[i];
            if (vprint) std::cout << "Col: " << i << ", " << src_soln_gdofs[i] << "\n";
            m_nTotDofs_SrcCov++;
        }
    }
    else {
        if (isSrcContinuous) dgll_cgll_covcol_ldofmap.resize (m_remapper->m_covering_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, 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 ldof = (*srcdataGLLNodes)[p][q][j] - 1;
                    const int idof = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
                    if ( isSrcContinuous && !dgll_cgll_covcol_ldofmap[ldof] ) {
                        m_nTotDofs_SrcCov++;
                        dgll_cgll_covcol_ldofmap[ldof] = true;
                    }
                    if ( !isSrcContinuous ) m_nTotDofs_SrcCov++;
                    col_dofmap[ idof ] = ldof;
                    col_ldofmap[ ldof ] = idof;
                    assert(src_soln_gdofs[idof] > 0);
                    col_gdofmap[ idof ] = src_soln_gdofs[idof] - 1;
                    if (vprint) std::cout << "Col: " << m_remapper->lid_to_gid_covsrc[j] << ", " <<  idof << ", " << ldof << ", " << col_gdofmap[idof] << ", " << m_nTotDofs_SrcCov << "\n";
                }
            }
        }
    }

    srccol_dofmap.resize (m_remapper->m_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, ULONG_MAX);
    srccol_ldofmap.resize (m_remapper->m_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, ULONG_MAX);
    srccol_gdofmap.resize (m_remapper->m_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, ULONG_MAX);
    locsrc_soln_gdofs.resize(m_remapper->m_source_entities.size()*m_nDofsPEl_Src*m_nDofsPEl_Src, INT_MAX);
    rval = mbCore->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 || srcType == DiscretizationType_FV) { /* we only have a mapping for elements as DoFs */
        for (unsigned i=0; i < srccol_dofmap.size(); ++i) {
            srccol_dofmap[i] = i;
            srccol_ldofmap[i] = i;
            srccol_gdofmap[i] = locsrc_soln_gdofs[i];
            m_nTotDofs_Src++;
        }
    }
    else {
        if (isSrcContinuous) dgll_cgll_col_ldofmap.resize(m_remapper->m_source_entities.size() * m_nDofsPEl_Src * m_nDofsPEl_Src, 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 ldof = (*srcdataGLLNodesSrc)[p][q][j] - 1;
                    const int idof = j * m_nDofsPEl_Src * m_nDofsPEl_Src + p * m_nDofsPEl_Src + q;
                    if ( isSrcContinuous && !dgll_cgll_col_ldofmap[ldof] ) {
                        m_nTotDofs_Src++;
                        dgll_cgll_col_ldofmap[ldof] = true;
                    }
                    if ( !isSrcContinuous ) m_nTotDofs_Src++;
                    srccol_dofmap[ idof ] = ldof;
                    srccol_ldofmap[ ldof ] = idof;
                    srccol_gdofmap[ idof ] = locsrc_soln_gdofs[idof] - 1;
                }
            }
        }
    }

    row_dofmap.resize (m_remapper->m_target_entities.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest, ULONG_MAX);
    row_ldofmap.resize (m_remapper->m_target_entities.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest, ULONG_MAX);
    row_gdofmap.resize (m_remapper->m_target_entities.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest, ULONG_MAX);
    tgt_soln_gdofs.resize(m_remapper->m_target_entities.size()*m_nDofsPEl_Dest*m_nDofsPEl_Dest, INT_MAX);
    rval = mbCore->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
    m_nTotDofs_Dest = 0;
    if (tgtdataGLLNodes == NULL || destType == DiscretizationType_FV) { /* we only have a mapping for elements as DoFs */
        for (unsigned i=0; i < row_dofmap.size(); ++i) {
            row_dofmap[i] = i;
            row_ldofmap[i] = i;
            row_gdofmap[i] = tgt_soln_gdofs[i];
            // if (vprint) std::cout << "Row: " << m_remapper->lid_to_gid_tgt[i] << ", " <<  i << ", " << row_dofmap[i] << ", " << row_ldofmap[i] << ", " << tgt_soln_gdofs[i] << ", " << row_gdofmap[i] << "\n";
            m_nTotDofs_Dest++;
        }
    }
    else {
        if (isTgtContinuous) dgll_cgll_row_ldofmap.resize (m_remapper->m_target_entities.size() * m_nDofsPEl_Dest * m_nDofsPEl_Dest, 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 ldof = (*tgtdataGLLNodes)[p][q][j] - 1;
                    const int idof = j * m_nDofsPEl_Dest * m_nDofsPEl_Dest + p * m_nDofsPEl_Dest + q;
                    if ( isTgtContinuous && !dgll_cgll_row_ldofmap[ldof] ) {
                        m_nTotDofs_Dest++;
                        dgll_cgll_row_ldofmap[ldof] = true;
                    }
                    if ( !isTgtContinuous ) m_nTotDofs_Dest++;
                    row_dofmap[ idof ] = ldof;
                    row_ldofmap[ ldof ] = idof;
                    row_gdofmap[ idof ] = tgt_soln_gdofs[idof] - 1;
                    if (vprint) std::cout << "Row: " << idof << ", " << ldof << ", " << tgt_soln_gdofs[idof] - 1 << "\n";
                }
            }
        }
    }

    // Let us also allocate the local representation of the sparse matrix
#ifdef MOAB_HAVE_EIGEN
    // if (vprint)
    {
        std::cout << "[" << rank << "]" << "DoFs: row = " << m_nTotDofs_Dest << ", " << row_dofmap.size() << ", col = " << m_nTotDofs_Src << ", " << m_nTotDofs_SrcCov << ", " << col_dofmap.size() << "\n";
        // std::cout << "Max col_dofmap: " << maxcol << ", Min col_dofmap" << mincol << "\n";
    }
#endif

    return moab::MB_SUCCESS;
}
moab::ErrorCode moab::TempestOfflineMap::SetDofMapTags ( const std::string  srcDofTagName,
const std::string  tgtDofTagName 
) [private]

Store the tag names associated with global DoF ids for source and target meshes.

Definition at line 144 of file TempestOfflineMap.cpp.

References MB_CHK_ERR, MB_SUCCESS, MB_TAG_ANY, and MB_TYPE_INTEGER.


Member Data Documentation

std::vector<unsigned long> moab::TempestOfflineMap::col_dofmap

Definition at line 411 of file TempestOfflineMap.hpp.

std::vector<unsigned long> moab::TempestOfflineMap::col_gdofmap

Definition at line 412 of file TempestOfflineMap.hpp.

std::vector<unsigned long> moab::TempestOfflineMap::col_ldofmap

Definition at line 413 of file TempestOfflineMap.hpp.

Definition at line 415 of file TempestOfflineMap.hpp.

Definition at line 415 of file TempestOfflineMap.hpp.

Definition at line 415 of file TempestOfflineMap.hpp.

Definition at line 425 of file TempestOfflineMap.hpp.

Referenced by TempestOfflineMap().

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

Definition at line 410 of file TempestOfflineMap.hpp.

The boolean flag representing whether the root process has the updated global view.

Definition at line 375 of file TempestOfflineMap.hpp.

Referenced by TempestOfflineMap().

Definition at line 420 of file TempestOfflineMap.hpp.

Referenced by TempestOfflineMap().

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

The fundamental remapping operator object.

Definition at line 364 of file TempestOfflineMap.hpp.

Referenced by TempestOfflineMap().

The SparseMatrix representing this operator.

Definition at line 370 of file TempestOfflineMap.hpp.

Referenced by GetGlobalSourceAreas(), GetGlobalTargetAreas(), and TempestOfflineMap().

The DataVector that stores the global (GID-based) areas of the source mesh.

The DataVector that stores the global (GID-based) areas of the target mesh. The reference to the moab::Core object that contains source/target and overlap sets.

Definition at line 398 of file TempestOfflineMap.hpp.

Referenced by TempestOfflineMap().

Definition at line 426 of file TempestOfflineMap.hpp.

Referenced by TempestOfflineMap().

std::vector<unsigned long> moab::TempestOfflineMap::row_dofmap

Definition at line 411 of file TempestOfflineMap.hpp.

std::vector<unsigned long> moab::TempestOfflineMap::row_gdofmap

Definition at line 412 of file TempestOfflineMap.hpp.

std::vector<unsigned long> moab::TempestOfflineMap::row_ldofmap

Definition at line 413 of file TempestOfflineMap.hpp.

Definition at line 426 of file TempestOfflineMap.hpp.

Referenced by TempestOfflineMap().

std::vector<unsigned long> moab::TempestOfflineMap::srccol_dofmap

Definition at line 411 of file TempestOfflineMap.hpp.

std::vector<unsigned long> moab::TempestOfflineMap::srccol_gdofmap

Definition at line 412 of file TempestOfflineMap.hpp.

std::vector<unsigned long> moab::TempestOfflineMap::srccol_ldofmap

Definition at line 413 of file TempestOfflineMap.hpp.

List of all members.


The documentation for this class was generated from the following files:
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines