Skip to content

Commit 4d08f10

Browse files
committed
Made area jacobians computation on demand
1 parent a47df7e commit 4d08f10

File tree

4 files changed

+117
-31
lines changed

4 files changed

+117
-31
lines changed

python/src/collision_mesh.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,39 @@ void define_collision_mesh(py::module_& m)
5252
py::overload_cast<const Eigen::SparseMatrix<double>&>(
5353
&CollisionMesh::to_full_dof, py::const_),
5454
"", py::arg("X"))
55+
.def(
56+
"init_adjacencies", &CollisionMesh::init_adjacencies,
57+
"Initialize vertex-vertex and edge-vertex adjacencies.")
5558
.def_property_readonly(
5659
"vertex_vertex_adjacencies",
5760
&CollisionMesh::vertex_vertex_adjacencies, "")
5861
.def_property_readonly(
5962
"edge_vertex_adjacencies", &CollisionMesh::edge_vertex_adjacencies,
6063
"")
64+
.def(
65+
"are_adjacencies_initialized",
66+
&CollisionMesh::are_adjacencies_initialized,
67+
"Determine if the adjacencies have been initialized by calling init_adjacencies().")
6168
.def(
6269
"is_vertex_on_boundary", &CollisionMesh::is_vertex_on_boundary, "",
6370
py::arg("i"))
64-
.def("vertex_area", &CollisionMesh::vertex_area, "", py::arg("pi"))
71+
.def("vertex_area", &CollisionMesh::vertex_area, "", py::arg("vi"))
6572
.def_property_readonly("vertex_areas", &CollisionMesh::vertex_areas, "")
73+
// TODO: enable these functions when Pybind11 supports
74+
// Eigen::SparseVector
75+
// .def(
76+
// "vertex_area_gradient", &CollisionMesh::vertex_area_gradient, "",
77+
// py::arg("vi"))
6678
.def("edge_area", &CollisionMesh::edge_area, "", py::arg("ei"))
6779
.def_property_readonly("edge_areas", &CollisionMesh::edge_areas, "")
80+
// TODO: enable these functions when Pybind11 supports
81+
// Eigen::SparseVector
82+
// .def(
83+
// "edge_area_gradient", &CollisionMesh::edge_area_gradient, "",
84+
// py::arg("ei"))
85+
.def(
86+
"are_area_jacobians_initialized",
87+
&CollisionMesh::are_area_jacobians_initialized, "")
6888
.def_static(
6989
"construct_is_on_surface", &CollisionMesh::construct_is_on_surface,
7090
"", py::arg("num_vertices"), py::arg("edges"))

src/ipc/collision_mesh.cpp

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,10 @@ CollisionMesh::CollisionMesh(
104104

105105
m_faces_to_edges = construct_faces_to_edges(m_faces, m_edges);
106106

107-
init_adjacencies();
108107
init_areas();
108+
// Compute these manually if needed.
109+
// init_adjacencies();
110+
// init_area_jacobian();
109111
}
110112

111113
///////////////////////////////////////////////////////////////////////////////
@@ -203,66 +205,40 @@ void CollisionMesh::init_areas()
203205
// Compute vertex areas as the sum of ½ the length of connected edges
204206
Eigen::VectorXd vertex_edge_areas =
205207
Eigen::VectorXd::Constant(num_vertices(), -1);
206-
m_vertex_area_jacobian.resize(
207-
num_vertices(), Eigen::SparseVector<double>(ndof()));
208208
for (int i = 0; i < m_edges.rows(); i++) {
209209
const auto& e0 = m_vertices_at_rest.row(m_edges(i, 0));
210210
const auto& e1 = m_vertices_at_rest.row(m_edges(i, 1));
211211
double edge_len = (e1 - e0).norm();
212212

213-
VectorMax6d edge_len_gradient;
214-
edge_length_gradient(e0, e1, edge_len_gradient);
215-
216213
for (int j = 0; j < m_edges.cols(); j++) {
217214
if (vertex_edge_areas[m_edges(i, j)] < 0) {
218215
vertex_edge_areas[m_edges(i, j)] = 0;
219216
}
220217
vertex_edge_areas[m_edges(i, j)] += edge_len / 2;
221-
222-
local_gradient_to_global_gradient(
223-
edge_len_gradient / 2, m_edges.row(i), dim(),
224-
m_vertex_area_jacobian[m_edges(i, j)]);
225218
}
226219
}
227220

228221
// Compute vertex/edge areas as the sum of ⅓ the area of connected face
229222
Eigen::VectorXd vertex_face_areas =
230223
Eigen::VectorXd::Constant(num_vertices(), -1);
231224
m_edge_areas.setConstant(m_edges.rows(), -1);
232-
m_edge_area_jacobian.resize(
233-
m_edges.rows(), Eigen::SparseVector<double>(ndof()));
234225
if (dim() == 3) {
235226
for (int i = 0; i < m_faces.rows(); i++) {
236227
const auto& f0 = m_vertices_at_rest.row(m_faces(i, 0));
237228
const auto& f1 = m_vertices_at_rest.row(m_faces(i, 1));
238229
const auto& f2 = m_vertices_at_rest.row(m_faces(i, 2));
239230
double face_area = cross(f1 - f0, f2 - f0).norm() / 2;
240231

241-
VectorMax9d face_area_gradient;
242-
triangle_area_gradient(f0, f1, f2, face_area_gradient);
243-
244232
for (int j = 0; j < m_faces.cols(); ++j) {
245233
if (vertex_face_areas[m_faces(i, j)] < 0) {
246234
vertex_face_areas[m_faces(i, j)] = 0;
247-
// remove the computed value from vertex_edge_areas
248-
m_vertex_area_jacobian[m_faces(i, j)].setZero();
249235
}
250236
vertex_face_areas[m_faces(i, j)] += face_area / 3;
251237

252238
if (m_edge_areas[m_faces_to_edges(i, j)] < 0) {
253239
m_edge_areas[m_faces_to_edges(i, j)] = 0;
254240
}
255241
m_edge_areas[m_faces_to_edges(i, j)] += face_area / 3;
256-
257-
// compute gradient of area
258-
259-
local_gradient_to_global_gradient(
260-
face_area_gradient / 3, m_faces.row(i), dim(),
261-
m_vertex_area_jacobian[m_faces(i, j)]);
262-
263-
local_gradient_to_global_gradient(
264-
face_area_gradient / 3, m_faces.row(i), dim(),
265-
m_edge_area_jacobian[m_faces_to_edges(i, j)]);
266242
}
267243
}
268244
}
@@ -278,6 +254,59 @@ void CollisionMesh::init_areas()
278254
m_edge_areas = (m_edge_areas.array() < 0).select(1, m_edge_areas);
279255
}
280256

257+
void CollisionMesh::init_area_jacobians()
258+
{
259+
// Compute vertex areas as the sum of ½ the length of connected edges
260+
m_vertex_area_jacobian.resize(
261+
num_vertices(), Eigen::SparseVector<double>(ndof()));
262+
for (int i = 0; i < m_edges.rows(); i++) {
263+
const auto& e0 = m_vertices_at_rest.row(m_edges(i, 0));
264+
const auto& e1 = m_vertices_at_rest.row(m_edges(i, 1));
265+
266+
VectorMax6d edge_len_gradient;
267+
edge_length_gradient(e0, e1, edge_len_gradient);
268+
269+
for (int j = 0; j < m_edges.cols(); j++) {
270+
local_gradient_to_global_gradient(
271+
edge_len_gradient / 2, m_edges.row(i), dim(),
272+
m_vertex_area_jacobian[m_edges(i, j)]);
273+
}
274+
}
275+
276+
// Compute vertex/edge areas as the sum of ⅓ the area of connected face
277+
m_edge_area_jacobian.resize(
278+
m_edges.rows(), Eigen::SparseVector<double>(ndof()));
279+
if (dim() == 3) {
280+
std::vector<bool> visited_vertex_before(num_vertices(), false);
281+
for (int i = 0; i < m_faces.rows(); i++) {
282+
const auto& f0 = m_vertices_at_rest.row(m_faces(i, 0));
283+
const auto& f1 = m_vertices_at_rest.row(m_faces(i, 1));
284+
const auto& f2 = m_vertices_at_rest.row(m_faces(i, 2));
285+
286+
VectorMax9d face_area_gradient;
287+
triangle_area_gradient(f0, f1, f2, face_area_gradient);
288+
289+
for (int j = 0; j < m_faces.cols(); ++j) {
290+
if (!visited_vertex_before[m_faces(i, j)]) {
291+
// remove the computed value from vertex_edge_areas
292+
m_vertex_area_jacobian[m_faces(i, j)].setZero();
293+
visited_vertex_before[m_faces(i, j)] = true;
294+
}
295+
296+
// compute gradient of area
297+
298+
local_gradient_to_global_gradient(
299+
face_area_gradient / 3, m_faces.row(i), dim(),
300+
m_vertex_area_jacobian[m_faces(i, j)]);
301+
302+
local_gradient_to_global_gradient(
303+
face_area_gradient / 3, m_faces.row(i), dim(),
304+
m_edge_area_jacobian[m_faces_to_edges(i, j)]);
305+
}
306+
}
307+
}
308+
}
309+
281310
////////////////////////////////////////////////////////////////////////////////
282311

283312
Eigen::MatrixXd

src/ipc/collision_mesh.hpp

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ class CollisionMesh {
5555
full_vertices_at_rest, edges, faces);
5656
}
5757

58+
// The following functions are used to initialize optional data structures.
59+
60+
/// @brief Initialize vertex-vertex and edge-vertex adjacencies.
61+
void init_adjacencies();
62+
63+
/// @brief Initialize vertex and edge areas.
64+
void init_area_jacobians();
65+
5866
/// @brief Destroy the Collision Mesh object
5967
~CollisionMesh() { }
6068

@@ -152,15 +160,30 @@ class CollisionMesh {
152160
/// @brief Get the vertex-vertex adjacency matrix.
153161
const std::vector<unordered_set<int>>& vertex_vertex_adjacencies() const
154162
{
163+
if (!are_adjacencies_initialized()) {
164+
throw std::runtime_error(
165+
"Vertex-vertex adjacencies not initialized. Call init_adjacencies() first.");
166+
}
155167
return m_vertex_vertex_adjacencies;
156168
}
157169

158170
/// @brief Get the edge-vertex adjacency matrix.
159171
const std::vector<unordered_set<int>>& edge_vertex_adjacencies() const
160172
{
173+
if (!are_adjacencies_initialized()) {
174+
throw std::runtime_error(
175+
"Edge-vertex adjacencies not initialized. Call init_area_jacobians() first.");
176+
}
161177
return m_edge_vertex_adjacencies;
162178
}
163179

180+
/// @brief Determine if the adjacencies have been initialized by calling init_adjacencies().
181+
bool are_adjacencies_initialized() const
182+
{
183+
return !m_vertex_vertex_adjacencies.empty()
184+
&& !m_edge_vertex_adjacencies.empty();
185+
}
186+
164187
/// @brief Is a vertex on the boundary of the collision mesh?
165188
/// @param vi Vertex ID.
166189
/// @return True if the vertex is on the boundary of the collision mesh.
@@ -183,6 +206,10 @@ class CollisionMesh {
183206
const Eigen::SparseVector<double>&
184207
vertex_area_gradient(const size_t vi) const
185208
{
209+
if (!are_area_jacobians_initialized()) {
210+
throw std::runtime_error(
211+
"Vertex area Jacobian not initialized. Call init_area_jacobians() first.");
212+
}
186213
return m_vertex_area_jacobian[vi];
187214
}
188215

@@ -199,9 +226,19 @@ class CollisionMesh {
199226
/// @return Gradient of the barycentric area of edge ei wrt the rest positions of all points.
200227
const Eigen::SparseVector<double>& edge_area_gradient(const size_t ei) const
201228
{
229+
if (!are_area_jacobians_initialized()) {
230+
throw std::runtime_error(
231+
"Edge area Jacobian not initialized. Call init_area_jacobians() first.");
232+
}
202233
return m_edge_area_jacobian[ei];
203234
}
204235

236+
/// @brief Determine if the area Jacobians have been initialized by calling init_area_jacobians().
237+
bool are_area_jacobians_initialized() const
238+
{
239+
return !m_vertex_area_jacobian.empty() && !m_edge_area_jacobian.empty();
240+
}
241+
205242
// -----------------------------------------------------------------------
206243

207244
/// @brief Construct a vector of bools indicating whether each vertex is on the surface.
@@ -231,9 +268,6 @@ class CollisionMesh {
231268
/// @brief Initialize the selection matrix from full vertices/DOF to collision vertices/DOF.
232269
void init_selection_matrices(const int dim);
233270

234-
/// @brief Initialize vertex-vertex and edge-vertex adjacencies.
235-
void init_adjacencies();
236-
237271
/// @brief Initialize vertex and edge areas.
238272
void init_areas();
239273

src/ipc/collisions/constraints.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,7 @@ void Constraints::edge_vertex_candiates_to_constraints(
261261

262262
Eigen::SparseVector<double> weight_gradient;
263263
if (compute_shape_derivatives) {
264+
assert(mesh.are_area_jacobians_initialized());
264265
weight_gradient = use_convergent_formulation
265266
? (mesh.vertex_area_gradient(vi) / 2)
266267
: Eigen::SparseVector<double>(V.size());
@@ -330,6 +331,7 @@ void Constraints::edge_edge_candiates_to_constraints(
330331

331332
Eigen::SparseVector<double> weight_gradient;
332333
if (compute_shape_derivatives) {
334+
assert(mesh.are_area_jacobians_initialized());
333335
weight_gradient = use_convergent_formulation
334336
? ((mesh.edge_area_gradient(eai) + mesh.edge_area_gradient(ebi))
335337
/ 4)
@@ -437,6 +439,7 @@ void Constraints::face_vertex_candiates_to_constraints(
437439

438440
Eigen::SparseVector<double> weight_gradient;
439441
if (compute_shape_derivatives) {
442+
assert(mesh.are_area_jacobians_initialized());
440443
weight_gradient = use_convergent_formulation
441444
? (mesh.vertex_area_gradient(vi) / 4)
442445
: Eigen::SparseVector<double>(V.size());

0 commit comments

Comments
 (0)