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.