12 #include "Teko_AdaptivePreconditionerFactory.hpp"
13 #include "Teko_ImplicitLinearOp.hpp"
14 #include "Teko_PreconditionerState.hpp"
16 #include "Teuchos_ENull.hpp"
20 using SizeOrdinalType = AdaptivePreconditionerFactory::SizeOrdinalType;
24 LinearOp
buildInverse(
const InverseFactory &invFact,
const Teuchos::RCP<InverseFactory> &precFact,
25 const LinearOp &matrix, PreconditionerState &state,
26 const std::string &opPrefix,
size_t i) {
28 ss << opPrefix <<
"_" << i;
30 ModifiableLinearOp &invOp = state.getModifiableOp(ss.str());
31 ModifiableLinearOp &precOp = state.getModifiableOp(
"prec_" + ss.str());
33 if (precFact != Teuchos::null) {
34 if (precOp == Teuchos::null) {
35 precOp = precFact->buildInverse(matrix);
36 state.addModifiableOp(
"prec_" + ss.str(), precOp);
42 if (invOp == Teuchos::null) {
43 if (precOp.is_null()) {
49 if (precOp.is_null()) {
59 class AdaptiveLinearOp :
public ImplicitLinearOp {
61 AdaptiveLinearOp(LinearOp A_,
const std::vector<Teuchos::RCP<InverseFactory>> &inverses_,
62 const std::vector<Teuchos::RCP<InverseFactory>> &preconditioners_,
63 const std::vector<SizeOrdinalType> &maximumSizes_, PreconditionerState &state_,
64 AdaptiveSolverSettings settings_)
67 preconditioners(preconditioners_),
68 maximumSizes(maximumSizes_),
71 subblockSize = A->range()->dim();
74 ~AdaptiveLinearOp()
override =
default;
76 VectorSpace range()
const override {
return A->range(); }
77 VectorSpace domain()
const override {
return A->domain(); }
79 void implicitApply(
const MultiVector &x, MultiVector &y,
const double alpha = 1.0,
80 const double beta = 0.0)
const override {
81 bool converged =
true;
82 bool additionalIterationsRequired =
false;
83 double residualReduction = 0.0;
84 bool try_next_solver =
true;
87 applyOp(A_inv, x, y, alpha, beta);
89 residualReduction = computeMaxRelativeNorm(x, y);
91 converged = residualReduction <= settings.targetResidualReduction;
92 if (converged)
continue;
94 if (!has_another_solver())
break;
96 try_next_solver = setup_next_solver();
98 additionalIterationsRequired =
true;
100 }
while (!converged && try_next_solver);
102 successfulApplications++;
103 if (additionalIterationsRequired || !converged) successfulApplications = 0;
106 if (successfulApplications >= settings.numAppliesCycle && index != 0) {
108 successfulApplications = 0;
113 void describe(Teuchos::FancyOStream &out_arg,
114 const Teuchos::EVerbosityLevel verbLevel)
const override {
115 A->describe(out_arg, verbLevel);
118 void initialize_step()
const { setup_solver(); }
121 bool has_another_solver()
const {
return (index + 1) < inverses.size(); }
123 bool setup_solver()
const {
124 if (subblockSize > maximumSizes.at(index)) {
129 A_inv =
buildInverse(*inverses.at(index), preconditioners.at(index), A, state, prefix, index);
131 }
catch (std::exception &exc) {
136 bool setup_next_solver()
const {
137 if (!has_another_solver())
return false;
139 const auto currentSolverIndex = index;
140 while (has_another_solver()) {
142 const auto success = setup_solver();
143 if (success)
return true;
146 index = currentSolverIndex;
150 double computeMaxRelativeNorm(
const MultiVector &x, MultiVector &y)
const {
151 const double alpha = 1.0;
152 std::vector<double> norms(y->domain()->dim());
153 std::vector<double> rhsNorms(x->domain()->dim());
155 auto residual = deepcopy(x);
156 applyOp(A, y, residual, -1.0, alpha);
158 Thyra::norms_2<double>(*residual, Teuchos::arrayViewFromVector(norms));
159 Thyra::norms_2<double>(*x, Teuchos::arrayViewFromVector(rhsNorms));
161 double maxRelRes = 0.0;
162 for (
auto i = 0U; i < norms.size(); ++i) {
163 const auto relRes = rhsNorms[i] == 0 ? norms[i] : norms[i] / rhsNorms[i];
164 maxRelRes = std::max(relRes, maxRelRes);
171 std::vector<Teuchos::RCP<InverseFactory>> inverses;
172 std::vector<Teuchos::RCP<InverseFactory>> preconditioners;
173 std::vector<SizeOrdinalType> maximumSizes;
174 PreconditionerState &state;
175 AdaptiveSolverSettings settings;
176 SizeOrdinalType subblockSize;
177 mutable size_t index = 0;
178 mutable int successfulApplications = 0;
179 mutable LinearOp A_inv;
181 const std::string prefix =
"adaptive";
184 LinearOp create_adaptive_linear_operator(
185 const LinearOp &A,
const std::vector<Teuchos::RCP<InverseFactory>> &inverses,
186 const std::vector<Teuchos::RCP<InverseFactory>> &preconditioners,
187 const std::vector<SizeOrdinalType> &maximumSizes, PreconditionerState &state,
188 const AdaptiveSolverSettings &settings) {
189 ModifiableLinearOp &adaptiveOp = state.getModifiableOp(
"adaptive_linear_op");
190 if (adaptiveOp == Teuchos::null) {
191 adaptiveOp = Teuchos::rcp(
192 new AdaptiveLinearOp(A, inverses, preconditioners, maximumSizes, state, settings));
196 auto adaptiveSolver = Teuchos::rcp_dynamic_cast<AdaptiveLinearOp>(adaptiveOp);
197 adaptiveSolver->initialize_step();
207 return create_adaptive_linear_operator(lo, inverses, preconditioners, maximumSizes, state,
212 settings.numAppliesCycle = 100;
213 settings.targetResidualReduction = 0.1;
215 if (pl.isParameter(
"Target Residual Reduction")) {
216 settings.targetResidualReduction = pl.get<
double>(
"Target Residual Reduction");
219 if (pl.isParameter(
"Number of Successful Applications Before Resetting")) {
220 settings.numAppliesCycle = pl.get<
int>(
"Number of Successful Applications Before Resetting");
223 const std::string inverse_type =
"Inverse Type";
224 const std::string preconditioner_type =
"Preconditioner Type";
225 const std::string maximum_size_subblock =
"Maximum Size";
228 std::set<int> positions;
229 for (
const auto &entry : pl) {
230 auto fieldName = entry.first;
233 bool isInverse = fieldName.find(inverse_type) != std::string::npos;
234 if (!isInverse)
continue;
237 std::string inverse, type;
240 std::stringstream ss(fieldName);
241 ss >> inverse >> type >> position;
244 Teko_DEBUG_MSG(
"Adaptive \"Inverse Type\" must be a (strictly) positive integer", 1);
247 positions.insert(position);
250 inverses.resize(positions.size());
251 preconditioners.resize(positions.size());
252 maximumSizes.resize(positions.size());
253 std::fill(maximumSizes.begin(), maximumSizes.end(), std::numeric_limits<SizeOrdinalType>::max());
256 for (
const auto &position : positions) {
257 auto inverseName = inverse_type + std::string(
" ") + std::to_string(position);
258 auto preconditionerName = preconditioner_type + std::string(
" ") + std::to_string(position);
259 auto maximumSizeName = maximum_size_subblock + std::string(
" ") + std::to_string(position);
262 const auto &invStr = pl.get<std::string>(inverseName);
263 inverses[position - 1] = invLib->getInverseFactory(invStr);
265 if (pl.isParameter(preconditionerName)) {
266 const auto &precStr = pl.get<std::string>(preconditionerName);
267 preconditioners[position - 1] = invLib->getInverseFactory(precStr);
270 if (pl.isParameter(maximumSizeName)) {
271 const auto maxSizeSubblock = pl.get<SizeOrdinalType>(maximumSizeName);
272 maximumSizes[position - 1] = maxSizeSubblock;
void rebuildInverse(const InverseFactory &factory, const LinearOp &A, InverseLinearOp &invA)
void initializeFromParameterList(const Teuchos::ParameterList &pl) override
This function builds the internals of the preconditioner factory from a parameter list...
LinearOp buildPreconditionerOperator(LinearOp &lo, PreconditionerState &state) const override
Function that is called to build the preconditioner for the linear operator that is passed in...
InverseLinearOp buildInverse(const InverseFactory &factory, const LinearOp &A)
Build an inverse operator using a factory and a linear operator.
Teuchos::RCP< const InverseLibrary > getInverseLibrary() const
Get the inverse library used by this preconditioner factory.
An implementation of a state object preconditioners.