46 #ifndef MUELU_HYBRIDAGGREGATIONFACTORY_DEF_HPP_
47 #define MUELU_HYBRIDAGGREGATIONFACTORY_DEF_HPP_
50 #include <Xpetra_Map.hpp>
52 #include <Xpetra_MultiVectorFactory.hpp>
58 #include "MueLu_InterfaceAggregationAlgorithm.hpp"
59 #include "MueLu_OnePtAggregationAlgorithm.hpp"
60 #include "MueLu_PreserveDirichletAggregationAlgorithm.hpp"
62 #include "MueLu_AggregationPhase1Algorithm.hpp"
63 #include "MueLu_AggregationPhase2aAlgorithm.hpp"
64 #include "MueLu_AggregationPhase2bAlgorithm.hpp"
65 #include "MueLu_AggregationPhase3Algorithm.hpp"
68 #include "MueLu_AggregationStructuredAlgorithm.hpp"
69 #include "MueLu_UncoupledIndexManager.hpp"
75 #include "MueLu_LWGraph.hpp"
76 #include "MueLu_Aggregates.hpp"
82 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
85 : bDefinitionPhase_(true) {}
87 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
92 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
105 SET_VALID_ENTRY(
"aggregation: error on nodes with no on-rank neighbors");
117 #undef SET_VALID_ENTRY
122 validParamList->
set<
RCP<const FactoryBase> >(
"DofsPerNode", null,
"Generating factory for variable \'DofsPerNode\', usually the same as for \'Graph\'");
124 validParamList->
set<std::string>(
"OnePt aggregate map name",
"",
125 "Name of input map for single node aggregates. (default='')");
126 validParamList->
set<std::string>(
"OnePt aggregate map factory",
"",
127 "Generating factory of (DOF) map for single node aggregates.");
130 validParamList->
set<std::string>(
"Interface aggregate map name",
"",
131 "Name of input map for interface aggregates. (default='')");
132 validParamList->
set<std::string>(
"Interface aggregate map factory",
"",
133 "Generating factory of (DOF) map for interface aggregates.");
135 "Describes the dimensions of all the interfaces on this rank.");
137 "List the LIDs of the nodes on any interface.");
142 "Number of spatial dimension provided by CoordinatesTransferFactory.");
144 "Number of nodes per spatial dimmension provided by CoordinatesTransferFactory.");
148 "Type of aggregation to use on the region (\"structured\" or \"uncoupled\")");
150 return validParamList;
153 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
156 Input(currentLevel,
"Graph");
169 "Aggregation region type was not provided by the user!");
176 "numDimensions was not provided by the user on level0!");
183 "lNodesPerDim was not provided by the user on level0!");
186 Input(currentLevel,
"aggregationRegionType");
187 Input(currentLevel,
"numDimensions");
188 Input(currentLevel,
"lNodesPerDim");
192 Input(currentLevel,
"DofsPerNode");
195 if (pL.
get<
bool>(
"aggregation: use interface aggregation") ==
true) {
202 "interfacesDimensions was not provided by the user on level0!");
209 "nodeOnInterface was not provided by the user on level0!");
212 Input(currentLevel,
"interfacesDimensions");
213 Input(currentLevel,
"nodeOnInterface");
218 std::string mapOnePtName = pL.
get<std::string>(
"OnePt aggregate map name");
219 if (mapOnePtName.length() > 0) {
220 std::string mapOnePtFactName = pL.
get<std::string>(
"OnePt aggregate map factory");
221 if (mapOnePtFactName ==
"" || mapOnePtFactName ==
"NoFactory") {
230 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
236 if (
const char* dbg = std::getenv(
"MUELU_HYBRIDAGGREGATION_DEBUG")) {
237 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
243 *out <<
"Entering hybrid aggregation" << std::endl;
246 bDefinitionPhase_ =
false;
248 if (pL.
get<
int>(
"aggregation: max agg size") == -1)
249 pL.
set(
"aggregation: max agg size", INT_MAX);
257 const int myRank = fineMap->getComm()->getRank();
258 const int numRanks = fineMap->getComm()->getSize();
270 AggStatHostType aggStat(Kokkos::ViewAllocateWithoutInitializing(
"aggregation status"), numRows);
271 Kokkos::deep_copy(aggStat,
READY);
274 std::string regionType;
275 if (currentLevel.GetLevelID() == 0) {
277 regionType = currentLevel.Get<std::string>(
"aggregationRegionType",
NoFactory::get());
280 regionType = Get<std::string>(currentLevel,
"aggregationRegionType");
283 int numDimensions = 0;
284 if (currentLevel.GetLevelID() == 0) {
286 numDimensions = currentLevel.Get<
int>(
"numDimensions",
NoFactory::get());
289 numDimensions = Get<int>(currentLevel,
"numDimensions");
293 std::string coarseningRate = pL.
get<std::string>(
"aggregation: coarsening rate");
296 coarseRate = Teuchos::fromStringToArray<LO>(coarseningRate);
298 GetOStream(
Errors, -1) <<
" *** \"aggregation: coarsening rate\" must be a string convertible into an array! *** "
304 "\"aggregation: coarsening rate\" must have at least as many"
305 " components as the number of spatial dimensions in the problem.");
308 LO numNonAggregatedNodes = numRows;
309 if (regionType ==
"structured") {
315 const int interpolationOrder = pL.
get<
int>(
"aggregation: coarsening order");
317 if (currentLevel.GetLevelID() == 0) {
322 lFineNodesPerDir = Get<Array<LO> >(currentLevel,
"lNodesPerDim");
326 for (
int dim = numDimensions; dim < 3; ++dim) {
327 lFineNodesPerDir[dim] = 1;
344 "The local number of elements in the graph's map is not equal to "
345 "the number of nodes given by: lNodesPerDim!");
350 Set(currentLevel,
"lCoarseNodesPerDim", geoData->getLocalCoarseNodesPerDir());
354 if (regionType ==
"uncoupled") {
364 *out <<
" Build interface aggregates" << std::endl;
366 if (pL.
get<
bool>(
"aggregation: use interface aggregation") ==
true) {
367 BuildInterfaceAggregates(currentLevel, aggregates, aggStat, numNonAggregatedNodes,
371 *out <<
"Treat Dirichlet BC" << std::endl;
374 for (
LO i = 0; i < numRows; i++)
375 if (dirichletBoundaryMap[i] ==
true)
379 std::string mapOnePtName = pL.
get<std::string>(
"OnePt aggregate map name");
381 if (mapOnePtName.length()) {
382 std::string mapOnePtFactName = pL.
get<std::string>(
"OnePt aggregate map factory");
383 if (mapOnePtFactName ==
"" || mapOnePtFactName ==
"NoFactory") {
387 OnePtMap = currentLevel.Get<
RCP<Map> >(mapOnePtName, mapOnePtFact.
get());
391 LO nDofsPerNode = Get<LO>(currentLevel,
"DofsPerNode");
393 if (OnePtMap != Teuchos::null) {
394 for (
LO i = 0; i < numRows; i++) {
396 GO grid = (graph->
GetDomainMap()->getGlobalElement(i) - indexBase) * nDofsPerNode + indexBase;
397 for (
LO kr = 0; kr < nDofsPerNode; kr++)
398 if (OnePtMap->isNodeGlobalElement(grid + kr))
405 Set(currentLevel,
"lCoarseNodesPerDim", lCoarseNodesPerDir);
410 *out <<
"Run all the algorithms on the local rank" << std::endl;
411 for (
size_t a = 0; a < algos_.size(); a++) {
412 std::string phase = algos_[a]->description();
414 *out << regionType <<
" | Executing phase " << a << std::endl;
416 int oldRank = algos_[a]->SetProcRankVerbose(this->GetProcRankVerbose());
417 algos_[a]->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStat, numNonAggregatedNodes);
418 algos_[a]->SetProcRankVerbose(oldRank);
419 *out << regionType <<
" | Done Executing phase " << a << std::endl;
422 *out <<
"Compute statistics on aggregates" << std::endl;
425 Set(currentLevel,
"Aggregates", aggregates);
426 Set(currentLevel,
"numDimensions", numDimensions);
427 Set(currentLevel,
"aggregationRegionTypeCoarse", regionType);
430 *out <<
"HybridAggregation done!" << std::endl;
433 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
438 FactoryMonitor m(*
this,
"BuildInterfaceAggregates", currentLevel);
441 if (
const char* dbg = std::getenv(
"MUELU_HYBRIDAGGREGATION_DEBUG")) {
442 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
449 if (coarseRate.
size() == 1) {
450 coarseRate.
resize(3, coarseRate[0]);
454 Array<LO> interfacesDimensions = Get<Array<LO> >(currentLevel,
"interfacesDimensions");
455 Array<LO> nodesOnInterfaces = Get<Array<LO> >(currentLevel,
"nodeOnInterface");
456 const int numInterfaces = interfacesDimensions.
size() / 3;
457 const int myRank = aggregates->
GetMap()->getComm()->getRank();
460 Array<LO> coarseInterfacesDimensions(interfacesDimensions.
size());
463 LO endRate, totalNumCoarseNodes = 0, numCoarseNodes;
464 for (
int interfaceIdx = 0; interfaceIdx < numInterfaces; ++interfaceIdx) {
466 for (
int dim = 0; dim < 3; ++dim) {
467 endRate = (interfacesDimensions[3 * interfaceIdx + dim] - 1) % coarseRate[dim];
468 if (interfacesDimensions[3 * interfaceIdx + dim] == 1) {
469 coarseInterfacesDimensions[3 * interfaceIdx + dim] = 1;
471 coarseInterfacesDimensions[3 * interfaceIdx + dim] = (interfacesDimensions[3 * interfaceIdx + dim] - 1) / coarseRate[dim] + 2;
473 coarseInterfacesDimensions[3 * interfaceIdx + dim]--;
476 numCoarseNodes *= coarseInterfacesDimensions[3 * interfaceIdx + dim];
478 totalNumCoarseNodes += numCoarseNodes;
480 nodesOnCoarseInterfaces.
resize(totalNumCoarseNodes, -1);
484 LO interfaceOffset = 0, aggregateCount = 0, coarseNodeCount = 0;
485 for (
int interfaceIdx = 0; interfaceIdx < numInterfaces; ++interfaceIdx) {
486 ArrayView<LO> fineNodesPerDim = interfacesDimensions(3 * interfaceIdx, 3);
487 ArrayView<LO> coarseNodesPerDim = coarseInterfacesDimensions(3 * interfaceIdx, 3);
488 LO numInterfaceNodes = 1, numCoarseNodes = 1;
489 for (
int dim = 0; dim < 3; ++dim) {
490 numInterfaceNodes *= fineNodesPerDim[dim];
491 numCoarseNodes *= coarseNodesPerDim[dim];
492 endRate[dim] = (fineNodesPerDim[dim] - 1) % coarseRate[dim];
494 ArrayView<LO> interfaceNodes = nodesOnInterfaces(interfaceOffset, numInterfaceNodes);
496 interfaceOffset += numInterfaceNodes;
498 LO rem, rate, fineNodeIdx;
499 Array<LO> nodeIJK(3), coarseIJK(3), rootIJK(3);
502 for (
LO coarseNodeIdx = 0; coarseNodeIdx < numCoarseNodes; ++coarseNodeIdx) {
503 coarseIJK[2] = coarseNodeIdx / (coarseNodesPerDim[0] * coarseNodesPerDim[1]);
504 rem = coarseNodeIdx % (coarseNodesPerDim[0] * coarseNodesPerDim[1]);
505 coarseIJK[1] = rem / coarseNodesPerDim[0];
506 coarseIJK[0] = rem % coarseNodesPerDim[0];
508 for (
LO dim = 0; dim < 3; ++dim) {
509 if (coarseIJK[dim] == coarseNodesPerDim[dim] - 1) {
510 nodeIJK[dim] = fineNodesPerDim[dim] - 1;
512 nodeIJK[dim] = coarseIJK[dim] * coarseRate[dim];
515 fineNodeIdx = (nodeIJK[2] * fineNodesPerDim[1] + nodeIJK[1]) * fineNodesPerDim[0] + nodeIJK[0];
517 if (aggStat[interfaceNodes[fineNodeIdx]] ==
READY) {
518 vertex2AggId[interfaceNodes[fineNodeIdx]] = aggregateCount;
519 procWinner[interfaceNodes[fineNodeIdx]] = myRank;
520 aggStat[interfaceNodes[fineNodeIdx]] =
AGGREGATED;
522 --numNonAggregatedNodes;
524 nodesOnCoarseInterfaces[coarseNodeCount] = vertex2AggId[interfaceNodes[fineNodeIdx]];
531 for (
LO nodeIdx = 0; nodeIdx < numInterfaceNodes; ++nodeIdx) {
533 if (aggStat[interfaceNodes[nodeIdx]] ==
AGGREGATED) {
537 nodeIJK[2] = nodeIdx / (fineNodesPerDim[0] * fineNodesPerDim[1]);
538 rem = nodeIdx % (fineNodesPerDim[0] * fineNodesPerDim[1]);
539 nodeIJK[1] = rem / fineNodesPerDim[0];
540 nodeIJK[0] = rem % fineNodesPerDim[0];
542 for (
int dim = 0; dim < 3; ++dim) {
543 coarseIJK[dim] = nodeIJK[dim] / coarseRate[dim];
544 rem = nodeIJK[dim] % coarseRate[dim];
545 if (nodeIJK[dim] < fineNodesPerDim[dim] - endRate[dim]) {
546 rate = coarseRate[dim];
550 if (rem > (rate / 2)) {
555 for (
LO dim = 0; dim < 3; ++dim) {
556 if (coarseIJK[dim] == coarseNodesPerDim[dim] - 1) {
557 nodeIJK[dim] = fineNodesPerDim[dim] - 1;
559 nodeIJK[dim] = coarseIJK[dim] * coarseRate[dim];
562 fineNodeIdx = (nodeIJK[2] * fineNodesPerDim[1] + nodeIJK[1]) * fineNodesPerDim[0] + nodeIJK[0];
564 vertex2AggId[interfaceNodes[nodeIdx]] = vertex2AggId[interfaceNodes[fineNodeIdx]];
565 procWinner[interfaceNodes[nodeIdx]] = myRank;
566 aggStat[interfaceNodes[nodeIdx]] =
AGGREGATED;
567 --numNonAggregatedNodes;
575 Set(currentLevel,
"coarseInterfacesDimensions", coarseInterfacesDimensions);
576 Set(currentLevel,
"nodeOnCoarseInterface", nodesOnCoarseInterfaces);
Kokkos::View< unsigned *, typename LWGraphHostType::device_type > AggStatHostType
basic_FancyOStream & setProcRankAndSize(const int procRank, const int numProcs)
Algorithm for coarsening a graph with uncoupled aggregation. keep special marked nodes as singleton n...
const RCP< LOVector > & GetProcWinner() const
Returns constant vector that maps local node IDs to owning processor IDs.
Container class for aggregation information.
void setValidator(RCP< const ParameterEntryValidator > const &validator)
basic_FancyOStream & setShowProcRank(const bool showProcRank)
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Algorithm for coarsening a graph with structured aggregation.
void BuildInterfaceAggregates(Level ¤tLevel, RCP< Aggregates > aggregates, typename AggregationAlgorithmBase< LocalOrdinal, GlobalOrdinal, Node >::AggStatHostType &aggStat, LO &numNonAggregatedNodes, Array< LO > coarseRate) const
Specifically build aggregates along interfaces.
const RCP< const Map > GetMap() const
returns (overlapping) map of aggregate/node distribution
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
KOKKOS_INLINE_FUNCTION size_type GetNodeNumVertices() const
Return number of graph vertices.
KOKKOS_INLINE_FUNCTION const boundary_nodes_type GetBoundaryNodeMap() const
Returns map with global ids of boundary nodes.
void SetIndexManager(RCP< IndexManager > &geoData)
Set the index manager used by various aggregation algorithms. This has to be done by the aggregation ...
static const NoFactory * get()
Algorithm for coarsening a graph with uncoupled aggregation. creates aggregates along an interface us...
Builds one-to-one aggregates for all Dirichlet boundary nodes. For some applications this might be ne...
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
virtual void setObjectLabel(const std::string &objectLabel)
basic_FancyOStream & setShowAllFrontMatter(const bool showAllFrontMatter)
const RCP< LOMultiVector > & GetVertex2AggId() const
Returns constant vector that maps local node IDs to local aggregates IDs.
void resize(size_type new_size, const value_type &x=value_type())
const RCP< const Map > GetImportMap() const
Return overlapping import map (nodes).
void Build(Level ¤tLevel) const
Build aggregates.
Among unaggregated points, see if we can make a reasonable size aggregate out of it.IdeaAmong unaggregated points, see if we can make a reasonable size aggregate out of it. We do this by looking at neighbors and seeing how many are unaggregated and on my processor. Loosely, base the number of new aggregates created on the percentage of unaggregated nodes.
Add leftovers to existing aggregatesIdeaIn phase 2b non-aggregated nodes are added to existing aggreg...
void DeclareInput(Level ¤tLevel) const
Input.
const RCP< const Map > GetDomainMap() const
KOKKOS_INLINE_FUNCTION void AggregatesCrossProcessors(const bool &flag)
Record whether aggregates include DOFs from other processes.
Algorithm for coarsening a graph with uncoupled aggregation.
int GetLevelID() const
Return level number.
Exception throws to report errors in the internal logical of the program.
HybridAggregationFactory()
Constructor.
Handle leftover nodes. Try to avoid singleton nodesIdeaIn phase 3 we try to stick unaggregated nodes ...
#define SET_VALID_ENTRY(name)
ParameterEntry & getEntry(const std::string &name)
std::string description() const
Return a simple one-line description of this object.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
aggregates_sizes_type::const_type ComputeAggregateSizes(bool forceRecompute=false) const
Compute sizes of aggregates.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
void SetNumAggregates(LO nAggregates)
Set number of local aggregates on current processor.