CppNoddy  0.92
Loading...
Searching...
No Matches
ODE_EVP.cpp
Go to the documentation of this file.
1/// \file ODE_EVP.cpp
2/// A specification of a class for an \f$ n^{th} \f$-order ODE LINEAR EVP defined by
3/// \f[ {\underline f}^\prime (x) = {\underline R}( {\underline f}(x), x )\,, \f]
4/// subject to \f$ n \f$ zero Dirichlet conditions defined at \f$ x = x_{left} \f$ or
5/// \f$ x_{right} \f$ for some components of \f$ {\underline f}(x) \f$. The routine
6/// constructs a banded 2nd order finite-difference (banded) representation of the EVP
7/// in the form \f[ A_{MxM} {\underline x} = \lambda B_{MxM} {\underline x} \f]
8/// which can then be solved via the LinearEigenSystem class where
9/// \f$ M = N x O \f$ for an order O equation and N (uniformly spaced) mesh points. The default
10/// configuration uses the DenseLinearEigenSystem class for solution via LAPACK
11/// although ARPACK can be used if you really know the resulting system has the
12/// correct mass matrix properties (typically it wont!).
13
14#include <string>
15
16#include <Types.h>
17#include <Equation.h>
18#include <Utility.h>
19#include <ODE_EVP.h>
20#include <Exceptions.h>
22#include <Equation_2matrix.h>
23
24namespace CppNoddy {
25 template <typename _Type>
27 const DenseVector<double> &nodes,
28 Residual<_Type>* ptr_to_left_residual,
29 Residual<_Type>* ptr_to_right_residual) :
30 p_EQUATION(ptr_to_equation),
31 p_LEFT_RESIDUAL(ptr_to_left_residual),
32 p_RIGHT_RESIDUAL(ptr_to_right_residual),
33 NODES(nodes) {
34 unsigned n(nodes.size());
35 unsigned order(p_EQUATION -> get_order());
36 // first make the dense matrix equivalent of the problem
37 // using the Dense( banded ) constructor
38 p_A_DENSE = new DenseMatrix<_Type>(n * order, n * order, 0.0);
39 p_B_DENSE = new DenseMatrix<_Type>(n * order, n * order, 0.0);
40 // point the system pointer to the dense problem
41 p_SYSTEM = new DenseLinearEigenSystem<_Type>(p_A_DENSE, p_B_DENSE);
42 }
43
44 template <typename _Type>
46 // clean up the matrices & evp system
47 delete p_SYSTEM;
48 delete p_A_DENSE;
49 delete p_B_DENSE;
50 }
51
52 template <typename _Type>
54 return p_SYSTEM;
55 }
56
57 template <typename _Type>
59 // NOTE: moving construct_banded_system to the constructor is a bad idea, because
60 // sometimes we will want to construct an EVP that depends on an
61 // underlying baseflow solution that is unknown at the time of construction.
62 //
63 // construct the banded matrix eigenvalue problem that corresponds
64 // to the equation & boundary conditions specified in the constructor.
65 assemble_dense_problem();
66 // solve the system
67 p_SYSTEM -> eigensolve();
68 }
69
70
71 template <typename _Type>
73 // clear the A & B matrices, as they could have been filled with
74 // pivoting if this is a second solve.
75 p_A_DENSE -> assign(0.0);
76 p_B_DENSE -> assign(0.0);
77 // eqn order
78 unsigned order(p_EQUATION -> get_order());
79 // Jacobian matrix for the equation
80 DenseMatrix<_Type> jac_midpt(order, order, 0.0);
81 // local state variable and functions
82 // the problem has to be linear, so this is a dummy vector.
83 DenseVector<_Type> temp_dummy(order, 0.0);
84 // number of nodes in the mesh
85 std::size_t num_of_nodes(NODES.size());
86 // row counter
87 std::size_t row(0);
88
89 // update the BC residuals for the current iteration
90 p_LEFT_RESIDUAL -> update(temp_dummy);
91 // add the (linearised) LHS BCs to the matrix problem
92 for(unsigned i = 0; i < p_LEFT_RESIDUAL -> get_order(); ++i) {
93 // loop thru variables at LHS of the domain
94 for(unsigned var = 0; var < order; ++var) {
95 (*p_A_DENSE)(row, var) = p_LEFT_RESIDUAL -> jacobian()(i, var);
96 (*p_B_DENSE)(row, var) = 0.0;
97 }
98 ++row;
99 }
100
101 // inner nodes of the mesh, node = 0,1,2,...,num_of_nodes-2
102 for(std::size_t node = 0; node <= num_of_nodes - 2; ++node) {
103 const std::size_t lnode = node;
104 const std::size_t rnode = node + 1;
105 // get the current step length
106 double h = NODES[ rnode ] - NODES[ lnode ];
107 // reciprocal of the spatial step
108 const double invh(1. / h);
109 // mid point of the independent variable
110 double x_midpt = 0.5 * (NODES[ lnode ] + NODES[ rnode ]);
111 p_EQUATION -> coord(0) = x_midpt;
112 // Update the equation to the mid point position
113 p_EQUATION -> update(temp_dummy);
114 // loop over all the variables and fill the matrix
115 for(unsigned var = 0; var < order; ++var) {
116 std::size_t placement_row(row + var);
117 // deriv at the MID POINT between nodes
118 (*p_A_DENSE)(placement_row, order * rnode + var) = invh;
119 (*p_A_DENSE)(placement_row, order * lnode + var) = -invh;
120 // add the Jacobian terms to the linearised problem
121 for(unsigned i = 0; i < order; ++i) {
122 (*p_A_DENSE)(placement_row, order * lnode + i) -= 0.5 * p_EQUATION -> jacobian()(var, i);
123 (*p_A_DENSE)(placement_row, order * rnode + i) -= 0.5 * p_EQUATION -> jacobian()(var, i);
124 }
125 // RHS
126 for(unsigned i = 0; i < order; ++i) {
127 (*p_B_DENSE)(placement_row, order * lnode + i) -= 0.5 * p_EQUATION -> matrix1()(var, i);
128 (*p_B_DENSE)(placement_row, order * rnode + i) -= 0.5 * p_EQUATION -> matrix1()(var, i);
129 }
130 }
131 // increment the row
132 row += order;
133 }
134
135 // update the BC residuals for the current iteration
136 p_RIGHT_RESIDUAL -> update(temp_dummy);
137 // add the (linearised) LHS BCs to the matrix problem
138 for(unsigned i = 0; i < p_RIGHT_RESIDUAL -> get_order(); ++i) {
139 // loop thru variables at LHS of the domain
140 for(unsigned var = 0; var < order; ++var) {
141 (*p_A_DENSE)(row, order * (num_of_nodes - 1) + var) = p_RIGHT_RESIDUAL -> jacobian()(i, var);
142 (*p_B_DENSE)(row, order * (num_of_nodes - 1) + var) = 0.0;
143 }
144 ++row;
145 }
146
147 if(row != num_of_nodes * order) {
148 std::string problem("\n The ODE_BVP has an incorrect number of boundary conditions. \n");
149 throw ExceptionRuntime(problem);
150 }
151
152 }
153
154
155 // the templated versions that we require are:
156 template class ODE_EVP<double>
157 ;
158 template class ODE_EVP<std::complex<double> >
159 ;
160
161
162} // end namespace
163
Specification of the dense linear eigensystem class.
A templated class for equations that can be inherited from to allow instantiation of ODE/PDE objects ...
A templated class for equations that can be inherited from to allow instantiation of PDE_double_IBVP ...
The collection of CppNoddy exceptions.
A specification of a class for an -order ODE LINEAR EVP defined by.
A spec for a collection of utility functions.
A linear Nth-order generalised eigensystem class.
A matrix class that constructs a DENSE matrix as a row major std::vector of DenseVectors.
Definition: DenseMatrix.h:25
An DenseVector class – a dense vector object.
Definition: DenseVector.h:34
std::size_t size() const
A pass-thru definition to get the size of the vector.
Definition: DenseVector.h:330
An equation object base class used in the PDE_double_IBVP class.
A linear Nth-order generalised eigensystem base class.
A templated object for real/complex vector system of first-order ordinary differential equations.
Definition: ODE_EVP.h:35
LinearEigenSystem_base * p_eigensystem()
Allow access to the underlying dense linear eigensystem through a pointer to the private member data.
Definition: ODE_EVP.cpp:53
ODE_EVP(Equation_2matrix< _Type > *equation_ptr, const DenseVector< double > &nodes, Residual< _Type > *ptr_to_left_residual, Residual< _Type > *ptr_to_right_residual)
The class is defined by a vector function for the system.
Definition: ODE_EVP.cpp:26
void eigensolve()
Formulate and solve the global eigenvalue problem for a linear system.
Definition: ODE_EVP.cpp:58
~ODE_EVP()
Destructor.
Definition: ODE_EVP.cpp:45
A base class to be inherited by objects that define residuals.
Definition: Residual.h:15
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...

© 2012

R.E. Hewitt