refineable_t_junction.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 //Driver for refineable Young Laplace problem
31 
32 //Generic routines
33 #include "generic.h"
34 
35 // The YoungLaplace equations
36 #include "young_laplace.h"
37 
38 // The mesh
39 #include "meshes/rectangular_quadmesh.h"
40 
41 // Namespaces
42 using namespace std;
43 using namespace oomph;
44 
45 
46 
47 //======start_of_namespace========================================
48 /// Namespace for "global" problem parameters
49 //================================================================
50 namespace GlobalParameters
51 {
52 
53  /// Cos of contact angle
54  double Cos_gamma=cos(MathematicalConstants::Pi/6.0);
55 
56  /// Height control value for displacement control
57  double Controlled_height = 0.0;
58 
59  /// Length of domain
60  double L_x = 1.0;
61 
62  /// Width of domain
63  double L_y = 5.0;
64 
65  // Spine basis
66  //------------
67 
68  /// \short Spine basis: The position vector to the basis of the spine
69  /// as a function of the two coordinates x_1 and x_2, and its
70  /// derivatives w.r.t. to these coordinates.
71  /// dspine_B[i][j] = d spine_B[j] / dx_i
72  /// Spines start in the (x_1,x_2) plane at (x_1,x_2).
73  void spine_base_function(const Vector<double>& x,
74  Vector<double>& spine_B,
75  Vector< Vector<double> >& dspine_B)
76  {
77 
78  // Bspines and derivatives
79  spine_B[0] = x[0];
80  spine_B[1] = x[1];
81  spine_B[2] = 0.0 ;
82  dspine_B[0][0] = 1.0 ;
83  dspine_B[1][0] = 0.0 ;
84  dspine_B[0][1] = 0.0 ;
85  dspine_B[1][1] = 1.0 ;
86  dspine_B[0][2] = 0.0 ;
87  dspine_B[1][2] = 0.0 ;
88 
89  } // End of bspine functions
90 
91 
92 
93  // Spines rotate in the y-direction
94  //---------------------------------
95 
96  /// Min. spine angle against horizontal plane
97  double Alpha_min = MathematicalConstants::Pi/2.0*1.5;
98 
99  /// Max. spine angle against horizontal plane
100  double Alpha_max = MathematicalConstants::Pi/2.0*0.5;
101 
102  /// \short Spine: The spine vector field as a function of the two
103  /// coordinates x_1 and x_2, and its derivatives w.r.t. to these coordinates:
104  /// dspine[i][j] = d spine[j] / dx_i
105  void spine_function(const Vector<double>& x,
106  Vector<double>& spine,
107  Vector< Vector<double> >& dspine)
108  {
109 
110  /// Spines (and derivatives) are independent of x[0] and rotate
111  /// in the x[1]-direction
112  spine[0]=0.0;
113  dspine[0][0]=0.0;
114  dspine[1][0]=0.0;
115 
116  spine[1]=cos(Alpha_min+(Alpha_max-Alpha_min)*x[1]/L_y);
117  dspine[0][1]=0.0;
118  dspine[1][1]=-sin(Alpha_min+(Alpha_max-Alpha_min)*x[1]/L_y)
119  *(Alpha_max-Alpha_min)/L_y;
120 
121  spine[2]=sin(Alpha_min+(Alpha_max-Alpha_min)*x[1]/L_y);
122  dspine[0][2]=0.0;
123  dspine[1][2]=cos(Alpha_min+(Alpha_max-Alpha_min)*x[1]/L_y)
124  *(Alpha_max-Alpha_min)/L_y;
125 
126  } // End spine function
127 
128 
129 } // end of namespace
130 
131 
132 
133 
134 
135 
136 //====== start_of_problem_class=======================================
137 /// 2D RefineableYoungLaplace problem on rectangular domain, discretised with
138 /// 2D QRefineableYoungLaplace elements. The specific type of element is
139 /// specified via the template parameter.
140 //====================================================================
141 template<class ELEMENT>
142 class RefineableYoungLaplaceProblem : public Problem
143 {
144 
145 public:
146 
147  /// Constructor:
149 
150  /// Destructor (empty)
152 
153  /// Update the problem specs before solve: Empty
155 
156  /// Update the problem after solve: Empty
158 
159  /// Actions before adapt: Wipe the mesh of contact angle elements
161  {
162  // Kill the contact angle elements and wipe contact angle mesh
163  if (Contact_angle_mesh_pt!=0) delete_contact_angle_elements();
164 
165  // Rebuild the Problem's global mesh from its various sub-meshes
166  rebuild_global_mesh();
167  }
168 
169 
170  /// Actions after adapt: Rebuild the mesh of contact angle elements
172  {
173  create_contact_angle_elements(1);
174  create_contact_angle_elements(3);
175 
176  // Set function pointers for contact-angle elements
177  unsigned nel=Contact_angle_mesh_pt->nelement();
178  for (unsigned e=0;e<nel;e++)
179  {
180  // Upcast from GeneralisedElement to YoungLaplace contact angle
181  // element
182  YoungLaplaceContactAngleElement<ELEMENT> *el_pt =
183  dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
184  Contact_angle_mesh_pt->element_pt(e));
185 
186  // Set the pointer to the prescribed contact angle
187  el_pt->prescribed_cos_gamma_pt() = &GlobalParameters::Cos_gamma;
188  }
189 
190  // Rebuild the Problem's global mesh from its various sub-meshes
191  rebuild_global_mesh();
192 
193  }
194 
195  /// \short Doc the solution. DocInfo object stores flags/labels for where the
196  /// output gets written to and the trace file
197  void doc_solution(DocInfo& doc_info, ofstream& trace_file);
198 
199 private:
200 
201  /// \short Create YoungLaplace contact angle elements on the
202  /// b-th boundary of the bulk mesh and add them to contact angle mesh
203  void create_contact_angle_elements(const unsigned& b);
204 
205  /// Delete contact angle elements
206  void delete_contact_angle_elements();
207 
208  /// Pointer to the "bulk" mesh
209  RefineableRectangularQuadMesh<ELEMENT>* Bulk_mesh_pt;
210 
211  /// Pointer to the contact angle mesh
213 
214  /// Pointer to mesh containing the height control element
216 
217  /// Node at which the height (displacement along spine) is controlled/doced
219 
220  /// Pointer to Data object that stores the prescribed curvature
221  Data* Kappa_pt;
222 
223 }; // end of problem class
224 
225 
226 //=====start_of_constructor===============================================
227 /// Constructor for RefineableYoungLaplace problem
228 //========================================================================
229 template<class ELEMENT>
231 {
232 
233  // Setup bulk mesh
234  //----------------
235 
236  // # of elements in x-direction
237  unsigned n_x=8;
238 
239  // # of elements in y-direction
240  unsigned n_y=8;
241 
242  // Domain length in x-direction
243  double l_x=GlobalParameters::L_x;
244 
245  // Domain length in y-direction
246  double l_y=GlobalParameters::L_y;
247 
248  // Build and assign mesh
249  Bulk_mesh_pt=new RefineableRectangularQuadMesh<ELEMENT>(n_x,n_y,l_x,l_y);
250 
251  // Create/set error estimator
252  Bulk_mesh_pt->spatial_error_estimator_pt()=new Z2ErrorEstimator;
253 
254  // Set targets for spatial adaptivity
255  Bulk_mesh_pt->max_permitted_error()=1.0e-4;
256  Bulk_mesh_pt->min_permitted_error()=1.0e-6;
257 
258  // Check that we've got an even number of elements otherwise
259  // out counting doesn't work...
260  if ((n_x%2!=0)||(n_y%2!=0))
261  {
262  cout << "n_x n_y should be even" << endl;
263  abort();
264  }
265 
266  // This is the element that contains the central node:
267  ELEMENT* prescribed_height_element_pt= dynamic_cast<ELEMENT*>(
268  Bulk_mesh_pt->element_pt(n_y*n_x/2+n_x/2));
269 
270  // The central node is node 0 in that element
271  Control_node_pt= static_cast<Node*>(prescribed_height_element_pt->node_pt(0));
272 
273  std::cout << "Controlling height at (x,y) : (" << Control_node_pt->x(0)
274  << "," << Control_node_pt->x(1) << ")" << "\n" << endl;
275 
276  // Create a height control element and store the
277  // pointer to the Kappa Data created by this object
278  HeightControlElement* height_control_element_pt=new HeightControlElement(
279  Control_node_pt,&GlobalParameters::Controlled_height);
280 
281  // Add to mesh
282  Height_control_mesh_pt = new Mesh;
283  Height_control_mesh_pt->add_element_pt(height_control_element_pt);
284 
285  // Store curvature data
286  Kappa_pt=height_control_element_pt->kappa_pt();
287 
288 
289  // Contact angle elements
290  //-----------------------
291 
292  // Create prescribed-contact-angle elements from all elements that are
293  // adjacent to boundary 1 and 3 and add them to their own mesh
294 
295  // set up new mesh
296  Contact_angle_mesh_pt=new Mesh;
297 
298  // creation of contact angle elements
299  create_contact_angle_elements(1);
300  create_contact_angle_elements(3);
301 
302 
303  // Add various meshes and build the global mesh
304  //----------------------------------------------
305  add_sub_mesh(Bulk_mesh_pt);
306  add_sub_mesh(Height_control_mesh_pt);
307  add_sub_mesh(Contact_angle_mesh_pt);
308  build_global_mesh();
309 
310 
311  // Boundary conditions
312  //--------------------
313 
314  // Set the boundary conditions for this problem: All nodes are
315  // free by default -- only need to pin the ones that have Dirichlet conditions
316  // here.
317  unsigned n_bound = Bulk_mesh_pt->nboundary();
318  for(unsigned b=0;b<n_bound;b++)
319  {
320  // Pin all boundaries for three cases and only boundaries
321  // 0 and 2 in all others:
322  if ((b==0)||(b==2))
323  {
324  unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
325  for (unsigned n=0;n<n_node;n++)
326  {
327  Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
328  }
329  }
330  } // end bcs
331 
332  // Complete build of elements
333  //---------------------------
334 
335  // Complete the build of all elements so they are fully functional
336  unsigned n_bulk=Bulk_mesh_pt->nelement();
337  for(unsigned i=0;i<n_bulk;i++)
338  {
339  // Upcast from GeneralsedElement to the present element
340  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(i));
341 
342  //Set the spine function pointers
343  el_pt->spine_base_fct_pt() = GlobalParameters::spine_base_function;
344  el_pt->spine_fct_pt() = GlobalParameters::spine_function;
345 
346  // Set the curvature data for the element
347  el_pt->set_kappa(Kappa_pt);
348  }
349 
350  // Set function pointers for contact-angle elements
351  unsigned nel=Contact_angle_mesh_pt->nelement();
352  for (unsigned e=0;e<nel;e++)
353  {
354  // Upcast from GeneralisedElement to YoungLaplace contact angle
355  // element
356  YoungLaplaceContactAngleElement<ELEMENT> *el_pt =
357  dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
358  Contact_angle_mesh_pt->element_pt(e));
359 
360  // Set the pointer to the prescribed contact angle
361  el_pt->prescribed_cos_gamma_pt() = &GlobalParameters::Cos_gamma;
362  }
363 
364 
365  // Setup equation numbering scheme
366  cout <<"\nNumber of equations: " << assign_eqn_numbers() << endl;
367  cout << "\n********************************************\n" << endl;
368 
369 } // end of constructor
370 
371 
372 //============start_of_create_contact_angle_elements=====================
373 /// Create YoungLaplace contact angle elements on the b-th boundary of the
374 /// bulk mesh and add them to the contact angle mesh
375 //=======================================================================
376 template<class ELEMENT>
378  const unsigned &b)
379 {
380  // How many bulk elements are adjacent to boundary b?
381  unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
382 
383  // Loop over the bulk elements adjacent to boundary b?
384  for(unsigned e=0;e<n_element;e++)
385  {
386  // Get pointer to the bulk element that is adjacent to boundary b
387  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
388  Bulk_mesh_pt->boundary_element_pt(b,e));
389 
390  // What is the index of the face of the bulk element at the boundary
391  int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
392 
393  // Build the corresponding contact angle element
394  YoungLaplaceContactAngleElement<ELEMENT>* contact_angle_element_pt = new
395  YoungLaplaceContactAngleElement<ELEMENT>(bulk_elem_pt,face_index);
396 
397  //Add the contact angle element to the contact angle mesh
398  Contact_angle_mesh_pt->add_element_pt(contact_angle_element_pt);
399 
400  } //end of loop over bulk elements adjacent to boundary b
401 
402 } // end of create_contact_angle_elements
403 
404 
405 //============start_of_delete_contact_angle_elements=====================
406 /// Delete YoungLaplace contact angle elements
407 //=======================================================================
408 template<class ELEMENT>
410 {
411 
412  // How many contact angle elements are there?
413  unsigned n_element = Contact_angle_mesh_pt->nelement();
414 
415  // Loop over the surface elements
416  for(unsigned e=0;e<n_element;e++)
417  {
418  // Kill surface element
419  delete Contact_angle_mesh_pt->element_pt(e);
420  }
421 
422  // Wipe the mesh
423  Contact_angle_mesh_pt->flush_element_and_node_storage();
424 
425 
426 } // end of delete_contact_angle_elements
427 
428 
429 
430 //===============start_of_doc=============================================
431 /// Doc the solution: doc_info contains labels/output directory etc.
432 //========================================================================
433 template<class ELEMENT>
435  ofstream& trace_file)
436 {
437 
438  // Output kappa vs height
439  //-----------------------
440  trace_file << -1.0*Kappa_pt->value(0) << " ";
441  trace_file << Control_node_pt->value(0) ;
442  trace_file << endl;
443 
444  // Number of plot points: npts x npts
445  unsigned npts=5;
446 
447  // Output full solution
448  //---------------------
449  ofstream some_file;
450  char filename[100];
451  //YoungLaplaceEquations::Output_meniscus_and_spines=false;
452  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
453  doc_info.number());
454  some_file.open(filename);
455  Bulk_mesh_pt->output(some_file,npts);
456  some_file.close();
457 
458  // Output contact angle
459  //---------------------
460 
461  ofstream tangent_file;
462  sprintf(filename,"%s/tangent_to_contact_line%i.dat",
463  doc_info.directory().c_str(),
464  doc_info.number());
465  tangent_file.open(filename);
466 
467  ofstream normal_file;
468  sprintf(filename,"%s/normal_to_contact_line%i.dat",
469  doc_info.directory().c_str(),
470  doc_info.number());
471  normal_file.open(filename);
472 
473 
474  ofstream contact_angle_file;
475  sprintf(filename,"%s/contact_angle%i.dat",
476  doc_info.directory().c_str(),
477  doc_info.number());
478  contact_angle_file.open(filename);
479 
480  // Tangent and normal vectors to contact line
481  Vector<double> tangent(3);
482  Vector<double> normal(3);
483  Vector<double> r_contact(3);
484 
485  // How many contact angle elements are there?
486  unsigned n_element = Contact_angle_mesh_pt->nelement();
487 
488  // Loop over the surface elements
489  for(unsigned e=0;e<n_element;e++)
490  {
491 
492  tangent_file << "ZONE" << std::endl;
493  normal_file << "ZONE" << std::endl;
494  contact_angle_file << "ZONE" << std::endl;
495 
496  // Upcast from GeneralisedElement to YoungLaplace contact angle element
497  YoungLaplaceContactAngleElement<ELEMENT>* el_pt =
498  dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
499  Contact_angle_mesh_pt->element_pt(e));
500 
501  // Loop over a few points in the contact angle element
502  Vector<double> s(1);
503  for (unsigned i=0;i<npts;i++)
504  {
505  s[0]=-1.0+2.0*double(i)/double(npts-1);
506 
507  dynamic_cast<ELEMENT*>(el_pt->bulk_element_pt())->
508  position(el_pt->local_coordinate_in_bulk(s),r_contact);
509 
510  el_pt->contact_line_vectors(s,tangent,normal);
511  tangent_file << r_contact[0] << " "
512  << r_contact[1] << " "
513  << r_contact[2] << " "
514  << tangent[0] << " "
515  << tangent[1] << " "
516  << tangent[2] << " " << std::endl;
517 
518  normal_file << r_contact[0] << " "
519  << r_contact[1] << " "
520  << r_contact[2] << " "
521  << normal[0] << " "
522  << normal[1] << " "
523  << normal[2] << " " << std::endl;
524 
525  contact_angle_file << r_contact[1] << " "
526  << el_pt->actual_cos_contact_angle(s)
527  << std::endl;
528  }
529 
530 
531  } // end of loop over both boundaries
532 
533  tangent_file.close();
534  normal_file.close();
535  contact_angle_file.close();
536 
537 
538 cout << "\n********************************************" << endl << endl;
539 
540 } // end of doc
541 
542 
543 
544 //===============start_of_main============================================
545 /// Drive code
546 //========================================================================
547 int main()
548 {
549 
550  // Create label for output
551  DocInfo doc_info;
552 
553  // Trace file
554  ofstream trace_file;
555 
556  // Set output directory
557  doc_info.set_directory("RESLT");
558 
559  // Open a trace file
560  char filename[100];
561  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
562  trace_file.open(filename);
563 
564  // Tecplot header for trace file: kappa and height value
565  trace_file << "VARIABLES=\"<GREEK>k</GREEK>\",\"h\"" << std::endl;
566  trace_file << "ZONE" << std::endl;
567 
568 
569  //Set up the problem
570  //------------------
571 
572  // Create the problem with 2D nine-node elements from the
573  // RefineableQYoungLaplaceElement family.
575 
576  // Perform one uniform refinement
577  problem.refine_uniformly();
578 
579  //Output the solution
580  problem.doc_solution(doc_info,trace_file);
581 
582  //Increment counter for solutions
583  doc_info.number()++;
584 
585  // Parameter incrementation
586  //-------------------------
587  double increment=0.1;
588 
589  // Loop over steps
590  unsigned nstep=2; // 10;
591  for (unsigned istep=0;istep<nstep;istep++)
592  {
594 
595  // Solve the problem
596  unsigned max_adapt=1;
597  problem.newton_solve(max_adapt);
598 
599  //Output the solution
600  problem.doc_solution(doc_info,trace_file);
601 
602  //Increment counter for solutions
603  doc_info.number()++;
604  }
605 
606  // Close output file
607  trace_file.close();
608 
609 } //end of main
610 
611 
double L_x
Length and width of the domain.
double Controlled_height
Height control value.
Definition: barrel.cc:55
double Alpha_min
Min. spine angle against horizontal plane.
Definition: barrel.cc:100
void actions_before_newton_solve()
Update the problem specs before solve: Empty.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of contact angle elements.
void doc_solution(DocInfo &doc_info, ofstream &trace_file)
Doc the solution. DocInfo object stores flags/labels for where the output gets written to and the tra...
~RefineableYoungLaplaceProblem()
Destructor (empty)
void spine_function(const Vector< double > &x, Vector< double > &spine, Vector< Vector< double > > &dspine)
Spine: The spine vector field as a function of the two coordinates x_1 and x_2, and its derivatives w...
Definition: barrel.cc:108
Namespace for "global" problem parameters.
Definition: barrel.cc:48
Mesh * Contact_angle_mesh_pt
Pointer to the contact angle mesh.
Data * Kappa_pt
Pointer to Data object that stores the prescribed curvature.
int main()
Drive code.
void spine_base_function(const Vector< double > &x, Vector< double > &spine_B, Vector< Vector< double > > &dspine_B)
Spine basis: The position vector to the basis of the spine as a function of the two coordinates x_1 a...
Definition: barrel.cc:76
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of contact angle elements.
Node * Control_node_pt
Node at which the height (displacement along spine) is controlled/doced.
double Cos_gamma
Cos of contact angle.
double Alpha_max
Max. spine angle against horizontal plane.
Definition: barrel.cc:103
double L_y
Width of domain.
Mesh * Height_control_mesh_pt
Pointer to mesh containing the height control element.
void create_contact_angle_elements(const unsigned &b)
Create YoungLaplace contact angle elements on the b-th boundary of the bulk mesh and add them to cont...
Data * Kappa_pt
Pointer to Data object that stores the prescribed curvature.
RefineableRectangularQuadMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
void actions_after_newton_solve()
Update the problem after solve: Empty.
void delete_contact_angle_elements()
Delete contact angle elements.