Example codes
and tutorials
The (Not-so) Quick Guide
List of tutorials/demo codes
Single-Physics Problems
Poisson
Adaptivity illustrated for Poisson
Advection-Diffusion
Unsteady heat equation
Linear wave equation
The Young-Laplace equation
Navier-Stokes
Free-surface Navier-Stokes
Axisymmetric Navier-Stokes
Solid mechanics
Beam structures
Shell structures
Multi-physics Problems
Fluid-structure interaction
Boussinesq convection
Steady thermoelasticity
Methods-based example codes and tutorials
Mesh generation
Linear solvers and preconditioners
Visualisation of the results
Parallel processing
How to write a new element
How to write a new refineable element
Default nonlinear solvers -- the sequence of action functions
...
Documentation
FE theory and top-down discussion of the data structure
The (Not-so) Quick Guide
Comprehensive bottom-up discussion of the data structure
List of available structured and unstructured meshes
Linear solvers and preconditioners
Visualisation of the results
Parallel processing
Coding conventions and C++ style
Creating documentation
Optimisation - robustness vs. "raw speed"
Linear vs. nonlinear problems
Storing shape functions
Changing the default "full" integration scheme
Disabling the ALE formulation of unsteady equations
C vs. C++ output
Different sparse assembly techniques and the STL memory pool
Publications
Publications
Talks
Journal publications
Theses
Picture show
Download
Copyright
Download/installation instructions
Download page
FAQ & Contact
FAQ
Change log
Bugs and other known problems
Completeness of the library & our "To-Do List"
Contact the developers
Get involved

 


Beta release!

Please note that the library has not been "officially" released. While we continue to work on the documentation, these web pages are likely to contain broken links and documents in draft form. Please send an email to

oomph-lib AT maths DOT man DOT ac DOT uk

if you wish to be informed of the library's "official" release.

bretherton_spine_mesh.template.cc

Go to the documentation of this file.
00001 //LIC// ====================================================================
00002 //LIC// This file forms part of oomph-lib, the object-oriented, 
00003 //LIC// multi-physics finite-element library, available 
00004 //LIC// at http://www.oomph-lib.org.
00005 //LIC// 
00006 //LIC//           Version 0.90. August 3, 2009.
00007 //LIC// 
00008 //LIC// Copyright (C) 2006-2009 Matthias Heil and Andrew Hazel
00009 //LIC// 
00010 //LIC// This library is free software; you can redistribute it and/or
00011 //LIC// modify it under the terms of the GNU Lesser General Public
00012 //LIC// License as published by the Free Software Foundation; either
00013 //LIC// version 2.1 of the License, or (at your option) any later version.
00014 //LIC// 
00015 //LIC// This library is distributed in the hope that it will be useful,
00016 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018 //LIC// Lesser General Public License for more details.
00019 //LIC// 
00020 //LIC// You should have received a copy of the GNU Lesser General Public
00021 //LIC// License along with this library; if not, write to the Free Software
00022 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00023 //LIC// 02110-1301  USA.
00024 //LIC// 
00025 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
00026 //LIC// 
00027 //LIC//====================================================================
00028 #ifndef OOMPH_BRETHERTON_SPINE_MESH_TEMPLATE_CC
00029 #define OOMPH_BRETHERTON_SPINE_MESH_TEMPLATE_CC
00030 
00031 #include "bretherton_spine_mesh.template.h"
00032 #include "../generic/mesh_as_geometric_object.h"
00033 #include "../generic/face_element_as_geometric_object.h"
00034 
00035 #include "single_layer_spine_mesh.template.cc"
00036 #include "simple_rectangular_quadmesh.template.cc"
00037 
00038 
00039 namespace oomph
00040 {
00041 
00042 
00043 //======================================================================
00044 /// Constructor. Arguments: 
00045 /// - nx1:   Number of elements along wall in deposited film region
00046 /// - nx2:   Number of elements along wall in horizontal transition region
00047 /// - nx3:   Number of elements along wall in channel region
00048 /// - nhalf: Number of elements in vertical transition region (there are
00049 ///          twice as many elements across the channel)
00050 /// - nh:    Number of elements across the deposited film
00051 /// - h:     Thickness of deposited film
00052 /// - zeta0:   Start coordinate on wall
00053 /// - zeta1:   Wall coordinate of start of transition region
00054 /// - zeta2:   Wall coordinate of end of liquid filled region (inflow)
00055 /// - lower_wall_pt: Pointer to geometric object that represents the lower wall
00056 /// - upper_wall_pt: Pointer to geometric object that represents the upper wall
00057 /// - time_stepper_pt: Pointer to timestepper; defaults to Static
00058 //======================================================================
00059 template<class ELEMENT, class INTERFACE_ELEMENT>
00060 BrethertonSpineMesh<ELEMENT,INTERFACE_ELEMENT>::BrethertonSpineMesh(
00061  const unsigned &nx1,
00062  const unsigned &nx2,
00063  const unsigned &nx3,
00064  const unsigned &nh, 
00065  const unsigned &nhalf,
00066  const double& h,
00067  GeomObject* lower_wall_pt,
00068  GeomObject* upper_wall_pt,
00069  const double& zeta_start,
00070  const double& zeta_transition_start,
00071  const double& zeta_transition_end, 
00072  const double& zeta_end,
00073  TimeStepper* time_stepper_pt) :
00074  SingleLayerSpineMesh<ELEMENT,INTERFACE_ELEMENT>
00075 (2*(nx1+nx2+nhalf),nh,1.0,h,time_stepper_pt),
00076  Nx1(nx1), Nx2(nx2), Nx3(nx3), Nhalf(nhalf), Nh(nh), H(h),
00077  Upper_wall_pt(upper_wall_pt), Lower_wall_pt(lower_wall_pt),
00078  Zeta_start(zeta_start), Zeta_end(zeta_end), 
00079  Zeta_transition_start(zeta_transition_start),
00080  Zeta_transition_end(zeta_transition_end),
00081  Spine_centre_fraction_pt(&Default_spine_centre_fraction),
00082  Default_spine_centre_fraction(0.5)
00083 {
00084 
00085  //Initialise start of transition region to zero
00086  //Zeta_transition_start = 0.0;
00087 
00088  // Length of deposited film region
00089  double llayer = Zeta_transition_start - Zeta_start;
00090 
00091  // Length of transition region
00092  double d = Zeta_transition_end - Zeta_transition_start;
00093 
00094  // Work out radius of circular cap from lower and upper wall
00095  Vector<double> r_wall_lo(2), r_wall_up(2);
00096  Vector<double> zeta(1), s_lo(1), s_up(1);
00097  GeomObject *lower_sub_geom_object_pt=0, *upper_sub_geom_object_pt=0;
00098 
00099  GeomObject *lower_transition_geom_object_pt=0;
00100  GeomObject *upper_transition_geom_object_pt=0;
00101  Vector<double> s_transition_lo(1), s_transition_up(1);
00102  Vector<double> spine_centre(2);
00103 
00104  //Find position of lower and upper walls at start of transition region
00105  zeta[0] = Zeta_transition_start;
00106  Lower_wall_pt->position(zeta,r_wall_lo);
00107  Upper_wall_pt->position(zeta,r_wall_up);
00108  //Radius is the difference between the film thickness and the distance
00109  //to the lower wall
00110  double radius=-r_wall_lo[1]-H;
00111 
00112  //Check to non-symmetric mesh
00113  if (std::abs(r_wall_lo[1]+r_wall_up[1])>1.0e-4)
00114   {
00115    oomph_info << "\n\n=================================================== "  << std::endl;
00116    oomph_info << "Warning: " << std::endl;
00117    oomph_info << "-------- " << std::endl;
00118    oomph_info << " "  << std::endl;
00119    oomph_info << "Upper and lower walls are not symmetric at zeta=0" << std::endl;
00120    oomph_info << "Your initial mesh will look very odd." << std::endl;
00121    oomph_info << "y-coordinates of walls at zeta=0 are: " << r_wall_lo[1] 
00122         << " and " << r_wall_up[1] << std::endl << std::endl;
00123    oomph_info << "===================================================\n\n "  << std::endl;
00124   }
00125 
00126  // Reorder elements: Vertical stacks of elements, each topped by
00127  // their interface element -- this is (currently) identical to the
00128  // version in the SingleLayerSpineMesh but it's important 
00129  // that element reordering is maintained in exactly this form
00130  // so to be on the safe side, we move the function in here.
00131  initial_element_reorder();
00132 
00133  // Store pointer to control element
00134  Control_element_pt=dynamic_cast<ELEMENT*>(
00135   this->element_pt((nx1+nx2+nhalf)*(nh+1)-2));
00136  
00137  // Temporary storage for boundary lookup scheme
00138  Vector<std::set<Node*> > set_boundary_node_pt(6);
00139 
00140  // Boundary 1 -> 3; 2 -> 4; 3 -> 5
00141  for (unsigned ibound=1;ibound<=3;ibound++)
00142   {
00143    unsigned numnod = this->nboundary_node(ibound);
00144    for (unsigned j=0;j<numnod;j++)
00145     {
00146      set_boundary_node_pt[ibound+2].insert(this->boundary_node_pt(ibound,j));
00147     }
00148   }
00149 
00150  // Get number of nodes per element
00151  unsigned nnod = this->finite_element_pt(0)->nnode();
00152 
00153  // Get number of nodes along element edge
00154  unsigned np = this->finite_element_pt(0)->nnode_1d();
00155 
00156  // Initialise number of elements in previous regions:
00157  unsigned n_prev_elements=0;
00158 
00159  // We've now built the straight single-layer mesh and need to change the
00160  // the update functions for all nodes so that the domain
00161  // deforms into the Bretherton shape
00162 
00163  // Loop over elements in lower deposited film region
00164  // -------------------------------------------------
00165  {
00166   // Increments in wall coordinate
00167   double dzeta_el=llayer/double(nx1);
00168   double dzeta_node=llayer/double(nx1*(np-1));
00169   
00170   // Loop over elements horizontally
00171   for (unsigned i=0;i<nx1;i++)
00172    {
00173     // Start of wall coordinate
00174     double zeta_lo = Zeta_start + double(i)*dzeta_el;
00175     
00176     // Loop over elements vertically
00177     for (unsigned j=0;j<nh;j++)
00178      {
00179       // Work out element number in overall mesh
00180       unsigned e=n_prev_elements+i*(nh+1)+j;
00181       
00182       // Get pointer to element
00183       FiniteElement* el_pt = this->finite_element_pt(e);
00184       
00185       // Loop over its nodes
00186       for (unsigned i0=0;i0<np;i0++)
00187        {
00188         for (unsigned i1=0;i1<np;i1++)
00189          {
00190           // Node number:
00191           unsigned n=i0*np+i1;
00192           
00193           // Get spine node
00194           SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(n));
00195           
00196           // Set update fct id
00197           nod_pt->node_update_fct_id()=0;
00198           
00199           // Provide spine with additional storage for wall coordinate 
00200           // and wall geom object:
00201           if (i0==0)
00202            {
00203             // Get the Lagrangian coordinate in the Lower Wall
00204             zeta[0] =  zeta_lo + double(i1)*dzeta_node;
00205             //Get the geometric object and local coordinate
00206             Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
00207 
00208             //The local coordinate is a geometric parameter
00209             //This needs to be set (rather than added) because the
00210             //same spine may be visited more than once
00211             Vector<double> parameters(1,s_lo[0]);
00212             nod_pt->spine_pt()->set_geom_parameter(parameters);
00213 
00214             // Adjust spine height
00215             nod_pt->spine_pt()->height()=H;
00216 
00217             // The sub geom object is one (and only) geom object
00218             // for spine:
00219             Vector<GeomObject*> geom_object_pt(1);
00220             geom_object_pt[0] = lower_sub_geom_object_pt;
00221             
00222             // Pass geom object(s) to spine
00223             nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
00224 
00225             //Push the node back onto boundaries
00226             if (j==0) set_boundary_node_pt[0].insert(nod_pt);
00227            }
00228          }
00229        }
00230      }
00231    }
00232   
00233   // Increment number of previous elements
00234   n_prev_elements+=nx1*(nh+1);
00235 
00236  }
00237 
00238  {
00239   //Calculate the centre for the spine nodes in the transition region
00240   zeta[0] = Zeta_transition_start;
00241   //Get the geometric objects on the walls at the start of the transition
00242   //region
00243   Lower_wall_pt->locate_zeta(zeta,lower_transition_geom_object_pt,
00244                              s_transition_lo);
00245   Upper_wall_pt->locate_zeta(zeta,upper_transition_geom_object_pt,
00246                              s_transition_up);
00247   
00248   //Find the Eulerian coordinates of the walls at the transition region
00249   lower_transition_geom_object_pt->position(s_transition_lo,r_wall_lo);
00250   upper_transition_geom_object_pt->position(s_transition_up,r_wall_up);
00251 
00252   //Take the average of these positions to define the origin of the spines in
00253   //the transition region
00254   //Horizontal position is always halfway
00255   spine_centre[0] = 0.5*(r_wall_lo[0] + r_wall_up[0]);
00256   
00257   //Vertical Position is given by a specified fraction
00258   //between the upper and lower walls
00259   spine_centre[1] = r_wall_lo[1] + 
00260      spine_centre_fraction()*(r_wall_up[1] - r_wall_lo[1]);
00261  }
00262 
00263 
00264  // Loop over elements in lower horizontal transition region
00265  // --------------------------------------------------------
00266  {
00267   // Increments in wall coordinate
00268   double dzeta_el=d/double(nx2);
00269   double dzeta_node=d/double(nx2*(np-1));
00270   
00271   // Loop over elements horizontally
00272   for (unsigned i=0;i<nx2;i++)
00273    {
00274     // Start of wall coordinate
00275     double zeta_lo = Zeta_transition_start + double(i)*dzeta_el;
00276     
00277     // Loop over elements vertically
00278     for (unsigned j=0;j<nh;j++)
00279      {
00280       // Work out element number in overall mesh
00281       unsigned e=n_prev_elements+i*(nh+1)+j;
00282 
00283       // Get pointer to element
00284       FiniteElement* el_pt = this->finite_element_pt(e);
00285       
00286       // Loop over its nodes
00287       for (unsigned i0=0;i0<np;i0++)
00288        {
00289         for (unsigned i1=0;i1<np;i1++)
00290          {
00291           // Node number:
00292           unsigned n=i0*np+i1;
00293           
00294           // Get spine node
00295           SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(n));
00296           
00297           // Set update id
00298           nod_pt->node_update_fct_id()=1;
00299           
00300           // Provide spine with additional storage for wall coordinate 
00301           if (i0==0)
00302            {
00303             // Get the Lagrangian coordinate in the Lower Wall
00304             zeta[0] = zeta_lo + double(i1)*dzeta_node;
00305             // Get the sub geometric object and local coordinate
00306             Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
00307        
00308             // Pass geometric parameter to the spine
00309             Vector<double> parameters(3);
00310             parameters[0] = s_lo[0];
00311             parameters[1] = s_transition_lo[0];
00312             parameters[2] = s_transition_up[0];
00313             nod_pt->spine_pt()->set_geom_parameter(parameters);
00314  
00315             // Get position vector to wall
00316             lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
00317             
00318             // Get normal vector towards origin
00319             Vector<double> N(2);
00320             N[0] = spine_centre[0] - r_wall_lo[0];
00321             N[1] = spine_centre[1] - r_wall_lo[1];
00322             double length=sqrt(N[0]*N[0]+N[1]*N[1]);
00323             nod_pt->spine_pt()->height()=length-radius;
00324 
00325             // Lower sub geom object is one (and only) geom object
00326             // for spine:
00327             Vector<GeomObject*> geom_object_pt(3);
00328             geom_object_pt[0] = lower_sub_geom_object_pt;
00329             geom_object_pt[1] = lower_transition_geom_object_pt;
00330             geom_object_pt[2] = upper_transition_geom_object_pt;
00331 
00332             // Pass geom object(s) to spine
00333             nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
00334             
00335             //Push the node back onto boundaries
00336             if (j==0) set_boundary_node_pt[0].insert(nod_pt);
00337            }
00338          }
00339        }
00340      }
00341    }
00342 
00343   // Increment number of previous elements
00344   n_prev_elements+=nx2*(nh+1);
00345  }
00346 
00347  // Loop over elements in lower vertical transition region
00348  // --------------------------------------------------------
00349  {
00350   for (unsigned i=0;i<nhalf;i++)
00351    {
00352     // Loop over elements vertically
00353     for (unsigned j=0;j<nh;j++)
00354      {
00355       // Work out element number in overall mesh
00356       unsigned e=n_prev_elements+i*(nh+1)+j;
00357       
00358       // Get pointer to element
00359       FiniteElement* el_pt = this->finite_element_pt(e);
00360             
00361       // Loop over its nodes
00362       for (unsigned i0=0;i0<np;i0++)
00363        {
00364         for (unsigned i1=0;i1<np;i1++)
00365          {
00366           // Node number:
00367           unsigned n=i0*np+i1;
00368           
00369           // Get spine node
00370           SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(n));
00371           
00372           // Set update id
00373           nod_pt->node_update_fct_id()=2;
00374           
00375           // Provide spine with additional storage for fraction along vertical
00376           // line
00377           if (i0==0)
00378            {
00379             // Get position vectors to wall
00380             zeta[0] = Zeta_transition_end;
00381             // Get the sub geometric objects
00382             Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
00383             Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
00384 
00385             lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
00386             upper_sub_geom_object_pt->position(s_up,r_wall_up);
00387 
00388             // Set vertical fraction
00389             double vertical_fraction=
00390              (double(i)+double(i1)/double(np-1))/double(2.0*nhalf);
00391 
00392             //Add the geometric parameters in order
00393             Vector<double> parameters(5);
00394             parameters[0] = s_lo[0];
00395             parameters[1] = s_up[0];
00396             parameters[2] = vertical_fraction;
00397             parameters[3] = s_transition_lo[0];
00398             parameters[4] = s_transition_up[0];
00399             nod_pt->spine_pt()->set_geom_parameter(parameters);
00400 
00401             // Origin of spine
00402             Vector<double> S0(2);
00403             S0[0] = r_wall_lo[0] + 
00404              vertical_fraction*(r_wall_up[0]-r_wall_lo[0]);
00405             S0[1] = r_wall_lo[1] + 
00406              vertical_fraction*(r_wall_up[1]-r_wall_lo[1]);
00407             
00408             // Get normal vector towards origin
00409             Vector<double> N(2);
00410             N[0] = spine_centre[0] - S0[0];
00411             N[1] = spine_centre[1] - S0[1];
00412 
00413             double length=sqrt(N[0]*N[0]+N[1]*N[1]);
00414             nod_pt->spine_pt()->height()=length-radius;
00415 
00416             // Lower and Upper wall sub geom objects affect  spine:
00417             Vector<GeomObject*> geom_object_pt(4);
00418             geom_object_pt[0] = lower_sub_geom_object_pt;
00419             geom_object_pt[1] = upper_sub_geom_object_pt;
00420             geom_object_pt[2] = lower_transition_geom_object_pt;
00421             geom_object_pt[3] = upper_transition_geom_object_pt;
00422 
00423             // Pass geom object(s) to spine
00424             nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
00425 
00426             //Push the node back onto boundaries
00427             if (j==0) set_boundary_node_pt[1].insert(nod_pt);
00428            }
00429          }
00430        }
00431      }
00432    }
00433    
00434   // Increment number of previous elements
00435   n_prev_elements+=nhalf*(nh+1);
00436  }
00437 
00438 
00439  // Loop over elements in upper vertical transition region
00440  // ------------------------------------------------------
00441  {
00442   for (unsigned i=0;i<nhalf;i++)
00443    {
00444     // Loop over elements vertically
00445     for (unsigned j=0;j<nh;j++)
00446      {
00447       // Work out element number in overall mesh
00448       unsigned e=n_prev_elements+i*(nh+1)+j;
00449       
00450       // Get pointer to element
00451       FiniteElement* el_pt = this->finite_element_pt(e);
00452     
00453       // Loop over its nodes
00454       for (unsigned i0=0;i0<np;i0++)
00455        {
00456         for (unsigned i1=0;i1<np;i1++)
00457          {
00458           // Node number:
00459           unsigned n=i0*np+i1;
00460           
00461           // Get spine node
00462           SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(n));
00463           
00464           // Set update id
00465           nod_pt->node_update_fct_id()=3;
00466           
00467           // Provide spine with additional storage for fraction along vertical
00468           // line
00469           if (i0==0)
00470            {
00471             // Get position vectors to wall
00472             zeta[0] = Zeta_transition_end;
00473             // Get the sub geometric objects
00474             Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
00475             Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
00476             
00477             lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
00478             upper_sub_geom_object_pt->position(s_up,r_wall_up);
00479         
00480             // Set vertical fraction
00481             double vertical_fraction=0.5 +
00482              (double(i)+double(i1)/double(np-1))/double(2.0*nhalf);
00483             
00484             //Add the geometric parameters in order
00485             Vector<double> parameters(5);
00486             parameters[0] = s_lo[0];
00487             parameters[1] = s_up[0];
00488             parameters[2] = vertical_fraction;
00489             parameters[3] = s_transition_lo[0];
00490             parameters[4] = s_transition_up[0];
00491             nod_pt->spine_pt()->set_geom_parameter(parameters);
00492 
00493             // Origin of spine
00494             Vector<double> S0(2);
00495             S0[0] = r_wall_lo[0] + 
00496              vertical_fraction*(r_wall_up[0]-r_wall_lo[0]);
00497             S0[1] = r_wall_lo[1] + 
00498              vertical_fraction*(r_wall_up[1]-r_wall_lo[1]);
00499             
00500             // Get normal vector towards origin
00501             Vector<double> N(2);
00502             N[0] = spine_centre[0] - S0[0];
00503             N[1] = spine_centre[1] - S0[1];
00504 
00505             double length=sqrt(N[0]*N[0]+N[1]*N[1]);
00506             nod_pt->spine_pt()->height()=length-radius;    
00507 
00508             // Upper and Lower wall geom objects affect spine
00509             Vector<GeomObject*> geom_object_pt(4);
00510             geom_object_pt[0] = lower_sub_geom_object_pt;
00511             geom_object_pt[1] = upper_sub_geom_object_pt;
00512             geom_object_pt[2] = lower_transition_geom_object_pt;
00513             geom_object_pt[3] = upper_transition_geom_object_pt;
00514 
00515             // Pass geom object(s) to spine
00516             nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
00517 
00518             //Push the node back onto boundaries
00519             if (j==0) set_boundary_node_pt[1].insert(nod_pt);
00520            }
00521          }
00522        }
00523      }
00524    }
00525   // Increment number of previous elements
00526   n_prev_elements+=nhalf*(nh+1);
00527  }
00528 
00529 
00530  // Loop over elements in upper horizontal transition region
00531  // --------------------------------------------------------
00532  {
00533 
00534   // Increments in wall coordinate
00535   double dzeta_el=d/double(nx2);
00536   double dzeta_node=d/double(nx2*(np-1));
00537   
00538   // Loop over elements horizontally
00539   for (unsigned i=0;i<nx2;i++)
00540    {
00541     // Start of wall coordinate
00542     double zeta_lo = Zeta_transition_end - double(i)*dzeta_el;
00543     
00544     // Loop over elements vertically
00545     for (unsigned j=0;j<nh;j++)
00546      {
00547       // Work out element number in overall mesh
00548       unsigned e=n_prev_elements+i*(nh+1)+j;
00549       
00550       // Get pointer to element
00551       FiniteElement* el_pt = this->finite_element_pt(e);
00552       
00553       // Loop over its nodes
00554       for (unsigned i0=0;i0<np;i0++)
00555        {
00556         for (unsigned i1=0;i1<np;i1++)
00557          {
00558           // Node number:
00559           unsigned n=i0*np+i1;
00560           
00561           // Get spine node
00562           SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(n));
00563           
00564           // Set update id
00565           nod_pt->node_update_fct_id()=4;
00566           
00567           // Provide spine with additional storage for wall coordinate 
00568           if (i0==0)
00569            {
00570 
00571             //Get the Lagrangian coordinate in the Upper wall
00572             zeta[0] = zeta_lo - double(i1)*dzeta_node;
00573             // Get the sub geometric object and local coordinate
00574             Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
00575 
00576             // Pass geometric parameter to spine
00577             Vector<double> parameters(3);
00578             parameters[0] = s_up[0];
00579             parameters[1] = s_transition_lo[0];
00580             parameters[2] = s_transition_up[0];
00581             nod_pt->spine_pt()->set_geom_parameter(parameters);
00582             
00583             //Get position vector to wall
00584             upper_sub_geom_object_pt->position(s_up,r_wall_up);
00585             
00586             // Get normal vector towards origin
00587             Vector<double> N(2);
00588             N[0] = spine_centre[0] - r_wall_up[0];
00589             N[1] = spine_centre[1] - r_wall_up[1];
00590             double length = sqrt(N[0]*N[0]+N[1]*N[1]);
00591             nod_pt->spine_pt()->height()=length-radius;
00592 
00593             // upper wall sub geom object is one (and only) geom object
00594             // for spine:
00595             Vector<GeomObject*> geom_object_pt(3);
00596             geom_object_pt[0] = upper_sub_geom_object_pt;
00597             geom_object_pt[1] = lower_transition_geom_object_pt;
00598             geom_object_pt[2] = upper_transition_geom_object_pt;
00599 
00600             // Pass geom object(s) to spine
00601             nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
00602 
00603             //Push the node back onto boundaries
00604             if (j==0) set_boundary_node_pt[2].insert(nod_pt);
00605            }
00606          }
00607        }
00608      }
00609    }
00610   
00611   // Increment number of previous elements
00612   n_prev_elements+=nx2*(nh+1);
00613  }
00614 
00615 
00616  // Loop over elements in upper deposited film region
00617  // -------------------------------------------------
00618  {
00619   // Increments in wall coordinate
00620   double dzeta_el=llayer/double(nx1);
00621   double dzeta_node=llayer/double(nx1*(np-1));
00622  
00623   // Loop over elements horizontally
00624   for (unsigned i=0;i<nx1;i++)
00625    {
00626     // Start of wall coordinate
00627     double zeta_lo = Zeta_transition_start - double(i)*dzeta_el;
00628 
00629     // Loop over elements vertically
00630     for (unsigned j=0;j<nh;j++)
00631      {
00632       // Work out element number in overall mesh
00633       unsigned e=n_prev_elements+i*(nh+1)+j;
00634       
00635       // Get pointer to element
00636       FiniteElement* el_pt = this->finite_element_pt(e);
00637       
00638       // Loop over its nodes
00639       for (unsigned i0=0;i0<np;i0++)
00640        {
00641         for (unsigned i1=0;i1<np;i1++)
00642          {
00643           // Node number:
00644           unsigned n=i0*np+i1;
00645           
00646           // Get spine node
00647           SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(n));
00648           
00649           // Set update id
00650           nod_pt->node_update_fct_id()=5;
00651           
00652           // Provide spine with additional storage for wall coordinate 
00653           if (i0==0)
00654            {
00655 
00656             // Get the Lagrangian coordinate in the Upper wall
00657             zeta[0] = zeta_lo - double(i1)*dzeta_node;
00658             // Get the geometric object and local coordinate
00659             Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
00660 
00661             //The local coordinate is a geometric parameter
00662             Vector<double> parameters(1,s_up[0]);
00663             nod_pt->spine_pt()->set_geom_parameter(parameters);
00664 
00665             // Adjust spine height
00666             nod_pt->spine_pt()->height()=H;
00667 
00668             // upper sub geom object is one (and only) geom object
00669             // for spine:
00670             Vector<GeomObject*> geom_object_pt(1);
00671             geom_object_pt[0] = upper_sub_geom_object_pt;
00672 
00673             // Pass geom object(s) to spine
00674             nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
00675 
00676             //Push the node back onto boundaries
00677             if (j==0) set_boundary_node_pt[2].insert(nod_pt);
00678            }
00679          }
00680        }
00681      }
00682    }
00683  }
00684  
00685  // Wipe the boundary lookup schemes
00686  this->remove_boundary_nodes();
00687  this->set_nboundary(6);
00688 
00689  // Copy from sets to vectors
00690  for (unsigned ibound=0;ibound<6;ibound++)
00691   {
00692    typedef std::set<Node*>::iterator IT;
00693    for (IT it=set_boundary_node_pt[ibound].begin();
00694         it!=set_boundary_node_pt[ibound].end();it++)
00695     {
00696      this->add_boundary_node(ibound,*it);
00697     }
00698   }
00699 
00700 
00701 
00702  //Loop over the free surface boundary (4) and set a boundary coordinate
00703  {
00704   //Boundary coordinate
00705   Vector<double> zeta(1);
00706   unsigned n_boundary_node = this->nboundary_node(4);
00707   for(unsigned n=0;n<n_boundary_node;++n)
00708    {
00709     zeta[0] = this->boundary_node_pt(4,n)->x(0);
00710     this->boundary_node_pt(4,n)->set_coordinates_on_boundary(4,zeta);
00711    }
00712  }
00713 
00714 
00715 
00716  // Now add the rectangular mesh in the channel ahead of the finger tip
00717  //--------------------------------------------------------------------
00718 
00719  // Build a temporary version of a SimpleRectangularQuadMesh as
00720  // a unit square
00721  SimpleRectangularQuadMesh<ELEMENT>* aux_mesh_pt=
00722   new SimpleRectangularQuadMesh<ELEMENT>
00723   (Nx3,2*nhalf,1.0,1.0,time_stepper_pt);
00724  
00725  //Wipe the boundary information in the auxilliary mesh
00726  aux_mesh_pt->remove_boundary_nodes();
00727 
00728 // Copy all nodes in the auxiliary mesh into a set (from where they
00729 // can easily be removed)
00730  nnod=aux_mesh_pt->nnode(); 
00731  std::set<Node*> aux_node_pt;
00732  for (unsigned i=0;i<nnod;i++)
00733   {
00734    aux_node_pt.insert(aux_mesh_pt->node_pt(i));
00735   }
00736 
00737 // Loop over elements in first column and set pointers
00738 // to the nodes in their first column to the ones that already exist
00739 
00740 // Boundary node number for first node in element
00741  unsigned first_bound_node=0;
00742  
00743  // Loop over elements
00744  for (unsigned e=0;e<2*nhalf;e++)
00745   {
00746    FiniteElement* el_pt=aux_mesh_pt->finite_element_pt(e*Nx3);
00747    // Loop over first column of nodes
00748    for (unsigned i=0;i<np;i++)
00749      {
00750       // Node number in element
00751       unsigned n=i*np;
00752       // Remove node from set and kill it
00753       if ((e<1)||(i>0))
00754        {
00755         aux_node_pt.erase(el_pt->node_pt(n));
00756         delete el_pt->node_pt(n);
00757        }
00758       // Set pointer to existing node
00759       el_pt->node_pt(n) = this->boundary_node_pt(1,first_bound_node+i);
00760      }
00761 
00762    // Increment first node number
00763    first_bound_node+=np-1;
00764   }
00765 
00766  // Now add all the remaining nodes in the auxiliary mesh 
00767  // to the actual one
00768  typedef std::set<Node*>::iterator IT;
00769  for (IT it=aux_node_pt.begin();it!=aux_node_pt.end();it++)
00770   {
00771    this->Node_pt.push_back(*it);
00772   }
00773 
00774  // Store number of elements before the new bit gets added:
00775  unsigned nelement_orig = this->Element_pt.size();
00776 
00777  // Add the elements to the actual mesh
00778  unsigned nelem=aux_mesh_pt->nelement();
00779  for (unsigned e=0;e<nelem;e++)
00780   {
00781    this->Element_pt.push_back(aux_mesh_pt->element_pt(e));
00782    //Don't forget to add them to the bulk
00783    this->Bulk_element_pt.push_back(aux_mesh_pt->finite_element_pt(e));
00784   }
00785 
00786  // Now wipe the boundary node storage scheme for the
00787  // nodes that used to be at the end of the domain:
00788  this->remove_boundary_nodes(1);
00789 
00790 
00791  //FIRST SPINE
00792  //-----------
00793 
00794  //Element 0
00795  //Node 0
00796  //Assign the new spine with unit height (pinned dummy -- never used)
00797  Spine* new_spine_pt=new Spine(1.0);
00798  this->Spine_pt.push_back(new_spine_pt);
00799  new_spine_pt->spine_height_pt()->pin(0);
00800 
00801  // Get pointer to node
00802  SpineNode* nod_pt = this->element_node_pt(nelement_orig+0,0);
00803  //Set the pointer to node
00804  nod_pt->spine_pt() = new_spine_pt;
00805  //Set the fraction
00806  nod_pt->fraction() = 0.0;
00807  // Pointer to the mesh that implements the update fct
00808  nod_pt->spine_mesh_pt() = this; 
00809  // ID for the update function
00810  nod_pt->node_update_fct_id() = 6; 
00811 
00812  //Need to get the local coordinates for the upper and lower wall
00813  zeta[0] = Zeta_transition_end;
00814  // Get the sub geometric objects
00815  Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
00816  Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
00817  
00818  lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
00819  upper_sub_geom_object_pt->position(s_up,r_wall_up);
00820 
00821  // Pass additional data to spine
00822  Vector<double> parameters(2); 
00823  parameters[0] = s_lo[0]; 
00824  parameters[1] = s_up[0];
00825  new_spine_pt->set_geom_parameter(parameters);
00826  
00827  // Lower and upper wall sub geom objects affect update
00828  // for spine:
00829  Vector<GeomObject*> geom_object_pt(2);
00830  geom_object_pt[0] = lower_sub_geom_object_pt;
00831  geom_object_pt[1] = upper_sub_geom_object_pt;
00832  
00833  // Pass geom object(s) to spine
00834  new_spine_pt->set_geom_object_pt(geom_object_pt);
00835  
00836  //Loop vertically along the spine
00837  //Loop over the elements 
00838  for(unsigned long i=0;i<2*nhalf;i++)
00839   {
00840    //Loop over the vertical nodes, apart from the first
00841    for(unsigned l1=1;l1<np;l1++)
00842     {
00843      // Get pointer to node
00844      SpineNode* nod_pt = this->element_node_pt(nelement_orig+i*Nx3,l1*np);
00845      //Set the pointer to the spine
00846      nod_pt->spine_pt() = new_spine_pt;
00847      //Set the fraction
00848      nod_pt->fraction() =(double(i)+double(l1)/double(np-1))/double(2*nhalf);
00849      // Pointer to the mesh that implements the update fct
00850      nod_pt->spine_mesh_pt() = this; 
00851      // ID for the update function
00852       nod_pt->node_update_fct_id() = 6; 
00853     }
00854   }
00855 
00856 
00857  //LOOP OVER OTHER SPINES
00858  //----------------------
00859 
00860  //Now loop over the elements horizontally
00861  for(unsigned long j=0;j<Nx3;j++)
00862   {
00863    //Loop over the nodes in the elements horizontally, ignoring 
00864    //the first column
00865    for(unsigned l2=1;l2<np;l2++)
00866     {
00867      //Assign the new spine with unit height (pinned dummy; never used)
00868      new_spine_pt=new Spine(1.0);
00869      this->Spine_pt.push_back(new_spine_pt);
00870      new_spine_pt->spine_height_pt()->pin(0);
00871 
00872      // Get the node
00873      SpineNode* nod_pt = this->element_node_pt(nelement_orig+j,l2);
00874      //Set the pointer to the spine
00875      nod_pt->spine_pt() = new_spine_pt;
00876      //Set the fraction
00877      nod_pt->fraction() = 0.0;
00878      // Pointer to the mesh that implements the update fct
00879      nod_pt->spine_mesh_pt() = this; 
00880      // ID for the update function
00881      nod_pt->node_update_fct_id() = 6; 
00882      
00883      // Add to boundary lookup scheme
00884      this->add_boundary_node(0,nod_pt);
00885      if ((j==Nx3-1)&&(l2==np-1))
00886       {
00887        this->add_boundary_node(1,nod_pt);
00888       }
00889 
00890      // Increment in wall coordinate
00891      double dzeta_el=(Zeta_end-Zeta_transition_end)/double(Nx3);
00892      double dzeta_nod=dzeta_el/double(np-1);
00893 
00894      // Get wall coordinate
00895      zeta[0] = Zeta_transition_end + j*dzeta_el + l2*dzeta_nod;
00896      
00897      // Get the sub geometric objects
00898      Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
00899      Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
00900      
00901      lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
00902      upper_sub_geom_object_pt->position(s_up,r_wall_up);
00903           
00904      // Add geometric parameters to spine
00905      Vector<double> parameters(2); 
00906      parameters[0] = s_lo[0]; 
00907      parameters[1] = s_up[0];
00908      new_spine_pt->set_geom_parameter(parameters);
00909      
00910      // Lower and upper sub geom objects affect update
00911      // for spine:
00912      Vector<GeomObject*> geom_object_pt(2);
00913      geom_object_pt[0] = lower_sub_geom_object_pt;
00914      geom_object_pt[1] = upper_sub_geom_object_pt;
00915      
00916      // Pass geom object(s) to spine
00917      new_spine_pt->set_geom_object_pt(geom_object_pt);
00918  
00919 
00920      //Loop vertically along the spine
00921      //Loop over the elements 
00922      for(unsigned long i=0;i<2*nhalf;i++)
00923       {
00924        //Loop over the vertical nodes, apart from the first
00925        for(unsigned l1=1;l1<np;l1++)
00926         {
00927          // Get node
00928          SpineNode* nod_pt = 
00929           this->element_node_pt(nelement_orig+i*Nx3+j,l1*np+l2);
00930          //Set the pointer to the spine
00931          nod_pt->spine_pt() = new_spine_pt;
00932          //Set the fraction
00933          nod_pt->fraction()=
00934           (double(i)+double(l1)/double(np-1))/double(2*nhalf);
00935          // Pointer to the mesh that implements the update fct
00936          nod_pt->spine_mesh_pt() = this; 
00937          // ID for the update function
00938          nod_pt->node_update_fct_id() = 6; 
00939 
00940          // Add to boundary lookup scheme
00941          if ((j==Nx3-1)&&(l2==np-1))
00942           {
00943            this->add_boundary_node(1,nod_pt);
00944           }
00945 
00946          // Add to boundary lookup scheme
00947          if ((i==2*nhalf-1)&&(l1==np-1))
00948           {
00949            this->add_boundary_node(2,nod_pt);
00950           }
00951 
00952         }  
00953       }
00954     }
00955   }
00956   
00957  // (Re-)setup lookup scheme that establishes which elements are located
00958  // on the mesh boundaries
00959  this->setup_boundary_element_info();
00960  
00961  // Flush the storage for elements and nodes in the auxiliary mesh
00962  // so it can be safely deleted
00963  aux_mesh_pt->flush_element_and_node_storage();
00964 
00965  // Kill the auxiliary mesh
00966  delete aux_mesh_pt;
00967 
00968 }
00969  
00970 
00971 //======================================================================
00972 /// Reorder elements: Vertical stacks of elements, each topped by
00973 /// their interface element -- this is (currently) identical to the
00974 /// version in the SingleLayerSpineMesh but it's important 
00975 /// that element reordering is maintained in exactly this form
00976 /// so to be on the safe side, we move the function in here.
00977 //======================================================================
00978 template<class ELEMENT, class INTERFACE_ELEMENT>
00979 void BrethertonSpineMesh<ELEMENT,INTERFACE_ELEMENT>::initial_element_reorder()
00980 {
00981  unsigned Nx = this->Nx;
00982  unsigned Ny = this->Ny;
00983  //Find out how many elements there are
00984  unsigned long Nelement = this->nelement();
00985  //Find out how many fluid elements there are
00986  unsigned long Nfluid = Nx*Ny;
00987  //Create a dummy array of elements
00988  Vector<FiniteElement *> dummy;
00989 
00990  //Loop over the elements in horizontal order
00991  for(unsigned long j=0;j<Nx;j++)
00992   {
00993    //Loop over the elements in lower layer vertically
00994    for(unsigned long i=0;i<Ny;i++)
00995     {
00996      //Push back onto the new stack
00997      dummy.push_back(this->finite_element_pt(Nx*i + j));
00998     }
00999 
01000    //Push back the line element onto the stack
01001    dummy.push_back(this->finite_element_pt(Nfluid+j));
01002   }
01003 
01004  //Now copy the reordered elements into the element_pt
01005  for(unsigned long e=0;e<Nelement;e++)
01006   {
01007    this->Element_pt[e] = dummy[e];
01008   }
01009 
01010 }
01011 
01012 //=======================================================================
01013 /// Calculate the distance from the spine base to the free surface, i.e.
01014 /// the spine height.
01015 //=======================================================================
01016 template<class ELEMENT, class INTERFACE_ELEMENT>
01017 double BrethertonSpineMesh<ELEMENT,INTERFACE_ELEMENT>::
01018 find_distance_to_free_surface(GeomObject* const &fs_geom_object_pt,
01019                               Vector<double> &initial_zeta,
01020                               const Vector<double> &spine_base, 
01021                               const Vector<double> &spine_end)
01022 {
01023 
01024  //Now we need to find the intersection points
01025  double lambda = 0.5;
01026 
01027  Vector<double> dx(2);
01028  Vector<double> new_free_x(2);
01029  DenseDoubleMatrix jacobian(2,2,0.0);
01030  Vector<double> spine_x(2);
01031  Vector<double> free_x(2);
01032 
01033  double maxres = 100.0;
01034 
01035  unsigned count=0;
01036   //Let's Newton method it
01037  do
01038  {
01039   count++;
01040   //Find the spine's location
01041   for(unsigned i=0;i<2;++i) {spine_x[i] = spine_base[i] + 
01042                               lambda*(spine_end[i] - spine_base[i]);}
01043   
01044   //Find the free_surface location
01045   fs_geom_object_pt->position(initial_zeta,free_x);
01046   
01047   for(unsigned i=0;i<2;++i) {dx[i] = spine_x[i] - free_x[i];}
01048 
01049   //Calculate the entries of the jacobian matrix
01050   jacobian(0,0) = (spine_end[0] - spine_base[0]);
01051   jacobian(1,0) = (spine_end[1] - spine_base[1]);
01052   
01053   //Calculate the others by finite differences
01054   double FD_Jstep = 1.0e-6;
01055   double old_zeta = initial_zeta[0];
01056   initial_zeta[0] += FD_Jstep;
01057   fs_geom_object_pt->position(initial_zeta,new_free_x);
01058   
01059   for(unsigned i=0;i<2;++i) 
01060    {jacobian(i,1) = (free_x[i] - new_free_x[i])/FD_Jstep;}
01061   
01062   //Now let's solve the damn thing
01063   jacobian.solve(dx);
01064   
01065   lambda -= dx[0]; initial_zeta[0] = old_zeta - dx[1];
01066   
01067   //How are we doing
01068   
01069   for(unsigned i=0;i<2;++i) {spine_x[i] = spine_base[i] + 
01070                               lambda*(spine_end[i] - spine_base[i]);}
01071   fs_geom_object_pt->position(initial_zeta,free_x);
01072   
01073   for(unsigned i=0;i<2;++i) {dx[i] = spine_x[i] - free_x[i];}
01074   maxres = std::abs(dx[0]) > std::abs(dx[1]) ? std::abs(dx[0]) : 
01075    std::abs(dx[1]);
01076 
01077   if(count > 100) 
01078    {
01079     throw OomphLibError("Failed to converge after 100 steps",
01080                         "BrethertonSpineMesh::find_distance_to_free_surface()",
01081                         OOMPH_EXCEPTION_LOCATION);
01082    }
01083 
01084  } while(maxres > 1.0e-8);
01085 
01086 
01087  oomph_info << "DONE " << initial_zeta[0] << std::endl;
01088  double spine_length = sqrt(pow((spine_base[0] - spine_end[0]),2.0)
01089                             + pow((spine_base[1] - spine_end[1]),2.0));
01090   
01091  return (lambda*spine_length); // Divided by spine length
01092 }
01093 
01094 //=======================================================================
01095 /// Reposition the spines that emenate from the lower wall
01096 //=======================================================================
01097 template<class ELEMENT, class INTERFACE_ELEMENT>
01098 void BrethertonSpineMesh<ELEMENT,INTERFACE_ELEMENT>::reposition_spines(
01099  const double &zeta_lo_transition_start,
01100  const double &zeta_lo_transition_end,
01101  const double &zeta_up_transition_start,
01102  const double &zeta_up_transition_end)
01103 {
01104  //Firstly create a geometric object of the free surface
01105  Mesh* fs_mesh_pt = new Mesh;
01106  this->template build_face_mesh<ELEMENT,FaceElementAsGeomObject>
01107   (4,fs_mesh_pt);
01108  
01109  //Loop over these new face elements and set the boundary number
01110  //of the bulk mesh
01111  unsigned n_face_element = fs_mesh_pt->nelement();
01112  //Loop over the elements
01113  for(unsigned e=0;e<n_face_element;e++)
01114   {
01115    //Cast the element pointer to the correct thing!
01116    dynamic_cast<FaceElementAsGeomObject<ELEMENT>*>
01117     (fs_mesh_pt->element_pt(e))->set_boundary_number_in_bulk_mesh(4);
01118   }
01119  
01120  //Now make a single geometric object that represents the collection of 
01121  //geometric objects that form the boundary of the bulk mesh. Two
01122  //Eulerian coordinates, one intrinsic coordinate.
01123  MeshAsGeomObject<1,2,FaceElementAsGeomObject<ELEMENT> >* 
01124   fs_geom_object_pt = 
01125   new MeshAsGeomObject<1,2,FaceElementAsGeomObject<ELEMENT> >
01126   (fs_mesh_pt);
01127   
01128 
01129  // Length of deposited film region
01130  double llayer_lower = zeta_lo_transition_start - Zeta_start;
01131  double llayer_upper = zeta_up_transition_start - Zeta_start;
01132 
01133  // Length of transition region
01134  double d_lower = zeta_lo_transition_end - zeta_lo_transition_start;
01135  double d_upper = zeta_up_transition_end - zeta_up_transition_start;
01136 
01137  // Work out radius of circular cap from lower and upper wall
01138  Vector<double> r_wall_lo(2), r_wall_up(2);
01139  Vector<double> zeta(1), s_lo(1), s_up(1);
01140  GeomObject *lower_sub_geom_object_pt=0, *upper_sub_geom_object_pt=0;
01141 
01142  GeomObject *lower_transition_geom_object_pt=0;
01143  GeomObject *upper_transition_geom_object_pt=0;
01144  Vector<double> s_transition_lo(1), s_transition_up(1);
01145  Vector<double> spine_centre(2);
01146 
01147  // Get number of nodes along element edge
01148  unsigned np = this->finite_element_pt(0)->nnode_1d();
01149 
01150  //Calculate the centre for the spine nodes in the transition region
01151  {
01152   //Get the geometric objects on the walls at the start of the transition
01153   //region
01154   //Lower wall
01155   zeta[0] = zeta_lo_transition_start;
01156   Lower_wall_pt->locate_zeta(zeta,lower_transition_geom_object_pt,
01157                              s_transition_lo);
01158   //Upper wall
01159   zeta[0] = zeta_up_transition_start;
01160   Upper_wall_pt->locate_zeta(zeta,upper_transition_geom_object_pt,
01161                              s_transition_up);
01162   
01163   //Find the Eulerian coordinates of the walls at the transition region
01164   lower_transition_geom_object_pt->position(s_transition_lo,r_wall_lo);
01165   upper_transition_geom_object_pt->position(s_transition_up,r_wall_up);
01166 
01167   //Take the average of these positions to define the origin of the spines in
01168   //the transition region
01169   //Horizontal position is always halfway
01170   spine_centre[0] = 0.5*(r_wall_lo[0] + r_wall_up[0]);
01171   
01172   //Vertical Position is given by a specified fraction
01173   //between the upper and lower walls
01174   spine_centre[1] = r_wall_lo[1] + 
01175      spine_centre_fraction()*(r_wall_up[1] - r_wall_lo[1]);
01176  }
01177 
01178 
01179  // Initialise number of elements in previous regions:
01180  unsigned n_prev_elements=0;
01181 
01182  // Storage for the end of the spines
01183  Vector<double> spine_end(2);
01184  Vector<double> fs_zeta(1,0.0);
01185 
01186  // Loop over elements in lower deposited film region
01187  // -------------------------------------------------
01188  {
01189   oomph_info << "LOWER FILM " << std::endl;
01190   // Increments in wall coordinate
01191   double dzeta_el = llayer_lower/double(Nx1);
01192   double dzeta_node = llayer_lower/double(Nx1*(np-1));
01193 
01194   // Loop over elements horizontally
01195   for(unsigned i=0;i<Nx1;i++)
01196    {
01197     // Start of wall coordinate
01198     double zeta_lo = Zeta_start + double(i)*dzeta_el;
01199     
01200     //Work out element number in overall mesh
01201     unsigned e = n_prev_elements + i*(Nh+1);
01202 
01203     // Get pointer to lower element
01204     FiniteElement* el_pt = this->finite_element_pt(e);
01205     
01206     // Loop over its nodes "horizontally"
01207     for(unsigned i1=0;i1<(np-1);i1++)
01208      {
01209       // Get spine node
01210       SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(i1));
01211 
01212       // Get the Lagrangian coordinate in the Lower Wall
01213       zeta[0] =  zeta_lo + double(i1)*dzeta_node;
01214       //Reset the boundary coordinate
01215       nod_pt->set_coordinates_on_boundary(0,zeta);
01216       //Get the geometric object and local coordinate
01217       Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
01218       
01219       //The local coordinate is a geometric parameter
01220       //This needs to be set (rather than added) because the
01221       //same spine may be visited more than once
01222       Vector<double> parameters(1,s_lo[0]);
01223       nod_pt->spine_pt()->set_geom_parameter(parameters);
01224       
01225       // The sub geom object is one (and only) geom object
01226       // for spine:
01227       Vector<GeomObject*> geom_object_pt(1);
01228       geom_object_pt[0] = lower_sub_geom_object_pt;
01229       
01230       // Pass geom object(s) to spine
01231       nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01232       
01233       //Get the wall position at the bottom of the spine
01234       lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
01235       //The end of the spine is vertically above the base
01236       spine_end[0] = r_wall_lo[0];
01237       spine_end[1] = spine_centre[1];
01238       nod_pt->spine_pt()->height() = 
01239        find_distance_to_free_surface(fs_geom_object_pt,fs_zeta,r_wall_lo,spine_end);
01240      }
01241    }
01242 
01243   // Increment number of previous elements
01244   n_prev_elements += Nx1*(Nh+1);
01245  }
01246 
01247 
01248  // Loop over elements in lower horizontal transition region
01249  // --------------------------------------------------------
01250  {
01251   oomph_info << "LOWER HORIZONTAL TRANSITION " << std::endl;
01252   // Increments in wall coordinate
01253   double dzeta_el=d_lower/double(Nx2);
01254   double dzeta_node=d_lower/double(Nx2*(np-1));
01255   
01256   // Loop over elements horizontally
01257   for (unsigned i=0;i<Nx2;i++)
01258    {
01259     // Start of wall coordinate
01260     double zeta_lo = zeta_lo_transition_start + double(i)*dzeta_el;
01261     
01262     // Work out element number in overall mesh
01263     unsigned e=n_prev_elements+i*(Nh+1);
01264     
01265     // Get pointer to element
01266     FiniteElement* el_pt = this->finite_element_pt(e);
01267     
01268     // Loop over its nodes
01269     for (unsigned i1=0;i1<(np-1);i1++)
01270      {
01271       // Get spine node
01272       SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(i1));
01273       
01274       // Get the Lagrangian coordinate in the Lower Wall
01275       zeta[0] = zeta_lo + double(i1)*dzeta_node;
01276       //Reset the boundary coordinate
01277       nod_pt->set_coordinates_on_boundary(0,zeta);
01278       // Get the sub geometric object and local coordinate
01279       Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
01280        
01281       // Pass geometric parameter to the spine
01282       Vector<double> parameters(3);
01283       parameters[0] = s_lo[0];
01284       parameters[1] = s_transition_lo[0];
01285       parameters[2] = s_transition_up[0];
01286       nod_pt->spine_pt()->set_geom_parameter(parameters);
01287 
01288       // Lower sub geom object is one (and only) geom object
01289       // for spine:
01290       Vector<GeomObject*> geom_object_pt(3);
01291       geom_object_pt[0] = lower_sub_geom_object_pt;
01292       geom_object_pt[1] = lower_transition_geom_object_pt;
01293       geom_object_pt[2] = upper_transition_geom_object_pt;
01294       
01295       // Pass geom object(s) to spine
01296       nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01297       
01298       // Get position vector to wall
01299       lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
01300       //The end of the spine is the spine centre,so the height is easy(ish)
01301       nod_pt->spine_pt()->height() =
01302        find_distance_to_free_surface(fs_geom_object_pt,fs_zeta,r_wall_lo,spine_centre);
01303      }
01304    }
01305 
01306   // Increment number of previous elements
01307   n_prev_elements += Nx2*(Nh+1);
01308  }
01309 
01310  // Loop over elements in lower vertical transition region
01311  // --------------------------------------------------------
01312  {
01313   oomph_info << "LOWER VERTICAL TRANSITION " << std::endl;
01314   for (unsigned i=0;i<Nhalf;i++)
01315    {
01316     // Work out element number in overall mesh
01317     unsigned e = n_prev_elements+i*(Nh+1);
01318     
01319     // Get pointer to element
01320     FiniteElement* el_pt = this->finite_element_pt(e);
01321             
01322     // Loop over its nodes
01323     for (unsigned i1=0;i1<(np-1);i1++)
01324      {
01325       // Get spine node
01326       //Note that I have to loop over the second row of nodes
01327       //because the first row are updated in region 6 and so
01328       //you get the wrong spines from them (doh!)
01329       SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(np+i1));
01330       
01331       // Get position vectors to wall
01332       zeta[0] = zeta_lo_transition_end;
01333       // Get the sub geometric objects
01334       Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
01335       zeta[0] = zeta_up_transition_end;
01336       Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
01337       
01338       lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
01339       upper_sub_geom_object_pt->position(s_up,r_wall_up);
01340       
01341       // Set vertical fraction
01342       double vertical_fraction=
01343        (double(i)+double(i1)/double(np-1))/double(2.0*Nhalf);
01344       
01345       //Add the geometric parameters in order
01346       Vector<double> parameters(5);
01347       parameters[0] = s_lo[0];
01348       parameters[1] = s_up[0];
01349       parameters[2] = vertical_fraction;
01350       parameters[3] = s_transition_lo[0];
01351       parameters[4] = s_transition_up[0];
01352       nod_pt->spine_pt()->set_geom_parameter(parameters);
01353 
01354       // Origin of spine
01355       Vector<double> S0(2);
01356       S0[0] = r_wall_lo[0] + 
01357        vertical_fraction*(r_wall_up[0]-r_wall_lo[0]);
01358       S0[1] = r_wall_lo[1] + 
01359        vertical_fraction*(r_wall_up[1]-r_wall_lo[1]);
01360 
01361       // Lower and Upper wall sub geom objects affect  spine:
01362       Vector<GeomObject*> geom_object_pt(4);
01363       geom_object_pt[0] = lower_sub_geom_object_pt;
01364       geom_object_pt[1] = upper_sub_geom_object_pt;
01365       geom_object_pt[2] = lower_transition_geom_object_pt;
01366       geom_object_pt[3] = upper_transition_geom_object_pt;
01367       
01368       // Pass geom object(s) to spine
01369       nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01370 
01371       //Calculate the spine height
01372       nod_pt->spine_pt()->height() = 
01373        find_distance_to_free_surface(fs_geom_object_pt,fs_zeta,S0,spine_centre);
01374      }
01375    }
01376    
01377   // Increment number of previous elements
01378   n_prev_elements+=Nhalf*(Nh+1);
01379  }
01380 
01381 
01382  // Loop over elements in upper vertical transition region
01383  // --------------------------------------------------------
01384  {
01385   oomph_info << "UPPER VERTICAL TRANSITION" << std::endl;
01386   for (unsigned i=0;i<Nhalf;i++)
01387    {
01388     // Work out element number in overall mesh
01389     unsigned e = n_prev_elements+i*(Nh+1);
01390     
01391     // Get pointer to element
01392     FiniteElement* el_pt = this->finite_element_pt(e);
01393             
01394     // Loop over its nodes
01395     for (unsigned i1=0;i1<(np-1);i1++)
01396      {
01397       // Get spine node
01398       //Note that I have to loop over the second row of nodes
01399       //because the first row are updated in region 6 and so
01400       //you get the wrong spines from them (doh!)
01401       SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(np+i1));
01402       
01403       // Get position vectors to wall
01404       zeta[0] = zeta_lo_transition_end;
01405       // Get the sub geometric objects
01406       Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
01407       zeta[0] = zeta_up_transition_end;
01408       Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
01409       
01410       lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
01411       upper_sub_geom_object_pt->position(s_up,r_wall_up);
01412             
01413       
01414       // Set vertical fraction
01415       double vertical_fraction= 0.5 + 
01416        (double(i)+double(i1)/double(np-1))/double(2.0*Nhalf);
01417       
01418       //Add the geometric parameters in order
01419       Vector<double> parameters(5);
01420       parameters[0] = s_lo[0];
01421       parameters[1] = s_up[0];
01422       parameters[2] = vertical_fraction;
01423       parameters[3] = s_transition_lo[0];
01424       parameters[4] = s_transition_up[0];
01425       nod_pt->spine_pt()->set_geom_parameter(parameters);
01426 
01427       // Origin of spine
01428       Vector<double> S0(2);
01429       S0[0] = r_wall_lo[0] + 
01430        vertical_fraction*(r_wall_up[0]-r_wall_lo[0]);
01431       S0[1] = r_wall_lo[1] + 
01432        vertical_fraction*(r_wall_up[1]-r_wall_lo[1]);
01433 
01434       // Lower and Upper wall sub geom objects affect  spine:
01435       Vector<GeomObject*> geom_object_pt(4);
01436       geom_object_pt[0] = lower_sub_geom_object_pt;
01437       geom_object_pt[1] = upper_sub_geom_object_pt;
01438       geom_object_pt[2] = lower_transition_geom_object_pt;
01439       geom_object_pt[3] = upper_transition_geom_object_pt;
01440       
01441       // Pass geom object(s) to spine
01442       nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01443       
01444       //Calculate the spine height
01445       nod_pt->spine_pt()->height() = 
01446        find_distance_to_free_surface(fs_geom_object_pt,fs_zeta,S0,spine_centre);
01447      }
01448    }
01449    
01450   // Increment number of previous elements
01451   n_prev_elements+=Nhalf*(Nh+1);
01452  }
01453 
01454   
01455  // Loop over elements in upper horizontal transition region
01456  // --------------------------------------------------------
01457  {
01458   oomph_info << "UPPER HORIZONTAL TRANSITION " << std::endl;
01459   // Increments in wall coordinate
01460   double dzeta_el=d_upper/double(Nx2);
01461   double dzeta_node=d_upper/double(Nx2*(np-1));
01462   
01463   // Loop over elements horizontally
01464   for (unsigned i=0;i<Nx2;i++)
01465    {
01466     // Start of wall coordinate
01467     double zeta_lo = zeta_up_transition_end - double(i)*dzeta_el;
01468     
01469     // Work out element number in overall mesh
01470     unsigned e=n_prev_elements+i*(Nh+1);
01471     
01472     // Get pointer to element
01473     FiniteElement* el_pt = this->finite_element_pt(e);
01474     
01475     // Loop over its nodes
01476     for (unsigned i1=0;i1<(np-1);i1++)
01477      {
01478       // Get spine node (same comment)
01479       SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(np+i1));
01480       
01481       // Get the Lagrangian coordinate in the Lower Wall
01482       zeta[0] = zeta_lo - double(i1)*dzeta_node;
01483       //Reset the boundary coordinate
01484       el_pt->node_pt(i1)->set_coordinates_on_boundary(2,zeta);
01485       // Get the sub geometric object and local coordinate
01486       Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
01487        
01488       // Pass geometric parameter to the spine
01489       Vector<double> parameters(3);
01490       parameters[0] = s_up[0];
01491       parameters[1] = s_transition_lo[0];
01492       parameters[2] = s_transition_up[0];
01493       nod_pt->spine_pt()->set_geom_parameter(parameters);
01494       
01495       // Lower sub geom object is one (and only) geom object
01496       // for spine:
01497       Vector<GeomObject*> geom_object_pt(3);
01498       geom_object_pt[0] = upper_sub_geom_object_pt;
01499       geom_object_pt[1] = lower_transition_geom_object_pt;
01500       geom_object_pt[2] = upper_transition_geom_object_pt;
01501       
01502       // Pass geom object(s) to spine
01503       nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01504 
01505   
01506       // Get position vector to wall
01507       upper_sub_geom_object_pt->position(s_up,r_wall_up);
01508       //Find spine height
01509       nod_pt->spine_pt()->height() = 
01510        find_distance_to_free_surface(fs_geom_object_pt,fs_zeta,r_wall_up,spine_centre);
01511 
01512      }
01513    }
01514 
01515   // Increment number of previous elements
01516   n_prev_elements += Nx2*(Nh+1);
01517  }
01518 
01519 
01520  // Loop over elements in upper deposited film region
01521  // -------------------------------------------------
01522  {
01523   oomph_info << "UPPER THIN FILM" << std::endl;
01524   // Increments in wall coordinate
01525   double dzeta_el=llayer_upper/double(Nx1);
01526   double dzeta_node=llayer_upper/double(Nx1*(np-1));
01527  
01528   // Loop over elements horizontally
01529   for (unsigned i=0;i<Nx1;i++)
01530    {
01531     // Start of wall coordinate
01532     double zeta_lo = zeta_up_transition_start - double(i)*dzeta_el;
01533     
01534     // Work out element number in overall mesh
01535     unsigned e=n_prev_elements+i*(Nh+1);
01536     
01537     // Get pointer to element
01538     FiniteElement* el_pt = this->finite_element_pt(e);
01539     
01540     //Loop over its nodes "horizontally"
01541     for (unsigned i1=0;i1<(np-1);i1++)
01542      {
01543       // Get spine node
01544       SpineNode* nod_pt=dynamic_cast<SpineNode*>(el_pt->node_pt(i1));
01545       
01546       // Get the Lagrangian coordinate in the Upper wall
01547       zeta[0] = zeta_lo - double(i1)*dzeta_node;
01548       //Reset coordinate on boundary
01549       nod_pt->set_coordinates_on_boundary(2,zeta);
01550       // Get the geometric object and local coordinate
01551       Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
01552       
01553       //The local coordinate is a geometric parameter
01554       Vector<double> parameters(1,s_up[0]);
01555       nod_pt->spine_pt()->set_geom_parameter(parameters);
01556 
01557       // upper sub geom object is one (and only) geom object
01558       // for spine:
01559       Vector<GeomObject*> geom_object_pt(1);
01560       geom_object_pt[0] = upper_sub_geom_object_pt;
01561       
01562       // Pass geom object(s) to spine
01563       nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01564  
01565       //Get the wall position at the bottom of the spine
01566       upper_sub_geom_object_pt->position(s_up,r_wall_up);
01567       spine_end[0] = r_wall_up[0];
01568       spine_end[1] = spine_centre[1];
01569       //Find the new spine height
01570       nod_pt->spine_pt()->height() = 
01571        find_distance_to_free_surface(fs_geom_object_pt,fs_zeta,
01572                                      r_wall_up,spine_end);      
01573      }
01574    }
01575 
01576 
01577   // Increment number of previous elements
01578   n_prev_elements += Nx1*(Nh+1);
01579  }
01580 
01581 
01582  //Additional mesh
01583  { 
01584   unsigned e = n_prev_elements;
01585 
01586   // Get pointer to node
01587   SpineNode* nod_pt = this->element_node_pt(e,0);
01588   
01589   //Need to get the local coordinates for the upper and lower wall
01590   zeta[0] = zeta_lo_transition_end;
01591   // Get the sub geometric objects
01592   Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
01593   zeta[0] = zeta_up_transition_end; 
01594   Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
01595   
01596   lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
01597   upper_sub_geom_object_pt->position(s_up,r_wall_up);
01598   
01599   // Pass additional data to spine
01600   Vector<double> parameters(2); 
01601   parameters[0] = s_lo[0]; 
01602   parameters[1] = s_up[0];
01603   nod_pt->spine_pt()->set_geom_parameter(parameters);
01604   
01605   // Lower and upper wall sub geom objects affect update
01606   // for spine:
01607   Vector<GeomObject*> geom_object_pt(2);
01608   geom_object_pt[0] = lower_sub_geom_object_pt;
01609   geom_object_pt[1] = upper_sub_geom_object_pt;
01610   
01611   // Pass geom object(s) to spine
01612   nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01613   
01614  //LOOP OVER OTHER SPINES
01615  //----------------------
01616 
01617  //Now loop over the elements horizontally
01618  for(unsigned long j=0;j<Nx3;j++)
01619   {
01620    unsigned e = n_prev_elements + j;
01621 
01622    //Loop over the nodes in the elements horizontally, ignoring 
01623    //the first column
01624    for(unsigned l2=0;l2<np;l2++)
01625     {
01626      // Get pointer to node at the base of the spine
01627      SpineNode* nod_pt = this->element_node_pt(e,l2);
01628 
01629      // Increment in wall coordinate
01630      double dzeta_el_lower=(Zeta_end-zeta_lo_transition_end)/double(Nx3);
01631      double dzeta_nod_lower=dzeta_el_lower/double(np-1);
01632 
01633      double dzeta_el_upper=(Zeta_end-zeta_up_transition_end)/double(Nx3);
01634      double dzeta_nod_upper=dzeta_el_upper/double(np-1);
01635 
01636      // Get wall coordinate
01637      zeta[0] = zeta_lo_transition_end + j*dzeta_el_lower + l2*dzeta_nod_lower;
01638      //Reset the boundary coordinate
01639      nod_pt->set_coordinates_on_boundary(0,zeta);
01640      
01641      // Get the sub geometric objects
01642      Lower_wall_pt->locate_zeta(zeta,lower_sub_geom_object_pt,s_lo);
01643 
01644      zeta[0] = zeta_up_transition_end + j*dzeta_el_upper + l2*dzeta_nod_upper;
01645      //Reset the upper boundary coordinate
01646      this->element_node_pt(e+Nx3*(2*Nhalf-1),np*(np-1)+l2)
01647       ->set_coordinates_on_boundary(2,zeta);
01648      Upper_wall_pt->locate_zeta(zeta,upper_sub_geom_object_pt,s_up);
01649      
01650      lower_sub_geom_object_pt->position(s_lo,r_wall_lo);
01651      upper_sub_geom_object_pt->position(s_up,r_wall_up);
01652           
01653      // Add geometric parameters to spine
01654      Vector<double> parameters(2); 
01655      parameters[0] = s_lo[0]; 
01656      parameters[1] = s_up[0];
01657      nod_pt->spine_pt()->set_geom_parameter(parameters);
01658      
01659      // Lower and upper sub geom objects affect update
01660      // for spine:
01661      Vector<GeomObject*> geom_object_pt(2);
01662      geom_object_pt[0] = lower_sub_geom_object_pt;
01663      geom_object_pt[1] = upper_sub_geom_object_pt;
01664      
01665      // Pass geom object(s) to spine
01666      nod_pt->spine_pt()->set_geom_object_pt(geom_object_pt);
01667     }
01668   }
01669  }
01670 
01671 
01672  //Clean up all the memory
01673  //Can delete the Geometric object 
01674  delete fs_geom_object_pt;
01675  //Need to be careful with the FaceMesh, because we can't delete the nodes
01676  //Loop
01677   for(unsigned e=n_face_element;e>0;e--)
01678    {
01679     delete fs_mesh_pt->element_pt(e-1);
01680     fs_mesh_pt->element_pt(e-1) = 0;
01681    }
01682   //Now clear all element and node storage (should maybe fine-grain this)
01683   fs_mesh_pt->flush_element_and_node_storage();
01684   //Finally delete the mesh
01685   delete fs_mesh_pt;
01686 
01687 }
01688  
01689 }
01690 
01691 #endif

Generated on Mon Aug 10 11:23:45 2009 by  doxygen 1.4.7