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