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 //Header file for refineable 2D quad Navier Stokes elements 00029 00030 #ifndef OOMPH_REFINEABLE_NAVIER_STOKES_ELEMENTS_HEADER 00031 #define OOMPH_REFINEABLE_NAVIER_STOKES_ELEMENTS_HEADER 00032 00033 // Config header generated by autoconfig 00034 #ifdef HAVE_CONFIG_H 00035 #include <oomph-lib-config.h> 00036 #endif 00037 00038 //Oomph-lib headers 00039 #include "../generic/refineable_quad_element.h" 00040 #include "../generic/refineable_brick_element.h" 00041 #include "../generic/error_estimator.h" 00042 #include "navier_stokes_elements.h" 00043 00044 namespace oomph 00045 { 00046 00047 00048 //====================================================================== 00049 /// Refineable version of the Navier--Stokes equations 00050 /// 00051 /// 00052 //====================================================================== 00053 template<unsigned DIM> 00054 class RefineableNavierStokesEquations : 00055 public virtual NavierStokesEquations<DIM>, 00056 public virtual RefineableElement, 00057 public virtual ElementWithZ2ErrorEstimator 00058 { 00059 protected: 00060 00061 /// \short Pointer to n_p-th pressure node (Default: NULL, 00062 /// indicating that pressure is not based on nodal interpolation). 00063 virtual Node* pressure_node_pt(const unsigned& n_p) {return NULL;} 00064 00065 /// \short Unpin all pressure dofs in the element 00066 virtual void unpin_elemental_pressure_dofs()=0; 00067 00068 /// \short Pin unused nodal pressure dofs (empty by default, because 00069 /// by default pressure dofs are not associated with nodes) 00070 virtual void pin_elemental_redundant_nodal_pressure_dofs(){} 00071 00072 public: 00073 00074 /// \short Constructor 00075 RefineableNavierStokesEquations() : 00076 NavierStokesEquations<DIM>(), 00077 RefineableElement(), 00078 ElementWithZ2ErrorEstimator() {} 00079 00080 00081 /// \short Loop over all elements in Vector (which typically contains 00082 /// all the elements in a fluid mesh) and pin the nodal pressure degrees 00083 /// of freedom that are not being used. Function uses 00084 /// the member function 00085 /// - \c RefineableNavierStokesEquations:: 00086 /// pin_elemental_redundant_nodal_pressure_dofs() 00087 /// . 00088 /// which is empty by default and should be implemented for 00089 /// elements with nodal pressure degrees of freedom 00090 /// (e.g. for refineable Taylor-Hood.) 00091 static void pin_redundant_nodal_pressures(const Vector<GeneralisedElement*>& 00092 element_pt) 00093 { 00094 // Loop over all elements and call the function that pins their 00095 // unused nodal pressure data 00096 unsigned n_element = element_pt.size(); 00097 for(unsigned e=0;e<n_element;e++) 00098 { 00099 dynamic_cast<RefineableNavierStokesEquations<DIM>*>(element_pt[e])-> 00100 pin_elemental_redundant_nodal_pressure_dofs(); 00101 } 00102 } 00103 00104 /// \short Unpin all pressure dofs in elements listed in vector. 00105 static void unpin_all_pressure_dofs(const Vector<GeneralisedElement*>& 00106 element_pt) 00107 { 00108 // Loop over all elements 00109 unsigned n_element = element_pt.size(); 00110 for(unsigned e=0;e<n_element;e++) 00111 { 00112 dynamic_cast<RefineableNavierStokesEquations<DIM>*>(element_pt[e])-> 00113 unpin_elemental_pressure_dofs(); 00114 } 00115 } 00116 00117 00118 /// Number of 'flux' terms for Z2 error estimation 00119 unsigned num_Z2_flux_terms() 00120 { 00121 // DIM diagonal strain rates, DIM(DIM -1) /2 off diagonal rates 00122 return DIM + (DIM*(DIM-1))/2; 00123 } 00124 00125 /// \short Get 'flux' for Z2 error recovery: Upper triangular entries 00126 /// in strain rate tensor. 00127 void get_Z2_flux(const Vector<double>& s, Vector<double>& flux) 00128 { 00129 #ifdef PARANOID 00130 unsigned num_entries=DIM+(DIM*(DIM-1))/2; 00131 if (flux.size() < num_entries) 00132 { 00133 std::ostringstream error_message; 00134 error_message << "The flux vector has the wrong number of entries, " 00135 << flux.size() << ", whereas it should be at least " 00136 << num_entries << std::endl; 00137 throw OomphLibError(error_message.str(), 00138 "RefineableNavierStokesEquations::get_Z2_flux()", 00139 OOMPH_EXCEPTION_LOCATION); 00140 } 00141 #endif 00142 00143 // Get strain rate matrix 00144 DenseMatrix<double> strainrate(DIM); 00145 this->strain_rate(s,strainrate); 00146 00147 // Pack into flux Vector 00148 unsigned icount=0; 00149 00150 // Start with diagonal terms 00151 for(unsigned i=0;i<DIM;i++) 00152 { 00153 flux[icount]=strainrate(i,i); 00154 icount++; 00155 } 00156 00157 //Off diagonals row by row 00158 for(unsigned i=0;i<DIM;i++) 00159 { 00160 for(unsigned j=i+1;j<DIM;j++) 00161 { 00162 flux[icount]=strainrate(i,j); 00163 icount++; 00164 } 00165 } 00166 } 00167 00168 /// Further build, pass the pointers down to the sons 00169 void further_build() 00170 { 00171 //Find the father element 00172 RefineableNavierStokesEquations<DIM>* cast_father_element_pt 00173 = dynamic_cast<RefineableNavierStokesEquations<DIM>*> 00174 (this->father_element_pt()); 00175 00176 //Set the viscosity ratio pointer 00177 this->Viscosity_Ratio_pt = cast_father_element_pt->viscosity_ratio_pt(); 00178 //Set the density ratio pointer 00179 this->Density_Ratio_pt = cast_father_element_pt->density_ratio_pt(); 00180 //Set pointer to global Reynolds number 00181 this->Re_pt = cast_father_element_pt->re_pt(); 00182 //Set pointer to global Reynolds number x Strouhal number (=Womersley) 00183 this->ReSt_pt = cast_father_element_pt->re_st_pt(); 00184 //Set pointer to global Reynolds number x inverse Froude number 00185 this->ReInvFr_pt = cast_father_element_pt->re_invfr_pt(); 00186 //Set pointer to global gravity Vector 00187 this->G_pt = cast_father_element_pt->g_pt(); 00188 00189 //Set pointer to body force function 00190 this->Body_force_fct_pt = cast_father_element_pt->body_force_fct_pt(); 00191 00192 //Set pointer to volumetric source function 00193 this->Source_fct_pt = cast_father_element_pt->source_fct_pt(); 00194 00195 //Set the ALE flag 00196 this->ALE_is_disabled = cast_father_element_pt->ALE_is_disabled; 00197 } 00198 00199 00200 /// \short Compute the derivatives of the i-th component of 00201 /// velocity at point s with respect 00202 /// to all data that can affect its value. In addition, return the global 00203 /// equation numbers corresponding to the data. 00204 /// Overload the non-refineable version to take account of hanging node 00205 /// information 00206 void dinterpolated_u_nst_ddata(const Vector<double> &s, 00207 const unsigned &i, 00208 Vector<double> &du_ddata, 00209 Vector<unsigned> &global_eqn_number) 00210 { 00211 //Find number of nodes 00212 unsigned n_node = this->nnode(); 00213 //Local shape function 00214 Shape psi(n_node); 00215 //Find values of shape function at the given local coordinate 00216 this->shape(s,psi); 00217 00218 //Find the index at which the velocity component is stored 00219 const unsigned u_nodal_index = this->u_index_nst(i); 00220 00221 //Storage for hang info pointer 00222 HangInfo* hang_info_pt=0; 00223 //Storage for global equation 00224 int global_eqn = 0; 00225 00226 //Find the number of dofs associated with interpolated u 00227 unsigned n_u_dof=0; 00228 for(unsigned l=0;l<n_node;l++) 00229 { 00230 unsigned n_master = 1; 00231 00232 //Local bool (is the node hanging) 00233 bool is_node_hanging = this->node_pt(l)->is_hanging(); 00234 00235 //If the node is hanging, get the number of master nodes 00236 if(is_node_hanging) 00237 { 00238 hang_info_pt = this->node_pt(l)->hanging_pt(); 00239 n_master = hang_info_pt->nmaster(); 00240 } 00241 //Otherwise there is just one master node, the node itself 00242 else 00243 { 00244 n_master = 1; 00245 } 00246 00247 //Loop over the master nodes 00248 for(unsigned m=0;m<n_master;m++) 00249 { 00250 //Get the equation number 00251 if(is_node_hanging) 00252 { 00253 //Get the equation number from the master node 00254 global_eqn = hang_info_pt->master_node_pt(m)-> 00255 eqn_number(u_nodal_index); 00256 } 00257 else 00258 { 00259 // Global equation number 00260 global_eqn = this->node_pt(l)->eqn_number(u_nodal_index); 00261 } 00262 00263 //If it's positive add to the count 00264 if(global_eqn >= 0) {++n_u_dof;} 00265 } 00266 } 00267 00268 //Now resize the storage schemes 00269 du_ddata.resize(n_u_dof,0.0); 00270 global_eqn_number.resize(n_u_dof,0); 00271 00272 //Loop over th nodes again and set the derivatives 00273 unsigned count=0; 00274 //Loop over the local nodes and sum 00275 for(unsigned l=0;l<n_node;l++) 00276 { 00277 unsigned n_master = 1; 00278 double hang_weight = 1.0; 00279 00280 //Local bool (is the node hanging) 00281 bool is_node_hanging = this->node_pt(l)->is_hanging(); 00282 00283 //If the node is hanging, get the number of master nodes 00284 if(is_node_hanging) 00285 { 00286 hang_info_pt = this->node_pt(l)->hanging_pt(); 00287 n_master = hang_info_pt->nmaster(); 00288 } 00289 //Otherwise there is just one master node, the node itself 00290 else 00291 { 00292 n_master = 1; 00293 } 00294 00295 //Loop over the master nodes 00296 for(unsigned m=0;m<n_master;m++) 00297 { 00298 //If the node is hanging get weight from master node 00299 if(is_node_hanging) 00300 { 00301 //Get the hang weight from the master node 00302 hang_weight = hang_info_pt->master_weight(m); 00303 } 00304 else 00305 { 00306 // Node contributes with full weight 00307 hang_weight = 1.0; 00308 } 00309 00310 //Get the equation number 00311 if(is_node_hanging) 00312 { 00313 //Get the equation number from the master node 00314 global_eqn = hang_info_pt->master_node_pt(m)-> 00315 eqn_number(u_nodal_index); 00316 } 00317 else 00318 { 00319 // Local equation number 00320 global_eqn = this->node_pt(l)->eqn_number(u_nodal_index); 00321 } 00322 00323 if (global_eqn >= 0) 00324 { 00325 //Set the global equation number 00326 global_eqn_number[count] = global_eqn; 00327 //Set the derivative with respect to the unknown 00328 du_ddata[count] = psi[l]*hang_weight; 00329 //Increase the counter 00330 ++count; 00331 } 00332 } 00333 } 00334 } 00335 00336 00337 00338 protected: 00339 00340 00341 /// \short Add element's contribution to elemental residual vector and/or 00342 /// Jacobian matrix 00343 /// flag=1: compute both 00344 /// flag=0: compute only residual vector 00345 void fill_in_generic_residual_contribution_nst( 00346 Vector<double> &residuals, 00347 DenseMatrix<double> &jacobian, 00348 DenseMatrix<double> &mass_matrix, 00349 unsigned flag); 00350 00351 /// \short Compute derivatives of elemental residual vector with respect 00352 /// to nodal coordinates. Overwrites default implementation in 00353 /// FiniteElement base class. 00354 /// dresidual_dnodal_coordinates(l,i,j) = d res(l) / dX_{ij} 00355 virtual void get_dresidual_dnodal_coordinates(RankThreeTensor<double>& 00356 dresidual_dnodal_coordinates); 00357 00358 }; 00359 00360 00361 //====================================================================== 00362 /// Refineable version of Taylor Hood elements. These classes 00363 /// can be written in total generality. 00364 //====================================================================== 00365 template<unsigned DIM> 00366 class RefineableQTaylorHoodElement : 00367 public QTaylorHoodElement<DIM>, 00368 public virtual RefineableNavierStokesEquations<DIM>, 00369 public virtual RefineableQElement<DIM> 00370 { 00371 private: 00372 00373 /// \short Pointer to n_p-th pressure node 00374 Node* pressure_node_pt(const unsigned &n_p) 00375 {return this->node_pt(this->Pconv[n_p]);} 00376 00377 /// Unpin all pressure dofs 00378 void unpin_elemental_pressure_dofs() 00379 { 00380 //find the index at which the pressure is stored 00381 int p_index = this->p_nodal_index_nst(); 00382 unsigned n_node = this->nnode(); 00383 // loop over nodes 00384 for(unsigned n=0;n<n_node;n++) 00385 {this->node_pt(n)->unpin(p_index);} 00386 } 00387 00388 /// Pin all nodal pressure dofs that are not required 00389 void pin_elemental_redundant_nodal_pressure_dofs() 00390 { 00391 //Find the pressure index 00392 int p_index = this->p_nodal_index_nst(); 00393 //Loop over all nodes 00394 unsigned n_node = this->nnode(); 00395 // loop over all nodes and pin all the nodal pressures 00396 for(unsigned n=0;n<n_node;n++) {this->node_pt(n)->pin(p_index);} 00397 00398 // Loop over all actual pressure nodes and unpin if they're not hanging 00399 unsigned n_pres = this->npres_nst(); 00400 for(unsigned l=0;l<n_pres;l++) 00401 { 00402 Node* nod_pt = this->pressure_node_pt(l); 00403 if (!nod_pt->is_hanging(p_index)) {nod_pt->unpin(p_index);} 00404 } 00405 } 00406 00407 public: 00408 00409 /// \short Constructor 00410 RefineableQTaylorHoodElement() : 00411 RefineableElement(), 00412 RefineableNavierStokesEquations<DIM>(), 00413 RefineableQElement<DIM>(), 00414 QTaylorHoodElement<DIM>() {} 00415 00416 /// \short Number of values required at local node n. In order to simplify 00417 /// matters, we allocate storage for pressure variables at all the nodes 00418 /// and then pin those that are not used. 00419 unsigned required_nvalue(const unsigned &n) const {return DIM+1;} 00420 00421 /// Number of continuously interpolated values: (DIM velocities + 1 pressure) 00422 unsigned ncont_interpolated_values() const {return DIM+1;} 00423 00424 /// Rebuild from sons: empty 00425 void rebuild_from_sons(Mesh* &mesh_pt) {} 00426 00427 /// \short Order of recovery shape functions for Z2 error estimation: 00428 /// Same order as shape functions. 00429 unsigned nrecovery_order() {return 2;} 00430 00431 /// \short Number of vertex nodes in the element 00432 unsigned nvertex_node() const 00433 {return QTaylorHoodElement<DIM>::nvertex_node();} 00434 00435 /// \short Pointer to the j-th vertex node in the element 00436 Node* vertex_node_pt(const unsigned& j) const 00437 {return QTaylorHoodElement<DIM>::vertex_node_pt(j);} 00438 00439 /// \short Get the function value u in Vector. 00440 /// Note: Given the generality of the interface (this function 00441 /// is usually called from black-box documentation or interpolation routines), 00442 /// the values Vector sets its own size in here. 00443 void get_interpolated_values(const Vector<double>&s, Vector<double>& values) 00444 { 00445 // Set size of Vector: u,v,p and initialise to zero 00446 values.resize(DIM+1,0.0); 00447 00448 //Calculate velocities: values[0],... 00449 for(unsigned i=0;i<DIM;i++) {values[i] = this->interpolated_u_nst(s,i);} 00450 00451 //Calculate pressure: values[DIM] 00452 values[DIM] = this->interpolated_p_nst(s); 00453 } 00454 00455 /// \short Get the function value u in Vector. 00456 /// Note: Given the generality of the interface (this function 00457 /// is usually called from black-box documentation or interpolation routines), 00458 /// the values Vector sets its own size in here. 00459 void get_interpolated_values(const unsigned& t, const Vector<double>&s, 00460 Vector<double>& values) 00461 { 00462 // Set size of Vector: u,v,p 00463 values.resize(DIM+1); 00464 00465 // Initialise 00466 for(unsigned i=0;i<DIM+1;i++) {values[i]=0.0;} 00467 00468 //Find out how many nodes there are 00469 unsigned n_node = this->nnode(); 00470 00471 // Shape functions 00472 Shape psif(n_node); 00473 this->shape(s,psif); 00474 00475 //Calculate velocities: values[0],... 00476 for(unsigned i=0;i<DIM;i++) 00477 { 00478 //Get the index at which the i-th velocity is stored 00479 unsigned u_nodal_index = this->u_index_nst(i); 00480 for(unsigned l=0;l<n_node;l++) 00481 { 00482 values[i] += this->nodal_value(t,l,u_nodal_index)*psif[l]; 00483 } 00484 } 00485 00486 //Calculate pressure: values[DIM] 00487 //(no history is carried in the pressure) 00488 values[DIM] = this->interpolated_p_nst(s); 00489 } 00490 00491 00492 /// \short Perform additional hanging node procedures for variables 00493 /// that are not interpolated by all nodes. The pressures are stored 00494 /// at the p_nodal_index_nst-th location in each node 00495 void further_setup_hanging_nodes() 00496 { 00497 this->setup_hang_for_value(this->p_nodal_index_nst()); 00498 } 00499 00500 /// \short The velocities are isoparametric and so the "nodes" interpolating 00501 /// the velocities are the geometric nodes. The pressure "nodes" are a 00502 /// subset of the nodes, so when value_id==DIM, the n-th pressure 00503 /// node is returned. 00504 Node* interpolating_node_pt(const unsigned &n, 00505 const int &value_id) 00506 00507 { 00508 //The only different nodes are the pressure nodes 00509 if(value_id==DIM) {return this->pressure_node_pt(n);} 00510 //The other variables are interpolated via the usual nodes 00511 else {return this->node_pt(n);} 00512 } 00513 00514 /// \short The pressure nodes are the corner nodes, so when n_value==DIM, 00515 /// the fraction is the same as the 1d node number, 0 or 1. 00516 double local_one_d_fraction_of_interpolating_node(const unsigned &n1d, 00517 const unsigned &i, 00518 const int &value_id) 00519 { 00520 if(value_id==DIM) 00521 { 00522 //The pressure nodes are just located on the boundaries at 0 or 1 00523 return double(n1d); 00524 } 00525 //Otherwise the velocity nodes are the same as the geometric ones 00526 else 00527 { 00528 return this->local_one_d_fraction_of_node(n1d,i); 00529 } 00530 } 00531 00532 /// \short The velocity nodes are the same as the geometric nodes. The 00533 /// pressure nodes must be calculated by using the same methods as 00534 /// the geometric nodes, but by recalling that there are only two pressure 00535 /// nodes per edge. 00536 Node* get_interpolating_node_at_local_coordinate(const Vector<double> &s, 00537 const int &value_id) 00538 { 00539 //If we are calculating pressure nodes 00540 if(value_id==DIM) 00541 { 00542 //Storage for the index of the pressure node 00543 unsigned total_index=0; 00544 //The number of nodes along each 1d edge is 2. 00545 unsigned NNODE_1D = 2; 00546 //Storage for the index along each boundary 00547 Vector<int> index(DIM); 00548 //Loop over the coordinates 00549 for(unsigned i=0;i<DIM;i++) 00550 { 00551 //If we are at the lower limit, the index is zero 00552 if(s[i]==-1.0) 00553 { 00554 index[i] = 0; 00555 } 00556 //If we are at the upper limit, the index is the number of nodes minus 1 00557 else if(s[i] == 1.0) 00558 { 00559 index[i] = NNODE_1D-1; 00560 } 00561 //Otherwise, we have to calculate the index in general 00562 else 00563 { 00564 //For uniformly spaced nodes the 0th node number would be 00565 double float_index = 0.5*(1.0 + s[i])*(NNODE_1D-1); 00566 index[i] = int(float_index); 00567 //What is the excess. This should be safe because the 00568 //taking the integer part rounds down 00569 double excess = float_index - index[i]; 00570 //If the excess is bigger than our tolerance there is no node, 00571 //return null 00572 if((excess > FiniteElement::Node_location_tolerance) && ( 00573 (1.0 - excess) > FiniteElement::Node_location_tolerance)) 00574 { 00575 return 0; 00576 } 00577 } 00578 ///Construct the general pressure index from the components. 00579 total_index += index[i]* 00580 static_cast<unsigned>(pow(static_cast<float>(NNODE_1D), 00581 static_cast<int>(i))); 00582 } 00583 //If we've got here we have a node, so let's return a pointer to it 00584 return this->pressure_node_pt(total_index); 00585 } 00586 //Otherwise velocity nodes are the same as pressure nodes 00587 else 00588 { 00589 return this->get_node_at_local_coordinate(s); 00590 } 00591 } 00592 00593 00594 /// \short The number of 1d pressure nodes is 2, the number of 1d velocity 00595 /// nodes is the same as the number of 1d geometric nodes. 00596 unsigned ninterpolating_node_1d(const int &value_id) 00597 { 00598 if(value_id==DIM) {return 2;} 00599 else {return this->nnode_1d();} 00600 } 00601 00602 /// \short The number of pressure nodes is 2^DIM. The number of 00603 /// velocity nodes is the same as the number of geometric nodes. 00604 unsigned ninterpolating_node(const int &value_id) 00605 { 00606 if(value_id==DIM) 00607 {return static_cast<unsigned>(pow(2.0,static_cast<int>(DIM)));} 00608 else {return this->nnode();} 00609 } 00610 00611 /// \short The basis interpolating the pressure is given by pshape(). 00612 //// The basis interpolating the velocity is shape(). 00613 void interpolating_basis(const Vector<double> &s, 00614 Shape &psi, 00615 const int &value_id) const 00616 { 00617 if(value_id==DIM) {return this->pshape_nst(s,psi);} 00618 else {return this->shape(s,psi);} 00619 } 00620 00621 00622 /// \short Add to the set \c paired_load_data pairs containing 00623 /// - the pointer to a Data object 00624 /// and 00625 /// - the index of the value in that Data object 00626 /// . 00627 /// for all values (pressures, velocities) that affect the 00628 /// load computed in the \c get_load(...) function. 00629 /// (Overloads non-refineable version and takes hanging nodes 00630 /// into account) 00631 void identify_load_data( 00632 std::set<std::pair<Data*,unsigned> > &paired_load_data) 00633 { 00634 //Get the nodal indices at which the velocities are stored 00635 unsigned u_index[DIM]; 00636 for(unsigned i=0;i<DIM;i++) {u_index[i] = this->u_index_nst(i);} 00637 00638 //Loop over the nodes 00639 unsigned n_node = this->nnode(); 00640 for(unsigned n=0;n<n_node;n++) 00641 { 00642 // Pointer to current node 00643 Node* nod_pt=this->node_pt(n); 00644 00645 // Check if it's hanging: 00646 if (nod_pt->is_hanging()) 00647 { 00648 // It's hanging -- get number of master nodes 00649 unsigned nmaster=nod_pt->hanging_pt()->nmaster(); 00650 00651 // Loop over masters 00652 for (unsigned j=0;j<nmaster;j++) 00653 { 00654 Node* master_nod_pt=nod_pt->hanging_pt()->master_node_pt(j); 00655 00656 //Loop over the velocity components and add pointer to their data 00657 //and indices to the vectors 00658 for(unsigned i=0;i<DIM;i++) 00659 { 00660 paired_load_data.insert(std::make_pair(master_nod_pt,u_index[i])); 00661 } 00662 } 00663 } 00664 //Not hanging 00665 else 00666 { 00667 //Loop over the velocity components and add pointer to their data 00668 //and indices to the vectors 00669 for(unsigned i=0;i<DIM;i++) 00670 { 00671 paired_load_data.insert(std::make_pair(this->node_pt(n),u_index[i])); 00672 } 00673 } 00674 } 00675 00676 //Get the nodal index at which the pressure is stored 00677 int p_index = this->p_nodal_index_nst(); 00678 00679 //Loop over the pressure data 00680 unsigned n_pres= this->npres_nst(); 00681 for(unsigned l=0;l<n_pres;l++) 00682 { 00683 //Get the pointer to the nodal pressure 00684 Node* pres_node_pt = this->pressure_node_pt(l); 00685 // Check if the pressure dof is hanging 00686 if(pres_node_pt->is_hanging(p_index)) 00687 { 00688 //Get the pointer to the hang info object 00689 // (pressure is stored as p_index--th nodal dof). 00690 HangInfo* hang_info_pt = pres_node_pt->hanging_pt(p_index); 00691 00692 // Get number of pressure master nodes (pressure is stored 00693 unsigned nmaster = hang_info_pt->nmaster(); 00694 00695 // Loop over pressure master nodes 00696 for(unsigned m=0;m<nmaster;m++) 00697 { 00698 //The p_index-th entry in each nodal data is the pressure, which 00699 //affects the traction 00700 paired_load_data.insert( 00701 std::make_pair(hang_info_pt->master_node_pt(m),p_index)); 00702 } 00703 } 00704 // It's not hanging 00705 else 00706 { 00707 //The p_index-th entry in each nodal data is the pressure, which 00708 //affects the traction 00709 paired_load_data.insert(std::make_pair(pres_node_pt,p_index)); 00710 } 00711 } 00712 00713 } 00714 00715 00716 }; 00717 00718 00719 //======================================================================= 00720 /// \short Face geometry of the RefineableQTaylorHoodElements is the 00721 /// same as the Face geometry of the QTaylorHoodElements. 00722 //======================================================================= 00723 template<unsigned DIM> 00724 class FaceGeometry<RefineableQTaylorHoodElement<DIM> >: 00725 public virtual FaceGeometry<QTaylorHoodElement<DIM> > 00726 { 00727 public: 00728 FaceGeometry() : FaceGeometry<QTaylorHoodElement<DIM> >() {} 00729 }; 00730 00731 00732 //======================================================================= 00733 /// \short Face geometry of the face geometry of 00734 /// the RefineableQTaylorHoodElements is the 00735 /// same as the Face geometry of the Face geometry of QTaylorHoodElements. 00736 //======================================================================= 00737 template<unsigned DIM> 00738 class FaceGeometry<FaceGeometry<RefineableQTaylorHoodElement<DIM> > >: 00739 public virtual FaceGeometry<FaceGeometry<QTaylorHoodElement<DIM> > > 00740 { 00741 public: 00742 FaceGeometry() : FaceGeometry<FaceGeometry<QTaylorHoodElement<DIM> > >() 00743 {} 00744 }; 00745 00746 00747 /////////////////////////////////////////////////////////////////////////// 00748 /////////////////////////////////////////////////////////////////////////// 00749 /////////////////////////////////////////////////////////////////////////// 00750 00751 00752 //====================================================================== 00753 /// Refineable version of Crouzeix Raviart elements. Generic class definitions 00754 //====================================================================== 00755 template<unsigned DIM> 00756 class RefineableQCrouzeixRaviartElement : 00757 public QCrouzeixRaviartElement<DIM>, 00758 public virtual RefineableNavierStokesEquations<DIM>, 00759 public virtual RefineableQElement<DIM> 00760 { 00761 private: 00762 00763 /// Unpin all internal pressure dofs 00764 void unpin_elemental_pressure_dofs() 00765 { 00766 unsigned n_pres = this->npres_nst(); 00767 // loop over pressure dofs and unpin them 00768 for(unsigned l=0;l<n_pres;l++) 00769 {this->internal_data_pt(this->P_nst_internal_index)->unpin(l);} 00770 } 00771 00772 public: 00773 00774 /// \short Constructor 00775 RefineableQCrouzeixRaviartElement() : 00776 RefineableElement(), 00777 RefineableNavierStokesEquations<DIM>(), 00778 RefineableQElement<DIM>(), 00779 QCrouzeixRaviartElement<DIM>() {} 00780 00781 /// Number of continuously interpolated values: DIM (velocities) 00782 unsigned ncont_interpolated_values() const {return DIM;} 00783 00784 /// \short Rebuild from sons: Reconstruct pressure from the (merged) sons 00785 /// This must be specialised for each dimension. 00786 inline void rebuild_from_sons(Mesh* &mesh_pt); 00787 00788 /// \short Order of recovery shape functions for Z2 error estimation: 00789 /// Same order as shape functions. 00790 unsigned nrecovery_order() {return 2;} 00791 00792 /// \short Number of vertex nodes in the element 00793 unsigned nvertex_node() const 00794 {return QCrouzeixRaviartElement<DIM>::nvertex_node();} 00795 00796 /// \short Pointer to the j-th vertex node in the element 00797 Node* vertex_node_pt(const unsigned& j) const 00798 { 00799 return QCrouzeixRaviartElement<DIM>::vertex_node_pt(j); 00800 } 00801 00802 /// \short Get the function value u in Vector. 00803 /// Note: Given the generality of the interface (this function 00804 /// is usually called from black-box documentation or interpolation routines), 00805 /// the values Vector sets its own size in here. 00806 void get_interpolated_values(const Vector<double>&s, Vector<double>& values) 00807 { 00808 // Set size of Vector: u,v,p and initialise to zero 00809 values.resize(DIM,0.0); 00810 00811 //Calculate velocities: values[0],... 00812 for(unsigned i=0;i<DIM;i++) {values[i] = this->interpolated_u_nst(s,i);} 00813 } 00814 00815 /// \short Get all function values [u,v..,p] at previous timestep t 00816 /// (t=0: present; t>0: previous timestep). 00817 /// \n 00818 /// Note: Given the generality of the interface (this function 00819 /// is usually called from black-box documentation or interpolation routines), 00820 /// the values Vector sets its own size in here. 00821 /// \n 00822 /// Note: No pressure history is kept, so pressure is always 00823 /// the current value. 00824 void get_interpolated_values(const unsigned& t, const Vector<double>&s, 00825 Vector<double>& values) 00826 { 00827 // Set size of Vector: u,v,p 00828 values.resize(DIM); 00829 00830 // Initialise 00831 for(unsigned i=0;i<DIM;i++) {values[i]=0.0;} 00832 00833 //Find out how many nodes there are 00834 unsigned n_node = this->nnode(); 00835 00836 // Shape functions 00837 Shape psif(n_node); 00838 this->shape(s,psif); 00839 00840 //Calculate velocities: values[0],... 00841 for(unsigned i=0;i<DIM;i++) 00842 { 00843 //Get the nodal index at which the i-th velocity component is stored 00844 unsigned u_nodal_index = this->u_index_nst(i); 00845 for(unsigned l=0;l<n_node;l++) 00846 { 00847 values[i] += this->nodal_value(t,l,u_nodal_index)*psif[l]; 00848 } 00849 } 00850 } 00851 00852 /// \short Perform additional hanging node procedures for variables 00853 /// that are not interpolated by all nodes. Empty 00854 void further_setup_hanging_nodes() {} 00855 00856 /// Further build for Crouzeix_Raviart interpolates the internal 00857 /// pressure dofs from father element: Make sure pressure values and 00858 /// dp/ds agree between fathers and sons at the midpoints of the son 00859 /// elements. This must be specialised for each dimension. 00860 inline void further_build(); 00861 00862 00863 00864 /// \short Add to the set \c paired_load_data pairs containing 00865 /// - the pointer to a Data object 00866 /// and 00867 /// - the index of the value in that Data object 00868 /// . 00869 /// for all values (pressures, velocities) that affect the 00870 /// load computed in the \c get_load(...) function. 00871 /// (Overloads non-refineable version and takes hanging nodes 00872 /// into account) 00873 void identify_load_data( 00874 std::set<std::pair<Data*,unsigned> > &paired_load_data) 00875 { 00876 //Get the nodal indices at which the velocities are stored 00877 unsigned u_index[DIM]; 00878 for(unsigned i=0;i<DIM;i++) {u_index[i] = this->u_index_nst(i);} 00879 00880 //Loop over the nodes 00881 unsigned n_node = this->nnode(); 00882 for(unsigned n=0;n<n_node;n++) 00883 { 00884 // Pointer to current node 00885 Node* nod_pt=this->node_pt(n); 00886 00887 // Check if it's hanging: 00888 if (nod_pt->is_hanging()) 00889 { 00890 // It's hanging -- get number of master nodes 00891 unsigned nmaster=nod_pt->hanging_pt()->nmaster(); 00892 00893 // Loop over masters 00894 for (unsigned j=0;j<nmaster;j++) 00895 { 00896 Node* master_nod_pt=nod_pt->hanging_pt()->master_node_pt(j); 00897 00898 //Loop over the velocity components and add pointer to their data 00899 //and indices to the vectors 00900 for(unsigned i=0;i<DIM;i++) 00901 { 00902 paired_load_data.insert(std::make_pair(master_nod_pt,u_index[i])); 00903 } 00904 } 00905 } 00906 //Not hanging 00907 else 00908 { 00909 //Loop over the velocity components and add pointer to their data 00910 //and indices to the vectors 00911 for(unsigned i=0;i<DIM;i++) 00912 { 00913 paired_load_data.insert(std::make_pair(this->node_pt(n),u_index[i])); 00914 } 00915 } 00916 } 00917 00918 00919 //Loop over the pressure data (can't be hanging!) 00920 unsigned n_pres = this->npres_nst(); 00921 for(unsigned l=0;l<n_pres;l++) 00922 { 00923 //The entries in the internal data at P_nst_internal_index 00924 //are the pressures, which affect the traction 00925 paired_load_data.insert( 00926 std::make_pair(this->internal_data_pt(this->P_nst_internal_index),l)); 00927 } 00928 } 00929 00930 00931 }; 00932 00933 00934 //======================================================================= 00935 /// Face geometry of the RefineableQuadQCrouzeixRaviartElements 00936 //======================================================================= 00937 template<unsigned DIM> 00938 class FaceGeometry<RefineableQCrouzeixRaviartElement<DIM> >: 00939 public virtual FaceGeometry<QCrouzeixRaviartElement<DIM> > 00940 { 00941 public: 00942 FaceGeometry() : FaceGeometry<QCrouzeixRaviartElement<DIM> >() {} 00943 }; 00944 00945 //====================================================================== 00946 /// \short Face geometry of the face geometry of 00947 /// the RefineableQCrouzeixRaviartElements is the 00948 /// same as the Face geometry of the Face geometry of 00949 /// QCrouzeixRaviartElements. 00950 //======================================================================= 00951 template<unsigned DIM> 00952 class FaceGeometry<FaceGeometry<RefineableQCrouzeixRaviartElement<DIM> > >: 00953 public virtual FaceGeometry<FaceGeometry<QCrouzeixRaviartElement<DIM> > > 00954 { 00955 public: 00956 FaceGeometry() : FaceGeometry<FaceGeometry<QCrouzeixRaviartElement<DIM> > >() 00957 {} 00958 }; 00959 00960 00961 //===================================================================== 00962 /// 2D Rebuild from sons: Reconstruct pressure from the (merged) sons 00963 //===================================================================== 00964 template<> 00965 inline void RefineableQCrouzeixRaviartElement<2>:: 00966 rebuild_from_sons(Mesh* &mesh_pt) 00967 { 00968 using namespace QuadTreeNames; 00969 00970 //Central pressure value: 00971 //----------------------- 00972 00973 // Use average of the sons central pressure values 00974 // Other options: Take average of the four (discontinuous) 00975 // pressure values at the father's midpoint] 00976 00977 double av_press=0.0; 00978 00979 // Loop over the sons 00980 for (unsigned ison=0;ison<4;ison++) 00981 { 00982 // Add the sons midnode pressure 00983 // Note that we can assume that the pressure is stored at the same 00984 // location because these are EXACTLY the same type of elements 00985 av_press += quadtree_pt()->son_pt(ison)->object_pt()-> 00986 internal_data_pt(this->P_nst_internal_index)->value(0); 00987 } 00988 00989 // Use the average 00990 internal_data_pt(this->P_nst_internal_index)->set_value(0,0.25*av_press); 00991 00992 00993 //Slope in s_0 direction 00994 //---------------------- 00995 00996 // Use average of the 2 FD approximations based on the 00997 // elements central pressure values 00998 // [Other options: Take average of the four 00999 // pressure derivatives] 01000 01001 double slope1= 01002 quadtree_pt()->son_pt(SE)->object_pt()-> 01003 internal_data_pt(this->P_nst_internal_index)->value(0) - 01004 quadtree_pt()->son_pt(SW)->object_pt()-> 01005 internal_data_pt(this->P_nst_internal_index)->value(0); 01006 01007 double slope2 = 01008 quadtree_pt()->son_pt(NE)->object_pt()-> 01009 internal_data_pt(this->P_nst_internal_index)->value(0) - 01010 quadtree_pt()->son_pt(NW)->object_pt()-> 01011 internal_data_pt(this->P_nst_internal_index)->value(0); 01012 01013 01014 // Use the average 01015 internal_data_pt(this->P_nst_internal_index)-> 01016 set_value(1,0.5*(slope1+slope2)); 01017 01018 01019 01020 //Slope in s_1 direction 01021 //---------------------- 01022 01023 // Use average of the 2 FD approximations based on the 01024 // elements central pressure values 01025 // [Other options: Take average of the four 01026 // pressure derivatives] 01027 01028 slope1 = 01029 quadtree_pt()->son_pt(NE)->object_pt() 01030 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01031 quadtree_pt()->son_pt(SE)->object_pt() 01032 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01033 01034 slope2= 01035 quadtree_pt()->son_pt(NW)->object_pt() 01036 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01037 quadtree_pt()->son_pt(SW)->object_pt() 01038 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01039 01040 01041 // Use the average 01042 internal_data_pt(this->P_nst_internal_index)-> 01043 set_value(2,0.5*(slope1+slope2)); 01044 } 01045 01046 01047 01048 //================================================================= 01049 /// 3D Rebuild from sons: Reconstruct pressure from the (merged) sons 01050 //================================================================= 01051 template<> 01052 inline void RefineableQCrouzeixRaviartElement<3>:: 01053 rebuild_from_sons(Mesh* &mesh_pt) 01054 { 01055 using namespace OcTreeNames; 01056 01057 //Central pressure value: 01058 //----------------------- 01059 01060 // Use average of the sons central pressure values 01061 // Other options: Take average of the four (discontinuous) 01062 // pressure values at the father's midpoint] 01063 01064 double av_press=0.0; 01065 01066 // Loop over the sons 01067 for (unsigned ison=0;ison<8;ison++) 01068 { 01069 // Add the sons midnode pressure 01070 av_press += octree_pt()->son_pt(ison)->object_pt()-> 01071 internal_data_pt(this->P_nst_internal_index)->value(0); 01072 } 01073 01074 // Use the average 01075 internal_data_pt(this->P_nst_internal_index)-> 01076 set_value(0,0.125*av_press); 01077 01078 01079 //Slope in s_0 direction 01080 //---------------------- 01081 01082 // Use average of the 4 FD approximations based on the 01083 // elements central pressure values 01084 // [Other options: Take average of the four 01085 // pressure derivatives] 01086 01087 double slope1 = 01088 octree_pt()->son_pt(RDF)->object_pt()-> 01089 internal_data_pt(this->P_nst_internal_index)->value(0) - 01090 octree_pt()->son_pt(LDF)->object_pt()-> 01091 internal_data_pt(this->P_nst_internal_index)->value(0); 01092 01093 double slope2 = 01094 octree_pt()->son_pt(RUF)->object_pt()-> 01095 internal_data_pt(this->P_nst_internal_index)->value(0) - 01096 octree_pt()->son_pt(LUF)->object_pt()-> 01097 internal_data_pt(this->P_nst_internal_index)->value(0); 01098 01099 double slope3 = 01100 octree_pt()->son_pt(RDB)->object_pt()-> 01101 internal_data_pt(this->P_nst_internal_index)->value(0) - 01102 octree_pt()->son_pt(LDB)->object_pt()-> 01103 internal_data_pt(this->P_nst_internal_index)->value(0); 01104 01105 double slope4 = 01106 octree_pt()->son_pt(RUB)->object_pt()-> 01107 internal_data_pt(this->P_nst_internal_index)->value(0) - 01108 octree_pt()->son_pt(LUB)->object_pt()-> 01109 internal_data_pt(this->P_nst_internal_index)->value(0); 01110 01111 01112 // Use the average 01113 internal_data_pt(this->P_nst_internal_index)-> 01114 set_value(1,0.25*(slope1+slope2+slope3+slope4)); 01115 01116 01117 //Slope in s_1 direction 01118 //---------------------- 01119 01120 // Use average of the 4 FD approximations based on the 01121 // elements central pressure values 01122 // [Other options: Take average of the four 01123 // pressure derivatives] 01124 01125 slope1 = 01126 octree_pt()->son_pt(LUB)->object_pt() 01127 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01128 octree_pt()->son_pt(LDB)->object_pt() 01129 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01130 01131 slope2 = 01132 octree_pt()->son_pt(RUB)->object_pt() 01133 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01134 octree_pt()->son_pt(RDB)->object_pt() 01135 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01136 01137 slope3 = 01138 octree_pt()->son_pt(LUF)->object_pt() 01139 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01140 octree_pt()->son_pt(LDF)->object_pt() 01141 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01142 01143 slope4 = 01144 octree_pt()->son_pt(RUF)->object_pt() 01145 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01146 octree_pt()->son_pt(RDF)->object_pt() 01147 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01148 01149 01150 // Use the average 01151 internal_data_pt(this->P_nst_internal_index)-> 01152 set_value(2,0.25*(slope1+slope2+slope3+slope4)); 01153 01154 01155 //Slope in s_2 direction 01156 //---------------------- 01157 01158 // Use average of the 4 FD approximations based on the 01159 // elements central pressure values 01160 // [Other options: Take average of the four 01161 // pressure derivatives] 01162 01163 slope1 = 01164 octree_pt()->son_pt(LUF)->object_pt() 01165 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01166 octree_pt()->son_pt(LUB)->object_pt() 01167 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01168 01169 slope2 = 01170 octree_pt()->son_pt(RUF)->object_pt() 01171 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01172 octree_pt()->son_pt(RUB)->object_pt() 01173 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01174 01175 slope3 = 01176 octree_pt()->son_pt(LDF)->object_pt() 01177 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01178 octree_pt()->son_pt(LDB)->object_pt() 01179 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01180 01181 slope4 = 01182 octree_pt()->son_pt(RDF)->object_pt() 01183 ->internal_data_pt(this->P_nst_internal_index)->value(0) - 01184 octree_pt()->son_pt(RDB)->object_pt() 01185 ->internal_data_pt(this->P_nst_internal_index)->value(0); 01186 01187 // Use the average 01188 internal_data_pt(this->P_nst_internal_index)-> 01189 set_value(3,0.25*(slope1+slope2+slope3+slope4)); 01190 01191 } 01192 01193 01194 //====================================================================== 01195 /// 2D Further build for Crouzeix_Raviart interpolates the internal 01196 /// pressure dofs from father element: Make sure pressure values and 01197 /// dp/ds agree between fathers and sons at the midpoints of the son 01198 /// elements. 01199 //====================================================================== 01200 template<> 01201 inline void RefineableQCrouzeixRaviartElement<2>::further_build() 01202 { 01203 //Call the generic further build 01204 RefineableNavierStokesEquations<2>::further_build(); 01205 01206 using namespace QuadTreeNames; 01207 01208 // What type of son am I? Ask my quadtree representation... 01209 int son_type=quadtree_pt()->son_type(); 01210 01211 // Pointer to my father (in element impersonation) 01212 RefineableElement* father_el_pt= quadtree_pt()->father_pt()->object_pt(); 01213 01214 Vector<double> s_father(2); 01215 01216 // Son midpoint is located at the following coordinates in father element: 01217 01218 // South west son 01219 if (son_type==SW) 01220 { 01221 s_father[0]=-0.5; 01222 s_father[1]=-0.5; 01223 } 01224 // South east son 01225 else if (son_type==SE) 01226 { 01227 s_father[0]= 0.5; 01228 s_father[1]=-0.5; 01229 } 01230 // North east son 01231 else if (son_type==NE) 01232 { 01233 s_father[0]=0.5; 01234 s_father[1]=0.5; 01235 } 01236 01237 // North west son 01238 else if (son_type==NW) 01239 { 01240 s_father[0]=-0.5; 01241 s_father[1]= 0.5; 01242 } 01243 01244 // Pressure value in father element 01245 RefineableQCrouzeixRaviartElement<2>* cast_father_element_pt= 01246 dynamic_cast<RefineableQCrouzeixRaviartElement<2>*>(father_el_pt); 01247 01248 double press=cast_father_element_pt->interpolated_p_nst(s_father); 01249 01250 // Pressure value gets copied straight into internal dof: 01251 internal_data_pt(this->P_nst_internal_index)->set_value(0,press); 01252 01253 // The slopes get copied from father 01254 for(unsigned i=1;i<3;i++) 01255 { 01256 double half_father_slope = 0.5*cast_father_element_pt-> 01257 internal_data_pt(this->P_nst_internal_index)->value(i); 01258 //Set the value in the son 01259 internal_data_pt(this->P_nst_internal_index)-> 01260 set_value(i,half_father_slope); 01261 } 01262 } 01263 01264 01265 //======================================================================= 01266 /// 3D Further build for Crouzeix_Raviart interpolates the internal 01267 /// pressure dofs from father element: Make sure pressure values and 01268 /// dp/ds agree between fathers and sons at the midpoints of the son 01269 /// elements. 01270 //======================================================================= 01271 template<> 01272 inline void RefineableQCrouzeixRaviartElement<3>::further_build() 01273 { 01274 RefineableNavierStokesEquations<3>::further_build(); 01275 01276 using namespace OcTreeNames; 01277 01278 // What type of son am I? Ask my octree representation... 01279 int son_type=octree_pt()->son_type(); 01280 01281 // Pointer to my father (in element impersonation) 01282 RefineableQElement<3>* father_el_pt= 01283 dynamic_cast<RefineableQElement<3>*>( 01284 octree_pt()->father_pt()->object_pt()); 01285 01286 Vector<double> s_father(3); 01287 01288 // Son midpoint is located at the following coordinates in father element: 01289 for(unsigned i=0;i<3;i++) 01290 { 01291 s_father[i]=0.5*OcTree::Direction_to_vector[son_type][i]; 01292 } 01293 01294 // Pressure value in father element 01295 RefineableQCrouzeixRaviartElement<3>* cast_father_element_pt= 01296 dynamic_cast<RefineableQCrouzeixRaviartElement<3>*>(father_el_pt); 01297 01298 double press=cast_father_element_pt->interpolated_p_nst(s_father); 01299 01300 // Pressure value gets copied straight into internal dof: 01301 internal_data_pt(this->P_nst_internal_index)->set_value(0,press); 01302 01303 // The slopes get copied from father 01304 for(unsigned i=1;i<4;i++) 01305 { 01306 double half_father_slope = 0.5*cast_father_element_pt 01307 ->internal_data_pt(this->P_nst_internal_index)->value(i); 01308 //Set the value 01309 internal_data_pt(this->P_nst_internal_index) 01310 ->set_value(i,half_father_slope); 01311 } 01312 } 01313 01314 } 01315 01316 #endif
1.4.7