CppNoddy  0.92
Loading...
Searching...
No Matches
EVPOrrSommerfeldNeutralCurve_lapack.cpp
Go to the documentation of this file.
1/// \file EVPOrrSommerfeldNeutralCurve.cpp
2/// \ingroup Tests
3/// \ingroup EVP
4/// Solves the following linear eigenvalue problem for values \f$ c \f$
5/// that satisfy :
6/// \f[ \phi''(y) - \alpha^2 \phi(y) - \psi(y) = 0\,, \f]
7/// \f[ \psi''(y) - \alpha^2 \psi(y) - i \alpha Re \left \{ ( U(y) - c ) \psi(y) - U''(y) \phi \right \} = 0\,, \f]
8/// subject to \f$ \phi(\pm 1) = \phi'(\pm 1) = 0 \f$ determining the
9/// values of \f$ \alpha \f$ and \f$ Re \f$ that lead to \f$c_i = 0\f$.
10/// In other words, we compute the temporal linear neutral curve
11/// for perturbations to plane Poiseuille flow. The problem is solved by bolting
12/// together the ODE_EVP (to get the initial global spectrum), the ODE_BVP
13/// to (adaptively) refine the most dangerous eigenmode and the Newton class
14/// to perform arc-length continuation of the neutral curve.
15
16#include <cassert>
17
18#include <EVP_bundle.h>
19#include <BVP_bundle.h>
20
21#include "../Utils_Fill.h"
22
23// enumerate the variables in the ODE
24enum { phi, phid, psi, psid, eval };
25
26namespace CppNoddy
27{
28 namespace Example
29 {
30
31 /// Globally define the Reynolds number and wavenumber
32 double Re, alpha;
33 /// The phase speed of the instability
34 double wave_speed;
35 /// Globally define the base flow
36 double U( double y )
37 {
38 return 1.0 - y * y;
39 };
40 /// Globally define the base flow curvature
41 double Udd( double y )
42 {
43 return -2.0;
44 };
45 int MAX_REFINE(3);
46
47
48 /// Define the OS equation for the global QZ EVP
49 class OS_evp_equation : public Equation_2matrix<D_complex>
50 {
51 public:
52 /// The OS equation is a 4th order complex ODE
54
55 /// The OS equation
57 {
58 // define the equation as four 1st order equations
59 g[ phi ] = z[ phid ];
60 g[ phid ] = z[ psi ] + alpha * alpha * z[ phi ];
61 g[ psi ] = z[ psid ];
62 g[ psid ] = alpha * alpha * z[ psi ]
63 + D_complex( 0.0, 1.0 ) * alpha * Re * ( U( coord(0) ) * z[ psi ] - Udd( coord(0) ) * z[ phi ] );
64 }
65
66 /// matrix to multiply the BVP coordinate
68 {
70 }
71
72 /// Define the unsteady terms by providing the mass matrix
73 /// Here we define the eigenvalue contribution to the g[ psid ] equation
74 /// - D_complex( 0.0, 1.0 ) * alpha * Re * c * z[ psi ]
76 {
77 // the eigenvalue is in equation 3, and multiplies unknown 2
78 m( 3, 2 ) = D_complex( 0.0, 1.0 ) * alpha * Re;
79 }
80
81 };
82
83
84 /// Define the OSE for the local refinement procedure
85 class OS_bvp_equation : public Equation_1matrix<D_complex>
86 {
87 public:
88 /// The OS local problem is a nonlinear 5th order complex BVP
90
91 /// The OS equation
93 {
94 // define the equation as 5 1st order equations
95 g[ phi ] = z[ phid ];
96 g[ phid ] = z[ psi ] + alpha * alpha * z[ phi ];
97 g[ psi ] = z[ psid ];
98 g[ psid ] = alpha * alpha * z[ psi ]
99 + D_complex( 0.0, 1.0 ) * alpha * Re * ( U( coord(0) ) * z[ psi ] - Udd( coord(0) ) * z[ phi ] )
100 - D_complex( 0.0, 1.0 ) * alpha * Re * z[ eval ] * z[ psi ];
101 g[ eval ] = 0.0;
102 }
103
104 /// matrix to multiply the BVP coordinate
106 {
108 }
109 };
110
111 // BOUNDARY CONDITIONS FOR THE EVP SOLVER - same at both boundaries
112 class OS_evp_both_BC : public Residual<D_complex>
113 {
114 public:
115 // 2 boundary conditions and 4 unknowns
117
119 {
120 B[ 0 ] = z[ phi ];
121 B[ 1 ] = z[ phid ];
122 }
123 };
124
125
126 // BOUNDARY CONDITIONS FOR THE BVP SOLVER
127 class OS_bvp_left_BC : public Residual<D_complex>
128 {
129 public:
130 // 3 boundary conditions and 5 unknowns
132
134 {
135 B[ 0 ] = z[ phi ];
136 B[ 1 ] = z[ phid ];
137 B[ 2 ] = z[ psi ] - 1.0; // an arbitrary amplitude traded against eigenvalue
138 }
139 };
140
141 class OS_bvp_right_BC : public Residual<D_complex>
142 {
143 public:
144 // 2 boundary conditions and 5 unknowns
146
148 {
149 B[ 0 ] = z[ phi ];
150 B[ 1 ] = z[ phid ];
151 }
152 };
153
154 // Residual that defines the neutral curve
155 class Neutral_residual : public Residual<double>
156 {
157
158 public:
159
160 Neutral_residual( const unsigned& initial_N ) : Residual<double>( 1 )
161 {
162 // instantiate the object by doing a rough QZ pass of the eigenvalues
163 OS_evp_equation evp;
164 // instantiate the BCs
165 OS_evp_both_BC BC_both;
166 // domain is -1 to 1
167 double left = -1.0;
168 double right = 1.0;
169 // number of nodal points
170 int N = initial_N;
171 // mesh
172 DenseVector<double> nodes( Utility::uniform_node_vector( left, right, N ) );
173 // pass it to the ode
174 ODE_EVP<D_complex> ode_global( &evp, nodes, &BC_both, &BC_both );
175 try
176 {
177 // solve the global eigenvalue problem for growth rate
178 ode_global.eigensolve();
179 }
180 catch (const std::runtime_error &error )
181 {
182 std::cout << " \033[1;31;48m * FAILED THROUGH EXCEPTION BEING RAISED \033[0m\n";
183 assert(false);
184 }
185 // get the eigenvalues near the origin
186 ode_global.p_eigensystem() -> tag_eigenvalues_disc( + 1, 0.6 );
187 // make a mesh of each tagged eigenmode in the ODE_EVP class
188 ode_global.add_tagged_to_mesh();
189 DenseVector<D_complex> lambdas = ode_global.p_eigensystem() -> get_tagged_eigenvalues();
190
191 // instantiate the nonlinear BVP formulation
192 bvp = new OS_bvp_equation;
195 // pass it to the ode BVP solver
197 ode_local -> set_monitor_det( false );
198 // use our not-great initial guess from QZ code to start the solver off
199 // here we just use the first (0) tagged eigenvalue
200 ode_local -> solution() = ode_global.get_mesh( 0 );
201 // interpolate onto a finer mesh
202 ode_local -> solution().remesh1( Utility::uniform_node_vector( left, right, 201 ) );
203 ode_local -> set_monitor_det( false );
204 ode_local -> solve2();
205 // adaptively refine the mesh
206 for ( int i = 0; i < MAX_REFINE; ++i )
207 {
208 ode_local -> adapt( 1.e-2 );
209 ode_local -> solve2();
210 std::cout << "Adapted to " << ode_local -> solution().get_nnodes() << " nodes \n";
211 }
212 }
213
215 {
216 delete bvp;
217 delete BC_left;
218 delete BC_right;
219 delete ode_local;
220 }
221
223 {
224 Example::Re = z[ 0 ];
225 // solve the nonlinear BVP
226 ode_local -> solve2();
227 // return the residual
228 f[ 0 ] = ode_local -> solution()( 0, eval ).imag();
229 wave_speed = ode_local -> solution()( 0, eval ).real();
230 }
231
236 };
237
238 } // end Example namespace
239} // end CppNoddy namespace
240
241using namespace CppNoddy;
242using namespace std;
243
244int main()
245{
246 cout << "\n";
247 cout << "=== EVP: Temporal OSE via the equation interface ====\n";
248 cout << "=== followed by local refinement of the eigenvalue \n";
249 cout << "=== and arclength continuation of the neutral curve.\n";
250 cout << "\n";
251
252 double tol = 1.e-8;
253 unsigned initial_QZ_mesh = 121;
254 DenseVector<double> Re( 1, 5750.0 );
255 Example::alpha = 1.0;
256 Example::Re = Re[0];
257
258 Example::Neutral_residual residual_problem( initial_QZ_mesh );
259
260 Newton<double> newton( &residual_problem, 20, tol );
261 newton.set_monitor_det( false );
262 newton.rescale_theta() = true;
263 newton.theta() = 0.00001;
264 newton.init_arc( Re, &Example::alpha, 0.001, 0.01 );
265
266 // set up the output file
267 std::string dirname("./DATA");
268 mkdir( dirname.c_str(), S_IRWXU );
269 TrackerFile my_file( "DATA/neutral.dat" );
270 my_file.precision( 8 );
271 my_file.push_ptr( &Re, "Reynolds number" );
272 my_file.push_ptr( &Example::alpha, "Wavenumber" );
273 my_file.push_ptr( &Example::wave_speed, "Phase speed" );
274 my_file.header();
275
276 double min_Re( Re[ 0 ] );
277 do
278 {
279 try {
280 newton.arclength_solve( Re );
281 } catch ( const ExceptionBifurcation &bifn ) {
282 }
283 my_file.update();
284 min_Re = std::min( Re[ 0 ], min_Re );
285 }
286 while ( Re[ 0 ] < 5820.0 );
287
288 std::cout << " Minimum Reynolds number (for this spatial resolution ) = " << min_Re << "\n";
289 // the known minimum critical Re is approx 5772 at alpha =1.02
290 // increase MAX_REFINE to get a closer value to 5772.
291 if ( std::abs( min_Re - 5772. ) < 30.0 )
292 {
293 cout << "\033[1;32;48m * PASSED \033[0m\n";
294 return 0;
295 }
296 cout << "\033[1;31;48m * FAILED \033[0m\n";
297 return 1;
298}
@ f
Definition: BVPBerman.cpp:15
@ U
Definition: BVPKarman.cpp:20
A shorter bundled include file for ODE_BVP and PDE_IBVP codes.
A shorter bundled include file for ODE_EVP and general eigenvalue problems.
void init_arc(DenseVector< _Type > x, _Type *p, const double &length, const double &max_length)
Initialise the class ready for arc-length continuation.
bool & rescale_theta()
Handle to the RESCALE_THETA flag.
double & theta()
Set the arclength theta parameter.
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
An equation object base class used in the IBVP classes (and others).
An equation object base class used in the PDE_double_IBVP class.
void residual_fn(const DenseVector< double > &z, DenseVector< double > &f) const
A blank virtual residual function method.
Define the OSE for the local refinement procedure.
OS_bvp_equation()
The OS local problem is a nonlinear 5th order complex BVP.
void matrix0(const DenseVector< D_complex > &z, DenseMatrix< D_complex > &m) const
matrix to multiply the BVP coordinate
void residual_fn(const DenseVector< D_complex > &z, DenseVector< D_complex > &g) const
The OS equation.
void residual_fn(const DenseVector< D_complex > &z, DenseVector< D_complex > &B) const
A blank virtual residual function method.
void residual_fn(const DenseVector< D_complex > &z, DenseVector< D_complex > &B) const
A blank virtual residual function method.
void residual_fn(const DenseVector< D_complex > &z, DenseVector< D_complex > &B) const
A blank virtual residual function method.
Define the OS equation for the global QZ EVP.
void matrix1(const DenseVector< D_complex > &z, DenseMatrix< D_complex > &m) const
Define the unsteady terms by providing the mass matrix Here we define the eigenvalue contribution to ...
void residual_fn(const DenseVector< D_complex > &z, DenseVector< D_complex > &g) const
The OS equation.
void matrix0(const DenseVector< D_complex > &z, DenseMatrix< D_complex > &m) const
matrix to multiply the BVP coordinate
OS_evp_equation()
The OS equation is a 4th order complex ODE.
A vector NEWTON iteration class.
Definition: Newton.h:25
void set_monitor_det(bool flag)
If set then the system will monitor the sign of determinant of the Jacobian matrix and cause an Excep...
Definition: Newton.h:47
void arclength_solve(DenseVector< _Type > &x)
Arc-length solve the system.
Definition: Newton.cpp:98
A templated object for real/complex vector system of first-order ordinary differential equations.
Definition: ODE_BVP.h:37
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
void add_tagged_to_mesh()
Definition: ODE_EVP.h:60
OneD_Node_Mesh< D_complex > get_mesh(const unsigned &i) const
Definition: ODE_EVP.h:99
void eigensolve()
Formulate and solve the global eigenvalue problem for a linear system.
Definition: ODE_EVP.cpp:58
_Xtype & coord(const unsigned &i)
General handle access to the coordinates.
A base class to be inherited by objects that define residuals.
Definition: Residual.h:15
void precision(unsigned prec)
Definition: TrackerFile.cpp:76
void push_ptr(double *scalar, std::string desc="")
Definition: TrackerFile.cpp:27
double Udd(double y)
Globally define the base flow curvature.
double Re
Globally define the Reynolds number and wavenumber.
double g(1.0)
gravitational acceleration
double wave_speed
The phase speed of the instability.
DenseVector< double > uniform_node_vector(const double &lower, const double &upper, const std::size_t &N)
Return a DENSE vector with the nodal points of a uniform mesh distributed between the upper/lower bou...
Definition: Utility.cpp:113
A collection of OO numerical routines aimed at simple (typical) applied problems in continuum mechani...
std::complex< double > D_complex
A complex double precision number using std::complex.
Definition: Types.h:98
void fill_identity(CppNoddy::Sequential_Matrix_base< _Type > &A)
Fill diagonal with unit values.
Definition: Utils_Fill.h:22

© 2012

R.E. Hewitt