harmonic.cc
Go to the documentation of this file.
1//LIC// ====================================================================
2//LIC// This file forms part of oomph-lib, the object-oriented,
3//LIC// multi-physics finite-element library, available
4//LIC// at http://www.oomph-lib.org.
5//LIC//
6//LIC// Copyright (C) 2006-2025 Matthias Heil and Andrew Hazel
7//LIC//
8//LIC// This library is free software; you can redistribute it and/or
9//LIC// modify it under the terms of the GNU Lesser General Public
10//LIC// License as published by the Free Software Foundation; either
11//LIC// version 2.1 of the License, or (at your option) any later version.
12//LIC//
13//LIC// This library is distributed in the hope that it will be useful,
14//LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15//LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16//LIC// Lesser General Public License for more details.
17//LIC//
18//LIC// You should have received a copy of the GNU Lesser General Public
19//LIC// License along with this library; if not, write to the Free Software
20//LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21//LIC// 02110-1301 USA.
22//LIC//
23//LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24//LIC//
25//LIC//====================================================================
26//Driver to solve the harmonic equation with homogeneous Dirichlet boundary
27//conditions.
28
29// Generic oomph-lib routines
30#include "generic.h"
31
32// Include the mesh
33#include "meshes/one_d_mesh.h"
34
35using namespace std;
36
37using namespace oomph;
38
39
40//===================================================================
41/// Function-type-object to perform comparison of complex data types
42/// Needed to sort the complex eigenvalues into order based on the
43/// size of the real part.
44//==================================================================
45template <class T>
46class ComplexLess
47{
48public:
49
50 /// Comparison. Are the values identical or not?
51 bool operator()(const complex<T> &x, const complex<T> &y) const
52 {
53 return x.real() < y.real();
54 }
55};
56
57
58//=================================================================
59/// A class for all elements that solve the simple one-dimensional
60/// eigenvalue problem
61/// \f[ \frac{\partial^2 u}{\partial x_i^2} + \lambda u = 0 \f]
62/// These elements are very closely related to the Poisson
63/// elements and could inherit from them. They are here developed
64/// from scratch for pedagogical purposes.
65/// This class contains the generic maths. Shape functions, geometric
66/// mapping etc. must get implemented in derived class.
67//================================================================
68class HarmonicEquations : public virtual FiniteElement
69{
70
71public:
72 /// Empty Constructor
74
75 /// Access function: Eigenfunction value at local node n
76 /// Note that solving the eigenproblem does not assign values
77 /// to this storage space. It is used for output purposes only.
78 virtual inline double u(const unsigned& n) const
79 {return nodal_value(n,0);}
80
81 /// Output the eigenfunction with default number of plot points
82 void output(ostream &outfile)
83 {
84 unsigned nplot=5;
85 output(outfile,nplot);
86 }
87
88 /// Output FE representation of soln: x,y,u or x,y,z,u at
89 /// Nplot plot points
90 void output(ostream &outfile, const unsigned &nplot)
91 {
92 //Vector of local coordinates
93 Vector<double> s(1);
94
95 // Tecplot header info
96 outfile << tecplot_zone_string(nplot);
97
98 // Loop over plot points
99 unsigned num_plot_points=nplot_points(nplot);
100 for (unsigned iplot=0;iplot<num_plot_points;iplot++)
101 {
102 // Get local coordinates of plot point
103 get_s_plot(iplot,nplot,s);
104 //Output the coordinate and the eigenfunction
105 outfile << interpolated_x(s,0) << " " << interpolated_u(s) << std::endl;
106 }
107 // Write tecplot footer (e.g. FE connectivity lists)
108 write_tecplot_zone_footer(outfile,nplot);
109 }
110
111 /// Assemble the contributions to the jacobian and mass
112 /// matrices
114 Vector<double> &residuals,
115 DenseMatrix<double> &jacobian, DenseMatrix<double> &mass_matrix)
116 {
117 //Find out how many nodes there are
118 unsigned n_node = nnode();
119
120 //Set up memory for the shape functions and their derivatives
121 Shape psi(n_node);
122 DShape dpsidx(n_node,1);
123
124 //Set the number of integration points
125 unsigned n_intpt = integral_pt()->nweight();
126
127 //Integers to store the local equation and unknown numbers
128 int local_eqn=0, local_unknown=0;
129
130 //Loop over the integration points
131 for(unsigned ipt=0;ipt<n_intpt;ipt++)
132 {
133 //Get the integral weight
134 double w = integral_pt()->weight(ipt);
135
136 //Call the derivatives of the shape and test functions
137 double J = dshape_eulerian_at_knot(ipt,psi,dpsidx);
138
139 //Premultiply the weights and the Jacobian
140 double W = w*J;
141
142 //Assemble the contributions to the mass matrix
143 //Loop over the test functions
144 for(unsigned l=0;l<n_node;l++)
145 {
146 //Get the local equation number
147 local_eqn = u_local_eqn(l);
148 /*IF it's not a boundary condition*/
149 if(local_eqn >= 0)
150 {
151 //Loop over the shape functions
152 for(unsigned l2=0;l2<n_node;l2++)
153 {
154 local_unknown = u_local_eqn(l2);
155 //If at a non-zero degree of freedom add in the entry
156 if(local_unknown >= 0)
157 {
158 jacobian(local_eqn,local_unknown) += dpsidx(l,0)*dpsidx(l2,0)*W;
159 mass_matrix(local_eqn, local_unknown) += psi(l)*psi(l2)*W;
160 }
161 }
162 }
163 }
164 }
165 } //end_of_fill_in_contribution_to_jacobian_and_mass_matrix
166
167 /// Return FE representation of function value u(s) at local coordinate s
168 inline double interpolated_u(const Vector<double> &s) const
169 {
170 unsigned n_node = nnode();
171
172 //Local shape functions
173 Shape psi(n_node);
174
175 //Find values of basis function
176 this->shape(s,psi);
177
178 //Initialise value of u
179 double interpolated_u = 0.0;
180
181 //Loop over the local nodes and sum
182 for(unsigned l=0;l<n_node;l++) {interpolated_u+=u(l)*psi[l];}
183
184 //Return the interpolated value of the eigenfunction
185 return(interpolated_u);
186 }
187
188protected:
189
190 /// Shape/test functions and derivs w.r.t. to global coords at
191 /// local coord. s; return Jacobian of mapping
192 virtual double dshape_eulerian(const Vector<double> &s,
193 Shape &psi,
194 DShape &dpsidx) const=0;
195
196 /// Shape/test functions and derivs w.r.t. to global coords at
197 /// integration point ipt; return Jacobian of mapping
198 virtual double dshape_eulerian_at_knot(const unsigned &ipt,
199 Shape &psi,
200 DShape &dpsidx) const=0;
201
202 /// Access function that returns the local equation number
203 /// of the unknown in the problem. Default is to assume that it is the
204 /// first (only) value stored at the node.
205 virtual inline int u_local_eqn(const unsigned &n)
206 {return nodal_local_eqn(n,0);}
207
208 private:
209
210};
211
212
213
214//======================================================================
215/// QHarmonicElement<NNODE_1D> elements are 1D Elements with
216/// NNODE_1D nodal points that are used to solve the Harmonic eigenvalue
217/// Problem described by HarmonicEquations.
218//======================================================================
219template <unsigned NNODE_1D>
220class QHarmonicElement : public virtual QElement<1,NNODE_1D>,
221 public HarmonicEquations
222{
223
224 public:
225
226 /// Constructor: Call constructors for QElement and
227 /// Poisson equations
228 QHarmonicElement() : QElement<1,NNODE_1D>(), HarmonicEquations() {}
229
230 /// Required # of `values' (pinned or dofs)
231 /// at node n
232 inline unsigned required_nvalue(const unsigned &n) const {return 1;}
233
234 /// Output function overloaded from HarmonicEquations
235 void output(ostream &outfile)
236 {HarmonicEquations::output(outfile);}
237
238 /// Output function overloaded from HarmonicEquations
239 void output(ostream &outfile, const unsigned &Nplot)
240 {HarmonicEquations::output(outfile,Nplot);}
241
242
243protected:
244
245/// Shape, test functions & derivs. w.r.t. to global coords. Return Jacobian.
246 inline double dshape_eulerian(const Vector<double> &s,
247 Shape &psi,
248 DShape &dpsidx) const
249 {return QElement<1,NNODE_1D>::dshape_eulerian(s,psi,dpsidx);}
250
251
252 /// Shape, test functions & derivs. w.r.t. to global coords. at
253 /// integration point ipt. Return Jacobian.
254 inline double dshape_eulerian_at_knot(const unsigned& ipt,
255 Shape &psi,
256 DShape &dpsidx) const
257 {return QElement<1,NNODE_1D>::dshape_eulerian_at_knot(ipt,psi,dpsidx);}
258
259}; //end_of_QHarmonic_class_definition
260
261
262//==start_of_problem_class============================================
263/// 1D Harmonic problem in unit interval.
264//====================================================================
265template<class ELEMENT,class EIGEN_SOLVER>
266class HarmonicProblem : public Problem
267{
268public:
269
270 /// Constructor: Pass number of elements and pointer to source function
271 HarmonicProblem(const unsigned& n_element);
272
273 /// Destructor (empty)
274 ~HarmonicProblem(){delete this->mesh_pt(); delete this->eigen_solver_pt();}
275
276 /// Solve the problem
277 void solve(const unsigned &label);
278
279 /// Doc the solution, pass the number of the case considered,
280 /// so that output files can be distinguished.
281 void doc_solution(const unsigned& label);
282
283}; // end of problem class
284
285
286
287//=====start_of_constructor===============================================
288/// Constructor for 1D Harmonic problem in unit interval.
289/// Discretise the 1D domain with n_element elements of type ELEMENT.
290/// Specify function pointer to source function.
291//========================================================================
292template<class ELEMENT,class EIGEN_SOLVER>
294 const unsigned& n_element)
295{
296 //Create the eigen solver
297 this->eigen_solver_pt() = new EIGEN_SOLVER;
298
299 //Set domain length
300 double L=1.0;
301
302 // Build mesh and store pointer in Problem
303 Problem::mesh_pt() = new OneDMesh<ELEMENT>(n_element,L);
304
305 // Set the boundary conditions for this problem: By default, all nodal
306 // values are free -- we only need to pin the ones that have
307 // Dirichlet conditions.
308
309 // Pin the single nodal value at the single node on mesh
310 // boundary 0 (= the left domain boundary at x=0)
311 mesh_pt()->boundary_node_pt(0,0)->pin(0);
312
313 // Pin the single nodal value at the single node on mesh
314 // boundary 1 (= the right domain boundary at x=1)
315 mesh_pt()->boundary_node_pt(1,0)->pin(0);
316
317 // Setup equation numbering scheme
318 assign_eqn_numbers();
319
320} // end of constructor
321
322
323
324//===start_of_doc=========================================================
325/// Doc the solution in tecplot format. Label files with label.
326//========================================================================
327template<class ELEMENT,class EIGEN_SOLVER>
329{
330
331 ofstream some_file;
332 char filename[100];
333
334 // Number of plot points
335 unsigned npts;
336 npts=5;
337
338 // Output solution with specified number of plot points per element
339 snprintf(filename, sizeof(filename), "soln%i.dat",label);
340 some_file.open(filename);
341 mesh_pt()->output(some_file,npts);
342 some_file.close();
343
344} // end of doc
345
346//=======================start_of_solve==============================
347/// Solve the eigenproblem
348//===================================================================
349template<class ELEMENT,class EIGEN_SOLVER>
351solve(const unsigned& label)
352{
353 //Set external storage for the eigenvalues
354 Vector<complex<double> > eigenvalue;
355 //Set external storage for the eigenvectors
356 Vector<DoubleVector> eigenvector_real;
357 Vector<DoubleVector> eigenvector_imag;
358 //Desired number eigenvalues
359 unsigned n_eval=4;
360
361 //Solve the eigenproblem
362 this->solve_eigenproblem(n_eval,eigenvalue,eigenvector_real,eigenvector_imag);
363
364 //We now need to sort the output based on the size of the real part
365 //of the eigenvalues.
366 //This is because the solver does not necessarily sort the eigenvalues
367 Vector<complex<double> > sorted_eigenvalue = eigenvalue;
368 sort(sorted_eigenvalue.begin(),sorted_eigenvalue.end(),
370
371 //Read out the second smallest eigenvalue
372 complex<double> temp_evalue = sorted_eigenvalue[1];
373 unsigned second_smallest_index=0;
374 //Loop over the unsorted eigenvalues and find the entry that corresponds
375 //to our second smallest eigenvalue.
376 for(unsigned i=0;i<eigenvalue.size();i++)
377 {
378 //Note that equality tests for doubles are bad, but it was just
379 //sorted data, so should be fine
380 if(eigenvalue[i] == temp_evalue) {second_smallest_index=i; break;}
381 }
382
383 //Normalise the eigenvector
384 {
385 //Get the dimension of the eigenvector
386 unsigned dim = eigenvector_real[second_smallest_index].nrow();
387 double length=0.0;
388 //Loop over all the entries
389 for(unsigned i=0;i<dim;i++)
390 {
391 //Add the contribution to the length
392 length += std::pow(eigenvector_real[second_smallest_index][i],2.0);
393 }
394 //Now take the magnitude
395 length = sqrt(length);
396 //Fix the sign
397 if(eigenvector_real[second_smallest_index][0] < 0) {length *= -1.0;}
398 //Finally normalise
399 for(unsigned i=0;i<dim;i++)
400 {
401 eigenvector_real[second_smallest_index][i] /= length;
402 }
403 }
404
405 //Now assign the second eigenvector to the dofs of the problem
406 this->assign_eigenvector_to_dofs(eigenvector_real[second_smallest_index]);
407 //Output solution for this case (label output files with "1")
408 this->doc_solution(label);
409
410 char filename[100];
411 snprintf(filename, sizeof(filename), "eigenvalues%i.dat",label);
412
413 //Open an output file for the sorted eigenvalues
414 ofstream evalues(filename);
415 for(unsigned i=0;i<n_eval;i++)
416 {
417 //Print to screen
418 cout << sorted_eigenvalue[i].real() << " "
419 << sorted_eigenvalue[i].imag() << std::endl;
420 //Send to file
421 evalues << sorted_eigenvalue[i].real() << " "
422 << sorted_eigenvalue[i].imag() << std::endl;
423 }
424
425 evalues.close();
426} //end_of_solve
427
428
429////////////////////////////////////////////////////////////////////////
430////////////////////////////////////////////////////////////////////////
431////////////////////////////////////////////////////////////////////////
432
433
434//======start_of_main==================================================
435/// Driver for 1D Poisson problem
436//=====================================================================
437int main(int argc, char **argv)
438{
439//Want to test Trilinos if we have it, so we must initialise MPI
440//if we have compiled with it
441#ifdef OOMPH_HAS_MPI
442 MPI_Helpers::init(argc,argv);
443#endif
444
445 // Set up the problem:
446 unsigned n_element=100; //Number of elements
447
448 clock_t t_start1 = clock();
449 //Solve with LAPACK_QZ
450 {
452 problem(n_element);
453
454 problem.solve(1);
455 }
456 clock_t t_end1 = clock();
457
458#ifdef OOMPH_HAS_TRILINOS
459 clock_t t_start2 = clock();
460//Solve with Anasazi
461 {
462 // hierher Andrew: This doesn't seem to be included in the self tests
463 HarmonicProblem<QHarmonicElement<3>,ANASAZI> problem(n_element);
464 problem.solve(2);
465 }
466 clock_t t_end2 = clock();
467#endif
468
469 std::cout << "LAPACK TIME: " << (double)(t_end1 - t_start1)/CLOCKS_PER_SEC
470 << std::endl;
471
472#ifdef OOMPH_HAS_TRILINOS
473 std::cout << "ANASAZI TIME: " << (double)(t_end2 - t_start2)/CLOCKS_PER_SEC
474 << std::endl;
475#else
476 //Need to skip test
477#endif
478
479#ifdef OOMPH_HAS_MPI
480 MPI_Helpers::finalize();
481#endif
482
483} // end of main
484
485
486
487
488
489
490
491
492
493
Function-type-object to perform comparison of complex data types Needed to sort the complex eigenvalu...
bool operator()(const complex< T > &x, const complex< T > &y) const
Comparison. Are the values identical or not?
Definition harmonic.cc:51
A class for all elements that solve the simple one-dimensional eigenvalue problem.
Definition harmonic.cc:69
void fill_in_contribution_to_jacobian_and_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix)
Assemble the contributions to the jacobian and mass matrices.
Definition harmonic.cc:113
HarmonicEquations()
Empty Constructor.
Definition harmonic.cc:73
double interpolated_u(const Vector< double > &s) const
Return FE representation of function value u(s) at local coordinate s.
Definition harmonic.cc:168
virtual int u_local_eqn(const unsigned &n)
Access function that returns the local equation number of the unknown in the problem....
Definition harmonic.cc:205
virtual double dshape_eulerian_at_knot(const unsigned &ipt, Shape &psi, DShape &dpsidx) const =0
Shape/test functions and derivs w.r.t. to global coords at integration point ipt; return Jacobian of ...
void output(ostream &outfile, const unsigned &nplot)
Output FE representation of soln: x,y,u or x,y,z,u at Nplot plot points.
Definition harmonic.cc:90
virtual double u(const unsigned &n) const
Access function: Eigenfunction value at local node n Note that solving the eigenproblem does not assi...
Definition harmonic.cc:78
void output(ostream &outfile)
Output the eigenfunction with default number of plot points.
Definition harmonic.cc:82
virtual double dshape_eulerian(const Vector< double > &s, Shape &psi, DShape &dpsidx) const =0
Shape/test functions and derivs w.r.t. to global coords at local coord. s; return Jacobian of mapping...
1D Harmonic problem in unit interval.
Definition harmonic.cc:267
HarmonicProblem(const unsigned &n_element)
Constructor: Pass number of elements and pointer to source function.
Definition harmonic.cc:293
~HarmonicProblem()
Destructor (empty)
Definition harmonic.cc:274
void doc_solution(const unsigned &label)
Doc the solution, pass the number of the case considered, so that output files can be distinguished.
Definition harmonic.cc:328
void solve(const unsigned &label)
Solve the problem.
Definition harmonic.cc:351
QHarmonicElement<NNODE_1D> elements are 1D Elements with NNODE_1D nodal points that are used to solve...
Definition harmonic.cc:222
QHarmonicElement()
Constructor: Call constructors for QElement and Poisson equations.
Definition harmonic.cc:228
double dshape_eulerian(const Vector< double > &s, Shape &psi, DShape &dpsidx) const
Shape, test functions & derivs. w.r.t. to global coords. Return Jacobian.
Definition harmonic.cc:246
void output(ostream &outfile, const unsigned &Nplot)
Output function overloaded from HarmonicEquations.
Definition harmonic.cc:239
double dshape_eulerian_at_knot(const unsigned &ipt, Shape &psi, DShape &dpsidx) const
Shape, test functions & derivs. w.r.t. to global coords. at integration point ipt....
Definition harmonic.cc:254
unsigned required_nvalue(const unsigned &n) const
Required # of ‘values’ (pinned or dofs) at node n.
Definition harmonic.cc:232
void output(ostream &outfile)
Output function overloaded from HarmonicEquations.
Definition harmonic.cc:235
int main(int argc, char **argv)
Driver for 1D Poisson problem.
Definition harmonic.cc:437