10 #ifndef MUELU_HYBRIDAGGREGATIONFACTORY_DEF_HPP_
11 #define MUELU_HYBRIDAGGREGATIONFACTORY_DEF_HPP_
14 #include <Xpetra_Map.hpp>
16 #include <Xpetra_MultiVectorFactory.hpp>
22 #include "MueLu_InterfaceAggregationAlgorithm.hpp"
23 #include "MueLu_OnePtAggregationAlgorithm.hpp"
24 #include "MueLu_PreserveDirichletAggregationAlgorithm.hpp"
26 #include "MueLu_AggregationPhase1Algorithm.hpp"
27 #include "MueLu_AggregationPhase2aAlgorithm.hpp"
28 #include "MueLu_AggregationPhase2bAlgorithm.hpp"
29 #include "MueLu_AggregationPhase3Algorithm.hpp"
32 #include "MueLu_AggregationStructuredAlgorithm.hpp"
33 #include "MueLu_UncoupledIndexManager.hpp"
39 #include "MueLu_LWGraph.hpp"
40 #include "MueLu_Aggregates.hpp"
46 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
49 : bDefinitionPhase_(true) {}
51 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
56 #define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
69 SET_VALID_ENTRY(
"aggregation: error on nodes with no on-rank neighbors");
83 #undef SET_VALID_ENTRY
88 validParamList->
set<
RCP<const FactoryBase> >(
"DofsPerNode", null,
"Generating factory for variable \'DofsPerNode\', usually the same as for \'Graph\'");
90 validParamList->
set<std::string>(
"OnePt aggregate map name",
"",
91 "Name of input map for single node aggregates. (default='')");
92 validParamList->
set<std::string>(
"OnePt aggregate map factory",
"",
93 "Generating factory of (DOF) map for single node aggregates.");
96 validParamList->
set<std::string>(
"Interface aggregate map name",
"",
97 "Name of input map for interface aggregates. (default='')");
98 validParamList->
set<std::string>(
"Interface aggregate map factory",
"",
99 "Generating factory of (DOF) map for interface aggregates.");
101 "Describes the dimensions of all the interfaces on this rank.");
103 "List the LIDs of the nodes on any interface.");
108 "Number of spatial dimension provided by CoordinatesTransferFactory.");
110 "Number of nodes per spatial dimmension provided by CoordinatesTransferFactory.");
114 "Type of aggregation to use on the region (\"structured\" or \"uncoupled\")");
116 return validParamList;
119 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
122 Input(currentLevel,
"Graph");
135 "Aggregation region type was not provided by the user!");
142 "numDimensions was not provided by the user on level0!");
149 "lNodesPerDim was not provided by the user on level0!");
152 Input(currentLevel,
"aggregationRegionType");
153 Input(currentLevel,
"numDimensions");
154 Input(currentLevel,
"lNodesPerDim");
158 Input(currentLevel,
"DofsPerNode");
161 if (pL.
get<
bool>(
"aggregation: use interface aggregation") ==
true) {
168 "interfacesDimensions was not provided by the user on level0!");
175 "nodeOnInterface was not provided by the user on level0!");
178 Input(currentLevel,
"interfacesDimensions");
179 Input(currentLevel,
"nodeOnInterface");
184 std::string mapOnePtName = pL.
get<std::string>(
"OnePt aggregate map name");
185 if (mapOnePtName.length() > 0) {
186 std::string mapOnePtFactName = pL.
get<std::string>(
"OnePt aggregate map factory");
187 if (mapOnePtFactName ==
"" || mapOnePtFactName ==
"NoFactory") {
196 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
202 if (
const char* dbg = std::getenv(
"MUELU_HYBRIDAGGREGATION_DEBUG")) {
203 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
209 *out <<
"Entering hybrid aggregation" << std::endl;
212 bDefinitionPhase_ =
false;
214 if (pL.
get<
int>(
"aggregation: max agg size") == -1)
215 pL.
set(
"aggregation: max agg size", INT_MAX);
223 const int myRank = fineMap->getComm()->getRank();
224 const int numRanks = fineMap->getComm()->getSize();
236 AggStatHostType aggStat(Kokkos::ViewAllocateWithoutInitializing(
"aggregation status"), numRows);
237 Kokkos::deep_copy(aggStat,
READY);
240 std::string regionType;
241 if (currentLevel.GetLevelID() == 0) {
243 regionType = currentLevel.Get<std::string>(
"aggregationRegionType",
NoFactory::get());
246 regionType = Get<std::string>(currentLevel,
"aggregationRegionType");
249 int numDimensions = 0;
250 if (currentLevel.GetLevelID() == 0) {
252 numDimensions = currentLevel.Get<
int>(
"numDimensions",
NoFactory::get());
255 numDimensions = Get<int>(currentLevel,
"numDimensions");
259 std::string coarseningRate = pL.
get<std::string>(
"aggregation: coarsening rate");
262 coarseRate = Teuchos::fromStringToArray<LO>(coarseningRate);
264 GetOStream(
Errors, -1) <<
" *** \"aggregation: coarsening rate\" must be a string convertible into an array! *** "
270 "\"aggregation: coarsening rate\" must have at least as many"
271 " components as the number of spatial dimensions in the problem.");
274 LO numNonAggregatedNodes = numRows;
275 if (regionType ==
"structured") {
281 const int interpolationOrder = pL.
get<
int>(
"aggregation: coarsening order");
283 if (currentLevel.GetLevelID() == 0) {
288 lFineNodesPerDir = Get<Array<LO> >(currentLevel,
"lNodesPerDim");
292 for (
int dim = numDimensions; dim < 3; ++dim) {
293 lFineNodesPerDir[dim] = 1;
310 "The local number of elements in the graph's map is not equal to "
311 "the number of nodes given by: lNodesPerDim!");
316 Set(currentLevel,
"lCoarseNodesPerDim", geoData->getLocalCoarseNodesPerDir());
320 if (regionType ==
"uncoupled") {
330 *out <<
" Build interface aggregates" << std::endl;
332 if (pL.
get<
bool>(
"aggregation: use interface aggregation") ==
true) {
333 BuildInterfaceAggregates(currentLevel, aggregates, aggStat, numNonAggregatedNodes,
337 *out <<
"Treat Dirichlet BC" << std::endl;
340 for (
LO i = 0; i < numRows; i++)
341 if (dirichletBoundaryMap[i] ==
true)
345 std::string mapOnePtName = pL.
get<std::string>(
"OnePt aggregate map name");
347 if (mapOnePtName.length()) {
348 std::string mapOnePtFactName = pL.
get<std::string>(
"OnePt aggregate map factory");
349 if (mapOnePtFactName ==
"" || mapOnePtFactName ==
"NoFactory") {
353 OnePtMap = currentLevel.Get<
RCP<Map> >(mapOnePtName, mapOnePtFact.
get());
357 LO nDofsPerNode = Get<LO>(currentLevel,
"DofsPerNode");
359 if (OnePtMap != Teuchos::null) {
360 for (
LO i = 0; i < numRows; i++) {
362 GO grid = (graph->
GetDomainMap()->getGlobalElement(i) - indexBase) * nDofsPerNode + indexBase;
363 for (
LO kr = 0; kr < nDofsPerNode; kr++)
364 if (OnePtMap->isNodeGlobalElement(grid + kr))
371 Set(currentLevel,
"lCoarseNodesPerDim", lCoarseNodesPerDir);
376 *out <<
"Run all the algorithms on the local rank" << std::endl;
377 for (
size_t a = 0; a < algos_.size(); a++) {
378 std::string phase = algos_[a]->description();
380 *out << regionType <<
" | Executing phase " << a << std::endl;
382 int oldRank = algos_[a]->SetProcRankVerbose(this->GetProcRankVerbose());
383 algos_[a]->BuildAggregatesNonKokkos(pL, *graph, *aggregates, aggStat, numNonAggregatedNodes);
384 algos_[a]->SetProcRankVerbose(oldRank);
385 *out << regionType <<
" | Done Executing phase " << a << std::endl;
388 *out <<
"Compute statistics on aggregates" << std::endl;
391 Set(currentLevel,
"Aggregates", aggregates);
392 Set(currentLevel,
"numDimensions", numDimensions);
393 Set(currentLevel,
"aggregationRegionTypeCoarse", regionType);
396 *out <<
"HybridAggregation done!" << std::endl;
399 template <
class LocalOrdinal,
class GlobalOrdinal,
class Node>
404 FactoryMonitor m(*
this,
"BuildInterfaceAggregates", currentLevel);
407 if (
const char* dbg = std::getenv(
"MUELU_HYBRIDAGGREGATION_DEBUG")) {
408 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
415 if (coarseRate.
size() == 1) {
416 coarseRate.
resize(3, coarseRate[0]);
420 Array<LO> interfacesDimensions = Get<Array<LO> >(currentLevel,
"interfacesDimensions");
421 Array<LO> nodesOnInterfaces = Get<Array<LO> >(currentLevel,
"nodeOnInterface");
422 const int numInterfaces = interfacesDimensions.
size() / 3;
423 const int myRank = aggregates->
GetMap()->getComm()->getRank();
426 Array<LO> coarseInterfacesDimensions(interfacesDimensions.
size());
429 LO endRate, totalNumCoarseNodes = 0, numCoarseNodes;
430 for (
int interfaceIdx = 0; interfaceIdx < numInterfaces; ++interfaceIdx) {
432 for (
int dim = 0; dim < 3; ++dim) {
433 endRate = (interfacesDimensions[3 * interfaceIdx + dim] - 1) % coarseRate[dim];
434 if (interfacesDimensions[3 * interfaceIdx + dim] == 1) {
435 coarseInterfacesDimensions[3 * interfaceIdx + dim] = 1;
437 coarseInterfacesDimensions[3 * interfaceIdx + dim] = (interfacesDimensions[3 * interfaceIdx + dim] - 1) / coarseRate[dim] + 2;
439 coarseInterfacesDimensions[3 * interfaceIdx + dim]--;
442 numCoarseNodes *= coarseInterfacesDimensions[3 * interfaceIdx + dim];
444 totalNumCoarseNodes += numCoarseNodes;
446 nodesOnCoarseInterfaces.
resize(totalNumCoarseNodes, -1);
450 LO interfaceOffset = 0, aggregateCount = 0, coarseNodeCount = 0;
451 for (
int interfaceIdx = 0; interfaceIdx < numInterfaces; ++interfaceIdx) {
452 ArrayView<LO> fineNodesPerDim = interfacesDimensions(3 * interfaceIdx, 3);
453 ArrayView<LO> coarseNodesPerDim = coarseInterfacesDimensions(3 * interfaceIdx, 3);
454 LO numInterfaceNodes = 1, numCoarseNodes = 1;
455 for (
int dim = 0; dim < 3; ++dim) {
456 numInterfaceNodes *= fineNodesPerDim[dim];
457 numCoarseNodes *= coarseNodesPerDim[dim];
458 endRate[dim] = (fineNodesPerDim[dim] - 1) % coarseRate[dim];
460 ArrayView<LO> interfaceNodes = nodesOnInterfaces(interfaceOffset, numInterfaceNodes);
462 interfaceOffset += numInterfaceNodes;
464 LO rem, rate, fineNodeIdx;
465 Array<LO> nodeIJK(3), coarseIJK(3), rootIJK(3);
468 for (
LO coarseNodeIdx = 0; coarseNodeIdx < numCoarseNodes; ++coarseNodeIdx) {
469 coarseIJK[2] = coarseNodeIdx / (coarseNodesPerDim[0] * coarseNodesPerDim[1]);
470 rem = coarseNodeIdx % (coarseNodesPerDim[0] * coarseNodesPerDim[1]);
471 coarseIJK[1] = rem / coarseNodesPerDim[0];
472 coarseIJK[0] = rem % coarseNodesPerDim[0];
474 for (
LO dim = 0; dim < 3; ++dim) {
475 if (coarseIJK[dim] == coarseNodesPerDim[dim] - 1) {
476 nodeIJK[dim] = fineNodesPerDim[dim] - 1;
478 nodeIJK[dim] = coarseIJK[dim] * coarseRate[dim];
481 fineNodeIdx = (nodeIJK[2] * fineNodesPerDim[1] + nodeIJK[1]) * fineNodesPerDim[0] + nodeIJK[0];
483 if (aggStat[interfaceNodes[fineNodeIdx]] ==
READY) {
484 vertex2AggId[interfaceNodes[fineNodeIdx]] = aggregateCount;
485 procWinner[interfaceNodes[fineNodeIdx]] = myRank;
486 aggStat[interfaceNodes[fineNodeIdx]] =
AGGREGATED;
488 --numNonAggregatedNodes;
490 nodesOnCoarseInterfaces[coarseNodeCount] = vertex2AggId[interfaceNodes[fineNodeIdx]];
497 for (
LO nodeIdx = 0; nodeIdx < numInterfaceNodes; ++nodeIdx) {
499 if (aggStat[interfaceNodes[nodeIdx]] ==
AGGREGATED) {
503 nodeIJK[2] = nodeIdx / (fineNodesPerDim[0] * fineNodesPerDim[1]);
504 rem = nodeIdx % (fineNodesPerDim[0] * fineNodesPerDim[1]);
505 nodeIJK[1] = rem / fineNodesPerDim[0];
506 nodeIJK[0] = rem % fineNodesPerDim[0];
508 for (
int dim = 0; dim < 3; ++dim) {
509 coarseIJK[dim] = nodeIJK[dim] / coarseRate[dim];
510 rem = nodeIJK[dim] % coarseRate[dim];
511 if (nodeIJK[dim] < fineNodesPerDim[dim] - endRate[dim]) {
512 rate = coarseRate[dim];
516 if (rem > (rate / 2)) {
521 for (
LO dim = 0; dim < 3; ++dim) {
522 if (coarseIJK[dim] == coarseNodesPerDim[dim] - 1) {
523 nodeIJK[dim] = fineNodesPerDim[dim] - 1;
525 nodeIJK[dim] = coarseIJK[dim] * coarseRate[dim];
528 fineNodeIdx = (nodeIJK[2] * fineNodesPerDim[1] + nodeIJK[1]) * fineNodesPerDim[0] + nodeIJK[0];
530 vertex2AggId[interfaceNodes[nodeIdx]] = vertex2AggId[interfaceNodes[fineNodeIdx]];
531 procWinner[interfaceNodes[nodeIdx]] = myRank;
532 aggStat[interfaceNodes[nodeIdx]] =
AGGREGATED;
533 --numNonAggregatedNodes;
541 Set(currentLevel,
"coarseInterfacesDimensions", coarseInterfacesDimensions);
542 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)
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.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
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.