18 #include "libmesh/variational_smoother_system.h" 20 #include "libmesh/elem.h" 21 #include "libmesh/fe_base.h" 22 #include "libmesh/fe_interface.h" 23 #include "libmesh/fem_context.h" 24 #include "libmesh/mesh.h" 25 #include "libmesh/quadrature.h" 26 #include "libmesh/string_to_enum.h" 27 #include "libmesh/utility.h" 28 #include "libmesh/numeric_vector.h" 29 #include "libmesh/parallel_ghost_sync.h" 41 bool apply_heterogeneous_constraints,
42 bool apply_no_constraints)
48 for (
auto * node :
mesh.local_node_ptr_range())
52 const auto dof_id = node->dof_number(this->
number(), d, 0);
61 FEMSystem::assembly(get_residual, get_jacobian, apply_heterogeneous_constraints, apply_no_constraints);
67 const auto & elem_orders =
mesh.elem_default_orders();
68 libmesh_error_msg_if(elem_orders.size() != 1,
69 "The variational smoother cannot be used for mixed-order meshes!");
70 const auto fe_order = *elem_orders.begin();
82 for (
auto * node :
mesh.local_node_ptr_range())
86 const auto dof_id = node->dof_number(this->
number(), d, 0);
88 (*solution).set(dof_id, (*node)(d));
98 FEMContext & femcontext = cast_ref<FEMContext &>(*con);
103 Real elem_averaged_det_J_sum = 0.;
109 const auto & JxW = fe_map.get_JxW();
111 for (
const auto * elem :
mesh.active_local_element_ptr_range())
116 const auto elem_integrated_det_J = std::accumulate(JxW.begin(), JxW.end(), 0.);
117 const auto ref_elem_vol = elem->reference_elem()->volume();
118 elem_averaged_det_J_sum += elem_integrated_det_J / ref_elem_vol;
122 mesh.comm().sum(elem_averaged_det_J_sum);
124 _ref_vol = elem_averaged_det_J_sum /
mesh.n_active_elem();
131 FEMContext & c = cast_ref<FEMContext &>(context);
139 const std::set<unsigned char> & elem_dims =
142 for (
const auto &
dim : elem_dims)
145 my_fe->get_nothing();
147 auto & fe_map = my_fe->get_fe_map();
148 fe_map.get_dxyzdxi();
149 fe_map.get_dxyzdeta();
150 fe_map.get_dxyzdzeta();
154 my_fe->get_nothing();
164 FEMContext & c = cast_ref<FEMContext &>(context);
173 const auto & dxyzdxi = fe_map.get_dxyzdxi();
174 const auto & dxyzdeta = fe_map.get_dxyzdeta();
175 const auto & dxyzdzeta = fe_map.get_dxyzdzeta();
177 const auto & dphidxi_map = fe_map.get_dphidxi_map();
178 const auto & dphideta_map = fe_map.get_dphideta_map();
179 const auto & dphidzeta_map = fe_map.get_dphidzeta_map();
183 unsigned int x_var = 0, y_var = 1, z_var = 2;
194 std::reference_wrapper<DenseSubVector<Number>> F[3] =
201 std::reference_wrapper<DenseSubMatrix<Number>> K[3][3] =
239 dxyzdxi[qp](0), 0, 0,
247 dxyzdxi[qp](0), dxyzdeta[qp](0), 0,
248 dxyzdxi[qp](1), dxyzdeta[qp](1), 0,
262 libmesh_error_msg(
"Unsupported dimension.");
269 const Real det_sq = det * det;
270 const Real det_cube = det_sq * det;
282 const Real tr_div_dim = tr /
dim;
285 const Real half_dim = 0.5 *
dim;
286 const std::vector<Real> trace_powers{
288 std::pow(tr_div_dim, half_dim - 1.),
289 std::pow(tr_div_dim, half_dim - 2.),
306 const Real chi = 0.5 * (det + std::sqrt(epsilon_sq + det_sq));
307 const Real chi_sq = chi * chi;
308 const Real sqrt_term = std::sqrt(epsilon_sq + det_sq);
310 const Real chi_prime = 0.5 * (1. + det / sqrt_term);
311 const Real chi_prime_sq = chi_prime * chi_prime;
313 const Real chi_2prime = 0.5 * (1. / sqrt_term - det_sq /
std::pow(sqrt_term, 3));
317 const RealTensor dbeta_dS = (trace_powers[1] / chi) * S - (trace_powers[0] / chi_sq * chi_prime * det) * S_inv_T;
322 const Real alpha = (-chi_prime * det_cube + 2. * det_sq * chi - ref_vol_sq * det * chi_prime) / (2. *
_ref_vol * chi_sq);
330 std::vector<std::vector<std::vector<Real>>> dphi_maps = {dphidxi_map, dphideta_map, dphidzeta_map};
334 for (
const auto l : elem.node_index_range())
341 dS_dR(var_id, jj) = dphi_maps[jj][l][qp];
345 F[var_id](l) += quad_weights[qp] * dE_dS.
contract(dS_dR);
350 if (request_jacobian)
364 const std::vector<Real> d2beta_dS2_coefs = {
368 trace_powers[1] / chi,
370 ((
dim - 2.) /
dim) * trace_powers[2] / chi,
372 -(trace_powers[1] / chi_sq) * chi_prime * det,
377 -(trace_powers[1] / chi_sq) * chi_prime * det,
379 trace_powers[0] * (det / chi_sq)
380 * ((2. * chi_prime_sq / chi - chi_2prime) * det - chi_prime),
382 (trace_powers[0] / chi_sq) * chi_prime * det,
387 const Real dalpha_dS_coef = (det / (2. *
_ref_vol * chi_sq))
388 * (-4. *
_ref_vol * alpha * chi * chi_prime - chi_2prime * det_cube
389 - chi_prime * det_sq + 4 * chi * det - ref_vol_sq * (chi_prime + det * chi_2prime));
391 for (
const auto l: elem.node_index_range())
399 dS_dR_l(var_id1, ii) = dphi_maps[ii][l][qp];
401 for (
const auto p: elem.node_index_range())
409 dS_dR_p(var_id2, jj) = dphi_maps[jj][p][qp];
411 Real d2beta_dR2 = 0.;
423 const std::vector<Real> d2beta_dS2_tensor_contributions =
429 S_inv(b,a) * S_inv(j,i),
430 S_inv(j,a) * S_inv(b,i),
434 Real d2beta_dS2 = 0.;
435 for (
const auto comp_id :
index_range(d2beta_dS2_coefs))
437 const Real contribution = d2beta_dS2_coefs[comp_id] * d2beta_dS2_tensor_contributions[comp_id];
438 d2beta_dS2 += contribution;
442 const Real d2mu_dS2 = dalpha_dS_coef * S_inv(b,a) * S_inv(j,i) - alpha * S_inv(b,i) * S_inv(j,a);
445 d2beta_dR2 += d2beta_dS2 * dS_dR_l(a, b) * dS_dR_p(i, j);
446 d2mu_dR2 += d2mu_dS2 * dS_dR_l(a, b) * dS_dR_p(i, j);
463 return request_jacobian;
virtual std::unique_ptr< DiffContext > build_context() override
Builds a FEMContext object with enough information to do evaluations on each element.
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used...
const DenseMatrix< Number > & get_elem_jacobian() const
Const accessor for element Jacobian.
This class provides all data required for a physics package (e.g.
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...
virtual void pre_fe_reinit(const System &, const Elem *e)
Reinitializes local data vectors/matrices on the current geometric element.
const Elem & get_elem() const
Accessor for current Elem object.
virtual void init_context(DiffContext &) override
TypeTensor< T > transpose() const
This is the base class from which all geometric element types are derived.
virtual void assembly(bool get_residual, bool get_jacobian, bool apply_heterogeneous_constraints=false, bool apply_no_constraints=false) override
Assembly method to update the mesh based on the smoother solve.
const std::vector< Real > & get_weights() const
RealTensorValue RealTensor
The libMesh namespace provides an interface to certain functionality in the library.
const MeshBase & get_mesh() const
Real _dilation_weight
The relative weight to give the dilation metric. The distortion metric is given weight 1 - _dilation_...
unsigned char get_dim() const
Accessor for cached mesh dimension.
virtual void elem_fe_reinit(const std::vector< Point > *const pts=nullptr)
Reinitializes interior FE objects on the current geometric element.
unsigned int number() const
std::unique_ptr< NumericVector< Number > > solution
Data structure to hold solution values.
virtual void init_data() override
Initializes the member data fields associated with the system, so that, e.g., assemble() may be used...
This class provides all data required for a physics package (e.g.
unsigned int add_variable(std::string_view var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Adds the variable var to the list of variables for this system.
virtual bool element_time_derivative(bool request_jacobian, libMesh::DiffContext &context) override
Adds the time derivative contribution on elem to elem_residual.
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost dofobjects uniquely identified by their id.
CompareTypes< T, T2 >::supertype contract(const TypeTensor< T2 > &) const
Multiply 2 tensors together to return a scalar, i.e.
Real _ref_vol
The reference volume for each element.
void compute_element_reference_volume()
const DenseVector< Number > & get_elem_residual() const
Const accessor for element residual.
const Real _epsilon_squared
The small nonzero constant to prevent zero denominators (degenerate elements only) ...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
TypeTensor< T > inverse() const
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
virtual void init_context(libMesh::DiffContext &context) override
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...
virtual void assembly(bool get_residual, bool get_jacobian, bool apply_heterogeneous_constraints=false, bool apply_no_constraints=false) override
Prepares matrix or rhs for matrix assembly.
~VariationalSmootherSystem() override
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
This class forms the foundation from which generic finite elements may be derived.
const QBase & get_element_qrule() const
Accessor for element interior quadrature rule for the dimension of the current _elem.
const std::set< unsigned char > & elem_dimensions() const
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.