hp_coarsentest.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 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 // C++ includes
19 #include <limits> // for std::numeric_limits::max
20 #include <math.h> // for sqrt
21 
22 
23 // Local Includes
24 #include "libmesh/hp_coarsentest.h"
25 #include "libmesh/dense_matrix.h"
26 #include "libmesh/dense_vector.h"
27 #include "libmesh/dof_map.h"
28 #include "libmesh/fe_base.h"
29 #include "libmesh/fe_interface.h"
31 #include "libmesh/elem.h"
32 #include "libmesh/error_vector.h"
33 #include "libmesh/mesh_base.h"
35 #include "libmesh/quadrature.h"
36 #include "libmesh/system.h"
37 #include "libmesh/tensor_value.h"
38 
39 #ifdef LIBMESH_ENABLE_AMR
40 
41 namespace libMesh
42 {
43 
44 //-----------------------------------------------------------------
45 // HPCoarsenTest implementations
46 
48  const Elem * elem,
49  unsigned int var)
50 {
51  // If we have children, we need to add their projections instead
52  if (!elem->active())
53  {
54  libmesh_assert(!elem->subactive());
55  for (auto & child : elem->child_ref_range())
56  this->add_projection(system, &child, var);
57  return;
58  }
59 
60  // The DofMap for this system
61  const DofMap & dof_map = system.get_dof_map();
62 
63  // The type of finite element to use for this variable
64  const FEType & fe_type = dof_map.variable_type (var);
65 
66  const FEContinuity cont = fe->get_continuity();
67 
68  fe->reinit(elem);
69 
70  dof_map.dof_indices(elem, dof_indices, var);
71 
72  const unsigned int n_dofs =
73  cast_int<unsigned int>(dof_indices.size());
74 
76  fe_type, coarse, *xyz_values, coarse_qpoints);
77 
78  fe_coarse->reinit(coarse, &coarse_qpoints);
79 
80  const unsigned int n_coarse_dofs =
81  cast_int<unsigned int>(phi_coarse->size());
82 
83  if (Uc.size() == 0)
84  {
85  Ke.resize(n_coarse_dofs, n_coarse_dofs);
86  Ke.zero();
87  Fe.resize(n_coarse_dofs);
88  Fe.zero();
89  Uc.resize(n_coarse_dofs);
90  Uc.zero();
91  }
92  libmesh_assert_equal_to (Uc.size(), phi_coarse->size());
93 
94  // Loop over the quadrature points
95  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
96  {
97  // The solution value at the quadrature point
98  Number val = libMesh::zero;
99  Gradient grad;
100  Tensor hess;
101 
102  for (unsigned int i=0; i != n_dofs; i++)
103  {
104  dof_id_type dof_num = dof_indices[i];
105  val += (*phi)[i][qp] *
106  system.current_solution(dof_num);
107  if (cont == C_ZERO || cont == C_ONE)
108  grad.add_scaled((*dphi)[i][qp],system.current_solution(dof_num));
109  if (cont == C_ONE)
110  hess.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num));
111  }
112 
113  // The projection matrix and vector
114  for (unsigned int i=0; i != Fe.size(); ++i)
115  {
116  Fe(i) += (*JxW)[qp] *
117  (*phi_coarse)[i][qp]*val;
118  if (cont == C_ZERO || cont == C_ONE)
119  Fe(i) += (*JxW)[qp] *
120  (grad*(*dphi_coarse)[i][qp]);
121  if (cont == C_ONE)
122  Fe(i) += (*JxW)[qp] *
123  hess.contract((*d2phi_coarse)[i][qp]);
124 
125  for (unsigned int j=0; j != Fe.size(); ++j)
126  {
127  Ke(i,j) += (*JxW)[qp] *
128  (*phi_coarse)[i][qp]*(*phi_coarse)[j][qp];
129  if (cont == C_ZERO || cont == C_ONE)
130  Ke(i,j) += (*JxW)[qp] *
131  (*dphi_coarse)[i][qp]*(*dphi_coarse)[j][qp];
132  if (cont == C_ONE)
133  Ke(i,j) += (*JxW)[qp] *
134  ((*d2phi_coarse)[i][qp].contract((*d2phi_coarse)[j][qp]));
135  }
136  }
137  }
138 }
139 
141 {
142  LOG_SCOPE("select_refinement()", "HPCoarsenTest");
143 
144  // The current mesh
145  MeshBase & mesh = system.get_mesh();
146 
147  // The dimensionality of the mesh
148  const unsigned int dim = mesh.mesh_dimension();
149 
150  // The number of variables in the system
151  const unsigned int n_vars = system.n_vars();
152 
153  // The DofMap for this system
154  const DofMap & dof_map = system.get_dof_map();
155 
156  // The system number (for doing bad hackery)
157  const unsigned int sys_num = system.number();
158 
159  // Check for a valid component_scale
160  if (!component_scale.empty())
161  {
162  if (component_scale.size() != n_vars)
163  libmesh_error_msg("ERROR: component_scale is the wrong size:\n" \
164  << " component_scale.size()=" \
165  << component_scale.size() \
166  << "\n n_vars=" \
167  << n_vars);
168  }
169  else
170  {
171  // No specified scaling. Scale all variables by one.
172  component_scale.resize (n_vars, 1.0);
173  }
174 
175  // Resize the error_per_cell vectors to handle
176  // the number of elements, initialize them to 0.
177  std::vector<ErrorVectorReal> h_error_per_cell(mesh.max_elem_id(), 0.);
178  std::vector<ErrorVectorReal> p_error_per_cell(mesh.max_elem_id(), 0.);
179 
180  // Loop over all the variables in the system
181  for (unsigned int var=0; var<n_vars; var++)
182  {
183  // Possibly skip this variable
184  if (!component_scale.empty())
185  if (component_scale[var] == 0.0) continue;
186 
187  // The type of finite element to use for this variable
188  const FEType & fe_type = dof_map.variable_type (var);
189 
190  // Finite element objects for a fine (and probably a coarse)
191  // element will be needed
192  fe = FEBase::build (dim, fe_type);
193  fe_coarse = FEBase::build (dim, fe_type);
194 
195  // Any cached coarse element results have expired
196  coarse = nullptr;
197  unsigned int cached_coarse_p_level = 0;
198 
199  const FEContinuity cont = fe->get_continuity();
200  libmesh_assert (cont == DISCONTINUOUS || cont == C_ZERO ||
201  cont == C_ONE);
202 
203  // Build an appropriate quadrature rule
204  qrule = fe_type.default_quadrature_rule(dim);
205 
206  // Tell the refined finite element about the quadrature
207  // rule. The coarse finite element need not know about it
208  fe->attach_quadrature_rule (qrule.get());
209 
210  // We will always do the integration
211  // on the fine elements. Get their Jacobian values, etc..
212  JxW = &(fe->get_JxW());
213  xyz_values = &(fe->get_xyz());
214 
215  // The shape functions
216  phi = &(fe->get_phi());
217  phi_coarse = &(fe_coarse->get_phi());
218 
219  // The shape function derivatives
220  if (cont == C_ZERO || cont == C_ONE)
221  {
222  dphi = &(fe->get_dphi());
223  dphi_coarse = &(fe_coarse->get_dphi());
224  }
225 
226  // The shape function second derivatives
227  if (cont == C_ONE)
228  {
229 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
230  d2phi = &(fe->get_d2phi());
231  d2phi_coarse = &(fe_coarse->get_d2phi());
232 #else
233  libmesh_error_msg("Minimization of H2 error without second derivatives is not possible.");
234 #endif
235  }
236 
237  // Iterate over all the active elements in the mesh
238  // that live on this processor.
239  for (const auto & elem : mesh.active_local_element_ptr_range())
240  {
241  // We're only checking elements that are already flagged for h
242  // refinement
243  if (elem->refinement_flag() != Elem::REFINE)
244  continue;
245 
246  const dof_id_type e_id = elem->id();
247 
248  // Find the projection onto the parent element,
249  // if necessary
250  if (elem->parent() &&
251  (coarse != elem->parent() ||
252  cached_coarse_p_level != elem->p_level()))
253  {
254  Uc.resize(0);
255 
256  coarse = elem->parent();
257  cached_coarse_p_level = elem->p_level();
258 
259  unsigned int old_parent_level = coarse->p_level();
260  (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level());
261 
262  this->add_projection(system, coarse, var);
263 
264  (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level);
265 
266  // Solve the h-coarsening projection problem
268  }
269 
270  fe->reinit(elem);
271 
272  // Get the DOF indices for the fine element
273  dof_map.dof_indices (elem, dof_indices, var);
274 
275  // The number of quadrature points
276  const unsigned int n_qp = qrule->n_points();
277 
278  // The number of DOFS on the fine element
279  const unsigned int n_dofs =
280  cast_int<unsigned int>(dof_indices.size());
281 
282  // The number of nodes on the fine element
283  const unsigned int n_nodes = elem->n_nodes();
284 
285  // The average element value (used as an ugly hack
286  // when we have nothing p-coarsened to compare to)
287  // Real average_val = 0.;
288  Number average_val = 0.;
289 
290  // Calculate this variable's contribution to the p
291  // refinement error
292 
293  if (elem->p_level() == 0)
294  {
295  unsigned int n_vertices = 0;
296  for (unsigned int n = 0; n != n_nodes; ++n)
297  if (elem->is_vertex(n))
298  {
299  n_vertices++;
300  const Node & node = elem->node_ref(n);
301  average_val += system.current_solution
302  (node.dof_number(sys_num,var,0));
303  }
304  average_val /= n_vertices;
305  }
306  else
307  {
308  unsigned int old_elem_level = elem->p_level();
309  (const_cast<Elem *>(elem))->hack_p_level(old_elem_level - 1);
310 
311  fe_coarse->reinit(elem, &(qrule->get_points()));
312 
313  const unsigned int n_coarse_dofs =
314  cast_int<unsigned int>(phi_coarse->size());
315 
316  (const_cast<Elem *>(elem))->hack_p_level(old_elem_level);
317 
318  Ke.resize(n_coarse_dofs, n_coarse_dofs);
319  Ke.zero();
320  Fe.resize(n_coarse_dofs);
321  Fe.zero();
322 
323  // Loop over the quadrature points
324  for (unsigned int qp=0; qp<qrule->n_points(); qp++)
325  {
326  // The solution value at the quadrature point
327  Number val = libMesh::zero;
328  Gradient grad;
329  Tensor hess;
330 
331  for (unsigned int i=0; i != n_dofs; i++)
332  {
333  dof_id_type dof_num = dof_indices[i];
334  val += (*phi)[i][qp] *
335  system.current_solution(dof_num);
336  if (cont == C_ZERO || cont == C_ONE)
337  grad.add_scaled((*dphi)[i][qp], system.current_solution(dof_num));
338  if (cont == C_ONE)
339  hess.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num));
340  }
341 
342  // The projection matrix and vector
343  for (unsigned int i=0; i != Fe.size(); ++i)
344  {
345  Fe(i) += (*JxW)[qp] *
346  (*phi_coarse)[i][qp]*val;
347  if (cont == C_ZERO || cont == C_ONE)
348  Fe(i) += (*JxW)[qp] *
349  grad * (*dphi_coarse)[i][qp];
350  if (cont == C_ONE)
351  Fe(i) += (*JxW)[qp] *
352  hess.contract((*d2phi_coarse)[i][qp]);
353 
354  for (unsigned int j=0; j != Fe.size(); ++j)
355  {
356  Ke(i,j) += (*JxW)[qp] *
357  (*phi_coarse)[i][qp]*(*phi_coarse)[j][qp];
358  if (cont == C_ZERO || cont == C_ONE)
359  Ke(i,j) += (*JxW)[qp] *
360  (*dphi_coarse)[i][qp]*(*dphi_coarse)[j][qp];
361  if (cont == C_ONE)
362  Ke(i,j) += (*JxW)[qp] *
363  ((*d2phi_coarse)[i][qp].contract((*d2phi_coarse)[j][qp]));
364  }
365  }
366  }
367 
368  // Solve the p-coarsening projection problem
370  }
371 
372  // loop over the integration points on the fine element
373  for (unsigned int qp=0; qp<n_qp; qp++)
374  {
375  Number value_error = 0.;
376  Gradient grad_error;
377  Tensor hessian_error;
378  for (unsigned int i=0; i<n_dofs; i++)
379  {
380  const dof_id_type dof_num = dof_indices[i];
381  value_error += (*phi)[i][qp] *
382  system.current_solution(dof_num);
383  if (cont == C_ZERO || cont == C_ONE)
384  grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num));
385  if (cont == C_ONE)
386  hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num));
387  }
388  if (elem->p_level() == 0)
389  {
390  value_error -= average_val;
391  }
392  else
393  {
394  for (unsigned int i=0; i<Up.size(); i++)
395  {
396  value_error -= (*phi_coarse)[i][qp] * Up(i);
397  if (cont == C_ZERO || cont == C_ONE)
398  grad_error.subtract_scaled((*dphi_coarse)[i][qp], Up(i));
399  if (cont == C_ONE)
400  hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Up(i));
401  }
402  }
403 
404  p_error_per_cell[e_id] += static_cast<ErrorVectorReal>
405  (component_scale[var] *
406  (*JxW)[qp] * TensorTools::norm_sq(value_error));
407  if (cont == C_ZERO || cont == C_ONE)
408  p_error_per_cell[e_id] += static_cast<ErrorVectorReal>
409  (component_scale[var] *
410  (*JxW)[qp] * grad_error.norm_sq());
411  if (cont == C_ONE)
412  p_error_per_cell[e_id] += static_cast<ErrorVectorReal>
413  (component_scale[var] *
414  (*JxW)[qp] * hessian_error.norm_sq());
415  }
416 
417  // Calculate this variable's contribution to the h
418  // refinement error
419 
420  if (!elem->parent())
421  {
422  // For now, we'll always start with an h refinement
423  h_error_per_cell[e_id] =
425  }
426  else
427  {
428  FEInterface::inverse_map (dim, fe_type, coarse,
430 
431  unsigned int old_parent_level = coarse->p_level();
432  (const_cast<Elem *>(coarse))->hack_p_level(elem->p_level());
433 
434  fe_coarse->reinit(coarse, &coarse_qpoints);
435 
436  (const_cast<Elem *>(coarse))->hack_p_level(old_parent_level);
437 
438  // The number of DOFS on the coarse element
439  unsigned int n_coarse_dofs =
440  cast_int<unsigned int>(phi_coarse->size());
441 
442  // Loop over the quadrature points
443  for (unsigned int qp=0; qp<n_qp; qp++)
444  {
445  // The solution difference at the quadrature point
446  Number value_error = libMesh::zero;
447  Gradient grad_error;
448  Tensor hessian_error;
449 
450  for (unsigned int i=0; i != n_dofs; ++i)
451  {
452  const dof_id_type dof_num = dof_indices[i];
453  value_error += (*phi)[i][qp] *
454  system.current_solution(dof_num);
455  if (cont == C_ZERO || cont == C_ONE)
456  grad_error.add_scaled((*dphi)[i][qp], system.current_solution(dof_num));
457  if (cont == C_ONE)
458  hessian_error.add_scaled((*d2phi)[i][qp], system.current_solution(dof_num));
459  }
460 
461  for (unsigned int i=0; i != n_coarse_dofs; ++i)
462  {
463  value_error -= (*phi_coarse)[i][qp] * Uc(i);
464  if (cont == C_ZERO || cont == C_ONE)
465  grad_error.subtract_scaled((*dphi_coarse)[i][qp], Uc(i));
466  if (cont == C_ONE)
467  hessian_error.subtract_scaled((*d2phi_coarse)[i][qp], Uc(i));
468  }
469 
470  h_error_per_cell[e_id] += static_cast<ErrorVectorReal>
471  (component_scale[var] *
472  (*JxW)[qp] * TensorTools::norm_sq(value_error));
473  if (cont == C_ZERO || cont == C_ONE)
474  h_error_per_cell[e_id] += static_cast<ErrorVectorReal>
475  (component_scale[var] *
476  (*JxW)[qp] * grad_error.norm_sq());
477  if (cont == C_ONE)
478  h_error_per_cell[e_id] += static_cast<ErrorVectorReal>
479  (component_scale[var] *
480  (*JxW)[qp] * hessian_error.norm_sq());
481  }
482 
483  }
484  }
485  }
486 
487  // Now that we've got our approximations for p_error and h_error, let's see
488  // if we want to switch any h refinement flags to p refinement
489 
490  // Iterate over all the active elements in the mesh
491  // that live on this processor.
492  for (auto & elem : mesh.active_local_element_ptr_range())
493  {
494  // We're only checking elements that are already flagged for h
495  // refinement
496  if (elem->refinement_flag() != Elem::REFINE)
497  continue;
498 
499  const dof_id_type e_id = elem->id();
500 
501  unsigned int dofs_per_elem = 0, dofs_per_p_elem = 0;
502 
503  // Loop over all the variables in the system
504  for (unsigned int var=0; var<n_vars; var++)
505  {
506  // The type of finite element to use for this variable
507  const FEType & fe_type = dof_map.variable_type (var);
508 
509  // FIXME: we're overestimating the number of DOFs added by h
510  // refinement
511  FEType elem_fe_type = fe_type;
512  elem_fe_type.order =
513  static_cast<Order>(fe_type.order + elem->p_level());
514  dofs_per_elem +=
515  FEInterface::n_dofs(dim, elem_fe_type, elem->type());
516 
517  elem_fe_type.order =
518  static_cast<Order>(fe_type.order + elem->p_level() + 1);
519  dofs_per_p_elem +=
520  FEInterface::n_dofs(dim, elem_fe_type, elem->type());
521  }
522 
523  const unsigned int new_h_dofs = dofs_per_elem *
524  (elem->n_children() - 1);
525 
526  const unsigned int new_p_dofs = dofs_per_p_elem -
527  dofs_per_elem;
528 
529  /*
530  libMesh::err << "Cell " << e_id << ": h = " << elem->hmax()
531  << ", p = " << elem->p_level() + 1 << "," << std::endl
532  << " h_error = " << h_error_per_cell[e_id]
533  << ", p_error = " << p_error_per_cell[e_id] << std::endl
534  << " new_h_dofs = " << new_h_dofs
535  << ", new_p_dofs = " << new_p_dofs << std::endl;
536  */
537  const Real p_value =
538  std::sqrt(p_error_per_cell[e_id]) * p_weight / new_p_dofs;
539  const Real h_value =
540  std::sqrt(h_error_per_cell[e_id]) /
541  static_cast<Real>(new_h_dofs);
542  if (p_value > h_value)
543  {
544  elem->set_p_refinement_flag(Elem::REFINE);
545  elem->set_refinement_flag(Elem::DO_NOTHING);
546  }
547  }
548 
549  // libMesh::MeshRefinement will now assume that users have set
550  // refinement flags consistently on all processors, but all we've
551  // done so far is set refinement flags on local elements. Let's
552  // make sure that flags on geometrically ghosted elements are all
553  // set to whatever their owners decided.
555 }
556 
557 } // namespace libMesh
558 
559 #endif // #ifdef LIBMESH_ENABLE_AMR
Manages the family, order, etc. parameters for a given FE.
Definition: fe_type.h:179
virtual unsigned int size() const override
Definition: dense_vector.h:92
dof_id_type dof_number(const unsigned int s, const unsigned int var, const unsigned int comp) const
Definition: dof_object.h:833
const std::vector< std::vector< Real > > * phi
const Elem * parent() const
Definition: elem.h:2479
std::vector< float > component_scale
Definition: hp_selector.h:82
void add_projection(const System &, const Elem *, unsigned int var)
A geometric point in (x,y,z) space associated with a DOF.
Definition: node.h:52
static unsigned int n_dofs(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:454
DenseVector< Number > Fe
virtual void select_refinement(System &system) override
void dof_indices(const Elem *const elem, std::vector< dof_id_type > &di) const
Definition: dof_map.C:1930
void add_scaled(const TypeTensor< T2 > &, const T)
Definition: type_tensor.h:808
void add_scaled(const TypeVector< T2 > &, const T)
Definition: type_vector.h:627
std::unique_ptr< FEBase > fe_coarse
const std::vector< std::vector< Real > > * phi_coarse
void resize(const unsigned int n)
Definition: dense_vector.h:355
const FEType & variable_type(const unsigned int c) const
Definition: dof_map.h:1792
The base class for all geometric element types.
Definition: elem.h:100
MeshBase & mesh
const std::vector< std::vector< RealGradient > > * dphi_coarse
unsigned int p_level() const
Definition: elem.h:2555
OrderWrapper order
Definition: fe_type.h:198
const unsigned int n_vars
Definition: tecplot_io.C:69
const Number zero
Definition: libmesh.h:239
const std::vector< Point > * xyz_values
long double max(long double a, double b)
const MeshBase & get_mesh() const
Definition: system.h:2033
DIE A HORRIBLE DEATH HERE typedef float ErrorVectorReal
DenseVector< Number > Uc
Base class for Mesh.
Definition: mesh_base.h:77
SimpleRange< ChildRefIter > child_ref_range()
Definition: elem.h:1779
Number current_solution(const dof_id_type global_dof_number) const
Definition: system.C:194
const std::vector< Real > * JxW
Manages the degrees of freedom (DOFs) in a simulation.
Definition: dof_map.h:176
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition: fe_type.C:31
const dof_id_type n_nodes
Definition: tecplot_io.C:68
unsigned int number() const
Definition: system.h:2025
Responsible for mesh refinement algorithms and data.
Manages consistently variables, degrees of freedom, and coefficient vectors.
Definition: system.h:92
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
static Point inverse_map(const unsigned int dim, const FEType &fe_t, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: fe_interface.C:590
DenseVector< Number > Up
CompareTypes< T, T2 >::supertype contract(const TypeTensor< T2 > &) const
Definition: type_tensor.h:1204
void subtract_scaled(const TypeVector< T2 > &, const T)
Definition: type_vector.h:701
Real norm_sq() const
Definition: type_vector.h:943
std::unique_ptr< FEBase > fe
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual void zero() override
Definition: dense_matrix.h:808
bool subactive() const
Definition: elem.h:2408
void resize(const unsigned int new_m, const unsigned int new_n)
Definition: dense_matrix.h:792
unsigned int mesh_dimension() const
Definition: mesh_base.C:126
const std::vector< std::vector< RealTensor > > * d2phi_coarse
const std::vector< std::vector< RealTensor > > * d2phi
void cholesky_solve(const DenseVector< T2 > &b, DenseVector< T2 > &x)
const std::vector< std::vector< RealGradient > > * dphi
unsigned int n_vars() const
Definition: system.h:2105
std::vector< dof_id_type > dof_indices
std::vector< Point > coarse_qpoints
bool active() const
Definition: elem.h:2390
const DofMap & get_dof_map() const
Definition: system.h:2049
std::unique_ptr< QBase > qrule
Real norm_sq() const
Definition: type_tensor.h:1299
void subtract_scaled(const TypeTensor< T2 > &, const T)
Definition: type_tensor.h:878
virtual void zero() override
Definition: dense_vector.h:379
uint8_t dof_id_type
Definition: id_types.h:64
DenseMatrix< Number > Ke