libMesh
naviersystem.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 #include "libmesh/getpot.h"
19 
20 #include "naviersystem.h"
21 
22 #include "libmesh/dirichlet_boundaries.h"
23 #include "libmesh/dof_map.h"
24 #include "libmesh/fe_base.h"
25 #include "libmesh/fe_interface.h"
26 #include "libmesh/fem_context.h"
27 #include "libmesh/mesh.h"
28 #include "libmesh/quadrature.h"
29 #include "libmesh/string_to_enum.h"
30 #include "libmesh/zero_function.h"
31 #include "libmesh/elem.h"
32 #include "libmesh/auto_ptr.h" // libmesh_make_unique
33 
34 // Bring in everything from the libMesh namespace
35 using namespace libMesh;
36 
37 
38 // Boundary conditions for the 3D test case
39 class BdyFunction : public FunctionBase<Number>
40 {
41 public:
42  BdyFunction (unsigned int u_var,
43  unsigned int v_var,
44  unsigned int w_var,
45  Real Reynolds)
46  : _u_var(u_var), _v_var(v_var), _w_var(w_var), _Re(Reynolds)
47  { this->_initialized = true; }
48 
49  virtual Number operator() (const Point &, const Real = 0)
50  { libmesh_not_implemented(); }
51 
52  virtual void operator() (const Point & p,
53  const Real,
54  DenseVector<Number> & output)
55  {
56  output.zero();
57  const Real x=p(0), y=p(1), z=p(2);
58  output(_u_var) = (_Re+1)*(y*y + z*z);
59  output(_v_var) = (_Re+1)*(x*x + z*z);
60  output(_w_var) = (_Re+1)*(x*x + y*y);
61  }
62 
63  virtual std::unique_ptr<FunctionBase<Number>> clone() const
64  { return libmesh_make_unique<BdyFunction>(_u_var, _v_var, _w_var, _Re); }
65 
66 private:
67  const unsigned int _u_var, _v_var, _w_var;
68  const Real _Re;
69 };
70 
71 
73 {
74  const unsigned int dim = this->get_mesh().mesh_dimension();
75 
76  // Check the input file for Reynolds number, application type,
77  // approximation type
78  GetPot infile("navier.in");
79  Reynolds = infile("Reynolds", 1.);
80  application = infile("application", 0);
81  unsigned int pressure_p = infile("pressure_p", 1);
82  std::string fe_family = infile("fe_family", std::string("LAGRANGE"));
83 
84  // LBB needs better-than-quadratic velocities for better-than-linear
85  // pressures, and libMesh needs non-Lagrange elements for
86  // better-than-quadratic velocities.
87  libmesh_assert((pressure_p == 1) || (fe_family != "LAGRANGE"));
88 
89  FEFamily fefamily = Utility::string_to_enum<FEFamily>(fe_family);
90 
91  // Add the velocity components "u" & "v". They
92  // will be approximated using second-order approximation.
93  u_var = this->add_variable ("u", static_cast<Order>(pressure_p+1),
94  fefamily);
95  v_var = this->add_variable ("v",
96  static_cast<Order>(pressure_p+1),
97  fefamily);
98 
99  if (dim == 3)
100  w_var = this->add_variable ("w",
101  static_cast<Order>(pressure_p+1),
102  fefamily);
103  else
104  w_var = u_var;
105 
106  // Add the pressure variable "p". This will
107  // be approximated with a first-order basis,
108  // providing an LBB-stable pressure-velocity pair.
109  p_var = this->add_variable ("p",
110  static_cast<Order>(pressure_p),
111  fefamily);
112 
113  // Tell the system to march velocity forward in time, but
114  // leave p as a constraint only
115  this->time_evolving(u_var, 1);
116  this->time_evolving(v_var, 1);
117  if (dim == 3)
118  this->time_evolving(w_var, 1);
119 
120  // Useful debugging options
121  // Set verify_analytic_jacobians to 1e-6 to use
122  this->verify_analytic_jacobians = infile("verify_analytic_jacobians", 0.);
123  this->print_jacobians = infile("print_jacobians", false);
124  this->print_element_jacobians = infile("print_element_jacobians", false);
125 
126  // Set Dirichlet boundary conditions
127 #ifdef LIBMESH_ENABLE_DIRICHLET
128  const boundary_id_type top_id = (dim==3) ? 5 : 2;
129 
130  std::set<boundary_id_type> top_bdys;
131  top_bdys.insert(top_id);
132 
133  const boundary_id_type all_ids[6] = {0, 1, 2, 3, 4, 5};
134  std::set<boundary_id_type> all_bdys(all_ids, all_ids+(dim*2));
135 
136  std::set<boundary_id_type> nontop_bdys = all_bdys;
137  nontop_bdys.erase(top_id);
138 
139  std::vector<unsigned int> u_only(1, u_var);
140  std::vector<unsigned int> vw(1, v_var), uvw(1, u_var);
141  uvw.push_back(v_var);
142  if (dim == 3)
143  {
144  vw.push_back(w_var);
145  uvw.push_back(w_var);
146  }
147 
149  ConstFunction<Number> one(1);
150  // For lid-driven cavity, set u=1,v=w=0 on the lid and u=v=w=0 elsewhere
151  if (application == 0)
152  {
153  this->get_dof_map().add_dirichlet_boundary
154  (DirichletBoundary (top_bdys, u_only, &one));
155  this->get_dof_map().add_dirichlet_boundary
156  (DirichletBoundary (top_bdys, vw, &zero));
157  this->get_dof_map().add_dirichlet_boundary
158  (DirichletBoundary (nontop_bdys, uvw, &zero));
159  }
160  // For forcing with zero wall velocity, set homogeneous Dirichlet BCs
161  else if (application == 1)
162  {
163  this->get_dof_map().add_dirichlet_boundary
164  (DirichletBoundary (all_bdys, uvw, &zero));
165  }
166  // For 3D test case with quadratic velocity field, set that field on walls
167  else if (application == 2)
168  {
169  BdyFunction bdy(u_var, v_var, w_var, Reynolds);
170  this->get_dof_map().add_dirichlet_boundary
171  (DirichletBoundary (all_bdys, uvw, &bdy));
172  }
173 #endif // LIBMESH_ENABLE_DIRICHLET
174 
175  // Do the parent's initialization after variables and boundary constraints are defined
177 }
178 
179 
180 
182 {
183  FEMContext & c = cast_ref<FEMContext &>(context);
184 
185  FEBase * u_elem_fe;
186  FEBase * p_elem_fe;
187  FEBase * u_side_fe;
188 
189  c.get_element_fe(u_var, u_elem_fe);
190  c.get_element_fe(p_var, p_elem_fe);
191  c.get_side_fe(u_var, u_side_fe);
192 
193  // We should prerequest all the data
194  // we will need to build the linear system.
195  u_elem_fe->get_JxW();
196  u_elem_fe->get_phi();
197  u_elem_fe->get_dphi();
198  u_elem_fe->get_xyz();
199 
200  p_elem_fe->get_phi();
201 
202  u_side_fe->get_JxW();
203  u_side_fe->get_phi();
204  u_side_fe->get_xyz();
205 }
206 
207 
208 bool NavierSystem::element_time_derivative (bool request_jacobian,
209  DiffContext & context)
210 {
211  FEMContext & c = cast_ref<FEMContext &>(context);
212 
213  FEBase * u_elem_fe;
214  FEBase * p_elem_fe;
215 
216  c.get_element_fe(u_var, u_elem_fe);
217  c.get_element_fe(p_var, p_elem_fe);
218 
219  // First we get some references to cell-specific data that
220  // will be used to assemble the linear system.
221 
222  // Element Jacobian * quadrature weights for interior integration
223  const std::vector<Real> & JxW = u_elem_fe->get_JxW();
224 
225  // The velocity shape functions at interior quadrature points.
226  const std::vector<std::vector<Real>> & phi = u_elem_fe->get_phi();
227 
228  // The velocity shape function gradients at interior
229  // quadrature points.
230  const std::vector<std::vector<RealGradient>> & dphi = u_elem_fe->get_dphi();
231 
232  // The pressure shape functions at interior
233  // quadrature points.
234  const std::vector<std::vector<Real>> & psi = p_elem_fe->get_phi();
235 
236  // Physical location of the quadrature points
237  const std::vector<Point> & qpoint = u_elem_fe->get_xyz();
238 
239  // The number of local degrees of freedom in each variable
240  const unsigned int n_p_dofs = c.n_dof_indices(p_var);
241  const unsigned int n_u_dofs = c.n_dof_indices(u_var);
242  libmesh_assert_equal_to (n_u_dofs, c.n_dof_indices(v_var));
243 
244  // The subvectors and submatrices we need to fill:
245  const unsigned int dim = this->get_mesh().mesh_dimension();
246  DenseSubMatrix<Number> & Kuu = c.get_elem_jacobian(u_var, u_var);
247  DenseSubMatrix<Number> & Kvv = c.get_elem_jacobian(v_var, v_var);
248  DenseSubMatrix<Number> & Kww = c.get_elem_jacobian(w_var, w_var);
249  DenseSubMatrix<Number> & Kuv = c.get_elem_jacobian(u_var, v_var);
250  DenseSubMatrix<Number> & Kuw = c.get_elem_jacobian(u_var, w_var);
251  DenseSubMatrix<Number> & Kvu = c.get_elem_jacobian(v_var, u_var);
252  DenseSubMatrix<Number> & Kvw = c.get_elem_jacobian(v_var, w_var);
253  DenseSubMatrix<Number> & Kwu = c.get_elem_jacobian(w_var, u_var);
254  DenseSubMatrix<Number> & Kwv = c.get_elem_jacobian(w_var, v_var);
255  DenseSubMatrix<Number> & Kup = c.get_elem_jacobian(u_var, p_var);
256  DenseSubMatrix<Number> & Kvp = c.get_elem_jacobian(v_var, p_var);
257  DenseSubMatrix<Number> & Kwp = c.get_elem_jacobian(w_var, p_var);
261 
262  // Now we will build the element Jacobian and residual.
263  // Constructing the residual requires the solution and its
264  // gradient from the previous timestep. This must be
265  // calculated at each quadrature point by summing the
266  // solution degree-of-freedom values by the appropriate
267  // weight functions.
268  unsigned int n_qpoints = c.get_element_qrule().n_points();
269 
270  // Variables to store solutions & its gradient at old Newton iterate
271  Number p, u, v, w;
272  Gradient grad_u, grad_v, grad_w;
273 
274  for (unsigned int qp=0; qp != n_qpoints; qp++)
275  {
276  // Compute the solution & its gradient at the old Newton iterate
277  c.interior_value(p_var, qp, p);
278  c.interior_value(u_var, qp, u);
279  c.interior_value(v_var, qp, v);
280  c.interior_value(w_var, qp, w);
281  c.interior_gradient(u_var, qp, grad_u);
282  c.interior_gradient(v_var, qp, grad_v);
283  c.interior_gradient(w_var, qp, grad_w);
284 
285  // Definitions for convenience. It is sometimes simpler to do a
286  // dot product if you have the full vector at your disposal.
287  NumberVectorValue U (u, v);
288  if (dim == 3)
289  U(2) = w;
290  const Number u_x = grad_u(0);
291  const Number u_y = grad_u(1);
292  const Number u_z = (dim == 3) ? grad_u(2) : 0;
293  const Number v_x = grad_v(0);
294  const Number v_y = grad_v(1);
295  const Number v_z = (dim == 3) ? grad_v(2) : 0;
296  const Number w_x = (dim == 3) ? grad_w(0) : 0;
297  const Number w_y = (dim == 3) ? grad_w(1) : 0;
298  const Number w_z = (dim == 3) ? grad_w(2) : 0;
299 
300  // Value of the forcing function at this quadrature point
301  Point f = this->forcing(qpoint[qp]);
302 
303  // First, an i-loop over the velocity degrees of freedom.
304  // We know that n_u_dofs == n_v_dofs so we can compute contributions
305  // for both at the same time.
306  for (unsigned int i=0; i != n_u_dofs; i++)
307  {
308  Fu(i) += JxW[qp] *
309  (-Reynolds*(U*grad_u)*phi[i][qp] + // convection term
310  p*dphi[i][qp](0) - // pressure term
311  (grad_u*dphi[i][qp]) + // diffusion term
312  f(0)*phi[i][qp] // forcing function
313  );
314 
315 
316  Fv(i) += JxW[qp] *
317  (-Reynolds*(U*grad_v)*phi[i][qp] + // convection term
318  p*dphi[i][qp](1) - // pressure term
319  (grad_v*dphi[i][qp]) + // diffusion term
320  f(1)*phi[i][qp] // forcing function
321  );
322 
323 
324  if (dim == 3)
325  Fw(i) += JxW[qp] *
326  (-Reynolds*(U*grad_w)*phi[i][qp] + // convection term
327  p*dphi[i][qp](2) - // pressure term
328  (grad_w*dphi[i][qp]) + // diffusion term
329  f(2)*phi[i][qp] // forcing function
330  );
331 
332 
333  // Note that the Fp block is identically zero unless we are using
334  // some kind of artificial compressibility scheme...
335 
336  if (request_jacobian && c.elem_solution_derivative)
337  {
338  libmesh_assert_equal_to (c.elem_solution_derivative, 1.0);
339 
340  // Matrix contributions for the uu and vv couplings.
341  for (unsigned int j=0; j != n_u_dofs; j++)
342  {
343  Kuu(i,j) += JxW[qp] *
344  /* convection term */ (-Reynolds*(U*dphi[j][qp])*phi[i][qp] -
345  /* diffusion term */ (dphi[i][qp]*dphi[j][qp]) -
346  /* Newton term */ Reynolds*u_x*phi[i][qp]*phi[j][qp]);
347 
348  Kuv(i,j) += JxW[qp] *
349  /* Newton term */ -Reynolds*u_y*phi[i][qp]*phi[j][qp];
350 
351  Kvv(i,j) += JxW[qp] *
352  /* convection term */ (-Reynolds*(U*dphi[j][qp])*phi[i][qp] -
353  /* diffusion term */ (dphi[i][qp]*dphi[j][qp]) -
354  /* Newton term */ Reynolds*v_y*phi[i][qp]*phi[j][qp]);
355 
356  Kvu(i,j) += JxW[qp] *
357  /* Newton term */ -Reynolds*v_x*phi[i][qp]*phi[j][qp];
358  if (dim == 3)
359  {
360  Kww(i,j) += JxW[qp] *
361  /* convection term */ (-Reynolds*(U*dphi[j][qp])*phi[i][qp] -
362  /* diffusion term */ (dphi[i][qp]*dphi[j][qp]) -
363  /* Newton term */ Reynolds*w_z*phi[i][qp]*phi[j][qp]);
364  Kuw(i,j) += JxW[qp] *
365  /* Newton term */ -Reynolds*u_z*phi[i][qp]*phi[j][qp];
366  Kvw(i,j) += JxW[qp] *
367  /* Newton term */ -Reynolds*v_z*phi[i][qp]*phi[j][qp];
368  Kwu(i,j) += JxW[qp] *
369  /* Newton term */ -Reynolds*w_x*phi[i][qp]*phi[j][qp];
370  Kwv(i,j) += JxW[qp] *
371  /* Newton term */ -Reynolds*w_y*phi[i][qp]*phi[j][qp];
372  }
373  }
374 
375  // Matrix contributions for the up and vp couplings.
376  for (unsigned int j=0; j != n_p_dofs; j++)
377  {
378  Kup(i,j) += JxW[qp]*psi[j][qp]*dphi[i][qp](0);
379  Kvp(i,j) += JxW[qp]*psi[j][qp]*dphi[i][qp](1);
380  if (dim == 3)
381  Kwp(i,j) += JxW[qp]*psi[j][qp]*dphi[i][qp](2);
382  }
383  }
384  }
385  } // end of the quadrature point qp-loop
386 
387  return request_jacobian;
388 }
389 
390 
391 
392 bool NavierSystem::element_constraint (bool request_jacobian,
393  DiffContext & context)
394 {
395  FEMContext & c = cast_ref<FEMContext &>(context);
396 
397  FEBase * u_elem_fe;
398  FEBase * p_elem_fe;
399 
400  c.get_element_fe(u_var, u_elem_fe);
401  c.get_element_fe(p_var, p_elem_fe);
402 
403  // Here we define some references to cell-specific data that
404  // will be used to assemble the linear system.
405 
406  // Element Jacobian * quadrature weight for interior integration
407  const std::vector<Real> & JxW = u_elem_fe->get_JxW();
408 
409  // The velocity shape function gradients at interior
410  // quadrature points.
411  const std::vector<std::vector<RealGradient>> & dphi = u_elem_fe->get_dphi();
412 
413  // The pressure shape functions at interior
414  // quadrature points.
415  const std::vector<std::vector<Real>> & psi = p_elem_fe->get_phi();
416 
417  // The number of local degrees of freedom in each variable
418  const unsigned int n_u_dofs = c.n_dof_indices(u_var);
419  const unsigned int n_p_dofs = c.n_dof_indices(p_var);
420 
421  // The subvectors and submatrices we need to fill:
422  const unsigned int dim = this->get_mesh().mesh_dimension();
423  DenseSubMatrix<Number> & Kpu = c.get_elem_jacobian(p_var, u_var);
424  DenseSubMatrix<Number> & Kpv = c.get_elem_jacobian(p_var, v_var);
425  DenseSubMatrix<Number> & Kpw = c.get_elem_jacobian(p_var, w_var);
427 
428  // Add the constraint given by the continuity equation
429  unsigned int n_qpoints = c.get_element_qrule().n_points();
430 
431  // Variables to store solutions & its gradient at old Newton iterate
432  Gradient grad_u, grad_v, grad_w;
433 
434  for (unsigned int qp=0; qp != n_qpoints; qp++)
435  {
436  // Compute the velocity gradient at the old Newton iterate
437  c.interior_gradient(u_var, qp, grad_u),
438  c.interior_gradient(v_var, qp, grad_v),
439  c.interior_gradient(w_var, qp, grad_w);
440 
441  // Now a loop over the pressure degrees of freedom. This
442  // computes the contributions of the continuity equation.
443  for (unsigned int i=0; i != n_p_dofs; i++)
444  {
445  Fp(i) += JxW[qp] * psi[i][qp] *
446  (grad_u(0) + grad_v(1));
447  if (dim == 3)
448  Fp(i) += JxW[qp] * psi[i][qp] *
449  (grad_w(2));
450 
451  if (request_jacobian && c.get_elem_solution_derivative())
452  {
453  libmesh_assert_equal_to (c.get_elem_solution_derivative(), 1.0);
454 
455  for (unsigned int j=0; j != n_u_dofs; j++)
456  {
457  Kpu(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](0);
458  Kpv(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](1);
459  if (dim == 3)
460  Kpw(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](2);
461  }
462  }
463  }
464  } // end of the quadrature point qp-loop
465 
466  return request_jacobian;
467 }
468 
469 
470 
471 bool NavierSystem::side_constraint (bool request_jacobian,
472  DiffContext & context)
473 {
474  FEMContext & c = cast_ref<FEMContext &>(context);
475 
476  FEBase * p_elem_fe;
477 
478  c.get_element_fe(p_var, p_elem_fe);
479 
480  // Pin p = 0 at the origin
481  const Point zero(0., 0.);
482 
483  if (c.get_elem().contains_point(zero))
484  {
485  // The pressure penalty value. \f$ \frac{1}{\epsilon} \f$
486  const Real penalty = 1.e9;
487 
488  DenseSubMatrix<Number> & Kpp = c.get_elem_jacobian(p_var, p_var);
490  const unsigned int n_p_dofs = c.n_dof_indices(p_var);
491 
492  Number p;
493  c.point_value(p_var, zero, p);
494 
495  Number p_value = 0.;
496 
497  unsigned int dim = get_mesh().mesh_dimension();
498  FEType fe_type = p_elem_fe->get_fe_type();
499  Point p_master = FEMap::inverse_map(dim, &c.get_elem(), zero);
500 
501  std::vector<Real> point_phi(n_p_dofs);
502  for (unsigned int i=0; i != n_p_dofs; i++)
503  {
504  point_phi[i] = FEInterface::shape(dim, fe_type, &c.get_elem(), i, p_master);
505  }
506 
507  for (unsigned int i=0; i != n_p_dofs; i++)
508  {
509  Fp(i) += penalty * (p - p_value) * point_phi[i];
510  if (request_jacobian && c.get_elem_solution_derivative())
511  {
512  libmesh_assert_equal_to (c.get_elem_solution_derivative(), 1.0);
513 
514  for (unsigned int j=0; j != n_p_dofs; j++)
515  Kpp(i,j) += penalty * point_phi[i] * point_phi[j];
516  }
517  }
518  }
519 
520  return request_jacobian;
521 }
522 
523 
524 // We override the default mass_residual function,
525 // because in the non-dimensionalized Navier-Stokes equations
526 // the time derivative of velocity has a Reynolds number coefficient.
527 // Alternatively we could divide the whole equation by
528 // Reynolds number (or choose a more complicated non-dimensionalization
529 // of time), but this gives us an opportunity to demonstrate overriding
530 // FEMSystem::mass_residual()
531 bool NavierSystem::mass_residual (bool request_jacobian,
532  DiffContext & context)
533 {
534  FEMContext & c = cast_ref<FEMContext &>(context);
535 
536  FEBase * u_elem_fe;
537 
538  c.get_element_fe(u_var, u_elem_fe);
539 
540  // The subvectors and submatrices we need to fill:
541  const unsigned int dim = this->get_mesh().mesh_dimension();
542 
543  // Element Jacobian * quadrature weight for interior integration
544  const std::vector<Real> & JxW = u_elem_fe->get_JxW();
545 
546  // The velocity shape functions at interior quadrature points.
547  const std::vector<std::vector<Real>> & phi = u_elem_fe->get_phi();
548 
549  // The subvectors and submatrices we need to fill:
553  DenseSubMatrix<Number> & Kuu = c.get_elem_jacobian(u_var, u_var);
554  DenseSubMatrix<Number> & Kvv = c.get_elem_jacobian(v_var, v_var);
555  DenseSubMatrix<Number> & Kww = c.get_elem_jacobian(w_var, w_var);
556 
557  // The number of local degrees of freedom in velocity
558  const unsigned int n_u_dofs = c.n_dof_indices(u_var);
559 
560  unsigned int n_qpoints = c.get_element_qrule().n_points();
561 
562  // Variables to store time derivatives at old Newton iterate
563  Number u_dot, v_dot, w_dot;
564 
565  for (unsigned int qp = 0; qp != n_qpoints; ++qp)
566  {
567  // Compute time derivatives
568  c.interior_rate(u_var, qp, u_dot),
569  c.interior_rate(v_var, qp, v_dot),
570  c.interior_rate(w_var, qp, w_dot);
571 
572  // We pull as many calculations as possible outside of loops
573  Number JxWxRe = JxW[qp] * Reynolds;
574  Number JxWxRexU = JxWxRe * u_dot;
575  Number JxWxRexV = JxWxRe * v_dot;
576  Number JxWxRexW = JxWxRe * w_dot;
577 
578  for (unsigned int i = 0; i != n_u_dofs; ++i)
579  {
580  Fu(i) -= JxWxRexU * phi[i][qp];
581  Fv(i) -= JxWxRexV * phi[i][qp];
582  if (dim == 3)
583  Fw(i) -= JxWxRexW * phi[i][qp];
584 
585  if (request_jacobian && c.get_elem_solution_derivative())
586  {
587  libmesh_assert_equal_to (c.get_elem_solution_derivative(), 1.0);
588 
589  Number JxWxRexPhiI = JxWxRe * phi[i][qp];
590  Number JxWxRexPhiII = -JxWxRexPhiI * phi[i][qp];
591  Kuu(i,i) += JxWxRexPhiII;
592  Kvv(i,i) += JxWxRexPhiII;
593  if (dim == 3)
594  Kww(i,i) += JxWxRexPhiII;
595 
596  // The mass matrix is symmetric, so we calculate
597  // one triangle and add it to both upper and lower
598  // triangles
599  for (unsigned int j = i+1; j != n_u_dofs; ++j)
600  {
601  Number Kij = -JxWxRexPhiI * phi[j][qp];
602  Kuu(i,j) += Kij;
603  Kuu(j,i) += Kij;
604  Kvv(i,j) += Kij;
605  Kvv(j,i) += Kij;
606  if (dim == 3)
607  {
608  Kww(i,j) += Kij;
609  Kww(j,i) += Kij;
610  }
611  }
612  }
613  }
614  }
615 
616  return request_jacobian;
617 }
618 
619 
620 
622 {
623  const unsigned int dim = this->get_mesh().mesh_dimension();
624 
625  Point p(1./3., 1./3.);
626  Number u = point_value(u_var, p),
627  v = point_value(v_var, p),
628  w = (dim == 3) ? point_value(w_var, p) : 0;
629 
630  libMesh::out << "u(1/3,1/3) = ("
631  << u << ", "
632  << v << ", "
633  << w << ")"
634  << std::endl;
635 }
636 
637 
638 
639 
641 {
642  switch (application)
643  {
644  // lid driven cavity
645  case 0:
646  {
647  // No forcing
648  return Point(0.,0.,0.);
649  }
650 
651  // Homogeneous Dirichlet BCs + sinusoidal forcing
652  case 1:
653  {
654  const unsigned int dim = this->get_mesh().mesh_dimension();
655 
656  // This assumes your domain is defined on [0,1]^dim.
657  Point f;
658 
659  // Counter-Clockwise vortex in x-y plane
660  if (dim==2)
661  {
662  f(0) = std::sin(2.*libMesh::pi*p(1));
663  f(1) = -std::sin(2.*libMesh::pi*p(0));
664  }
665 
666  // Counter-Clockwise vortex in x-z plane
667  else if (dim==3)
668  {
669  f(0) = std::sin(2.*libMesh::pi*p(1));
670  f(1) = 0.;
671  f(2) = -std::sin(2.*libMesh::pi*p(0));
672  }
673 
674  return f;
675  }
676 
677  // 3D test case with quadratic velocity and linear pressure field
678  case 2:
679  {
680  // This problem doesn't make sense in 1D...
681  libmesh_assert_not_equal_to (1, this->get_mesh().mesh_dimension());
682  const Real x=p(0), y=p(1), z=p(2);
683  const Real
684  u=(Reynolds+1)*(y*y + z*z),
685  v=(Reynolds+1)*(x*x + z*z),
686  w=(Reynolds+1)*(x*x + y*y);
687 
688  if (this->get_mesh().mesh_dimension() == 2)
689  return 2*Reynolds*(Reynolds+1)*Point(v*y,
690  u*x);
691  else
692  return 2*Reynolds*(Reynolds+1)*Point(v*y + w*z,
693  u*x + w*z,
694  u*x + v*y);
695  }
696 
697  default:
698  libmesh_error_msg("Invalid application id = " << application);
699  }
700 }
NavierSystem::side_constraint
virtual bool side_constraint(bool request_jacobian, DiffContext &context)
Adds the constraint contribution on side of elem to elem_residual.
Definition: naviersystem.C:471
libMesh::Number
Real Number
Definition: libmesh_common.h:195
libMesh::DiffContext::get_elem_residual
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
Definition: diff_context.h:249
libMesh::FEMContext::get_element_qrule
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
Definition: fem_context.h:790
libMesh::FunctionBase
Base class for functors that can be evaluated at a point and (optionally) time.
Definition: dirichlet_boundaries.h:44
libMesh::pi
const Real pi
.
Definition: libmesh.h:237
libMesh::FEAbstract::get_xyz
const std::vector< Point > & get_xyz() const
Definition: fe_abstract.h:237
BdyFunction::_Re
const Real _Re
Definition: naviersystem.C:68
libMesh::Elem::contains_point
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const
Definition: elem.C:2094
libMesh::FEMSystem::init_data
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
Definition: fem_system.C:843
libMesh::DenseSubMatrix
Defines a dense submatrix for use in Finite Element-type computations.
Definition: dense_submatrix.h:45
libMesh::QBase::n_points
unsigned int n_points() const
Definition: quadrature.h:126
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::DenseVector::zero
virtual void zero() override
Set every element in the vector to 0.
Definition: dense_vector.h:379
libMesh::DiffContext::get_elem_solution_derivative
Real get_elem_solution_derivative() const
The derivative of the current elem_solution w.r.t.
Definition: diff_context.h:436
libMesh::FEGenericBase
This class forms the foundation from which generic finite elements may be derived.
Definition: exact_error_estimator.h:39
libMesh::FEAbstract::get_JxW
const std::vector< Real > & get_JxW() const
Definition: fe_abstract.h:244
libMesh::FEMContext::get_elem
const Elem & get_elem() const
Accessor for current Elem object.
Definition: fem_context.h:896
BdyFunction
Definition: coupled_system.C:38
libMesh::FEGenericBase::get_dphi
const std::vector< std::vector< OutputGradient > > & get_dphi() const
Definition: fe_base.h:214
NavierSystem::init_context
virtual void init_context(DiffContext &context)
Definition: naviersystem.C:181
libMesh::boundary_id_type
int8_t boundary_id_type
Definition: id_types.h:51
libMesh::FEMContext::point_value
Number point_value(unsigned int var, const Point &p) const
Definition: fem_context.C:833
dim
unsigned int dim
Definition: adaptivity_ex3.C:113
libMesh::VectorValue< Number >
libMesh::zero
const Number zero
.
Definition: libmesh.h:243
NavierSystem::init_data
virtual void init_data()
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used.
Definition: naviersystem.C:72
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::FEMContext::interior_rate
void interior_rate(unsigned int var, unsigned int qp, OutputType &u) const
Definition: fem_context.C:1318
naviersystem.h
libMesh::FEMap::inverse_map
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: fe_map.C:1622
NavierSystem::postprocess
virtual void postprocess()
Runs a postprocessing loop over all elements, and if postprocess_sides is true over all sides.
Definition: naviersystem.C:621
NavierSystem::element_constraint
virtual bool element_constraint(bool request_jacobian, DiffContext &context)
Adds the constraint contribution on elem to elem_residual.
Definition: naviersystem.C:392
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
NavierSystem::element_time_derivative
virtual bool element_time_derivative(bool request_jacobian, DiffContext &context)
Adds the time derivative contribution on elem to elem_residual.
Definition: naviersystem.C:208
BdyFunction::clone
virtual std::unique_ptr< FunctionBase< Number > > clone() const
Definition: naviersystem.C:63
libMesh::DiffContext::n_dof_indices
unsigned int n_dof_indices() const
Total number of dof indices on the element.
Definition: diff_context.h:399
BdyFunction::BdyFunction
BdyFunction(unsigned int u_var, unsigned int v_var, unsigned int w_var, Real Reynolds)
Definition: naviersystem.C:42
NavierSystem::mass_residual
virtual bool mass_residual(bool request_jacobian, DiffContext &context)
Subtracts a mass vector contribution on elem from elem_residual.
Definition: naviersystem.C:531
BdyFunction::_w_var
const unsigned int _w_var
Definition: naviersystem.C:67
libMesh::ZeroFunction
ConstFunction that simply returns 0.
Definition: zero_function.h:36
libMesh::FEAbstract::get_fe_type
FEType get_fe_type() const
Definition: fe_abstract.h:427
libMesh::DiffContext
This class provides all data required for a physics package (e.g.
Definition: diff_context.h:55
libMesh::DenseSubVector< Number >
libMesh::DiffContext::elem_solution_derivative
Real elem_solution_derivative
The derivative of elem_solution with respect to the current nonlinear solution.
Definition: diff_context.h:500
NavierSystem::forcing
Point forcing(const Point &p)
Definition: naviersystem.C:640
libMesh::FEMContext::get_element_fe
void get_element_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for interior finite element object for variable var for the largest dimension in the mesh.
Definition: fem_context.h:275
libMesh::FEMContext::interior_gradient
Gradient interior_gradient(unsigned int var, unsigned int qp) const
Definition: fem_context.C:426
libMesh::FEType
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:178
libMesh::FEFamily
FEFamily
Definition: enum_fe_family.h:34
libMesh::DiffContext::get_elem_jacobian
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
Definition: diff_context.h:283
libMesh::DirichletBoundary
This class allows one to associate Dirichlet boundary values with a given set of mesh boundary ids an...
Definition: dirichlet_boundaries.h:88
libMesh::FEMContext::get_side_fe
void get_side_fe(unsigned int var, FEGenericBase< OutputShape > *&fe) const
Accessor for edge/face (2D/3D) finite element object for variable var for the largest dimension in th...
Definition: fem_context.h:312
libMesh::FEGenericBase::get_phi
const std::vector< std::vector< OutputShape > > & get_phi() const
Definition: fe_base.h:206
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::out
OStreamProxy out
libMesh::ConstFunction
Function that returns a single value that never changes.
Definition: const_function.h:43
libMesh::FEMContext::interior_value
Number interior_value(unsigned int var, unsigned int qp) const
Definition: fem_context.C:371
libMesh::DenseVector< Number >
libMesh::FEInterface::shape
static Real shape(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const Point &p)
Definition: fe_interface.C:687
libMesh::FEMContext
This class provides all data required for a physics package (e.g.
Definition: fem_context.h:62