10 #include "Teko_BlockImplicitLinearOp.hpp"
11 #include "Teko_HierarchicalGaussSeidelPreconditionerFactory.hpp"
21 BlockedMultiVector extractSubBlockVector(
const BlockedMultiVector& blo,
22 const std::vector<int>& rows) {
23 const int nrows = rows.size();
24 TEUCHOS_ASSERT(blockCount(blo) >= nrows);
25 std::vector<MultiVector> subVectors;
26 for (
int row_id = 0; row_id < nrows; ++row_id) {
27 const auto row = rows[row_id];
28 subVectors.push_back(getBlock(row, blo));
31 return buildBlockedMultiVector(subVectors);
34 BlockedLinearOp extractSubblockMatrix(
const BlockedLinearOp& blo,
const std::vector<int>& rows,
35 const std::vector<int>& cols) {
36 int nOuterBlockRows = blockRowCount(blo);
37 for (
auto&& row : rows) {
38 TEUCHOS_ASSERT(row < nOuterBlockRows);
40 int nOuterBlockCols = blockColCount(blo);
41 for (
auto&& col : cols) {
42 TEUCHOS_ASSERT(col < nOuterBlockCols);
46 auto subblock = createBlockedOp();
48 const int nInnerBlockRows = rows.size();
49 const int nInnerBlockCols = cols.size();
52 subblock->beginBlockFill(nInnerBlockRows, nInnerBlockCols);
53 for (
int innerBlockRow = 0U; innerBlockRow < nInnerBlockRows; ++innerBlockRow) {
54 for (
int innerBlockCol = 0U; innerBlockCol < nInnerBlockCols; ++innerBlockCol) {
55 auto [outerBlockRow, outerBlockCol] =
56 std::make_tuple(rows[innerBlockRow], cols[innerBlockCol]);
57 auto A_row_col = blo->getBlock(outerBlockRow, outerBlockCol);
59 if (A_row_col != Teuchos::null) {
60 subblock->setBlock(innerBlockRow, innerBlockCol, A_row_col);
66 for (
int outerBlock = 0; outerBlock < nOuterBlockCols; ++outerBlock) {
67 auto A_ij = blo->getBlock(outerBlockRow, outerBlock);
68 if (A_ij != Teuchos::null) {
69 range = A_ij->range();
74 for (
int outerBlock = 0; outerBlock < nOuterBlockRows; ++outerBlock) {
75 auto A_ij = blo->getBlock(outerBlock, outerBlockCol);
76 if (A_ij != Teuchos::null) {
77 domain = A_ij->domain();
82 TEUCHOS_ASSERT(range != Teuchos::null);
83 TEUCHOS_ASSERT(domain != Teuchos::null);
85 subblock->setBlock(innerBlockRow, innerBlockCol, zero(range, domain));
90 subblock->endBlockFill();
95 std::vector<std::string> tokenize_input(std::string input,
const std::string& delimiter) {
97 std::vector<std::string> tokens;
98 while ((pos = input.find(delimiter)) != std::string::npos) {
99 tokens.push_back(input.substr(0, pos));
100 input.erase(0, pos + delimiter.length());
102 tokens.push_back(input);
109 std::optional<int> extract_hierarchical_block_number(
const Teuchos::ParameterList& params,
110 const std::string& key) {
111 const std::string blockHierarchy =
"Hierarchical Block ";
112 if (key.find(blockHierarchy) == std::string::npos)
return {};
113 if (!params.isSublist(key))
return {};
115 int blockNumber = -1;
117 auto tokens = tokenize_input(key,
" ");
118 blockNumber = std::stoi(tokens.back());
119 }
catch (std::exception& err) {
120 std::ostringstream ss;
121 ss <<
"Error occured when trying to parse entry with key " << key <<
"\n";
122 ss <<
"It said:\n" << err.what() <<
"\n";
123 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error, ss.str());
125 return blockNumber - 1;
128 std::vector<int> extract_block_numbers(
const Teuchos::ParameterList& params) {
129 const std::string includedBlocks =
"Included Subblocks";
131 std::ostringstream ss;
132 ss <<
"Parameter 'Included Subblocks' is missing for params:\n" << params;
133 TEUCHOS_TEST_FOR_EXCEPTION(!params.isParameter(includedBlocks), std::runtime_error, ss.str());
134 std::vector<int> blocks;
136 auto blockStrs = tokenize_input(params.get<std::string>(includedBlocks),
",");
137 for (
const auto& blockStr : blockStrs) {
138 blocks.emplace_back(std::stoi(blockStr) - 1);
140 }
catch (std::exception& err) {
141 std::ostringstream errSS;
142 errSS <<
"Error occured when trying to parse 'Included SubBlocks' for params:\n"
144 errSS <<
"It said:\n" << err.what() <<
"\n";
145 TEUCHOS_TEST_FOR_EXCEPTION(
true, std::runtime_error, errSS.str());
150 unsigned index(
unsigned i,
unsigned j,
unsigned N) {
return i * N + j; }
154 NestedBlockGS::NestedBlockGS(
const std::map<
int, std::vector<int>>& blockToRow_,
155 const std::map<int, LinearOp>& blockToInvOp_, BlockedLinearOp& A_,
156 bool useLowerTriangle_)
157 : blockToRow(blockToRow_),
158 blockToInvOp(blockToInvOp_),
160 useLowerTriangle(useLowerTriangle_) {
161 productRange_ = A->productRange();
162 productDomain_ = A->productDomain();
163 const auto Nrows = blockToRow.size();
164 Ab.resize(Nrows * Nrows);
165 for (
auto [hierchicalBlockRow, rows] : blockToRow) {
166 for (
auto [hierchicalBlockCol, cols] : blockToRow) {
167 Ab[index(hierchicalBlockRow, hierchicalBlockCol, Nrows)] =
168 extractSubblockMatrix(A, rows, cols);
173 void NestedBlockGS::implicitApply(
const BlockedMultiVector& r, BlockedMultiVector& z,
174 const double alpha,
const double beta)
const {
175 const int blocks = blockToRow.size();
177 auto src = deepcopy(r);
178 std::vector<BlockedMultiVector> rVec;
179 std::vector<BlockedMultiVector> zVec;
181 for (
int b = 0; b < blocks; b++) {
182 rVec.push_back(extractSubBlockVector(src, blockToRow.at(b)));
183 zVec.push_back(extractSubBlockVector(z, blockToRow.at(b)));
186 if (useLowerTriangle) {
187 lowerTriangularImplicitApply(rVec, zVec, alpha, beta);
189 upperTriangularImplicitApply(rVec, zVec, alpha, beta);
193 void NestedBlockGS::upperTriangularImplicitApply(std::vector<BlockedMultiVector>& r,
194 std::vector<BlockedMultiVector>& z,
196 const double )
const {
197 const int blocks = blockToRow.size();
199 for (
int b = blocks - 1; b >= 0; b--) {
200 int blockCount = Teko::blockCount(r[b]);
201 if (blockCount == 1) {
202 auto r_b = Teko::getBlock(0, r[b]);
203 auto z_b = Teko::getBlock(0, z[b]);
204 applyOp(blockToInvOp.at(b), r_b, z_b);
206 applyOp(blockToInvOp.at(b), r[b], z[b]);
209 for (
int i = 0; i < b; i++) {
210 auto u_ib = Ab[index(i, b, blocks)];
211 if (u_ib != Teuchos::null) {
212 applyOp(u_ib, z[b], r[i], -1.0, 1.0);
218 void NestedBlockGS::lowerTriangularImplicitApply(std::vector<BlockedMultiVector>& r,
219 std::vector<BlockedMultiVector>& z,
221 const double )
const {
222 const int blocks = blockToRow.size();
224 for (
int b = 0; b < blocks; b++) {
225 int blockCount = Teko::blockCount(r[b]);
226 if (blockCount == 1) {
227 auto r_b = Teko::getBlock(0, r[b]);
228 auto z_b = Teko::getBlock(0, z[b]);
229 applyOp(blockToInvOp.at(b), r_b, z_b);
231 applyOp(blockToInvOp.at(b), r[b], z[b]);
235 for (
int i = b + 1; i < blocks; i++) {
236 auto l_ib = Ab[index(i, b, blocks)];
237 if (l_ib != Teuchos::null) {
238 applyOp(l_ib, z[b], r[i], -1.0, 1.0);
244 HierarchicalGaussSeidelPreconditionerFactory::HierarchicalGaussSeidelPreconditionerFactory() =
247 LinearOp HierarchicalGaussSeidelPreconditionerFactory::buildPreconditionerOperator(
248 BlockedLinearOp& blo, BlockPreconditionerState& state)
const {
249 for (
auto [hierarchicalBlockNum, blocks] : blockToRow) {
250 auto A_bb = extractSubblockMatrix(blo, blocks, blocks);
251 blockToInvOp[hierarchicalBlockNum] = this->buildBlockInverse(
252 *blockToInverse.at(hierarchicalBlockNum), blockToPreconditioner.at(hierarchicalBlockNum),
253 A_bb, state, hierarchicalBlockNum);
256 return Teuchos::rcp(
new NestedBlockGS(blockToRow, blockToInvOp, blo, useLowerTriangle));
259 LinearOp HierarchicalGaussSeidelPreconditionerFactory::buildBlockInverse(
260 const InverseFactory& invFact,
const Teuchos::RCP<InverseFactory>& precFact,
261 const BlockedLinearOp& matrix, BlockPreconditionerState& state,
262 int hierarchicalBlockNum)
const {
264 const int nBlock = Teko::blockRowCount(matrix);
266 const auto& subblockMatrix = Teko::getBlock(0, 0, matrix);
267 return buildInverseImpl<LinearOp>(invFact, precFact, subblockMatrix, state,
268 hierarchicalBlockNum);
271 return buildInverseImpl<BlockedLinearOp>(invFact, precFact, matrix, state, hierarchicalBlockNum);
274 void HierarchicalGaussSeidelPreconditionerFactory::initializeFromParameterList(
275 const Teuchos::ParameterList& pl) {
276 RCP<const InverseLibrary> invLib = getInverseLibrary();
278 for (
const auto& entry : pl) {
279 const auto key = entry.first;
280 const auto value = entry.second;
281 auto hierarchicalBlockNumber = extract_hierarchical_block_number(pl, key);
282 if (!hierarchicalBlockNumber)
continue;
283 const auto& hierarchicalParams = pl.sublist(key);
284 blockToRow[*hierarchicalBlockNumber] = extract_block_numbers(hierarchicalParams);
286 std::ostringstream ss;
287 ss <<
"Missing required parameter \"Inverse Type\" for hierarchical block "
288 << *hierarchicalBlockNumber <<
"\n";
289 TEUCHOS_TEST_FOR_EXCEPTION(!hierarchicalParams.isParameter(
"Inverse Type"), std::runtime_error,
291 auto invStr = hierarchicalParams.get<std::string>(
"Inverse Type");
292 blockToInverse[*hierarchicalBlockNumber] = invLib->getInverseFactory(invStr);
294 blockToPreconditioner[*hierarchicalBlockNumber] = Teuchos::null;
295 if (hierarchicalParams.isParameter(
"Preconditioner Type")) {
296 auto precStr = hierarchicalParams.get<std::string>(
"Preconditioner Type");
297 blockToPreconditioner[*hierarchicalBlockNumber] = invLib->getInverseFactory(precStr);
301 useLowerTriangle =
false;
302 if (pl.isParameter(
"Use Upper Triangle")) {
303 useLowerTriangle = !pl.get<
bool>(
"Use Upper Triangle");