GRINS-0.6.0
elastic_cable.C
Go to the documentation of this file.
1 //-----------------------------------------------------------------------bl-
2 //--------------------------------------------------------------------------
3 //
4 // GRINS - General Reacting Incompressible Navier-Stokes
5 //
6 // Copyright (C) 2014-2015 Paul T. Bauman, Roy H. Stogner
7 // Copyright (C) 2010-2013 The PECOS Development Team
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the Version 2.1 GNU Lesser General
11 // Public License as published by the Free Software Foundation.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc. 51 Franklin Street, Fifth Floor,
21 // Boston, MA 02110-1301 USA
22 //
23 //-----------------------------------------------------------------------el-
24 
25 // This class
26 #include "grins/elastic_cable.h"
27 
28 // GRINS
29 #include "grins_config.h"
34 #include "grins/physics.h"
35 
36 // libMesh
37 #include "libmesh/getpot.h"
38 #include "libmesh/quadrature.h"
39 #include "libmesh/boundary_info.h"
40 #include "libmesh/fem_system.h"
41 #include "libmesh/fe_interface.h"
42 
43 namespace GRINS
44 {
45  template<typename StressStrainLaw>
46  ElasticCable<StressStrainLaw>::ElasticCable( const PhysicsName& physics_name, const GetPot& input,
47  bool is_compressible )
48  : ElasticCableBase(physics_name,input),
49  _stress_strain_law(input),
50  _A( 1.0 ),
51  _is_compressible(is_compressible)
52  {
53  // Force the user to set A
54  if( !input.have_variable("Physics/"+physics_name+"/A") )
55  {
56  std::cerr << "Error: Must specify initial area for "+physics_name << std::endl
57  << " Input the option Physics/"+physics_name+"/A" << std::endl;
58  libmesh_error();
59  }
60 
61  this->set_parameter
62  (_A, input, "Physics/"+physics_name+"/A", _A );
63 
64  this->_bc_handler = new SolidMechanicsBCHandling( physics_name, input );
65 
66  this->_ic_handler = new GenericICHandler(physics_name, input);
67 
68  return;
69  }
70 
71  template<typename StressStrainLaw>
73  {
74  return;
75  }
76 
77 
78  template<typename StressStrainLaw>
81  {
82  std::string section = "Physics/"+elastic_cable+"/output_vars";
83 
84  if( input.have_variable(section) )
85  {
86  unsigned int n_vars = input.vector_variable_size(section);
87 
88  for( unsigned int v = 0; v < n_vars; v++ )
89  {
90  std::string name = input(section,"DIE!",v);
91 
92  if( name == std::string("stress") )
93  {
94  // sigma_xx only, i.e., locally normal to the cutting plane
95  // sigma_yy=sigma_zz = 0 by assumption of this Physics
96  _stress_indices.resize(1);
97 
98  this->_stress_indices[0] = postprocessing.register_quantity("cable_stress");
99 
100  }
101  else if( name == std::string("strain") )
102  {
103  // eps_xx only, i.e., locally normal to the cutting plane
104  // eps_yy=eps_zz = 0 by assumption of this Physics
105  _strain_indices.resize(1);
106 
107  this->_strain_indices[0] = postprocessing.register_quantity("cable_strain");
108 
109  }
110  else if( name == std::string("force") )
111  {
112  // force_x only, i.e., locally normal to the cutting plane
113  // force_y=force_z=0 by assumption of this Physics
114  _force_indices.resize(1);
115 
116  this->_force_indices[0] = postprocessing.register_quantity("cable_force");
117 
118  }
119  else
120  {
121  std::cerr << "Error: Invalue output_vars value for "+elastic_cable << std::endl
122  << " Found " << name << std::endl
123  << " Acceptable values are: stress" << std::endl
124  << " strain" << std::endl
125  << " force " << std::endl;
126  libmesh_error();
127  }
128  }
129  }
130  return;
131  }
132 
133  template<typename StressStrainLaw>
135  AssemblyContext& context,
136  CachedValues& /*cache*/ )
137  {
138  const unsigned int n_u_dofs = context.get_dof_indices(_disp_vars.u_var()).size();
139 
140  const std::vector<libMesh::Real> &JxW =
141  this->get_fe(context)->get_JxW();
142 
143  // Residuals that we're populating
144  libMesh::DenseSubVector<libMesh::Number> &Fu = context.get_elem_residual(_disp_vars.u_var());
145  libMesh::DenseSubVector<libMesh::Number> &Fv = context.get_elem_residual(_disp_vars.v_var());
146  libMesh::DenseSubVector<libMesh::Number> &Fw = context.get_elem_residual(_disp_vars.w_var());
147 
148  //Grab the Jacobian matrix as submatrices
149  //libMesh::DenseMatrix<libMesh::Number> &K = context.get_elem_jacobian();
150  libMesh::DenseSubMatrix<libMesh::Number> &Kuu = context.get_elem_jacobian(_disp_vars.u_var(),_disp_vars.u_var());
151  libMesh::DenseSubMatrix<libMesh::Number> &Kuv = context.get_elem_jacobian(_disp_vars.u_var(),_disp_vars.v_var());
152  libMesh::DenseSubMatrix<libMesh::Number> &Kuw = context.get_elem_jacobian(_disp_vars.u_var(),_disp_vars.w_var());
153  libMesh::DenseSubMatrix<libMesh::Number> &Kvu = context.get_elem_jacobian(_disp_vars.v_var(),_disp_vars.u_var());
154  libMesh::DenseSubMatrix<libMesh::Number> &Kvv = context.get_elem_jacobian(_disp_vars.v_var(),_disp_vars.v_var());
155  libMesh::DenseSubMatrix<libMesh::Number> &Kvw = context.get_elem_jacobian(_disp_vars.v_var(),_disp_vars.w_var());
156  libMesh::DenseSubMatrix<libMesh::Number> &Kwu = context.get_elem_jacobian(_disp_vars.w_var(),_disp_vars.u_var());
157  libMesh::DenseSubMatrix<libMesh::Number> &Kwv = context.get_elem_jacobian(_disp_vars.w_var(),_disp_vars.v_var());
158  libMesh::DenseSubMatrix<libMesh::Number> &Kww = context.get_elem_jacobian(_disp_vars.w_var(),_disp_vars.w_var());
159 
160 
161  unsigned int n_qpoints = context.get_element_qrule().n_points();
162 
163  // All shape function gradients are w.r.t. master element coordinates
164  const std::vector<std::vector<libMesh::Real> >& dphi_dxi = this->get_fe(context)->get_dphidxi();
165 
166  const libMesh::DenseSubVector<libMesh::Number>& u_coeffs = context.get_elem_solution( _disp_vars.u_var() );
167  const libMesh::DenseSubVector<libMesh::Number>& v_coeffs = context.get_elem_solution( _disp_vars.v_var() );
168  const libMesh::DenseSubVector<libMesh::Number>& w_coeffs = context.get_elem_solution( _disp_vars.w_var() );
169 
170  // Need these to build up the covariant and contravariant metric tensors
171  const std::vector<libMesh::RealGradient>& dxdxi = this->get_fe(context)->get_dxyzdxi();
172 
173  const unsigned int dim = 1; // The cable dimension is always 1 for this physics
174 
175 
176  for (unsigned int qp=0; qp != n_qpoints; qp++)
177  {
178  // Gradients are w.r.t. master element coordinates
179  libMesh::Gradient grad_u, grad_v, grad_w;
180 
181  for( unsigned int d = 0; d < n_u_dofs; d++ )
182  {
183  libMesh::RealGradient u_gradphi( dphi_dxi[d][qp] );
184  grad_u += u_coeffs(d)*u_gradphi;
185  grad_v += v_coeffs(d)*u_gradphi;
186  grad_w += w_coeffs(d)*u_gradphi;
187  }
188 
189  libMesh::RealGradient grad_x( dxdxi[qp](0) );
190  libMesh::RealGradient grad_y( dxdxi[qp](1) );
191  libMesh::RealGradient grad_z( dxdxi[qp](2) );
192 
193  libMesh::TensorValue<libMesh::Real> a_cov, a_contra, A_cov, A_contra;
194  libMesh::Real lambda_sq = 0;
195 
196  this->compute_metric_tensors( qp, *(this->get_fe(context)), context,
197  grad_u, grad_v, grad_w,
198  a_cov, a_contra, A_cov, A_contra,
199  lambda_sq );
200 
201  // Compute stress tensor
204  //_stress_strain_law.compute_stress(dim,a_contra,a_cov,A_contra,A_cov,tau);
205  _stress_strain_law.compute_stress_and_elasticity(dim,a_contra,a_cov,A_contra,A_cov,tau,C);
206 
207 
208  libMesh::Real jac = JxW[qp];
209 
210  for (unsigned int i=0; i != n_u_dofs; i++)
211  {
212  libMesh::RealGradient u_gradphi( dphi_dxi[i][qp] );
213 
214  Fu(i) -= tau(0,0)*_A*( (grad_x(0) + grad_u(0))*u_gradphi(0) ) * jac;
215 
216  Fv(i) -= tau(0,0)*_A*( (grad_y(0) + grad_v(0))*u_gradphi(0) ) * jac;
217 
218  Fw(i) -= tau(0,0)*_A*( (grad_z(0) + grad_w(0))*u_gradphi(0) ) * jac;
219 
220  }
221 
222  if( compute_jacobian )
223  {
224  for(unsigned int i=0; i != n_u_dofs; i++)
225  {
226  libMesh::RealGradient u_gradphi_I( dphi_dxi[i][qp] );
227  for(unsigned int j=0; j != n_u_dofs; j++)
228  {
229  libMesh::RealGradient u_gradphi_J( dphi_dxi[j][qp] );
230 
231  const libMesh::Real diag_term = _A*jac*tau(0,0)*( u_gradphi_J(0)*u_gradphi_I(0));
232 
233  Kuu(i,j) -= diag_term;
234 
235  Kvv(i,j) -= diag_term;
236 
237  Kww(i,j) -= diag_term;
238 
239  const libMesh::Real dgamma_du = ( u_gradphi_J(0)*(grad_x(0)+grad_u(0)) );
240 
241  const libMesh::Real dgamma_dv = ( u_gradphi_J(0)*(grad_y(0)+grad_v(0)) );
242 
243  const libMesh::Real dgamma_dw = ( u_gradphi_J(0)*(grad_z(0)+grad_w(0)) );
244 
245  const libMesh::Real C1 = _A*jac*C(0,0,0,0);
246 
247  const libMesh::Real x_term = C1*( (grad_x(0)+grad_u(0))*u_gradphi_I(0) );
248 
249  const libMesh::Real y_term = C1*( (grad_y(0)+grad_v(0))*u_gradphi_I(0) );
250 
251  const libMesh::Real z_term = C1*( (grad_z(0)+grad_w(0))*u_gradphi_I(0) );
252 
253  Kuu(i,j) -= x_term*dgamma_du;
254 
255  Kuv(i,j) -= x_term*dgamma_dv;
256 
257  Kuw(i,j) -= x_term*dgamma_dw;
258 
259  Kvu(i,j) -= y_term*dgamma_du;
260 
261  Kvv(i,j) -= y_term*dgamma_dv;
262 
263  Kvw(i,j) -= y_term*dgamma_dw;
264 
265  Kwu(i,j) -= z_term*dgamma_du;
266 
267  Kwv(i,j) -= z_term*dgamma_dv;
268 
269  Kww(i,j) -= z_term*dgamma_dw;
270 
271  }
272  }
273  //libmesh_not_implemented();
274  }
275  }
276 
277  return;
278  }
279 
280  template<typename StressStrainLaw>
282  AssemblyContext& context,
283  CachedValues& cache )
284  {
285  std::vector<BoundaryID> ids = context.side_boundary_ids();
286 
287  for( std::vector<BoundaryID>::const_iterator it = ids.begin();
288  it != ids.end(); it++ )
289  {
290  libmesh_assert (*it != libMesh::BoundaryInfo::invalid_id);
291 
292  _bc_handler->apply_neumann_bcs( context, cache, compute_jacobian, *it );
293  }
294 
295  return;
296  }
297 
298  template<typename StressStrainLaw>
299  void ElasticCable<StressStrainLaw>::mass_residual( bool /*compute_jacobian*/,
300  AssemblyContext& /*context*/,
301  CachedValues& /*cache*/ )
302  {
303  libmesh_not_implemented();
304  return;
305  }
306 
307  template<typename StressStrainLaw>
309  const AssemblyContext& context,
310  const libMesh::Point& point,
311  libMesh::Real& value )
312  {
313  bool is_strain = false;
314  if( !_strain_indices.empty() )
315  is_strain = ( _strain_indices[0] == quantity_index );
316 
317  bool is_stress = false;
318  if( !_stress_indices.empty() )
319  is_stress = ( _stress_indices[0] == quantity_index );
320 
321  bool is_force = false;
322  if( !_force_indices.empty() )
323  is_force = ( _force_indices[0] == quantity_index );
324 
325  if( is_strain || is_stress || is_force )
326  {
327  const unsigned int n_u_dofs = context.get_dof_indices(_disp_vars.u_var()).size();
328 
329  const libMesh::DenseSubVector<libMesh::Number>& u_coeffs = context.get_elem_solution( _disp_vars.u_var() );
330  const libMesh::DenseSubVector<libMesh::Number>& v_coeffs = context.get_elem_solution( _disp_vars.v_var() );
331  const libMesh::DenseSubVector<libMesh::Number>& w_coeffs = context.get_elem_solution( _disp_vars.w_var() );
332 
333  // Build new FE for the current point. We need this to build tensors at point.
334  libMesh::AutoPtr<libMesh::FEGenericBase<libMesh::Real> > fe_new = this->build_new_fe( context.get_elem(), this->get_fe(context), point );
335 
336  const std::vector<std::vector<libMesh::Real> >& dphi_dxi = fe_new->get_dphidxi();
337 
338  // Need these to build up the covariant and contravariant metric tensors
339  const std::vector<libMesh::RealGradient>& dxdxi = fe_new->get_dxyzdxi();
340 
341  // Gradients are w.r.t. master element coordinates
342  libMesh::Gradient grad_u, grad_v, grad_w;
343  for( unsigned int d = 0; d < n_u_dofs; d++ )
344  {
345  libMesh::RealGradient u_gradphi( dphi_dxi[d][0] );
346  grad_u += u_coeffs(d)*u_gradphi;
347  grad_v += v_coeffs(d)*u_gradphi;
348  grad_w += w_coeffs(d)*u_gradphi;
349  }
350 
351  libMesh::RealGradient grad_x( dxdxi[0](0) );
352  libMesh::RealGradient grad_y( dxdxi[0](1) );
353  libMesh::RealGradient grad_z( dxdxi[0](2) );
354 
355  libMesh::TensorValue<libMesh::Real> a_cov, a_contra, A_cov, A_contra;
356  libMesh::Real lambda_sq = 0;
357 
358  this->compute_metric_tensors(0, *fe_new, context, grad_u, grad_v, grad_w, a_cov, a_contra, A_cov, A_contra, lambda_sq );
359 
360  libMesh::Real det_a = a_cov(0,0)*a_cov(1,1) - a_cov(0,1)*a_cov(1,0);
361  libMesh::Real det_A = A_cov(0,0)*A_cov(1,1) - A_cov(0,1)*A_cov(1,0);
362 
363  libMesh::Real I3 = lambda_sq*det_A/det_a;
364 
366  _stress_strain_law.compute_stress(1,a_contra,a_cov,A_contra,A_cov,tau);
367 
368  // We have everything we need for strain now, so check if we are computing strain
369  if( is_strain )
370  {
371  if( _strain_indices[0] == quantity_index )
372  {
373  value = 0.5*(A_cov(0,0) - a_cov(0,0));
374  }
375  else
376  {
377  //Wat?!
378  libmesh_error();
379  }
380  return;
381  }
382 
383  if( is_stress )
384  {
385  if( _stress_indices[0] == quantity_index )
386  {
387  // Need to convert to Cauchy stress
388  value = tau(0,0)/std::sqrt(I3);
389  }
390  else
391  {
392  libmesh_error();
393  }
394  }
395  if( is_force )
396  {
397 
398  if( _force_indices[0] == quantity_index )
399  {
400  //This force is in deformed configuration and will be significantly influenced by large strains
401  value = tau(0,0)/std::sqrt(I3)*_A;
402  }
403  else
404  {
405  libmesh_error();
406  }
407  }
408  }
409 
410  return;
411  }
412 
413  template<typename StressStrainLaw>
414  libMesh::AutoPtr<libMesh::FEGenericBase<libMesh::Real> > ElasticCable<StressStrainLaw>::build_new_fe( const libMesh::Elem& elem,
415  const libMesh::FEGenericBase<libMesh::Real>* fe,
416  const libMesh::Point p )
417  {
418  using namespace libMesh;
419  FEType fe_type = fe->get_fe_type();
420 
421  // If we don't have an Elem to evaluate on, then the only functions
422  // we can sensibly evaluate are the scalar dofs which are the same
423  // everywhere.
424  libmesh_assert(&elem || fe_type.family == SCALAR);
425 
426  unsigned int elem_dim = &elem ? elem.dim() : 0;
427 
428  AutoPtr<FEGenericBase<libMesh::Real> >
429  fe_new(FEGenericBase<libMesh::Real>::build(elem_dim, fe_type));
430 
431  // Map the physical co-ordinates to the master co-ordinates using the inverse_map from fe_interface.h
432  // Build a vector of point co-ordinates to send to reinit
433  Point master_point = &elem ?
434  FEInterface::inverse_map(elem_dim, fe_type, &elem, p) :
435  Point(0);
436 
437  std::vector<Point> coor(1, master_point);
438 
439  // Reinitialize the element and compute the shape function values at coor
440  fe_new->reinit (&elem, &coor);
441 
442  return fe_new;
443  }
444 
445  template<typename StressStrainLaw>
447  const libMesh::FEBase& elem,
448  const AssemblyContext& /*context*/,
449  const libMesh::Gradient& grad_u,
450  const libMesh::Gradient& grad_v,
451  const libMesh::Gradient& grad_w,
456  libMesh::Real& lambda_sq )
457  {
458  const std::vector<libMesh::RealGradient>& dxdxi = elem.get_dxyzdxi();
459 
460  const std::vector<libMesh::Real>& dxidx = elem.get_dxidx();
461  const std::vector<libMesh::Real>& dxidy = elem.get_dxidy();
462  const std::vector<libMesh::Real>& dxidz = elem.get_dxidz();
463 
464  libMesh::RealGradient dxi( dxidx[qp], dxidy[qp], dxidz[qp] );
465 
466  libMesh::RealGradient dudxi( grad_u(0), grad_v(0), grad_w(0) );
467 
468  // Covariant metric tensor of reference configuration
469  a_cov.zero();
470  a_cov(0,0) = dxdxi[qp]*dxdxi[qp];
471  a_cov(1,1) = 1.0;
472  a_cov(2,2) = 1.0;
473 
474  // Covariant metric tensor of current configuration
475  A_cov.zero();
476  A_cov(0,0) = (dxdxi[qp] + dudxi)*(dxdxi[qp] + dudxi);
477 
478  // Contravariant metric tensor of reference configuration
479  a_contra.zero();
480  a_contra(0,0) = 1/a_cov(0,0);
481  a_contra(1,1) = 1.0;
482  a_contra(2,2) = 1.0;
483 
484  // Contravariant metric tensor in current configuration is A_cov^{-1}
485  A_contra.zero();
486  A_contra(0,0) = 1/A_cov(0,0);
487 
488  // If the material is compressible, then lambda_sq is an independent variable
489  if( _is_compressible )
490  {
491  libmesh_not_implemented();
492  //lambda_sq = context.interior_value(this->_lambda_sq_var, qp);
493  }
494  else
495  {
496  // If the material is incompressible, lambda^2 is known
497  lambda_sq = a_cov(0,0)/A_cov(0,0);//det_a/det_A;
498  }
499 
500  //Update the covariant and contravariant tensors of current configuration
501  A_cov(1,1) = lambda_sq;
502  A_cov(2,2) = lambda_sq;
503  A_contra(1,1) = 1.0/lambda_sq;
504  A_contra(2,2) = 1.0/lambda_sq;
505 
506  return;
507  }
508 
509 } // end namespace GRINS
virtual void set_parameter(libMesh::Number &param_variable, const GetPot &input, const std::string &param_name, libMesh::Number param_default)
Each subclass can simultaneously read a parameter value from.
void compute_metric_tensors(unsigned int qp, const libMesh::FEBase &elem, const AssemblyContext &context, const libMesh::Gradient &grad_u, const libMesh::Gradient &grad_v, const libMesh::Gradient &grad_w, libMesh::TensorValue< libMesh::Real > &a_cov, libMesh::TensorValue< libMesh::Real > &a_contra, libMesh::TensorValue< libMesh::Real > &A_cov, libMesh::TensorValue< libMesh::Real > &A_contra, libMesh::Real &lambda_sq)
unsigned int register_quantity(std::string name)
Register quantity to be postprocessed.
GRINS::ICHandlingBase * _ic_handler
Definition: physics.h:258
GRINS::BCHandlingBase * _bc_handler
Definition: physics.h:256
virtual void compute_postprocessed_quantity(unsigned int quantity_index, const AssemblyContext &context, const libMesh::Point &point, libMesh::Real &value)
Compute the registered postprocessed quantities.
libMesh::Real _A
Definition: elastic_cable.h:93
Base class for reading and handling initial conditions for physics classes.
virtual void side_time_derivative(bool compute_jacobian, AssemblyContext &context, CachedValues &cache)
Time dependent part(s) of physics for boundaries of elements on the domain boundary.
GRINS namespace.
virtual ~ElasticCable()
Definition: elastic_cable.C:72
virtual void register_postprocessing_vars(const GetPot &input, PostProcessedQuantities< libMesh::Real > &postprocessing)
Register postprocessing variables for ElasticCable.
Definition: elastic_cable.C:79
const PhysicsName elastic_cable
std::string PhysicsName
virtual void mass_residual(bool compute_jacobian, AssemblyContext &context, CachedValues &cache)
Mass matrix part(s) for element interiors. All boundary terms lie within the time_derivative part...
virtual void element_time_derivative(bool compute_jacobian, AssemblyContext &context, CachedValues &cache)
Time dependent part(s) of physics for element interiors.
libMesh::AutoPtr< libMesh::FEGenericBase< libMesh::Real > > build_new_fe(const libMesh::Elem &elem, const libMesh::FEGenericBase< libMesh::Real > *fe, const libMesh::Point p)

Generated on Mon Jun 22 2015 21:32:20 for GRINS-0.6.0 by  doxygen 1.8.9.1