PolyFEM
Loading...
Searching...
No Matches
ESPContactForm.cpp
Go to the documentation of this file.
1#include "ESPContactForm.hpp"
8
9#include <ipc/utils/eigen_ext.hpp>
10#include <ipc/barrier/adaptive_stiffness.hpp>
11#include <ipc/utils/world_bbox_diagonal_length.hpp>
12#include <ipc/barrier/barrier.hpp>
13
14namespace polyfem::solver
15{
16 namespace
17 {
18 ipc::FaceQuadRule build_quad_rule(const int order)
19 {
22
23 ipc::FaceQuadRule rule;
24 rule.reserve(quad.size());
25 for (int i = 0; i < quad.size(); i++)
26 {
27 const double x = quad.points(i, 0);
28 const double y = quad.points(i, 1);
29 // polyfem divides weights by 2 (reference triangle area); multiply
30 // back to match ipc-toolkit's convention of weights summing to 1.
31 const double w = quad.weights(i) * 2.0;
32 rule.push_back({{{1.0 - x - y, x, y}}, w});
33 }
34 return rule;
35 }
36 } // namespace
37
40 bool is_vertex_point(const ipc::FaceQuadPoint &qp, int vertex, double tol = 1e-12)
41 {
42 for (int i = 0; i < 3; i++)
43 {
44 if (std::abs(qp.lambda[i] - (i == vertex ? 1.0 : 0.0)) > tol)
45 return false;
46 }
47 return true;
48 }
49
51 void verify_vertices_in_quad_rule(const ipc::FaceQuadRule &rule)
52 {
53 for (int v = 0; v < 3; v++)
54 {
55 bool found = false;
56 for (const auto &qp : rule)
57 {
58 if (is_vertex_point(qp, v))
59 {
60 found = true;
61 break;
62 }
63 }
64 if (!found)
65 throw std::runtime_error("Face quadrature rule is missing triangle vertex " + std::to_string(v) + "; choose a quadrature scheme that includes corner points");
66 }
67 }
68
69 ipc::ESPParameters init_params(const double dhat, const json &esp_params, const bool skip_obstacles, std::shared_ptr<ipc::Barrier> barrier, const int dim)
70 {
71 const int quadrature_order = esp_params["quadrature_order"];
72 const double dbar_factor = esp_params["dbar_factor"];
73 const bool area_weights = esp_params["area_weights"];
74 const ipc::ESPParameters::IntegrationType itype = skip_obstacles ? ipc::ESPParameters::IntegrationType::NO_OBST : ipc::ESPParameters::IntegrationType::NORMAL;
75 ipc::ESPParameters params(dhat, dbar_factor, quadrature_order, area_weights, itype);
76 params.barrier = barrier ? barrier : (dim == 3 ? std::make_shared<ipc::InversePowerBarrier<>>(2.0) : std::make_shared<ipc::InversePowerBarrier<>>(1.0));
77 if (quadrature_order > 0)
78 {
79 params.set_quad_rule(build_quad_rule(quadrature_order));
80 verify_vertices_in_quad_rule(params.quad_rule());
81 }
82 return params;
83 }
84
85 ESPContactForm::ESPContactForm(const ipc::CollisionMesh &collision_mesh,
86 const double dhat,
87 const double avg_mass,
88 const json esp_params,
89 const bool skip_obstacles,
90 std::shared_ptr<ipc::Barrier> barrier,
91 const bool use_adaptive_dhat,
92 const bool use_adaptive_barrier_stiffness,
93 const bool is_time_dependent,
94 const bool enable_shape_derivatives,
95 const ipc::BroadPhaseMethod broad_phase_method,
96 const double ccd_tolerance,
97 const int ccd_max_iterations,
98 const double dhat_epsilon_scale) : ContactForm(collision_mesh, dhat, avg_mass, use_adaptive_barrier_stiffness, is_time_dependent, enable_shape_derivatives, broad_phase_method, ccd_tolerance, ccd_max_iterations, dhat_epsilon_scale), params(init_params(dhat, esp_params, skip_obstacles, barrier, static_cast<int>(collision_mesh.dim()))),
99 barrier_potential_(params, esp_params["normalize_weights"])
100 {
101 if (use_adaptive_dhat)
102 log_and_throw_error("Adaptive dhat is not implemented for ESPContactForm!");
103 }
104
105 void ESPContactForm::update_barrier_stiffness(const Eigen::VectorXd &x, const Eigen::MatrixXd &grad_energy)
106 {
108 return;
109
110 log_and_throw_error("Adaptive barrier stiffness not implemented for ESPContactForm!");
111 }
112
113 void ESPContactForm::update_collision_set(const Eigen::MatrixXd &displaced_surface)
114 {
115 // Store the previous value used to compute the constraint set to avoid duplicate computation.
116 if (cached_displaced_surface.size() == displaced_surface.size() && cached_displaced_surface == displaced_surface)
117 return;
118
119 collision_set_.build(
120 collision_mesh_, displaced_surface, params, broad_phase_.get());
121 cached_displaced_surface = displaced_surface;
122 }
123
124 double ESPContactForm::value_unweighted(const Eigen::VectorXd &x) const
125 {
126 const Eigen::MatrixXd displaced = compute_displaced_surface(x);
127 if (cached_displaced_surface != displaced)
128 {
129 return 0.;
130 }
132 }
133
134 Eigen::VectorXd ESPContactForm::value_per_element_unweighted(const Eigen::VectorXd &x) const
135 {
136 log_and_throw_error("value_per_element_unweighted not implemented!");
137 }
138
139 void ESPContactForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
140 {
141 const Eigen::MatrixXd displaced = compute_displaced_surface(x);
142 if (cached_displaced_surface != displaced)
143 {
144 gradv.setZero(x.size());
145 return;
146 }
147 gradv = barrier_potential_.gradient(collision_set_, collision_mesh_, displaced);
148 gradv = collision_mesh_.to_full_dof(gradv);
149 }
150
151 void ESPContactForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
152 {
153 POLYFEM_SCOPED_TIMER("barrier hessian");
154 hessian = barrier_potential_.hessian(collision_set_, collision_mesh_, compute_displaced_surface(x), project_to_psd_ ? ipc::PSDProjectionMethod::CLAMP : ipc::PSDProjectionMethod::NONE);
155 hessian = collision_mesh_.to_full_dof(hessian);
156 }
157
158 void ESPContactForm::post_step(const polysolve::nonlinear::PostStepData &data)
159 {
160 const Eigen::MatrixXd displaced_surface = compute_displaced_surface(data.x);
161
162 // Always requires update_collision_set
163 update_collision_set(displaced_surface);
164
165 const double curr_distance = collision_set_.compute_minimum_distance(collision_mesh_, displaced_surface);
166 if (!std::isinf(curr_distance))
167 {
168 const double ratio = sqrt(curr_distance) / dhat();
169 const auto log_level = (ratio < 1e-6) ? spdlog::level::err : ((ratio < 1e-4) ? spdlog::level::warn : spdlog::level::debug);
170 polyfem::logger().log(log_level, "Minimum distance during solve: {}, dhat: {}", sqrt(curr_distance), dhat());
171 }
172
173 if (data.iter_num == 0)
174 return;
175
177 {
179 {
180 const double prev_barrier_stiffness = barrier_stiffness();
181
182 barrier_stiffness_ = ipc::update_barrier_stiffness(
184 barrier_stiffness(), ipc::world_bbox_diagonal_length(displaced_surface),
186
187 if (barrier_stiffness() != prev_barrier_stiffness)
188 {
189 polyfem::logger().debug(
190 "updated barrier stiffness from {:g} to {:g}",
191 prev_barrier_stiffness, barrier_stiffness());
192 }
193 }
194 else
195 {
196 // TODO: missing feature
197 // update_barrier_stiffness(data.x);
198 }
199 }
200
201 prev_distance_ = curr_distance;
202 }
203} // namespace polyfem::solver
int y
int x
#define POLYFEM_SCOPED_TIMER(...)
Definition Timer.hpp:10
void get_quadrature(const int order, Quadrature &quad)
Form representing the contact potential and forces.
const bool use_adaptive_barrier_stiffness_
If true, use an adaptive barrier stiffness.
Eigen::MatrixXd compute_displaced_surface(const Eigen::VectorXd &x) const
Compute the displaced positions of the surface nodes.
double barrier_stiffness() const
Get the current barrier stiffness.
const double dhat_epsilon_scale_
dhat_epsilon_scale used by ipc::update_barrier_stiffness.
double barrier_stiffness_
Barrier stiffness.
double max_barrier_stiffness_
Maximum barrier stiffness to use when using adaptive barrier stiffness.
double prev_distance_
Previous minimum distance between all elements.
const ipc::CollisionMesh & collision_mesh_
Collision mesh.
bool use_adaptive_barrier_stiffness() const
Get use_adaptive_barrier_stiffness.
const std::shared_ptr< ipc::BroadPhase > broad_phase_
const bool is_time_dependent_
Is the simulation time dependent?
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the contact barrier potential value.
void update_collision_set(const Eigen::MatrixXd &displaced_surface) override
Update the cached candidate set for the current solution.
void post_step(const polysolve::nonlinear::PostStepData &data) override
Update fields after a step in the optimization.
void update_barrier_stiffness(const Eigen::VectorXd &x, const Eigen::MatrixXd &grad_energy) override
Update the barrier stiffness based on the current elasticity energy.
ipc::ESPCollisions collision_set_
Cached constraint set for the current solution.
ipc::ESPPotential barrier_potential_
Contact potential.
ESPContactForm(const ipc::CollisionMesh &collision_mesh, const double dhat, const double avg_mass, const json esp_params, const bool skip_obstacles, std::shared_ptr< ipc::Barrier > barrier, const bool use_adaptive_dhat, const bool use_adaptive_barrier_stiffness, const bool is_time_dependent, const bool enable_shape_derivatives, const ipc::BroadPhaseMethod broad_phase_method, const double ccd_tolerance, const int ccd_max_iterations, const double dhat_epsilon_scale)
void first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Compute the first derivative of the value wrt x.
void second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const override
Compute the second derivative of the value wrt x.
Eigen::VectorXd value_per_element_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form multiplied per element.
bool project_to_psd_
If true, the form's second derivative is projected to be positive semidefinite.
Definition Form.hpp:147
bool is_vertex_point(const ipc::FaceQuadPoint &qp, int vertex, double tol=1e-12)
Check if a quadrature point is at a triangle vertex (one barycentric coordinate ≈ 1,...
ipc::ESPParameters init_params(const double dhat, const json &esp_params, const bool skip_obstacles, std::shared_ptr< ipc::Barrier > barrier, const int dim)
void verify_vertices_in_quad_rule(const ipc::FaceQuadRule &rule)
Verify the quadrature rule contains the 3 triangle vertices.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24