action functions
|
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 if you wish to be informed of the library's "official" release. |
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
1.4.7