mesh_from_inline_triangle_no_adapt.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 #include <fenv.h>
27 
28 //Generic routines
29 #include "generic.h"
30 
31 // The equations
32 #include "poisson.h"
33 
34 // The mesh
35 #include "meshes/triangle_mesh.h"
36 
37 using namespace std;
38 using namespace oomph;
39 
40 
41 
42 //===== start_of_namespace=============================================
43 /// Namespace for exact solution for Poisson equation with "sharp step"
44 //=====================================================================
45 namespace TanhSolnForPoisson
46 {
47 
48  /// Parameter for steepness of "step"
49  double Alpha=5.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 get_source(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 
70  /// Zero function -- used to compute norm of the computed solution by
71  /// computing the norm of the error when compared against this.
72  void zero(const Vector<double>& x, Vector<double>& u)
73  {
74  u[0]=0.0;
75  }
76 
77 } // end of namespace
78 
79 
80 
81 /// ////////////////////////////////////////////////////////
82 /// ////////////////////////////////////////////////////////
83 /// ////////////////////////////////////////////////////////
84 
85 
86 //==start_of_problem_class============================================
87 /// Class definition
88 //====================================================================
89 template<class ELEMENT>
90 class UnstructuredPoissonProblem : public virtual Problem
91 {
92 
93 public:
94 
95  /// Constructor
97 
98  /// Destructor
100 
101  /// Update after solve (empty)
103 
104  /// Update the problem specs before solve: Re-apply boundary conditons
106  {
107  apply_boundary_conditions();
108  }
109 
110  /// Doc the solution
111  void doc_solution(const std::string& comment="");
112 
113 
114 private:
115 
116  /// Doc info object for labeling output
117  DocInfo Doc_info;
118 
119  /// Helper function to apply boundary conditions
121 
122  /// Helper function to (re-)set boundary condition
123  /// and complete the build of all elements
125 
126  /// Pointers to specific mesh
127  TriangleMesh<ELEMENT>* My_mesh_pt;
128 
129  /// Trace file to document norm of solution
130  ofstream Trace_file;
131 
132 }; // end_of_problem_class
133 
134 
135 
136 
137 
138 //==start_constructor=====================================================
139 /// Constructor
140 //========================================================================
141 template<class ELEMENT>
143 {
144  // Intrinsic coordinate along GeomObject
145  Vector<double> zeta(1);
146 
147  // Position vector on GeomObject
148  Vector<double> posn(2);
149 
150  // Ellipse defining the outer boundary
151  double x_center = 0.0;
152  double y_center = 0.0;
153  double A = 1.0;
154  double B = 1.0;
155  Ellipse * outer_boundary_ellipse_pt = new Ellipse(A,B);
156 
157  // Pointer to the closed curve that defines the outer boundary
158  TriangleMeshClosedCurve* closed_curve_pt=0;
159 
160  // Build outer boundary as Polygon?
161  //---------------------------------
162  bool polygon_for_outer_boundary=false;
163 #ifdef OUTER_POLYGON
164  polygon_for_outer_boundary=true;
165 #endif
166  if (polygon_for_outer_boundary)
167  {
168  // Number of segments that make up the boundary
169  unsigned n_seg = 5;
170  double unit_zeta = 0.5*MathematicalConstants::Pi/double(n_seg);
171 
172  // The boundary is bounded by two distinct boundaries, each
173  // represented by its own polyline
174  Vector<TriangleMeshCurveSection*> boundary_polyline_pt(2);
175 
176  // Vertex coordinates on boundary
177  Vector<Vector<double> > bound_coords(n_seg+1);
178 
179  // First part of the boundary
180  //---------------------------
181  for(unsigned ipoint=0; ipoint<n_seg+1;ipoint++)
182  {
183  // Resize the vector
184  bound_coords[ipoint].resize(2);
185 
186  // Get the coordinates
187  zeta[0]=unit_zeta*double(ipoint);
188  outer_boundary_ellipse_pt->position(zeta,posn);
189  bound_coords[ipoint][0]=posn[0]+x_center;
190  bound_coords[ipoint][1]=posn[1]+y_center;
191  }
192 
193  // Build the 1st boundary polyline
194  unsigned boundary_id=0;
195  boundary_polyline_pt[0]=new TriangleMeshPolyLine(bound_coords,boundary_id);
196 
197 
198 
199  // Second part of the boundary
200  //----------------------------
201  unit_zeta*=3.0;
202  for(unsigned ipoint=0; ipoint<n_seg+1;ipoint++)
203  {
204  // Resize the vector
205  bound_coords[ipoint].resize(2);
206 
207  // Get the coordinates
208  zeta[0]=(unit_zeta*double(ipoint))+0.5*MathematicalConstants::Pi;
209  outer_boundary_ellipse_pt->position(zeta,posn);
210  bound_coords[ipoint][0]=posn[0]+x_center;
211  bound_coords[ipoint][1]=posn[1]+y_center;
212  }
213 
214  // Build the 2nd hole polyline
215  boundary_id=1;
216  boundary_polyline_pt[1]=new TriangleMeshPolyLine(bound_coords,boundary_id);
217 
218 
219  // Create the triangle mesh polygon for outer boundary
220  //----------------------------------------------------
221  TriangleMeshPolygon* outer_boundary_polygon_pt =
222  new TriangleMeshPolygon(boundary_polyline_pt);
223 
224  // Enable redistribution of polylines
225  outer_boundary_polygon_pt->
226  enable_redistribution_of_segments_between_polylines();
227 
228  // Set the pointer
229  closed_curve_pt=outer_boundary_polygon_pt;
230 
231  }
232  // Build outer boundary as curvilinear
233  //------------------------------------
234  else
235  {
236 
237  // Provide storage for pointers to the two parts of the curvilinear boundary
238  Vector<TriangleMeshCurveSection*> outer_curvilinear_boundary_pt(2);
239 
240  // First bit
241  //----------
242  double zeta_start=0.0;
243  double zeta_end=MathematicalConstants::Pi;
244  unsigned nsegment=5;
245  unsigned boundary_id=0;
246  outer_curvilinear_boundary_pt[0]=new TriangleMeshCurviLine(
247  outer_boundary_ellipse_pt,zeta_start,zeta_end,nsegment,boundary_id);
248 
249  // Second bit
250  //-----------
251  zeta_start=MathematicalConstants::Pi;
252  zeta_end=2.0*MathematicalConstants::Pi;
253  nsegment=8;
254  boundary_id=1;
255  outer_curvilinear_boundary_pt[1]=new TriangleMeshCurviLine(
256  outer_boundary_ellipse_pt,zeta_start,zeta_end,nsegment,boundary_id);
257 
258  // Combine to curvilinear boundary
259  //--------------------------------
260  TriangleMeshClosedCurve* curvilinear_outer_boundary_pt=
261  new TriangleMeshClosedCurve(outer_curvilinear_boundary_pt);
262 
263  // Set the pointer
264  closed_curve_pt=curvilinear_outer_boundary_pt;
265  }
266 
267 
268  // Now build the holes
269  //====================
270  Vector<TriangleMeshClosedCurve*> hole_pt(2);
271 
272  // Build polygonal hole
273  //=====================
274 
275  // Build first hole: A circle
276  x_center = 0.0;
277  y_center = 0.5;
278  A = 0.1;
279  B = 0.1;
280  Ellipse* polygon_ellipse_pt=new Ellipse(A,B);
281 
282  // Number of segments defining upper and lower half of the hole
283  unsigned n_seg = 6;
284  double unit_zeta = MathematicalConstants::Pi/double(n_seg);
285 
286  // This hole is bounded by two distinct boundaries, each
287  // represented by its own polyline
288  Vector<TriangleMeshCurveSection*> hole_polyline_pt(2);
289 
290 
291  // First boundary of polygonal hole
292  //---------------------------------
293 
294  // Vertex coordinates
295  Vector<Vector<double> > bound_hole(n_seg+1);
296  for(unsigned ipoint=0; ipoint<n_seg+1;ipoint++)
297  {
298  // Resize the vector
299  bound_hole[ipoint].resize(2);
300 
301  // Get the coordinates
302  zeta[0]=unit_zeta*double(ipoint);
303  polygon_ellipse_pt->position(zeta,posn);
304  bound_hole[ipoint][0]=posn[0]+x_center;
305  bound_hole[ipoint][1]=posn[1]+y_center;
306  }
307 
308  // Specify the hole boundary id
309  unsigned boundary_id=2;
310 
311  // Build the 1st hole polyline
312  hole_polyline_pt[0] = new TriangleMeshPolyLine(bound_hole,boundary_id);
313 
314 
315  // Second boundary of polygonal hole
316  //----------------------------------
317  for(unsigned ipoint=0; ipoint<n_seg+1;ipoint++)
318  {
319  // Resize the vector
320  bound_hole[ipoint].resize(2);
321 
322  // Get the coordinates
323  zeta[0]=(unit_zeta*double(ipoint))+MathematicalConstants::Pi;
324  polygon_ellipse_pt->position(zeta,posn);
325  bound_hole[ipoint][0]=posn[0]+x_center;
326  bound_hole[ipoint][1]=posn[1]+y_center;
327  }
328 
329  // Specify the hole boundary id
330  boundary_id=3;
331 
332  // Build the 2nd hole polyline
333  hole_polyline_pt[1] = new TriangleMeshPolyLine(bound_hole,boundary_id);
334 
335 
336  // Build the polygonal hole
337  //-------------------------
338 
339  // Inner hole center coordinates
340  Vector<double> hole_center(2);
341  hole_center[0]=x_center;
342  hole_center[1]=y_center;
343 
344  hole_pt[0] = new TriangleMeshPolygon(hole_polyline_pt, hole_center);
345 
346 
347 
348 
349  // Build curvlinear hole
350  //======================
351 
352  // Build second hole: Another ellipse
353  A = 0.2;
354  B = 0.1;
355  Ellipse* ellipse_pt=new Ellipse(A,B);
356 
357  // Build the two parts of the curvilinear boundary
358  Vector<TriangleMeshCurveSection*> curvilinear_boundary_pt(2);
359 
360 
361  // First part of curvilinear boundary
362  //-----------------------------------
363  double zeta_start=0.0;
364  double zeta_end=MathematicalConstants::Pi;
365  unsigned nsegment=10;
366  boundary_id=4;
367  curvilinear_boundary_pt[0]=new TriangleMeshCurviLine(
368  ellipse_pt,zeta_start,zeta_end,
369  nsegment,boundary_id);
370 
371  // Second part of curvilinear boundary
372  //-------------------------------------
373  zeta_start=MathematicalConstants::Pi;
374  zeta_end=2.0*MathematicalConstants::Pi;
375  nsegment=15;
376  boundary_id=5;
377  curvilinear_boundary_pt[1]=new TriangleMeshCurviLine(
378  ellipse_pt,zeta_start,zeta_end,
379  nsegment,boundary_id);
380 
381 
382  // Combine to hole
383  //----------------
384  Vector<double> hole_coords(2);
385  hole_coords[0]=0.0;
386  hole_coords[1]=0.0;
387  Vector<TriangleMeshClosedCurve*> curvilinear_hole_pt(1);
388  hole_pt[1]=
389  new TriangleMeshClosedCurve(curvilinear_boundary_pt,
390  hole_coords);
391 
392 
393  // Now build the mesh
394  //===================
395 
396  // Use the TriangleMeshParameters object for helping on the manage of the
397  // TriangleMesh parameters
398  TriangleMeshParameters triangle_mesh_parameters(closed_curve_pt);
399 
400  // Specify the closed curve using the TriangleMeshParameters object
401  triangle_mesh_parameters.internal_closed_curve_pt() = hole_pt;
402 
403  // Specify the maximum area element
404  double uniform_element_area=0.2;
405  triangle_mesh_parameters.element_area() = uniform_element_area;
406 
407  // Create the mesh
408  My_mesh_pt=new
409  TriangleMesh<ELEMENT>(triangle_mesh_parameters);
410 
411  // Store as the problem's one and only mesh
412  Problem::mesh_pt()=My_mesh_pt;
413 
414  // Set boundary condition and complete the build of all elements
415  complete_problem_setup();
416 
417  // Open trace file
418  char filename[100];
419  sprintf(filename,"RESLT/trace.dat");
420  Trace_file.open(filename);
421 
422  // Setup equation numbering scheme
423  oomph_info <<"Number of equations: "
424  << this->assign_eqn_numbers() << std::endl;
425 
426 } // end_of_constructor
427 
428 
429 
430 
431 //==start_of_complete======================================================
432  /// Set boundary condition exactly, and complete the build of
433  /// all elements
434 //========================================================================
435 template<class ELEMENT>
437 {
438 
439  // Set the boundary conditions for problem: All nodes are
440  // free by default -- just pin the ones that have Dirichlet conditions
441  // here.
442  unsigned nbound=My_mesh_pt->nboundary();
443  for(unsigned ibound=0;ibound<nbound;ibound++)
444  {
445  unsigned num_nod=My_mesh_pt->nboundary_node(ibound);
446  for (unsigned inod=0;inod<num_nod;inod++)
447  {
448  // Get node
449  Node* nod_pt=My_mesh_pt->boundary_node_pt(ibound,inod);
450 
451  // Pin one-and-only unknown value
452  nod_pt->pin(0);
453  }
454  } // end loop over boundaries
455 
456 
457  // Complete the build of all elements so they are fully functional
458  unsigned n_element = My_mesh_pt->nelement();
459  for(unsigned e=0;e<n_element;e++)
460  {
461  // Upcast from GeneralisedElement to the present element
462  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(My_mesh_pt->element_pt(e));
463 
464  //Set the source function pointer
465  el_pt->source_fct_pt() = &TanhSolnForPoisson::get_source;
466  }
467 
468  // Re-apply Dirichlet boundary conditions (projection ignores
469  // boundary conditions!)
470  apply_boundary_conditions();
471 }
472 
473 
474 
475 
476 //==start_of_apply_bc=====================================================
477  /// Helper function to apply boundary conditions
478 //========================================================================
479 template<class ELEMENT>
481 {
482 
483  // Loop over all boundary nodes
484  unsigned nbound=this->My_mesh_pt->nboundary();
485  for(unsigned ibound=0;ibound<nbound;ibound++)
486  {
487  unsigned num_nod=this->My_mesh_pt->nboundary_node(ibound);
488  for (unsigned inod=0;inod<num_nod;inod++)
489  {
490  // Get node
491  Node* nod_pt=this->My_mesh_pt->boundary_node_pt(ibound,inod);
492 
493  // Extract nodal coordinates from node:
494  Vector<double> x(2);
495  x[0]=nod_pt->x(0);
496  x[1]=nod_pt->x(1);
497 
498  // Compute the value of the exact solution at the nodal point
499  Vector<double> u(1);
501 
502  // Assign the value to the one (and only) nodal value at this node
503  nod_pt->set_value(0,u[0]);
504  }
505  }
506 
507 } // end set bc
508 
509 
510 //==start_of_doc_solution=================================================
511 /// Doc the solution
512 //========================================================================
513 template<class ELEMENT>
515  std::string& comment)
516 {
517  ofstream some_file;
518  char filename[100];
519 
520  // Number of plot points
521  unsigned npts;
522  npts=5;
523 
524  sprintf(filename,"RESLT/soln%i.dat",Doc_info.number());
525  some_file.open(filename);
526  this->My_mesh_pt->output(some_file,npts);
527  some_file << "TEXT X = 22, Y = 92, CS=FRAME T = \""
528  << comment << "\"\n";
529  some_file.close();
530 
531  // Output exact solution
532  //----------------------
533  sprintf(filename,"RESLT/exact_soln%i.dat",Doc_info.number());
534  some_file.open(filename);
535  My_mesh_pt->output_fct(some_file,npts,TanhSolnForPoisson::get_exact_u);
536  some_file.close();
537 
538  // Output boundaries
539  //------------------
540  sprintf(filename,"RESLT/boundaries%i.dat",Doc_info.number());
541  some_file.open(filename);
542  My_mesh_pt->output_boundaries(some_file);
543  some_file.close();
544 
545 
546  // Doc error and return of the square of the L2 error
547  //---------------------------------------------------
548  double error,norm,dummy_error,zero_norm;
549  sprintf(filename,"RESLT/error%i.dat",Doc_info.number());
550  some_file.open(filename);
551  My_mesh_pt->compute_error(some_file,TanhSolnForPoisson::get_exact_u,
552  error,norm);
553 
554  My_mesh_pt->compute_error(some_file,TanhSolnForPoisson::zero,
555  dummy_error,zero_norm);
556  some_file.close();
557 
558  // Doc L2 error and norm of solution
559  oomph_info << "\nNorm of error : " << sqrt(error) << std::endl;
560  oomph_info << "Norm of exact solution: " << sqrt(norm) << std::endl;
561  oomph_info << "Norm of computed solution: " << sqrt(dummy_error) << std::endl;
562  Trace_file << sqrt(norm) << " " << sqrt(dummy_error) << std::endl;
563 
564  // Increment the doc_info number
565  Doc_info.number()++;
566 
567 } // end of doc
568 
569 
570 //=======start_of_main========================================
571 /// Driver code for demo of inline triangle mesh generation
572 //============================================================
573 int main(int argc, char **argv)
574 {
575  // Store command line arguments
576  CommandLineArgs::setup(argc,argv);
577 
578  // Define possible command line arguments and parse the ones that
579  // were actually specified
580 
581  // Validation?
582  CommandLineArgs::specify_command_line_flag("--validation");
583 
584  // Parse command line
585  CommandLineArgs::parse_and_assign();
586 
587  // Doc what has actually been specified on the command line
588  CommandLineArgs::doc_specified_flags();
589 
590  // Create problem
592 
593  // Loop over orientation of step
594  //==============================
595  unsigned nstep=5;
596  if (CommandLineArgs::command_line_flag_has_been_set("--validation"))
597  {
598  nstep=2;
599  }
600  for (unsigned i=0;i<nstep;i++)
601  {
602  // Solve
603  //=======
604  problem.newton_solve();
605 
606  // Doc the solution
607  //=================
608  std::stringstream comment_stream;
609  comment_stream << "Solution for tan(phi) = " << TanhSolnForPoisson::TanPhi;
610  problem.doc_solution(comment_stream.str());
611 
612  // Rotate orientation of solution
614  }
615 
616 } //End of main
//////////////////////////////////////////////////////// ////////////////////////////////////////////...
TriangleMesh< ELEMENT > * My_mesh_pt
Pointers to specific mesh.
UnstructuredPoissonProblem()
Constructor.
void actions_before_newton_solve()
Update the problem specs before solve: Re-apply boundary conditons.
void complete_problem_setup()
Helper function to (re-)set boundary condition and complete the build of all elements.
void actions_after_newton_solve()
Update after solve (empty)
void doc_solution(const std::string &comment="")
Doc the solution.
void apply_boundary_conditions()
Helper function to apply boundary conditions.
int main(int argc, char **argv)
Driver code for demo of inline triangle mesh generation.
Namespace for exact solution for Poisson equation with "sharp step".
void zero(const Vector< double > &x, Vector< double > &u)
Zero function – used to compute norm of the computed solution by computing the norm of the error when...
double TanPhi
Parameter for angle Phi of "step".
void get_source(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.