Skip to content

Commit

Permalink
Tpetra: Added Details::isLocallyFitted(map1,map2) (Fix #561)
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Hoemmen committed Aug 17, 2016
1 parent 4f480d7 commit 38acc27
Show file tree
Hide file tree
Showing 4 changed files with 493 additions and 20 deletions.
33 changes: 29 additions & 4 deletions packages/tpetra/core/src/Tpetra_Map_decl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,7 +1072,7 @@ namespace Tpetra {
/// over this Map's communicator.
bool isSameAs (const Map<LocalOrdinal,GlobalOrdinal,Node> &map) const;

/// \brief Is the given Map locally the same as the input Map?
/// \brief Is this Map locally the same as the input Map?
///
/// "Locally the same" means that on the calling process, the two
/// Maps' global indices are the same and occur in the same order.
Expand Down Expand Up @@ -1514,7 +1514,7 @@ namespace Tpetra {
/// \relatesalso Map
template <class LocalOrdinal, class GlobalOrdinal, class Node>
Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
createUniformContigMapWithNode (global_size_t numElements,
createUniformContigMapWithNode (const global_size_t numElements,
const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
const Teuchos::RCP<Node>& node = Teuchos::null);

Expand All @@ -1540,8 +1540,8 @@ namespace Tpetra {
*/
template <class LocalOrdinal, class GlobalOrdinal, class Node>
Teuchos::RCP<const Map<LocalOrdinal,GlobalOrdinal,Node> >
createContigMapWithNode (global_size_t numElements,
size_t localNumElements,
createContigMapWithNode (const global_size_t numElements,
const size_t localNumElements,
const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
const Teuchos::RCP<Node>& node =
defaultArgNode<Node> ());
Expand Down Expand Up @@ -1714,6 +1714,31 @@ namespace Tpetra {
return Teuchos::rcp (new out_map_type (cloner_type::clone (*this, nodeOut)));
}

namespace Details {
/// \brief Is map1 locally fitted to map2?
///
/// \param map1 [in] The first Map
/// \param map2 [in] The second Map
///
/// For Map instances map1 and map2, we say that map1 is
/// <i>locally fitted</i> to map2 (on the calling process), when
/// the initial indices of map1 (on the calling process) are the
/// same and in the same order as those of map2. "Fittedness" is
/// entirely a local (per MPI process) property.
///
/// The predicate "is map1 fitted to map2 ?" is <i>not</i>
/// symmetric. For example, map2 may have more entries than map1.
///
/// Fittedness on a process can let Tpetra avoid deep copies in
/// some Export or Import (communication) operations. Tpetra
/// could use this, for example, in optimizing its sparse
/// matrix-vector multiply.
template <class LocalOrdinal,class GlobalOrdinal, class Node>
bool
isLocallyFitted (const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& map1,
const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& map2);
} // namespace Details

} // namespace Tpetra

/// \brief True if map1 is the same as (in the sense of isSameAs()) map2, else false.
Expand Down
117 changes: 101 additions & 16 deletions packages/tpetra/core/src/Tpetra_Map_def.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1842,7 +1842,80 @@ namespace Tpetra {
return global;
}

} // Tpetra namespace
namespace Details {

template <class LocalOrdinal,class GlobalOrdinal, class Node>
bool
isLocallyFitted (const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& map1,
const Tpetra::Map<LocalOrdinal, GlobalOrdinal, Node>& map2)
{
using Teuchos::ArrayView;
typedef GlobalOrdinal GO; // a handy abbreviation
typedef typename ArrayView<const GO>::size_type size_type;

bool fitted = true;
if (&map1 == &map2) {
fitted = true;
}
else if (map1.isContiguous () && map2.isContiguous () &&
map1.getMinGlobalIndex () == map2.getMinGlobalIndex () &&
map1.getMaxGlobalIndex () <= map2.getMaxGlobalIndex ()) {
// Special case where both Maps are contiguous.
fitted = true;
}
else {
ArrayView<const GO> inds_map2 = map2.getNodeElementList ();
const size_type numInds_map1 =
static_cast<size_type> (map1.getNodeNumElements ());

if (map1.isContiguous ()) {
// Avoid calling getNodeElementList() on the always one-to-one
// Map, if it is contiguous (a common case). When called on a
// contiguous Map, getNodeElementList() causes allocation of
// an array that sticks around, even though the array isn't
// needed. (The Map is contiguous, so you can compute the
// entries; you don't need to store them.)
if (numInds_map1 > inds_map2.size ()) {
// There are fewer indices in map1 on this process than in
// map2. This case might be impossible.
fitted = false;
}
else {
// Do all the map1 indices match the initial map2 indices?
const GO minInd_map1 = map1.getMinGlobalIndex ();
for (size_type k = 0; k < numInds_map1; ++k) {
const GO inds_map1_k = static_cast<GO> (k) + minInd_map1;
if (inds_map1_k != inds_map2[k]) {
fitted = false;
break;
}
}
}
}
else { // map1 is not contiguous.
// Get index lists from both Maps, and compare their indices.
ArrayView<const GO> inds_map1 = map1.getNodeElementList ();
if (numInds_map1 > inds_map2.size ()) {
// There are fewer indices in map1 on this process than in
// map2. This case might be impossible.
fitted = false;
}
else {
// Do all the map1 indices match those in map2?
for (size_type k = 0; k < numInds_map1; ++k) {
if (inds_map1[k] != inds_map2[k]) {
fitted = false;
break;
}
}
}
}
}
return fitted;
}

} // namespace Details
} // namespace Tpetra

template <class LocalOrdinal, class GlobalOrdinal>
Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal> >
Expand All @@ -1868,7 +1941,7 @@ Tpetra::createUniformContigMap (const global_size_t numElements,

template <class LocalOrdinal, class GlobalOrdinal, class Node>
Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
Tpetra::createUniformContigMapWithNode (global_size_t numElements,
Tpetra::createUniformContigMapWithNode (const global_size_t numElements,
const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
const Teuchos::RCP<Node>& node)
{
Expand Down Expand Up @@ -1906,8 +1979,8 @@ Tpetra::createLocalMapWithNode (const size_t numElements,

template <class LocalOrdinal, class GlobalOrdinal, class Node>
Teuchos::RCP< const Tpetra::Map<LocalOrdinal,GlobalOrdinal,Node> >
Tpetra::createContigMapWithNode (Tpetra::global_size_t numElements,
size_t localNumElements,
Tpetra::createContigMapWithNode (const Tpetra::global_size_t numElements,
const size_t localNumElements,
const Teuchos::RCP<const Teuchos::Comm<int> >& comm,
const Teuchos::RCP<Node>& node)
{
Expand Down Expand Up @@ -2129,30 +2202,42 @@ Tpetra::createOneToOne (const Teuchos::RCP<const Tpetra::Map<LocalOrdinal,Global
template class Map< LO , GO , NODE >; \
\
template Teuchos::RCP< const Map<LO,GO,NODE> > \
createLocalMapWithNode<LO,GO,NODE>(size_t numElements, const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
createLocalMapWithNode<LO,GO,NODE> (const size_t numElements, \
const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
const Teuchos::RCP< NODE >& node); \
\
template Teuchos::RCP< const Map<LO,GO,NODE> > \
createContigMapWithNode<LO,GO,NODE>(global_size_t numElements, size_t localNumElements, \
const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
createContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
const size_t localNumElements, \
const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
const Teuchos::RCP< NODE > &node); \
\
template Teuchos::RCP< const Map<LO,GO,NODE> > \
createNonContigMapWithNode(const Teuchos::ArrayView<const GO> &elementList, \
const RCP<const Teuchos::Comm<int> > &comm, \
const RCP<NODE> &node); \
const Teuchos::RCP<const Teuchos::Comm<int> > &comm, \
const Teuchos::RCP<NODE> &node); \
\
template Teuchos::RCP< const Map<LO,GO,NODE> > \
createUniformContigMapWithNode<LO,GO,NODE>(global_size_t numElements, \
const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
createUniformContigMapWithNode<LO,GO,NODE> (const global_size_t numElements, \
const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
const Teuchos::RCP< NODE > &node); \
\
template Teuchos::RCP< const Map<LO,GO,NODE> > \
createWeightedContigMapWithNode<LO,GO,NODE>(int thisNodeWeight, global_size_t numElements, \
const Teuchos::RCP< const Teuchos::Comm< int > > &comm, const Teuchos::RCP< NODE > &node); \
createWeightedContigMapWithNode<LO,GO,NODE> (const int thisNodeWeight, \
const global_size_t numElements, \
const Teuchos::RCP< const Teuchos::Comm< int > >& comm, \
const Teuchos::RCP< NODE >& node); \
\
template Teuchos::RCP<const Map<LO,GO,NODE> > \
createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> > &M); \
createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> >& M); \
\
template Teuchos::RCP<const Map<LO,GO,NODE> > \
createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> > &M, \
const Tpetra::Details::TieBreak<LO,GO> & tie_break);
createOneToOne (const Teuchos::RCP<const Map<LO,GO,NODE> >& M, \
const Tpetra::Details::TieBreak<LO,GO>& tie_break); \
\
template bool \
Details::isLocallyFitted (const Tpetra::Map<LO, GO, NODE>& map1, \
const Tpetra::Map<LO, GO, NODE>& map2);


//! Explicit instantiation macro supporting the Map class, on the default node for specified ordinals.
Expand Down
11 changes: 11 additions & 0 deletions packages/tpetra/core/test/Map/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,14 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST(
NUM_MPI_PROCS 1-10
STANDARD_PASS_OUTPUT
)

# This test needs to run on at least 2 MPI processes.
TRIBITS_ADD_EXECUTABLE_AND_TEST(
Map_isLocallyFitted
SOURCES
Map_isLocallyFitted.cpp
${TEUCHOS_STD_UNIT_TEST_MAIN}
COMM mpi
NUM_MPI_PROCS 2-10
STANDARD_PASS_OUTPUT
)
Loading

0 comments on commit 38acc27

Please sign in to comment.