refineable_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// Copyright (C) 2006-2025 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 refineable Young Laplace problem
27
28#include <cassert>
29
30//Generic routines
31#include "generic.h"
32
33// The YoungLaplace equations
34#include "young_laplace.h"
35
36// The mesh
37#include "meshes/rectangular_quadmesh.h"
38
39// Namespaces
40using namespace std;
41using namespace oomph;
42
43// Namespace (shared with non-refineable version)
45
46//====== start_of_problem_class=======================================
47/// 2D RefineableYoungLaplace problem on rectangular domain, discretised with
48/// 2D QRefineableYoungLaplace elements. The specific type of element is
49/// specified via the template parameter.
50//====================================================================
51template<class ELEMENT>
52class RefineableYoungLaplaceProblem : public Problem
53{
54
55public:
56
57 /// Constructor:
59
60 /// Destructor (empty)
62
63 /// Update the problem specs before solve: Empty
65
66 /// Update the problem after solve: Empty
68
69 /// Actions before adapt: Wipe the mesh of contact angle elements
71 {
72 // Kill the contact angle elements and wipe contact angle mesh
74
75 // Rebuild the Problem's global mesh from its various sub-meshes
76 rebuild_global_mesh();
77 }
78
79
80 /// Actions after adapt: Rebuild the mesh of contact angle elements
82 {
83 // Create contact angle elements on boundaries 1 and 3 of bulk mesh
86 {
89
90 // Set function pointers for contact-angle elements
91 unsigned nel=Contact_angle_mesh_pt->nelement();
92 for (unsigned e=0;e<nel;e++)
93 {
94 // Upcast from GeneralisedElement to YoungLaplace contact angle
95 // element
96 YoungLaplaceContactAngleElement<ELEMENT> *el_pt =
97 dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
98 Contact_angle_mesh_pt->element_pt(e));
99
100 // Set the pointer to the prescribed contact angle
101 el_pt->prescribed_cos_gamma_pt() = &GlobalParameters::Cos_gamma;
102 }
103 }
104
105 // Rebuild the Problem's global mesh from its various sub-meshes
106 rebuild_global_mesh();
107
108 }
109
110 /// Increase the problem parameters before each solve
112
113 /// Doc the solution. DocInfo object stores flags/labels for where the
114 /// output gets written to and the trace file
115 void doc_solution(DocInfo& doc_info, ofstream& trace_file);
116
117private:
118
119 /// Create YoungLaplace contact angle elements on the
120 /// b-th boundary of the bulk mesh and add them to contact angle mesh
121 void create_contact_angle_elements(const unsigned& b);
122
123 /// Delete contact angle elements
125
126 /// Pointer to the "bulk" mesh
127 RefineableRectangularQuadMesh<ELEMENT>* Bulk_mesh_pt;
128
129 /// Pointer to the contact angle mesh
131
132 /// Pointer to mesh containing the height control element
134
135 /// Pointer to height control element
136 HeightControlElement* Height_control_element_pt;
137
138 /// Node at which the height (displacement along spine) is controlled/doced
139 Node* Control_node_pt;
140
141}; // end of problem class
142
143
144//=====start_of_constructor===============================================
145/// Constructor for RefineableYoungLaplace problem
146//========================================================================
147template<class ELEMENT>
149{
150
151 // Setup dependent parameters in namespace
153
154
155 // Setup bulk mesh
156 //----------------
157
158 // # of elements in x-direction
159 unsigned n_x=GlobalParameters::N_x;
160
161 // # of elements in y-direction
162 unsigned n_y=GlobalParameters::N_y;
163
164 // Domain length in x-direction
165 double l_x=GlobalParameters::L_x;
166
167 // Domain length in y-direction
168 double l_y=GlobalParameters::L_y;
169
170 // Print Size of the mesh
171 cout << "Lx = " << l_x << " and Ly = " << l_y << endl;
172
173 // Build and assign mesh
174 Bulk_mesh_pt=new RefineableRectangularQuadMesh<ELEMENT>(n_x,n_y,l_x,l_y);
175
176 // Create/set error estimator
177 Bulk_mesh_pt->spatial_error_estimator_pt()=new Z2ErrorEstimator;
178
179 // Set targets for spatial adaptivity
180 Bulk_mesh_pt->max_permitted_error()=1.0e-4;
181 Bulk_mesh_pt->min_permitted_error()=1.0e-6;
182
183 // Add bulk mesh to the global mesh
184 add_sub_mesh(Bulk_mesh_pt);
185
186
187 // Prescribed height?
188 //-------------------
189
190 // Choose the prescribed height element
191 ELEMENT* prescribed_height_element_pt= dynamic_cast<ELEMENT*>(
192 Bulk_mesh_pt->element_pt(GlobalParameters::Control_element));
193
194 // ...and the associated control node (node 0 in that element)
195 // (we're storing this node even if there's no height-control, for
196 // output purposes...)
197 Control_node_pt= static_cast<Node*>(
198 prescribed_height_element_pt->node_pt(0));
199
200 cout << "Controlling height at (x,y) : (" << Control_node_pt->x(0)
201 << "," << Control_node_pt->x(1) << ")" << endl;
202
203 // If needed, create a height control element and store the
204 // pointer to the Kappa Data created by this object
205 Height_control_element_pt=0;
206 Height_control_mesh_pt=0;
208 {
209 Height_control_element_pt=new HeightControlElement(
210 Control_node_pt,&GlobalParameters::Controlled_height);
211
212 GlobalParameters::Kappa_pt=Height_control_element_pt->kappa_pt();
213 Height_control_element_pt->kappa_pt()->
215
216 // Add to mesh
217 Height_control_mesh_pt = new Mesh;
218 Height_control_mesh_pt->add_element_pt(Height_control_element_pt);
219
220 // Add height control mesh to the global mesh
221 add_sub_mesh(Height_control_mesh_pt);
222 }
223 //...otherwise create a kappa data item from scratch and pin its
224 // single unknown value
225 else
226 {
228 GlobalParameters::Kappa_pt=new Data(1);
231 }
232
233
234 // Contact angle elements
235 //-----------------------
236
237 // Create prescribed-contact-angle elements from all elements that are
238 // adjacent to boundary 1 and 3 and add them to their own mesh
239 Contact_angle_mesh_pt=0;
242 {
243 // set up new mesh
244 Contact_angle_mesh_pt=new Mesh;
245
246 // creation of contact angle elements
247 create_contact_angle_elements(1);
248 create_contact_angle_elements(3);
249
250 // Add contact angle mesh to the global mesh
251 add_sub_mesh(Contact_angle_mesh_pt);
252 }
253
254
255 // Build global mesh
256 //------------------
257 build_global_mesh();
258
259
260 // Boundary conditions
261 //--------------------
262
263 // Set the boundary conditions for this problem: All nodes are
264 // free by default -- only need to pin the ones that have Dirichlet conditions
265 // here.
266 unsigned n_bound = Bulk_mesh_pt->nboundary();
267 for(unsigned b=0;b<n_bound;b++)
268 {
269 // Pin all boundaries for three cases and only boundaries
270 // 0 and 2 in all others:
272 (b==0)||
273 (b==2))
274 {
275 unsigned n_node = Bulk_mesh_pt->nboundary_node(b);
276 for (unsigned n=0;n<n_node;n++)
277 {
278 Bulk_mesh_pt->boundary_node_pt(b,n)->pin(0);
279 }
280 }
281 }
282
283 // Complete build of elements
284 //---------------------------
285
286 // Complete the build of all elements so they are fully functional
287 unsigned n_bulk=Bulk_mesh_pt->nelement();
288 for(unsigned i=0;i<n_bulk;i++)
289 {
290 // Upcast from GeneralsedElement to the present element
291 ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(i));
292
294 {
295 //Set the spine function pointers
296 el_pt->spine_base_fct_pt() = GlobalParameters::spine_base_function;
297 el_pt->spine_fct_pt() = GlobalParameters::spine_function;
298 }
299
300 // Set the curvature data for the element
301 el_pt->set_kappa(GlobalParameters::Kappa_pt);
302
303 }
304
305 // Set function pointers for contact-angle elements
308 {
309 // Set function pointers for contact-angle elements
310 unsigned nel=Contact_angle_mesh_pt->nelement();
311 for (unsigned e=0;e<nel;e++)
312 {
313 // Upcast from GeneralisedElement to YoungLaplace contact angle
314 // element
315 YoungLaplaceContactAngleElement<ELEMENT> *el_pt =
316 dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
317 Contact_angle_mesh_pt->element_pt(e));
318
319 // Set the pointer to the prescribed contact angle
320 el_pt->prescribed_cos_gamma_pt() = &GlobalParameters::Cos_gamma;
321 }
322 }
323
324 // Setup equation numbering scheme
325 cout <<"\nNumber of equations: " << assign_eqn_numbers() << endl;
326 cout << "\n********************************************\n" << endl;
327
328} // end of constructor
329
330
331//============start_of_create_contact_angle_elements=====================
332/// Create YoungLaplace contact angle elements on the b-th boundary of the
333/// bulk mesh and add them to the contact angle mesh
334//=======================================================================
335template<class ELEMENT>
337 const unsigned &b)
338{
339 // How many bulk elements are adjacent to boundary b?
340 unsigned n_element = Bulk_mesh_pt->nboundary_element(b);
341
342 // Loop over the bulk elements adjacent to boundary b?
343 for(unsigned e=0;e<n_element;e++)
344 {
345 // Get pointer to the bulk element that is adjacent to boundary b
346 ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
347 Bulk_mesh_pt->boundary_element_pt(b,e));
348
349 // What is the index of the face of the bulk element at the boundary
350 int face_index = Bulk_mesh_pt->face_index_at_boundary(b,e);
351
352 // Build the corresponding contact angle element
353 YoungLaplaceContactAngleElement<ELEMENT>* contact_angle_element_pt = new
354 YoungLaplaceContactAngleElement<ELEMENT>(bulk_elem_pt,face_index);
355
356 //Add the contact angle element to the contact angle mesh
357 Contact_angle_mesh_pt->add_element_pt(contact_angle_element_pt);
358
359 } //end of loop over bulk elements adjacent to boundary b
360
361} // end of create_contact_angle_elements
362
363
364//============start_of_delete_contact_angle_elements=====================
365/// Delete YoungLaplace contact angle elements
366//=======================================================================
367template<class ELEMENT>
369{
370
371 // How many contact angle elements are there?
372 unsigned n_element = Contact_angle_mesh_pt->nelement();
373
374 // Loop over the surface elements
375 for(unsigned e=0;e<n_element;e++)
376 {
377 // Kill surface element
378 delete Contact_angle_mesh_pt->element_pt(e);
379 }
380
381 // Wipe the mesh
382 Contact_angle_mesh_pt->flush_element_and_node_storage();
383
384
385} // end of delete_contact_angle_elements
386
387
388
389//===============start_of_update_parameters============================
390/// Update (increase/decrease) parameters
391//=====================================================================
392template<class ELEMENT>
394{
395
396 // Increment kappa or height value
398 {
399 double kappa=GlobalParameters::Kappa_pt->value(0);
401 GlobalParameters::Kappa_pt->set_value(0,kappa);
402
403 cout << "Solving for Prescribed KAPPA Value = " ;
404 cout << GlobalParameters::Kappa_pt->value(0) << "\n" << endl;
405 }
406 else
407 {
410
411 cout << "Solving for Prescribed HEIGHT Value = " ;
412 cout << GlobalParameters::Controlled_height << "\n" << endl;
413 }
414
415}
416
417
418//===============start_of_doc=============================================
419/// Doc the solution: doc_info contains labels/output directory etc.
420//========================================================================
421template<class ELEMENT>
423 ofstream& trace_file)
424{
425
426 // Output kappa vs height
427 //-----------------------
428 trace_file << -1.0*GlobalParameters::Kappa_pt->value(0) << " ";
429 trace_file << GlobalParameters::get_exact_kappa() << " ";
430 trace_file << Control_node_pt->value(0) ;
431 trace_file << endl;
432
433 // Number of plot points: npts x npts
434 unsigned npts=5;
435
436 // Output full solution
437 //---------------------
438 ofstream some_file;
439 char filename[100];
440 //YoungLaplaceEquations::Output_meniscus_and_spines=false;
441 snprintf(filename, sizeof(filename), "%s/soln%i.dat",doc_info.directory().c_str(),
442 doc_info.number());
443 some_file.open(filename);
444 Bulk_mesh_pt->output(some_file,npts);
445 some_file.close();
446
447 // Output contact angle
448 //---------------------
449
450 //Doc contact angle stuff
453 {
454
455 ofstream tangent_file;
456 snprintf(filename, sizeof(filename), "%s/tangent_to_contact_line%i.dat",
457 doc_info.directory().c_str(),
458 doc_info.number());
459 tangent_file.open(filename);
460
461 ofstream normal_file;
462 snprintf(filename, sizeof(filename), "%s/normal_to_contact_line%i.dat",
463 doc_info.directory().c_str(),
464 doc_info.number());
465 normal_file.open(filename);
466
467
468 ofstream contact_angle_file;
469 snprintf(filename, sizeof(filename), "%s/contact_angle%i.dat",
470 doc_info.directory().c_str(),
471 doc_info.number());
472 contact_angle_file.open(filename);
473
474 // Tangent and normal vectors to contact line
475 Vector<double> tangent(3);
476 Vector<double> normal(3);
477 Vector<double> r_contact(3);
478
479 // How many contact angle elements are there?
480 unsigned n_element = Contact_angle_mesh_pt->nelement();
481
482 // Loop over the surface elements
483 for(unsigned e=0;e<n_element;e++)
484 {
485
486 tangent_file << "ZONE" << std::endl;
487 normal_file << "ZONE" << std::endl;
488 contact_angle_file << "ZONE" << std::endl;
489
490 // Upcast from GeneralisedElement to YoungLaplace contact angle element
491 YoungLaplaceContactAngleElement<ELEMENT>* el_pt =
492 dynamic_cast<YoungLaplaceContactAngleElement<ELEMENT>*>(
493 Contact_angle_mesh_pt->element_pt(e));
494
495 // Loop over a few points in the contact angle element
496 Vector<double> s(1);
497 for (unsigned i=0;i<npts;i++)
498 {
499 s[0]=-1.0+2.0*double(i)/double(npts-1);
500
501 dynamic_cast<ELEMENT*>(el_pt->bulk_element_pt())->
502 position(el_pt->local_coordinate_in_bulk(s),r_contact);
503
504 el_pt->contact_line_vectors(s,tangent,normal);
505 tangent_file << r_contact[0] << " "
506 << r_contact[1] << " "
507 << r_contact[2] << " "
508 << tangent[0] << " "
509 << tangent[1] << " "
510 << tangent[2] << " " << std::endl;
511
512 normal_file << r_contact[0] << " "
513 << r_contact[1] << " "
514 << r_contact[2] << " "
515 << normal[0] << " "
516 << normal[1] << " "
517 << normal[2] << " " << std::endl;
518
519 contact_angle_file << r_contact[1] << " "
520 << el_pt->actual_cos_contact_angle(s)
521 << std::endl;
522 }
523
524
525 } // end of loop over both boundaries
526
527 tangent_file.close();
528 normal_file.close();
529 contact_angle_file.close();
530
531 }
532
533 cout << "\n********************************************" << endl << endl;
534
535} // end of doc
536
537
538
539//========================================================================
540/// Run code for current setting of parameter values -- specify name
541/// of output directory
542//========================================================================
543void run_it(const string& output_directory)
544{
545
546 // Create label for output
547 //------------------------
548 DocInfo doc_info;
549
550 // Set outputs
551 //------------
552
553 // Trace file
554 ofstream trace_file;
555
556 // Set output directory
557 doc_info.set_directory(output_directory);
558
559 // Open a trace file
560 char filename[100];
561 snprintf(filename, sizeof(filename), "%s/trace.dat",doc_info.directory().c_str());
562 trace_file.open(filename);
563
564 // Write kappa, exact kappa if exists and height values
565 trace_file <<
566 "VARIABLES=\"<GREEK>k</GREEK>\",\"<GREEK>k</GREEK>_{ex}\",\"h\""
567 << std::endl;
568 trace_file << "ZONE" << std::endl;
569
570 //Set up the problem
571 //------------------
572
573 // Create the problem with 2D nine-node elements from the
574 // RefineableQYoungLaplaceElement family.
576
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
588 // Loop over steps
589 for (unsigned istep=0;istep<GlobalParameters::Nsteps;istep++)
590 {
591
592 // Bump up parameters
593 problem.increment_parameters();
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 run_it()
610
611
612
613//===== start_of_main=====================================================
614/// Driver code for 2D RefineableYoungLaplace problem. Input arguments: none
615/// (for validation) or case (0,1,2,3 for all pinned, barrel with spines,
616/// barrel without spines, and T junction), and number of steps.
617//========================================================================
618int main(int argc, char* argv[])
619{
620
621 // Store command line arguments
622 CommandLineArgs::setup(argc,argv);
623
624 // Cases to run (By default (validation) run all
625 unsigned case_lo=0;
626 unsigned case_hi=3;
627
628 // No command line args: Running every case with
629 // limited number of steps
630 if (CommandLineArgs::Argc==1)
631 {
632 std::cout
633 << "Running every case with limited number of steps for validation"
634 << std::endl;
635
636 // Number of steps
638 }
639 else
640 {
641 // Which case to run?
642 case_lo=atoi(argv[1]);
643 case_hi=atoi(argv[1]);
644
645 // Number of steps
646 GlobalParameters::Nsteps=atoi(argv[2]);
647 }
648
649 // Loop over chosen case(s)
650 //-------------------------
651 for (unsigned my_case=case_lo;my_case<=case_hi;my_case++)
652 {
653
654 // Choose
655 switch (my_case)
656 {
657
658 case 0:
659
660 cout << endl << endl
661 << "//////////////////////////////////////////////////////////\n"
662 << "All pinned solution \n"
663 << "//////////////////////////////////////////////////////////\n\n";
664
666
667 // Run with spines
669 run_it("RESLT_adapt_all_pinned");
670
671 break;
672
673 case 1:
674
675 cout << endl << endl
676 << "//////////////////////////////////////////////////////////\n"
677 << "Barrel-shaped solution with spine \n"
678 << "/////////////////////////////////////////////////////////\n\n";
679
683 run_it("RESLT_adapt_barrel_shape");
684
685 break;
686
687 case 2:
688
689 cout << endl << endl
690 << "//////////////////////////////////////////////////////////\n"
691 << "Barrel-shaped solution without spines \n"
692 << "/////////////////////////////////////////////////////////\n\n";
693
697 run_it("RESLT_adapt_barrel_shape_without_spines");
698
699 break;
700
701 case 3:
702
703 cout << endl << endl
704 << "//////////////////////////////////////////////////////////\n"
705 << "T-junction solution \n"
706 << "//////////////////////////////////////////////////////////\n\n";
707
710 GlobalParameters::Gamma=MathematicalConstants::Pi/6.0;
713
714 // Run with spines
716 run_it("RESLT_adapt_T_junction");
717
718 break;
719
720
721 default:
722
723 std::cout << "Wrong case! Options are:\n"
724 << "0: adaptive All pinned\n"
725 << "1: adaptive Barrel with spines\n"
726 << "2: adaptive Barrel without spines\n"
727 << "3: adaptive T_junction\n"
728 << std::endl;
729 assert(false);
730
731 }
732
733 }
734
735
736} //end of main
737
738
int main()
Driver code.
Definition barrel.cc:321
2D RefineableYoungLaplace problem on rectangular domain, discretised with 2D QRefineableYoungLaplace ...
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...
void actions_after_newton_solve()
Update the problem after solve: Empty.
~RefineableYoungLaplaceProblem()
Destructor (empty)
RefineableRectangularQuadMesh< ELEMENT > * Bulk_mesh_pt
Pointer to the "bulk" mesh.
void actions_before_newton_solve()
Update the problem specs before solve: Empty.
Mesh * Contact_angle_mesh_pt
Pointer to the contact angle mesh.
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()
Constructor:
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of contact angle elements.
void delete_contact_angle_elements()
Delete contact angle elements.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of contact angle elements.
HeightControlElement * Height_control_element_pt
Pointer to height control element.
void increment_parameters()
Increase the problem parameters before each solve.
Mesh * Height_control_mesh_pt
Pointer to mesh containing the height control element.
Node * Control_node_pt
Node at which the height (displacement along spine) is controlled/doced.
double L_x
Length and width of the domain.
double Controlled_height
Height control value.
Definition barrel.cc:51
unsigned Control_element
Number of element in bulk mesh at which height control is applied. Initialise to 0 – will be overwrit...
double get_exact_kappa()
Exact kappa.
Definition barrel.cc:54
bool Use_height_control
Use height control (true) or not (false)?
double Controlled_height_increment
Increment for height control.
double Kappa_increment
Increment for prescribed curvature.
bool Use_spines
Use spines (true) or not (false)
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:104
unsigned Nsteps
Number of steps.
unsigned N_x
Number of elements in the mesh.
Data * Kappa_pt
Pointer to Data object that stores the prescribed curvature.
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:72
double L_y
Width of domain.
double Gamma
Contact angle and its cos (dependent parameter – is reassigned)
double Kappa_initial
Initial value for kappa.
double Cos_gamma
Cos of contact angle.
int Case
What case are we considering: Choose one from the enumeration Cases.
void setup_dependent_parameters_and_sanity_check()
Setup dependent parameters and perform sanity check.
void run_it(const string &output_directory)
Run code for current setting of parameter values – specify name of output directory.