two_d_poisson_flux_bc2.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 a simple 2D Poisson problem with flux boundary conditions
27 //uses two separate meshes for bulk and surface mesh
28 
29 //Generic routines
30 #include "generic.h"
31 
32 // The Poisson equations
33 #include "poisson.h"
34 
35 // The mesh
36 #include "meshes/simple_rectangular_quadmesh.h"
37 
38 using namespace std;
39 
40 using namespace oomph;
41 
42 //===== start_of_namespace=============================================
43 /// Namespace for exact solution for Poisson equation with "sharp step"
44 //=====================================================================
46 {
47 
48  /// Parameter for steepness of "step"
49  double Alpha=1.0;
50 
51  /// Parameter for angle Phi of "step"
52  double TanPhi=0.0;
53 
54  /// Exact solution as a Vector
55  void get_exact_u(const Vector<double>& x, Vector<double>& u)
56  {
57  u[0]=tanh(1.0-Alpha*(TanPhi*x[0]-x[1]));
58  }
59 
60  /// Source function required to make the solution above an exact solution
61  void source_function(const Vector<double>& x, double& source)
62  {
63  source = 2.0*tanh(-1.0+Alpha*(TanPhi*x[0]-x[1]))*
64  (1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*
65  Alpha*Alpha*TanPhi*TanPhi+2.0*tanh(-1.0+Alpha*(TanPhi*x[0]-x[1]))*
66  (1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*Alpha*Alpha;
67  }
68 
69  /// Flux required by the exact solution on a boundary on which x is fixed
70  void prescribed_flux_on_fixed_x_boundary(const Vector<double>& x,
71  double& flux)
72  {
73  //The outer unit normal to the boundary is (1,0)
74  double N[2] = {1.0, 0.0};
75  //The flux in terms of the normal is
76  flux =
77  -(1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*Alpha*TanPhi*N[0]+(
78  1.0-pow(tanh(-1.0+Alpha*(TanPhi*x[0]-x[1])),2.0))*Alpha*N[1];
79  }
80 
81 } // end of namespace
82 
83 //========= start_of_problem_class=====================================
84 /// 2D Poisson problem on rectangular domain, discretised with
85 /// 2D QPoisson elements. Flux boundary conditions are applied
86 /// along boundary 1 (the boundary where x=L). The specific type of
87 /// element is specified via the template parameter.
88 //====================================================================
89 template<class ELEMENT>
90 class TwoMeshFluxPoissonProblem : public Problem
91 {
92 
93 public:
94 
95  /// Constructor: Pass pointer to source function
96  TwoMeshFluxPoissonProblem(PoissonEquations<2>::PoissonSourceFctPt source_fct_pt);
97 
98  /// Destructor (empty)
100 
101  /// Doc the solution. DocInfo object stores flags/labels for where the
102  /// output gets written to
103  void doc_solution(DocInfo& doc_info);
104 
105 
106 private:
107 
108  /// Update the problem specs before solve: Reset boundary conditions
109  /// to the values from the exact solution.
110  void actions_before_newton_solve();
111 
112  /// Update the problem specs after solve (empty)
114 
115  /// Create Poisson flux elements on boundary b of the Mesh pointed
116  /// to by bulk_mesh_pt and add them to the Mesh object pointed to by
117  /// surface_mesh_pt
118  void create_flux_elements(const unsigned &b, Mesh* const &bulk_mesh_pt,
119  Mesh* const &surface_mesh_pt);
120 
121  /// Pointer to the "bulk" mesh
122  SimpleRectangularQuadMesh<ELEMENT>* Bulk_mesh_pt;
123 
124  /// Pointer to the "surface" mesh
126 
127  /// Pointer to source function
128  PoissonEquations<2>::PoissonSourceFctPt Source_fct_pt;
129 
130 }; // end of problem class
131 
132 
133 
134 
135 //=======start_of_constructor=============================================
136 /// Constructor for Poisson problem: Pass pointer to source function.
137 //========================================================================
138 template<class ELEMENT>
140 TwoMeshFluxPoissonProblem(PoissonEquations<2>::PoissonSourceFctPt source_fct_pt)
141  : Source_fct_pt(source_fct_pt)
142 {
143  // Setup "bulk" mesh
144 
145  // # of elements in x-direction
146  unsigned n_x=4;
147 
148  // # of elements in y-direction
149  unsigned n_y=4;
150 
151  // Domain length in x-direction
152  double l_x=1.0;
153 
154  // Domain length in y-direction
155  double l_y=2.0;
156 
157  // Build "bulk" mesh
158  Bulk_mesh_pt=new SimpleRectangularQuadMesh<ELEMENT>(n_x,n_y,l_x,l_y);
159 
160 
161  // Create "surface mesh" that will contain only the prescribed-flux
162  // elements. The constructor just creates the mesh without
163  // giving it any elements, nodes, etc.
164  Surface_mesh_pt = new Mesh;
165 
166  // Create prescribed-flux elements from all elements that are
167  // adjacent to boundary 1, but add them to a separate mesh.
168  // Note that this is exactly the same function as used in the
169  // single mesh version of the problem, we merely pass different Mesh pointers.
171 
172  // Add the two sub meshes to the problem
173  add_sub_mesh(Bulk_mesh_pt);
174  add_sub_mesh(Surface_mesh_pt);
175 
176  // Combine all submeshes into a single Mesh
177  build_global_mesh();
178 
179 
180  // Set the boundary conditions for this problem: All nodes are
181  // free by default -- just pin the ones that have Dirichlet conditions
182  // here.
183  unsigned n_bound = Bulk_mesh_pt->nboundary();
184  for(unsigned b=0;b<n_bound;b++)
185  {
186  //Leave nodes on boundary 1 free
187  if (b!=1)
188  {
189  unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
190  for (unsigned n=0;n<n_node;n++)
191  {
192  Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
193  }
194  }
195  }
196 
197  // Complete the build of all elements so they are fully functional
198 
199  // Loop over the Poisson bulk elements to set up element-specific
200  // things that cannot be handled by constructor: Pass pointer to
201  // source function
202  unsigned n_element = Bulk_mesh_pt->nelement();
203  for(unsigned e=0;e<n_element;e++)
204  {
205  // Upcast from GeneralisedElement to Poisson bulk element
206  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
207 
208  //Set the source function pointer
209  el_pt->source_fct_pt() = Source_fct_pt;
210  }
211 
212  // Loop over the flux elements to pass pointer to prescribed flux function
213  n_element=Surface_mesh_pt->nelement();
214  for(unsigned e=0;e<n_element;e++)
215  {
216  // Upcast from GeneralisedElement to Poisson flux element
217  PoissonFluxElement<ELEMENT> *el_pt =
218  dynamic_cast< PoissonFluxElement<ELEMENT>*>(
219  Surface_mesh_pt->element_pt(e));
220 
221  // Set the pointer to the prescribed flux function
222  el_pt->flux_fct_pt() =
224  }
225 
226  // Setup equation numbering scheme
227  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
228 
229 } // end of constructor
230 
231 
232 
233 
234 //====================start_of_actions_before_newton_solve=======================
235 /// Update the problem specs before solve: Reset boundary conditions
236 /// to the values from the exact solution.
237 //========================================================================
238 template<class ELEMENT>
240 {
241  // How many boundaries are in the bulk mesh?
242  unsigned n_bound = Bulk_mesh_pt->nboundary();
243 
244  //Loop over the boundaries in the bulk mesh
245  for(unsigned i=0;i<n_bound;i++)
246  {
247  // Only update Dirichlet nodes
248  if (i!=1)
249  {
250  // How many nodes are there on this boundary?
251  unsigned n_node = Bulk_mesh_pt->nboundary_node(i);
252 
253  // Loop over the nodes on boundary
254  for (unsigned n=0;n<n_node;n++)
255  {
256  // Get pointer to node
257  Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(i,n);
258 
259  // Extract nodal coordinates from node:
260  Vector<double> x(2);
261  x[0]=nod_pt->x(0);
262  x[1]=nod_pt->x(1);
263 
264  // Compute the value of the exact solution at the nodal point
265  Vector<double> u(1);
267 
268  // Assign the value to the one (and only) nodal value at this node
269  nod_pt->set_value(0,u[0]);
270  }
271  }
272  }
273 } // end of actions before solve
274 
275 
276 
277 //=====================start_of_doc=======================================
278 /// Doc the solution: doc_info contains labels/output directory etc.
279 //========================================================================
280 template<class ELEMENT>
282 {
283 
284  ofstream some_file;
285  char filename[100];
286 
287  // Number of plot points
288  unsigned npts;
289  npts=5;
290 
291  // Output solution
292  //-----------------
293  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
294  doc_info.number());
295  some_file.open(filename);
296  Bulk_mesh_pt->output(some_file,npts);
297  some_file.close();
298 
299  // Output exact solution
300  //----------------------
301  sprintf(filename,"%s/exact_soln%i.dat",doc_info.directory().c_str(),
302  doc_info.number());
303  some_file.open(filename);
304  Bulk_mesh_pt->output_fct(some_file,npts,TanhSolnForPoisson::get_exact_u);
305  some_file.close();
306 
307 
308  // Doc error and return of the square of the L2 error
309  //---------------------------------------------------
310  double error,norm;
311  sprintf(filename,"%s/error%i.dat",doc_info.directory().c_str(),
312  doc_info.number());
313  some_file.open(filename);
314  Bulk_mesh_pt->compute_error(some_file,TanhSolnForPoisson::get_exact_u,
315  error,norm);
316  some_file.close();
317 
318  // Doc L2 error and norm of solution
319  cout << "\nNorm of error : " << sqrt(error) << std::endl;
320  cout << "Norm of solution: " << sqrt(norm) << std::endl << std::endl;
321 
322 
323 } // end of doc
324 
325 
326 //============start_of_create_flux_elements==============================
327 /// Create Poisson Flux Elements on the b-th boundary of the Mesh object
328 /// pointed to by bulk_mesh_pt and add the elements to the Mesh object
329 /// pointeed to by surface_mesh_pt.
330 //=======================================================================
331 template<class ELEMENT>
333 create_flux_elements(const unsigned &b, Mesh* const &bulk_mesh_pt,
334  Mesh* const &surface_mesh_pt)
335 {
336  // How many bulk elements are adjacent to boundary b?
337  unsigned n_element = bulk_mesh_pt->nboundary_element(b);
338 
339  // Loop over the bulk elements adjacent to boundary b?
340  for(unsigned e=0;e<n_element;e++)
341  {
342  // Get pointer to the bulk element that is adjacent to boundary b
343  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
344  bulk_mesh_pt->boundary_element_pt(b,e));
345 
346  //What is the index of the face of the bulk element e on bondary b
347  int face_index = bulk_mesh_pt->face_index_at_boundary(b,e);
348 
349  // Build the corresponding prescribed-flux element
350  PoissonFluxElement<ELEMENT>* flux_element_pt = new
351  PoissonFluxElement<ELEMENT>(bulk_elem_pt,face_index);
352 
353  //Add the prescribed-flux element to the surface mesh
354  surface_mesh_pt->add_element_pt(flux_element_pt);
355 
356  } //end of loop over bulk elements adjacent to boundary b
357 
358 } // end of create_flux_elements
359 
360 
361 //==========start_of_main=================================================
362 /// Demonstrate how to solve 2D Poisson problem with flux boundary
363 /// conditions, using two meshes.
364 //========================================================================
365 int main()
366 {
367 
368  //Set up the problem
369  //------------------
370 
371  //Set up the problem with 2D nine-node elements from the
372  //QPoissonElement family. Pass pointer to source function.
375 
376 
377  // Create label for output
378  //------------------------
379  DocInfo doc_info;
380 
381  // Set output directory
382  doc_info.set_directory("RESLT");
383 
384  // Step number
385  doc_info.number()=0;
386 
387 
388 
389  // Check if we're ready to go:
390  //----------------------------
391  cout << "\n\n\nProblem self-test ";
392  if (problem.self_test()==0)
393  {
394  cout << "passed: Problem can be solved." << std::endl;
395  }
396  else
397  {
398  throw OomphLibError("Self test failed",
399  OOMPH_CURRENT_FUNCTION,
400  OOMPH_EXCEPTION_LOCATION);
401  }
402 
403 
404  // Set the orientation of the "step" to 45 degrees
406 
407  // Initial value for the steepness of the "step"
409 
410  // Do a couple of solutions for different forcing functions
411  //---------------------------------------------------------
412  unsigned nstep=4;
413  for (unsigned istep=0;istep<nstep;istep++)
414  {
415  // Increase the steepness of the step:
417 
418  cout << "\n\nSolving for TanhSolnForPoisson::Alpha="
419  << TanhSolnForPoisson::Alpha << std::endl << std::endl;
420 
421  // Solve the problem
422  problem.newton_solve();
423 
424  //Output solution
425  problem.doc_solution(doc_info);
426 
427  //Increment counter for solutions
428  doc_info.number()++;
429  }
430 
431 } //end of main
432 
433 
434 
435 
436 
437 
438 
439 
440 
2D Poisson problem on rectangular domain, discretised with 2D QPoisson elements. Flux boundary condit...
~TwoMeshFluxPoissonProblem()
Destructor (empty)
void actions_before_newton_solve()
Update the problem specs before solve: Reset boundary conditions to the values from the exact solutio...
PoissonEquations< 2 >::PoissonSourceFctPt Source_fct_pt
Pointer to source function.
void doc_solution(DocInfo &doc_info)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to.
void create_flux_elements(const unsigned &b, Mesh *const &bulk_mesh_pt, Mesh *const &surface_mesh_pt)
Create Poisson flux elements on boundary b of the Mesh pointed to by bulk_mesh_pt and add them to the...
Mesh * Surface_mesh_pt
Pointer to the "surface" mesh.
void actions_after_newton_solve()
Update the problem specs after solve (empty)
SimpleRectangularQuadMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
TwoMeshFluxPoissonProblem(PoissonEquations< 2 >::PoissonSourceFctPt source_fct_pt)
Constructor: Pass pointer to source function.
Namespace for exact solution for Poisson equation with "sharp step".
void prescribed_flux_on_fixed_x_boundary(const Vector< double > &x, double &flux)
Flux required by the exact solution on a boundary on which x is fixed.
double TanPhi
Parameter for angle Phi of "step".
void source_function(const Vector< double > &x, double &source)
Source function required to make the solution above an exact solution.
double Alpha
Parameter for steepness of "step".
void get_exact_u(const Vector< double > &x, Vector< double > &u)
Exact solution as a Vector.
int main()
Demonstrate how to solve 2D Poisson problem with flux boundary conditions, using two meshes.