two_d_linear_wave_flux.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-2023 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 for 2D linear wave equation in a rectangular domain
27 // with flux boundary conditions along one of the edges of the domain.
28 
29 //Generic includes
30 #include "generic.h"
31 
32 // Linear wave includes
33 #include "linear_wave.h"
34 
35 // Mesh
36 #include "meshes/rectangular_quadmesh.h"
37 
38 using namespace std;
39 
40 using namespace oomph;
41 
42 //==start_of_tanh_solution============================================
43 /// Namespace for travelling wave solution for LinearWave equation
44 /// with sharp step
45 //====================================================================
46 namespace TanhSolnForLinearWave
47 {
48 
49  /// Parameter for steepness of step
50  double Alpha;
51 
52  /// Orientation of step wave
53  double Phi;
54 
55  /// Exact solution
56  double exact_u(const double& time, const Vector<double>& x)
57  {
58  double zeta=cos(Phi)*x[0]+sin(Phi)*x[1];
59  return tanh(1.0-Alpha*(zeta-time));
60  }
61 
62  /// 1st time-deriv of exact solution
63  double exact_dudt(const double& time, const Vector<double>& x)
64  {
65  double zeta=cos(Phi)*x[0]+sin(Phi)*x[1];
66  return Alpha/(cosh(1.0-Alpha*(zeta-time))*
67  cosh(1.0-Alpha*(zeta-time)));
68  }
69 
70  /// 2nd time-deriv of exact solution
71  double exact_d2udt2(const double& time, const Vector<double>& x)
72  {
73  double zeta=cos(Phi)*x[0]+sin(Phi)*x[1];
74  return -2.0*Alpha*Alpha*tanh(1.0-Alpha*(zeta-time))/
75  (cosh(1.0-Alpha*(zeta-time))*cosh(1.0-Alpha*(zeta-time)));
76  }
77 
78 
79  /// Exact solution as a vector
80  void get_exact_u(const double& time, const Vector<double>& x,
81  Vector<double>& u)
82  {
83  u[0]=exact_u(time,x);
84  u[1]=exact_dudt(time,x);
85  u[2]=exact_d2udt2(time,x);
86  }
87 
88  /// Source function to make it an exact solution
89  void get_source(const double& time, const Vector<double>& x, double& source)
90  {
91  source=0.0;
92  }
93 
94 
95  /// Gradient of exact solution
96  void get_exact_gradient(const double& time, const Vector<double>& x,
97  Vector<double>& dudx)
98  {
99  double zeta=cos(Phi)*x[0]+sin(Phi)*x[1];
100  dudx[0] = -Alpha*cos(Phi)/(cosh(1.0-Alpha*(zeta-time))
101  *cosh(1.0-Alpha*(zeta-time)));
102  dudx[1] = -Alpha*sin(Phi)/(cosh(1.0-Alpha*(zeta-time))
103  *cosh(1.0-Alpha*(zeta-time)));
104  }
105 
106 
107  /// Prescribed flux on a fixed y max boundary
108  void prescribed_flux_on_fixed_y_boundary(const double& time,
109  const Vector<double>& x,
110  double& flux)
111  {
112  // Set up normal
113  Vector<double> dudx(2), n(2);
114  n[0]=1.0;
115  n[1]=0.0;
116 
117  // Get gradient
118  get_exact_gradient(time,x,dudx);
119 
120  // Flux
121  flux = dudx[0]*n[0] + dudx[1]*n[1];
122  }
123 
124 
125 } // end of tanh solution
126 
127 
128 
129 
130 /// /////////////////////////////////////////////////////////////////////
131 /// /////////////////////////////////////////////////////////////////////
132 /// /////////////////////////////////////////////////////////////////////
133 
134 
135 
136 //===start_of_problem_class===========================================
137 /// LinearWave problem with flux boundary conditions in rectangle
138 //====================================================================
139 template<class ELEMENT, class TIMESTEPPER>
140 class LinearWaveProblem : public Problem
141 {
142 
143 public:
144 
145  /// Constructor: pass number of elements in x and y directions
146  /// and pointer to source function.
147  LinearWaveProblem(const unsigned& nx, const unsigned& ny,
148  LinearWaveEquations<2>::LinearWaveSourceFctPt source_fct_pt);
149 
150  /// Destructor (empty)
152 
153  /// Update the problem specs after solve (empty)
155 
156  /// Update the problem specs before solve (empty)
158 
159  /// Update the problem specs after solve (empty)
161 
162  /// Update the problem specs before next timestep:
163  /// Set Dirchlet boundary conditions from exact solution.
165  {
166  Vector<typename TIMESTEPPER::NodeInitialConditionFctPt>
167  initial_value_fct(1);
168  Vector<typename TIMESTEPPER::NodeInitialConditionFctPt>
169  initial_veloc_fct(1);
170  Vector<typename TIMESTEPPER::NodeInitialConditionFctPt>
171  initial_accel_fct(1);
172 
173  // Assign values for analytical value, veloc and accel:
174  initial_value_fct[0]=&TanhSolnForLinearWave::exact_u;
175  initial_veloc_fct[0]=&TanhSolnForLinearWave::exact_dudt;
176  initial_accel_fct[0]=&TanhSolnForLinearWave::exact_d2udt2;
177 
178  // Loop over boundaries
179  unsigned num_bound=Bulk_mesh_pt->nboundary();
180  for (unsigned ibound=0;ibound<num_bound;ibound++)
181  {
182  // Ignore boundary 1 where flux condition is applied
183  if (ibound!=1)
184  {
185  // Loop over boundary nodes
186  unsigned num_nod=Bulk_mesh_pt->nboundary_node(ibound);
187  for (unsigned inod=0;inod<num_nod;inod++)
188  {
189  // Set the boundary condition from the exact solution
190  Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(ibound,inod);
191 
192  bool use_direct_assignment=false;
193  if (use_direct_assignment)
194  {
195  // Set nodal coordinates for evaluation of BC:
196  Vector<double> x(2);
197  x[0]=nod_pt->x(0);
198  x[1]=nod_pt->x(1);
199 
200  // Set exact solution at current time
201  nod_pt->
202  set_value(0,
203  TanhSolnForLinearWave::exact_u(time_pt()->time(),x));
204  }
205  else
206  {
207  // Get timestepper
208  TIMESTEPPER* timestepper_pt=dynamic_cast<TIMESTEPPER*>
209  (time_stepper_pt());
210 
211  // Assign the history values
212  timestepper_pt->assign_initial_data_values(nod_pt,
213  initial_value_fct,
214  initial_veloc_fct,
215  initial_accel_fct);
216  }
217  }
218  }
219  }
220  } // end of actions before timestep
221 
222  /// Set initial condition (incl history values) according
223  /// to specified function.
225 
226  /// Doc the solution
227  void doc_solution(DocInfo& doc_info);
228 
229  /// Do unsteady run
230  void unsteady_run();
231 
232 private:
233 
234  /// Create LinearWave flux elements on boundary b of the Mesh pointed
235  /// to by bulk_mesh_pt and add them to the Mesh object pointed to by
236  /// surface_mesh_pt
237  void create_flux_elements(const unsigned& b, Mesh* const& bulk_mesh_pt,
238  Mesh* const& surface_mesh_pt);
239 
240  /// Pointer to the "bulk" mesh
241  RectangularQuadMesh<ELEMENT>* Bulk_mesh_pt;
242 
243  /// Pointer to the "surface" mesh
245 
246  // Trace file
247  ofstream Trace_file;
248 
249 }; // end of problem class
250 
251 
252 
253 //===start_of_constructor=================================================
254 /// Constructor for LinearWave problem
255 //========================================================================
256 template<class ELEMENT, class TIMESTEPPER>
258  const unsigned& nx, const unsigned& ny,
259  LinearWaveEquations<2>::LinearWaveSourceFctPt source_fct_pt)
260 {
261 
262  //Create the timestepper -- this constructs the time object as well
263  add_time_stepper_pt(new TIMESTEPPER());
264 
265 
266  // Set up parameters for exact solution
267  //-------------------------------------
268 
269  // Steepness of tanh profile
271 
272  // Orientation of step wave
273  TanhSolnForLinearWave::Phi=MathematicalConstants::Pi/180.0*30.0;
274 
275 
276 
277  // Set up mesh
278  //------------
279 
280  // # of elements in x-direction
281  unsigned Nx=nx;
282 
283  // # of elements in y-direction
284  unsigned Ny=ny;
285 
286  // Domain length in x-direction
287  double Lx=1.0;
288 
289  // Domain length in y-direction
290  double Ly=2.0;
291 
292  // Build bulk mesh
293  Bulk_mesh_pt=new RectangularQuadMesh<ELEMENT>(Nx,Ny,Lx,Ly,time_stepper_pt());
294 
295  // Create "surface mesh" that will contain only the prescribed-flux
296  // elements. The constructor just creates the mesh without
297  // giving it any elements, nodes, etc.
298  Surface_mesh_pt = new Mesh;
299 
300  // Create prescribed-flux elements from all elements that are
301  // adjacent to boundary 1, but add them to a separate mesh.
302  // Note that this is exactly the same function as used in the
303  // single mesh version of the problem, we merely pass different Mesh pointers.
304  create_flux_elements(1,Bulk_mesh_pt,Surface_mesh_pt);
305 
306  // Add the two sub meshes to the problem
307  add_sub_mesh(Bulk_mesh_pt);
308  add_sub_mesh(Surface_mesh_pt);
309 
310  // Combine all submeshes into a single Mesh
311  build_global_mesh();
312 
313 
314 
315  // Set the boundary conditions for this problem: All nodes are
316  // free by default -- just pin the ones that have Dirichlet conditions
317  // here.
318  unsigned num_bound = Bulk_mesh_pt->nboundary();
319  for(unsigned ibound=0;ibound<num_bound;ibound++)
320  {
321  if (ibound!=1) // Not on the flux boundary
322  {
323  unsigned num_nod= Bulk_mesh_pt->nboundary_node(ibound);
324  for (unsigned inod=0;inod<num_nod;inod++)
325  {
326  Bulk_mesh_pt->boundary_node_pt(ibound,inod)->pin(0);
327  }
328  }
329  }
330 
331  // Complete build of bulk elements
332  // -------------------------------
333 
334  // Loop over the elements to set up element-specific
335  // things that cannot be handled by constructor
336  unsigned n_element = Bulk_mesh_pt->nelement();
337  for(unsigned i=0;i<n_element;i++)
338  {
339  // Upcast from FiniteElement to the present element
340  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(i));
341 
342  //Set the source function pointer
343  el_pt->source_fct_pt() = source_fct_pt;
344  }
345 
346 
347  // Complete build of flux elements
348  // -------------------------------
349 
350  // Loop over surface elements to set up element-specific
351  // things that cannot be handled by constructor
352  n_element = Surface_mesh_pt->nelement();
353  for (unsigned e=0;e<n_element;e++)
354  {
355  // Upcast from GeneralisedElement to LinearWave flux element
356  LinearWaveFluxElement<ELEMENT> *el_pt =
357  dynamic_cast< LinearWaveFluxElement<ELEMENT>*>(
358  Surface_mesh_pt->element_pt(e));
359 
360  el_pt->flux_fct_pt() =
362  }
363 
364  //Setup equation numbering scheme
365  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
366 
367 } // end of constructor
368 
369 
370 
371 //===start_of_set_initial_condition=======================================
372 /// Set initial condition.
373 //========================================================================
374 template<class ELEMENT, class TIMESTEPPER>
376 {
377 
378  // Get timestepper
379  TIMESTEPPER* timestepper_pt=dynamic_cast<TIMESTEPPER*>(time_stepper_pt());
380 
381  // Vector of function pointers to functions that specify the
382  // value, and the first and second time-derivatives of the
383  // function used as the initial condition
384  Vector<typename TIMESTEPPER::NodeInitialConditionFctPt>
385  initial_value_fct(1);
386  Vector<typename TIMESTEPPER::NodeInitialConditionFctPt>
387  initial_veloc_fct(1);
388  Vector<typename TIMESTEPPER::NodeInitialConditionFctPt>
389  initial_accel_fct(1);
390 
391  // Assign values for analytical value, veloc and accel:
392  initial_value_fct[0]=&TanhSolnForLinearWave::exact_u;
393  initial_veloc_fct[0]=&TanhSolnForLinearWave::exact_dudt;
394  initial_accel_fct[0]=&TanhSolnForLinearWave::exact_d2udt2;
395 
396  // Assign Newmark history values so that Newmark approximations
397  // for velocity and accel are correct at initial time:
398 
399  // Loop over the nodes to set initial conditions everywhere
400  unsigned num_nod=mesh_pt()->nnode();
401  for (unsigned jnod=0;jnod<num_nod;jnod++)
402  {
403  // Pointer to node
404  Node* nod_pt=mesh_pt()->node_pt(jnod);
405 
406  // Assign the history values
407  timestepper_pt->assign_initial_data_values(nod_pt,
408  initial_value_fct,
409  initial_veloc_fct,
410  initial_accel_fct);
411  }
412 } // end of set initial condition
413 
414 
415 
416 //============start_of_create_flux_elements==============================
417 /// Create LinearWave Flux Elements on the b-th boundary of the Mesh object
418 /// pointed to by bulk_mesh_pt and add the elements to the Mesh object
419 /// pointed to by surface_mesh_pt.
420 //=======================================================================
421 template<class ELEMENT,class TIMESTEPPER>
423 create_flux_elements(const unsigned &b, Mesh* const& bulk_mesh_pt,
424  Mesh* const &surface_mesh_pt)
425 {
426  // How many bulk elements are adjacent to boundary b?
427  unsigned n_element = bulk_mesh_pt->nboundary_element(b);
428 
429  // Loop over the bulk elements adjacent to boundary b?
430  for(unsigned e=0;e<n_element;e++)
431  {
432  // Get pointer to the bulk element that is adjacent to boundary b
433  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
434  bulk_mesh_pt->boundary_element_pt(b,e));
435 
436  //Find the index of the face of element e along boundary b
437  int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
438 
439  // Build the corresponding prescribed-flux element
440  LinearWaveFluxElement<ELEMENT>* flux_element_pt = new
441  LinearWaveFluxElement<ELEMENT>(bulk_elem_pt,face_index);
442 
443  //Add the prescribed-flux element to the surface mesh
444  surface_mesh_pt->add_element_pt(flux_element_pt);
445 
446  } //end of loop over bulk elements adjacent to boundary b
447 
448 } // end of create flux elements
449 
450 
451 
452 //===start_of_doc_solution================================================
453 /// Doc the solution
454 //========================================================================
455 template<class ELEMENT, class TIMESTEPPER>
457 {
458 
459  ofstream some_file;
460  char filename[100];
461 
462  // Number of plot points
463  unsigned npts;
464  npts=5;
465 
466  cout << std::endl;
467  cout << "=================================================" << std::endl;
468  cout << "Docing solution for t=" << time_pt()->time() << std::endl;
469  cout << "=================================================" << std::endl;
470 
471  // Output solution
472  //-----------------
473  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
474  doc_info.number());
475  some_file.open(filename);
476  Bulk_mesh_pt->output(some_file,npts);
477  some_file << "TEXT X=2.5,Y=93.6,F=HELV,HU=POINT,C=BLUE,H=26,T=\"time = "
478  << time_pt()->time() << "\"";
479  some_file << "GEOMETRY X=2.5,Y=98,T=LINE,C=BLUE,LT=0.4" << std::endl;
480  some_file << "1" << std::endl;
481  some_file << "2" << std::endl;
482  some_file << " 0 0" << std::endl;
483  some_file << time_pt()->time()*20.0 << " 0" << std::endl;
484  some_file.close();
485 
486  // Output exact solution
487  //----------------------
488  sprintf(filename,"%s/exact_soln%i.dat",doc_info.directory().c_str(),
489  doc_info.number());
490  some_file.open(filename);
491  Bulk_mesh_pt->output_fct(some_file,npts,time_pt()->time(),
493  some_file.close();
494 
495  // Doc error
496  //----------
497  double error,norm;
498  sprintf(filename,"%s/error%i.dat",doc_info.directory().c_str(),
499  doc_info.number());
500  some_file.open(filename);
501  Bulk_mesh_pt->compute_error(some_file,
503  time_pt()->time(),
504  error,norm);
505  some_file.close();
506 
507  cout << "error: " << error << std::endl;
508  cout << "norm : " << norm << std::endl << std::endl;
509  Trace_file << time_pt()->time() << " " << time_pt()->dt()
510  << " " << Bulk_mesh_pt->nelement() << " "
511  << error << " " << norm << std::endl;
512 
513 } // end of doc solution
514 
515 
516 
517 
518 //===start_of_unsteady_run================================================
519 /// Perform run up to specified time
520 //========================================================================
521 template<class ELEMENT, class TIMESTEPPER>
523 {
524 
525  // Setup labels for output
526  //-------------------------
527  DocInfo doc_info;
528 
529  // Output directory
530  doc_info.set_directory("RESLT");
531 
532  // Step number
533  doc_info.number()=0;
534 
535  // Open trace file
536  char filename[100];
537  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
538  Trace_file.open(filename);
539 
540 
541  // Maximum time
542  double t_max=4.0;
543 
544  // Size of timestep
545  double dt=0.005;
546 
547  // Initialise time
548  double time0=0.0;
549  time_pt()->time()=time0;
550 
551  // Set initial timestep
552  time_pt()->initialise_dt(dt);
553 
554  // Set IC
555  set_initial_condition();
556 
557  //Output solution
558  doc_solution(doc_info);
559 
560  //Increment counter for solutions
561  doc_info.number()++;
562 
563  // Number of steps
564  unsigned nstep=unsigned(t_max/dt);
565 
566  // If validation run only do 2 timesteps
567  if (CommandLineArgs::Argc>1)
568  {
569  nstep=2;
570  cout << "validation run" << std::endl;
571  }
572 
573  // Timestepping loop
574  for (unsigned istep=0;istep<nstep;istep++)
575  {
576  //Take fixed timestep without spatial adaptivity
577  unsteady_newton_solve(dt);
578 
579  //Output solution
580  doc_solution(doc_info);
581 
582  //Increment counter for solutions
583  doc_info.number()++;
584  }
585 
586  // Close trace file
587  Trace_file.close();
588 
589 } // end of unsteady run
590 
591 
592 
593 
594 /// /////////////////////////////////////////////////////////////////////
595 /// /////////////////////////////////////////////////////////////////////
596 /// /////////////////////////////////////////////////////////////////////
597 
598 
599 
600 //===start_of_main========================================================
601 /// Demonstrate how to solve LinearWave problem
602 //========================================================================
603 int main(int argc, char* argv[])
604 {
605 
606  // Store command line arguments
607  CommandLineArgs::setup(argc,argv);
608 
609  // Pointer to source function
610  LinearWaveEquations<2>::LinearWaveSourceFctPt source_fct_pt=
612 
613  // Number of elements in x direction
614  unsigned n_x=10;
615 
616  // Number of elements in y direction
617  unsigned n_y=20;
618 
619  // Build problem
621  problem(n_x,n_y,source_fct_pt);
622 
623  // Run it
624  problem.unsteady_run();
625 
626 
627 }; // end of main
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh.
void create_flux_elements(const unsigned &b, Mesh *const &bulk_mesh_pt, Mesh *const &surface_mesh_pt)
Create LinearWave flux elements on boundary b of the Mesh pointed to by bulk_mesh_pt and add them to ...
void actions_before_implicit_timestep()
Update the problem specs before next timestep: Set Dirchlet boundary conditions from exact solution.
LinearWaveProblem(const unsigned &nx, const unsigned &ny, const bool &impulsive_start, LinearWaveEquations< 2 >::LinearWaveSourceFctPt source_fct_pt)
Constructor: pass number of elements in x and y directions, bool indicating impulsive or "smooth" sta...
void actions_after_implicit_timestep()
Update the problem specs after solve (empty)
void actions_after_newton_solve()
Update the problem specs after solve (empty)
void actions_before_newton_solve()
Update the problem specs before solve (empty)
void doc_solution(DocInfo &doc_info)
Doc the solution.
void unsteady_run()
Do unsteady run.
RectangularQuadMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
~LinearWaveProblem()
Destructor (empty)
void set_initial_condition()
Set initial condition (incl history values) according to specified function.
Namespace for exact solution for LinearWave equation with sharp step.
void get_source(const double &time, const Vector< double > &x, double &source)
Source function to make it an exact solution.
double Alpha
Parameter for steepness of step.
double Phi
Orientation of step wave.
void prescribed_flux_on_fixed_y_boundary(const double &time, const Vector< double > &x, double &flux)
Prescribed flux on a fixed y max boundary.
double exact_d2udt2(const double &time, const Vector< double > &x)
2nd time-deriv of exact solution
void get_exact_u(const double &time, const Vector< double > &x, Vector< double > &u)
Exact solution as a vector.
double exact_dudt(const double &time, const Vector< double > &x)
1st time-deriv of exact solution
double exact_u(const double &time, const Vector< double > &x)
Exact solution.
void get_exact_gradient(const double &time, const Vector< double > &x, Vector< double > &dudx)
Gradient of exact solution.
int main(int argc, char *argv[])
///////////////////////////////////////////////////////////////////// ///////////////////////////////...