57 _dim = _current_elem->dim();
59 const unsigned int n_nodes = _current_elem->n_nodes();
67 std::unique_ptr<FEBaseType> fe(FEBaseType::build(_dim, _fe_type));
70 std::unique_ptr<QBase> qrule(_fe_type.default_quadrature_rule(_dim));
71 std::unique_ptr<QBase> qedgerule(_fe_type.default_quadrature_rule(1));
72 std::unique_ptr<QBase> qsiderule(_fe_type.default_quadrature_rule(_dim - 1));
75 _phi = &fe->get_phi();
80 _cont = fe->get_continuity();
84 const std::vector<std::vector<GradientShapeType>> & ref_dphi = fe->get_dphi();
89 _JxW = &fe->get_JxW();
91 _xyz_values = &fe->get_xyz();
97 const unsigned int n_dofs = _dof_indices.size() / _var.count();
98 mooseAssert(_dof_indices.size() % _var.count() == 0,
99 "The number of degrees of freedom should be cleanly divisible by the variable count");
105 _dof_is_fixed.clear();
106 _dof_is_fixed.resize(n_dofs,
false);
108 _free_dof.resize(n_dofs, 0);
114 DenseVector<char> mask(n_dofs,
true);
126 auto & dof_map = _var.dofMap();
127 const bool add_p_level =
128 dof_map.should_p_refine(dof_map.var_group_from_var_number(_var.number()));
130 for (_n = 0; _n !=
n_nodes; ++_n)
132 _nc = FEInterface::n_dofs_at_node(_fe_type, _current_elem, _n, add_p_level);
136 auto curr_node = _current_elem->node_ptr(_n);
137 const auto & block_ids = _sys.mesh().getNodeBlockIds(*curr_node);
139 auto priority_block = *(block_ids.begin());
140 for (
auto id : block_ids)
141 if (_var.hasBlocks(
id))
147 if (!hasBlocks(priority_block) && _var.isNodal())
149 for (
decltype(_nc) i = 0; i < _nc; ++i)
151 mask(_current_dof) =
false;
157 if (!_current_elem->is_vertex(_n))
163 if (_cont == DISCONTINUOUS || _cont == H_CURL || _cont == H_DIV)
164 libmesh_assert(_nc == 0);
165 else if (_cont == C_ZERO)
167 else if (_fe_type.family == HERMITE)
168 setHermiteVertices();
169 else if (_cont == C_ONE)
170 setOtherCOneVertices();
171 else if (_cont == SIDE_DISCONTINUOUS)
178 _current_node =
nullptr;
181 if (_dim > 2 && _cont != DISCONTINUOUS)
182 for (
unsigned int e = 0; e != _current_elem->n_edges(); ++e)
184 FEInterface::dofs_on_edge(_current_elem, _dim, _fe_type, e, _side_dofs, add_p_level);
189 for (
unsigned int i = 0; i != _side_dofs.size(); ++i)
190 if (!_dof_is_fixed[_side_dofs[i]])
191 _free_dof[_free_dofs++] = i;
198 fe->attach_quadrature_rule(qedgerule.get());
199 fe->edge_reinit(_current_elem, e);
200 _n_qp = qedgerule->n_points();
202 choleskySolve(
false);
206 if (_dim > 1 && _cont != DISCONTINUOUS)
207 for (
unsigned int s = 0; s != _current_elem->n_sides(); ++s)
209 FEInterface::dofs_on_side(_current_elem, _dim, _fe_type, s, _side_dofs, add_p_level);
214 for (
unsigned int i = 0; i != _side_dofs.size(); ++i)
215 if (!_dof_is_fixed[_side_dofs[i]])
216 _free_dof[_free_dofs++] = i;
223 fe->attach_quadrature_rule(qsiderule.get());
224 fe->reinit(_current_elem, s);
225 _n_qp = qsiderule->n_points();
227 choleskySolve(
false);
235 for (
unsigned int i = 0; i != n_dofs; ++i)
236 if (!_dof_is_fixed[i])
237 _free_dof[_free_dofs++] = i;
243 fe->attach_quadrature_rule(qrule.get());
244 fe->reinit(_current_elem);
245 _n_qp = qrule->n_points();
251 for (
unsigned int i = 0; i != n_dofs; ++i)
252 libmesh_assert(_dof_is_fixed[i]);
254 for (
size_t i = 0; i < mask.size(); i++)
256 _var.setDofValue(_Ue(i), i);
315 _current_node = _current_elem->node_ptr(_n);
316 _Ue(_current_dof) = value(*_current_node);
317 _dof_is_fixed[_current_dof] =
true;
321 _Ue(_current_dof) = gradientComponent(grad, 0);
322 _dof_is_fixed[_current_dof] =
true;
327 Point nxminus = _current_elem->point(_n), nxplus = _current_elem->point(_n);
328 nxminus(0) -= TOLERANCE;
329 nxplus(0) += TOLERANCE;
333 _Ue(_current_dof) = gradientComponent(grad, 1);
334 _dof_is_fixed[_current_dof] =
true;
338 (gradientComponent(gxplus, 1) - gradientComponent(gxminus, 1)) / 2. / TOLERANCE;
339 _dof_is_fixed[_current_dof] =
true;
345 _Ue(_current_dof) = gradientComponent(grad, 2);
346 _dof_is_fixed[_current_dof] =
true;
350 (gradientComponent(gxplus, 2) - gradientComponent(gxminus, 2)) / 2. / TOLERANCE;
351 _dof_is_fixed[_current_dof] =
true;
354 Point nyminus = _current_elem->point(_n), nyplus = _current_elem->point(_n);
355 nyminus(1) -= TOLERANCE;
356 nyplus(1) += TOLERANCE;
361 (gradientComponent(gyplus, 2) - gradientComponent(gyminus, 2)) / 2. / TOLERANCE;
362 _dof_is_fixed[_current_dof] =
true;
365 Point nxmym = _current_elem->point(_n), nxmyp = _current_elem->point(_n),
366 nxpym = _current_elem->point(_n), nxpyp = _current_elem->point(_n);
367 nxmym(0) -= TOLERANCE;
368 nxmym(1) -= TOLERANCE;
369 nxmyp(0) -= TOLERANCE;
370 nxmyp(1) += TOLERANCE;
371 nxpym(0) += TOLERANCE;
372 nxpym(1) -= TOLERANCE;
373 nxpyp(0) += TOLERANCE;
374 nxpyp(1) += TOLERANCE;
380 (gradientComponent(gxpyp, 2) - gradientComponent(gxmyp, 2)) / 2. / TOLERANCE;
382 (gradientComponent(gxpym, 2) - gradientComponent(gxmym, 2)) / 2. / TOLERANCE;
384 _Ue(_current_dof) = (gxzplus - gxzminus) / 2. / TOLERANCE;
385 _dof_is_fixed[_current_dof] =
true;
429 for (_qp = 0; _qp < _n_qp; _qp++)
432 auto fineval = value((*_xyz_values)[_qp]);
436 finegrad = gradient((*_xyz_values)[_qp]);
438 auto dofs_size = is_volume ? (_dof_indices.size() / _var.count()) : _side_dofs.size();
441 for (
decltype(dofs_size) geomi = 0, freei = 0; geomi != dofs_size; ++geomi)
443 auto i = is_volume ? geomi : _side_dofs[geomi];
446 if (_dof_is_fixed[i])
448 for (
decltype(dofs_size) geomj = 0, freej = 0; geomj != dofs_size; ++geomj)
450 auto j = is_volume ? geomj : _side_dofs[geomj];
451 if (_dof_is_fixed[j])
452 _Fe(freei) -= (*_phi)[i][_qp] * (*_phi)[j][_qp] * (*_JxW)[_qp] * _Ue(j);
454 _Ke(freei, freej) += (*_phi)[i][_qp] * (*_phi)[j][_qp] * (*_JxW)[_qp];
457 if (_dof_is_fixed[j])
458 _Fe(freei) -= dotHelper((*_dphi)[i][_qp], (*_dphi)[j][_qp]) * (*_JxW)[_qp] * _Ue(j);
460 _Ke(freei, freej) += dotHelper((*_dphi)[i][_qp], (*_dphi)[j][_qp]) * (*_JxW)[_qp];
462 if (!_dof_is_fixed[j])
465 _Fe(freei) += (*_phi)[i][_qp] * fineval * (*_JxW)[_qp];
467 _Fe(freei) += dotHelper(finegrad, (*_dphi)[i][_qp]) * (*_JxW)[_qp];
504 _Ke.resize(_free_dofs, _free_dofs);
506 _Fe.resize(_free_dofs);
507 for (
unsigned int i = 0; i < _free_dofs; ++i)
508 _Fe(i).setZero(_var.count());
510 choleskyAssembly(is_volume);
513 DenseVector<DataType> U = _Fe;
515 for (
unsigned int i = 0; i < _var.count(); ++i)
517 DenseVector<Real> v(_free_dofs), x(_free_dofs);
518 for (
unsigned int j = 0; j < _free_dofs; ++j)
521 _Ke.cholesky_solve(v, x);
523 for (
unsigned int j = 0; j < _free_dofs; ++j)
528 for (
unsigned int i = 0; i != _free_dofs; ++i)
530 auto the_dof = is_volume ? _free_dof[i] : _side_dofs[_free_dof[i]];
532 libmesh_assert(ui.matrix().norm() < TOLERANCE || (ui - U(i)).matrix().norm() < TOLERANCE);
534 _dof_is_fixed[the_dof] =
true;