PolyFEM
Loading...
Searching...
No Matches
SmoothContactForm.cpp
Go to the documentation of this file.
2
6
7#include <ipc/barrier/adaptive_stiffness.hpp>
8#include <ipc/utils/world_bbox_diagonal_length.hpp>
9
10#include <cmath>
11
12namespace polyfem::solver
13{
14 SmoothContactForm::SmoothContactForm(const ipc::CollisionMesh &collision_mesh,
15 const double dhat,
16 const double avg_mass,
17 const double alpha_t,
18 const double alpha_n,
19 const bool use_adaptive_dhat,
20 const double min_distance_ratio,
21 const bool use_adaptive_barrier_stiffness,
22 const bool is_time_dependent,
23 const bool enable_shape_derivatives,
24 const ipc::BroadPhaseMethod broad_phase_method,
25 const double ccd_tolerance,
26 const int ccd_max_iterations) : ContactForm(collision_mesh, dhat, avg_mass, use_adaptive_barrier_stiffness, is_time_dependent, enable_shape_derivatives, broad_phase_method, ccd_tolerance, ccd_max_iterations), params(dhat_, alpha_t, 0, alpha_n, 0, collision_mesh.dim() - 1), use_adaptive_dhat(use_adaptive_dhat), barrier_potential_(params)
27 {
28 params.set_adaptive_dhat_ratio(min_distance_ratio);
30 {
31 collision_set_.compute_adaptive_dhat(collision_mesh, collision_mesh.rest_positions(), params, broad_phase_);
33 logger().error("Adaptive dhat is not compatible with adaptive barrier stiffness");
34 }
35 }
36
37 void SmoothContactForm::update_barrier_stiffness(const Eigen::VectorXd &x, const Eigen::MatrixXd &grad_energy)
38 {
40 return;
41
42 log_and_throw_error("Adaptive barrier stiffness not implemented for SmoothContactForm!");
43 }
44
45 void SmoothContactForm::update_collision_set(const Eigen::MatrixXd &displaced_surface)
46 {
47 // Store the previous value used to compute the constraint set to avoid duplicate computation.
48 static Eigen::MatrixXd cached_displaced_surface;
49 if (cached_displaced_surface.size() == displaced_surface.size() && cached_displaced_surface == displaced_surface)
50 return;
51
53 collision_set_.build(
55 else
56 collision_set_.build(
58 cached_displaced_surface = displaced_surface;
59 }
60
65
66 Eigen::VectorXd SmoothContactForm::value_per_element_unweighted(const Eigen::VectorXd &x) const
67 {
68 log_and_throw_error("value_per_element_unweighted not implemented!");
69 }
70
71 void SmoothContactForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
72 {
74 gradv = collision_mesh_.to_full_dof(gradv);
75 }
76
77 void SmoothContactForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
78 {
79 // {
80 // io::OBJWriter::write(
81 // "collision_mesh.obj",
82 // compute_displaced_surface(x),
83 // collision_mesh_.edges(), collision_mesh_.faces());
84 // }
85 POLYFEM_SCOPED_TIMER("barrier hessian");
86 hessian = barrier_potential_.hessian(collision_set_, collision_mesh_, compute_displaced_surface(x), project_to_psd_ ? ipc::PSDProjectionMethod::CLAMP : ipc::PSDProjectionMethod::NONE);
87 hessian = collision_mesh_.to_full_dof(hessian);
88 }
89
90 void SmoothContactForm::post_step(const polysolve::nonlinear::PostStepData &data)
91 {
92 const Eigen::MatrixXd displaced_surface = compute_displaced_surface(data.x);
93
94 const double curr_distance = collision_set_.compute_minimum_distance(collision_mesh_, displaced_surface);
95 const double curr_active_distance = collision_set_.compute_active_minimum_distance(collision_mesh_, displaced_surface);
96 if (!std::isinf(curr_distance))
97 {
98 const double ratio = sqrt(curr_distance) / dhat();
99 const auto log_level = (ratio < 1e-6) ? spdlog::level::err : ((ratio < 1e-4) ? spdlog::level::warn : spdlog::level::debug);
100 polyfem::logger().log(log_level, "Minimum distance during solve: {}, active distance: {}, dhat: {}", sqrt(curr_distance), sqrt(curr_active_distance), dhat());
101 }
102
103 if (data.iter_num == 0)
104 return;
105
107 {
109 {
110 const double prev_barrier_stiffness = barrier_stiffness();
111
112 barrier_stiffness_ = ipc::update_barrier_stiffness(
114 barrier_stiffness(), ipc::world_bbox_diagonal_length(displaced_surface), 1e-7);
115
116 if (barrier_stiffness() != prev_barrier_stiffness)
117 {
118 polyfem::logger().debug(
119 "updated barrier stiffness from {:g} to {:g}",
120 prev_barrier_stiffness, barrier_stiffness());
121 }
122 }
123 else
124 {
125 // TODO: missing feature
126 // update_barrier_stiffness(data.x);
127 }
128 }
129
130 prev_distance_ = curr_distance;
131 }
132} // namespace polyfem::solver
int x
#define POLYFEM_SCOPED_TIMER(...)
Definition Timer.hpp:10
Form representing the contact potential and forces.
const bool use_adaptive_barrier_stiffness_
If true, use an adaptive barrier stiffness.
bool use_cached_candidates_
If true, use the cached candidate set for the current solution.
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.
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.
ipc::Candidates candidates_
Cached candidate set for the current solution.
const std::shared_ptr< ipc::BroadPhase > broad_phase_
const bool is_time_dependent_
Is the simulation time dependent?
bool project_to_psd_
If true, the form's second derivative is projected to be positive semidefinite.
Definition Form.hpp:147
void update_collision_set(const Eigen::MatrixXd &displaced_surface) override
Update the cached candidate set for the current solution.
ipc::SmoothContactPotential barrier_potential_
Contact potential.
void update_barrier_stiffness(const Eigen::VectorXd &x, const Eigen::MatrixXd &grad_energy) override
Update the barrier stiffness based on the current elasticity energy.
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.
void first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Compute the first derivative of the value wrt x.
SmoothContactForm(const ipc::CollisionMesh &collision_mesh, const double dhat, const double avg_mass, const double alpha_t, const double alpha_n, const bool use_adaptive_dhat, const double min_distance_ratio, 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)
void post_step(const polysolve::nonlinear::PostStepData &data) override
Update fields after a step in the optimization.
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the contact barrier potential value.
ipc::SmoothContactParameters params
ipc::SmoothCollisions collision_set_
Cached constraint set for the current solution.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24