ANS-1-1
step-fsi.cc
Go to the documentation of this file.
00001 /* Author: Thomas Wick, 2012 */
00002 /* University of Heidelberg  */
00003 /* Date: May 3, 2011, */
00004 /*       Revised Jan 30, 2012 */
00005 /* E-mail: thomas.wick@iwr.uni-heidelberg.de */
00006 /*
00007 /*                                                                */
00008 /*    Copyright (C) 2011, 2012 by Thomas Wick                     */
00009 /*                                                                */
00010 /*    This file is subject to QPL and may not be  distributed     */
00011 /*    without copyright and license information. Please refer     */
00012 /*    to the webpage XXX for the  text  and     */
00013 /*    further information on this license.                        */
00014 
00015 
00097 #include <base/quadrature_lib.h>
00098 #include <base/logstream.h>
00099 #include <base/function.h>
00100 #include <base/utilities.h>
00101 #include <base/timer.h>  
00102 
00103 #include <lac/block_vector.h>
00104 #include <lac/full_matrix.h>
00105 #include <lac/block_sparse_matrix.h>
00106 #include <lac/sparse_direct.h>
00107 #include <lac/constraint_matrix.h>
00108 
00109 #include <grid/tria.h>
00110 #include <grid/grid_generator.h>
00111 #include <grid/tria_accessor.h>
00112 #include <grid/tria_iterator.h>
00113 #include <grid/tria_boundary_lib.h>
00114 #include <grid/grid_tools.h>
00115 #include <grid/grid_in.h>
00116 
00117 #include <dofs/dof_handler.h>
00118 #include <dofs/dof_renumbering.h>
00119 #include <dofs/dof_accessor.h>
00120 #include <dofs/dof_tools.h>
00121 
00122 #include <fe/fe_q.h>
00123 #include <fe/fe_dgq.h>
00124 #include <fe/fe_dgp.h>
00125 #include <fe/fe_system.h>
00126 #include <fe/fe_values.h>
00127 #include <fe/mapping_q1.h>
00128 
00129 #include <numerics/vector_tools.h>
00130 #include <numerics/matrix_tools.h>
00131 #include <numerics/data_out.h>
00132 #include <numerics/solution_transfer.h>
00133 
00134 
00135 // C++
00136 #include <fstream>
00137 #include <sstream>
00138 
00139 // At the end of this top-matter, we import
00140 // all deal.II names into the global
00141 // namespace:                           
00142 using namespace dealii;
00143 
00144 
00145 
00154 namespace ALETransformations
00155 {    
00156   template <int dim> 
00157     inline
00158     Tensor<2,dim> 
00159     get_pI (unsigned int q,
00160             std::vector<Vector<double> > old_solution_values)
00161     {
00162       Tensor<2,dim> tmp;
00163       tmp[0][0] =  old_solution_values[q](dim+dim);
00164       tmp[1][1] =  old_solution_values[q](dim+dim);
00165       
00166       return tmp;      
00167     }
00168 
00169   template <int dim> 
00170     inline
00171     Tensor<2,dim> 
00172     get_pI_LinP (const double phi_i_p)
00173     {
00174       Tensor<2,dim> tmp;
00175       tmp.clear();
00176       tmp[0][0] = phi_i_p;    
00177       tmp[1][1] = phi_i_p;
00178       
00179       return tmp;
00180    }
00181 
00182  template <int dim> 
00183    inline
00184    Tensor<1,dim> 
00185    get_grad_p (unsigned int q,
00186                std::vector<std::vector<Tensor<1,dim> > > old_solution_grads)     
00187    {     
00188      Tensor<1,dim> grad_p;     
00189      grad_p[0] =  old_solution_grads[q][dim+dim][0];
00190      grad_p[1] =  old_solution_grads[q][dim+dim][1];
00191       
00192      return grad_p;
00193    }
00194 
00195  template <int dim> 
00196   inline
00197   Tensor<1,dim> 
00198   get_grad_p_LinP (const Tensor<1,dim> phi_i_grad_p)     
00199     {
00200       Tensor<1,dim> grad_p;      
00201       grad_p[0] =  phi_i_grad_p[0];
00202       grad_p[1] =  phi_i_grad_p[1];
00203            
00204       return grad_p;
00205    }
00206 
00207  template <int dim> 
00208    inline
00209    Tensor<2,dim> 
00210    get_grad_u (unsigned int q,
00211                std::vector<std::vector<Tensor<1,dim> > > old_solution_grads)     
00212    {   
00213       Tensor<2,dim> structure_continuation;     
00214       structure_continuation[0][0] = old_solution_grads[q][dim][0];
00215       structure_continuation[0][1] = old_solution_grads[q][dim][1];
00216       structure_continuation[1][0] = old_solution_grads[q][dim+1][0];
00217       structure_continuation[1][1] = old_solution_grads[q][dim+1][1];
00218 
00219       return structure_continuation;
00220    }
00221 
00222   template <int dim> 
00223   inline
00224   Tensor<2,dim> 
00225   get_grad_v (unsigned int q,
00226               std::vector<std::vector<Tensor<1,dim> > > old_solution_grads)      
00227     {      
00228       Tensor<2,dim> grad_v;      
00229       grad_v[0][0] =  old_solution_grads[q][0][0];
00230       grad_v[0][1] =  old_solution_grads[q][0][1];
00231       grad_v[1][0] =  old_solution_grads[q][1][0];
00232       grad_v[1][1] =  old_solution_grads[q][1][1];
00233       
00234       return grad_v;
00235    }
00236 
00237   template <int dim> 
00238     inline
00239     Tensor<2,dim> 
00240     get_grad_v_T (const Tensor<2,dim> tensor_grad_v)
00241     {   
00242       Tensor<2,dim> grad_v_T;
00243       grad_v_T = transpose (tensor_grad_v);
00244             
00245       return grad_v_T;      
00246     }
00247   
00248   template <int dim> 
00249     inline
00250     Tensor<2,dim> 
00251     get_grad_v_LinV (const Tensor<2,dim> phi_i_grads_v)  
00252     {     
00253         Tensor<2,dim> tmp;               
00254         tmp[0][0] = phi_i_grads_v[0][0];
00255         tmp[0][1] = phi_i_grads_v[0][1];
00256         tmp[1][0] = phi_i_grads_v[1][0];
00257         tmp[1][1] = phi_i_grads_v[1][1];
00258       
00259         return tmp;
00260     }
00261 
00262   template <int dim> 
00263     inline
00264     Tensor<2,dim> 
00265     get_Identity ()
00266     {   
00267       Tensor<2,dim> identity;
00268       identity[0][0] = 1.0;
00269       identity[0][1] = 0.0;
00270       identity[1][0] = 0.0;
00271       identity[1][1] = 1.0;
00272             
00273       return identity;      
00274    }
00275 
00276  template <int dim> 
00277  inline
00278  Tensor<2,dim> 
00279  get_F (unsigned int q,
00280         std::vector<std::vector<Tensor<1,dim> > > old_solution_grads)
00281     {     
00282       Tensor<2,dim> F;
00283       F[0][0] = 1.0 +  old_solution_grads[q][dim][0];
00284       F[0][1] = old_solution_grads[q][dim][1];
00285       F[1][0] = old_solution_grads[q][dim+1][0];
00286       F[1][1] = 1.0 + old_solution_grads[q][dim+1][1];
00287       return F;
00288    }
00289 
00290  template <int dim> 
00291  inline
00292  Tensor<2,dim> 
00293  get_F_T (const Tensor<2,dim> F)
00294     {
00295       return  transpose (F);
00296     }
00297 
00298  template <int dim> 
00299  inline
00300  Tensor<2,dim> 
00301  get_F_Inverse (const Tensor<2,dim> F)
00302     {     
00303       return invert (F);    
00304     }
00305 
00306  template <int dim> 
00307  inline
00308  Tensor<2,dim> 
00309  get_F_Inverse_T (const Tensor<2,dim> F_Inverse)
00310    { 
00311      return transpose (F_Inverse);
00312    }
00313 
00314  template <int dim> 
00315    inline
00316    double
00317    get_J (const Tensor<2,dim> tensor_F)
00318    {     
00319      return determinant (tensor_F);
00320    }
00321 
00322 
00323  template <int dim> 
00324  inline
00325  Tensor<1,dim> 
00326  get_v (unsigned int q,
00327         std::vector<Vector<double> > old_solution_values)
00328     {
00329       Tensor<1,dim> v;      
00330       v[0] = old_solution_values[q](0);
00331       v[1] = old_solution_values[q](1);
00332       
00333       return v;    
00334    }
00335 
00336  template <int dim> 
00337    inline
00338    Tensor<1,dim> 
00339    get_v_LinV (const Tensor<1,dim> phi_i_v)
00340    {
00341      Tensor<1,dim> tmp;
00342      tmp[0] = phi_i_v[0];
00343      tmp[1] = phi_i_v[1];
00344      
00345      return tmp;    
00346    }
00347 
00348  template <int dim> 
00349  inline
00350  Tensor<1,dim> 
00351  get_u (unsigned int q,
00352         std::vector<Vector<double> > old_solution_values)
00353    {
00354      Tensor<1,dim> u;     
00355      u[0] = old_solution_values[q](dim);
00356      u[1] = old_solution_values[q](dim+1);
00357      
00358      return u;          
00359    }
00360 
00361  template <int dim> 
00362    inline
00363    Tensor<1,dim> 
00364    get_u_LinU (const Tensor<1,dim> phi_i_u)
00365    {
00366      Tensor<1,dim> tmp;     
00367      tmp[0] = phi_i_u[0];
00368      tmp[1] = phi_i_u[1];
00369      
00370      return tmp;    
00371    }
00372  
00373  template <int dim> 
00374  inline
00375  Tensor<1,dim> 
00376  get_w (unsigned int q,
00377         std::vector<Vector<double> > old_solution_values)
00378    {
00379      Tensor<1,dim> w;     
00380      w[0] = old_solution_values[q](dim+dim+1);
00381      w[1] = old_solution_values[q](dim+dim+2);
00382      
00383      return w;          
00384    }
00385 
00386  template <int dim> 
00387    inline
00388    Tensor<2,dim> 
00389    get_grad_w (unsigned int q,
00390                std::vector<std::vector<Tensor<1,dim> > > old_solution_grads)     
00391    {   
00392       Tensor<2,dim> 
00393       tmp;     
00394       tmp[0][0] = old_solution_grads[q][dim+dim+1][0];
00395       tmp[0][1] = old_solution_grads[q][dim+dim+1][1];
00396       tmp[1][0] = old_solution_grads[q][dim+dim+2][0];
00397       tmp[1][1] = old_solution_grads[q][dim+dim+2][1];
00398 
00399       return tmp;
00400    }
00401 
00402 
00403 
00404  template <int dim> 
00405  inline
00406  double
00407  get_J_LinU (unsigned int q, 
00408              const std::vector<std::vector<Tensor<1,dim> > > old_solution_grads,
00409              const Tensor<2,dim> phi_i_grads_u)     
00410 {
00411   return (phi_i_grads_u[0][0] * (1 + old_solution_grads[q][dim+1][1]) +
00412                    (1 + old_solution_grads[q][dim][0]) * phi_i_grads_u[1][1] -
00413                    phi_i_grads_u[0][1] * old_solution_grads[q][dim+1][0] - 
00414                    old_solution_grads[q][dim][1] * phi_i_grads_u[1][0]);  
00415 }
00416 
00417   template <int dim> 
00418   inline
00419   double
00420   get_J_Inverse_LinU (const double J,
00421                       const double J_LinU)
00422     {
00423       return (-1.0/std::pow(J,2) * J_LinU);
00424     }
00425 
00426 template <int dim> 
00427  inline
00428  Tensor<2,dim>
00429   get_F_LinU (const Tensor<2,dim> phi_i_grads_u)  
00430   {
00431     Tensor<2,dim> tmp;
00432     tmp[0][0] = phi_i_grads_u[0][0];
00433     tmp[0][1] = phi_i_grads_u[0][1];
00434     tmp[1][0] = phi_i_grads_u[1][0];
00435     tmp[1][1] = phi_i_grads_u[1][1];
00436     
00437     return tmp;
00438   }
00439 
00440 template <int dim> 
00441  inline
00442  Tensor<2,dim>
00443   get_F_Inverse_LinU (const Tensor<2,dim> phi_i_grads_u,
00444                        const double J,
00445                        const double J_LinU,
00446                        unsigned int q,
00447                        std::vector<std::vector<Tensor<1,dim> > > old_solution_grads
00448                        )  
00449   {
00450     Tensor<2,dim> F_tilde;
00451     F_tilde[0][0] = 1.0 + old_solution_grads[q][dim+1][1];
00452     F_tilde[0][1] = -old_solution_grads[q][dim][1];
00453     F_tilde[1][0] = -old_solution_grads[q][dim+1][0];
00454     F_tilde[1][1] = 1.0 + old_solution_grads[q][dim][0];
00455     
00456     Tensor<2,dim> F_tilde_LinU;
00457     F_tilde_LinU[0][0] = phi_i_grads_u[1][1];
00458     F_tilde_LinU[0][1] = -phi_i_grads_u[0][1];
00459     F_tilde_LinU[1][0] = -phi_i_grads_u[1][0];
00460     F_tilde_LinU[1][1] = phi_i_grads_u[0][0];
00461 
00462     return (-1.0/(J*J) * J_LinU * F_tilde +
00463             1.0/J * F_tilde_LinU);
00464  
00465   }
00466 
00467  template <int dim> 
00468    inline
00469    Tensor<2,dim>
00470    get_J_F_Inverse_T_LinU (const Tensor<2,dim> phi_i_grads_u)  
00471    {
00472      Tensor<2,dim> tmp;
00473      tmp[0][0] = phi_i_grads_u[1][1];
00474      tmp[0][1] = -phi_i_grads_u[1][0];
00475      tmp[1][0] = -phi_i_grads_u[0][1];
00476      tmp[1][1] = phi_i_grads_u[0][0];
00477      
00478      return  tmp;
00479    }
00480 
00481 
00482  template <int dim> 
00483  inline
00484  double
00485  get_tr_C_LinU (unsigned int q, 
00486                  const std::vector<std::vector<Tensor<1,dim> > > old_solution_grads,
00487                  const Tensor<2,dim> phi_i_grads_u)         
00488 {
00489   return ((1 + old_solution_grads[q][dim][0]) *
00490           phi_i_grads_u[0][0] + 
00491           old_solution_grads[q][dim][1] *
00492           phi_i_grads_u[0][1] +
00493           (1 + old_solution_grads[q][dim+1][1]) *
00494           phi_i_grads_u[1][1] + 
00495           old_solution_grads[q][dim+1][0] *
00496           phi_i_grads_u[1][0]);
00497 }
00498 
00499  
00500 }
00501 
00507 namespace NSEALE
00508 {
00509   template <int dim> 
00510  inline
00511  Tensor<2,dim>
00512  get_stress_fluid_ALE (const double density,
00513                        const double viscosity,  
00514                        const Tensor<2,dim>  pI,
00515                        const Tensor<2,dim>  grad_v,
00516                        const Tensor<2,dim>  grad_v_T,
00517                        const Tensor<2,dim>  F_Inverse,
00518                        const Tensor<2,dim>  F_Inverse_T)
00519   {    
00520     return (-pI + density * viscosity *
00521            (grad_v * F_Inverse + F_Inverse_T * grad_v_T ));
00522   }
00523 
00524   template <int dim> 
00525   inline
00526   Tensor<2,dim>
00527   get_stress_fluid_except_pressure_ALE (const double density,
00528                                         const double viscosity, 
00529                                         const Tensor<2,dim>  grad_v,
00530                                         const Tensor<2,dim>  grad_v_T,
00531                                         const Tensor<2,dim>  F_Inverse,
00532                                         const Tensor<2,dim>  F_Inverse_T)
00533   {
00534     return (density * viscosity * (grad_v * F_Inverse + F_Inverse_T * grad_v_T));
00535   }
00536 
00537   template <int dim> 
00538   inline
00539   Tensor<2,dim> 
00540   get_stress_fluid_ALE_1st_term_LinAll (const Tensor<2,dim>  pI,
00541                                         const Tensor<2,dim>  F_Inverse_T,
00542                                         const Tensor<2,dim>  J_F_Inverse_T_LinU,                                            
00543                                         const Tensor<2,dim>  pI_LinP,
00544                                         const double J)
00545   {          
00546     return (-J * pI_LinP * F_Inverse_T - pI * J_F_Inverse_T_LinU);           
00547   }
00548   
00549   template <int dim> 
00550   inline
00551   Tensor<2,dim> 
00552   get_stress_fluid_ALE_2nd_term_LinAll_short (const Tensor<2,dim> J_F_Inverse_T_LinU,                                       
00553                                               const Tensor<2,dim> stress_fluid_ALE,
00554                                               const Tensor<2,dim> grad_v,
00555                                               const Tensor<2,dim> grad_v_LinV,                                      
00556                                               const Tensor<2,dim> F_Inverse,
00557                                               const Tensor<2,dim> F_Inverse_LinU,                                           
00558                                               const double J,
00559                                               const double viscosity,
00560                                               const double density 
00561                                               )  
00562 {
00563     Tensor<2,dim> sigma_LinV;
00564     Tensor<2,dim> sigma_LinU;
00565 
00566     sigma_LinV = grad_v_LinV * F_Inverse + transpose(F_Inverse) * transpose(grad_v_LinV);
00567     sigma_LinU = grad_v *  F_Inverse_LinU + transpose(F_Inverse_LinU) * transpose(grad_v);
00568  
00569     return (density * viscosity * 
00570             (sigma_LinV + sigma_LinU) * J * transpose(F_Inverse) +
00571             stress_fluid_ALE * J_F_Inverse_T_LinU);    
00572   }
00573 
00574 template <int dim> 
00575 inline
00576 Tensor<2,dim> 
00577 get_stress_fluid_ALE_3rd_term_LinAll_short (const Tensor<2,dim> F_Inverse,                         
00578                                             const Tensor<2,dim> F_Inverse_LinU,                                      
00579                                             const Tensor<2,dim> grad_v,
00580                                             const Tensor<2,dim> grad_v_LinV,                                        
00581                                             const double viscosity,
00582                                             const double density,
00583                                             const double J,
00584                                             const Tensor<2,dim> J_F_Inverse_T_LinU)                                                          
00585 {
00586   return density * viscosity * 
00587     (J_F_Inverse_T_LinU * transpose(grad_v) * transpose(F_Inverse) +
00588      J * transpose(F_Inverse) * transpose(grad_v_LinV) * transpose(F_Inverse) +
00589      J * transpose(F_Inverse) * transpose(grad_v) * transpose(F_Inverse_LinU));  
00590 }
00591 
00592 
00593 
00594 template <int dim> 
00595 inline
00596 double
00597 get_Incompressibility_ALE (unsigned int q,
00598                            std::vector<std::vector<Tensor<1,dim> > > old_solution_grads)         
00599 {
00600   return (old_solution_grads[q][0][0] +
00601           old_solution_grads[q][dim+1][1] * old_solution_grads[q][0][0] -
00602           old_solution_grads[q][dim][1] * old_solution_grads[q][1][0] -
00603           old_solution_grads[q][dim+1][0] * old_solution_grads[q][0][1] +
00604           old_solution_grads[q][1][1] +
00605           old_solution_grads[q][dim][0] * old_solution_grads[q][1][1]); 
00606 
00607 }
00608 
00609 template <int dim> 
00610 inline
00611 double
00612 get_Incompressibility_ALE_LinAll (const Tensor<2,dim> phi_i_grads_v,
00613                                   const Tensor<2,dim> phi_i_grads_u,
00614                                   unsigned int q,                               
00615                                   const std::vector<std::vector<Tensor<1,dim> > > old_solution_grads)               
00616 {
00617   return (phi_i_grads_v[0][0] + phi_i_grads_v[1][1] + 
00618           phi_i_grads_u[1][1] * old_solution_grads[q][0][0] -
00619           phi_i_grads_u[0][1] * old_solution_grads[q][1][0] -
00620           phi_i_grads_u[1][0] * old_solution_grads[q][0][1] +
00621           phi_i_grads_u[0][0] * old_solution_grads[q][1][1]);
00622 }
00623 
00624 
00625   template <int dim> 
00626   inline
00627   Tensor<1,dim> 
00628   get_Convection_LinAll_short (const Tensor<2,dim> phi_i_grads_v,
00629                                const Tensor<1,dim> phi_i_v,
00630                                const double J,
00631                                const double J_LinU,
00632                                const Tensor<2,dim> F_Inverse,
00633                                const Tensor<2,dim> F_Inverse_LinU,                                              
00634                                const Tensor<1,dim> v,
00635                                const Tensor<2,dim> grad_v,                              
00636                                const double density                                  
00637                                )
00638   {
00639     // Linearization of fluid convection term
00640     // rho J(F^{-1}v\cdot\grad)v = rho J grad(v)F^{-1}v
00641     
00642     Tensor<1,dim> convection_LinU;
00643     convection_LinU = (J_LinU * grad_v * F_Inverse * v +
00644                        J * grad_v * F_Inverse_LinU * v);
00645     
00646     Tensor<1,dim> convection_LinV;
00647     convection_LinV = (J * (phi_i_grads_v * F_Inverse * v + 
00648                             grad_v * F_Inverse * phi_i_v));
00649     
00650     return density * (convection_LinU + convection_LinV);
00651   }
00652   
00653 
00654   template <int dim> 
00655   inline
00656   Tensor<1,dim> 
00657   get_Convection_u_LinAll_short (const Tensor<2,dim> phi_i_grads_v,
00658                                  const Tensor<1,dim> phi_i_u,
00659                                  const double J,
00660                                  const double J_LinU,                       
00661                                  const Tensor<2,dim>  F_Inverse,
00662                                  const Tensor<2,dim>  F_Inverse_LinU,
00663                                  const Tensor<1,dim>  u,
00664                                  const Tensor<2,dim>  grad_v,                           
00665                                  const double density                                
00666                                  )
00667   {
00668     // Linearization of fluid convection term
00669     // rho J(F^{-1}v\cdot\grad)u = rho J grad(v)F^{-1}u
00670     
00671     Tensor<1,dim> convection_LinU;
00672     convection_LinU = (J_LinU * grad_v * F_Inverse * u +
00673                        J * grad_v * F_Inverse_LinU * u +
00674                        J * grad_v * F_Inverse * phi_i_u);
00675     
00676     Tensor<1,dim> convection_LinV;
00677     convection_LinV = (J * phi_i_grads_v * F_Inverse * u); 
00678         
00679     return density * (convection_LinU + convection_LinV);
00680 }
00681 
00682 
00683   
00684   template <int dim> 
00685   inline
00686   Tensor<1,dim> 
00687   get_Convection_u_old_LinAll_short (const Tensor<2,dim> phi_i_grads_v,                          
00688                                      const double J,
00689                                      const double J_LinU,                                
00690                                      const Tensor<2,dim>  F_Inverse,
00691                                      const Tensor<2,dim>  F_Inverse_LinU,                                                       
00692                                      const Tensor<1,dim>  old_timestep_solution_displacement,   
00693                                      const Tensor<2,dim>  grad_v,                               
00694                                      const double density                                                                    
00695                                      )
00696   {
00697     // Linearization of fluid convection term
00698     // rho J(F^{-1}v\cdot\grad)u = rho J grad(v)F^{-1}u
00699     
00700     Tensor<1,dim> convection_LinU;
00701     convection_LinU = (J_LinU * grad_v * F_Inverse * old_timestep_solution_displacement +
00702                        J * grad_v * F_Inverse_LinU * old_timestep_solution_displacement);
00703     
00704     Tensor<1,dim> convection_LinV;
00705     convection_LinV = (J * phi_i_grads_v * F_Inverse * old_timestep_solution_displacement); 
00706     
00707     
00708     return density * (convection_LinU  + convection_LinV);
00709   }
00710 
00711 template <int dim> 
00712 inline
00713 Tensor<1,dim> 
00714 get_accelaration_term_LinAll (const Tensor<1,dim> phi_i_v,
00715                               const Tensor<1,dim> v,
00716                               const Tensor<1,dim> old_timestep_v,
00717                               const double J_LinU,
00718                               const double J,
00719                               const double old_timestep_J,
00720                               const double density)
00721 {   
00722   return density/2.0 * (J_LinU * (v - old_timestep_v) + (J + old_timestep_J) * phi_i_v);
00723   
00724 }
00725 
00726 
00727 }
00728 
00729 
00733 namespace StructureTermsALE
00734 {
00735   // Green-Lagrange strain tensor
00736   template <int dim> 
00737   inline
00738   Tensor<2,dim> 
00739   get_E (const Tensor<2,dim> F_T,
00740          const Tensor<2,dim> F,
00741          const Tensor<2,dim> Identity)
00742   {    
00743     return 0.5 * (F_T * F - Identity);
00744   }
00745 
00746   template <int dim> 
00747   inline
00748   double
00749   get_tr_E (const Tensor<2,dim> E)
00750   {     
00751     return trace (E);
00752   }
00753 
00754   template <int dim> 
00755   inline
00756   double
00757   get_tr_E_LinU (unsigned int q, 
00758                  const std::vector<std::vector<Tensor<1,dim> > > old_solution_grads,
00759                  const Tensor<2,dim> phi_i_grads_u)         
00760   {
00761     return ((1 + old_solution_grads[q][dim][0]) *
00762             phi_i_grads_u[0][0] + 
00763             old_solution_grads[q][dim][1] *
00764             phi_i_grads_u[0][1] +
00765             (1 + old_solution_grads[q][dim+1][1]) *
00766             phi_i_grads_u[1][1] + 
00767             old_solution_grads[q][dim+1][0] *
00768             phi_i_grads_u[1][0]); 
00769   }
00770   
00771 }
00772 
00773 
00774 
00784 template <int dim>
00785 class BoundaryParabolic : public Function<dim> 
00786 {
00787   public:
00788   BoundaryParabolic (const double time)    
00789     : Function<dim>(dim+dim+dim+1) 
00790     {
00791       _time = time;      
00792     }
00793     
00794   virtual double value (const Point<dim>   &p,
00795                         const unsigned int  component = 0) const;
00796 
00797   virtual void vector_value (const Point<dim> &p, 
00798                              Vector<double>   &value) const;
00799 
00800 private:
00801   double _time;
00802 
00803 };
00804 
00805 // The boundary values are given to component 
00806 // with number 0.
00807 template <int dim>
00808 double
00809 BoundaryParabolic<dim>::value (const Point<dim>  &p,
00810                              const unsigned int component) const
00811 {
00812   Assert (component < this->n_components,
00813           ExcIndexRange (component, 0, this->n_components));
00814 
00815   const long double pi = 3.141592653589793238462643;
00816   
00817   // The maximum inflow depends on the configuration
00818   // for the different test cases:
00819   // FSI 1: 0.2; FSI 2: 1.0; FSI 3: 2.0
00820   //
00821   // For the two unsteady test cases FSI 2 and FSI 3, it
00822   // is recommanded to start with a smooth increase of 
00823   // the inflow. Hence, we use the cosine function 
00824   // to control the inflow at the beginning until
00825   // the total time 2.0 has been reached. 
00826   double inflow_velocity = 2.0e-1;
00827 
00828   if (component == 0)   
00829     {
00830       if (_time < 2.0)
00831         {
00832           return   ( (p(0) == 0) && (p(1) <= 0.41) ? -1.5 * inflow_velocity * 
00833                      (1.0 - std::cos(pi/2.0 * _time))/2.0 * 
00834                      (4.0/0.1681) *                                 
00835                      (std::pow(p(1), 2) - 0.41 * std::pow(p(1),1)) : 0 );
00836         }
00837       else 
00838         {
00839           return ( (p(0) == 0) && (p(1) <= 0.41) ? -1.5 * inflow_velocity *                     
00840                    (4.0/0.1681) *                                   
00841                    (std::pow(p(1), 2) - 0.41 * std::pow(p(1),1)) : 0 );
00842           
00843         }
00844 
00845     }
00846  
00847   return 0;
00848 }
00849 
00850 
00851 
00852 template <int dim>
00853 void
00854 BoundaryParabolic<dim>::vector_value (const Point<dim> &p,
00855                                     Vector<double>   &values) const 
00856 {
00857   for (unsigned int c=0; c<this->n_components; ++c)
00858     values (c) = BoundaryParabolic<dim>::value (p, c);
00859 }
00860 
00861 
00913 template <int dim>
00914 class FSIALEProblem 
00915 {
00916 public:
00917   
00918   FSIALEProblem (const unsigned int degree);
00919   ~FSIALEProblem (); 
00920   void run ();
00921   
00922 private:
00923   
00924   void set_runtime_parameters ();
00925   void setup_system ();
00926   void assemble_system_matrix ();   
00927   void assemble_system_rhs ();
00928   
00929   void set_initial_bc (const double time);
00930   void set_newton_bc ();
00931   
00932   void solve ();
00933   void newton_iteration(const double time);                       
00934   void output_results (const unsigned int refinement_cycle,
00935                        const BlockVector<double> solution) const;
00936   
00937   double compute_point_value (Point<dim> p,
00938                               const unsigned int component) const;
00939   
00940   void compute_drag_lift_fsi_fluid_tensor ();
00941   void compute_functional_values (); 
00942 
00943   const unsigned int   degree;
00944   
00945   Triangulation<dim>   triangulation;
00946   FESystem<dim>        fe;
00947   DoFHandler<dim>      dof_handler;
00948 
00949   ConstraintMatrix     constraints;
00950   
00951   BlockSparsityPattern      sparsity_pattern; 
00952   BlockSparseMatrix<double> system_matrix; 
00953   
00954   BlockVector<double> solution, newton_update, old_timestep_solution;
00955   BlockVector<double> system_rhs;
00956   
00957   TimerOutput         timer;
00958   
00959   // Global variables for timestepping scheme   
00960   unsigned int timestep_number;
00961   unsigned int max_no_timesteps;  
00962   double timestep, theta, time; 
00963   std::string time_stepping_scheme;
00964 
00965   // Fluid parameters 
00966   double density_fluid, viscosity; 
00967   
00968   // Structure parameters
00969   double density_structure; 
00970   double lame_coefficient_mu, lame_coefficient_lambda, poisson_ratio_nu;  
00971 
00972   // Other parameters to control the fluid mesh motion 
00973   double cell_diameter;  
00974   double alpha_u, alpha_w;
00975   
00976  
00977   
00978   
00979 
00980 };
00981 
00982 
00989 template <int dim>
00990 FSIALEProblem<dim>::FSIALEProblem (const unsigned int degree)
00991                 :
00992                 degree (degree),
00993                 triangulation (Triangulation<dim>::maximum_smoothing),
00994                 fe (FE_Q<dim>(degree+1), dim,                    
00995                     FE_Q<dim>(degree+1), dim,               
00996                     FE_DGP<dim>(degree), 1,
00997                     FE_Q<dim>(degree+1), dim),            
00998                 dof_handler (triangulation),
00999                 timer (std::cout, TimerOutput::summary, TimerOutput::cpu_times)         
01000 {}
01001 
01002 
01003 // This is the standard destructor.
01004 template <int dim>
01005 FSIALEProblem<dim>::~FSIALEProblem () 
01006 {}
01007 
01008 
01015 template <int dim>
01016 void FSIALEProblem<dim>::set_runtime_parameters ()
01017 {
01018    // Fluid parameters
01019   density_fluid = 1.0e+3;
01020 
01021   // FSI 1 & 3: 1.0e+3; FSI 2: 1.0e+4
01022   density_structure = 1.0e+3; 
01023   viscosity = 1.0e-3; 
01024 
01025   // Structure parameters
01026   // FSI 1 & 2: 0.5e+6; FSI 3: 2.0e+6
01027   lame_coefficient_mu = 0.5e+6; 
01028   poisson_ratio_nu = 0.4; 
01029   
01030   lame_coefficient_lambda =  (2 * poisson_ratio_nu * lame_coefficient_mu)/
01031     (1.0 - 2 * poisson_ratio_nu);
01032 
01033   // Diffusion parameters to control the fluid mesh motion
01034   // The higher these parameters the stiffer the fluid mesh.
01035   alpha_u = 1.0e-5;
01036   alpha_w = 1.0e-5;
01037   
01038   // Timestepping schemes
01039   //BE, CN, CN_shifted
01040   time_stepping_scheme = "BE";
01041 
01042   // Timestep size:
01043   // FSI 1: 1.0 (quasi-stationary)
01044   // FSI 2: <= 1.0e-2 (non-stationary)
01045   // FSI 3: <= 1.0e-3 (non-stationary)
01046   timestep = 1.0;
01047 
01048   // Maximum number of timesteps:
01049   // FSI 1: 25 , T= 25   (timestep == 1.0)
01050   // FSI 2: 1500, T= 15  (timestep == 1.0e-2)
01051   // FSI 3: 10000, T= 10 (timestep == 1.0e-3)
01052   max_no_timesteps = 25;
01053   
01054   // A variable to count the number of time steps
01055   timestep_number = 0;
01056 
01057   // Counts total time  
01058   time = 0;
01059  
01060   // Here, we choose a time-stepping scheme that
01061   // is based on finite differences:
01062   // BE         = backward Euler scheme 
01063   // CN         = Crank-Nicolson scheme
01064   // CN_shifted = time-shifted Crank-Nicolson scheme 
01065   // For further properties of these schemes,
01066   // we refer to standard literature.
01067   if (time_stepping_scheme == "BE")
01068     theta = 1.0;
01069   else if (time_stepping_scheme == "CN")
01070     theta = 0.5;
01071   else if (time_stepping_scheme == "CN_shifted")
01072     theta = 0.5 + timestep;
01073   else 
01074     std::cout << "No such timestepping scheme" << std::endl;
01075 
01076   // In the following, we read a *.inp grid from a file.
01077   // The geometry information is based on the 
01078   // fluid-structure interaction benchmark problems 
01079   // (Lit. J. Hron, S. Turek, 2006)
01080   std::string grid_name;
01081   grid_name  = "fsi.inp"; 
01082   
01083   GridIn<dim> grid_in;
01084   grid_in.attach_triangulation (triangulation);
01085   std::ifstream input_file(grid_name.c_str());      
01086   Assert (dim==2, ExcInternalError());
01087   grid_in.read_ucd (input_file); 
01088   
01089   Point<dim> p(0.2, 0.2);
01090   double radius = 0.05;
01091   static const HyperBallBoundary<dim> boundary(p,radius);
01092   triangulation.set_boundary (80, boundary);
01093   triangulation.set_boundary (81, boundary);
01094     
01095   triangulation.refine_global (1); 
01096  
01097 }
01098 
01099 
01100 
01101 // This function is similar to many deal.II tuturial steps.
01102 template <int dim>
01103 void FSIALEProblem<dim>::setup_system ()
01104 {
01105   timer.enter_section("Setup system.");
01106 
01107   // We set runtime parameters to drive the problem.
01108   // These parameters could also be read from a parameter file that
01109   // can be handled by the ParameterHandler object (see step-19)
01110   set_runtime_parameters ();
01111 
01112   system_matrix.clear ();
01113   
01114   dof_handler.distribute_dofs (fe);  
01115   DoFRenumbering::Cuthill_McKee (dof_handler);
01116 
01117   // We are dealing with 7 components for this 
01118   // two-dimensional fluid-structure interacion problem
01119   // Precisely, we use:
01120   // velocity in x and y:                0
01121   // structure displacement in x and y:  1
01122   // scalar pressure field:              2
01123   // additional displacement in x and y: 3
01124   std::vector<unsigned int> block_component (7,0);
01125   block_component[dim] = 1;
01126   block_component[dim+1] = 1;
01127   block_component[dim+dim] = 2;
01128   block_component[dim+dim+1] = 3;
01129   block_component[dim+dim+dim] = 3;
01130  
01131   DoFRenumbering::component_wise (dof_handler, block_component);
01132 
01133   {                              
01134     constraints.clear ();
01135     set_newton_bc ();
01136     DoFTools::make_hanging_node_constraints (dof_handler,
01137                                              constraints);
01138   }
01139   constraints.close ();
01140   
01141   std::vector<unsigned int> dofs_per_block (4);
01142   DoFTools::count_dofs_per_block (dof_handler, dofs_per_block, block_component);  
01143   const unsigned int n_v = dofs_per_block[0],
01144     n_u = dofs_per_block[1],
01145     n_p =  dofs_per_block[2],
01146     n_w =  dofs_per_block[3];
01147 
01148   std::cout << "Cells:\t"
01149             << triangulation.n_active_cells()
01150             << std::endl          
01151             << "DoFs:\t"
01152             << dof_handler.n_dofs()
01153             << " (" << n_v << '+' << n_u << '+' << n_p << '+' << n_w <<  ')'
01154             << std::endl;
01155 
01156 
01157  
01158       
01159  {
01160     BlockCompressedSimpleSparsityPattern csp (4,4);
01161 
01162     csp.block(0,0).reinit (n_v, n_v);
01163     csp.block(0,1).reinit (n_v, n_u);
01164     csp.block(0,2).reinit (n_v, n_p);
01165     csp.block(0,3).reinit (n_v, n_w);
01166   
01167     csp.block(1,0).reinit (n_u, n_v);
01168     csp.block(1,1).reinit (n_u, n_u);
01169     csp.block(1,2).reinit (n_u, n_p);
01170     csp.block(1,3).reinit (n_u, n_w);
01171   
01172     csp.block(2,0).reinit (n_p, n_v);
01173     csp.block(2,1).reinit (n_p, n_u);
01174     csp.block(2,2).reinit (n_p, n_p);
01175     csp.block(2,3).reinit (n_p, n_w);
01176 
01177     csp.block(3,0).reinit (n_w, n_v);
01178     csp.block(3,1).reinit (n_w, n_u);
01179     csp.block(3,2).reinit (n_w, n_p);
01180     csp.block(3,3).reinit (n_w, n_w);
01181  
01182     csp.collect_sizes();    
01183   
01184 
01185     DoFTools::make_sparsity_pattern (dof_handler, csp, constraints, false);
01186 
01187     sparsity_pattern.copy_from (csp);
01188   }
01189  
01190  system_matrix.reinit (sparsity_pattern);
01191 
01192   // Actual solution at time step n
01193   solution.reinit (4);
01194   solution.block(0).reinit (n_v);
01195   solution.block(1).reinit (n_u);
01196   solution.block(2).reinit (n_p);
01197   solution.block(3).reinit (n_w);
01198  
01199   solution.collect_sizes ();
01200  
01201   // Old timestep solution at time step n-1
01202   old_timestep_solution.reinit (4);
01203   old_timestep_solution.block(0).reinit (n_v);
01204   old_timestep_solution.block(1).reinit (n_u);
01205   old_timestep_solution.block(2).reinit (n_p);
01206   old_timestep_solution.block(3).reinit (n_w);
01207  
01208   old_timestep_solution.collect_sizes ();
01209 
01210 
01211   // Updates for Newton's method
01212   newton_update.reinit (4);
01213   newton_update.block(0).reinit (n_v);
01214   newton_update.block(1).reinit (n_u);
01215   newton_update.block(2).reinit (n_p);
01216   newton_update.block(3).reinit (n_w);
01217  
01218   newton_update.collect_sizes ();
01219  
01220   // Residual for  Newton's method
01221   system_rhs.reinit (4);
01222   system_rhs.block(0).reinit (n_v);
01223   system_rhs.block(1).reinit (n_u);
01224   system_rhs.block(2).reinit (n_p);
01225   system_rhs.block(3).reinit (n_w);
01226 
01227   system_rhs.collect_sizes ();
01228 
01229   timer.exit_section(); 
01230 }
01231 
01232 
01258 template <int dim>
01259 void FSIALEProblem<dim>::assemble_system_matrix ()
01260 {
01261   timer.enter_section("Assemble Matrix.");
01262   system_matrix=0;
01263      
01264   QGauss<dim>   quadrature_formula(degree+2);  
01265   QGauss<dim-1> face_quadrature_formula(degree+2);
01266 
01267   FEValues<dim> fe_values (fe, quadrature_formula,
01268                            update_values    |
01269                            update_quadrature_points  |
01270                            update_JxW_values |
01271                            update_gradients);
01272   
01273   FEFaceValues<dim> fe_face_values (fe, face_quadrature_formula, 
01274                                     update_values         | update_quadrature_points  |
01275                                     update_normal_vectors | update_gradients |
01276                                     update_JxW_values);
01277    
01278   const unsigned int   dofs_per_cell   = fe.dofs_per_cell;
01279   
01280   const unsigned int   n_q_points      = quadrature_formula.size();
01281   const unsigned int n_face_q_points   = face_quadrature_formula.size();
01282 
01283   FullMatrix<double>   local_matrix (dofs_per_cell, dofs_per_cell);
01284 
01285   std::vector<unsigned int> local_dof_indices (dofs_per_cell); 
01286                 
01287 
01288   // Now, we are going to use the 
01289   // FEValuesExtractors to determine
01290   // the four principle variables
01291   const FEValuesExtractors::Vector velocities (0);
01292   const FEValuesExtractors::Vector displacements (dim); // 2
01293   const FEValuesExtractors::Scalar pressure (dim+dim); // 4
01294   const FEValuesExtractors::Vector displacements_w (dim+dim+1); // 4
01295  
01296 
01297   // We declare Vectors and Tensors for 
01298   // the solutions at the previous Newton iteration:
01299   std::vector<Vector<double> > old_solution_values (n_q_points, 
01300                                                     Vector<double>(dim+dim+dim+1));
01301 
01302   std::vector<std::vector<Tensor<1,dim> > > old_solution_grads (n_q_points, 
01303                                                                 std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01304 
01305   std::vector<Vector<double> >  old_solution_face_values (n_face_q_points, 
01306                                                           Vector<double>(dim+dim+dim+1));
01307        
01308   std::vector<std::vector<Tensor<1,dim> > > old_solution_face_grads (n_face_q_points, 
01309                                                                      std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01310     
01311 
01312   // We declare Vectors and Tensors for 
01313   // the solution at the previous time step:
01314    std::vector<Vector<double> > old_timestep_solution_values (n_q_points, 
01315                                                     Vector<double>(dim+dim+dim+1));
01316 
01317 
01318   std::vector<std::vector<Tensor<1,dim> > > old_timestep_solution_grads (n_q_points, 
01319                                           std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01320 
01321 
01322   std::vector<Vector<double> >   old_timestep_solution_face_values (n_face_q_points, 
01323                                                                     Vector<double>(dim+dim+dim+1));
01324   
01325     
01326   std::vector<std::vector<Tensor<1,dim> > >  old_timestep_solution_face_grads (n_face_q_points, 
01327                                                                                std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01328    
01329   // Declaring test functions:
01330   std::vector<Tensor<1,dim> > phi_i_v (dofs_per_cell); 
01331   std::vector<Tensor<2,dim> > phi_i_grads_v(dofs_per_cell);
01332   std::vector<double>         phi_i_p(dofs_per_cell);   
01333   std::vector<Tensor<1,dim> > phi_i_u (dofs_per_cell); 
01334   std::vector<Tensor<2,dim> > phi_i_grads_u(dofs_per_cell);
01335   std::vector<Tensor<1,dim> > phi_i_w (dofs_per_cell); 
01336   std::vector<Tensor<2,dim> > phi_i_grads_w(dofs_per_cell);
01337 
01338   // This is the identity matrix in two dimensions:
01339   const Tensor<2,dim> Identity = ALETransformations
01340     ::get_Identity<dim> ();
01341                                                                    
01342   typename DoFHandler<dim>::active_cell_iterator
01343     cell = dof_handler.begin_active(),
01344     endc = dof_handler.end();
01345   
01346   for (; cell!=endc; ++cell)
01347     { 
01348       fe_values.reinit (cell);
01349       local_matrix = 0;
01350       
01351       // We need the cell diameter to control the fluid mesh motion
01352       cell_diameter = cell->diameter();
01353       
01354       // Old Newton iteration values
01355       fe_values.get_function_values (solution, old_solution_values);
01356       fe_values.get_function_grads (solution, old_solution_grads);
01357       
01358       // Old_timestep_solution values
01359       fe_values.get_function_values (old_timestep_solution, old_timestep_solution_values);
01360       fe_values.get_function_grads (old_timestep_solution, old_timestep_solution_grads);
01361       
01362       // Next, we run over all cells for the fluid equations
01363       if (cell->material_id() == 0)
01364         {
01365           for (unsigned int q=0; q<n_q_points; ++q)
01366             {
01367               for (unsigned int k=0; k<dofs_per_cell; ++k)
01368                 {
01369                   phi_i_v[k]       = fe_values[velocities].value (k, q);
01370                   phi_i_grads_v[k] = fe_values[velocities].gradient (k, q);
01371                   phi_i_p[k]       = fe_values[pressure].value (k, q);                                           
01372                   phi_i_u[k]       = fe_values[displacements].value (k, q);
01373                   phi_i_grads_u[k] = fe_values[displacements].gradient (k, q);
01374                   phi_i_w[k]       = fe_values[displacements_w].value (k, q);
01375                   phi_i_grads_w[k] = fe_values[displacements_w].gradient (k, q);
01376                 }
01377               
01378               // We build values, vectors, and tensors
01379               // from information of the previous Newton step. These are introduced 
01380               // for two reasons:
01381               // First, these are used to perform the ALE mapping of the 
01382               // fluid equations. Second, these terms are used to 
01383               // make the notation as simple and self-explaining as possible:
01384               const Tensor<2,dim> pI = ALETransformations               
01385                 ::get_pI<dim> (q, old_solution_values);
01386               
01387               const Tensor<1,dim> v = ALETransformations
01388                 ::get_v<dim> (q, old_solution_values);
01389               
01390               const Tensor<1,dim> u = ALETransformations
01391                 ::get_u<dim> (q,old_solution_values);
01392                               
01393               const Tensor<2,dim> grad_v = ALETransformations
01394                 ::get_grad_v<dim> (q, old_solution_grads);      
01395               
01396               const Tensor<2,dim> grad_v_T = ALETransformations
01397                 ::get_grad_v_T<dim> (grad_v);
01398               
01399               const Tensor<2,dim> F = ALETransformations
01400                 ::get_F<dim> (q, old_solution_grads);       
01401               
01402               const Tensor<2,dim> F_Inverse = ALETransformations
01403                 ::get_F_Inverse<dim> (F);
01404               
01405               const Tensor<2,dim> F_Inverse_T = ALETransformations
01406                 ::get_F_Inverse_T<dim> (F_Inverse);
01407               
01408               const double J = ALETransformations
01409                 ::get_J<dim> (F);
01410               
01411               // Stress tensor for the fluid in ALE notation          
01412               const Tensor<2,dim> sigma_ALE = NSEALE
01413                 ::get_stress_fluid_ALE<dim> (density_fluid, viscosity, pI,
01414                                              grad_v, grad_v_T, F_Inverse, F_Inverse_T );
01415               
01416               // Further, we also need some information from the previous time steps
01417               const Tensor<1,dim> old_timestep_v = ALETransformations
01418                 ::get_v<dim> (q, old_timestep_solution_values);
01419 
01420               const Tensor<1,dim> old_timestep_u = ALETransformations
01421                 ::get_u<dim> (q, old_timestep_solution_values);
01422               
01423               const Tensor<2,dim> old_timestep_F = ALETransformations
01424                 ::get_F<dim> (q, old_timestep_solution_grads);
01425               
01426               const double old_timestep_J = ALETransformations
01427                 ::get_J<dim> (old_timestep_F);
01428               
01429               // Outer loop for dofs
01430               for (unsigned int i=0; i<dofs_per_cell; ++i)
01431                 {       
01432                   const Tensor<2,dim> pI_LinP = ALETransformations
01433                     ::get_pI_LinP<dim> (phi_i_p[i]);
01434                   
01435                   const Tensor<2,dim> grad_v_LinV = ALETransformations
01436                     ::get_grad_v_LinV<dim> (phi_i_grads_v[i]);
01437                   
01438                   const double J_LinU =  ALETransformations
01439                     ::get_J_LinU<dim> (q, old_solution_grads, phi_i_grads_u[i]);
01440                   
01441                   const Tensor<2,dim> J_F_Inverse_T_LinU = ALETransformations
01442                     ::get_J_F_Inverse_T_LinU<dim> (phi_i_grads_u[i]);
01443                   
01444                   const Tensor<2,dim> F_Inverse_LinU = ALETransformations
01445 		    ::get_F_Inverse_LinU (phi_i_grads_u[i], J, J_LinU, q, old_solution_grads);
01446                     
01447                   const Tensor<2,dim>  stress_fluid_ALE_1st_term_LinAll = NSEALE                        
01448                     ::get_stress_fluid_ALE_1st_term_LinAll<dim> 
01449                     (pI, F_Inverse_T, J_F_Inverse_T_LinU, pI_LinP, J);
01450                                                       
01451                   const Tensor<2,dim> stress_fluid_ALE_2nd_term_LinAll = NSEALE
01452 		    ::get_stress_fluid_ALE_2nd_term_LinAll_short 
01453                     (J_F_Inverse_T_LinU, sigma_ALE, grad_v, grad_v_LinV,                                                                      
01454                      F_Inverse, F_Inverse_LinU, J, viscosity, density_fluid);  
01455 
01456                   const Tensor<1,dim> convection_fluid_LinAll_short = NSEALE                
01457                     ::get_Convection_LinAll_short<dim> 
01458                     (phi_i_grads_v[i], phi_i_v[i], J,J_LinU,                                            
01459                      F_Inverse, F_Inverse_LinU, v, grad_v, density_fluid);
01460            
01461                   const double incompressibility_ALE_LinAll = NSEALE
01462                     ::get_Incompressibility_ALE_LinAll<dim> 
01463                     (phi_i_grads_v[i], phi_i_grads_u[i], q, old_solution_grads); 
01464                                              
01465                   const Tensor<1,dim> accelaration_term_LinAll = NSEALE
01466 		    ::get_accelaration_term_LinAll 
01467                     (phi_i_v[i], v, old_timestep_v, J_LinU,
01468                      J, old_timestep_J, density_fluid);
01469               
01470                   const Tensor<1,dim> convection_fluid_u_LinAll_short =  NSEALE
01471                     ::get_Convection_u_LinAll_short<dim> 
01472                     (phi_i_grads_v[i], phi_i_u[i], J,J_LinU, F_Inverse,
01473                      F_Inverse_LinU, u, grad_v, density_fluid);
01474 
01475                   const Tensor<1,dim> convection_fluid_u_old_LinAll_short = NSEALE
01476                     ::get_Convection_u_old_LinAll_short<dim> 
01477                     (phi_i_grads_v[i], J, J_LinU, F_Inverse,
01478                      F_Inverse_LinU, old_timestep_u, grad_v, density_fluid);
01479         
01480                   // Inner loop for dofs
01481                   for (unsigned int j=0; j<dofs_per_cell; ++j)
01482                     {   
01483                       // Fluid , NSE in ALE
01484                       const unsigned int comp_j = fe.system_to_component_index(j).first; 
01485                       if (comp_j == 0 || comp_j == 1)
01486                         {               
01487                           local_matrix(j,i) += (accelaration_term_LinAll * phi_i_v[j] +   
01488                                                 timestep * theta *                                        
01489                                                 convection_fluid_LinAll_short * phi_i_v[j] -                                          
01490                                                 convection_fluid_u_LinAll_short * phi_i_v[j] +
01491                                                 convection_fluid_u_old_LinAll_short * phi_i_v[j] +
01492                                                 timestep * scalar_product(stress_fluid_ALE_1st_term_LinAll, phi_i_grads_v[j]) +
01493                                                 timestep * theta *
01494                                                 scalar_product(stress_fluid_ALE_2nd_term_LinAll, phi_i_grads_v[j])                                       
01495                                                 ) * fe_values.JxW(q);
01496                         }                                           
01497                       else if (comp_j == 2 || comp_j == 3)
01498                         {
01499                           local_matrix(j,i) += (alpha_u * scalar_product(phi_i_grads_w[i], phi_i_grads_u[j])
01500                                                 ) * fe_values.JxW(q);
01501                         }
01502                       else if (comp_j == 4)
01503                         {
01504                           local_matrix(j,i) += (incompressibility_ALE_LinAll *  phi_i_p[j] 
01505                                                 ) * fe_values.JxW(q);           
01506                         }
01507                       else if (comp_j == 5 || comp_j == 6)
01508                         {
01509                           local_matrix(j,i) += (alpha_w * (phi_i_w[i] * phi_i_w[j] - scalar_product(phi_i_grads_u[i],phi_i_grads_w[j])) 
01510                                                 ) * fe_values.JxW(q);
01511                         }
01512                       
01513                       // end j dofs  
01514                     }   
01515                   // end i dofs   
01516                 }   
01517               // end n_q_points  
01518             }    
01519                   
01520           // We compute in the following
01521           // one term on the outflow boundary. 
01522           // This relation is well-know in the literature 
01523           // as "do-nothing" condition. Therefore, we only
01524           // ask for the corresponding color at the outflow 
01525           // boundary that is 1 in our case.
01526           for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
01527             {
01528               if (cell->face(face)->at_boundary() &&              
01529                   (cell->face(face)->boundary_indicator() == 1) 
01530                   )
01531                 {
01532                   
01533                   fe_face_values.reinit (cell, face);
01534                   
01535                   fe_face_values.get_function_values (solution, old_solution_face_values);
01536                   fe_face_values.get_function_grads (solution, old_solution_face_grads);        
01537                   
01538                   for (unsigned int q=0; q<n_face_q_points; ++q)
01539                     {
01540                       for (unsigned int k=0; k<dofs_per_cell; ++k)
01541                         {
01542                           phi_i_v[k]       = fe_face_values[velocities].value (k, q);
01543                           phi_i_grads_v[k] = fe_face_values[velocities].gradient (k, q);                
01544                           phi_i_grads_u[k] = fe_face_values[displacements].gradient (k, q);
01545                         }
01546                       
01547                       const Tensor<2,dim> pI = ALETransformations
01548                         ::get_pI<dim> (q, old_solution_face_values);
01549                       
01550                       const Tensor<1,dim> v = ALETransformations
01551                         ::get_v<dim> (q, old_solution_face_values);
01552                       
01553                       const Tensor<2,dim>  grad_v = ALETransformations
01554                         ::get_grad_v<dim> (q, old_solution_face_grads);
01555                       
01556                       const Tensor<2,dim> grad_v_T = ALETransformations 
01557                         ::get_grad_v_T<dim> (grad_v);
01558                       
01559                       const Tensor<2,dim> F = ALETransformations
01560                         ::get_F<dim> (q, old_solution_face_grads);
01561                       
01562                       const Tensor<2,dim> F_Inverse = ALETransformations
01563                         ::get_F_Inverse<dim> (F);
01564                       
01565                       const Tensor<2,dim> F_Inverse_T = ALETransformations
01566                         ::get_F_Inverse_T<dim> (F_Inverse);
01567                       
01568                       const double J = ALETransformations
01569                         ::get_J<dim> (F);
01570                       
01571                       
01572                       for (unsigned int i=0; i<dofs_per_cell; ++i)
01573                         {
01574                           const Tensor<2,dim> grad_v_LinV = ALETransformations
01575                             ::get_grad_v_LinV<dim> (phi_i_grads_v[i]);
01576                           
01577                           const double J_LinU = ALETransformations
01578                             ::get_J_LinU<dim> (q, old_solution_face_grads, phi_i_grads_u[i]);
01579                                                                   
01580                           const Tensor<2,dim> J_F_Inverse_T_LinU = ALETransformations
01581                             ::get_J_F_Inverse_T_LinU<dim> (phi_i_grads_u[i]);
01582                           
01583                           const Tensor<2,dim> F_Inverse_LinU = ALETransformations
01584 			    ::get_F_Inverse_LinU 
01585                             (phi_i_grads_u[i], J, J_LinU, q, old_solution_face_grads);
01586                           
01587                           const Tensor<2,dim> stress_fluid_ALE_3rd_term_LinAll =  NSEALE
01588                             ::get_stress_fluid_ALE_3rd_term_LinAll_short<dim> 
01589                             (F_Inverse, F_Inverse_LinU, grad_v, grad_v_LinV,
01590                              viscosity, density_fluid, J, J_F_Inverse_T_LinU);
01591                                 
01592                           // Here, we multiply the symmetric part of fluid's stress tensor
01593                           // with the normal direction.
01594                           const Tensor<1,dim> neumann_value
01595                             = (stress_fluid_ALE_3rd_term_LinAll * fe_face_values.normal_vector(q));
01596                           
01597                           for (unsigned int j=0; j<dofs_per_cell; ++j)
01598                             {                
01599                               const unsigned int comp_j = fe.system_to_component_index(j).first; 
01600                               if (comp_j == 0 || comp_j == 1)
01601                                 {
01602                                   local_matrix(j,i) -= (timestep * theta *
01603                                                         neumann_value * phi_i_v[j] 
01604                                                         ) * fe_face_values.JxW(q);
01605                                 }
01606                               // end j    
01607                             } 
01608                           // end i
01609                         }   
01610                       // end q_face_points
01611                     } 
01612                   // end if-routine face integrals
01613                 }             
01614               // end face integrals 
01615             }   
01616 
01617           
01618           // Next, we compute the face integrals on the interface between fluid and structure.
01619           // The appear because of partial integration of the additional equations for 
01620           // the fluid mesh motion.       
01621           for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
01622             {
01623               if (cell->neighbor_index(face) != -1)            
01624                 if (cell->material_id() !=  cell->neighbor(face)->material_id() &&
01625                     cell->face(face)->boundary_indicator()!=81)
01626                   {
01627                     
01628                     fe_face_values.reinit (cell, face);
01629                     
01630                     for (unsigned int q=0; q<n_face_q_points; ++q)
01631                       {
01632                         for (unsigned int k=0; k<dofs_per_cell; ++k)
01633                           {
01634                             phi_i_u[k]       = fe_face_values[displacements].value (k, q); 
01635                             phi_i_grads_u[k] = fe_face_values[displacements].gradient (k, q);           
01636 
01637                             phi_i_w[k]       = fe_face_values[displacements_w].value (k, q); 
01638                             phi_i_grads_w[k] = fe_face_values[displacements_w].gradient (k, q);         
01639                           }
01640                                                                                          
01641                         for (unsigned int i=0; i<dofs_per_cell; ++i)
01642                           {
01643                             const Tensor<1,dim> neumann_value_w
01644                               = (phi_i_grads_w[i] * fe_face_values.normal_vector(q));
01645 
01646                             const Tensor<1,dim> neumann_value_u
01647                               = (phi_i_grads_u[i] * fe_face_values.normal_vector(q));
01648                             
01649                             for (unsigned int j=0; j<dofs_per_cell; ++j)
01650                               {              
01651                                 const unsigned int comp_j = fe.system_to_component_index(j).first; 
01652                                 if (comp_j == 2 || comp_j == 3)
01653                                   {                       
01654                                     local_matrix(j,i) -= (alpha_u * neumann_value_w * phi_i_u[j] * fe_face_values.JxW(q));         
01655                                     
01656                                   }
01657                                 else if (comp_j == 5 || comp_j == 6)
01658                                   {
01659                                     local_matrix(j,i) -= (alpha_w * neumann_value_u * phi_i_w[j] *  fe_face_values.JxW(q));  
01660 
01661                                   }
01662 
01663                               }  // end j
01664                             
01665                           }   // end i
01666                         
01667                       }  // end q_face_points
01668                   }  // end if-routine face integrals
01669               
01670               
01671             }   // end face artificial Gamma i //
01672           
01673 
01674           // This is the same as discussed in step-22:
01675           cell->get_dof_indices (local_dof_indices);
01676           constraints.distribute_local_to_global (local_matrix, local_dof_indices,
01677                                                   system_matrix);
01678           
01679           // Finally, we arrive at the end for assembling the matrix
01680           // for the fluid equations and step to the computation of the 
01681           // structure terms:
01682         } 
01683       else if (cell->material_id() == 1)
01684         {             
01685           for (unsigned int q=0; q<n_q_points; ++q)
01686             {         
01687               for (unsigned int k=0; k<dofs_per_cell; ++k)
01688                 {
01689                   phi_i_v[k]       = fe_values[velocities].value (k, q);
01690                   phi_i_grads_v[k] = fe_values[velocities].gradient (k, q);
01691                   phi_i_p[k]       = fe_values[pressure].value (k, q);                                           
01692                   phi_i_u[k]       = fe_values[displacements].value (k, q);
01693                   phi_i_grads_u[k] = fe_values[displacements].gradient (k, q);
01694                   phi_i_w[k]       = fe_values[displacements_w].value (k, q);
01695                   phi_i_grads_w[k] = fe_values[displacements_w].gradient (k, q);
01696                 }
01697               
01698               // It is here the same as already shown for the fluid equations.
01699               // First, we prepare things coming from the previous Newton
01700               // iteration...
01701               const Tensor<2,dim> pI = ALETransformations       
01702                 ::get_pI<dim> (q, old_solution_values);
01703               
01704               const Tensor<2,dim> grad_v = ALETransformations
01705                 ::get_grad_v<dim> (q, old_solution_grads);
01706               
01707               const Tensor<2,dim> grad_v_T = ALETransformations 
01708                 ::get_grad_v_T<dim> (grad_v);
01709               
01710               const Tensor<1,dim> v = ALETransformations
01711                 ::get_v<dim> (q, old_solution_values);
01712                               
01713               const Tensor<2,dim> F = ALETransformations
01714                 ::get_F<dim> (q, old_solution_grads);
01715               
01716               const Tensor<2,dim> F_Inverse = ALETransformations
01717                 ::get_F_Inverse<dim> (F);
01718               
01719               const Tensor<2,dim> F_Inverse_T = ALETransformations
01720                 ::get_F_Inverse_T<dim> (F_Inverse);
01721               
01722               const Tensor<2,dim> F_T = ALETransformations
01723                 ::get_F_T<dim> (F);
01724               
01725               const double J = ALETransformations
01726                 ::get_J<dim> (F);
01727 
01728               const Tensor<2,dim> E = StructureTermsALE 
01729                 ::get_E<dim> (F_T, F, Identity);
01730               
01731               const double tr_E = StructureTermsALE
01732                 ::get_tr_E<dim> (E);
01733 
01734               // ... and then things coming from the previous time steps
01735               const Tensor<1,dim> old_timestep_v = ALETransformations
01736                 ::get_v<dim> (q, old_timestep_solution_values);
01737               
01738               const Tensor<2,dim> old_timestep_F = ALETransformations
01739                 ::get_F<dim> (q, old_timestep_solution_grads);
01740               
01741               const double old_timestep_J = ALETransformations
01742                 ::get_J<dim> (old_timestep_F);
01743                     
01744                       
01745               for (unsigned int i=0; i<dofs_per_cell; ++i)
01746                 {                               
01747                   const Tensor<2,dim> pI_LinP = ALETransformations
01748                     ::get_pI_LinP<dim> (phi_i_p[i]);
01749                   
01750                   const double J_LinU = ALETransformations
01751                     ::get_J_LinU<dim> (q, old_solution_grads, phi_i_grads_u[i]);
01752                                                   
01753                   const Tensor<2,dim> F_LinU = ALETransformations                 
01754                     ::get_F_LinU<dim> (phi_i_grads_u[i]);
01755                   
01756                   const Tensor<2,dim> F_Inverse_LinU = ALETransformations
01757                     ::get_F_Inverse_LinU<dim> 
01758                     (phi_i_grads_u[i], J, J_LinU, q, old_solution_grads);
01759                     
01760                   const Tensor<2,dim> F_Inverse_T_LinU = transpose(F_Inverse_LinU);
01761                 
01762                   const Tensor<2,dim> J_F_Inverse_T_LinU = ALETransformations
01763                     ::get_J_F_Inverse_T_LinU<dim> (phi_i_grads_u[i]);
01764                                        
01765                   const Tensor<1,dim> accelaration_term_LinAll = NSEALE
01766 		    ::get_accelaration_term_LinAll 
01767                     (phi_i_v[i], v, old_timestep_v, J_LinU, J, old_timestep_J, density_structure);
01768                        
01769                   // STVK: Green-Lagrange strain tensor derivatives
01770                   const Tensor<2,dim> E_LinU = 0.5 * (transpose(F_LinU) * F + transpose(F) * F_LinU);
01771                   
01772                   const double tr_E_LinU = StructureTermsALE
01773                     ::get_tr_E_LinU<dim> (q,old_solution_grads, phi_i_grads_u[i]);
01774                   
01775                        
01776                   // STVK
01777                   // Piola-kirchhoff stress structure STVK linearized in all directions                   
01778                   Tensor<2,dim> piola_kirchhoff_stress_structure_STVK_LinALL;
01779                   piola_kirchhoff_stress_structure_STVK_LinALL = lame_coefficient_lambda * 
01780                     (F_LinU * tr_E * Identity + F * tr_E_LinU * Identity) 
01781                     + 2 * lame_coefficient_mu * (F_LinU * E + F * E_LinU);
01782                        
01783                            
01784                   for (unsigned int j=0; j<dofs_per_cell; ++j)
01785                     {
01786                       // STVK 
01787                       const unsigned int comp_j = fe.system_to_component_index(j).first; 
01788                       if (comp_j == 0 || comp_j == 1)
01789                         {
01790                           local_matrix(j,i) += (density_structure * phi_i_v[i] * phi_i_v[j] +                                                      
01791                                                 timestep * theta * scalar_product(piola_kirchhoff_stress_structure_STVK_LinALL, 
01792                                                                                   phi_i_grads_v[j]) 
01793                                                 ) * fe_values.JxW(q);           
01794                         }                    
01795                       else if (comp_j == 2 || comp_j == 3)
01796                         {
01797                           local_matrix(j,i) += (density_structure * 1.0/(cell_diameter*cell_diameter) * 
01798                                                 (phi_i_u[i] * phi_i_u[j] - timestep * theta * phi_i_v[i] * phi_i_u[j])                                          
01799                                                 ) *  fe_values.JxW(q);                    
01800                         }
01801                       else if (comp_j == 4)
01802                         {
01803                           local_matrix(j,i) += (phi_i_p[i] * phi_i_p[j]) * fe_values.JxW(q);      
01804                         }
01805                       else if (comp_j == 5 || comp_j == 6)
01806                         {
01807                           local_matrix(j,i) += (alpha_w * (phi_i_w[i] * phi_i_w[j] - scalar_product(phi_i_grads_u[i],phi_i_grads_w[j]) ) 
01808                                                 ) * fe_values.JxW(q);
01809                         } 
01810                       // end j dofs
01811                     }  
01812                   // end i dofs              
01813                 }   
01814               // end n_q_points 
01815             }    
01816 
01817           
01818           cell->get_dof_indices (local_dof_indices);
01819           constraints.distribute_local_to_global (local_matrix, local_dof_indices,
01820                                                   system_matrix);
01821           // end if (second PDE: STVK material)  
01822         } 
01823       // end cell
01824     }   
01825   
01826   timer.exit_section();
01827 }
01828 
01829 
01830 
01836 template <int dim>
01837 void
01838 FSIALEProblem<dim>::assemble_system_rhs ()
01839 {
01840   timer.enter_section("Assemble Rhs.");
01841   system_rhs=0;
01842   
01843   QGauss<dim>   quadrature_formula(degree+2);
01844   QGauss<dim-1> face_quadrature_formula(degree+2);
01845 
01846   FEValues<dim> fe_values (fe, quadrature_formula,
01847                            update_values    |
01848                            update_quadrature_points  |
01849                            update_JxW_values |
01850                            update_gradients);
01851 
01852   FEFaceValues<dim> fe_face_values (fe, face_quadrature_formula, 
01853                                     update_values         | update_quadrature_points  |
01854                                     update_normal_vectors | update_gradients |
01855                                     update_JxW_values);
01856 
01857   const unsigned int   dofs_per_cell   = fe.dofs_per_cell;
01858   
01859   const unsigned int   n_q_points      = quadrature_formula.size();
01860   const unsigned int n_face_q_points   = face_quadrature_formula.size();
01861  
01862   Vector<double>       local_rhs (dofs_per_cell);
01863 
01864   std::vector<unsigned int> local_dof_indices (dofs_per_cell);
01865   
01866   const FEValuesExtractors::Vector velocities (0);
01867   const FEValuesExtractors::Vector displacements (dim); 
01868   const FEValuesExtractors::Scalar pressure (dim+dim); 
01869   const FEValuesExtractors::Vector displacements_w (dim+dim+1); 
01870  
01871   std::vector<Vector<double> > 
01872     old_solution_values (n_q_points, Vector<double>(dim+dim+dim+1));
01873 
01874   std::vector<std::vector<Tensor<1,dim> > > 
01875     old_solution_grads (n_q_points, std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01876 
01877 
01878   std::vector<Vector<double> > 
01879     old_solution_face_values (n_face_q_points, Vector<double>(dim+dim+dim+1));
01880   
01881   std::vector<std::vector<Tensor<1,dim> > > 
01882     old_solution_face_grads (n_face_q_points, std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01883   
01884   std::vector<Vector<double> > 
01885     old_timestep_solution_values (n_q_points, Vector<double>(dim+dim+dim+1));
01886 
01887   std::vector<std::vector<Tensor<1,dim> > > 
01888     old_timestep_solution_grads (n_q_points, std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01889 
01890   std::vector<Vector<double> > 
01891     old_timestep_solution_face_values (n_face_q_points, Vector<double>(dim+dim+dim+1));
01892      
01893   std::vector<std::vector<Tensor<1,dim> > > 
01894     old_timestep_solution_face_grads (n_face_q_points, std::vector<Tensor<1,dim> > (dim+dim+dim+1));
01895    
01896   
01897   typename DoFHandler<dim>::active_cell_iterator
01898     cell = dof_handler.begin_active(),
01899     endc = dof_handler.end();
01900 
01901   for (; cell!=endc; ++cell)
01902     { 
01903       fe_values.reinit (cell);   
01904       local_rhs = 0;    
01905       
01906       cell_diameter = cell->diameter();
01907       
01908       // old Newton iteration
01909       fe_values.get_function_values (solution, old_solution_values);
01910       fe_values.get_function_grads (solution, old_solution_grads);
01911             
01912       // old timestep iteration
01913       fe_values.get_function_values (old_timestep_solution, old_timestep_solution_values);
01914       fe_values.get_function_grads (old_timestep_solution, old_timestep_solution_grads);
01915       
01916       // Again, material_id == 0 corresponds to 
01917       // the domain for fluid equations
01918       if (cell->material_id() == 0)
01919         {
01920           for (unsigned int q=0; q<n_q_points; ++q)
01921             {         
01922               const Tensor<2,dim> pI = ALETransformations
01923                 ::get_pI<dim> (q, old_solution_values);
01924               
01925               const Tensor<1,dim> v = ALETransformations
01926                 ::get_v<dim> (q, old_solution_values);
01927               
01928               const Tensor<2,dim> grad_v = ALETransformations 
01929                 ::get_grad_v<dim> (q, old_solution_grads);
01930               
01931               const Tensor<2,dim> grad_u = ALETransformations 
01932                 ::get_grad_u<dim> (q, old_solution_grads);
01933               
01934               const Tensor<2,dim> grad_v_T = ALETransformations
01935                 ::get_grad_v_T<dim> (grad_v);
01936               
01937               const Tensor<1,dim> u = ALETransformations
01938                 ::get_u<dim> (q, old_solution_values); 
01939               
01940               const Tensor<1,dim> w = ALETransformations
01941                 ::get_w<dim> (q, old_solution_values); 
01942               
01943               const Tensor<2,dim> grad_w = ALETransformations 
01944                 ::get_grad_w<dim> (q, old_solution_grads);
01945               
01946               const Tensor<2,dim> F = ALETransformations
01947                 ::get_F<dim> (q, old_solution_grads);                
01948               
01949               const Tensor<2,dim> F_Inverse = ALETransformations
01950                 ::get_F_Inverse<dim> (F);
01951               
01952               const Tensor<2,dim> F_Inverse_T = ALETransformations
01953                 ::get_F_Inverse_T<dim> (F_Inverse);
01954               
01955               const double J = ALETransformations
01956                 ::get_J<dim> (F);
01957               
01958               // This is the fluid stress tensor in ALE formulation
01959               const Tensor<2,dim> sigma_ALE = NSEALE
01960                 ::get_stress_fluid_except_pressure_ALE<dim> 
01961                 (density_fluid, viscosity, grad_v, grad_v_T, F_Inverse, F_Inverse_T );
01962                                       
01963               // We proceed by catching the previous time step values
01964               const Tensor<2,dim> old_timestep_pI = ALETransformations
01965                 ::get_pI<dim> (q, old_timestep_solution_values);
01966 
01967               const Tensor<1,dim> old_timestep_v = ALETransformations
01968                 ::get_v<dim> (q, old_timestep_solution_values);
01969               
01970               const Tensor<2,dim> old_timestep_grad_v = ALETransformations
01971                 ::get_grad_v<dim> (q, old_timestep_solution_grads);
01972 
01973               const Tensor<2,dim> old_timestep_grad_v_T = ALETransformations
01974                 ::get_grad_v_T<dim> (old_timestep_grad_v);
01975 
01976               const Tensor<1,dim> old_timestep_u = ALETransformations
01977                      ::get_u<dim> (q, old_timestep_solution_values);             
01978 
01979               const Tensor<2,dim> old_timestep_grad_u = ALETransformations 
01980                 ::get_grad_u<dim> (q, old_timestep_solution_grads);
01981                
01982               const Tensor<2,dim> old_timestep_F = ALETransformations
01983                 ::get_F<dim> (q, old_timestep_solution_grads);
01984                
01985               const Tensor<2,dim> old_timestep_F_Inverse = ALETransformations
01986                 ::get_F_Inverse<dim> (old_timestep_F);
01987                
01988               const Tensor<2,dim> old_timestep_F_Inverse_T = ALETransformations
01989                 ::get_F_Inverse_T<dim> (old_timestep_F_Inverse);
01990               
01991               const double old_timestep_J = ALETransformations
01992                 ::get_J<dim> (old_timestep_F);
01993                            
01994               // This is the fluid stress tensor in the ALE formulation
01995               // at the previous time step
01996               const Tensor<2,dim> old_timestep_sigma_ALE = NSEALE
01997                 ::get_stress_fluid_except_pressure_ALE<dim> 
01998                 (density_fluid, viscosity, old_timestep_grad_v, old_timestep_grad_v_T, 
01999                  old_timestep_F_Inverse, old_timestep_F_Inverse_T );
02000                         
02001               Tensor<2,dim> stress_fluid;
02002               stress_fluid.clear();
02003               stress_fluid = (J * sigma_ALE * F_Inverse_T);
02004               
02005               Tensor<2,dim> fluid_pressure;
02006               fluid_pressure.clear();
02007               fluid_pressure = (-pI * J * F_Inverse_T);
02008                               
02009               Tensor<2,dim> old_timestep_stress_fluid;
02010               old_timestep_stress_fluid.clear();
02011               old_timestep_stress_fluid = 
02012                 (old_timestep_J * old_timestep_sigma_ALE * old_timestep_F_Inverse_T);
02013           
02014               // Divergence of the fluid in the ALE formulation
02015               const double incompressiblity_fluid = NSEALE
02016                 ::get_Incompressibility_ALE<dim> (q, old_solution_grads);
02017             
02018               // Convection term of the fluid in the ALE formulation.
02019               // We emphasize that the fluid convection term for
02020               // non-stationary flow problems in ALE
02021               // representation is difficult to derive.               
02022               // For adequate discretization, the convection term will be 
02023               // split into three smaller terms:
02024               Tensor<1,dim> convection_fluid;
02025               convection_fluid.clear();
02026               convection_fluid = density_fluid * J * (grad_v * F_Inverse * v);
02027                      
02028               // The second convection term for the fluid in the ALE formulation              
02029               Tensor<1,dim> convection_fluid_with_u;
02030               convection_fluid_with_u.clear();
02031               convection_fluid_with_u = 
02032                 density_fluid * J * (grad_v * F_Inverse * u);
02033               
02034               // The third convection term for the fluid in the ALE formulation       
02035               Tensor<1,dim> convection_fluid_with_old_timestep_u;
02036               convection_fluid_with_old_timestep_u.clear();
02037               convection_fluid_with_old_timestep_u = 
02038                 density_fluid * J * (grad_v * F_Inverse * old_timestep_u);
02039               
02040               // The convection term of the previous time step
02041               Tensor<1,dim> old_timestep_convection_fluid;
02042               old_timestep_convection_fluid.clear();
02043               old_timestep_convection_fluid = 
02044                 (density_fluid * old_timestep_J * 
02045                  (old_timestep_grad_v * old_timestep_F_Inverse * old_timestep_v));
02046             
02047               for (unsigned int i=0; i<dofs_per_cell; ++i)
02048                 {
02049                   // Fluid, NSE in ALE
02050                   const unsigned int comp_i = fe.system_to_component_index(i).first; 
02051                   if (comp_i == 0 || comp_i == 1)
02052                     {                     
02053                       const Tensor<1,dim> phi_i_v = fe_values[velocities].value (i, q);
02054                       const Tensor<2,dim> phi_i_grads_v = fe_values[velocities].gradient (i, q);
02055                       
02056                       local_rhs(i) -= (density_fluid * (J + old_timestep_J)/2.0 * 
02057                                        (v - old_timestep_v) * phi_i_v +                         
02058                                        timestep * theta * convection_fluid * phi_i_v +  
02059                                        timestep * (1.0-theta) *
02060                                        old_timestep_convection_fluid * phi_i_v -
02061                                        (convection_fluid_with_u -
02062                                         convection_fluid_with_old_timestep_u) * phi_i_v +
02063                                        timestep * scalar_product(fluid_pressure, phi_i_grads_v) +
02064                                        timestep * theta * scalar_product(stress_fluid, phi_i_grads_v) +
02065                                        timestep * (1.0-theta) *
02066                                        scalar_product(old_timestep_stress_fluid, phi_i_grads_v)                         
02067                                        ) *  fe_values.JxW(q);
02068                       
02069                     }           
02070                   else if (comp_i == 2 || comp_i == 3)
02071                     {   
02072                       const Tensor<1,dim> phi_i_u = fe_values[displacements].value (i, q);
02073                       const Tensor<2,dim> phi_i_grads_u = fe_values[displacements].gradient (i, q);
02074 
02075                       local_rhs(i) -= (alpha_u * scalar_product(grad_w, phi_i_grads_u)
02076                                        ) * fe_values.JxW(q);
02077                     }  
02078                   else if (comp_i == 4)
02079                     {
02080                       const double phi_i_p = fe_values[pressure].value (i, q);
02081                       local_rhs(i) -= (incompressiblity_fluid * phi_i_p) *  fe_values.JxW(q);
02082                     }
02083                   else if (comp_i == 5 || comp_i == 6)
02084                     {   
02085                       const Tensor<1,dim> phi_i_w = fe_values[displacements_w].value (i, q);
02086                       const Tensor<2,dim> phi_i_grads_w = fe_values[displacements_w].gradient (i, q);
02087                       
02088                       local_rhs(i) -= alpha_w * (w * phi_i_w - scalar_product(grad_u,phi_i_grads_w)) *
02089                         fe_values.JxW(q);
02090                     }  
02091                   // end i dofs  
02092                 }                  
02093               // close n_q_points  
02094             } 
02095                                   
02096           // As already discussed in the assembling method for the matrix,
02097           // we have to integrate some terms on the outflow boundary:
02098           for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
02099             {
02100               if (cell->face(face)->at_boundary() &&              
02101                   (cell->face(face)->boundary_indicator() == 1) 
02102                   )
02103                 {
02104                   
02105                   fe_face_values.reinit (cell, face);
02106                   
02107                   fe_face_values.get_function_values (solution, old_solution_face_values);
02108                   fe_face_values.get_function_grads (solution, old_solution_face_grads);
02109                   
02110                   fe_face_values.get_function_values (old_timestep_solution, old_timestep_solution_face_values);
02111                   fe_face_values.get_function_grads (old_timestep_solution, old_timestep_solution_face_grads);                  
02112                   
02113                   for (unsigned int q=0; q<n_face_q_points; ++q)
02114                     {   
02115                       // These are terms coming from the
02116                       // previous Newton iterations ...
02117                       const Tensor<1,dim> v = ALETransformations
02118                         ::get_v<dim> (q, old_solution_face_values);
02119                       
02120                       const Tensor<2,dim> grad_v = ALETransformations
02121                         ::get_grad_v<dim> (q, old_solution_face_grads);
02122                       
02123                       const Tensor<2,dim> grad_v_T = ALETransformations
02124                         ::get_grad_v_T<dim> (grad_v);
02125                       
02126                       const Tensor<2,dim> F = ALETransformations
02127                         ::get_F<dim> (q, old_solution_face_grads);
02128                       
02129                       const Tensor<2,dim> F_Inverse = ALETransformations
02130                         ::get_F_Inverse<dim> (F);
02131                       
02132                       const Tensor<2,dim> F_Inverse_T = ALETransformations
02133                         ::get_F_Inverse_T<dim> (F_Inverse);
02134                       
02135                       const double J = ALETransformations
02136                         ::get_J<dim> (F);
02137                       
02138                       // ... and here from the previous time step iteration
02139                       const Tensor<1,dim> old_timestep_v = ALETransformations
02140                         ::get_v<dim> (q, old_timestep_solution_face_values);
02141                       
02142                       const Tensor<2,dim> old_timestep_grad_v = ALETransformations
02143                         ::get_grad_v<dim> (q, old_timestep_solution_face_grads);
02144                       
02145                       const Tensor<2,dim> old_timestep_grad_v_T = ALETransformations
02146                         ::get_grad_v_T<dim> (old_timestep_grad_v);
02147                       
02148                       const Tensor<2,dim> old_timestep_F = ALETransformations
02149                         ::get_F<dim> (q, old_timestep_solution_face_grads);
02150                       
02151                       const Tensor<2,dim> old_timestep_F_Inverse = ALETransformations
02152                         ::get_F_Inverse<dim> (old_timestep_F);
02153                       
02154                       const Tensor<2,dim> old_timestep_F_Inverse_T = ALETransformations
02155                         ::get_F_Inverse_T<dim> (old_timestep_F_Inverse);
02156                       
02157                       const double old_timestep_J = ALETransformations
02158                         ::get_J<dim> (old_timestep_F);
02159                                       
02160                       Tensor<2,dim> sigma_ALE_tilde;
02161                       sigma_ALE_tilde.clear();
02162                       sigma_ALE_tilde = 
02163                         (density_fluid * viscosity * F_Inverse_T * grad_v_T);
02164                       
02165                       Tensor<2,dim> old_timestep_sigma_ALE_tilde;
02166                       old_timestep_sigma_ALE_tilde.clear();
02167                       old_timestep_sigma_ALE_tilde = 
02168                         (density_fluid * viscosity * old_timestep_F_Inverse_T * old_timestep_grad_v_T);
02169                       
02170                       // Neumann boundary integral
02171                       Tensor<2,dim> stress_fluid_transposed_part;
02172                       stress_fluid_transposed_part.clear();
02173                       stress_fluid_transposed_part = (J * sigma_ALE_tilde * F_Inverse_T);
02174                       
02175                       Tensor<2,dim> old_timestep_stress_fluid_transposed_part;
02176                       old_timestep_stress_fluid_transposed_part.clear();                      
02177                       old_timestep_stress_fluid_transposed_part = 
02178                         (old_timestep_J * old_timestep_sigma_ALE_tilde * old_timestep_F_Inverse_T);
02179 
02180                       const Tensor<1,dim> neumann_value
02181                         = (stress_fluid_transposed_part * fe_face_values.normal_vector(q));
02182                       
02183                       const Tensor<1,dim> old_timestep_neumann_value
02184                         = (old_timestep_stress_fluid_transposed_part * fe_face_values.normal_vector(q));
02185                                      
02186                       for (unsigned int i=0; i<dofs_per_cell; ++i)
02187                         {
02188                           const unsigned int comp_i = fe.system_to_component_index(i).first; 
02189                           if (comp_i == 0 || comp_i == 1)
02190                             {  
02191                               local_rhs(i) +=  (timestep * theta * 
02192                                                  neumann_value * fe_face_values[velocities].value (i, q) +
02193                                                  timestep * (1.0-theta) *
02194                                                  old_timestep_neumann_value * 
02195                                                  fe_face_values[velocities].value (i, q)
02196                                                  ) * fe_face_values.JxW(q);                                        
02197                             }
02198                           // end i
02199                         }  
02200                       // end face_n_q_points    
02201                     }                                     
02202                 } 
02203             }  // end face integrals do-nothing condition
02204 
02205           
02206            // The computation of these face integrals on the interface has
02207           // already been discussed in the matrix section. 
02208           for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
02209             {
02210               if (cell->neighbor_index(face) != -1)            
02211                 if (cell->material_id() !=  cell->neighbor(face)->material_id() &&
02212                     cell->face(face)->boundary_indicator()!=81)
02213                   {                 
02214                     fe_face_values.reinit (cell, face);
02215                     fe_face_values.get_function_grads (solution, old_solution_face_grads);
02216                     
02217                     for (unsigned int q=0; q<n_face_q_points; ++q)
02218                       {
02219                         const Tensor<2,dim> grad_u = ALETransformations 
02220                           ::get_grad_u<dim> (q, old_solution_face_grads);
02221 
02222                         const Tensor<2,dim> grad_w = ALETransformations 
02223                           ::get_grad_w<dim> (q, old_solution_face_grads);
02224                         
02225                         const Tensor<1,dim> neumann_value_u
02226                           = (grad_u * fe_face_values.normal_vector(q));
02227 
02228                         const Tensor<1,dim> neumann_value_w
02229                           = (grad_w * fe_face_values.normal_vector(q));
02230                         
02231                         for (unsigned int i=0; i<dofs_per_cell; ++i)
02232                           {
02233                             const unsigned int comp_i = fe.system_to_component_index(i).first; 
02234                             if (comp_i == 2 || comp_i == 3)
02235                               {  
02236                                 local_rhs(i) +=  (alpha_w * neumann_value_w *
02237                                                   fe_face_values[displacements].value (i, q)) *                                    
02238                                   fe_face_values.JxW(q);
02239                               }
02240                             else if (comp_i == 5 || comp_i == 6)
02241                               {
02242                                 local_rhs(i) +=  (alpha_u * neumann_value_u *
02243                                                   fe_face_values[displacements_w].value (i, q)) *                                          
02244                                   fe_face_values.JxW(q);
02245                               }
02246 
02247                           }  // end i
02248                         
02249                       }   // end face_n_q_points
02250                     
02251                   } 
02252             }   // end face for interface conditions
02253           
02254           
02255           cell->get_dof_indices (local_dof_indices);
02256           constraints.distribute_local_to_global (local_rhs, local_dof_indices,
02257                                                   system_rhs);
02258          
02259           // Finally, we arrive at the end for assembling 
02260           // the variational formulation for the fluid part and step to
02261           // the assembling process of the structure terms:
02262         }   
02263       else if (cell->material_id() == 1)
02264         {         
02265           for (unsigned int q=0; q<n_q_points; ++q)
02266             {                                         
02267               const Tensor<2,dim> pI = ALETransformations
02268                 ::get_pI<dim> (q, old_solution_values);
02269               
02270               const Tensor<1,dim> v = ALETransformations
02271                 ::get_v<dim> (q, old_solution_values);
02272               
02273               const Tensor<2,dim> grad_v = ALETransformations
02274                 ::get_grad_v<dim> (q, old_solution_grads);
02275               
02276               const Tensor<2,dim> grad_v_T = ALETransformations
02277                 ::get_grad_v_T<dim> (grad_v);
02278               
02279               const Tensor<1,dim> u = ALETransformations
02280                 ::get_u<dim> (q, old_solution_values);
02281               
02282               const Tensor<2,dim> grad_u = ALETransformations 
02283                 ::get_grad_u<dim> (q, old_solution_grads);
02284               
02285               const Tensor<1,dim> w = ALETransformations
02286                 ::get_w<dim> (q, old_solution_values); 
02287               
02288               const Tensor<2,dim> grad_w = ALETransformations 
02289                 ::get_grad_w<dim> (q, old_solution_grads);
02290               
02291               const Tensor<2,dim> F = ALETransformations
02292                 ::get_F<dim> (q, old_solution_grads);
02293               
02294               const Tensor<2,dim> F_T = ALETransformations
02295                 ::get_F_T<dim> (F);
02296               
02297               const Tensor<2,dim> Identity = ALETransformations
02298                 ::get_Identity<dim> ();
02299               
02300               const Tensor<2,dim> F_Inverse = ALETransformations
02301                 ::get_F_Inverse<dim> (F);
02302               
02303               const Tensor<2,dim> F_Inverse_T = ALETransformations
02304                 ::get_F_Inverse_T<dim> (F_Inverse);
02305               
02306               const double J = ALETransformations
02307                 ::get_J<dim> (F);
02308               
02309               const Tensor<2,dim> E = StructureTermsALE
02310                 ::get_E<dim> (F_T, F, Identity);
02311               
02312               const double tr_E = StructureTermsALE
02313                 ::get_tr_E<dim> (E);
02314               
02315               // Previous time step values
02316               const Tensor<2,dim> old_timestep_pI = ALETransformations
02317                 ::get_pI<dim> (q, old_timestep_solution_values);
02318               
02319               const Tensor<1,dim> old_timestep_v = ALETransformations
02320                 ::get_v<dim> (q, old_timestep_solution_values);
02321               
02322               const Tensor<2,dim> old_timestep_grad_v = ALETransformations
02323                 ::get_grad_v<dim> (q, old_timestep_solution_grads);
02324               
02325               const Tensor<2,dim> old_timestep_grad_v_T = ALETransformations
02326                 ::get_grad_v_T<dim> (old_timestep_grad_v);
02327               
02328               const Tensor<1,dim> old_timestep_u = ALETransformations
02329                 ::get_u<dim> (q, old_timestep_solution_values);
02330               
02331               const Tensor<2,dim> old_timestep_F = ALETransformations
02332                 ::get_F<dim> (q, old_timestep_solution_grads);
02333               
02334               const Tensor<2,dim> old_timestep_F_Inverse = ALETransformations
02335                 ::get_F_Inverse<dim> (old_timestep_F);
02336               
02337               const Tensor<2,dim> old_timestep_F_T = ALETransformations
02338                 ::get_F_T<dim> (old_timestep_F);
02339               
02340               const Tensor<2,dim> old_timestep_F_Inverse_T = ALETransformations
02341                 ::get_F_Inverse_T<dim> (old_timestep_F_Inverse);
02342               
02343               const double old_timestep_J = ALETransformations
02344                 ::get_J<dim> (old_timestep_F);
02345               
02346               const Tensor<2,dim> old_timestep_E = StructureTermsALE
02347                 ::get_E<dim> (old_timestep_F_T, old_timestep_F, Identity);
02348               
02349               const double old_timestep_tr_E = StructureTermsALE
02350                 ::get_tr_E<dim> (old_timestep_E);
02351               
02352               
02353               // STVK structure model
02354               Tensor<2,dim> sigma_structure_ALE;
02355               sigma_structure_ALE.clear();
02356               sigma_structure_ALE = (1.0/J *
02357                                      F * (lame_coefficient_lambda *
02358                                           tr_E * Identity +
02359                                           2 * lame_coefficient_mu *
02360                                           E) * 
02361                                      F_T);
02362               
02363               
02364               Tensor<2,dim> stress_term;
02365               stress_term.clear();
02366               stress_term = (J * sigma_structure_ALE * F_Inverse_T);
02367               
02368               Tensor<2,dim> old_timestep_sigma_structure_ALE;
02369               old_timestep_sigma_structure_ALE.clear();
02370               old_timestep_sigma_structure_ALE = (1.0/old_timestep_J *
02371                                                   old_timestep_F * (lame_coefficient_lambda *
02372                                                                     old_timestep_tr_E * Identity +
02373                                                                     2 * lame_coefficient_mu *
02374                                                                     old_timestep_E) * 
02375                                                   old_timestep_F_T);
02376               
02377               Tensor<2,dim> old_timestep_stress_term;
02378               old_timestep_stress_term.clear();
02379               old_timestep_stress_term = (old_timestep_J * old_timestep_sigma_structure_ALE * old_timestep_F_Inverse_T);
02380                       
02381               for (unsigned int i=0; i<dofs_per_cell; ++i)
02382                 {
02383                   // STVK structure model
02384                   const unsigned int comp_i = fe.system_to_component_index(i).first; 
02385                   if (comp_i == 0 || comp_i == 1)
02386                     { 
02387                       const Tensor<1,dim> phi_i_v = fe_values[velocities].value (i, q);
02388                       const Tensor<2,dim> phi_i_grads_v = fe_values[velocities].gradient (i, q);
02389                       
02390                       local_rhs(i) -= (density_structure * (v - old_timestep_v) * phi_i_v +
02391                                        timestep * theta * scalar_product(stress_term,phi_i_grads_v) +  
02392                                        timestep * (1.0-theta) * scalar_product(old_timestep_stress_term, phi_i_grads_v) 
02393                                        ) * fe_values.JxW(q);    
02394                       
02395                     }           
02396                   else if (comp_i == 2 || comp_i == 3)
02397                     {
02398                       const Tensor<1,dim> phi_i_u = fe_values[displacements].value (i, q);
02399                       local_rhs(i) -=  (density_structure * 1.0/(cell_diameter*cell_diameter) * 
02400                                         ((u - old_timestep_u) * phi_i_u -
02401                                          timestep * (theta * v + (1.0-theta) * 
02402                                                      old_timestep_v) * phi_i_u)
02403                                         ) * fe_values.JxW(q);    
02404                       
02405                     }
02406                   else if (comp_i == 4)
02407                     {
02408                       const double phi_i_p = fe_values[pressure].value (i, q);
02409                       local_rhs(i) -= (old_solution_values[q](dim+dim) * phi_i_p) * fe_values.JxW(q);  
02410                       
02411                     }
02412                   else if (comp_i == 5 || comp_i == 6)
02413                     {   
02414                       const Tensor<1,dim> phi_i_w = fe_values[displacements_w].value (i, q);
02415                       const Tensor<2,dim> phi_i_grads_w = fe_values[displacements_w].gradient (i, q);
02416                       
02417                       local_rhs(i) -= alpha_w * (w * phi_i_w - scalar_product(grad_u,phi_i_grads_w)) *
02418                         fe_values.JxW(q);
02419                     }
02420                   // end i        
02421                 }       
02422               // end n_q_points                    
02423             } 
02424           
02425           cell->get_dof_indices (local_dof_indices);
02426           constraints.distribute_local_to_global (local_rhs, local_dof_indices,
02427                                                   system_rhs);
02428           
02429         // end if (for STVK material)  
02430         }   
02431       
02432     }  // end cell
02433       
02434   timer.exit_section();
02435 }
02436 
02437 
02455 template <int dim>
02456 void
02457 FSIALEProblem<dim>::set_initial_bc (const double time)
02458 { 
02459     std::map<unsigned int,double> boundary_values;  
02460     std::vector<bool> component_mask (dim+dim+dim+1, true);
02461     // (Scalar) pressure
02462     component_mask[dim+dim] = false;  
02463  
02464     // Additional displacement w:
02465     component_mask[dim+dim+1] = false;  
02466     component_mask[dim+dim+dim] = false; 
02467     
02468     VectorTools::interpolate_boundary_values (dof_handler,
02469                                               0,
02470                                               BoundaryParabolic<dim>(time),
02471                                               boundary_values,
02472                                               component_mask);    
02473     
02474     VectorTools::interpolate_boundary_values (dof_handler,
02475                                               2,
02476                                               ZeroFunction<dim>(dim+dim+dim+1),  
02477                                               boundary_values,
02478                                               component_mask);
02479     
02480     VectorTools::interpolate_boundary_values (dof_handler,
02481                                               80,
02482                                               ZeroFunction<dim>(dim+dim+dim+1),  
02483                                               boundary_values,
02484                                               component_mask);
02485     
02486     VectorTools::interpolate_boundary_values (dof_handler,
02487                                               81,
02488                                               ZeroFunction<dim>(dim+dim+dim+1),  
02489                                               boundary_values,
02490                                               component_mask);
02491     
02492     component_mask[0] = false;
02493     component_mask[1] = false;   
02494     
02495     VectorTools::interpolate_boundary_values (dof_handler,
02496                                               1,
02497                                               ZeroFunction<dim>(dim+dim+dim+1),  
02498                                               boundary_values,
02499                                               component_mask);
02500     
02501     for (typename std::map<unsigned int, double>::const_iterator
02502            i = boundary_values.begin();
02503          i != boundary_values.end();
02504          ++i)
02505       solution(i->first) = i->second;
02506     
02507 }
02508 
02515 template <int dim>
02516 void
02517 FSIALEProblem<dim>::set_newton_bc ()
02518 {
02519     std::vector<bool> component_mask (dim+dim+dim+1, true);
02520     component_mask[dim+dim] = false; 
02521     component_mask[dim+dim+1] = false; 
02522     component_mask[dim+dim+dim] = false; 
02523    
02524     VectorTools::interpolate_boundary_values (dof_handler,
02525                                               0,
02526                                               ZeroFunction<dim>(dim+dim+dim+1),                                             
02527                                               constraints,
02528                                               component_mask); 
02529 
02530     VectorTools::interpolate_boundary_values (dof_handler,
02531                                               2,
02532                                               ZeroFunction<dim>(dim+dim+dim+1),  
02533                                               constraints,
02534                                               component_mask);
02535 
02536     VectorTools::interpolate_boundary_values (dof_handler,
02537                                               80,
02538                                               ZeroFunction<dim>(dim+dim+dim+1),  
02539                                               constraints,
02540                                               component_mask);
02541     VectorTools::interpolate_boundary_values (dof_handler,
02542                                               81,
02543                                               ZeroFunction<dim>(dim+dim+dim+1),  
02544                                               constraints,
02545                                               component_mask);       
02546     component_mask[0] = false;
02547     component_mask[1] = false;
02548     
02549     VectorTools::interpolate_boundary_values (dof_handler,
02550                                               1,
02551                                               ZeroFunction<dim>(dim+dim+dim+1),  
02552                                               constraints,
02553                                               component_mask);
02554 }  
02555 
02556 
02562 template <int dim>
02563 void FSIALEProblem<dim>::newton_iteration (const double time) 
02564                                                
02565 { 
02566   Timer timer_newton;
02567   const double lower_bound_newton_residuum = 1.0e-8; 
02568   const unsigned int max_no_newton_steps  = 40;
02569 
02570   // Decision whether the system matrix should be build
02571   // at each Newton step
02572   const double nonlinear_rho = 0.1; 
02573  
02574   // Line search parameters
02575   unsigned int line_search_step;
02576   const unsigned int  max_no_line_search_steps = 10;
02577   const double line_search_damping = 0.6;
02578   double new_newton_residuum;
02579   
02580   // Application of the initial boundary conditions to the 
02581   // variational equations:
02582   set_initial_bc (time);
02583   assemble_system_rhs();
02584 
02585   double newton_residuum = system_rhs.linfty_norm(); 
02586   double old_newton_residuum= newton_residuum;
02587   unsigned int newton_step = 1;
02588    
02589   if (newton_residuum < lower_bound_newton_residuum)
02590     {
02591       std::cout << '\t' 
02592                 << std::scientific 
02593                 << newton_residuum 
02594                 << std::endl;     
02595     }
02596   
02597   while (newton_residuum > lower_bound_newton_residuum &&
02598          newton_step < max_no_newton_steps)
02599     {
02600       timer_newton.start();
02601       old_newton_residuum = newton_residuum;
02602       
02603       assemble_system_rhs();
02604       newton_residuum = system_rhs.linfty_norm();
02605 
02606       if (newton_residuum < lower_bound_newton_residuum)
02607         {
02608           std::cout << '\t' 
02609                     << std::scientific 
02610                     << newton_residuum << std::endl;
02611           break;
02612         }
02613   
02614       if (newton_residuum/old_newton_residuum > nonlinear_rho)
02615         assemble_system_matrix ();      
02616 
02617       // Solve Ax = b
02618       solve ();   
02619         
02620       line_search_step = 0;       
02621       for ( ; 
02622             line_search_step < max_no_line_search_steps; 
02623             ++line_search_step)
02624         {                                                
02625           solution += newton_update;
02626           
02627           assemble_system_rhs ();                       
02628           new_newton_residuum = system_rhs.linfty_norm();
02629           
02630           if (new_newton_residuum < newton_residuum)
02631               break;
02632           else    
02633             solution -= newton_update;
02634           
02635           newton_update *= line_search_damping;
02636         }          
02637      
02638       timer_newton.stop();
02639       
02640       std::cout << std::setprecision(5) <<newton_step << '\t' 
02641                 << std::scientific << newton_residuum << '\t'
02642                 << std::scientific << newton_residuum/old_newton_residuum  <<'\t' ;
02643       if (newton_residuum/old_newton_residuum > nonlinear_rho)
02644         std::cout << "r" << '\t' ;
02645       else 
02646         std::cout << " " << '\t' ;
02647       std::cout << line_search_step  << '\t' 
02648                 << std::scientific << timer_newton ()
02649                 << std::endl;
02650 
02651 
02652       // Updates
02653       timer_newton.reset();
02654       newton_step++;      
02655     }
02656 }
02657 
02676  template <int dim>
02677 void 
02678 FSIALEProblem<dim>::solve () 
02679 {
02680   timer.enter_section("Solve linear system.");
02681   Vector<double> sol, rhs;    
02682   sol = newton_update;    
02683   rhs = system_rhs;
02684   
02685   SparseDirectUMFPACK A_direct;
02686   A_direct.factorize(system_matrix);     
02687   A_direct.vmult(sol,rhs); 
02688   newton_update = sol;
02689   
02690   constraints.distribute (newton_update);
02691   timer.exit_section();
02692 }
02693 
02694 
02695 /* This function is known from almost all other 
02696  * tutorial steps in deal.II.
02697  * However, we emphasize that the FSI problem
02698  * is computed on a fixed mesh (instead of 
02699  * moving the mesh as done in other references;
02700  * we refer the reader to the accompanying article
02701  * and the comments made therein). 
02702  * For this reason, the output of the 
02703  * solution in *.vtk format corresponds to the 
02704  * solution on the fixed mesh and, therefore,
02705  * in a visualization program, the reader 
02706  * has to postprocess the solution.
02707  * We also refer to the MappingQEulerian in 
02708  * the deal.II librar, which is able
02709  * to tansform the solution to the current (i.e., 
02710  * the physical mesh) 
02711  */
02712 template <int dim>
02713 void
02714 FSIALEProblem<dim>::output_results (const unsigned int refinement_cycle,
02715                               const BlockVector<double> output_vector)  const
02716 {
02717 
02718   std::vector<std::string> solution_names (dim, "velocity"); 
02719   solution_names.push_back ("displacement");
02720   solution_names.push_back ("displacement");
02721   solution_names.push_back ("p_fluid");
02722   solution_names.push_back ("displace_w");
02723   solution_names.push_back ("displace_w");
02724    
02725   std::vector<DataComponentInterpretation::DataComponentInterpretation>
02726     data_component_interpretation
02727     (dim+dim, DataComponentInterpretation::component_is_part_of_vector);
02728 
02729   data_component_interpretation
02730     .push_back (DataComponentInterpretation::component_is_scalar);
02731 
02732   data_component_interpretation
02733     .push_back (DataComponentInterpretation::component_is_part_of_vector);
02734   data_component_interpretation
02735     .push_back (DataComponentInterpretation::component_is_part_of_vector);
02736   
02737   DataOut<dim> data_out;
02738   data_out.attach_dof_handler (dof_handler);  
02739    
02740   data_out.add_data_vector (output_vector, solution_names,
02741                             DataOut<dim>::type_dof_data,
02742                             data_component_interpretation);
02743   
02744   data_out.build_patches ();
02745 
02746   std::string filename_basis;
02747   filename_basis  = "solution_fsi_1_"; 
02748    
02749   std::ostringstream filename;
02750 
02751   std::cout << "------------------" << std::endl;
02752   std::cout << "Write solution" << std::endl;
02753   std::cout << "------------------" << std::endl;
02754   std::cout << std::endl;
02755   filename << filename_basis
02756            << Utilities::int_to_string (refinement_cycle, 5)
02757            << ".vtk";
02758   
02759   std::ofstream output (filename.str().c_str());
02760   data_out.write_vtk (output);
02761 
02762 }
02763 
02769 template <int dim>
02770 double FSIALEProblem<dim>::compute_point_value (Point<dim> p, 
02771                                                const unsigned int component) const  
02772 {
02773  
02774   Vector<double> tmp_vector(dim+dim+dim+1);
02775   VectorTools::point_value (dof_handler, 
02776                             solution, 
02777                             p, 
02778                             tmp_vector);
02779   
02780   return tmp_vector(component);
02781 }
02782 
02790 template <int dim>
02791 void FSIALEProblem<dim>::compute_drag_lift_fsi_fluid_tensor()
02792 {
02793     
02794   const QGauss<dim-1> face_quadrature_formula (3);
02795   FEFaceValues<dim> fe_face_values (fe, face_quadrature_formula, 
02796                                     update_values | update_gradients | update_normal_vectors | 
02797                                     update_JxW_values);
02798   
02799   const unsigned int dofs_per_cell = fe.dofs_per_cell;
02800   const unsigned int n_face_q_points = face_quadrature_formula.size();
02801 
02802   std::vector<unsigned int> local_dof_indices (dofs_per_cell);
02803   std::vector<Vector<double> >  face_solution_values (n_face_q_points, 
02804                                                       Vector<double> (dim+dim+dim+1));
02805 
02806   std::vector<std::vector<Tensor<1,dim> > > 
02807     face_solution_grads (n_face_q_points, std::vector<Tensor<1,dim> > (dim+dim+dim+1));
02808   
02809   Tensor<1,dim> drag_lift_value;
02810   
02811   typename DoFHandler<dim>::active_cell_iterator
02812     cell = dof_handler.begin_active(),
02813     endc = dof_handler.end();
02814 
02815    for (; cell!=endc; ++cell)
02816      {
02817 
02818        // First, we are going to compute the forces that
02819        // act on the cylinder. We notice that only the fluid 
02820        // equations are defined here.
02821        for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
02822          if (cell->face(face)->at_boundary() && 
02823              cell->face(face)->boundary_indicator()==80)
02824            {
02825              fe_face_values.reinit (cell, face);
02826              fe_face_values.get_function_values (solution, face_solution_values);
02827              fe_face_values.get_function_grads (solution, face_solution_grads);
02828                       
02829              for (unsigned int q_point=0; q_point<n_face_q_points; ++q_point)
02830                {               
02831                  const Tensor<2,dim> pI = ALETransformations
02832                    ::get_pI<dim> (q_point, face_solution_values);
02833                  
02834                  const Tensor<1,dim> v = ALETransformations
02835                    ::get_v<dim> (q_point, face_solution_values);
02836                  
02837                  const Tensor<2,dim> grad_v = ALETransformations 
02838                    ::get_grad_v<dim> (q_point, face_solution_grads);
02839                  
02840                  const Tensor<2,dim> grad_v_T = ALETransformations
02841                    ::get_grad_v_T<dim> (grad_v);
02842                  
02843                  const Tensor<2,dim> F = ALETransformations
02844                    ::get_F<dim> (q_point, face_solution_grads);              
02845                  
02846                  const Tensor<2,dim> F_Inverse = ALETransformations
02847                    ::get_F_Inverse<dim> (F);
02848                  
02849                  const Tensor<2,dim> F_Inverse_T = ALETransformations
02850                    ::get_F_Inverse_T<dim> (F_Inverse);
02851                  
02852                  const double J = ALETransformations
02853                    ::get_J<dim> (F);
02854                  
02855                  const Tensor<2,dim> sigma_ALE = NSEALE
02856                    ::get_stress_fluid_except_pressure_ALE<dim> 
02857                    (density_fluid, viscosity, 
02858                     grad_v, grad_v_T, F_Inverse, F_Inverse_T );
02859                  
02860                  Tensor<2,dim> stress_fluid;
02861                  stress_fluid.clear();
02862                  stress_fluid = (J * sigma_ALE * F_Inverse_T);
02863                  
02864                  Tensor<2,dim> fluid_pressure;
02865                  fluid_pressure.clear();
02866                  fluid_pressure = (-pI * J * F_Inverse_T);
02867                  
02868                  drag_lift_value -= (stress_fluid + fluid_pressure) * 
02869                    fe_face_values.normal_vector(q_point)* fe_face_values.JxW(q_point); 
02870                  
02871                }
02872            } // end boundary 80 for fluid
02873        
02874        // Now, we compute the forces that act on the beam. Here,
02875        // we have two possibilities as already discussed in the paper.
02876        // We use again the fluid tensor to compute 
02877        // drag and lift:
02878        if (cell->material_id() == 0)
02879          {         
02880            for (unsigned int face=0; face<GeometryInfo<dim>::faces_per_cell; ++face)
02881              if (cell->neighbor_index(face) != -1)             
02882                if (cell->material_id() !=  cell->neighbor(face)->material_id() &&
02883                    cell->face(face)->boundary_indicator()!=80)
02884                  {
02885                    
02886                    fe_face_values.reinit (cell, face);
02887                    fe_face_values.get_function_values (solution, face_solution_values);
02888                    fe_face_values.get_function_grads (solution, face_solution_grads);
02889                                   
02890                    for (unsigned int q_point=0; q_point<n_face_q_points; ++q_point)
02891                      {
02892                        const Tensor<2,dim> pI = ALETransformations
02893                          ::get_pI<dim> (q_point, face_solution_values);
02894                        
02895                        const Tensor<1,dim> v = ALETransformations
02896                          ::get_v<dim> (q_point, face_solution_values);
02897                        
02898                        const Tensor<2,dim> grad_v = ALETransformations 
02899                          ::get_grad_v<dim> (q_point, face_solution_grads);
02900                        
02901                        const Tensor<2,dim> grad_v_T = ALETransformations
02902                          ::get_grad_v_T<dim> (grad_v);
02903                        
02904                        const Tensor<2,dim> F = ALETransformations
02905                          ::get_F<dim> (q_point, face_solution_grads);                
02906                        
02907                        const Tensor<2,dim> F_Inverse = ALETransformations
02908                          ::get_F_Inverse<dim> (F);
02909                        
02910                        const Tensor<2,dim> F_Inverse_T = ALETransformations
02911                          ::get_F_Inverse_T<dim> (F_Inverse);
02912                        
02913                        const double J = ALETransformations
02914                          ::get_J<dim> (F);
02915                        
02916                        const Tensor<2,dim> sigma_ALE = NSEALE
02917                          ::get_stress_fluid_except_pressure_ALE<dim> 
02918                          (density_fluid, viscosity, grad_v, grad_v_T, F_Inverse, F_Inverse_T );
02919                        
02920                        Tensor<2,dim> stress_fluid;
02921                        stress_fluid.clear();
02922                        stress_fluid = (J * sigma_ALE * F_Inverse_T);
02923                        
02924                        Tensor<2,dim> fluid_pressure;
02925                        fluid_pressure.clear();
02926                        fluid_pressure = (-pI * J * F_Inverse_T);
02927                        
02928                        drag_lift_value -= (stress_fluid + fluid_pressure) * 
02929                          fe_face_values.normal_vector(q_point)* fe_face_values.JxW(q_point);                                   
02930                      }
02931                  }         
02932          }               
02933      } 
02934    
02935    std::cout << "Drag: " << drag_lift_value[0] << std::endl;
02936    std::cout << "Lift: " << drag_lift_value[1] << std::endl;
02937 }
02938 
02942 template<int dim>
02943 void FSIALEProblem<dim>::compute_functional_values()
02944 {
02945   double x1,y1;
02946   x1 = compute_point_value(Point<dim>(0.6,0.2), dim);
02947   y1 = compute_point_value(Point<dim>(0.6,0.2), dim+1);
02948   
02949   std::cout << "------------------" << std::endl;
02950   std::cout << "DisX: " << x1 << std::endl;
02951   std::cout << "DisY: " << y1 << std::endl;
02952   std::cout << "------------------" << std::endl;
02953   
02954   compute_drag_lift_fsi_fluid_tensor();
02955   
02956   std::cout << std::endl;
02957 }
02958 
02968  template <int dim>
02969 void FSIALEProblem<dim>::run () 
02970 {  
02971   setup_system();
02972 
02973   std::cout << "\n==============================" 
02974             << "====================================="  << std::endl;
02975   std::cout << "Parameters\n" 
02976             << "==========\n"
02977             << "Density fluid:     "   <<  density_fluid << "\n"
02978             << "Density structure: "   <<  density_structure << "\n"  
02979             << "Viscosity fluid:   "   <<  viscosity << "\n"
02980             << "alpha_u:           "   <<  alpha_u << "\n"
02981             << "alpha_w:           "   <<  alpha_w << "\n"    
02982             << "Lame coeff. mu:    "   <<  lame_coefficient_mu << "\n"
02983             << std::endl;
02984 
02985  
02986   const unsigned int output_skip = 5;
02987   do
02988     { 
02989       std::cout << "Timestep " << timestep_number 
02990                 << " (" << time_stepping_scheme 
02991                 << ")" <<    ": " << time
02992                 << " (" << timestep << ")"
02993                 << "\n==============================" 
02994                 << "=====================================" 
02995                 << std::endl; 
02996       
02997       std::cout << std::endl;
02998       
02999       // Compute next time step
03000       old_timestep_solution = solution;
03001       newton_iteration (time);   
03002       time += timestep;
03003         
03004       // Compute functional values: dx, dy, drag, lift
03005       std::cout << std::endl;
03006       compute_functional_values();
03007       
03008       // Write solutions 
03009       if ((timestep_number % output_skip == 0))
03010         output_results (timestep_number,solution);
03011       
03012       
03013       ++timestep_number;
03014 
03015     }
03016   while (timestep_number <= max_no_timesteps);
03017   
03018   
03019 }
03020 
03021 // The main function looks almost the same
03022 // as in all other deal.II tuturial steps. 
03023 int main () 
03024 {
03025   try
03026     {
03027       deallog.depth_console (0);
03028 
03029       FSIALEProblem<2> fsi_problem(1);
03030       fsi_problem.run ();
03031     }
03032   catch (std::exception &exc)
03033     {
03034       std::cerr << std::endl << std::endl
03035                 << "----------------------------------------------------"
03036                 << std::endl;
03037       std::cerr << "Exception on processing: " << std::endl
03038                 << exc.what() << std::endl
03039                 << "Aborting!" << std::endl
03040                 << "----------------------------------------------------"
03041                 << std::endl;
03042       
03043       return 1;
03044     }
03045   catch (...) 
03046     {
03047       std::cerr << std::endl << std::endl
03048                 << "----------------------------------------------------"
03049                 << std::endl;
03050       std::cerr << "Unknown exception!" << std::endl
03051                 << "Aborting!" << std::endl
03052                 << "----------------------------------------------------"
03053                 << std::endl;
03054       return 1;
03055     }
03056 
03057   return 0;
03058 }
03059 
03060 
03061 
03062