35 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)
37 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> trafo = grad_x;
38 for (
int i = 0; i < grad_x.rows(); ++i)
39 for (
int j = 0; j < grad_x.cols(); ++j)
40 trafo(i, j) = trafo(i, j) + grad_u_local(i, j);
42 Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic, 0, 3, 3> trafo_inv =
inverse(trafo);
44 Eigen::Matrix<T, Eigen::Dynamic, 1, 0, 3, 1> n(reference_normal.cols(), 1);
45 for (
int d = 0; d < n.size(); ++d)
48 for (
int i = 0; i < n.size(); ++i)
49 for (
int j = 0; j < n.size(); ++j)
50 n(j) = n(j) + (reference_normal(i) * trafo_inv(i, j));
56 class QuadraticBarrier :
public ipc::Barrier
59 QuadraticBarrier(
const double weight = 1) :
weight_(weight) {}
61 double operator()(
const double d,
const double dhat)
const override
66 return weight_ * (d - dhat) * (d - dhat);
68 double first_derivative(
const double d,
const double dhat)
const override
73 return 2 *
weight_ * (d - dhat);
75 double second_derivative(
const double d,
const double dhat)
const override
82 double units(
const double dhat)
const override
91 void compute_collision_mesh_quantities(
93 const std::set<int> &boundary_ids,
94 const ipc::CollisionMesh &collision_mesh,
95 Eigen::MatrixXd &node_positions,
96 Eigen::MatrixXi &boundary_edges,
97 Eigen::MatrixXi &boundary_triangles,
98 Eigen::SparseMatrix<double> &displacement_map,
99 std::vector<bool> &is_on_surface,
100 Eigen::MatrixXi &can_collide_cache)
102 std::vector<Eigen::Triplet<double>> displacement_map_entries;
104 node_positions, boundary_edges, boundary_triangles, displacement_map_entries);
106 is_on_surface.resize(node_positions.rows(),
false);
108 std::map<int, std::set<int>> boundary_ids_to_dof;
110 Eigen::MatrixXd
points, uv, normals;
111 Eigen::VectorXd weights;
112 Eigen::VectorXi global_primitive_ids;
115 const int e = lb.element_id();
126 for (
int i = 0; i < lb.size(); ++i)
128 const int primitive_global_id = lb.global_primitive_id(i);
130 const int boundary_id = state.
mesh->get_boundary_id(primitive_global_id);
132 if (!std::count(boundary_ids.begin(), boundary_ids.end(), boundary_id))
135 for (
long n = 0; n <
nodes.size(); ++n)
138 is_on_surface[v.
global[0].index] =
true;
139 if (v.
global[0].index >= node_positions.rows())
141 boundary_ids_to_dof[boundary_id].insert(v.
global[0].index);
146 if (!displacement_map_entries.empty())
148 displacement_map.resize(node_positions.rows(), state.
n_bases);
149 displacement_map.setFromTriplets(displacement_map_entries.begin(), displacement_map_entries.end());
153 Eigen::MatrixXi boundary_edges_alt(0, 2), boundary_triangles_alt(0, 3);
155 for (
int i = 0; i < boundary_edges.rows(); ++i)
157 bool on_surface =
true;
158 for (
int j = 0; j < boundary_edges.cols(); ++j)
159 on_surface &= is_on_surface[boundary_edges(i, j)];
162 boundary_edges_alt.conservativeResize(boundary_edges_alt.rows() + 1, 2);
163 boundary_edges_alt.row(boundary_edges_alt.rows() - 1) = boundary_edges.row(i);
167 if (state.
mesh->is_volume())
169 for (
int i = 0; i < boundary_triangles.rows(); ++i)
171 bool on_surface =
true;
172 for (
int j = 0; j < boundary_triangles.cols(); ++j)
173 on_surface &= is_on_surface[boundary_triangles(i, j)];
176 boundary_triangles_alt.conservativeResize(boundary_triangles_alt.rows() + 1, 3);
177 boundary_triangles_alt.row(boundary_triangles_alt.rows() - 1) = boundary_triangles.row(i);
182 boundary_triangles_alt.resize(0, 0);
184 boundary_edges = boundary_edges_alt;
185 boundary_triangles = boundary_triangles_alt;
187 can_collide_cache.resize(0, 0);
188 can_collide_cache.resize(collision_mesh.num_vertices(), collision_mesh.num_vertices());
189 for (
int i = 0; i < can_collide_cache.rows(); ++i)
191 int dof_idx_i = collision_mesh.to_full_vertex_id(i);
192 if (!is_on_surface[dof_idx_i])
194 for (
int j = 0; j < can_collide_cache.cols(); ++j)
196 int dof_idx_j = collision_mesh.to_full_vertex_id(j);
197 if (!is_on_surface[dof_idx_j])
200 bool collision_allowed =
true;
201 for (
const auto &
id : boundary_ids)
202 if (boundary_ids_to_dof[id].count(dof_idx_i) && boundary_ids_to_dof[id].count(dof_idx_j))
203 collision_allowed = false;
204 can_collide_cache(i, j) = collision_allowed;
209 double compute_quantity(
210 const Eigen::MatrixXd &node_positions,
211 const Eigen::MatrixXi &boundary_edges,
212 const Eigen::MatrixXi &boundary_triangles,
213 const Eigen::SparseMatrix<double> &displacement_map,
214 const std::vector<bool> &is_on_surface,
215 const Eigen::MatrixXi &can_collide_cache,
218 std::function<ipc::NormalCollisions(
const Eigen::MatrixXd &)> cs_func,
219 const Eigen::MatrixXd &u,
220 const ipc::BarrierPotential &barrier_potential)
223 ipc::CollisionMesh collision_mesh = ipc::CollisionMesh(is_on_surface,
224 std::vector<bool>(is_on_surface.size(),
false),
230 collision_mesh.can_collide = [&can_collide_cache](
size_t vi,
size_t vj) {
232 return (
bool)can_collide_cache(vi, vj);
235 collision_mesh.init_area_jacobians();
237 Eigen::MatrixXd displaced_surface = collision_mesh.displace_vertices(
utils::unflatten(u, collision_mesh.dim()));
239 ipc::NormalCollisions cs_ = cs_func(displaced_surface);
240 cs_.build(collision_mesh, displaced_surface, dhat, dmin, ipc::create_broad_phase(ipc::BroadPhaseMethod::HASH_GRID).get());
242 Eigen::MatrixXd forces = collision_mesh.to_full_dof(barrier_potential.gradient(cs_, collision_mesh, displaced_surface));
244 double sum = (forces.array() * forces.array()).sum();
805 std::shared_ptr<const legacy::State> state,
806 std::shared_ptr<const DiffCache> diff_cache,
808 const bool quadratic_potential,
811 state_(std::move(state)),
812 diff_cache_(std::move(diff_cache)),
815 barrier_potential_(dhat, 1.0, true)
817 auto tmp_ids = args[
"surface_selection"].get<std::vector<int>>();
824 if (
state_->problem->is_time_dependent())
826 int time_steps =
state_->args[
"time"][
"time_steps"].get<
int>() + 1;
828 for (
int i = 0; i < time_steps + 1; ++i)
846 if (quadratic_potential)
857 Eigen::MatrixXi boundary_edges, boundary_triangles;
858 std::vector<Eigen::Triplet<double>> displacement_map_entries;
860 node_positions_, boundary_edges, boundary_triangles, displacement_map_entries);
862 std::vector<bool> is_on_surface;
866 Eigen::MatrixXd points, uv, normals;
867 Eigen::VectorXd weights;
868 Eigen::VectorXi global_primitive_ids;
869 for (
const auto &lb :
state_->total_local_boundary)
871 const int e = lb.element_id();
882 for (
int i = 0; i < lb.size(); ++i)
884 const int primitive_global_id = lb.global_primitive_id(i);
886 const int boundary_id =
state_->mesh->get_boundary_id(primitive_global_id);
891 for (
long n = 0; n < nodes.size(); ++n)
894 is_on_surface[v.
global[0].index] =
true;
902 Eigen::SparseMatrix<double> displacement_map;
903 if (!displacement_map_entries.empty())
906 displacement_map.setFromTriplets(displacement_map_entries.begin(), displacement_map_entries.end());
910 Eigen::MatrixXi boundary_edges_alt(0, 2), boundary_triangles_alt(0, 3);
912 for (
int i = 0; i < boundary_edges.rows(); ++i)
914 bool on_surface =
true;
915 for (
int j = 0; j < boundary_edges.cols(); ++j)
916 on_surface &= is_on_surface[boundary_edges(i, j)];
919 boundary_edges_alt.conservativeResize(boundary_edges_alt.rows() + 1, 2);
920 boundary_edges_alt.row(boundary_edges_alt.rows() - 1) = boundary_edges.row(i);
924 if (
state_->mesh->is_volume())
926 for (
int i = 0; i < boundary_triangles.rows(); ++i)
928 bool on_surface =
true;
929 for (
int j = 0; j < boundary_triangles.cols(); ++j)
930 on_surface &= is_on_surface[boundary_triangles(i, j)];
933 boundary_triangles_alt.conservativeResize(boundary_triangles_alt.rows() + 1, 3);
934 boundary_triangles_alt.row(boundary_triangles_alt.rows() - 1) = boundary_triangles.row(i);
939 boundary_triangles_alt.resize(0, 0);
943 std::vector<bool>(is_on_surface.size(),
false),
946 boundary_triangles_alt,
953 if (!is_on_surface[dof_idx_i])
958 if (!is_on_surface[dof_idx_j])
961 bool collision_allowed =
true;
964 collision_allowed =
false;
990 assert(
state_->solve_data.time_integrator !=
nullptr);
991 assert(
state_->solve_data.contact_form !=
nullptr);
998 double sum = (forces.array() * forces.array()).sum();
1005 assert(
state_->solve_data.time_integrator !=
nullptr);
1006 assert(
state_->solve_data.contact_form !=
nullptr);
1014 Eigen::VectorXd gradu = 2 * hessian.transpose() * forces;
1041 assert(
state_->solve_data.time_integrator !=
nullptr);
1042 assert(
state_->solve_data.contact_form !=
nullptr);
1053 Eigen::VectorXd grads = 2 * shape_derivative.transpose() * forces;
1087 grads =
diff_cache_->basis_nodes_to_gbasis_nodes() * grads;
ElementAssemblyValues vals
Storage for additional data required by differntial code.
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
main class that contains the polyfem solver and all its state
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
int n_bases
number of bases
QuadratureOrders n_boundary_samples() const
quadrature used for projecting boundary conditions
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
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
Eigen::VectorXd apply_parametrization_jacobian(ParameterType type, const legacy::State &target, const Eigen::VectorXd &x, const std::function< Eigen::VectorXd()> &grad) const
Compute parametrization jacobian for all var2sim matching parameter type and output to target state.
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.