Loading [MathJax]/jax/output/HTML-CSS/config.js
PolyFEM
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
ContactForm.cpp
Go to the documentation of this file.
1#include "ContactForm.hpp"
2
10
12
13#include <ipc/barrier/adaptive_stiffness.hpp>
14#include <ipc/utils/world_bbox_diagonal_length.hpp>
15
16#include <igl/writePLY.h>
17
18namespace polyfem::solver
19{
20 ContactForm::ContactForm(const ipc::CollisionMesh &collision_mesh,
21 const double dhat,
22 const double avg_mass,
23 const bool use_adaptive_barrier_stiffness,
24 const bool is_time_dependent,
25 const bool enable_shape_derivatives,
26 const ipc::BroadPhaseMethod broad_phase_method,
27 const double ccd_tolerance,
28 const int ccd_max_iterations)
29 : collision_mesh_(collision_mesh),
30 dhat_(dhat),
31 use_adaptive_barrier_stiffness_(use_adaptive_barrier_stiffness),
32 avg_mass_(avg_mass),
33 is_time_dependent_(is_time_dependent),
34 enable_shape_derivatives_(enable_shape_derivatives),
35 broad_phase_method_(broad_phase_method),
36 broad_phase_(ipc::build_broad_phase(broad_phase_method)),
37 tight_inclusion_ccd_(ccd_tolerance, ccd_max_iterations)
38 {
39 assert(dhat_ > 0);
40 assert(ccd_tolerance > 0);
41
42 prev_distance_ = -1;
43 }
44
45 void ContactForm::init(const Eigen::VectorXd &x)
46 {
48 }
49
50 void ContactForm::update_quantities(const double t, const Eigen::VectorXd &x)
51 {
53 }
54
55 Eigen::MatrixXd ContactForm::compute_displaced_surface(const Eigen::VectorXd &x) const
56 {
57 return collision_mesh_.displace_vertices(utils::unflatten(x, collision_mesh_.dim()));
58 }
59
60 void ContactForm::solution_changed(const Eigen::VectorXd &new_x)
61 {
63 }
64
65 double ContactForm::max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
66 {
67 // Extract surface only
68 const Eigen::MatrixXd V0 = compute_displaced_surface(x0);
69 const Eigen::MatrixXd V1 = compute_displaced_surface(x1);
70
72 {
73 const Eigen::MatrixXi E = collision_mesh_.dim() == 2 ? Eigen::MatrixXi() : collision_mesh_.edges();
74 const Eigen::MatrixXi &F = collision_mesh_.faces();
75 igl::writePLY(resolve_output_path("debug_ccd_0.ply"), V0, F, E);
76 igl::writePLY(resolve_output_path("debug_ccd_1.ply"), V1, F, E);
77 }
78
79 double max_step;
80 if (use_cached_candidates_ && broad_phase_method_ != ipc::BroadPhaseMethod::SWEEP_AND_TINIEST_QUEUE)
81 max_step = candidates_.compute_collision_free_stepsize(
83 else
84 max_step = ipc::compute_collision_free_stepsize(
86
87 if (save_ccd_debug_meshes && ipc::has_intersections(collision_mesh_, (V1 - V0) * max_step + V0, broad_phase_))
88 {
89 log_and_throw_error("Taking max_step results in intersections (max_step={})", max_step);
90 }
91
92#ifndef NDEBUG
93 // This will check for static intersections as a failsafe. Not needed if we use our conservative CCD.
94 Eigen::MatrixXd V_toi = (V1 - V0) * max_step + V0;
95
96 while (ipc::has_intersections(collision_mesh_, V_toi, broad_phase_))
97 {
98 logger().error("Taking max_step results in intersections (max_step={:g})", max_step);
99 max_step /= 2.0;
100
101 const double Linf = (V_toi - V0).lpNorm<Eigen::Infinity>();
102 if (max_step <= 0 || Linf == 0)
103 log_and_throw_error("Unable to find an intersection free step size (max_step={:g} L∞={:g})", max_step, Linf);
104
105 V_toi = (V1 - V0) * max_step + V0;
106 }
107#endif
108
109 return max_step;
110 }
111
112 void ContactForm::line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1)
113 {
114 candidates_.build(
118 /*inflation_radius=*/barrier_support_size() / 2,
120
122 }
123
125 {
126 candidates_.clear();
128 }
129
130 bool ContactForm::is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
131 {
132 const auto displaced0 = compute_displaced_surface(x0);
133 const auto displaced1 = compute_displaced_surface(x1);
134
135 // Skip CCD if the displacement is zero.
136 if ((displaced1 - displaced0).lpNorm<Eigen::Infinity>() == 0.0)
137 {
138 // Assumes initially intersection-free
139 return true;
140 }
141
142 bool is_valid;
144 is_valid = candidates_.is_step_collision_free(
145 collision_mesh_, displaced0, displaced1, dmin_,
147 else
148 is_valid = ipc::is_step_collision_free(
149 collision_mesh_, displaced0, displaced1, dmin_, broad_phase_,
151
152 return is_valid;
153 }
154} // namespace polyfem::solver
int x
virtual void update_collision_set(const Eigen::MatrixXd &displaced_surface)=0
Update the cached candidate set for the current solution.
const double dmin_
Minimum distance between elements.
virtual void init(const Eigen::VectorXd &x) override
Initialize the form.
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.
virtual double max_step_size(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Determine the maximum step size allowable between the current and next solution.
virtual void solution_changed(const Eigen::VectorXd &new_x) override
Update cached fields upon a change in the solution.
double prev_distance_
Previous minimum distance between all elements.
const ipc::BroadPhaseMethod broad_phase_method_
Broad phase method to use for distance and CCD evaluations.
void line_search_end() override
Clear variables used during the line search.
const ipc::CollisionMesh & collision_mesh_
Collision mesh.
const ipc::TightInclusionCCD tight_inclusion_ccd_
Continuous collision detection specification object.
virtual void line_search_begin(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) override
Initialize variables used during the line search.
ipc::Candidates candidates_
Cached candidate set for the current solution.
virtual double barrier_support_size() const
ContactForm(const ipc::CollisionMesh &collision_mesh, const double dhat, const double avg_mass, 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)
Construct a new Contact Form object.
virtual void update_quantities(const double t, const Eigen::VectorXd &x) override
Update time-dependent fields.
bool save_ccd_debug_meshes
If true, output debug files.
const double dhat_
Barrier activation distance.
const std::shared_ptr< ipc::BroadPhase > broad_phase_
virtual bool is_step_collision_free(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Checks if the step is collision free.
std::string resolve_output_path(const std::string &path) const
Definition Form.hpp:155
std::tuple< bool, int, Tree > is_valid(const int dim, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const Eigen::VectorXd &u, const double threshold)
Definition Jacobian.cpp:297
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73