PolyFEM
Loading...
Searching...
No Matches
FrictionForm.cpp
Go to the documentation of this file.
1#include "FrictionForm.hpp"
3#include "GCPContactForm.hpp"
4#include "ESPContactForm.hpp"
5
8
9#include <ipc/broad_phase/create_broad_phase.hpp>
10#include <ipc/collisions/normal/normal_collisions.hpp>
11#include <ipc/gcp/gcp_collisions.hpp>
12
13#include <Eigen/Core>
14
15#include <cassert>
16#include <limits>
17#include <memory>
18#include <stdexcept>
19
20namespace polyfem::solver
21{
23 const ipc::CollisionMesh &collision_mesh,
24 const std::shared_ptr<time_integrator::ImplicitTimeIntegrator> time_integrator,
25 const double epsv,
26 const double mu,
27 const ipc::BroadPhaseMethod broad_phase_method,
28 const ContactForm &contact_form,
29 const int n_lagging_iters)
30 : collision_mesh_(collision_mesh),
31 time_integrator_(time_integrator),
32 epsv_(epsv),
33 mu_(mu),
34 broad_phase_method_(broad_phase_method),
35 n_lagging_iters_(n_lagging_iters < 0 ? std::numeric_limits<int>::max() : n_lagging_iters),
36 contact_form_(contact_form),
37 friction_potential_(epsv)
38 {
39 assert(epsv_ > 0);
40 }
41
42 Eigen::MatrixXd FrictionForm::compute_displaced_surface(const Eigen::VectorXd &x) const
43 {
45 }
46
47 Eigen::MatrixXd FrictionForm::compute_surface_velocities(const Eigen::VectorXd &x) const
48 {
49 // In the case of a static problem, the velocity is the displacement
50 const Eigen::VectorXd v = time_integrator_ != nullptr ? time_integrator_->compute_velocity(x) : x;
51 return collision_mesh_.map_displacements(utils::unflatten(v, collision_mesh_.dim()));
52 }
53
54 double FrictionForm::dv_dx() const
55 {
56 return time_integrator_ != nullptr ? time_integrator_->dv_dx() : 1;
57 }
58
63
64 void FrictionForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
65 {
66 const Eigen::VectorXd grad_friction = friction_potential_.gradient(
68 gradv = collision_mesh_.to_full_dof(grad_friction);
69 }
70
71 void FrictionForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
72 {
73 POLYFEM_SCOPED_TIMER("friction hessian");
74
75 ipc::PSDProjectionMethod psd_projection_method;
76
78 {
79 psd_projection_method = ipc::PSDProjectionMethod::CLAMP;
80 }
81 else
82 {
83 psd_projection_method = ipc::PSDProjectionMethod::NONE;
84 }
85
86 hessian = dv_dx() * friction_potential_.hessian( //
88
89 hessian = collision_mesh_.to_full_dof(hessian);
90 }
91
92 void FrictionForm::update_lagging(const Eigen::VectorXd &x, const int iter_num)
93 {
94 const Eigen::MatrixXd displaced_surface = compute_displaced_surface(x);
95
96 auto broad_phase = ipc::create_broad_phase(broad_phase_method_);
97 if (const auto barrier_contact = dynamic_cast<const BarrierContactForm *>(&contact_form_))
98 {
99 ipc::NormalCollisions collision_set;
100 collision_set.set_use_area_weighting(barrier_contact->use_area_weighting());
101 // Copy the collision set type directly rather than going through
102 // use_improved_max_operator(), which collapses it to a bool and so
103 // would silently downgrade OGC to IPC here.
104 collision_set.set_collision_set_type(barrier_contact->collision_set().collision_set_type());
105
106 collision_set.set_enable_shape_derivatives(barrier_contact->enable_shape_derivatives());
107 collision_set.build(
108 collision_mesh_, displaced_surface, barrier_contact->dhat(), /*dmin=*/0, broad_phase.get());
109
110 ipc::BarrierPotential bp = barrier_contact->barrier_potential();
111 bp.set_stiffness(barrier_contact->barrier_stiffness());
113 collision_mesh_, displaced_surface, collision_set,
114 bp, Eigen::VectorXd::Ones(collision_mesh_.num_vertices()) * mu_, Eigen::VectorXd::Ones(collision_mesh_.num_vertices()) * mu_);
115 }
116 else if (const auto gcp = dynamic_cast<const GCPContactForm *>(&contact_form_))
117 {
118 ipc::GCPCollisions collision_set;
119 if (gcp->using_adaptive_dhat())
120 collision_set.compute_adaptive_dhat(collision_mesh_, collision_mesh_.rest_positions(), gcp->get_params(), broad_phase.get());
121 collision_set.build(
122 collision_mesh_, displaced_surface, gcp->get_params(),
123 gcp->using_adaptive_dhat(), broad_phase.get());
124
126 collision_mesh_, displaced_surface,
127 collision_set, gcp->get_params(), contact_form_.barrier_stiffness(), Eigen::VectorXd::Ones(collision_mesh_.num_vertices()) * mu_, Eigen::VectorXd::Ones(collision_mesh_.num_vertices()) * mu_);
128 }
129 else if (const auto esp_contact = dynamic_cast<const ESPContactForm *>(&contact_form_))
130 {
131 ipc::ESPCollisions collision_set;
132 collision_set.build(
133 collision_mesh_, displaced_surface, esp_contact->get_params(),
134 broad_phase.get());
135
137 collision_mesh_, displaced_surface, collision_set,
138 esp_contact->get_params(), contact_form_.barrier_stiffness(),
139 Eigen::VectorXd::Ones(collision_mesh_.num_vertices()) * mu_,
140 Eigen::VectorXd::Ones(collision_mesh_.num_vertices()) * mu_);
141 }
142 else
143 {
144 throw std::runtime_error("Unknown contact form");
145 }
146 }
147} // namespace polyfem::solver
int x
#define POLYFEM_SCOPED_TIMER(...)
Definition Timer.hpp:10
Form representing the contact potential and forces.
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.
bool project_to_psd_
If true, the form's second derivative is projected to be positive semidefinite.
Definition Form.hpp:147
const ipc::BroadPhaseMethod broad_phase_method_
Broad-phase method used for distance computation and collision detection.
FrictionForm(const ipc::CollisionMesh &collision_mesh, const std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator, const double epsv, const double mu, const ipc::BroadPhaseMethod broad_phase_method, const ContactForm &contact_form, const int n_lagging_iters)
Construct a new Friction Form object.
void update_lagging(const Eigen::VectorXd &x, const int iter_num) override
Update lagged fields.
void second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const override
Compute the second derivative of the value wrt x.
const ipc::CollisionMesh & collision_mesh_
Reference to the collision mesh.
const std::shared_ptr< time_integrator::ImplicitTimeIntegrator > time_integrator_
Pointer to the time integrator.
Eigen::MatrixXd compute_surface_velocities(const Eigen::VectorXd &x) const
Compute the surface velocities.
const ipc::FrictionPotential friction_potential_
Eigen::MatrixXd compute_displaced_surface(const Eigen::VectorXd &x) const
Compute the displaced positions of the surface nodes.
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
double dv_dx() const
Compute the derivative of the velocities wrt x.
void first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Compute the first derivative of the value wrt x.
const ContactForm & contact_form_
necessary to have the barrier stiffnes, maybe clean me
ipc::TangentialCollisions friction_collision_set_
Lagged friction constraint set.
const double epsv_
Smoothing factor between static and dynamic friction.
const double mu_
Global coefficient of friction.
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24