7#include <wmtk/ExecutionScheduler.hpp>
8#include <wmtk/utils/TriQualityUtils.hpp>
9#include <wmtk/utils/TetraQualityUtils.hpp>
10#include <wmtk/utils/TupleUtils.hpp>
11#include <wmtk/utils/AMIPS.h>
12#include <wmtk/utils/AMIPS2D.h>
16 template <
class WMTKMesh>
24 std::array<double, NDOF> T;
25 for (
auto i = 0; i < WildRemesher<WMTKMesh>::VERTICES_PER_ELEMENT; i++)
26 for (
auto j = 0; j < WildRemesher<WMTKMesh>::DIM; j++)
32 if constexpr (std::is_same_v<wmtk::TriMesh, WMTKMesh>)
33 energy = wmtk::AMIPS2D_energy(T);
35 energy = wmtk::AMIPS_energy(T);
38 if (!std::isfinite(energy))
39 return std::numeric_limits<double>::max();
44 template <
class WMTKMesh>
52 const std::vector<basis::ElementBases> from_bases =
54 const std::vector<basis::ElementBases> to_bases =
57 const Eigen::MatrixXd &from_projection_quantities = old_local_mesh.projection_quantities();
58 const Eigen::MatrixXd &to_projection_quantities = new_local_mesh.projection_quantities();
61 Eigen::SparseMatrix<double> M, A;
68 m.
is_volume(), new_local_mesh.num_vertices(),
69 to_bases, to_bases,
cache, 0, M,
true);
70 assert(M.rows() == new_local_mesh.num_vertices() * m.
dim());
74 old_local_mesh.num_vertices(), from_bases, from_bases,
75 new_local_mesh.num_vertices(), to_bases, to_bases,
77 assert(A.rows() == new_local_mesh.num_vertices() * m.
dim());
78 assert(A.cols() == old_local_mesh.num_vertices() * m.
dim());
84 ipc::CollisionMesh collision_mesh;
98 std::vector<int> boundary_nodes;
99 for (
int d = 0; d < m.
dim(); ++d)
102 for (
const int fv : new_local_mesh.fixed_vertices())
103 boundary_nodes.push_back(fv * m.dim() + d);
105 for (
const int fv : new_local_mesh.boundary_facets().reshaped())
106 boundary_nodes.push_back(fv * m.dim() + d);
108 std::sort(boundary_nodes.begin(), boundary_nodes.end());
109 auto new_end = std::unique(boundary_nodes.begin(), boundary_nodes.end());
110 boundary_nodes.erase(new_end, boundary_nodes.end());
114 Eigen::MatrixXd projected_quantities = to_projection_quantities;
115 const int n_constrained_quantaties = projected_quantities.cols() / 3;
116 const int n_unconstrained_quantaties = projected_quantities.cols() - n_constrained_quantaties;
119 for (
int i = 0; i < n_constrained_quantaties; ++i)
121 const auto level_before =
logger().level();
122 logger().set_level(spdlog::level::warn);
126 M, A, from_projection_quantities.col(i),
128 new_local_mesh.rest_positions(), new_local_mesh.elements(), m.
dim(),
130 collision_mesh, m.
state.
args[
"contact"][
"dhat"],
134 m.
state.
args[
"contact"][
"use_convergent_formulation"],
135 m.
state.
args[
"solver"][
"contact"][
"CCD"][
"broad_phase"],
136 m.
state.
args[
"solver"][
"contact"][
"CCD"][
"tolerance"],
137 m.
state.
args[
"solver"][
"contact"][
"CCD"][
"max_iterations"],
139 boundary_nodes, 0, to_projection_quantities.col(i),
141 to_projection_quantities.col(i));
142 logger().set_level(level_before);
147 M, A, from_projection_quantities.rightCols(n_unconstrained_quantaties),
148 boundary_nodes, projected_quantities.rightCols(n_unconstrained_quantaties));
152 assert(projected_quantities.rows() == m.
dim() * new_local_mesh.num_vertices());
153 for (
int i = 0; i < new_local_mesh.num_vertices(); i++)
155 m.
vertex_attrs[new_local_mesh.local_to_global()[i]].projection_quantities =
156 projected_quantities.middleRows(m.
dim() * i, m.
dim());
162 template <
class WMTKMesh>
165 if (!WMTKMesh::smooth_before(v))
167 return !vertex_attrs[v.vid(*
this)].fixed;
170 template <
class WMTKMesh>
173 if (!Super::smooth_before(v))
176 if (this->op_cache ==
nullptr)
178 if constexpr (std::is_same_v<WMTKMesh, wmtk::TriMesh>)
179 this->op_cache = std::make_shared<TriOperationCache>();
181 this->op_cache = std::make_shared<TetOperationCache>();
184 this->op_cache->local_energy = local_mesh_energy(
185 vertex_attrs[v.vid(*
this)].rest_position);
192 template <
class WMTKMesh>
195 if (!WMTKMesh::smooth_before(v))
198 const size_t vid = v.vid(*
this);
200 const std::vector<Tuple> one_ring = this->get_one_ring_elements_for_vertex(v);
201 assert(one_ring.size() > 0);
208 double max_quality = 0;
209 for (
const Tuple &t : get_one_ring_elements_for_vertex(v))
210 max_quality = std::max(max_quality,
get_quality(*
this, t));
211 assert(max_quality > 0);
214 constexpr int NDOF = DIM * VERTICES_PER_ELEMENT;
215 std::vector<std::array<double, NDOF>> assembles(one_ring.size());
219 for (
int i = 0; i < one_ring.size(); i++)
221 const Tuple &t = one_ring[i];
222 auto t_id = t.fid(*
this);
224 assert(!is_inverted(t));
225 const auto local_verts = orient_preserve_element_reorder(element_vids(t), vid);
227 for (
auto j = 0; j < VERTICES_PER_ELEMENT; j++)
228 for (
auto d = 0; d < DIM; d++)
229 assembles[i][j * DIM + d] = vertex_attrs[local_verts[j]].rest_position[d];
234 const VectorNd old_rest_position = vertex_attrs[vid].rest_position;
237 const auto log_lvl = wmtk::logger().level();
238 wmtk::logger().set_level(spdlog::level::warn);
239 if constexpr (DIM == 2)
240 vertex_attrs[vid].rest_position = wmtk::newton_method_from_stack_2d(
241 assembles, wmtk::AMIPS2D_energy, wmtk::AMIPS2D_jacobian, wmtk::AMIPS2D_hessian);
243 vertex_attrs[vid].rest_position = wmtk::newton_method_from_stack(
244 assembles, wmtk::AMIPS_energy, wmtk::AMIPS_jacobian, wmtk::AMIPS_hessian);
245 wmtk::logger().set_level(log_lvl);
248 if (std::any_of(one_ring.begin(), one_ring.end(), [
this](
const Tuple &t) {
249 return this->is_rest_inverted(t);
260 vertex_attrs[vid].projection_quantities.leftCols(n_quantities() / 3) +=
261 old_rest_position - vertex_attrs[vid].rest_position;
268 if (std::any_of(one_ring.begin(), one_ring.end(), [
this](
const Tuple &t) {
269 return this->is_inverted(t);
279 template <
class WMTKMesh>
282 utils::Timer timer(this->timings[
"Smooth vertex after"]);
284 if (!Super::smooth_after(v))
292 const std::vector<Tuple> one_ring = this->get_one_ring_elements_for_vertex(v);
293 return local_relaxation(one_ring, args[
"smooth"][
"acceptance_tolerance"]);
296 template <
class WMTKMesh>
300 double max_quality = 0;
302 max_quality = std::max(max_quality,
get_quality(m, t));
303 assert(max_quality > 0);
306 executor.should_renew = [](
auto) {
return true; };
307 executor.renew_neighbor_tuples = [](
auto &,
auto,
auto &) ->
Operations {
return {}; };
309 const int max_iters = args[
"smooth"][
"max_iters"];
310 for (
int i = 0; i < max_iters; i++)
313 for (
auto &v : WMTKMesh::get_vertices())
314 smooths.emplace_back(
"vertex_smooth", v);
315 executor(*
this, smooths);
316 if (executor.cnt_success() == 0)
std::unique_ptr< MatrixCache > cache
#define POLYFEM_REMESHER_SCOPED_TIMER(name)
std::string formulation() const
return the formulation (checks if the problem is scalar or not and deals with multiphysics)
std::shared_ptr< polysolve::nonlinear::Solver > make_nl_solver(bool for_al) const
factory to create the nl solver depending on input
json args
main input arguments containing all defaults
solver::SolveData solve_data
timedependent stuff cached
Caches basis evaluation and geometric mapping at every element.
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, 9, 1 > assemble(const LinearAssemblerData &data) const override
computes and returns local stiffness matrix (1x1) for bases i,j (where i,j is passed in through data)...
void assemble_cross(const bool is_volume, const int size, const int n_from_basis, const std::vector< basis::ElementBases > &from_bases, const std::vector< basis::ElementBases > &from_gbases, const int n_to_basis, const std::vector< basis::ElementBases > &to_bases, const std::vector< basis::ElementBases > &to_gbases, const AssemblyValsCache &cache, StiffnessMatrix &mass) const
Assembles the cross mass matrix between to function spaces.
bool smooth_before(const Tuple &t) override
bool smooth_after(const Tuple &t) override
typename Super::Tuple Tuple
virtual bool is_volume() const
Is the mesh a volumetric mesh.
const State & state
Reference to the simulation state.
std::array< size_t, VERTICES_PER_ELEMENT > element_vids(const Tuple &t) const
Get the vertex ids of an element.
std::vector< std::pair< std::string, Tuple > > Operations
virtual bool smooth_before(const Tuple &t) override
typename WMTKMesh::Tuple Tuple
wmtk::AttributeCollection< VertexAttributes > vertex_attrs
virtual void smooth_vertices()
std::vector< Tuple > get_one_ring_elements_for_vertex(const Tuple &t) const
Get the one ring of elements around a vertex.
int dim() const override
Dimension of the mesh.
Eigen::Matrix< double, DIM, 1 > VectorNd
virtual bool smooth_after(const Tuple &t) override
std::shared_ptr< solver::ContactForm > contact_form
Eigen::VectorXd constrained_L2_projection(std::shared_ptr< polysolve::nonlinear::Solver > nl_solver, const Eigen::SparseMatrix< double > &M, const Eigen::SparseMatrix< double > &A, const Eigen::VectorXd &y, const Eigen::MatrixXd &rest_positions, const Eigen::MatrixXi &elements, const int dim, const ipc::CollisionMesh &collision_mesh, const double dhat, const double barrier_stiffness, const bool use_convergent_formulation, const ipc::BroadPhaseMethod broad_phase_method, const double ccd_tolerance, const int ccd_max_iterations, const std::vector< int > &boundary_nodes, const size_t obstacle_ndof, const Eigen::VectorXd &target_x, const Eigen::VectorXd &x0)
void project_local_quantities(WildRemesher< WMTKMesh > &m, LocalMesh< WildRemesher< WMTKMesh > > &old_local_mesh, LocalMesh< WildRemesher< WMTKMesh > > &new_local_mesh)
void reduced_L2_projection(const Eigen::MatrixXd &M, const Eigen::MatrixXd &A, const Eigen::Ref< const Eigen::MatrixXd > &y, const std::vector< int > &boundary_nodes, Eigen::Ref< Eigen::MatrixXd > x)
double get_quality(const WildRemesher< WMTKMesh > &m, const typename WMTKMesh::Tuple &t)
spdlog::logger & logger()
Retrieves the current logger.