17 template <
typename _Type>
19 class Rayleigh_equation :
public Equation_1matrix<std::complex<double>, _Type> {
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 ]);
30 g[ 1 ] = *p_ALPHA * *p_ALPHA * z[ 0 ] + Udd * z[ 0 ] / (
U - z[ 2 ]);
36 m(0,0)=
m(1,1)=
m(2,2)=1.0;
44 class Rayleigh_left_BC :
public Residual<std::complex<double> > {
50 void residual_fn(
const DenseVector<std::complex<double> > &z,
DenseVector<std::complex<double> > &B)
const {
52 B[ 1 ] = z[ 1 ] - AMPLITUDE;
55 std::complex<double> AMPLITUDE;
59 class Rayleigh_right_BC_deriv :
public Residual<std::complex<double> > {
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 ];
71 class Rayleigh_right_BC_Dirichlet :
public Residual<std::complex<double> > {
76 void residual_fn(
const DenseVector<std::complex<double> > &z,
DenseVector<std::complex<double> > &B)
const {
121 for(
unsigned i = 0; i < n; ++i) {
157 enum { phi, phid, psi, psid, eval };
159 class Orr_Sommerfeld_equation :
public Equation_1matrix<std::complex<double> > {
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 ]);
171 g[
phid ] = z[
psi ] + *p_ALPHA * *p_ALPHA * z[
phi ];
173 g[
psid ] = *p_ALPHA * *p_ALPHA * z[
psi ]
181 m(0,0)=
m(1,1)=
m(2,2)=
m(3,3)=
m(4,4)=1.0;
190 class OS_left_BC :
public Residual<D_complex> {
198 B[ 2 ] = z[
psi ] - 1.0;
202 class OS_right_BC :
public Residual<D_complex> {
229 const std::complex<double> I(0.0, 1.0);
252 std::size_t row = 2 * i;
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;
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;
265 b(row, row) = - I *
ALPHA *
RE;
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;
271 a(N - 1, N - 2) = 1.0;
331 template <
typename _Type>
334 RIGHT_BC_TYPE = right_bc_type;
336 BASEFLOW = base_flow_solution;
342 template <
typename _Type>
345 BASEFLOW = new_baseflow;
347 EIGENVECTORS.
remesh1(BASEFLOW.nodes());
357 std::cout <<
"ALPHA = " << ALPHA <<
"\n";
359 std::complex<double> copy_of_ev(EIGENVALUES[ i_ev ]);
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);
370 template <
typename _Type>
373 std::size_t N = BASEFLOW.get_nnodes();
375 Rayleigh_equation Rayleigh_problem;
377 Rayleigh_left_BC Rayleigh_left;
378 Rayleigh_right_BC_deriv Rayleigh_right_deriv;
379 Rayleigh_right_BC_Dirichlet Rayleigh_right_Dirichlet;
381 Rayleigh_problem.p_BASEFLOW = &BASEFLOW;
382 Rayleigh_problem.p_ALPHA = &ALPHA;
383 Rayleigh_right_deriv.p_ALPHA = &ALPHA;
387 if(RIGHT_BC_TYPE ==
"BL") {
389 }
else if(RIGHT_BC_TYPE ==
"CHANNEL") {
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.";
398 p_Rayleigh -> max_itns() = 30;
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 ];
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 ];
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 ];
416 p_Rayleigh -> solve2();
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);
429 unsigned N(BASEFLOW.get_nnodes());
437 for(std::size_t i = 1; i < N - 1; ++i) {
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) {
442 problem =
" Warning: The Rayleigh.global_evp method is only first order \n";
443 problem +=
" on a non-uniform mesh.\n";
447 double h(BASEFLOW.coord(i) - BASEFLOW.coord(i - 1));
448 double k(BASEFLOW.coord(i + 1) - BASEFLOW.coord(i));
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;
458 B(i, i) = - (sigma + 1.0) / h2 - ALPHA * ALPHA;
459 B(i, i - 1) = sigma / h2;
460 B(i, i + 1) = 1. / h2;
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);
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;
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.";
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));
493 rayleigh_evp.
set_shift(std::complex<double> (0.5 * (U_max + U_min), 0.0));
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);
509 unsigned N(BASEFLOW.get_nnodes());
518 for(std::size_t i = 1; i < N - 1; ++i) {
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) {
523 problem =
" Warning: The Rayleigh.global_evp method is only first order \n";
524 problem +=
" on a non-uniform mesh.\n";
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);
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;
539 B(i, i) = - (sigma + 1.0) / h2 - ALPHA * ALPHA;
540 B(i, i - 1) = sigma / h2;
541 B(i, i + 1) = 1. / h2;
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);
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;
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.";
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());
574 rayleigh_evp.
set_shift(std::complex<double> (0.5 * (U_max + U_min), 0.0));
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);
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.
An DenseVector class – a dense vector object.
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.
void global_evp()
Solve the global eigenvalue problem for the Rayleigh equation.
DenseVector< std::complex< double > > & eigenvalues()
A handle to the eigenvalues vector.
OneD_Node_Mesh< std::complex< double > > EIGENVECTORS
void remesh1(const OneD_Node_Mesh< double > &new_baseflow)
Refine the EIGENVECTORS mesh for a new baseflow.
OneD_Node_Mesh< std::complex< double > > & eigenvectors()
A handle to the eigenvectors mesh.
OneD_Node_Mesh< double > BASEFLOW
double & alpha()
A handle to the wavenumber.
void local_evp(std::size_t i_ev)
Solve the EVP locally as a nonlinear BVP for just one mode.
Orr_Sommerfeld(OneD_Node_Mesh< double > &base_flow_solution, double alpha, double rey)
ctor
DenseVector< std::complex< double > > EIGENVALUES
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 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.
DenseVector< std::complex< double > > & eigenvalues()
A handle to the eigenvalues vector.
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.
OneD_Node_Mesh< std::complex< double >, _Type > EIGENVECTORS
OneD_Node_Mesh< _Type, _Type > BASEFLOW
double & alpha()
A handle to the wavenumber.
void local_evp(std::size_t i_ev)
Solve the EVP locally as a nonlinear BVP for just one mode.
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.
std::string RIGHT_BC_TYPE
OneD_Node_Mesh< std::complex< double > > eigenvector(unsigned i_ev)
DenseVector< std::complex< double > > EIGENVALUES
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.
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.
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.