34 Eigen::Matrix<T, Eigen::Dynamic, 1, 0, 3, 1> compute_displaced_normal(
const Eigen::MatrixXd &reference_normal,
const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> &grad_x,
const Eigen::MatrixXd &grad_u_local)
36 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> trafo = grad_x;
37 for (
int i = 0; i < grad_x.rows(); ++i)
38 for (
int j = 0; j < grad_x.cols(); ++j)
39 trafo(i, j) = trafo(i, j) + grad_u_local(i, j);
41 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> trafo_inv =
inverse(trafo);
43 Eigen::Matrix<T, Eigen::Dynamic, 1, 0, 3, 1> n(reference_normal.cols(), 1);
44 for (
int d = 0; d < n.size(); ++d)
47 for (
int i = 0; i < n.size(); ++i)
48 for (
int j = 0; j < n.size(); ++j)
49 n(j) = n(j) + (reference_normal(i) * trafo_inv(i, j));
55 class QuadraticBarrier :
public ipc::Barrier
58 QuadraticBarrier(
const double weight = 1) :
weight_(weight) {}
60 double operator()(
const double d,
const double dhat)
const override
65 return weight_ * (d - dhat) * (d - dhat);
67 double first_derivative(
const double d,
const double dhat)
const override
72 return 2 *
weight_ * (d - dhat);
74 double second_derivative(
const double d,
const double dhat)
const override
81 double units(
const double dhat)
const override
90 void compute_collision_mesh_quantities(
92 const std::set<int> &boundary_ids,
93 const ipc::CollisionMesh &collision_mesh,
94 Eigen::MatrixXd &node_positions,
95 Eigen::MatrixXi &boundary_edges,
96 Eigen::MatrixXi &boundary_triangles,
97 Eigen::SparseMatrix<double> &displacement_map,
98 std::vector<bool> &is_on_surface,
99 Eigen::MatrixXi &can_collide_cache)
101 std::vector<Eigen::Triplet<double>> displacement_map_entries;
103 node_positions, boundary_edges, boundary_triangles, displacement_map_entries);
105 is_on_surface.resize(node_positions.rows(),
false);
107 std::map<int, std::set<int>> boundary_ids_to_dof;
109 Eigen::MatrixXd
points, uv, normals;
110 Eigen::VectorXd weights;
111 Eigen::VectorXi global_primitive_ids;
114 const int e = lb.element_id();
125 for (
int i = 0; i < lb.size(); ++i)
127 const int primitive_global_id = lb.global_primitive_id(i);
129 const int boundary_id = state.
mesh->get_boundary_id(primitive_global_id);
131 if (!std::count(boundary_ids.begin(), boundary_ids.end(), boundary_id))
134 for (
long n = 0; n <
nodes.size(); ++n)
137 is_on_surface[v.
global[0].index] =
true;
138 if (v.
global[0].index >= node_positions.rows())
140 boundary_ids_to_dof[boundary_id].insert(v.
global[0].index);
145 if (!displacement_map_entries.empty())
147 displacement_map.resize(node_positions.rows(), state.
n_bases);
148 displacement_map.setFromTriplets(displacement_map_entries.begin(), displacement_map_entries.end());
152 Eigen::MatrixXi boundary_edges_alt(0, 2), boundary_triangles_alt(0, 3);
154 for (
int i = 0; i < boundary_edges.rows(); ++i)
156 bool on_surface =
true;
157 for (
int j = 0; j < boundary_edges.cols(); ++j)
158 on_surface &= is_on_surface[boundary_edges(i, j)];
161 boundary_edges_alt.conservativeResize(boundary_edges_alt.rows() + 1, 2);
162 boundary_edges_alt.row(boundary_edges_alt.rows() - 1) = boundary_edges.row(i);
166 if (state.
mesh->is_volume())
168 for (
int i = 0; i < boundary_triangles.rows(); ++i)
170 bool on_surface =
true;
171 for (
int j = 0; j < boundary_triangles.cols(); ++j)
172 on_surface &= is_on_surface[boundary_triangles(i, j)];
175 boundary_triangles_alt.conservativeResize(boundary_triangles_alt.rows() + 1, 3);
176 boundary_triangles_alt.row(boundary_triangles_alt.rows() - 1) = boundary_triangles.row(i);
181 boundary_triangles_alt.resize(0, 0);
183 boundary_edges = boundary_edges_alt;
184 boundary_triangles = boundary_triangles_alt;
186 can_collide_cache.resize(0, 0);
187 can_collide_cache.resize(collision_mesh.num_vertices(), collision_mesh.num_vertices());
188 for (
int i = 0; i < can_collide_cache.rows(); ++i)
190 int dof_idx_i = collision_mesh.to_full_vertex_id(i);
191 if (!is_on_surface[dof_idx_i])
193 for (
int j = 0; j < can_collide_cache.cols(); ++j)
195 int dof_idx_j = collision_mesh.to_full_vertex_id(j);
196 if (!is_on_surface[dof_idx_j])
199 bool collision_allowed =
true;
200 for (
const auto &
id : boundary_ids)
201 if (boundary_ids_to_dof[id].count(dof_idx_i) && boundary_ids_to_dof[id].count(dof_idx_j))
202 collision_allowed = false;
203 can_collide_cache(i, j) = collision_allowed;
208 double compute_quantity(
209 const Eigen::MatrixXd &node_positions,
210 const Eigen::MatrixXi &boundary_edges,
211 const Eigen::MatrixXi &boundary_triangles,
212 const Eigen::SparseMatrix<double> &displacement_map,
213 const std::vector<bool> &is_on_surface,
214 const Eigen::MatrixXi &can_collide_cache,
217 std::function<ipc::NormalCollisions(
const Eigen::MatrixXd &)> cs_func,
218 const Eigen::MatrixXd &u,
219 const ipc::BarrierPotential &barrier_potential)
222 ipc::CollisionMesh collision_mesh = ipc::CollisionMesh(is_on_surface,
223 std::vector<bool>(is_on_surface.size(),
false),
229 collision_mesh.can_collide = [&can_collide_cache](
size_t vi,
size_t vj) {
231 return (
bool)can_collide_cache(vi, vj);
234 collision_mesh.init_area_jacobians();
236 Eigen::MatrixXd displaced_surface = collision_mesh.displace_vertices(
utils::unflatten(u, collision_mesh.dim()));
238 ipc::NormalCollisions cs_ = cs_func(displaced_surface);
239 cs_.build(collision_mesh, displaced_surface, dhat, dmin, ipc::create_broad_phase(ipc::BroadPhaseMethod::HASH_GRID));
241 Eigen::MatrixXd forces = collision_mesh.to_full_dof(barrier_potential.gradient(cs_, collision_mesh, displaced_surface));
243 double sum = (forces.array() * forces.array()).sum();
804 std::shared_ptr<const State> state,
805 std::shared_ptr<const DiffCache> diff_cache,
807 const bool quadratic_potential,
810 state_(std::move(state)),
811 diff_cache_(std::move(diff_cache)),
814 barrier_potential_(dhat, true)
816 auto tmp_ids = args[
"surface_selection"].get<std::vector<int>>();
823 if (
state_->problem->is_time_dependent())
825 int time_steps =
state_->args[
"time"][
"time_steps"].get<
int>() + 1;
827 for (
int i = 0; i < time_steps + 1; ++i)
845 if (quadratic_potential)
856 Eigen::MatrixXi boundary_edges, boundary_triangles;
857 std::vector<Eigen::Triplet<double>> displacement_map_entries;
859 node_positions_, boundary_edges, boundary_triangles, displacement_map_entries);
861 std::vector<bool> is_on_surface;
865 Eigen::MatrixXd points, uv, normals;
866 Eigen::VectorXd weights;
867 Eigen::VectorXi global_primitive_ids;
868 for (
const auto &lb :
state_->total_local_boundary)
870 const int e = lb.element_id();
881 for (
int i = 0; i < lb.size(); ++i)
883 const int primitive_global_id = lb.global_primitive_id(i);
885 const int boundary_id =
state_->mesh->get_boundary_id(primitive_global_id);
890 for (
long n = 0; n < nodes.size(); ++n)
893 is_on_surface[v.
global[0].index] =
true;
901 Eigen::SparseMatrix<double> displacement_map;
902 if (!displacement_map_entries.empty())
905 displacement_map.setFromTriplets(displacement_map_entries.begin(), displacement_map_entries.end());
909 Eigen::MatrixXi boundary_edges_alt(0, 2), boundary_triangles_alt(0, 3);
911 for (
int i = 0; i < boundary_edges.rows(); ++i)
913 bool on_surface =
true;
914 for (
int j = 0; j < boundary_edges.cols(); ++j)
915 on_surface &= is_on_surface[boundary_edges(i, j)];
918 boundary_edges_alt.conservativeResize(boundary_edges_alt.rows() + 1, 2);
919 boundary_edges_alt.row(boundary_edges_alt.rows() - 1) = boundary_edges.row(i);
923 if (
state_->mesh->is_volume())
925 for (
int i = 0; i < boundary_triangles.rows(); ++i)
927 bool on_surface =
true;
928 for (
int j = 0; j < boundary_triangles.cols(); ++j)
929 on_surface &= is_on_surface[boundary_triangles(i, j)];
932 boundary_triangles_alt.conservativeResize(boundary_triangles_alt.rows() + 1, 3);
933 boundary_triangles_alt.row(boundary_triangles_alt.rows() - 1) = boundary_triangles.row(i);
938 boundary_triangles_alt.resize(0, 0);
942 std::vector<bool>(is_on_surface.size(),
false),
945 boundary_triangles_alt,
952 if (!is_on_surface[dof_idx_i])
957 if (!is_on_surface[dof_idx_j])
960 bool collision_allowed =
true;
963 collision_allowed =
false;
989 assert(
state_->solve_data.time_integrator !=
nullptr);
990 assert(
state_->solve_data.contact_form !=
nullptr);
997 double sum = (forces.array() * forces.array()).sum();
1004 assert(
state_->solve_data.time_integrator !=
nullptr);
1005 assert(
state_->solve_data.contact_form !=
nullptr);
1013 Eigen::VectorXd gradu = 2 * hessian.transpose() * forces;
1040 assert(
state_->solve_data.time_integrator !=
nullptr);
1041 assert(
state_->solve_data.contact_form !=
nullptr);
1044 const Eigen::MatrixXd displaced_surface = collision_mesh_.displace_vertices(utils::unflatten(diff_cache_->u(time_step), collision_mesh_.dim()));
1046 auto collision_set = get_or_compute_collision_set(time_step, displaced_surface);
1048 Eigen::MatrixXd forces = collision_mesh_.to_full_dof(barrier_potential_.gradient(collision_set, collision_mesh_, displaced_surface));
1050 StiffnessMatrix shape_derivative = collision_mesh_.to_full_dof(barrier_potential_.shape_derivative(collision_set, collision_mesh_, displaced_surface));
1052 Eigen::VectorXd grads = 2 * shape_derivative.transpose() * forces;
1086 grads = diff_cache_->basis_nodes_to_gbasis_nodes() * grads;
1088 return AdjointTools::map_node_to_primitive_order(*state_, grads);
ElementAssemblyValues vals
Storage for additional data required by differntial code.
main class that contains the polyfem solver and all its state
int n_bases
number of bases
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
std::vector< mesh::LocalBoundary > total_local_boundary
mapping from elements to nodes for all mesh
QuadratureOrders n_boundary_samples() const
quadrature used for projecting boundary conditions
stores per local bases evaluations
std::vector< basis::Local2Global > global
stores per element basis values at given quadrature points and geometric mapping
std::vector< AssemblyValues > basis_values
void compute(const int el_index, const bool is_volume, const Eigen::MatrixXd &pts, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
computes the per element values at the local (ref el) points (pts) sets basis_values,...
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
Eigen::VectorXi local_nodes_for_primitive(const int local_index, const mesh::Mesh &mesh) const
std::vector< Basis > bases
one basis function per node in the element
static void extract_boundary_mesh(const mesh::Mesh &mesh, const int n_bases, const std::vector< basis::ElementBases > &bases, const std::vector< mesh::LocalBoundary > &total_local_boundary, Eigen::MatrixXd &node_positions, Eigen::MatrixXi &boundary_edges, Eigen::MatrixXi &boundary_triangles, std::vector< Eigen::Triplet< double > > &displacement_map_entries)
extracts the boundary mesh
A collection of VariableToSimulation.
virtual Eigen::VectorXd apply_parametrization_jacobian(const ParameterType type, const State *state_ptr, const Eigen::VectorXd &x, const std::function< Eigen::VectorXd()> &grad) const
Maps the partial gradient wrt.
static bool boundary_quadrature(const mesh::LocalBoundary &local_boundary, const QuadratureOrders &order, const mesh::Mesh &mesh, const bool skip_computation, Eigen::MatrixXd &uv, Eigen::MatrixXd &points, Eigen::MatrixXd &normals, Eigen::VectorXd &weights, Eigen::VectorXi &global_primitive_ids)
DScalar1< double, Eigen::Matrix< double, Eigen::Dynamic, 1 > > Diff
Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > inverse(const Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3 > &mat)
Eigen::MatrixXd unflatten(const Eigen::VectorXd &x, int dim)
Unflatten rowwises, so every dim elements in x become a row.
void log_and_throw_adjoint_error(const std::string &msg)
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Automatic differentiation scalar with first-order derivatives.