PolyFEM
Loading...
Searching...
No Matches
InversionBarrierForm.cpp
Go to the documentation of this file.
1
3
7
8#include <ipc/barrier/barrier.hpp>
9#include <ipc/utils/local_to_global.hpp>
10#include <ipc/utils/eigen_ext.hpp>
11
12namespace polyfem::solver
13{
15 const Eigen::MatrixXd &rest_positions, const Eigen::MatrixXi &elements, const int dim, const double vhat)
16 : rest_positions_(rest_positions), elements_(elements), dim_(dim), vhat_(vhat)
17 {
18 }
19
20 double InversionBarrierForm::value_unweighted(const Eigen::VectorXd &x) const
21 {
22 const Eigen::MatrixXd V = rest_positions_ + utils::unflatten(x, dim_);
23
24 auto storage = utils::create_thread_storage<double>(0.0);
25
26 const double scale = 1.0 / (vhat_ * vhat_);
27
28 utils::maybe_parallel_for(elements_.rows(), [&](int start, int end, int thread_id) {
29 double &local_potential = utils::get_local_thread_storage(storage, thread_id);
30 for (int i = start; i < end; i++)
31 {
32 local_potential +=
33 scale * element_volume(rest_positions_(elements_.row(i), Eigen::all))
34 * ipc::barrier(element_volume(V(elements_.row(i), Eigen::all)), vhat_);
35 }
36 });
37
38 double potential = 0;
39 for (const auto &local_potential : storage)
40 potential += local_potential;
41 return potential;
42 }
43
44 void InversionBarrierForm::first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const
45 {
46 const Eigen::MatrixXd V = rest_positions_ + utils::unflatten(x, dim_);
47
48 auto storage = utils::create_thread_storage<Eigen::VectorXd>(Eigen::VectorXd::Zero(x.size()));
49
50 const double scale = 1.0 / (vhat_ * vhat_);
51
52 utils::maybe_parallel_for(elements_.rows(), [&](int start, int end, int thread_id) {
53 Eigen::VectorXd &grad = utils::get_local_thread_storage(storage, thread_id);
54 for (int i = start; i < end; i++)
55 {
56 const Eigen::MatrixXd element_vertices = V(elements_.row(i), Eigen::all);
57
58 Eigen::VectorXd local_grad =
59 (scale * element_volume(rest_positions_(elements_.row(i), Eigen::all))
60 * ipc::barrier_first_derivative(element_volume(element_vertices), vhat_))
61 * element_volume_gradient(element_vertices);
62
63 ipc::local_gradient_to_global_gradient(local_grad, elements_.row(i), dim_, grad);
64 }
65 });
66
67 gradv = Eigen::VectorXd::Zero(x.size());
68 for (const auto &local_grad : storage)
69 gradv += local_grad;
70 }
71
72 void InversionBarrierForm::second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const
73 {
74 const Eigen::MatrixXd V = rest_positions_ + utils::unflatten(x, dim_);
75
76 auto storage = utils::create_thread_storage(std::vector<Eigen::Triplet<double>>());
77
78 const double scale = 1.0 / (vhat_ * vhat_);
79
80 utils::maybe_parallel_for(elements_.rows(), [&](int start, int end, int thread_id) {
81 std::vector<Eigen::Triplet<double>> &hess_triplets =
82 utils::get_local_thread_storage(storage, thread_id);
83
84 for (int i = start; i < end; i++)
85 {
86 const Eigen::MatrixXd element_vertices = V(elements_.row(i), Eigen::all);
87
88 const double volume = element_volume(element_vertices);
89 const Eigen::VectorXd volume_grad = element_volume_gradient(element_vertices);
90
91 const double rest_volume = element_volume(rest_positions_(elements_.row(i), Eigen::all));
92
93 Eigen::MatrixXd local_hess =
94 (scale * rest_volume * ipc::barrier_second_derivative(volume, vhat_)) * volume_grad * volume_grad.transpose()
95 + (scale * rest_volume * ipc::barrier_first_derivative(volume, vhat_)) * element_volume_hessian(element_vertices);
96
97 if (project_to_psd_)
98 local_hess = ipc::project_to_psd(local_hess);
99
100 ipc::local_hessian_to_global_triplets(local_hess, elements_.row(i), dim_, hess_triplets);
101 }
102 });
103
104 hessian.resize(x.size(), x.size());
105 for (const auto &local_hess_triplets : storage)
106 {
107 Eigen::SparseMatrix<double> local_hess(x.size(), x.size());
108 local_hess.setFromTriplets(
109 local_hess_triplets.begin(), local_hess_triplets.end());
110 hessian += local_hess;
111 }
112 }
113
114 double InversionBarrierForm::element_volume(const Eigen::MatrixXd &element_vertices)
115 {
116 if (element_vertices.rows() == 3)
117 return utils::triangle_area(element_vertices);
118
119 assert(element_vertices.rows() == 4 && element_vertices.cols() == 3);
120 return utils::tetrahedron_volume(element_vertices);
121 }
122
123 Eigen::VectorXd InversionBarrierForm::element_volume_gradient(const Eigen::MatrixXd &element_vertices)
124 {
125 Eigen::VectorXd grad(element_vertices.size());
126 if (element_vertices.rows() == 3)
127 {
128 assert(element_vertices.cols() == 2);
130 element_vertices(0, 0), element_vertices(0, 1),
131 element_vertices(1, 0), element_vertices(1, 1),
132 element_vertices(2, 0), element_vertices(2, 1),
133 grad.data());
134 }
135 else
136 {
137 assert(element_vertices.rows() == 4 && element_vertices.cols() == 3);
139 element_vertices(0, 0), element_vertices(0, 1), element_vertices(0, 2),
140 element_vertices(1, 0), element_vertices(1, 1), element_vertices(1, 2),
141 element_vertices(2, 0), element_vertices(2, 1), element_vertices(2, 2),
142 element_vertices(3, 0), element_vertices(3, 1), element_vertices(3, 2),
143 grad.data());
144 }
145 return grad;
146 }
147
148 Eigen::MatrixXd InversionBarrierForm::element_volume_hessian(const Eigen::MatrixXd &element_vertices)
149 {
150 Eigen::MatrixXd hess(element_vertices.size(), element_vertices.size());
151 if (element_vertices.rows() == 3)
152 {
153 assert(element_vertices.cols() == 2);
155 element_vertices(0, 0), element_vertices(0, 1),
156 element_vertices(1, 0), element_vertices(1, 1),
157 element_vertices(2, 0), element_vertices(2, 1),
158 hess.data());
159 }
160 else
161 {
162 assert(element_vertices.rows() == 4 && element_vertices.cols() == 3);
164 element_vertices(0, 0), element_vertices(0, 1), element_vertices(0, 2),
165 element_vertices(1, 0), element_vertices(1, 1), element_vertices(1, 2),
166 element_vertices(2, 0), element_vertices(2, 1), element_vertices(2, 2),
167 element_vertices(3, 0), element_vertices(3, 1), element_vertices(3, 2),
168 hess.data());
169 }
170 return hess;
171 }
172
173 bool InversionBarrierForm::is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const
174 {
175 const Eigen::MatrixXd V = rest_positions_ + utils::unflatten(x1, dim_);
176
177 for (size_t i = 0; i < elements_.rows(); ++i)
178 {
179 // TODO: use exact predicate for this
180 if (element_volume(V(elements_.row(i), Eigen::all)) <= 0)
181 {
182 return false;
183 }
184 }
185
186 return true;
187 }
188} // namespace polyfem::solver
int V
int x
InversionBarrierForm(const Eigen::MatrixXd &rest_positions, const Eigen::MatrixXi &elements, const int dim, const double vhat)
bool is_step_valid(const Eigen::VectorXd &x0, const Eigen::VectorXd &x1) const override
Determine if a step from solution x0 to solution x1 is allowed.
void first_derivative_unweighted(const Eigen::VectorXd &x, Eigen::VectorXd &gradv) const override
Compute the first derivative of the value wrt x.
static double element_volume(const Eigen::MatrixXd &element_vertices)
static Eigen::MatrixXd element_volume_hessian(const Eigen::MatrixXd &element_vertices)
double value_unweighted(const Eigen::VectorXd &x) const override
Compute the value of the form.
void second_derivative_unweighted(const Eigen::VectorXd &x, StiffnessMatrix &hessian) const override
Compute the second derivative of the value wrt x.
static Eigen::VectorXd element_volume_gradient(const Eigen::MatrixXd &element_vertices)
void triangle_area_2D_hessian(double ax, double ay, double bx, double by, double cx, double cy, double H[36])
Compute the Hessian of the signed area of a 2D triangle defined by three points.
void tetrahedron_volume_gradient(double ax, double ay, double az, double bx, double by, double bz, double cx, double cy, double cz, double dx, double dy, double dz, double g[12])
Compute the gradient of the signed volume of a tetrahedron defined by four points.
void tetrahedron_volume_hessian(double ax, double ay, double az, double bx, double by, double bz, double cx, double cy, double cz, double dx, double dy, double dz, double H[144])
Compute the gradient of the signed area of a 2D triangle defined by three points.
double tetrahedron_volume(const Eigen::Vector3d &a, const Eigen::Vector3d &b, const Eigen::Vector3d &c, const Eigen::Vector3d &d)
Compute the signed volume of a tetrahedron defined by four points.
void triangle_area_2D_gradient(double ax, double ay, double bx, double by, double cx, double cy, double g[6])
Compute the gradient of the signed area of a 2D triangle defined by three points.
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
auto create_thread_storage(const LocalStorage &initial_local_storage)
double triangle_area(const Eigen::MatrixXd V)
Compute the signed area of a triangle defined by three points.
void maybe_parallel_for(int size, const std::function< void(int, int, int)> &partial_for)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:20