womersley_elements.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 
31 //Non-inline functions for Womersley elements
32 #include "womersley_elements.h"
33 
34 
35 namespace oomph
36 {
37 
38 
39 /// Default Womersley number
40 template<unsigned DIM>
42 
43 
44 //========================================================================
45 /// Instantiation of static bool to suppress warning; initialise to false.
46 //========================================================================
48  false;
49 
50 
51 //========================================================================
52 /// Zero!
53 //========================================================================
55 
56 
57 
58 
59 //======================================================================
60 // Set the data for the number of Variables at each node
61 //======================================================================
62 template<unsigned DIM, unsigned NNODE_1D>
64 
65 
66 //======================================================================
67 /// Compute element residual Vector and/or element Jacobian matrix
68 ///
69 /// flag=1: compute both
70 /// flag=0: compute only residual Vector
71 ///
72 /// Pure version without hanging nodes
73 //======================================================================
74 template <unsigned DIM>
77  DenseMatrix<double> &jacobian,
78  unsigned flag)
79 {
80  //Find out how many nodes there are
81  unsigned n_node = nnode();
82 
83  //Find the index at which the variable is stored
84  unsigned u_nodal_index = u_index_womersley();
85 
86  //Set up memory for the shape and test functions
87  Shape psi(n_node), test(n_node);
88  DShape dpsidx(n_node,DIM), dtestdx(n_node,DIM);
89 
90  //Set the value of n_intpt
91  unsigned n_intpt = integral_pt()->nweight();
92 
93  //Set the Vector to hold local coordinates
94  Vector<double> s(DIM);
95 
96  //Integers to hold the local equation and unknowns
97  int local_eqn=0, local_unknown=0;
98 
99  //Loop over the integration points
100  for(unsigned ipt=0;ipt<n_intpt;ipt++)
101  {
102 
103  //Assign values of s
104  for(unsigned i=0;i<DIM;i++) s[i] = integral_pt()->knot(ipt,i);
105 
106  //Get the integral weight
107  double w = integral_pt()->weight(ipt);
108 
109  //Call the derivatives of the shape and test functions
110  double J =
111  dshape_and_dtest_eulerian_at_knot_womersley(ipt,psi,dpsidx,test,dtestdx);
112 
113  //Premultiply the weights and the Jacobian
114  double W = w*J;
115 
116  //Allocate memory for local quantities and initialise to zero
117  double interpolated_u=0.0;
118  double dudt=0.0;
119  Vector<double> interpolated_x(DIM,0.0);
120  Vector<double> interpolated_dudx(DIM,0.0);
121 
122  //Calculate function value and derivatives:
123  // Loop over nodes
124  for(unsigned l=0;l<n_node;l++)
125  {
126  //Calculate the value at the nodes
127  double u_value = raw_nodal_value(l,u_nodal_index);
128  interpolated_u += u_value*psi(l);
129  dudt += du_dt_womersley(l)*psi(l);
130  // Loop over directions
131  for(unsigned j=0;j<DIM;j++)
132  {
133  interpolated_x[j] += raw_nodal_position(l,j)*psi(l);
134  interpolated_dudx[j] += u_value*dpsidx(l,j);
135  }
136  }
137 
138  //Get pressure gradient
139  //---------------------
140  double dpdz;
141 
142  //If no pressure gradient has been set, use zero
143  if(Pressure_gradient_data_pt==0)
144  {
145  dpdz = 0.0;
146  }
147  else
148  {
149  // Get gressure gradient
150  dpdz=Pressure_gradient_data_pt->value(0);
151  }
152 
153 
154  // Assemble residuals and Jacobian
155  //--------------------------------
156 
157  // Loop over the test functions
158  for(unsigned l=0;l<n_node;l++)
159  {
160  local_eqn = nodal_local_eqn(l,u_nodal_index);
161  /*IF it's not a boundary condition*/
162  if(local_eqn >= 0)
163  {
164 
165  // Add dpdz term and time derivative
166  residuals[local_eqn] += (re_st()*dudt+dpdz)*test(l)*W;
167 
168  // Laplace operator
169  for(unsigned k=0;k<DIM;k++)
170  {
171  residuals[local_eqn] +=
172  interpolated_dudx[k]*dtestdx(l,k)*W;
173  }
174 
175 
176  // Calculate the jacobian
177  //-----------------------
178  if(flag)
179  {
180  //Loop over the velocity shape functions again
181  for(unsigned l2=0;l2<n_node;l2++)
182  {
183  local_unknown = nodal_local_eqn(l2,u_nodal_index);
184  //If at a non-zero degree of freedom add in the entry
185  if(local_unknown >= 0)
186  {
187  // Mass matrix
188  jacobian(local_eqn,local_unknown)
189  += re_st()*test(l)*psi(l2)*
190  node_pt(l2)->time_stepper_pt()->weight(1,0)*W;
191 
192  // Laplace operator & mesh velocity bit
193  for(unsigned i=0;i<DIM;i++)
194  {
195  double tmp=dtestdx(l,i);
196  jacobian(local_eqn,local_unknown) += dpsidx(l2,i)*tmp*W;
197  }
198  }
199  }
200 
201  // Derivative w.r.t. pressure gradient data (if it's
202  // an unknown)
203  if ((Pressure_gradient_data_pt!=0)&&
204  (!Pressure_gradient_data_pt->is_pinned(0)))
205  {
206  local_unknown=external_local_eqn(0,0);
207  if (local_unknown>=0)
208  {
209  jacobian(local_eqn,local_unknown) += test(l)*W;
210  }
211 
212  // Derivatives of the final eqn (volume flux constraint
213  // w.r.t. to this unknown)
214  unsigned final_local_eqn=external_local_eqn(0,0);
215  unsigned local_unknown=local_eqn; // [from above just renaming
216  // // for clarity(!?)]
217  jacobian(final_local_eqn,local_unknown)+=psi(l)*W;
218  }
219 
220  }
221  }
222  }
223 
224 
225  } // End of loop over integration points
226 }
227 
228 
229 
230 
231 
232 //======================================================================
233 /// Compute volume flux through element
234 //======================================================================
235 template <unsigned DIM>
237 {
238  //Find out how many nodes there are
239  unsigned n_node = nnode();
240 
241  //Find the index at which the variable is stored
242  unsigned u_nodal_index = u_index_womersley();
243 
244  //Set up memory for the shape fcs
245  Shape psi(n_node);
246  DShape dpsidx(n_node,DIM);
247 
248  //Set the value of n_intpt
249  unsigned n_intpt = integral_pt()->nweight();
250 
251  //Set the Vector to hold local coordinates
252  Vector<double> s(DIM);
253 
254  // Initialise flux
255  double flux=0.0;
256 
257  //Loop over the integration points
258  for(unsigned ipt=0;ipt<n_intpt;ipt++)
259  {
260 
261  //Assign values of s
262  for(unsigned i=0;i<DIM;i++) s[i] = integral_pt()->knot(ipt,i);
263 
264  //Get the integral weight
265  double w = integral_pt()->weight(ipt);
266 
267  //Call the derivatives of the shape and test functions
268  double J = dshape_eulerian_at_knot(ipt,psi,dpsidx);
269 
270  //Premultiply the weights and the Jacobian
271  double W = w*J;
272 
273  //Allocate memory for local quantities and initialise to zero
274  double interpolated_u=0.0;
275 
276  //Calculate function value
277 
278  // Loop over nodes
279  for(unsigned l=0;l<n_node;l++)
280  {
281  // Calculate the value at the nodes (takes hanging node status
282  // into account
283  interpolated_u += nodal_value(l,u_nodal_index)*psi(l);
284  }
285 
286  // Add to flux
287  flux+=interpolated_u*W;
288 
289  } // End of loop over integration points
290 
291  return flux;
292 
293 }
294 
295 
296 
297 
298 
299 
300 //======================================================================
301 /// Self-test: Return 0 for OK
302 //======================================================================
303 template <unsigned DIM>
305 {
306 
307  bool passed=true;
308 
309  // Check lower-level stuff
310  if (FiniteElement::self_test()!=0)
311  {
312  passed=false;
313  }
314 
315  // Return verdict
316  if (passed)
317  {
318  return 0;
319  }
320  else
321  {
322  return 1;
323  }
324 
325 }
326 
327 
328 
329 
330 //======================================================================
331 /// Output function: x,y,z_out,0,0,u,0 to allow comparison
332 /// against full Navier Stokes at n_nplot x n_plot points (2D)
333 //======================================================================
334 template <unsigned DIM>
335 void WomersleyEquations<DIM>::output_3d(std::ostream &outfile,
336  const unsigned &nplot,
337  const double& z_out)
338 {
339  //Vector of local coordinates
340  Vector<double> s(DIM);
341 
342  // Tecplot header info
343  outfile << tecplot_zone_string(nplot);
344 
345  // Loop over plot points
346  unsigned num_plot_points=nplot_points(nplot);
347  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
348  {
349  // Get local coordinates of plot point
350  get_s_plot(iplot,nplot,s);
351 
352  for(unsigned i=0;i<DIM;i++)
353  {
354  outfile << interpolated_x(s,i) << " ";
355  }
356  outfile << z_out << " 0.0 0.0 " ;
357  outfile << interpolated_u_womersley(s);
358  outfile << " 0.0 " << std::endl;
359  }
360 
361  // Write tecplot footer (e.g. FE connectivity lists)
362  write_tecplot_zone_footer(outfile,nplot);
363 
364 }
365 
366 //======================================================================
367 /// Output function:
368 ///
369 /// x,y,u or x,y,z,u
370 ///
371 /// nplot points in each coordinate direction
372 //======================================================================
373 template <unsigned DIM>
374 void WomersleyEquations<DIM>::output(std::ostream &outfile,
375  const unsigned &nplot)
376 {
377 
378  //Vector of local coordinates
379  Vector<double> s(DIM);
380 
381  // Tecplot header info
382  outfile << tecplot_zone_string(nplot);
383 
384  // Loop over plot points
385  unsigned num_plot_points=nplot_points(nplot);
386  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
387  {
388  // Get local coordinates of plot point
389  get_s_plot(iplot,nplot,s);
390 
391  for(unsigned i=0;i<DIM;i++)
392  {
393  outfile << interpolated_x(s,i) << " ";
394  }
395  outfile << interpolated_u_womersley(s) << std::endl;
396  }
397 
398  // Write tecplot footer (e.g. FE connectivity lists)
399  write_tecplot_zone_footer(outfile,nplot);
400 
401 }
402 
403 
404 
405 //======================================================================
406 /// C-style output function:
407 ///
408 /// x,y,u or x,y,z,u
409 ///
410 /// nplot points in each coordinate direction
411 //======================================================================
412 template <unsigned DIM>
414  const unsigned &nplot)
415 {
416  //Vector of local coordinates
417  Vector<double> s(DIM);
418 
419  // Tecplot header info
420  fprintf(file_pt,"%s",tecplot_zone_string(nplot).c_str());
421 
422  // Loop over plot points
423  unsigned num_plot_points=nplot_points(nplot);
424  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
425  {
426 
427  // Get local coordinates of plot point
428  get_s_plot(iplot,nplot,s);
429 
430  for(unsigned i=0;i<DIM;i++)
431  {
432  fprintf(file_pt,"%g ",interpolated_x(s,i));
433 
434  }
435  fprintf(file_pt,"%g \n",interpolated_u_womersley(s));
436  }
437 
438  // Write tecplot footer (e.g. FE connectivity lists)
439  write_tecplot_zone_footer(file_pt,nplot);
440 
441 }
442 
443 
444 
445 //======================================================================
446  /// Output exact solution
447  ///
448  /// Solution is provided via function pointer.
449  /// Plot at a given number of plot points.
450  ///
451  /// x,y,u_exact or x,y,z,u_exact
452 //======================================================================
453 template <unsigned DIM>
454 void WomersleyEquations<DIM>::output_fct(std::ostream &outfile,
455  const unsigned &nplot,
457 {
458 
459  //Vector of local coordinates
460  Vector<double> s(DIM);
461 
462  // Vector for coordintes
463  Vector<double> x(DIM);
464 
465  // Tecplot header info
466  outfile << tecplot_zone_string(nplot);
467 
468  // Exact solution Vector (here a scalar)
469  Vector<double> exact_soln(1);
470 
471  // Loop over plot points
472  unsigned num_plot_points=nplot_points(nplot);
473  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
474  {
475 
476  // Get local coordinates of plot point
477  get_s_plot(iplot,nplot,s);
478 
479  // Get x position as Vector
480  interpolated_x(s,x);
481 
482  // Get exact solution at this point
483  (*exact_soln_pt)(x,exact_soln);
484 
485  //Output x,y,...,u_exact
486  for(unsigned i=0;i<DIM;i++)
487  {
488  outfile << x[i] << " ";
489  }
490  outfile << exact_soln[0] << std::endl;
491 
492  }
493 
494  // Write tecplot footer (e.g. FE connectivity lists)
495  write_tecplot_zone_footer(outfile,nplot);
496 
497 }
498 
499 
500 
501 //======================================================================
502 /// Output exact solution at time t
503 ///
504 /// Solution is provided via function pointer.
505 /// Plot at a given number of plot points.
506 ///
507 /// x,y,u_exact or x,y,z,u_exact
508 //======================================================================
509 template <unsigned DIM>
510 void WomersleyEquations<DIM>::output_fct(std::ostream &outfile,
511  const unsigned &nplot,
512  const double& time,
514 
515 {
516 
517  //Vector of local coordinates
518  Vector<double> s(DIM);
519 
520  // Vector for coordintes
521  Vector<double> x(DIM);
522 
523 
524  // Tecplot header info
525  outfile << tecplot_zone_string(nplot);
526 
527  // Exact solution Vector (here a scalar)
528  Vector<double> exact_soln(1);
529 
530  // Loop over plot points
531  unsigned num_plot_points=nplot_points(nplot);
532  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
533  {
534 
535  // Get local coordinates of plot point
536  get_s_plot(iplot,nplot,s);
537 
538  // Get x position as Vector
539  interpolated_x(s,x);
540 
541  // Get exact solution at this point
542  (*exact_soln_pt)(time,x,exact_soln);
543 
544  //Output x,y,...,u_exact
545  for(unsigned i=0;i<DIM;i++)
546  {
547  outfile << x[i] << " ";
548  }
549  outfile << exact_soln[0] << std::endl;
550 
551  }
552 
553  // Write tecplot footer (e.g. FE connectivity lists)
554  write_tecplot_zone_footer(outfile,nplot);
555 
556 }
557 
558 
559 
560 //======================================================================
561  /// Validate against exact solution
562  ///
563  /// Solution is provided via function pointer.
564  /// Plot error at a given number of plot points.
565  ///
566 //======================================================================
567 template <unsigned DIM>
569 compute_error(std::ostream &outfile,
571  double& error, double& norm)
572 {
573 
574  // Initialise
575  error=0.0;
576  norm=0.0;
577 
578  //Vector of local coordinates
579  Vector<double> s(DIM);
580 
581  // Vector for coordintes
582  Vector<double> x(DIM);
583 
584  //Find out how many nodes there are in the element
585  unsigned n_node = nnode();
586 
587  Shape psi(n_node);
588 
589  //Set the value of n_intpt
590  unsigned n_intpt = integral_pt()->nweight();
591 
592  // Tecplot header info
593  outfile << "ZONE" << std::endl;
594 
595  // Exact solution Vector (here a scalar)
596  Vector<double> exact_soln(1);
597 
598  //Loop over the integration points
599  for(unsigned ipt=0;ipt<n_intpt;ipt++)
600  {
601 
602  //Assign values of s
603  for(unsigned i=0;i<DIM;i++)
604  {
605  s[i] = integral_pt()->knot(ipt,i);
606  }
607 
608  //Get the integral weight
609  double w = integral_pt()->weight(ipt);
610 
611  // Get jacobian of mapping
612  double J=J_eulerian(s);
613 
614  //Premultiply the weights and the Jacobian
615  double W = w*J;
616 
617  // Get x position as Vector
618  interpolated_x(s,x);
619 
620  // Get FE function value
621  double u_fe = interpolated_u_womersley(s);
622 
623  // Get exact solution at this point
624  (*exact_soln_pt)(x,exact_soln);
625 
626  //Output x,y,...,error
627  for(unsigned i=0;i<DIM;i++)
628  {
629  outfile << x[i] << " ";
630  }
631  outfile << exact_soln[0] << " " << exact_soln[0]-u_fe << std::endl;
632 
633  // Add to error and norm
634  norm+=exact_soln[0]*exact_soln[0]*W;
635  error+=(exact_soln[0]-u_fe)*(exact_soln[0]-u_fe)*W;
636  }
637 }
638 
639 
640 
641 
642 //======================================================================
643 /// Validate against exact solution at time t.
644 ///
645 /// Solution is provided via function pointer.
646 /// Plot error at a given number of plot points.
647 ///
648 //======================================================================
649 template<unsigned DIM>
650 void WomersleyEquations<DIM>::compute_error(std::ostream &outfile,
652  const double& time, double& error, double& norm)
653 
654 {
655 
656  // Initialise
657  error=0.0;
658  norm=0.0;
659 
660  //Vector of local coordinates
661  Vector<double> s(DIM);
662 
663  // Vector for coordintes
664  Vector<double> x(DIM);
665 
666 
667  //Find out how many nodes there are in the element
668  unsigned n_node = nnode();
669 
670  Shape psi(n_node);
671 
672  //Set the value of n_intpt
673  unsigned n_intpt = integral_pt()->nweight();
674 
675  // Tecplot
676  outfile << "ZONE" << std::endl;
677 
678  // Exact solution Vector (here a scalar)
679  Vector<double> exact_soln(1);
680 
681  //Loop over the integration points
682  for(unsigned ipt=0;ipt<n_intpt;ipt++)
683  {
684 
685  //Assign values of s
686  for(unsigned i=0;i<DIM;i++)
687  {
688  s[i] = integral_pt()->knot(ipt,i);
689  }
690 
691  //Get the integral weight
692  double w = integral_pt()->weight(ipt);
693 
694  // Get jacobian of mapping
695  double J=J_eulerian(s);
696 
697  //Premultiply the weights and the Jacobian
698  double W = w*J;
699 
700  // Get x position as Vector
701  interpolated_x(s,x);
702 
703  // Get FE function value
704  double u_fe = interpolated_u_womersley(s);
705 
706  // Get exact solution at this point
707  (*exact_soln_pt)(time,x,exact_soln);
708 
709  //Output x,y,...,error
710  for(unsigned i=0;i<DIM;i++)
711  {
712  outfile << x[i] << " ";
713  }
714  outfile << exact_soln[0] << " " << exact_soln[0]-u_fe << std::endl;
715 
716  // Add to error and norm
717  norm+=exact_soln[0]*exact_soln[0]*W;
718  error+=(exact_soln[0]-u_fe)*(exact_soln[0]-u_fe)*W;
719 
720  }
721 }
722 
723 
724 
725 
726 //====================================================================
727 // Force build of templates
728 //====================================================================
729 
730 template class WomersleyEquations<1>;
731 
732 template class QWomersleyElement<1,2>;
733 template class QWomersleyElement<1,3>;
734 template class QWomersleyElement<1,4>;
735 
736 template class WomersleyEquations<2>;
737 
738 template class QWomersleyElement<2,2>;
739 template class QWomersleyElement<2,3>;
740 template class QWomersleyElement<2,4>;
741 
742 //template class QWomersleyElement<3,2>;
743 //template class QWomersleyElement<3,3>;
744 //template class QWomersleyElement<3,4>;
745 
746 }
747 
static const unsigned Initial_Nvalue
Static array of ints to hold number of variables at nodes: Initial_Nvalue[n].
unsigned self_test()
Self-test: Return 0 for OK.
virtual void fill_in_generic_residual_contribution_womersley(Vector< double > &residuals, DenseMatrix< double > &jacobian, unsigned flag)
Compute element residual Vector only (if flag=and/or element Jacobian matrix.
cstr elem_len * i
Definition: cfortran.h:607
virtual unsigned self_test()
Self-test: Check inversion of element & do self-test for GeneralisedElement. Return 0 if OK...
Definition: elements.cc:4333
void(* UnsteadyExactSolutionFctPt)(const double &, const Vector< double > &, Vector< double > &)
Function pointer for function that computes Vector-valued time-dependent function as ...
Definition: elements.h:1729
double get_volume_flux()
Compute total volume flux through element.
void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Get error against and norm of exact solution.
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as ...
Definition: elements.h:1723
static char t char * s
Definition: cfortran.h:572
void output_3d(std::ostream &outfile, const unsigned &n_plot, const double &z_out)
Output function: x,y,z_out,0,0,u,0 to allow comparison against full Navier Stokes at n_nplot x n_plot...
void output_fct(std::ostream &outfile, const unsigned &nplot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output exact soln: x,y,u_exact or x,y,z,u_exact at nplot^DIM plot points.
void output(std::ostream &outfile)
Output with default number of plot points.
static bool Suppress_warning_about_unpinned_nst_dofs
Static bool to suppress warning.
static double Default_ReSt_value
Static default value for the Womersley number.