young_laplace.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 code for a 2D YoungLaplace 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/simple_rectangular_quadmesh.h"
40 
41 
42 using namespace std;
43 using namespace oomph;
44 
45 
46 // Namespace (shared with refineable version)
48 
49 
50 
51 //====== start_of_problem_class=======================================
52 /// 2D YoungLaplace problem on rectangular domain, discretised with
53 /// 2D QYoungLaplace elements. The specific type of element is
54 /// specified via the template parameter.
55 //====================================================================
56 template<class ELEMENT>
57 class YoungLaplaceProblem : public Problem
58 {
59 
60 public:
61 
62  /// Constructor:
64 
65  /// Destructor (empty)
67 
68  /// \short Update the problem specs before solve
69  void actions_before_newton_solve();
70 
71  /// Update the problem after solve: Empty
73 
74  /// \short Doc the solution. DocInfo object stores flags/labels for where the
75  /// output gets written to and the trace file
76  void doc_solution(DocInfo& doc_info, ofstream& trace_file);
77 
78 private:
79 
80  /// \short Create YoungLaplace contact angle elements on the
81  /// b-th boundary of the problem's mesh and add them to mesh
82  void create_contact_angle_elements(const unsigned& b);
83 
84  /// \short Number of YoungLaplace "bulk" elements (We're attaching the
85  /// contact angle elements to the bulk mesh --> only the first
86  /// N_bulk_elements elements in the mesh are bulk elements!)
87  unsigned N_bulk_elements;
88 
89  /// Number of last FaceElement on boundary 1
91 
92  /// Number of last FaceElement on boundary 3
94 
95  /// Node at which the height (displacement along spine) is controlled/doced
96  Node* Control_node_pt;
97 
98 }; // end of problem class
99 
100 
101 //=====start_of_constructor===============================================
102 /// Constructor for YoungLaplace problem
103 //========================================================================
104 template<class ELEMENT>
106 {
107 
108  // Setup dependent parameters in namespace
110 
111  // Setup mesh
112  //-----------
113 
114  // # of elements in x-direction
115  unsigned n_x=GlobalParameters::N_x;
116 
117  // # of elements in y-direction
118  unsigned n_y=GlobalParameters::N_y;
119 
120  // Domain length in x-direction
121  double l_x=GlobalParameters::L_x;
122 
123  // Domain length in y-direction
124  double l_y=GlobalParameters::L_y;
125 
126  // Print Size of the mesh
127  cout << "Lx = " << l_x << " and Ly = " << l_y << endl;
128 
129  // Build and assign mesh
130  Problem::mesh_pt()=new SimpleRectangularQuadMesh<ELEMENT>(n_x,n_y,l_x,l_y);
131 
132 
133  // Choose the prescribed height element
134  ELEMENT* prescribed_height_element_pt= dynamic_cast<ELEMENT*>(
135  mesh_pt()->element_pt(GlobalParameters::Control_element));
136 
137  // ...and the associated control node (node 0 in that element)
138  // (we're storing this node even if there's no height-control, for
139  // output purposes...)
140  Control_node_pt= static_cast<Node*>(
141  prescribed_height_element_pt->node_pt(0));
142 
143  // If needed, create a height control element and store the
144  // pointer to the Kappa Data created by this object
145  HeightControlElement* height_control_element_pt=0;
147  {
148  cout << "Controlling height at (x,y) : (" << Control_node_pt->x(0)
149  << "," << Control_node_pt->x(1) << ")" << "\n" << endl;
150 
151  height_control_element_pt=new HeightControlElement(
152  Control_node_pt,&GlobalParameters::Controlled_height);
153 
154  GlobalParameters::Kappa_pt=height_control_element_pt->kappa_pt();
155 
156  // Assign initial value for kappa value
157  height_control_element_pt->kappa_pt()
158  ->set_value(0,GlobalParameters::Kappa_initial);
159  }
160  //...otherwise create a kappa data item from scratch and pin its
161  // single unknown value
162  else
163  {
164  GlobalParameters::Kappa_pt=new Data(1);
167  }
168 
169  // Number of elements in the bulk mesh
170  N_bulk_elements = mesh_pt()->nelement();
171 
172  // Create contact angle elements from all elements that are
173  // adjacent to boundary 1 and 3 and add them to the (single) global mesh
176  {
177  create_contact_angle_elements(1);
178  Last_element_on_boundary1=mesh_pt()->nelement();
179 
180  create_contact_angle_elements(3);
181  Last_element_on_boundary3=mesh_pt()->nelement();
182  }
183  else
184  {
185  Last_element_on_boundary1=0;
186  Last_element_on_boundary3=0;
187  }
188 
189  // Boundary conditions
190  //--------------------
191 
192  // Set the boundary conditions for this problem: All nodes are
193  // free by default -- only need to pin the ones that have Dirichlet conditions
194  // here.
195  unsigned n_bound = mesh_pt()->nboundary();
196  for(unsigned b=0;b<n_bound;b++)
197  {
198  // Pin all boundaries for two cases and only boundaries
199  // 0 and 2 in all others:
201  (b==0)||
202  (b==2))
203  {
204  unsigned n_node = mesh_pt()->nboundary_node(b);
205  for (unsigned n=0;n<n_node;n++)
206  {
207  mesh_pt()->boundary_node_pt(b,n)->pin(0);
208  }
209  }
210  }
211 
212  // Complete build of elements
213  //---------------------------
214 
215  // Complete the build of all elements so they are fully functional
216  for(unsigned i=0;i<N_bulk_elements;i++)
217  {
218  // Upcast from GeneralsedElement to the present element
219  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(i));
220 
222  {
223  //Set the spine function pointers
224  el_pt->spine_base_fct_pt() = GlobalParameters::spine_base_function;
225  el_pt->spine_fct_pt() = GlobalParameters::spine_function;
226  }
227 
228  // Set the curvature data for the element
229  el_pt->set_kappa(GlobalParameters::Kappa_pt);
230 
231  }
232 
233  // Set function pointers for contact-angle elements
236  {
237  // Loop over the contact-angle elements (located at the "end" of the
238  // mesh) to pass function pointer to contact angle function.
239  for (unsigned e=N_bulk_elements;e<Last_element_on_boundary1;e++)
240  {
241  // Upcast from GeneralisedElement to YoungLaplace contact angle element
242  YoungLaplaceContactAngleElement<ELEMENT>* el_pt =
243  dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
244  mesh_pt()->element_pt(e));
245 
246  // Set the pointer to the prescribed contact angle
247  el_pt->prescribed_cos_gamma_pt() = &GlobalParameters::Cos_gamma;
248  }
249  for (unsigned e=Last_element_on_boundary1;e<Last_element_on_boundary3;e++)
250  {
251  // Upcast from GeneralisedElement to YoungLaplace contact angle element
252  YoungLaplaceContactAngleElement<ELEMENT> *el_pt =
253  dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
254  mesh_pt()->element_pt(e));
255 
256  // Set the pointer to the prescribed contact angle
257  el_pt->prescribed_cos_gamma_pt() = &GlobalParameters::Cos_gamma;
258  }
259  }
260 
261  // Height Element setup
262  //---------------------
263 
264  /// Add height control element to mesh at the very end
266  {
267  mesh_pt()->add_element_pt(height_control_element_pt);
268  }
269 
270 
271  // Setup equation numbering scheme
272  cout <<"\nNumber of equations: " << assign_eqn_numbers() << endl;
273  cout << "\n********************************************\n" << endl;
274 
275 } // end of constructor
276 
277 
278 
279 //============start_of_create_contact_angle_elements=====================
280 /// Create YoungLaplace contact angle elements on the b-th boundary of the Mesh
281 //=======================================================================
282 template<class ELEMENT>
284  const unsigned &b)
285 {
286  // How many bulk elements are adjacent to boundary b?
287  unsigned n_element = mesh_pt()->nboundary_element(b);
288 
289  // Loop over the bulk elements adjacent to boundary b?
290  for(unsigned e=0;e<n_element;e++)
291  {
292  // Get pointer to the bulk element that is adjacent to boundary b
293  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
294  mesh_pt()->boundary_element_pt(b,e));
295 
296  // What is the index of the face of the bulk element at the boundary
297  int face_index = mesh_pt()->face_index_at_boundary(b,e);
298 
299  // Build the corresponding prescribed contact angle element
300  YoungLaplaceContactAngleElement<ELEMENT>* contact_angle_element_pt = new
301  YoungLaplaceContactAngleElement<ELEMENT>(bulk_elem_pt,face_index);
302 
303  //Add the prescribed contact angle element to the mesh
304  mesh_pt()->add_element_pt(contact_angle_element_pt);
305 
306  } //end of loop over bulk elements adjacent to boundary b
307 
308 } // end of create_contact_angle_elements
309 
310 
311 
312 
313 //========================================start_of_actions_before_solve===
314 /// Update the problem specs before solve: (Re-)set boundary conditions
315 /// to the values from the exact solution.
316 //========================================================================
317 template<class ELEMENT>
319 {
320 
321  // Increment kappa or height value
323  {
324  double kappa=GlobalParameters::Kappa_pt->value(0);
326  GlobalParameters::Kappa_pt->set_value(0,kappa);
327 
328  cout << "Solving for Prescribed KAPPA Value = " ;
329  cout << GlobalParameters::Kappa_pt->value(0) << "\n" << endl;
330  }
331  else
332  {
335 
336  cout << "Solving for Prescribed HEIGHT Value = " ;
337  cout << GlobalParameters::Controlled_height << "\n" << endl;
338  }
339 
340 } // end of actions before solve
341 
342 
343 
344 
345 //===============start_of_doc=============================================
346 /// Doc the solution: doc_info contains labels/output directory etc.
347 //========================================================================
348 template<class ELEMENT>
349 void YoungLaplaceProblem<ELEMENT>::doc_solution(DocInfo& doc_info,
350  ofstream& trace_file)
351 {
352 
353  // Output kappa vs height of the apex
354  //------------------------------------
355  trace_file << -1.0*GlobalParameters::Kappa_pt->value(0) << " ";
356  trace_file << GlobalParameters::get_exact_kappa() << " ";
357  trace_file << Control_node_pt->value(0) ;
358  trace_file << endl;
359 
360  // Number of plot points: npts x npts
361  unsigned npts=5;
362 
363  // Output full solution
364  //---------------------
365  ofstream some_file;
366  char filename[100];
367  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
368  doc_info.number());
369  some_file.open(filename);
370  for(unsigned i=0;i<N_bulk_elements;i++)
371  {
372  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(i));
373  el_pt->output(some_file,npts);
374  }
375  some_file.close();
376 
377  // Output contact angle
378  //---------------------
379 
380  //Doc contact angle stuff
383  {
384 
385  ofstream tangent_file;
386  sprintf(filename,"%s/tangent_to_contact_line%i.dat",
387  doc_info.directory().c_str(),
388  doc_info.number());
389  tangent_file.open(filename);
390 
391  ofstream normal_file;
392  sprintf(filename,"%s/normal_to_contact_line%i.dat",
393  doc_info.directory().c_str(),
394  doc_info.number());
395  normal_file.open(filename);
396 
397 
398  ofstream contact_angle_file;
399  sprintf(filename,"%s/contact_angle%i.dat",
400  doc_info.directory().c_str(),
401  doc_info.number());
402  contact_angle_file.open(filename);
403 
404  // Tangent and normal vectors to contact line
405  Vector<double> tangent(3);
406  Vector<double> normal(3);
407  Vector<double> r_contact(3);
408 
409 
410  // Loop over both boundaries
411  for (unsigned bnd=0;bnd<2;bnd++)
412  {
413  unsigned el_lo=N_bulk_elements;
414  unsigned el_hi=Last_element_on_boundary1;
415  if (1==bnd)
416  {
417  el_lo=Last_element_on_boundary1;
418  el_hi=Last_element_on_boundary3;
419  }
420 
421  // Loop over the contact-angle elements (located at the "end" of the
422  // mesh)
423  for (unsigned e=el_lo;e<el_hi;e++)
424  {
425 
426  tangent_file << "ZONE" << std::endl;
427  normal_file << "ZONE" << std::endl;
428  contact_angle_file << "ZONE" << std::endl;
429 
430  // Upcast from GeneralisedElement to YoungLaplace contact angle element
431  YoungLaplaceContactAngleElement<ELEMENT>* el_pt =
432  dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
433  mesh_pt()->element_pt(e));
434 
435  // Loop over a few points in the contact angle element
436  Vector<double> s(1);
437  for (unsigned i=0;i<npts;i++)
438  {
439  s[0]=-1.0+2.0*double(i)/double(npts-1);
440 
441  dynamic_cast<ELEMENT*>(el_pt->bulk_element_pt())->
442  position(el_pt->local_coordinate_in_bulk(s),r_contact);
443 
444  el_pt->contact_line_vectors(s,tangent,normal);
445  tangent_file << r_contact[0] << " "
446  << r_contact[1] << " "
447  << r_contact[2] << " "
448  << tangent[0] << " "
449  << tangent[1] << " "
450  << tangent[2] << " " << std::endl;
451 
452  normal_file << r_contact[0] << " "
453  << r_contact[1] << " "
454  << r_contact[2] << " "
455  << normal[0] << " "
456  << normal[1] << " "
457  << normal[2] << " " << std::endl;
458 
459 
460  contact_angle_file << r_contact[1] << " "
461  << el_pt->actual_cos_contact_angle(s)
462  << std::endl;
463  }
464  }
465 
466  } // end of loop over both boundaries
467 
468  tangent_file.close();
469  normal_file.close();
470  contact_angle_file.close();
471 
472  }
473 
474 cout << "\n********************************************" << endl << endl;
475 
476 } // end of doc
477 
478 //========================================================================
479 /// Run code for current setting of parameter values -- specify name
480 /// of output directory
481 //========================================================================
482 void run_it(const string& output_directory)
483 {
484 
485  // Create label for output
486  //------------------------
487  DocInfo doc_info;
488 
489  // Set outputs
490  //------------
491 
492  // Trace file
493  ofstream trace_file;
494 
495  // Set output directory
496  doc_info.set_directory(output_directory);
497 
498  //Open a trace file
499  char filename[100];
500  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
501  trace_file.open(filename);
502 
503  // Write kappa, exact kappa if exists and height values
504  trace_file
505  << "VARIABLES=\"<GREEK>k</GREEK>\",\"<GREEK>k</GREEK>_{ex}\",\"h\""
506  << std::endl;
507  trace_file << "ZONE" << std::endl;
508 
509  //Set up the problem
510  //------------------
511 
512  // Create the problem with 2D nine-node elements from the
513  // QYoungLaplaceElement family.
515 
516  //Output the solution
517  problem.doc_solution(doc_info,trace_file);
518 
519  //Increment counter for solutions
520  doc_info.number()++;
521 
522 
523  // Parameter incrementation
524  //-------------------------
525 
526  // Loop over steps
527  for (unsigned istep=0;istep<GlobalParameters::Nsteps;istep++)
528  {
529 
530  // Solve the problem
531  problem.newton_solve();
532 
533  //Output the solution
534  problem.doc_solution(doc_info,trace_file);
535 
536  //Increment counter for solutions
537  doc_info.number()++;
538 
539  }
540 
541  // Close output file
542  trace_file.close();
543 
544 } //end of run_it()
545 
546 
547 
548 //===== start_of_main=====================================================
549 /// Driver code for 2D YoungLaplace problem. Input arguments: none
550 /// (for validation) or case (0,1,2 for all pinned, barrel and T junction)
551 /// and number of steps.
552 //========================================================================
553 int main(int argc, char* argv[])
554 {
555 
556  // Store command line arguments
557  CommandLineArgs::setup(argc,argv);
558 
559  // Cases to run (By default (validation) run all
560  unsigned case_lo=0;
561  unsigned case_hi=2;
562 
563  // No command line args: Running every case with
564  // limited number of steps
565  if (CommandLineArgs::Argc==1)
566  {
567  std::cout
568  << "Running every case with limited number of steps for validation"
569  << std::endl;
570 
571  // Number of steps
573  }
574  else
575  {
576  // Which case to run?
577  case_lo=atoi(argv[1]);
578  case_hi=atoi(argv[1]);
579 
580  // Number of steps
581  GlobalParameters::Nsteps=atoi(argv[2]);
582  }
583 
584 
585  // Loop over chosen case(s)
586  //-------------------------
587  for (unsigned my_case=case_lo;my_case<=case_hi;my_case++)
588  {
589 
590  // Choose
591  switch (my_case)
592  {
593 
594  case 0:
595 
596  cout << endl << endl
597  << "//////////////////////////////////////////////////////////\n"
598  << "All pinned solution \n"
599  << "//////////////////////////////////////////////////////////\n\n";
600 
602 
603  // Run with spines
605  run_it("RESLT_all_pinned");
606 
607  break;
608 
609  case 1:
610 
611  cout << endl << endl
612  << "//////////////////////////////////////////////////////////\n"
613  << "Barrel-shaped solution \n"
614  << "/////////////////////////////////////////////////////////\n\n";
615 
617 
618  // Run with spines
620  run_it("RESLT_barrel_shape");
621 
622  break;
623 
624  case 2:
625 
626  cout << endl << endl
627  << "//////////////////////////////////////////////////////////\n"
628  << "T-junction solution \n"
629  << "//////////////////////////////////////////////////////////\n\n";
630 
633 
634  // Adjust spine orientation
636  GlobalParameters::Gamma=MathematicalConstants::Pi/6.0;
637 
638  // Run with spines
640  run_it("RESLT_T_junction");
641 
642  break;
643 
644  default:
645 
646  std::cout << "Wrong case! Options are:\n"
647  << "0: All pinned\n"
648  << "1: Barrel \n"
649  << "2: T_junction\n"
650  << std::endl;
651  assert(false);
652 
653  }
654 
655  }
656 
657 
658 } //end of main
659 
660 
661 
662 
663 
664 
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...
Definition: barrel.cc:295
double L_x
Length and width of the domain.
~YoungLaplaceProblem()
Destructor (empty)
double Controlled_height
Height control value.
Definition: barrel.cc:55
YoungLaplaceProblem()
Constructor:
Definition: barrel.cc:184
unsigned Nsteps
Number of steps.
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
Data * Kappa_pt
Pointer to Data object that stores the prescribed curvature.
unsigned N_x
Number of elements in the mesh.
double Gamma
Contact angle and its cos (dependent parameter – is reassigned)
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
unsigned Last_element_on_boundary3
Number of last FaceElement on boundary 3.
bool Use_spines
Use spines (true) or not (false)
unsigned Last_element_on_boundary1
Number of last FaceElement on boundary 1.
unsigned N_bulk_elements
Number of YoungLaplace "bulk" elements (We&#39;re attaching the contact angle elements to the bulk mesh â€...
void setup_dependent_parameters_and_sanity_check()
Setup dependent parameters and perform sanity check.
void run_it(const string &output_directory)
double Cos_gamma
Cos of contact angle.
double L_y
Width of domain.
void actions_after_newton_solve()
Update the problem after solve: Empty.
int Case
What case are we considering: Choose one from the enumeration Cases.
void actions_before_newton_solve()
Update the problem before solve.
Definition: barrel.cc:155
double Kappa_increment
Increment for prescribed curvature.
double get_exact_kappa()
Exact kappa.
Definition: barrel.cc:58
int main(int argc, char *argv[])
bool Use_height_control
Use height control (true) or not (false)?
void create_contact_angle_elements(const unsigned &b)
Create YoungLaplace contact angle elements on the b-th boundary of the problem&#39;s mesh and add them to...
double Kappa_initial
Initial value for kappa.
double Controlled_height_increment
Increment for height control.