MueLu Version of the Day
MueLu_AggregationPhase3Algorithm_kokkos_def.hpp
Go to the documentation of this file.
1// @HEADER
2//
3// ***********************************************************************
4//
5// MueLu: A package for multigrid based preconditioning
6// Copyright 2012 Sandia Corporation
7//
8// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9// the U.S. Government retains certain rights in this software.
10//
11// Redistribution and use in source and binary forms, with or without
12// modification, are permitted provided that the following conditions are
13// met:
14//
15// 1. Redistributions of source code must retain the above copyright
16// notice, this list of conditions and the following disclaimer.
17//
18// 2. Redistributions in binary form must reproduce the above copyright
19// notice, this list of conditions and the following disclaimer in the
20// documentation and/or other materials provided with the distribution.
21//
22// 3. Neither the name of the Corporation nor the names of the
23// contributors may be used to endorse or promote products derived from
24// this software without specific prior written permission.
25//
26// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37//
38// Questions? Contact
39// Jonathan Hu (jhu@sandia.gov)
40// Andrey Prokopenko (aprokop@sandia.gov)
41// Ray Tuminaro (rstumin@sandia.gov)
42//
43// ***********************************************************************
44//
45// @HEADER
46#ifndef MUELU_AGGREGATIONPHASE3ALGORITHM_KOKKOS_DEF_HPP
47#define MUELU_AGGREGATIONPHASE3ALGORITHM_KOKKOS_DEF_HPP
48
49#ifdef HAVE_MUELU_KOKKOS_REFACTOR
50
51#include <Teuchos_Comm.hpp>
52#include <Teuchos_CommHelpers.hpp>
53
54#include <Xpetra_Vector.hpp>
55
57
58#include "MueLu_Aggregates_kokkos.hpp"
59#include "MueLu_Exceptions.hpp"
60#include "MueLu_LWGraph_kokkos.hpp"
61#include "MueLu_Monitor.hpp"
62
63// #include "Kokkos_Core.hpp"
64
65namespace MueLu {
66
67 // Try to stick unaggregated nodes into a neighboring aggregate if they are
68 // not already too big. Otherwise, make a new aggregate
69 template <class LocalOrdinal, class GlobalOrdinal, class Node>
70 void AggregationPhase3Algorithm_kokkos<LocalOrdinal, GlobalOrdinal, Node>::
71 BuildAggregates(const ParameterList& params,
72 const LWGraph_kokkos& graph,
73 Aggregates_kokkos& aggregates,
75 LO& numNonAggregatedNodes) const {
76
77 // So far we only have the non-deterministic version of the algorithm...
78 if(params.get<bool>("aggregation: deterministic")) {
79 Monitor m(*this, "BuildAggregatesDeterministic");
80 BuildAggregatesRandom(params, graph, aggregates, aggStat, numNonAggregatedNodes);
81 } else {
82 Monitor m(*this, "BuildAggregatesRandom");
83 BuildAggregatesRandom(params, graph, aggregates, aggStat, numNonAggregatedNodes);
84 }
85
86 }
87
88 // Try to stick unaggregated nodes into a neighboring aggregate if they are
89 // not already too big. Otherwise, make a new aggregate
90 template <class LocalOrdinal, class GlobalOrdinal, class Node>
91 void AggregationPhase3Algorithm_kokkos<LocalOrdinal, GlobalOrdinal, Node>::
92 BuildAggregatesRandom(const ParameterList& params,
93 const LWGraph_kokkos& graph,
94 Aggregates_kokkos& aggregates,
96 LO& numNonAggregatedNodes) const {
97
98 bool error_on_isolated = params.get<bool>("aggregation: error on nodes with no on-rank neighbors");
99 bool makeNonAdjAggs = params.get<bool>("aggregation: phase3 avoid singletons");
100
101 const LO numRows = graph.GetNodeNumVertices();
102 const int myRank = graph.GetComm()->getRank();
103
104 auto vertex2AggId = aggregates.GetVertex2AggId()->getDeviceLocalView(Xpetra::Access::ReadWrite);
105 auto procWinner = aggregates.GetProcWinner() ->getDeviceLocalView(Xpetra::Access::ReadWrite);
106 auto colors = aggregates.GetGraphColors();
107 const LO numColors = aggregates.GetGraphNumColors();
108
109 Kokkos::View<LO, device_type> numAggregates("numAggregates");
110 Kokkos::deep_copy(numAggregates, aggregates.GetNumAggregates());
111
112 Kokkos::View<unsigned*, device_type> aggStatOld("Initial aggregation status", aggStat.extent(0));
113 Kokkos::deep_copy(aggStatOld, aggStat);
114 Kokkos::View<LO, device_type> numNonAggregated("numNonAggregated");
115 Kokkos::deep_copy(numNonAggregated, numNonAggregatedNodes);
116 for(int color = 1; color < numColors + 1; ++color) {
117 Kokkos::parallel_for("Aggregation Phase 3: aggregates clean-up",
119 KOKKOS_LAMBDA(const LO nodeIdx) {
120 // Check if node has already been treated?
121 if( (colors(nodeIdx) != color) ||
122 (aggStatOld(nodeIdx) == AGGREGATED) ||
123 (aggStatOld(nodeIdx) == IGNORED) ){ return; }
124
125 // Grab node neighbors
126 auto neighbors = graph.getNeighborVertices(nodeIdx);
127 LO neighIdx;
128
129 // We don't want a singleton.
130 // So lets see if any neighbors can be used to form a new aggregate?
131 bool isNewAggregate = false;
132 for(int neigh = 0; neigh < neighbors.length; ++neigh) {
133 neighIdx = neighbors(neigh);
134
135 if((neighIdx != nodeIdx) &&
136 graph.isLocalNeighborVertex(neighIdx) &&
137 (aggStatOld(neighIdx) == READY)) {
138 isNewAggregate = true;
139 break;
140 }
141 }
142
143 // We can form a new non singleton aggregate!
144 if(isNewAggregate) {
145 // If this is the aggregate root
146 // we need to process the nodes in the aggregate
147 const LO aggId = Kokkos::atomic_fetch_add(&numAggregates(), 1);
148 aggStat(nodeIdx) = AGGREGATED;
149 procWinner(nodeIdx, 0) = myRank;
150 vertex2AggId(nodeIdx, 0) = aggId;
151 // aggregates.SetIsRoot(nodeIdx);
152 Kokkos::atomic_decrement(&numNonAggregated());
153 for(int neigh = 0; neigh < neighbors.length; ++neigh) {
154 neighIdx = neighbors(neigh);
155 if((neighIdx != nodeIdx) &&
156 graph.isLocalNeighborVertex(neighIdx) &&
157 (aggStatOld(neighIdx) == READY)) {
158 aggStat(neighIdx) = AGGREGATED;
159 procWinner(neighIdx, 0) = myRank;
160 vertex2AggId(neighIdx, 0) = aggId;
161 Kokkos::atomic_decrement(&numNonAggregated());
162 }
163 }
164 return;
165 }
166
167 // Getting a little desperate!
168 // Let us try to aggregate into a neighboring aggregate
169 for(int neigh = 0; neigh < neighbors.length; ++neigh) {
170 neighIdx = neighbors(neigh);
171 if (graph.isLocalNeighborVertex(neighIdx) &&
172 (aggStatOld(neighIdx) == AGGREGATED)) {
173 aggStat(nodeIdx) = AGGREGATED;
174 procWinner(nodeIdx, 0) = myRank;
175 vertex2AggId(nodeIdx, 0) = vertex2AggId(neighIdx, 0);
176 Kokkos::atomic_decrement(&numNonAggregated());
177 return;
178 }
179 }
180
181 // Getting quite desperate!
182 // Let us try to make a non contiguous aggregate
183 if(makeNonAdjAggs) {
184 for(LO otherNodeIdx = 0; otherNodeIdx < numRows; ++otherNodeIdx) {
185 if((otherNodeIdx != nodeIdx) &&
186 (aggStatOld(otherNodeIdx) == AGGREGATED)) {
187 aggStat(nodeIdx) = AGGREGATED;
188 procWinner(nodeIdx, 0) = myRank;
189 vertex2AggId(nodeIdx, 0) = vertex2AggId(otherNodeIdx, 0);
190 Kokkos::atomic_decrement(&numNonAggregated());
191 return;
192 }
193 }
194 }
195
196 // Total deperation!
197 // Let us make a singleton
198 if(!error_on_isolated) {
199 const LO aggId = Kokkos::atomic_fetch_add(&numAggregates(), 1);
200 aggStat(nodeIdx) = AGGREGATED;
201 procWinner(nodeIdx, 0) = myRank;
202 vertex2AggId(nodeIdx, 0) = aggId;
203 Kokkos::atomic_decrement(&numNonAggregated());
204 }
205 });
206 // LBV on 09/27/19: here we could copy numNonAggregated to host
207 // and check for it to be equal to 0 in which case we can stop
208 // looping over the different colors...
209 Kokkos::deep_copy(aggStatOld, aggStat);
210 } // loop over colors
211
212 auto numNonAggregated_h = Kokkos::create_mirror_view(numNonAggregated);
213 Kokkos::deep_copy(numNonAggregated_h, numNonAggregated);
214 numNonAggregatedNodes = numNonAggregated_h();
215 if( (error_on_isolated) && (numNonAggregatedNodes > 0) ) {
216 // Error on this isolated node, as the user has requested
217 std::ostringstream oss;
218 oss<<"MueLu::AggregationPhase3Algorithm::BuildAggregates: MueLu has detected a non-Dirichlet node that has no on-rank neighbors and is terminating (by user request). "<<std::endl;
219 oss<<"If this error is being generated at level 0, this is due to an initial partitioning problem in your matrix."<<std::endl;
220 oss<<"If this error is being generated at any other level, try turning on repartitioning, which may fix this problem."<<std::endl;
221 throw Exceptions::RuntimeError(oss.str());
222 }
223
224 // update aggregate object
225 auto numAggregates_h = Kokkos::create_mirror_view(numAggregates);
226 Kokkos::deep_copy(numAggregates_h, numAggregates);
227 aggregates.SetNumAggregates(numAggregates_h());
228 }
229
230} // end namespace
231
232#endif // HAVE_MUELU_KOKKOS_REFACTOR
233#endif // MUELU_AGGREGATIONPHASE3ALGORITHM_KOKKOS_DEF_HPP
KOKKOS_INLINE_FUNCTION constexpr std::enable_if< std::is_integral< iType >::value, size_t >::type extent(const iType &r) const noexcept
Namespace for MueLu classes and methods.
@ AGGREGATED
Definition: MueLu_Types.hpp:73