CppNoddy  0.92
Loading...
Searching...
No Matches
HST.h
Go to the documentation of this file.
1/// \file HST.h
2/// Some classes useful for hydrodynamic stability theory problems.
3/// In particular Cartesian versions of Rayleigh and Orr-Sommerfeld
4/// equations.
5
6#ifndef HST_H
7#define HST_H
8
9#include <ODE_BVP.h>
10#include <Equation_1matrix.h>
12
13namespace CppNoddy {
14 /// Some utility methods associated with CppNoddy containers.
15 namespace HST {
16
17 template <typename _Type>
18 class Rayleigh {
19 class Rayleigh_equation : public Equation_1matrix<std::complex<double>, _Type> {
20 public:
21 // this is 3rd order for local refinement
22 Rayleigh_equation() : Equation_1matrix<std::complex<double>, _Type>(3)
23 {}
24
25 void residual_fn(const DenseVector<std::complex<double> > &z, DenseVector<std::complex<double> > &g) const {
26 _Type y_pos(this -> coord(0));
27 _Type U(p_BASEFLOW -> get_interpolated_vars(y_pos)[ 0 ]);
28 _Type Udd(p_BASEFLOW -> get_interpolated_vars(y_pos)[ 1 ]);
29 g[ 0 ] = z[ 1 ];
30 g[ 1 ] = *p_ALPHA * *p_ALPHA * z[ 0 ] + Udd * z[ 0 ] / (U - z[ 2 ]);
31 g[ 2 ] = 0.0;
32 }
33
34 /// The matrix for the BVP coord -- in this case its identity
36 m(0,0)=m(1,1)=m(2,2)=1.0;
37 }
38
39 double* p_ALPHA;
41
42 };
43
44 class Rayleigh_left_BC : public Residual<std::complex<double> > {
45 public:
46 // 2 boundary conditions and 3 unknowns
47 Rayleigh_left_BC() : Residual<std::complex<double> > (2, 3)
48 { }
49
50 void residual_fn(const DenseVector<std::complex<double> > &z, DenseVector<std::complex<double> > &B) const {
51 B[ 0 ] = z[ 0 ];
52 B[ 1 ] = z[ 1 ] - AMPLITUDE;
53 }
54
55 std::complex<double> AMPLITUDE;
56
57 };
58
59 class Rayleigh_right_BC_deriv : public Residual<std::complex<double> > {
60 public:
61 // 1 boundary condition and 3 unknowns
62 Rayleigh_right_BC_deriv() : Residual<std::complex<double> > (1, 3) {}
63
64 void residual_fn(const DenseVector<std::complex<double> > &z, DenseVector<std::complex<double> > &B) const {
65 B[ 0 ] = z[ 1 ] + *p_ALPHA * z[ 0 ];
66 }
67
68 double* p_ALPHA;
69 };
70
71 class Rayleigh_right_BC_Dirichlet : public Residual<std::complex<double> > {
72 public:
73 // 1 boundary condition and 3 unknowns
74 Rayleigh_right_BC_Dirichlet() : Residual<std::complex<double> > (1, 3) {}
75
76 void residual_fn(const DenseVector<std::complex<double> > &z, DenseVector<std::complex<double> > &B) const {
77 B[ 0 ] = z[ 0 ];
78 }
79 };
80
81 public:
82
83 /// ctor -- either for a complex solution in the complex plane,
84 /// or a double solution along the real line.
85 /// \param base_flow_solution The base flow velocity profile and its curvature.
86 /// \param alpha The wavenumber of the perturbation.
87 /// \param right_bc_type Determines the choice of boundary condition.
88 /// "BL" is a derivative condition, whilst "CHANNEL" is a Dirichlet
89 /// impermeability condition
90
91 Rayleigh(OneD_Node_Mesh<_Type, _Type> &base_flow_solution, double& alpha, const std::string &right_bc_type = "BL");
92
93 /// Solve the global eigenvalue problem for the Rayleigh equation
94 /// by employing a second-order finite-difference matrix. The
95 /// scheme allows for a non-uniform distribution of nodal points.
96 void global_evp();
97
98 /// Solve the EVP locally as a nonlinear BVP for just one mode.
99 /// Again we employ a second-order accurate finite-difference scheme
100 /// which allows for non-uniform distribution of nodal points.
101 /// \param i_ev The index of the eigenvalue to solve for, based on the return
102 /// from the global_evp method.
103 void local_evp(std::size_t i_ev);
104
105 /// Refine the EIGENVECTORS mesh for a new baseflow. Useful following
106 /// a global_evp solve and prior to a local_evp solve.
107 /// \param new_baseflow A new mesh containing the base flow, we'll linearly
108 /// interpolate to this mesh
109 void remesh1(const OneD_Node_Mesh<_Type, _Type>& new_baseflow);
110
111 /// A handle to the eigenvectors mesh
112 /// \return A mesh containing the eigenvectors, with the i-th variable
113 /// corresponding to the i-th eigenvalue.
115 return EIGENVECTORS;
116 }
117
119 unsigned n(BASEFLOW.get_nnodes());
121 for(unsigned i = 0; i < n; ++i) {
122 temp(i, 0) = EIGENVECTORS(i, i_ev);
123 }
124 return temp;
125 }
126
127 /// Iterate on the wavenumber ALPHA, using the local_evp routine, to drive a
128 /// selected eigenvalue to be neutral (ie. imaginary part is zero)
129 /// \param i_ev The index of the eigenvalue to iterate on
130 void iterate_to_neutral(std::size_t i_ev);
131
132 /// A handle to the eigenvalues vector
133 /// \return A vector of eigenvalues
135 return EIGENVALUES;
136 }
137
138 /// A handle to the wavenumber
139 /// \return The wavenumber
140 double& alpha() {
141 return ALPHA;
142 }
143
144 protected:
145
146 std::string RIGHT_BC_TYPE;
147 double ALPHA;
151 };
152
153
154
155
157 enum { phi, phid, psi, psid, eval };
158
159 class Orr_Sommerfeld_equation : public Equation_1matrix<std::complex<double> > {
160 public:
161 // this is 5th order for local refinement
162 Orr_Sommerfeld_equation() : Equation_1matrix<std::complex<double> >(5)
163 {}
164
165 void residual_fn(const DenseVector<std::complex<double> > &z, DenseVector<std::complex<double> > &g) const {
166 double y_pos(this -> coord(0));
167 double U(p_BASEFLOW -> get_interpolated_vars(y_pos)[ 0 ]);
168 double Udd(p_BASEFLOW -> get_interpolated_vars(y_pos)[ 1 ]);
169 // define the equation as 5 1st order equations
170 g[ phi ] = z[ phid ];
171 g[ phid ] = z[ psi ] + *p_ALPHA * *p_ALPHA * z[ phi ];
172 g[ psi ] = z[ psid ];
173 g[ psid ] = *p_ALPHA * *p_ALPHA * z[ psi ]
174 + D_complex(0.0, 1.0) * *p_ALPHA * *p_RE * (U * z[ psi ] - Udd * z[ phi ])
175 - D_complex(0.0, 1.0) * *p_ALPHA * *p_RE * z[ eval ] * z[ psi ];
176 g[ eval ] = 0.0;
177 }
178
179 /// The matrix for the BVP coord -- in this case it's an identity matrix
181 m(0,0)=m(1,1)=m(2,2)=m(3,3)=m(4,4)=1.0;
182 }
183
184 double* p_ALPHA;
185 double* p_RE;
186 OneD_Node_Mesh<double>* p_BASEFLOW;
187
188 };
189
190 class OS_left_BC : public Residual<D_complex> {
191 public:
192 // 3 boundary conditions and 5 unknowns
193 OS_left_BC() : Residual<D_complex> (3, 5) {}
194
195 void residual_fn(const DenseVector<D_complex> &z, DenseVector<D_complex> &B) const {
196 B[ 0 ] = z[ phi ];
197 B[ 1 ] = z[ phid ];
198 B[ 2 ] = z[ psi ] - 1.0; // an arbitrary amplitude traded against the eigenvalue
199 }
200 };
201
202 class OS_right_BC : public Residual<D_complex> {
203 public:
204 // 2 boundary conditions and 5 unknowns
205 OS_right_BC() : Residual<D_complex> (2, 5) {}
206
207 void residual_fn(const DenseVector<D_complex> &z, DenseVector<D_complex> &B) const {
208 B[ 0 ] = z[ phi ];
209 B[ 1 ] = z[ phid ];
210 }
211 };
212
213
214 public:
215
216 /// ctor
217 /// \param base_flow_solution The base flow velocity profile and
218 /// its curvature.
219 /// \param alpha The wavenumber to compute the spectrum for.
220 /// \param rey The Reynolds number to compute the spectrum for.
221 Orr_Sommerfeld(OneD_Node_Mesh<double> &base_flow_solution, double alpha, double rey) {
222 ALPHA = alpha;
223 RE = rey;
224 BASEFLOW = base_flow_solution;
225 }
226
227 /// Solve the global eigenvalue problem for the Rayleigh equation.
228 void global_evp() {
229 const std::complex<double> I(0.0, 1.0);
230 unsigned N(2 * BASEFLOW.get_nnodes());
231 // matrices for the EVP, initialised with zeroes
232 DenseMatrix<D_complex> a(N, N, 0.0);
233 DenseMatrix<D_complex> b(N, N, 0.0);
234 //
235 double d = BASEFLOW.coord(1) - BASEFLOW.coord(0);
236 // boundary conditions at the left boundary
237 a(0, 0) = 1.0; // phi( left ) = 0
238 a(1, 0) = -1.5 / d; // phi'( left ) = 0
239 a(1, 2) = 2.0 / d;
240 a(1, 4) = -0.5 / d;
241 // fill the interior nodes
242 for(std::size_t i = 1; i <= BASEFLOW.get_nnodes() - 2; ++i) {
243 // position in the channel
244 //const double y = BASEFLOW.coord( i );
245 // base flow profile
246 const double U = BASEFLOW(i,0);
247 // BASEFLOW.get_interpolated_vars( y )[ 0 ];
248 const double Udd = (BASEFLOW(i+1,0) - 2*BASEFLOW(i,0) + BASEFLOW(i-1,0))/(d*d);
249 //BASEFLOW.get_interpolated_vars( y )[ 1 ];
250
251 // the first quation at the i'th nodal point
252 std::size_t row = 2 * i;
253 a(row, row) = -2.0 / (d * d) - ALPHA * ALPHA;
254 a(row, row - 2) = 1.0 / (d * d);
255 a(row, row + 2) = 1.0 / (d * d);
256 a(row, row + 1) = -1.0;
257
258 row += 1;
259 // the second equation at the i'th nodal point
260 a(row, row) = -2.0 / (d * d) - ALPHA * ALPHA - I * ALPHA * RE * U;
261 a(row, row - 2) = 1.0 / (d * d);
262 a(row, row + 2) = 1.0 / (d * d);
263 a(row, row - 1) = I * ALPHA * RE * Udd;
264
265 b(row, row) = - I * ALPHA * RE;
266 }
267 // boundary conditions at right boundary
268 a(N - 2, N - 2) = 1.5 / d;
269 a(N - 2, N - 4) = -2.0 / d;
270 a(N - 2, N - 6) = 0.5 / d; // psi'( right ) = 0
271 a(N - 1, N - 2) = 1.0; // psi( right ) = 0
272 // a vector for the eigenvalues
274 system.eigensolve();
275 system.tag_eigenvalues_disc(+1, 100.0);
277
278 }
279
280 /// Solve the EVP locally as a nonlinear BVP for just one mode.
281 /// \param i_ev The index of the eigenvalue to solve for, based on the return
282 /// from the global_evp method.
283 void local_evp(std::size_t i_ev) {}
284
285 /// Refine the EIGENVECTORS mesh for a new baseflow. Useful following
286 /// a global_evp solve and prior to a local_evp solve.
287 /// \param new_baseflow A new mesh containing the base flow, we'll linearly
288 /// interpolate to this mesh
289 void remesh1(const OneD_Node_Mesh<double>& new_baseflow) {}
290
291 /// A handle to the eigenvectors mesh
292 /// \return A mesh containing the eigenvectors, with the i-th variable
293 /// corresponding to the i-th eigenvalue.
295 return EIGENVECTORS;
296 }
297
298
299 /// Iterate on the wavenumber ALPHA, using the local_evp routine, to drive a
300 /// selected eigenvalue to be neutral (ie. imaginary part is zero)
301 /// \param i_ev The index of the eigenvalue to iterate on
302 void iterate_to_neutral(std::size_t i_ev) {}
303
304 /// A handle to the eigenvalues vector
305 /// \return A vector of eigenvalues
307 return EIGENVALUES;
308 }
309
310 /// A handle to the wavenumber
311 /// \return The wavenumber
312 double& alpha() {
313 return ALPHA;
314 }
315
316 protected:
317
318 double RE;
319 double ALPHA;
323 };
324
325
326
327
328
329
330
331 template <typename _Type>
332 Rayleigh<_Type>::Rayleigh(OneD_Node_Mesh<_Type, _Type> &base_flow_solution, double& alpha, const std::string &right_bc_type) {
333 // protected data storage
334 RIGHT_BC_TYPE = right_bc_type;
335 ALPHA = alpha;
336 BASEFLOW = base_flow_solution;
337 EIGENVALUES = DenseVector<std::complex<double> >(BASEFLOW.get_nnodes(), 0.0);
338 EIGENVECTORS = OneD_Node_Mesh<std::complex<double>, _Type>(BASEFLOW.nodes(), 1);
339 }
340
341
342 template <typename _Type>
344 // reset the baseflow mesh
345 BASEFLOW = new_baseflow;
346 // first order interpolation of the eigenvectors
347 EIGENVECTORS.remesh1(BASEFLOW.nodes());
348 }
349
350 template<>
351 void Rayleigh<double>::iterate_to_neutral(std::size_t i_ev) {}
352
353 template<>
354 void Rayleigh<std::complex<double> >::iterate_to_neutral(std::size_t i_ev) {
355 double delta(1.e-8);
356 do {
357 std::cout << "ALPHA = " << ALPHA << "\n";
358 local_evp(i_ev);
359 std::complex<double> copy_of_ev(EIGENVALUES[ i_ev ]);
360 ALPHA += delta;
361 local_evp(i_ev);
362 ALPHA -= delta;
363 double d_ev = (std::imag(EIGENVALUES[ i_ev ]) - std::imag(copy_of_ev)) / delta;
364 ALPHA -= std::imag(copy_of_ev) / d_ev;
365 std::cout << "ITERATING: " << ALPHA << " " << EIGENVALUES[ i_ev ] << " " << d_ev << "\n";
366 } while(std::abs(std::imag(EIGENVALUES[ i_ev ])) > 1.e-6);
367 }
368
369
370 template <typename _Type>
371 void Rayleigh<_Type>::local_evp(std::size_t i_ev) {
372 // number of nodes in the mesh
373 std::size_t N = BASEFLOW.get_nnodes();
374 // formulate the Rayleigh equation as a BVP
375 Rayleigh_equation Rayleigh_problem;
376 // boundary conditions
377 Rayleigh_left_BC Rayleigh_left;
378 Rayleigh_right_BC_deriv Rayleigh_right_deriv;
379 Rayleigh_right_BC_Dirichlet Rayleigh_right_Dirichlet;
380 // set the private member data in the objects
381 Rayleigh_problem.p_BASEFLOW = &BASEFLOW;
382 Rayleigh_problem.p_ALPHA = &ALPHA;
383 Rayleigh_right_deriv.p_ALPHA = &ALPHA;
384
385 // pointer to the equation
386 ODE_BVP<std::complex<double>, _Type>* p_Rayleigh;
387 if(RIGHT_BC_TYPE == "BL") {
388 p_Rayleigh = new ODE_BVP<std::complex<double>, _Type>(&Rayleigh_problem, BASEFLOW.nodes(), &Rayleigh_left, &Rayleigh_right_deriv);
389 } else if(RIGHT_BC_TYPE == "CHANNEL") {
390 p_Rayleigh = new ODE_BVP<std::complex<double>, _Type>(&Rayleigh_problem, BASEFLOW.nodes(), &Rayleigh_left, &Rayleigh_right_Dirichlet);
391 } else {
392 std::string problem;
393 problem = " The Rayleigh.global_evp_uniform class has been called with an unknown string \n";
394 problem += " that defines the far-field boundary condition.";
395 throw ExceptionRuntime(problem);
396 }
397
398 p_Rayleigh -> max_itns() = 30;
399
400 // set the initial guess using the global_evp solve data
401 p_Rayleigh -> solution()(0, 0) = EIGENVECTORS(0, i_ev);
402 p_Rayleigh -> solution()(0, 1) = (EIGENVECTORS(1, i_ev) - EIGENVECTORS(0, i_ev)) / (BASEFLOW.coord(1) - BASEFLOW.coord(0));
403 p_Rayleigh -> solution()(0, 2) = EIGENVALUES[ i_ev ];
404 // set the (arbitrary) amplitude from the global_evp solve data
405 Rayleigh_left.AMPLITUDE = p_Rayleigh -> solution()(0, 1);
406 for(unsigned i = 1; i < N - 1; ++i) {
407 p_Rayleigh -> solution()(i, 0) = EIGENVECTORS(i, i_ev);
408 p_Rayleigh -> solution()(i, 1) = (EIGENVECTORS(i + 1, i_ev) - EIGENVECTORS(i - 1, i_ev)) / (BASEFLOW.coord(i + 1) - BASEFLOW.coord(i - 1));
409 p_Rayleigh -> solution()(i, 2) = EIGENVALUES[ i_ev ];
410 }
411 p_Rayleigh -> solution()(N - 1, 0) = EIGENVECTORS(N - 1, i_ev);
412 p_Rayleigh -> solution()(N - 1, 1) = (EIGENVECTORS(N - 1, i_ev) - EIGENVECTORS(N - 2, i_ev)) / (BASEFLOW.coord(N - 1) - BASEFLOW.coord(N - 2));
413 p_Rayleigh -> solution()(N - 1, 2) = EIGENVALUES[ i_ev ];
414
415 // do a local solve
416 p_Rayleigh -> solve2();
417 // write the eigenvalue and eigenvector back to private member data store
418 EIGENVALUES[ i_ev ] = p_Rayleigh -> solution()(0, 2);
419 for(unsigned i = 0; i < N; ++i) {
420 EIGENVECTORS(i, i_ev) = p_Rayleigh -> solution()(i, 0);
421 }
422 // delete the equation object
423 delete p_Rayleigh;
424 }
425
426
427 template <>
429 unsigned N(BASEFLOW.get_nnodes());
430 // Rayleigh EVP -- we'll keep it complex even though its extra work
433 // f_0 = 0
434 A(0, 0) = 1.0;
435 B(0, 0) = 0.0;
436 // step through the interior nodes
437 for(std::size_t i = 1; i < N - 1; ++i) {
438#ifdef PARANOID
439 const double h1 = BASEFLOW.coord(1) - BASEFLOW.coord(0);
440 if(std::abs(BASEFLOW.coord(i) - BASEFLOW.coord(i - 1) - h1) > 1.e-12) {
441 std::string problem;
442 problem = " Warning: The Rayleigh.global_evp method is only first order \n";
443 problem += " on a non-uniform mesh.\n";
444 throw ExceptionRuntime(problem);
445 }
446#endif
447 double h(BASEFLOW.coord(i) - BASEFLOW.coord(i - 1));
448 double k(BASEFLOW.coord(i + 1) - BASEFLOW.coord(i));
449 double sigma(k / h); // sigma = 1 => uniform mesh
450 double y = BASEFLOW.coord(i);
451 double U = BASEFLOW.get_interpolated_vars(y)[ 0 ];
452 double Udd = BASEFLOW.get_interpolated_vars(y)[ 1 ];
453 double h2 = 0.5 * h * h * sigma * (sigma + 1.0);
454 A(i, i) = U * (-(sigma + 1.0) / h2 - ALPHA * ALPHA) - Udd;
455 A(i, i - 1) = sigma * U / h2;
456 A(i, i + 1) = U / h2;
457 //
458 B(i, i) = - (sigma + 1.0) / h2 - ALPHA * ALPHA;
459 B(i, i - 1) = sigma / h2;
460 B(i, i + 1) = 1. / h2;
461 }
462
463 // 3 point backward difference the far-field in BL, but pin in channel
464 if(RIGHT_BC_TYPE == "BL") {
465 double h = BASEFLOW.coord(N - 2) - BASEFLOW.coord(N - 3);
466 double k = BASEFLOW.coord(N - 1) - BASEFLOW.coord(N - 2);
467 //A( N - 1, N - 1 ) = -3.0 / ( 2 * h )- alpha;
468 //A( N - 1, N - 2 ) = 4.0 / ( 2 * h );
469 //A( N - 1, N - 3 ) = -1.0 / ( 2 * h );
470 A(N - 1, N - 1) = h * (h + k) / k * (- 1. / (h * h) + 1. / ((h + k) * (h + k))) - ALPHA;
471 A(N - 1, N - 2) = h * (h + k) / k * (1. / (h * h));
472 A(N - 1, N - 3) = h * (h + k) / k * (1. / ((h + k) * (h + k)));
473 B(N - 1, N - 1) = 0.0;
474 } else if(RIGHT_BC_TYPE == "CHANNEL") {
475 A(N - 1, N - 1) = 1.0;
476 B(N - 1, N - 1) = 0.0;
477 } else {
478 std::string problem;
479 problem = " The Rayleigh.global_evp_uniform class has been called with an unknown string \n";
480 problem += " that defines the far-field boundary condition.";
481 throw ExceptionRuntime(problem);
482 }
483 double U_max(BASEFLOW(0, 0));
484 double U_min(BASEFLOW(0, 0));
485 for(unsigned i = 1; i < N; ++i) {
486 U_max = std::max(U_max, BASEFLOW(i, 0));
487 U_min = std::min(U_min, BASEFLOW(i, 0));
488 }
489
490 DenseLinearEigenSystem<std::complex<double> > rayleigh_evp(&A, &B);
491 rayleigh_evp.eigensolve();
492 // return based on Howard's circle theorem
493 rayleigh_evp.set_shift(std::complex<double> (0.5 * (U_max + U_min), 0.0));
494 rayleigh_evp.tag_eigenvalues_disc(+1, 0.5 * (U_max - U_min));
495 EIGENVALUES = rayleigh_evp.get_tagged_eigenvalues();
496 DenseMatrix<std::complex<double> > eigenvecs_mtx = rayleigh_evp.get_tagged_eigenvectors();
497 // get eigenvectors
498 EIGENVECTORS = OneD_Node_Mesh<std::complex<double>, double>(BASEFLOW.nodes(), N);
499 for(unsigned evec = 0; evec < EIGENVALUES.size(); ++evec) {
500 for(unsigned node = 0; node < N; ++node) {
501 EIGENVECTORS(node, evec) = eigenvecs_mtx(evec, node);
502 }
503 }
504 }
505
506
507 template <>
508 void Rayleigh<std::complex<double> >::global_evp() {
509 unsigned N(BASEFLOW.get_nnodes());
510 // Rayleigh EVP
513 // f_0 = 0
514 A(0, 0) = 1.0;
515 B(0, 0) = 0.0;
516 //const std::complex<double> h1 = BASEFLOW.coord( 1 ) - BASEFLOW.coord( 0 );
517 // step through the interior nodes
518 for(std::size_t i = 1; i < N - 1; ++i) {
519#ifdef PARANOID
520 const double h1 = abs(BASEFLOW.coord(1) - BASEFLOW.coord(0));
521 if(std::abs(BASEFLOW.coord(i) - BASEFLOW.coord(i - 1) - h1) > 1.e-12) {
522 std::string problem;
523 problem = " Warning: The Rayleigh.global_evp method is only first order \n";
524 problem += " on a non-uniform mesh.\n";
525 //throw ExceptionRuntime( problem );
526 }
527#endif
528 std::complex<double> h(BASEFLOW.coord(i) - BASEFLOW.coord(i - 1));
529 std::complex<double> k(BASEFLOW.coord(i + 1) - BASEFLOW.coord(i));
530 std::complex<double> sigma(k / h); // sigma = 1 => uniform mesh
531 std::complex<double> y = BASEFLOW.coord(i);
532 std::complex<double> U = BASEFLOW.get_interpolated_vars(y)[ 0 ];
533 std::complex<double> Udd = BASEFLOW.get_interpolated_vars(y)[ 1 ];
534 std::complex<double> h2 = 0.5 * h * h * sigma * (sigma + 1.0);
535 A(i, i) = U * (-(sigma + 1.0) / h2 - ALPHA * ALPHA) - Udd;
536 A(i, i - 1) = sigma * U / h2;
537 A(i, i + 1) = U / h2;
538 //
539 B(i, i) = - (sigma + 1.0) / h2 - ALPHA * ALPHA;
540 B(i, i - 1) = sigma / h2;
541 B(i, i + 1) = 1. / h2;
542 }
543
544 // 3 point backward difference the far-field in BL, but pin in channel
545 if(RIGHT_BC_TYPE == "BL") {
546 std::complex<double> h = BASEFLOW.coord(N - 2) - BASEFLOW.coord(N - 3);
547 std::complex<double> k = BASEFLOW.coord(N - 1) - BASEFLOW.coord(N - 2);
548 //A( N - 1, N - 1 ) = -3.0 / ( 2 * h )- alpha;
549 //A( N - 1, N - 2 ) = 4.0 / ( 2 * h );
550 //A( N - 1, N - 3 ) = -1.0 / ( 2 * h );
551 A(N - 1, N - 1) = h * (h + k) / k * (- 1. / (h * h) + 1. / ((h + k) * (h + k))) - ALPHA;
552 A(N - 1, N - 2) = h * (h + k) / k * (1. / (h * h));
553 A(N - 1, N - 3) = h * (h + k) / k * (1. / ((h + k) * (h + k)));
554 B(N - 1, N - 1) = 0.0;
555 } else if(RIGHT_BC_TYPE == "CHANNEL") {
556 A(N - 1, N - 1) = 1.0;
557 B(N - 1, N - 1) = 0.0;
558 } else {
559 std::string problem;
560 problem = " The Rayleigh.global_evp_uniform class has been called with an unknown string \n";
561 problem += " that defines the far-field boundary condition.";
562 throw ExceptionRuntime(problem);
563 }
564 double U_max(BASEFLOW(0, 0).real());
565 double U_min(BASEFLOW(0, 0).real());
566 for(unsigned i = 1; i < N; ++i) {
567 U_max = std::max(U_max, BASEFLOW(i, 0).real());
568 U_min = std::min(U_min, BASEFLOW(i, 0).real());
569 }
570
571 DenseLinearEigenSystem<std::complex<double> > rayleigh_evp(&A, &B);
572 rayleigh_evp.eigensolve();
573 // return based on Howard's circle theorem
574 rayleigh_evp.set_shift(std::complex<double> (0.5 * (U_max + U_min), 0.0));
575 rayleigh_evp.tag_eigenvalues_disc(+1, 0.5 * (U_max - U_min));
576 EIGENVALUES = rayleigh_evp.get_tagged_eigenvalues();
577 DenseMatrix<std::complex<double> > eigenvecs_mtx = rayleigh_evp.get_tagged_eigenvectors();
578 // get eigenvectors
579 EIGENVECTORS = OneD_Node_Mesh<std::complex<double>, std::complex<double> >(BASEFLOW.nodes(), N);
580 for(unsigned evec = 0; evec < EIGENVALUES.size(); ++evec) {
581 for(unsigned node = 0; node < N; ++node) {
582 EIGENVECTORS(node, evec) = eigenvecs_mtx(evec, node);
583 }
584 }
585 }
586
587 }
588} // end namespace
589
590#endif // HST_H
@ U
Definition: BVPKarman.cpp:20
Specification of the dense linear eigensystem class.
A templated class for equations that can be inherited from to allow instantiation of PDE_IBVP objects...
A specification of a class for an -order ODE BVP defined by.
A linear Nth-order generalised eigensystem class.
void tag_eigenvalues_disc(const int &val, const double &radius)
Tag those eigenvalues that are within a disc centred at a point in the complex plane.
DenseVector< D_complex > get_tagged_eigenvalues() const
Get the the tagged eigenvalues.
void eigensolve()
Solve the matrix linear eigensystem.
DenseMatrix< D_complex > get_tagged_eigenvectors() const
Get the the tagged eigenvectors.
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).
const DenseMatrix< std::complex< double > > & matrix0() const
Return a handle to the matrix.
A generic runtime exception.
Definition: Exceptions.h:158
void global_evp()
Solve the global eigenvalue problem for the Rayleigh equation.
Definition: HST.h:228
DenseVector< std::complex< double > > & eigenvalues()
A handle to the eigenvalues vector.
Definition: HST.h:306
OneD_Node_Mesh< std::complex< double > > EIGENVECTORS
Definition: HST.h:321
void remesh1(const OneD_Node_Mesh< double > &new_baseflow)
Refine the EIGENVECTORS mesh for a new baseflow.
Definition: HST.h:289
OneD_Node_Mesh< std::complex< double > > & eigenvectors()
A handle to the eigenvectors mesh.
Definition: HST.h:294
OneD_Node_Mesh< double > BASEFLOW
Definition: HST.h:320
double & alpha()
A handle to the wavenumber.
Definition: HST.h:312
void local_evp(std::size_t i_ev)
Solve the EVP locally as a nonlinear BVP for just one mode.
Definition: HST.h:283
Orr_Sommerfeld(OneD_Node_Mesh< double > &base_flow_solution, double alpha, double rey)
ctor
Definition: HST.h:221
DenseVector< std::complex< double > > EIGENVALUES
Definition: HST.h:322
void iterate_to_neutral(std::size_t i_ev)
Iterate on the wavenumber ALPHA, using the local_evp routine, to drive a selected eigenvalue to be ne...
Definition: HST.h:302
void iterate_to_neutral(std::size_t i_ev)
Iterate on the wavenumber ALPHA, using the local_evp routine, to drive a selected eigenvalue to be ne...
void remesh1(const OneD_Node_Mesh< _Type, _Type > &new_baseflow)
Refine the EIGENVECTORS mesh for a new baseflow.
Definition: HST.h:343
DenseVector< std::complex< double > > & eigenvalues()
A handle to the eigenvalues vector.
Definition: HST.h:134
void global_evp()
Solve the global eigenvalue problem for the Rayleigh equation by employing a second-order finite-diff...
OneD_Node_Mesh< std::complex< double >, _Type > & eigenvectors()
A handle to the eigenvectors mesh.
Definition: HST.h:114
OneD_Node_Mesh< std::complex< double >, _Type > EIGENVECTORS
Definition: HST.h:149
OneD_Node_Mesh< _Type, _Type > BASEFLOW
Definition: HST.h:148
double & alpha()
A handle to the wavenumber.
Definition: HST.h:140
void local_evp(std::size_t i_ev)
Solve the EVP locally as a nonlinear BVP for just one mode.
Definition: HST.h:371
Rayleigh(OneD_Node_Mesh< _Type, _Type > &base_flow_solution, double &alpha, const std::string &right_bc_type="BL")
ctor – either for a complex solution in the complex plane, or a double solution along the real line.
Definition: HST.h:332
std::string RIGHT_BC_TYPE
Definition: HST.h:146
OneD_Node_Mesh< std::complex< double > > eigenvector(unsigned i_ev)
Definition: HST.h:118
DenseVector< std::complex< double > > EIGENVALUES
Definition: HST.h:150
void set_shift(const D_complex &z)
Set the shift value to be used in tagging.
A templated object for real/complex vector system of first-order ordinary differential equations.
Definition: ODE_BVP.h:37
A one dimensional mesh utility object.
const DenseVector< _Xtype > & nodes() const
const _Xtype & coord(const std::size_t &node) const
Access a nodal position.
std::size_t get_nnodes() const
void remesh1(const DenseVector< _Xtype > &z)
Interpolate this mesh data (linearly) into a new mesh with nodal points defined in the argument list.
_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
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

© 2012

R.E. Hewitt