Tempus Version of the Day
Time Integration
Loading...
Searching...
No Matches
Tempus_AdjointDAEJumpSolver.hpp
Go to the documentation of this file.
1//@HEADER
2// *****************************************************************************
3// Tempus: Time Integration and Sensitivity Analysis Package
4//
5// Copyright 2017 NTESS and the Tempus contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8//@HEADER
9
10#ifndef Tempus_AdjointDAEJumpSolver_hpp
11#define Tempus_AdjointDAEJumpSolver_hpp
12
13#include <algorithm>
14#include <string>
15
16#include "Teuchos_Array.hpp"
17#include "Teuchos_ParameterList.hpp"
18#include "Teuchos_RCP.hpp"
19#include "Teuchos_ScalarTraits.hpp"
20#include "Teuchos_TestForException.hpp"
21#include "Teuchos_VerboseObject.hpp"
22#include "Thyra_LinearOpWithSolveBase.hpp"
23#include "Thyra_ModelEvaluator.hpp"
24#include "Thyra_MultiVectorStdOps.hpp"
25#include "Thyra_VectorStdOps.hpp"
26
29
30namespace Tempus {
31
71template <class Scalar>
73 public:
76 typedef typename Teuchos::ScalarTraits<Scalar>::magnitudeType Mag;
77
79 static const std::string& sublistName()
80 {
81 static const std::string name("Algebraic Jump Solver");
82 return name;
83 }
84
85 static Teuchos::RCP<const Teuchos::ParameterList> getValidParameters()
86 {
87 Teuchos::RCP<Teuchos::ParameterList> pl =
88 Teuchos::parameterList(sublistName());
89 pl->set<double>("Relative Tolerance", 1.0e-10, "Tolerance on max_j |b_j - C^T z_j| / |b_j|");
90 pl->set<int>("Maximum Iterations Per Alpha", 20, "Maximum number of Richardson iterations for each alpha");
91 pl->set<double>("Initial Alpha Factor", 1.0, "Initial alpha, times the time step size at the response time");
92 pl->set<double>("Alpha Growth Factor", 10.0, "Factor by which alpha is increased when the iterations stagnate");
93 pl->set<int>("Maximum Alpha Increases", 8, "Maximum number of increases of alpha");
94 pl->set<double>("Minimum Residual Reduction", 0.5,
95 "alpha is increased when an iteration reduces the residual by a factor larger than this");
96 pl->set<bool>("Verbose", false, "Print the residual at each iteration");
97 return pl;
98 }
99
102 const Teuchos::RCP<const DAEStructure<Scalar> >& dae,
103 const Teuchos::RCP<const Teuchos::ParameterList>& pl = Teuchos::null)
104 : dae_(dae)
105 {
106 TEUCHOS_TEST_FOR_EXCEPTION(
107 dae_ == Teuchos::null, std::invalid_argument,
108 "Error - Tempus::AdjointDAEJumpSolver: null DAE structure.\n");
109 Teuchos::ParameterList params(sublistName());
110 if (pl != Teuchos::null) params = *pl;
111 params.validateParametersAndSetDefaults(*getValidParameters());
112 rel_tol_ = params.get<double>("Relative Tolerance");
113 max_iters_ = params.get<int>("Maximum Iterations Per Alpha");
114 alpha_factor_ = params.get<double>("Initial Alpha Factor");
115 alpha_growth_ = params.get<double>("Alpha Growth Factor");
116 max_alpha_increases_ = params.get<int>("Maximum Alpha Increases");
117 min_reduction_ = params.get<double>("Minimum Residual Reduction");
118 verbose_ = params.get<bool>("Verbose");
119 TEUCHOS_TEST_FOR_EXCEPTION(
120 alpha_factor_ <= 0.0 || alpha_growth_ <= 1.0 || max_iters_ < 1 ||
121 max_alpha_increases_ < 0 || min_reduction_ <= 0.0 ||
122 min_reduction_ >= 1.0,
123 std::invalid_argument,
124 "Error - Tempus::AdjointDAEJumpSolver: invalid options (need "
125 "\"Initial Alpha Factor\" > 0, \"Alpha Growth Factor\" > 1, "
126 "\"Maximum Iterations Per Alpha\" >= 1, \"Maximum Alpha Increases\" "
127 ">= 0, 0 < \"Minimum Residual Reduction\" < 1).\n");
128 }
129
140 bool solve(const Thyra::ModelEvaluator<Scalar>& adjoint_model,
141 const Thyra::ModelEvaluatorBase::InArgs<Scalar>& inArgs,
142 const Scalar dt, const MultiVector& b, MultiVector& z) const
143 {
144 using Teuchos::RCP;
145 typedef Teuchos::ScalarTraits<Scalar> ST;
146 typedef Thyra::ModelEvaluatorBase MEB;
147
148 TEUCHOS_TEST_FOR_EXCEPTION(
149 !(dt > Scalar(0.0)), std::logic_error,
150 "Error - Tempus::AdjointDAEJumpSolver: the time step size must be "
151 "positive (dt = "
152 << dt << ").\n");
153 RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
154
155 // E^T and A^T at the forward state
156 RCP<Thyra::LinearOpBase<Scalar> > ET = adjoint_model.create_W_op();
157 RCP<Thyra::LinearOpBase<Scalar> > AT = adjoint_model.create_W_op();
158 {
159 MEB::InArgs<Scalar> in = inArgs;
160 MEB::OutArgs<Scalar> outs = adjoint_model.createOutArgs();
161 in.set_alpha(ST::one());
162 in.set_beta(ST::zero());
163 outs.set_W_op(ET);
164 adjoint_model.evalModel(in, outs);
165 in.set_alpha(ST::zero());
166 in.set_beta(ST::one());
167 outs.set_W_op(AT);
168 adjoint_model.evalModel(in, outs);
169 }
170
171 const int num_cols = b.domain()->dim();
172 Teuchos::Array<Mag> b_norms(num_cols);
173 Thyra::norms_2(b, b_norms());
174 Thyra::assign(Teuchos::ptrFromRef(z), ST::zero());
175 if (*std::max_element(b_norms.begin(), b_norms.end()) == Teuchos::ScalarTraits<Mag>::zero())
176 return true;
177
178 RCP<MultiVector> r = b.clone_mv(); // residual, x space
179 RCP<MultiVector> w = z.clone_mv(); // correction, residual space
180 RCP<Vector> d = Thyra::createMember(dae_->getAlgebraicMask()->space());
181
182 Scalar alpha = Scalar(alpha_factor_) / dt;
183 Mag res = residual(*ET, *AT, b, z, b_norms, *r);
184 int num_solves = 0;
185 for (int level = 0; level <= max_alpha_increases_; ++level) {
186 // Solver of W(alpha,1) = (alpha E + A)^T, and D_alpha^{-1} = P_a + alpha P_d
187 RCP<Thyra::LinearOpWithSolveBase<Scalar> > W =
188 AdjointSensitivityUtils::createAdjointLinearOpWithSolve(adjoint_model, inArgs, alpha, ST::one());
189 Thyra::assign(d.ptr(), *dae_->getAlgebraicMask());
190 Thyra::Vp_StV(d.ptr(), alpha, *dae_->getDifferentialMask());
191
192 for (int it = 0; it < max_iters_; ++it) {
193 if (res <= Mag(rel_tol_)) {
194 if (verbose_)
195 *out << "Tempus::AdjointDAEJumpSolver: converged, residual " << res
196 << ", alpha*dt = " << alpha * dt << ", " << num_solves
197 << " solves" << std::endl;
198 return true;
199 }
200 // z <- z + D_alpha^{-1} W(alpha,1)^{-1} r
201 Thyra::assign(w.ptr(), ST::zero());
202 W->solve(Thyra::NOTRANS, *r, w.ptr());
203 ++num_solves;
204 for (int j = 0; j < num_cols; ++j)
205 Thyra::ele_wise_scale(*d, w->col(j).ptr());
206 Thyra::update(ST::one(), *w, Teuchos::ptrFromRef(z));
207
208 const Mag res_old = res;
209 res = residual(*ET, *AT, b, z, b_norms, *r);
210 if (verbose_)
211 *out << "Tempus::AdjointDAEJumpSolver: alpha*dt = " << alpha * dt
212 << ", iteration " << it + 1 << ", residual " << res
213 << std::endl;
214 if (res > Mag(min_reduction_) * res_old) break; // increase alpha
215 }
216 if (res <= Mag(rel_tol_)) return true;
217 alpha *= Scalar(alpha_growth_);
218 }
219 *out << "WARNING - Tempus::AdjointDAEJumpSolver: no convergence, relative "
220 << "residual " << res << " > " << rel_tol_ << " after " << num_solves
221 << " solves (final alpha*dt = " << alpha * dt / Scalar(alpha_growth_)
222 << ")." << std::endl;
223 return false;
224 }
225
226 private:
230 const Thyra::LinearOpBase<Scalar>& AT, const MultiVector& b,
231 const MultiVector& z, const Teuchos::Array<Mag>& b_norms,
232 MultiVector& r) const
233 {
234 typedef Teuchos::ScalarTraits<Scalar> ST;
235 Teuchos::RCP<MultiVector> za = z.clone_mv();
236 dae_->zeroDifferentialComponents(*za);
237 Teuchos::RCP<MultiVector> zd = z.clone_mv();
238 dae_->zeroAlgebraicComponents(*zd);
239 Thyra::assign(Teuchos::ptrFromRef(r), b);
240 AT.apply(Thyra::NOTRANS, *za, Teuchos::ptrFromRef(r), -ST::one(), ST::one());
241 ET.apply(Thyra::NOTRANS, *zd, Teuchos::ptrFromRef(r), -ST::one(), ST::one());
242
243 Teuchos::Array<Mag> r_norms(b_norms.size());
244 Thyra::norms_2(r, r_norms());
245 Mag res = Teuchos::ScalarTraits<Mag>::zero();
246 for (int j = 0; j < static_cast<int>(b_norms.size()); ++j)
247 if (b_norms[j] > Teuchos::ScalarTraits<Mag>::zero())
248 res = std::max(res, r_norms[j] / b_norms[j]);
249 return res;
250 }
251
252 Teuchos::RCP<const DAEStructure<Scalar> > dae_;
253 double rel_tol_;
260};
261
262} // namespace Tempus
263
264#endif // Tempus_AdjointDAEJumpSolver_hpp
bool solve(const Thyra::ModelEvaluator< Scalar > &adjoint_model, const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const Scalar dt, const MultiVector &b, MultiVector &z) const
Solve C^T z = b for each column of b.
AdjointDAEJumpSolver(const Teuchos::RCP< const DAEStructure< Scalar > > &dae, const Teuchos::RCP< const Teuchos::ParameterList > &pl=Teuchos::null)
Constructor. pl (optional) is the "Algebraic Jump Solver" sublist.
Mag residual(const Thyra::LinearOpBase< Scalar > &ET, const Thyra::LinearOpBase< Scalar > &AT, const MultiVector &b, const MultiVector &z, const Teuchos::Array< Mag > &b_norms, MultiVector &r) const
Teuchos::ScalarTraits< Scalar >::magnitudeType Mag
static const std::string & sublistName()
Name of the "Sensitivities" sublist with the options of this solver.
Thyra::MultiVectorBase< Scalar > MultiVector
static Teuchos::RCP< const Teuchos::ParameterList > getValidParameters()
Teuchos::RCP< const DAEStructure< Scalar > > dae_
Structure of an index-1 differential-algebraic system.
Teuchos::RCP< Thyra::LinearOpWithSolveBase< Scalar > > createAdjointLinearOpWithSolve(const Thyra::ModelEvaluator< Scalar > &adjoint_model, const Thyra::ModelEvaluatorBase::InArgs< Scalar > &inArgs, const Scalar alpha, const Scalar beta)
Create a solver for the adjoint model's W = (alpha*df/dx_dot + beta*df/dx)^T at inArgs.