PolyFEM
Loading...
Searching...
No Matches
DifferentiableVarForm.cpp
Go to the documentation of this file.
2
8
9namespace polyfem::varform
10{
11 const ipc::CollisionMesh &DifferentiableVarForm::collision_mesh() const
12 {
13 log_and_throw_error("Variational formulation {} does not expose a collision mesh.", name());
14 }
15
17 {
18 log_and_throw_error("Variational formulation {} does not expose an obstacle.", name());
19 }
20
22 {
23 log_and_throw_error("Variational formulation {} does not expose an initial solution.", name());
24 }
25
27 {
28 log_and_throw_error("Variational formulation {} does not expose an initial velocity.", name());
29 }
30
32 {
33 log_and_throw_error("Variational formulation {} does not expose an initial acceleration.", name());
34 }
35
37 {
38 return Eigen::MatrixXd::Zero(get_mesh().dimension(), get_mesh().dimension());
39 }
40
41 void DifferentiableVarForm::get_vertices(Eigen::MatrixXd &vertices) const
42 {
43 vertices.resize(get_mesh().n_vertices(), get_mesh().dimension());
44 for (int v = 0; v < get_mesh().n_vertices(); ++v)
45 vertices.row(v) = get_mesh().point(v);
46 }
47
48 std::unordered_map<int, std::array<bool, 3>> DifferentiableVarForm::boundary_conditions_ids(const std::string &bc_type) const
49 {
50 assert(get_args()["boundary_conditions"].contains(bc_type) && "Requested boundary-condition type must exist");
51 const std::vector<json> json_bcs = utils::json_as_array(get_args()["boundary_conditions"][bc_type]);
52 std::unordered_map<int, std::array<bool, 3>> bcs;
53 for (const json &bc : json_bcs)
54 {
55 assert(bc["dimension"].size() >= get_mesh().dimension() && "Boundary-condition dimensions must cover the mesh dimension");
56 std::array<bool, 3> dimension{{true, true, true}};
57 for (int d = 0; d < bc["dimension"].size(); ++d)
58 dimension[d] = bc["dimension"][d];
59 assert(bc.contains("id") && bc["id"].is_number_integer() && "Boundary conditions must have an integer id");
60 bcs[bc["id"].get<int>()] = dimension;
61 }
62 return bcs;
63 }
64
66 {
67 return get_args().contains("/constraints/macro_displacement_gradient"_json_pointer);
68 }
69
71 {
72 return get_args().contains("/boundary_conditions/periodic"_json_pointer)
73 && !get_args().at("/boundary_conditions/periodic"_json_pointer).empty();
74 }
75
77 {
78 const int dim = get_mesh().dimension();
79 const json &conditions = get_args().at("/boundary_conditions/periodic"_json_pointer);
80 Eigen::MatrixXd offsets(dim, conditions.size());
81 for (int i = 0; i < int(conditions.size()); ++i)
82 {
83 const json &condition = conditions[i];
84 if (!condition.contains("boundary_ids")
85 || !condition["boundary_ids"].is_array()
86 || condition["boundary_ids"].size() != 2)
87 {
89 "Periodic boundary condition {} must contain exactly two boundary_ids.", i);
90 }
91 const std::array<int, 2> boundary_ids = {{condition["boundary_ids"][0].get<int>(),
92 condition["boundary_ids"][1].get<int>()}};
94 primary_space().ndof(), primary_space().value_dim, get_mesh(),
95 primary_space().basis_list(), boundary_state().total_local_boundary,
96 boundary_ids, condition.value("tolerance", 1e-5));
97 offsets.col(i) = mapping.translation.transpose();
98 }
99 return offsets;
100 }
101
103 {
104 return get_args()["contact"]["adhesion"]["adhesion_enabled"];
105 }
106
108 {
109 return !get_args()["boundary_conditions"]["pressure_boundary"].empty()
110 || !get_args()["boundary_conditions"]["pressure_cavity"].empty();
111 }
112
114 {
115 return !get_args()["constraints"]["hard"].empty()
116 || !get_args()["constraints"]["soft"].empty();
117 }
118
123
125 {
126 const FESpace &space = primary_space();
128 get_mesh().is_volume(), space.n_bases, space.basis_list(), space.geometry_basis_list(),
129 assembly_cache(), 0, stiffness);
130 }
131
133 {
134 const FESpace &space = primary_space();
135 assert(space.geometry && "Node mapping requires an initialized geometry mapping");
136 const auto &mesh_nodes = space.geometry->mesh_nodes;
137 if (!mesh_nodes)
138 log_and_throw_error("Variational formulation {} does not expose a primitive-to-node mapping.", name());
139 std::vector<int> indices = mesh_nodes->primitive_to_node();
140 assert(indices.size() >= get_mesh().n_vertices() && "Primitive-to-node mapping must contain every mesh vertex");
141 indices.resize(get_mesh().n_vertices());
142 return indices;
143 }
144
146 {
147 const std::vector<int> p2n = primitive_to_node();
148 assert(primary_space().geometry && "Node mapping requires an initialized geometry mapping");
149 assert(primary_space().geometry->n_bases == p2n.size() && "Optimization requires first-order geometry bases");
150 std::vector<int> indices(p2n.size());
151 for (int i = 0; i < p2n.size(); ++i)
152 {
153 assert(p2n[i] >= 0 && p2n[i] < indices.size() && "Primitive-to-node entries must be valid node indices");
154 indices[p2n[i]] = i;
155 }
156 return indices;
157 }
158
159 void DifferentiableVarForm::get_elements(Eigen::MatrixXi &elements) const
160 {
161 if (!get_mesh().is_simplicial())
162 log_and_throw_error("Element extraction requires a simplicial mesh.");
163 const std::vector<int> n2p = node_to_primitive();
164 const auto &geometry_bases = primary_space().geometry_basis_list();
165 elements.resize(geometry_bases.size(), get_mesh().dimension() + 1);
166 for (int e = 0; e < geometry_bases.size(); ++e)
167 {
168 int i = 0;
169 for (const auto &basis : geometry_bases[e].bases)
170 elements(e, i++) = n2p[basis.global()[0].index];
171 }
172 }
173
175 {
176 const FESpace &space = primary_space();
177 assert(space.disc_orders.size() > 0 && "Boundary quadrature requires initialized FE orders");
178 assert(space.geometry && "Boundary quadrature requires an initialized geometry mapping");
179 assert(space.geometry->disc_orders.size() > 0 && "Boundary quadrature requires initialized geometry orders");
180 const int geometry_discr_order = get_mesh().orders().size() <= 0 ? 1 : get_mesh().orders().maxCoeff();
181 return boundary_samples(space.disc_orders.maxCoeff(), space.disc_ordersq.maxCoeff(), geometry_discr_order);
182 }
183
184 void DifferentiableVarForm::set_vertex_positions(const Eigen::MatrixXd &vertices)
185 {
186 mesh::Mesh &mesh = mutable_mesh();
187 if (vertices.rows() != mesh.n_vertices() || vertices.cols() != mesh.dimension())
189 "Invalid vertex matrix shape ({}, {}), expected ({}, {}).",
190 vertices.rows(), vertices.cols(), mesh.n_vertices(), mesh.dimension());
191 for (int i = 0; i < vertices.rows(); ++i)
192 mesh.set_point(i, vertices.row(i));
194 }
195
196 void DifferentiableVarForm::set_lame_parameters(const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu)
197 {
198 if (lambda.size() != get_mesh().n_elements() || mu.size() != get_mesh().n_elements())
199 log_and_throw_error("Lamé parameter vectors must contain one value per element.");
200 const_cast<assembler::Assembler &>(primary_assembler()).update_lame_params(lambda, mu);
202 }
203
205 {
206 get_args()["contact"]["friction_coefficient"] = coefficient;
208 }
209
210 void DifferentiableVarForm::set_damping_coefficients(const double psi, const double phi)
211 {
212 auto update_material = [psi, phi](json &material) {
213 material["psi"] = psi;
214 material["phi"] = phi;
215 };
216 if (get_args()["materials"].is_array())
217 {
218 for (auto &material : get_args()["materials"])
219 update_material(material);
220 }
221 else
222 update_material(get_args()["materials"]);
224 }
225
226 void DifferentiableVarForm::set_dirichlet_boundary(const int boundary_id, const int time_step, const Eigen::VectorXd &value)
227 {
228 auto *tensor_problem = dynamic_cast<assembler::GenericTensorProblem *>(&get_problem());
229 if (!tensor_problem)
230 log_and_throw_error("Dirichlet boundary updates require a generic tensor problem.");
231 tensor_problem->update_dirichlet_boundary(boundary_id, time_step, value);
233 }
234
235 void DifferentiableVarForm::set_dirichlet_nodes(const Eigen::VectorXi &input_nodes, const Eigen::MatrixXd &values)
236 {
237 auto *tensor_problem = dynamic_cast<assembler::GenericTensorProblem *>(&get_problem());
238 if (!tensor_problem)
239 log_and_throw_error("Nodal Dirichlet updates require a generic tensor problem.");
240 tensor_problem->update_dirichlet_nodes(primary_space().space_in_node_to_node, input_nodes, values);
242 }
243
244 void DifferentiableVarForm::set_pressure_boundary(const int boundary_id, const int time_step, const double value)
245 {
246 auto *tensor_problem = dynamic_cast<assembler::GenericTensorProblem *>(&get_problem());
247 if (!tensor_problem)
248 log_and_throw_error("Pressure updates require a generic tensor problem.");
249 tensor_problem->update_pressure_boundary(boundary_id, time_step, value);
251 }
252} // namespace polyfem::varform
virtual void assemble(const bool is_volume, const int n_basis, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, StiffnessMatrix &stiffness, const bool is_mass=false) const
Definition Assembler.hpp:70
virtual bool is_linear() const =0
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:49
virtual int n_vertices() const =0
number of vertices
virtual void set_point(const int global_index, const RowVectorNd &p)=0
Set the point.
virtual RowVectorNd point(const int global_index) const =0
point coordinates
const Eigen::MatrixXi & orders() const
order of each element
Definition Mesh.hpp:296
int dimension() const
utily for dimension
Definition Mesh.hpp:164
static Mapping build_mapping(int ndof, int value_dim, const mesh::Mesh &mesh, const std::vector< basis::ElementBases > &bases, const std::vector< mesh::LocalBoundary > &local_boundary, const std::array< int, 2 > &boundary_ids, double relative_tolerance)
virtual const assembler::AssemblyValsCache & assembly_cache() const =0
virtual Eigen::MatrixXd displacement_gradient() const
virtual std::string name() const =0
virtual void set_pressure_boundary(int boundary_id, int time_step, double value)
void build_stiffness_matrix(StiffnessMatrix &stiffness) const
virtual void set_lame_parameters(const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu)
virtual const assembler::Assembler & primary_assembler() const =0
virtual const VarFormBoundaryState & boundary_state() const =0
void set_vertex_positions(const Eigen::MatrixXd &vertices)
virtual void initial_solution(Eigen::MatrixXd &solution, const InitialConditionOverride *override=nullptr) const
virtual const mesh::Mesh & get_mesh() const =0
virtual const mesh::Obstacle & get_obstacle() const
virtual void invalidate_after_parameter_update()=0
void get_elements(Eigen::MatrixXi &elements) const
std::unordered_map< int, std::array< bool, 3 > > boundary_conditions_ids(const std::string &bc_type) const
virtual assembler::Problem & get_problem()=0
virtual QuadratureOrders boundary_samples(int discr_order, int discr_orderq, int geometry_discr_order) const =0
virtual bool is_contact_enabled() const =0
virtual void set_damping_coefficients(double psi, double phi)
virtual void set_dirichlet_boundary(int boundary_id, int time_step, const Eigen::VectorXd &value)
virtual mesh::Mesh & mutable_mesh()=0
virtual void invalidate_after_geometry_update()=0
virtual const FESpace & primary_space() const =0
void get_vertices(Eigen::MatrixXd &vertices) const
virtual void set_dirichlet_nodes(const Eigen::VectorXi &input_nodes, const Eigen::MatrixXd &values)
virtual const ipc::CollisionMesh & collision_mesh() const
virtual void set_friction_coefficient(double coefficient)
virtual void initial_acceleration(Eigen::MatrixXd &acceleration, const InitialConditionOverride *override=nullptr) const
virtual void initial_velocity(Eigen::MatrixXd &velocity, const InitialConditionOverride *override=nullptr) const
A finite-element space for one scalar- or vector-valued field.
Definition FESpace.hpp:59
const std::vector< basis::ElementBases > & geometry_basis_list() const
Definition FESpace.hpp:115
std::shared_ptr< GeometryMapping > geometry
Geometric mapping used to integrate this FE space.
Definition FESpace.hpp:89
Eigen::VectorXi disc_orders
Primary polynomial degree for each mesh element.
Definition FESpace.hpp:71
Eigen::VectorXi disc_ordersq
Secondary polynomial degree for anisotropic bases, e.g. prisms.
Definition FESpace.hpp:74
int n_bases
Number of globally indexed scalar basis functions in the space.
Definition FESpace.hpp:65
const std::vector< basis::ElementBases > & basis_list() const
Definition FESpace.hpp:109
std::vector< T > json_as_array(const json &j)
Return the value of a json object as an array.
Definition JSONUtils.hpp:41
std::array< int, 2 > QuadratureOrders
Definition Types.hpp:19
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_adjoint_error(const std::string &msg)
Definition Logger.cpp:79
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix
Definition Types.hpp:24