Flow123d  release_2.2.0-22-g936454a
pade_approximant.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file pade_approximant.cc
15  * @brief
16  */
17 
18 #include <armadillo>
19 
20 #include "system/global_defs.h"
21 #include "input/accessors.hh"
22 #include "input/factory.hh"
23 #include "system/sys_profiler.hh"
26 
27 
28 // FLOW123D_FORCE_LINK_IN_CHILD(padeApproximant)
29 
30 
31 using namespace Input::Type;
32 
33 
35  return Record("PadeApproximant",
36  "Record with an information about pade approximant parameters."
37  "Note that stable method is guaranteed only if d-n=1 or d-n=2, "
38  "where d=degree of denominator and n=degree of nominator. "
39  "In those cases the Pade approximant corresponds to an implicit "
40  "Runge-Kutta method which is both A- and L-stable. "
41  "The default values n=2, d=3 yield relatively good precision "
42  "while keeping the order moderately low.")
43 // .derive_from(LinearODESolverBase::get_input_type())
44  .declare_key("pade_nominator_degree", Integer(1), Default("1"),
45  "Polynomial degree of the nominator of Pade approximant.")
46  .declare_key("pade_denominator_degree", Integer(1), Default("3"),
47  "Polynomial degree of the denominator of Pade approximant")
48  .close();
49 }
50 
52  Input::register_class< PadeApproximant, Input::Record >("PadeApproximant") +
54 
56 {
57  nominator_degree_ = in_rec.val<int>("pade_nominator_degree");
58  denominator_degree_ = in_rec.val<int>("pade_denominator_degree");
59  if (nominator_degree_+1 != denominator_degree_ &&
60  nominator_degree_+2 != denominator_degree_)
61  WarningOut() << "Pade approximation can be unstable since (denominator_degree-nominator_degree) is not 1 or 2.\n";
62 }
63 
64 PadeApproximant::PadeApproximant(unsigned int nominator_degree, unsigned int denominator_degree)
65 : nominator_degree_(nominator_degree), denominator_degree_(denominator_degree)
66 {
67 }
68 
70 {
71 }
72 
73 void PadeApproximant::update_solution(arma::vec& init_vector, arma::vec& output_vec)
74 {
75  if(step_changed_)
76  {
77  solution_matrix_ = system_matrix_*step_; //coefficients multiplied by time
79  step_changed_ = false;
80  }
81 
82  output_vec = solution_matrix_ * init_vector;
83 }
84 
85 
86 void PadeApproximant::approximate_matrix(arma::mat &matrix)
87 {
88  START_TIMER("ODEAnalytic::compute_matrix");
89 
90  OLD_ASSERT(matrix.n_rows == matrix.n_cols, "Matrix is not square.");
91 
92  unsigned int size = matrix.n_rows;
93 
94  //compute Pade Approximant
95  arma::mat nominator_matrix(size, size),
96  denominator_matrix(size, size);
97 
98  nominator_matrix.fill(0);
99  denominator_matrix.fill(0);
100 
101  std::vector<double> nominator_coefs(nominator_degree_+1),
102  denominator_coefs(denominator_degree_+1);
103 
104  // compute Pade approximant polynomials for the function e^x
105  compute_exp_coefs(nominator_degree_, denominator_degree_, nominator_coefs, denominator_coefs);
106  // evaluation of polynomials of Pade approximant where x = -kt = R
107  evaluate_matrix_polynomial(nominator_matrix, matrix, nominator_coefs);
108  evaluate_matrix_polynomial(denominator_matrix, matrix, denominator_coefs);
109  // compute P(R(t)) / Q(R(t))
110  matrix = nominator_matrix * inv(denominator_matrix);
111 }
112 
113 void PadeApproximant::compute_exp_coefs(unsigned int nominator_degree,
114  unsigned int denominator_degree,
115  std::vector< double >& nominator_coefs,
116  std::vector< double >& denominator_coefs)
117 {
118  // compute factorials in forward
119  std::vector<unsigned int> factorials(nominator_degree+denominator_degree+1);
120  factorials[0] = 1;
121  for(unsigned int i = 1; i < factorials.size(); i++)
122  factorials[i] = factorials[i-1]*i;
123 
124  int sign; // variable for denominator sign alternation
125 
126  for(int j = nominator_degree; j >= 0; j--)
127  {
128  nominator_coefs[j] =
129  (double)(factorials[nominator_degree + denominator_degree - j] * factorials[nominator_degree])
130  / (factorials[nominator_degree + denominator_degree] * factorials[j] * factorials[nominator_degree - j]);
131  }
132 
133  for(int i = denominator_degree; i >= 0; i--)
134  {
135  if(i % 2 == 0) sign = 1; else sign = -1;
136  denominator_coefs[i] = sign *
137  (double)(factorials[nominator_degree + denominator_degree - i] * factorials[denominator_degree])
138  / (factorials[nominator_degree + denominator_degree] * factorials[i] * factorials[denominator_degree - i]);
139  }
140 }
141 
142 void PadeApproximant::evaluate_matrix_polynomial(arma::mat& polynomial_matrix,
143  const arma::mat& input_matrix,
144  const std::vector< double >& coefs)
145 {
146  arma::mat identity = arma::eye(input_matrix.n_rows, input_matrix.n_cols);
147 
148  ///Horner scheme for evaluating polynomial a0 + [a1 + [a2 + [a3 +...]*R(t)]*R(t)]*R(t)
149  for(int i = coefs.size()-1; i >= 0; i--)
150  {
151  polynomial_matrix = coefs[i] * identity + (polynomial_matrix * input_matrix);
152  }
153  //polynomial_matrix.print();
154 }
arma::mat system_matrix_
the square matrix of ODE system
void approximate_matrix(arma::mat &matrix)
int nominator_degree_
Degree of the polynomial in the nominator.
unsigned int size() const
Returns number of keys in the Record.
Definition: type_record.hh:598
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:61
void compute_exp_coefs(unsigned int nominator_degree, unsigned int denominator_degree, std::vector< double > &nominator_coefs, std::vector< double > &denominator_coefs)
Evaluates nominator and denominator coeficients of PadeApproximant for exponencial function...
void update_solution(arma::vec &init_vector, arma::vec &output_vec) override
Updates solution of the ODEs system.
Class for declaration of the integral input data.
Definition: type_base.hh:489
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:303
#define OLD_ASSERT(...)
Definition: global_defs.h:131
int denominator_degree_
Degree of the polynomial in the denominator.
Global macros to enhance readability and debugging, general constants.
PadeApproximant()
Hide default constructor.
Accessor to the data with type Type::Record.
Definition: accessors.hh:292
static const Input::Type::Record & get_input_type()
const Ret val(const string &key) const
#define START_TIMER(tag)
Starts a timer with specified tag.
static const int registrar
Registrar of class to factory.
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:490
bool step_changed_
flag is true if the step has been changed
void evaluate_matrix_polynomial(arma::mat &polynomial_matrix, const arma::mat &input_matrix, const std::vector< double > &coefs)
Evaluates the matrix polynomial by Horner scheme.
~PadeApproximant(void)
Destructor.
double step_
the step of the numerical method
arma::mat solution_matrix_
Solution matrix .
#define WarningOut()
Macro defining &#39;warning&#39; record of log.
Definition: logger.hh:236
Record type proxy class.
Definition: type_record.hh:182