Ifpack2 Templated Preconditioning Package Version 1.0
Loading...
Searching...
No Matches
Ifpack2_LinePartitioner_def.hpp
1// @HEADER
2// *****************************************************************************
3// Ifpack2: Templated Object-Oriented Algebraic Preconditioner Package
4//
5// Copyright 2009 NTESS and the Ifpack2 contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef IFPACK2_LINE_PARTITIONER_DEF_HPP
11#define IFPACK2_LINE_PARTITIONER_DEF_HPP
12
13#include "Tpetra_CrsGraph.hpp"
14#include "Tpetra_Util.hpp"
15
16namespace Ifpack2 {
17
18template <class T>
19inline typename Teuchos::ScalarTraits<T>::magnitudeType square(T x) {
20 return Teuchos::ScalarTraits<T>::magnitude(x) * Teuchos::ScalarTraits<T>::magnitude(x);
21}
22
23//==============================================================================
24// Constructor
25template <class GraphType, class Scalar>
27 LinePartitioner(const Teuchos::RCP<const row_graph_type>& graph)
28 : OverlappingPartitioner<GraphType>(graph)
29 , NumEqns_(1)
30 , threshold_(0.0) {}
31
32template <class GraphType, class Scalar>
34
35template <class GraphType, class Scalar>
37 setPartitionParameters(Teuchos::ParameterList& List) {
38 threshold_ = List.get("partitioner: line detection threshold", threshold_);
39 TEUCHOS_TEST_FOR_EXCEPTION(threshold_ < 0.0 || threshold_ > 1.0,
40 std::runtime_error, "Ifpack2::LinePartitioner: threshold not valid");
41
42 NumEqns_ = List.get("partitioner: PDE equations", NumEqns_);
43 TEUCHOS_TEST_FOR_EXCEPTION(NumEqns_ < 1, std::runtime_error, "Ifpack2::LinePartitioner: NumEqns not valid");
44
45 coord_ = List.get("partitioner: coordinates", coord_);
46 TEUCHOS_TEST_FOR_EXCEPTION(coord_.is_null(), std::runtime_error, "Ifpack2::LinePartitioner: coordinates not defined");
47}
48
49template <class GraphType, class Scalar>
51 const local_ordinal_type invalid = Teuchos::OrdinalTraits<local_ordinal_type>::invalid();
52
53 // Sanity Checks
54 TEUCHOS_TEST_FOR_EXCEPTION(coord_.is_null(), std::runtime_error, "Ifpack2::LinePartitioner: coordinates not defined");
55 TEUCHOS_TEST_FOR_EXCEPTION((size_t)this->Partition_.size() != this->Graph_->getLocalNumRows(), std::runtime_error, "Ifpack2::LinePartitioner: partition size error");
56
57 // Short circuit
58 if (this->Partition_.size() == 0) {
59 this->NumLocalParts_ = 0;
60 return;
61 }
62
63 // Set partitions to invalid to initialize algorithm
64 for (size_t i = 0; i < this->Graph_->getLocalNumRows(); i++)
65 this->Partition_[i] = invalid;
66
67 // Use the auto partitioner
68 this->NumLocalParts_ = this->Compute_Blocks_AutoLine(this->Partition_());
69
70 // Resize Parts_
71 this->Parts_.resize(this->NumLocalParts_);
72}
73
74// ============================================================================
75template <class GraphType, class Scalar>
76int LinePartitioner<GraphType, Scalar>::Compute_Blocks_AutoLine(Teuchos::ArrayView<local_ordinal_type> blockIndices) const {
77 typedef local_ordinal_type LO;
78 typedef magnitude_type MT;
79 const LO invalid = Teuchos::OrdinalTraits<LO>::invalid();
80 const MT zero = Teuchos::ScalarTraits<MT>::zero();
81
82 Teuchos::ArrayRCP<const MT> xvalsRCP, yvalsRCP, zvalsRCP;
83 Teuchos::ArrayView<const MT> xvals, yvals, zvals;
84 xvalsRCP = coord_->getData(0);
85 xvals = xvalsRCP();
86 if (coord_->getNumVectors() > 1) {
87 yvalsRCP = coord_->getData(1);
88 yvals = yvalsRCP();
89 }
90 if (coord_->getNumVectors() > 2) {
91 zvalsRCP = coord_->getData(2);
92 zvals = zvalsRCP();
93 }
94
95 double tol = threshold_;
96 size_t N = this->Graph_->getLocalNumRows();
97 size_t allocated_space = this->Graph_->getLocalMaxNumRowEntries();
98
99 nonconst_local_inds_host_view_type cols("cols", allocated_space);
100 Teuchos::Array<LO> indices(allocated_space);
101 Teuchos::Array<MT> dist(allocated_space);
102
103 Teuchos::Array<LO> itemp(2 * allocated_space);
104 Teuchos::Array<MT> dtemp(allocated_space);
105
106 LO num_lines = 0;
107
108 for (LO i = 0; i < (LO)N; i += NumEqns_) {
109 size_t nz = 0;
110 // Short circuit if I've already been blocked
111 if (blockIndices[i] != invalid) continue;
112
113 // Get neighbors and sort by distance
114 this->Graph_->getLocalRowCopy(i, cols, nz);
115 MT x0 = (!xvals.is_null()) ? xvals[i / NumEqns_] : zero;
116 MT y0 = (!yvals.is_null()) ? yvals[i / NumEqns_] : zero;
117 MT z0 = (!zvals.is_null()) ? zvals[i / NumEqns_] : zero;
118
119 LO neighbor_len = 0;
120 for (size_t j = 0; j < nz; j += NumEqns_) {
121 MT mydist = zero;
122 LO nn = cols[j] / NumEqns_;
123 if (cols[j] >= (LO)N) continue; // Check for off-proc entries
124 if (!xvals.is_null()) mydist += square<MT>(x0 - xvals[nn]);
125 if (!yvals.is_null()) mydist += square<MT>(y0 - yvals[nn]);
126 if (!zvals.is_null()) mydist += square<MT>(z0 - zvals[nn]);
127 dist[neighbor_len] = Teuchos::ScalarTraits<MT>::squareroot(mydist);
128 indices[neighbor_len] = cols[j];
129 neighbor_len++;
130 }
131
132 Teuchos::ArrayView<MT> dist_view = dist(0, neighbor_len);
133 Tpetra::sort2(dist_view.begin(), dist_view.end(), indices.begin());
134
135 // Number myself
136 for (LO k = 0; k < NumEqns_; k++)
137 blockIndices[i + k] = num_lines;
138
139 // Fire off a neighbor line search (nearest neighbor)
140 if (neighbor_len > 2 && dist[1] / dist[neighbor_len - 1] < tol) {
141 local_automatic_line_search(NumEqns_, blockIndices, i, indices[1], num_lines, tol, itemp, dtemp);
142 }
143 // Fire off a neighbor line search (second nearest neighbor)
144 if (neighbor_len > 3 && dist[2] / dist[neighbor_len - 1] < tol) {
145 local_automatic_line_search(NumEqns_, blockIndices, i, indices[2], num_lines, tol, itemp, dtemp);
146 }
147
148 num_lines++;
149 }
150 return num_lines;
151}
152// ============================================================================
153template <class GraphType, class Scalar>
154void LinePartitioner<GraphType, Scalar>::local_automatic_line_search(int NumEqns, Teuchos::ArrayView<local_ordinal_type> blockIndices, local_ordinal_type last, local_ordinal_type next, local_ordinal_type LineID, double tol, Teuchos::Array<local_ordinal_type> itemp, Teuchos::Array<magnitude_type> dtemp) const {
155 typedef local_ordinal_type LO;
156 typedef magnitude_type MT;
157 const LO invalid = Teuchos::OrdinalTraits<LO>::invalid();
158 const MT zero = Teuchos::ScalarTraits<MT>::zero();
159
160 Teuchos::ArrayRCP<const MT> xvalsRCP, yvalsRCP, zvalsRCP;
161 Teuchos::ArrayView<const MT> xvals, yvals, zvals;
162 xvalsRCP = coord_->getData(0);
163 xvals = xvalsRCP();
164 if (coord_->getNumVectors() > 1) {
165 yvalsRCP = coord_->getData(1);
166 yvals = yvalsRCP();
167 }
168 if (coord_->getNumVectors() > 2) {
169 zvalsRCP = coord_->getData(2);
170 zvals = zvalsRCP();
171 }
172
173 size_t N = this->Graph_->getLocalNumRows();
174 size_t allocated_space = this->Graph_->getLocalMaxNumRowEntries();
175
176 nonconst_local_inds_host_view_type cols(itemp.data(), allocated_space);
177 Teuchos::ArrayView<LO> indices = itemp.view(allocated_space, allocated_space);
178 Teuchos::ArrayView<MT> dist = dtemp();
179
180 while (blockIndices[next] == invalid) {
181 // Get the next row
182 size_t nz = 0;
183 LO neighbors_in_line = 0;
184
185 this->Graph_->getLocalRowCopy(next, cols, nz);
186 MT x0 = (!xvals.is_null()) ? xvals[next / NumEqns_] : zero;
187 MT y0 = (!yvals.is_null()) ? yvals[next / NumEqns_] : zero;
188 MT z0 = (!zvals.is_null()) ? zvals[next / NumEqns_] : zero;
189
190 // Calculate neighbor distances & sort
191 LO neighbor_len = 0;
192 for (size_t i = 0; i < nz; i += NumEqns) {
193 MT mydist = zero;
194 if (cols[i] >= (LO)N) continue; // Check for off-proc entries
195 LO nn = cols[i] / NumEqns;
196 if (blockIndices[nn] == LineID) neighbors_in_line++;
197 if (!xvals.is_null()) mydist += square<MT>(x0 - xvals[nn]);
198 if (!yvals.is_null()) mydist += square<MT>(y0 - yvals[nn]);
199 if (!zvals.is_null()) mydist += square<MT>(z0 - zvals[nn]);
200 dist[neighbor_len] = Teuchos::ScalarTraits<MT>::squareroot(mydist);
201 indices[neighbor_len] = cols[i];
202 neighbor_len++;
203 }
204 // If more than one of my neighbors is already in this line. I
205 // can't be because I'd create a cycle
206 if (neighbors_in_line > 1) break;
207
208 // Otherwise add me to the line
209 for (LO k = 0; k < NumEqns; k++)
210 blockIndices[next + k] = LineID;
211
212 // Try to find the next guy in the line (only check the closest two that aren't element 0 (diagonal))
213 Teuchos::ArrayView<MT> dist_view = dist(0, neighbor_len);
214 Tpetra::sort2(dist_view.begin(), dist_view.end(), indices.begin());
215
216 if (neighbor_len > 2 && indices[1] != last && blockIndices[indices[1]] == -1 && dist[1] / dist[neighbor_len - 1] < tol) {
217 last = next;
218 next = indices[1];
219 } else if (neighbor_len > 3 && indices[2] != last && blockIndices[indices[2]] == -1 && dist[2] / dist[neighbor_len - 1] < tol) {
220 last = next;
221 next = indices[2];
222 } else {
223 // I have no further neighbors in this line
224 break;
225 }
226 }
227}
228
229} // namespace Ifpack2
230
231#define IFPACK2_LINEPARTITIONER_INSTANT(S, LO, GO, N) \
232 template class Ifpack2::LinePartitioner<Tpetra::CrsGraph<LO, GO, N>, S>; \
233 template class Ifpack2::LinePartitioner<Tpetra::RowGraph<LO, GO, N>, S>;
234
235#endif // IFPACK2_LINEPARTITIONER_DEF_HPP
Ifpack2::LinePartitioner: A class to define partitions into a set of lines.
Definition Ifpack2_LinePartitioner_decl.hpp:45
LinePartitioner(const Teuchos::RCP< const row_graph_type > &graph)
Constructor.
Definition Ifpack2_LinePartitioner_def.hpp:27
void setPartitionParameters(Teuchos::ParameterList &List)
Set the partitioner's parameters (none for linear partitioning).
Definition Ifpack2_LinePartitioner_def.hpp:37
virtual ~LinePartitioner()
Destructor.
Definition Ifpack2_LinePartitioner_def.hpp:33
void computePartitions()
Compute the partitions.
Definition Ifpack2_LinePartitioner_def.hpp:50
Create overlapping partitions of a local graph.
Definition Ifpack2_OverlappingPartitioner_decl.hpp:45
Preconditioners and smoothers for Tpetra sparse matrices.
Definition Ifpack2_AdditiveSchwarz_decl.hpp:40