CppNoddy  0.92
Loading...
Searching...
No Matches
Functions
EVPOrrSommerfeldSparse_slepcz.cpp File Reference

Solves the following linear eigenvalue problem for values $ c $ that satisfy : More...

#include <Generic_bundle.h>
#include <SparseLinearEigenSystem.h>
#include <SlepcSession.h>

Go to the source code of this file.

Functions

int main (int argc, char *argv[])
 

Detailed Description

Solves the following linear eigenvalue problem for values $ c $ that satisfy :

\[ \phi''(y) - \alpha^2 \phi(y) - \psi(y) = 0\,, \]

\[ \psi''(y) - \alpha^2 \psi(y) - i \alpha Re \left \{ ( U(y) - c ) \psi(y) - U''(y) \phi \right \} = 0\,, \]

subject to $ \phi(\pm 1) = \phi'(\pm 1) = 0 $ where $ \alpha = 1.02 $, $ Re = 5772.2 $ and $ U(y) = 1 - y^2 $. The matrix problem is constructed manually in this case, using second-order finite differences. A sparse eigenvalue routine is employed, via SLEPc. These values approximately correspond to the first neutral temporal mode in plane Poiseuille flow, therefore the test to be satisfied is that an eigenvalue exists with $ \Im ( c ) \approx 0 $.

Definition in file EVPOrrSommerfeldSparse_slepcz.cpp.

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 24 of file EVPOrrSommerfeldSparse_slepcz.cpp.

25{
26 SlepcSession::getInstance(argc,argv);
27
28 cout << "\n";
29 cout << "=== EVP: Temporal spectra of the Orr-Sommerfeld eqn =\n";
30 cout << "=== with a matrix problem assembled by hand and \n";
31 cout << "=== eigenproblem solved with SLEPc sparse solver.\n";
32 cout << "\n";
33
34 // discretise with these many nodal points
35 const std::size_t nodes( 1001 );
36 // we'll solve as TWO second order problems
37 const std::size_t N( 2 * nodes );
38 // domain boundaries
39 const double left = -1.0;
40 const double right = 1.0;
41 // spatial step for a uniform mesh
42 const double d = ( right - left ) / ( nodes - 1 );
43
44 // matrices for the EVP, initialised with zeroes
47
48 // streamwise wavenumber and Reynolds number
49 const double alpha ( 1.02 );
50 const double Re ( 5772.2 );
51 const D_complex I( 0.0, 1.0 );
52
53 // boundary conditions at the left boundary
54 a( 0, 0 ) = 1.0; // phi( left ) = 0
55 a( 1, 0 ) = -1.5 / d; // phi'( left ) = 0
56 a( 1, 2 ) = 2.0 / d;
57 a( 1, 4 ) = -0.5 / d;
58 // fill the interior nodes
59 for ( std::size_t i = 1; i <= nodes - 2; ++i )
60 {
61 // position in the channel
62 const double y = left + i * d;
63 // Poiseuille flow profile
64 const double U = ( 1.0 - y * y );
65 const double Udd = -2.0;
66
67 // the first quation at the i'th nodal point
68 std::size_t row = 2 * i;
69 a( row, row ) = -2.0 / ( d * d ) - alpha * alpha;
70 a( row, row - 2 ) = 1.0 / ( d * d );
71 a( row, row + 2 ) = 1.0 / ( d * d );
72 a( row, row + 1 ) = -1.0;
73
74 row += 1;
75 // the second equation at the i'th nodal point
76 a( row, row ) = -2.0 / ( d * d ) - alpha * alpha - I * alpha * Re * U;
77 a( row, row - 2 ) = 1.0 / ( d * d );
78 a( row, row + 2 ) = 1.0 / ( d * d );
79 a( row, row - 1 ) = I * alpha * Re * Udd;
80
81 b( row, row ) = - I * alpha * Re;
82 }
83 // boundary conditions at right boundary
84 a( N - 2, N - 2 ) = 1.5 / d;
85 a( N - 2, N - 4 ) = -2.0 / d;
86 a( N - 2, N - 6 ) = 0.5 / d; // psi'( right ) = 0
87 a( N - 1, N - 2 ) = 1.0; // psi( right ) = 0
88
89 /* Note: current KSP configuration uses an LU preconditioner and MUMPS
90 which doesn't mind zeros on the diagonal of a. */
91
92
93 // a vector for storing the eigenvalues
95 SparseLinearEigenSystem<D_complex> system( &a, &b );
96 system.set_target(D_complex(0.2,0.0));
97 system.set_nev(4);
98 system.set_order( "EPS_TARGET_MAGNITUDE" );
99
100 try
101 {
102 system.eigensolve();
103 }
104 catch (const std::runtime_error &error )
105 {
106 cout << " \033[1;31;48m * FAILED THROUGH EXCEPTION BEING RAISED \033[0m\n";
107 return 1;
108 }
109 // tag any eigenvalues with imaginary part > -0.1
110 system.set_shift( D_complex( 0.0, -0.1 ) );
111 system.tag_eigenvalues_upper( + 1 );
112 lambdas = system.get_tagged_eigenvalues();
113 lambdas.dump();
114 double min_growth_rate( lambdas[ 0 ].imag() );
115 // make sure we have a near neutral mode
116 const double tol = 1.e-3;
117
118 std::string dirname("./DATA");
119 mkdir( dirname.c_str(), S_IRWXU );
120
121 TrackerFile spectrum( "./DATA/spectrum.dat" );
122 spectrum.push_ptr( &lambdas, "evs" );
123 spectrum.update();
124
125 // eigenfunctions
126 DenseMatrix<D_complex> eigenvectors;
127 eigenvectors = system.get_tagged_eigenvectors();
128 DenseVector<double> ynodes = Utility::uniform_node_vector(left,right,nodes);
129 OneD_Node_Mesh<D_complex> mesh( ynodes, 4 );
130 // non-zero eigenvalue list => dump index 0 mode
131 if ( lambdas.nelts() > 0 ) {
132 int index(0);
133 for ( unsigned i = 0; i < nodes; ++i ) {
134 mesh(i,0) = eigenvectors(index,2*i+0); //phi_i
135 mesh(i,1) = eigenvectors(index,2*i+1); //psi_i
136 }
137 for ( unsigned i = 1; i < nodes-1; ++i ) {
138 mesh(i,2) = (mesh(i+1,0)-mesh(i-1,0))/(2*d); //u_i=phi'
139 mesh(i,3) = -I*alpha*mesh(i,0); //v_i=-i*alpha*phi
140 }
141 }
142 mesh.normalise(0);
143 mesh.dump_gnu("./DATA/eigenmode.dat");
144
145 if ( std::abs( min_growth_rate ) < tol )
146 {
147 cout << "\033[1;32;48m * PASSED \033[0m\n";
148 return 0;
149 }
150
151 cout << "\033[1;31;48m * FAILED \033[0m\n";
152 cout << " Final error = " << min_growth_rate << "\n";
153 return 1;
154
155}
@ U
Definition: BVPKarman.cpp:20
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 nelts() const
Get the number of elements in the vector Since the vector is dense, the number of elements is the siz...
Definition: DenseVector.h:335
void dump() const
Dump to std::cout.
Definition: DenseVector.cpp:64
A one dimensional mesh utility object.
A matrix class that constructs a SPARSE matrix as a row major std::vector of SparseVectors.
Definition: SparseMatrix.h:31
double Udd(double y)
Globally define the base flow curvature.
double Re
Globally define the Reynolds number and wavenumber.
DenseVector< double > imag(const DenseVector< D_complex > &X)
Return a double DENSE vector containing the imaginary part of a complex DENSE vector.
Definition: Utility.cpp:185
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
std::complex< double > D_complex
A complex double precision number using std::complex.
Definition: Types.h:98

References CppNoddy::DenseVector< _Type >::dump(), CppNoddy::OneD_Node_Mesh< _Type, _Xtype >::dump_gnu(), CppNoddy::DenseVector< _Type >::nelts(), CppNoddy::OneD_Node_Mesh< _Type, _Xtype >::normalise(), CppNoddy::TrackerFile::push_ptr(), U, CppNoddy::Utility::uniform_node_vector(), and CppNoddy::TrackerFile::update().

© 2012

R.E. Hewitt