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