Coverage Report

Created: 2025-08-05 06:45

/src/quantlib/ql/methods/finitedifferences/schemes/trbdf2scheme.hpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*
4
 Copyright (C) 2018 Klaus Spanderen
5
6
 This file is part of QuantLib, a free-software/open-source library
7
 for financial quantitative analysts and developers - http://quantlib.org/
8
9
 QuantLib is free software: you can redistribute it and/or modify it
10
 under the terms of the QuantLib license.  You should have received a
11
 copy of the license along with this program; if not, please email
12
 <quantlib-dev@lists.sf.net>. The license is also available online at
13
 <http://quantlib.org/license.shtml>.
14
15
 This program is distributed in the hope that it will be useful, but WITHOUT
16
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17
 FOR A PARTICULAR PURPOSE.  See the license for more details.
18
*/
19
20
/*! \file trbdf2scheme.hpp
21
    \brief trapezoidal BDF2 scheme
22
*/
23
24
#ifndef quantlib_tr_bdf2_scheme_hpp
25
#define quantlib_tr_bdf2_scheme_hpp
26
27
#include <ql/functional.hpp>
28
#include <ql/math/functional.hpp>
29
#include <ql/math/matrixutilities/bicgstab.hpp>
30
#include <ql/math/matrixutilities/gmres.hpp>
31
#include <ql/methods/finitedifferences/operators/fdmlinearopcomposite.hpp>
32
#include <ql/methods/finitedifferences/operatortraits.hpp>
33
#include <ql/methods/finitedifferences/schemes/boundaryconditionschemehelper.hpp>
34
#include <utility>
35
36
namespace QuantLib {
37
38
    template <class TrapezoidalScheme>
39
    class TrBDF2Scheme {
40
      public:
41
        enum SolverType { BiCGstab, GMRES };
42
43
        // typedefs
44
        typedef OperatorTraits<FdmLinearOp> traits;
45
        typedef traits::operator_type operator_type;
46
        typedef traits::array_type array_type;
47
        typedef traits::bc_set bc_set;
48
        typedef traits::condition_type condition_type;
49
50
        // constructors
51
        TrBDF2Scheme(Real alpha,
52
                     ext::shared_ptr<FdmLinearOpComposite> map,
53
                     const ext::shared_ptr<TrapezoidalScheme>& trapezoidalScheme,
54
                     const bc_set& bcSet = bc_set(),
55
                     Real relTol = 1e-8,
56
                     SolverType solverType = BiCGstab);
57
58
        void step(array_type& a, Time t);
59
        void setStep(Time dt);
60
61
        Size numberOfIterations() const;
62
      protected:
63
        Array apply(const Array& r) const;
64
65
        Time dt_;
66
        Real beta_;
67
        ext::shared_ptr<Size> iterations_;
68
69
        const Real alpha_;
70
        const ext::shared_ptr<FdmLinearOpComposite> map_;
71
        const ext::shared_ptr<TrapezoidalScheme>& trapezoidalScheme_;
72
        const BoundaryConditionSchemeHelper bcSet_;
73
        const Real relTol_;
74
        const SolverType solverType_;
75
    };
76
77
    template <class TrapezoidalScheme>
78
    inline TrBDF2Scheme<TrapezoidalScheme>::TrBDF2Scheme(
79
        Real alpha,
80
        ext::shared_ptr<FdmLinearOpComposite> map,
81
        const ext::shared_ptr<TrapezoidalScheme>& trapezoidalScheme,
82
        const bc_set& bcSet,
83
        Real relTol,
84
        SolverType solverType)
85
0
    : dt_(Null<Real>()), beta_(Null<Real>()), iterations_(ext::make_shared<Size>(0U)),
86
0
      alpha_(alpha), map_(std::move(map)), trapezoidalScheme_(trapezoidalScheme), bcSet_(bcSet),
87
0
      relTol_(relTol), solverType_(solverType) {}
88
89
    template <class TrapezoidalScheme>
90
0
    inline void TrBDF2Scheme<TrapezoidalScheme>::setStep(Time dt) {
91
0
        dt_=dt;
92
0
        beta_= (1.0-alpha_)/(2.0-alpha_)*dt_;
93
0
    }
94
95
    template <class TrapezoidalScheme>
96
    inline Size TrBDF2Scheme<TrapezoidalScheme>::numberOfIterations() const {
97
        return *iterations_;
98
    }
99
100
    template <class TrapezoidalScheme>
101
0
    inline Array TrBDF2Scheme<TrapezoidalScheme>::apply(const Array& r) const {
102
0
        return r - beta_*map_->apply(r);
103
0
    }
104
105
    template <class TrapezoidalScheme>
106
0
    inline void TrBDF2Scheme<TrapezoidalScheme>::step(array_type& fn, Time t) {
107
0
        QL_REQUIRE(t-dt_ > -1e-8, "a step towards negative time given");
108
109
0
        const Time intermediateTimeStep = dt_*alpha_;
110
111
0
        array_type fStar = fn;
112
0
        trapezoidalScheme_->setStep(intermediateTimeStep);
113
0
        trapezoidalScheme_->step(fStar, t);
114
115
0
        bcSet_.setTime(std::max(0.0, t-dt_));
116
0
        bcSet_.applyBeforeSolving(*map_, fn);
117
118
0
        const array_type f =
119
0
            (1/alpha_*fStar - squared(1-alpha_)/alpha_*fn)/(2-alpha_);
120
121
0
        if (map_->size() == 1) {
122
0
            fn = map_->solve_splitting(0, f, -beta_);
123
0
        }
124
0
        else {
125
0
            auto preconditioner = [&](const Array& _a){ return map_->preconditioner(_a, -beta_); };
126
0
            auto applyF = [&](const Array& _a){ return apply(_a); };
127
128
0
            if (solverType_ == BiCGstab) {
129
0
                const BiCGStabResult result =
130
0
                    QuantLib::BiCGstab(applyF, std::max(Size(10), fn.size()),
131
0
                        relTol_, preconditioner).solve(f, f);
132
133
0
                (*iterations_) += result.iterations;
134
0
                fn = result.x;
135
0
            } else if (solverType_ == GMRES) {
136
0
                const GMRESResult result =
137
0
                    QuantLib::GMRES(applyF, std::max(Size(10), fn.size() / 10U), relTol_,
138
0
                                    preconditioner)
139
0
                        .solve(f, f);
140
141
0
                (*iterations_) += result.errors.size();
142
0
                fn = result.x;
143
0
            }
144
0
            else
145
0
                QL_FAIL("unknown/illegal solver type");
146
0
        }
147
148
0
        bcSet_.applyAfterSolving(fn);
149
0
    }
150
}
151
152
#endif