PolyFEM
Loading...
Searching...
No Matches
GCPContactForm.cpp
Go to the documentation of this file.
1#include "GCPContactForm.hpp"
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 GCPContactForm::GCPContactForm(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,
27 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(dhat_, alpha_t, 0, alpha_n, 0, collision_mesh.dim() - 1), use_adaptive_dhat(use_adaptive_dhat), barrier_potential_(params)
28 {
29 params.set_adaptive_dhat_ratio(min_distance_ratio);
31 {
32 collision_set_.compute_adaptive_dhat(collision_mesh, collision_mesh.rest_positions(), params, broad_phase_.get());
34 logger().error("Adaptive dhat is not compatible with adaptive barrier stiffness");
35 }
36 }
37
38 void GCPContactForm::update_barrier_stiffness(const Eigen::VectorXd &x, const Eigen::MatrixXd &grad_energy)
39 {
41 return;
42
43 log_and_throw_error("Adaptive barrier stiffness not implemented for GCPContactForm!");
44 }
45
46 void GCPContactForm::update_collision_set(const Eigen::MatrixXd &displaced_surface)
47 {
48 // Store the previous value used to compute the constraint set to avoid duplicate computation.
49 static Eigen::MatrixXd cached_displaced_surface;
50 if (cached_displaced_surface.size() == displaced_surface.size() && cached_displaced_surface == displaced_surface)
51 return;
52
54 collision_set_.build(
56 else
57 collision_set_.build(
58 collision_mesh_, displaced_surface, params, use_adaptive_dhat, broad_phase_.get());
59 cached_displaced_surface = displaced_surface;
60 }
61
66
67 Eigen::VectorXd GCPContactForm::value_per_element_unweighted(const Eigen::VectorXd &x) const
68 {
69 log_and_throw_error("value_per_element_unweighted not implemented!");
70 }
71
72 void GCPContactForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
73 {
75 gradv = collision_mesh_.to_full_dof(gradv);
76 }
77
78 void GCPContactForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
79 {
80 // {
81 // io::OBJWriter::write(
82 // "collision_mesh.obj",
83 // compute_displaced_surface(x),
84 // collision_mesh_.edges(), collision_mesh_.faces());
85 // }
86 POLYFEM_SCOPED_TIMER("barrier hessian");
87 hessian = barrier_potential_.hessian(collision_set_, collision_mesh_, compute_displaced_surface(x), project_to_psd_ ? ipc::PSDProjectionMethod::CLAMP : ipc::PSDProjectionMethod::NONE);
88 hessian = collision_mesh_.to_full_dof(hessian);
89 }
90
91 void GCPContactForm::post_step(const polysolve::nonlinear::PostStepData &data)
92 {
93 const Eigen::MatrixXd displaced_surface = compute_displaced_surface(data.x);
94
95 const double curr_distance = collision_set_.compute_minimum_distance(collision_mesh_, displaced_surface);
96 const double curr_active_distance = collision_set_.compute_active_minimum_distance(collision_mesh_, displaced_surface);
97 if (!std::isinf(curr_distance))
98 {
99 const double ratio = sqrt(curr_distance) / dhat();
100 const auto log_level = (ratio < 1e-6) ? spdlog::level::err : ((ratio < 1e-4) ? spdlog::level::warn : spdlog::level::debug);
101 polyfem::logger().log(log_level, "Minimum distance during solve: {}, active distance: {}, dhat: {}", sqrt(curr_distance), sqrt(curr_active_distance), dhat());
102 }
103
104 if (data.iter_num == 0)
105 return;
106
108 {
110 {
111 const double prev_barrier_stiffness = barrier_stiffness();
112
113 barrier_stiffness_ = ipc::update_barrier_stiffness(
115 barrier_stiffness(), ipc::world_bbox_diagonal_length(displaced_surface),
117
118 if (barrier_stiffness() != prev_barrier_stiffness)
119 {
120 polyfem::logger().debug(
121 "updated barrier stiffness from {:g} to {:g}",
122 prev_barrier_stiffness, barrier_stiffness());
123 }
124 }
125 else
126 {
127 // TODO: missing feature
128 // update_barrier_stiffness(data.x);
129 }
130 }
131
132 prev_distance_ = curr_distance;
133 }
134} // 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.
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.
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 post_step(const polysolve::nonlinear::PostStepData &data) override
Update fields after a step in the optimization.
void second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const override
Compute the second derivative of the value wrt x.
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 update_collision_set(const Eigen::MatrixXd &displaced_surface) override
Update the cached candidate set for the current solution.
ipc::GCPPotential barrier_potential_
Contact potential.
GCPContactForm(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, 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.
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the contact barrier potential value.
Eigen::VectorXd value_per_element_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form multiplied per element.
ipc::GCPCollisions 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