PolyFEM
Loading...
Searching...
No Matches
DifferentiableVarForm.cpp
Go to the documentation of this file.
2
8
9namespace polyfem::varform
10{
11 void DifferentiableVarForm::replace_mesh(const std::string &path)
12 {
13 log_and_throw_error("Mesh replacement is not supported by {}.", name());
14 }
15
16 const ipc::CollisionMesh &DifferentiableVarForm::collision_mesh() const
17 {
18 log_and_throw_error("Variational formulation {} does not expose a collision mesh.", name());
19 }
20
22 {
23 log_and_throw_error("Variational formulation {} does not expose an obstacle.", name());
24 }
25
27 {
28 log_and_throw_error("Variational formulation {} does not expose an initial solution.", name());
29 }
30
32 {
33 log_and_throw_error("Variational formulation {} does not expose an initial velocity.", name());
34 }
35
37 {
38 log_and_throw_error("Variational formulation {} does not expose an initial acceleration.", name());
39 }
40
42 {
43 return Eigen::MatrixXd::Zero(get_mesh().dimension(), get_mesh().dimension());
44 }
45
46 void DifferentiableVarForm::get_vertices(Eigen::MatrixXd &vertices) const
47 {
48 vertices.resize(get_mesh().n_vertices(), get_mesh().dimension());
49 for (int v = 0; v < get_mesh().n_vertices(); ++v)
50 vertices.row(v) = get_mesh().point(v);
51 }
52
53 std::unordered_map<int, std::array<bool, 3>> DifferentiableVarForm::boundary_conditions_ids(const std::string &bc_type) const
54 {
55 assert(get_args()["boundary_conditions"].contains(bc_type) && "Requested boundary-condition type must exist");
56 const std::vector<json> json_bcs = utils::json_as_array(get_args()["boundary_conditions"][bc_type]);
57 std::unordered_map<int, std::array<bool, 3>> bcs;
58 for (const json &bc : json_bcs)
59 {
60 assert(bc["dimension"].size() >= get_mesh().dimension() && "Boundary-condition dimensions must cover the mesh dimension");
61 std::array<bool, 3> dimension{{true, true, true}};
62 for (int d = 0; d < bc["dimension"].size(); ++d)
63 dimension[d] = bc["dimension"][d];
64 assert(bc.contains("id") && bc["id"].is_number_integer() && "Boundary conditions must have an integer id");
65 bcs[bc["id"].get<int>()] = dimension;
66 }
67 return bcs;
68 }
69
71 {
72 return get_args().contains("/constraints/macro_displacement_gradient"_json_pointer);
73 }
74
76 {
77 return get_args().contains("/boundary_conditions/periodic"_json_pointer)
78 && !get_args().at("/boundary_conditions/periodic"_json_pointer).empty();
79 }
80
82 {
83 const int dim = get_mesh().dimension();
84 const json &conditions = get_args().at("/boundary_conditions/periodic"_json_pointer);
85 Eigen::MatrixXd offsets(dim, conditions.size());
86 for (int i = 0; i < int(conditions.size()); ++i)
87 {
88 const json &condition = conditions[i];
89 if (!condition.contains("boundary_ids")
90 || !condition["boundary_ids"].is_array()
91 || condition["boundary_ids"].size() != 2)
92 {
94 "Periodic boundary condition {} must contain exactly two boundary_ids.", i);
95 }
96 const std::array<int, 2> boundary_ids = {{condition["boundary_ids"][0].get<int>(),
97 condition["boundary_ids"][1].get<int>()}};
99 primary_space().ndof(), primary_space().value_dim, get_mesh(),
100 primary_space().basis_list(), boundary_state().total_local_boundary,
101 boundary_ids, condition.value("tolerance", 1e-5));
102 offsets.col(i) = mapping.translation.transpose();
103 }
104 return offsets;
105 }
106
108 {
109 return get_args()["contact"]["adhesion"]["adhesion_enabled"];
110 }
111
113 {
114 return !get_args()["boundary_conditions"]["pressure_boundary"].empty()
115 || !get_args()["boundary_conditions"]["pressure_cavity"].empty();
116 }
117
119 {
120 return !get_args()["constraints"]["hard"].empty()
121 || !get_args()["constraints"]["soft"].empty();
122 }
123
128
130 {
131 const FESpace &space = primary_space();
133 get_mesh().is_volume(), space.n_bases, space.basis_list(), space.geometry_basis_list(),
134 assembly_cache(), 0, stiffness);
135 }
136
138 {
139 const FESpace &space = primary_space();
140 assert(space.geometry && "Node mapping requires an initialized geometry mapping");
141 const auto &mesh_nodes = space.geometry->mesh_nodes;
142 if (!mesh_nodes)
143 log_and_throw_error("Variational formulation {} does not expose a primitive-to-node mapping.", name());
144 std::vector<int> indices = mesh_nodes->primitive_to_node();
145 assert(indices.size() >= get_mesh().n_vertices() && "Primitive-to-node mapping must contain every mesh vertex");
146 indices.resize(get_mesh().n_vertices());
147 return indices;
148 }
149
151 {
152 const std::vector<int> p2n = primitive_to_node();
153 assert(primary_space().geometry && "Node mapping requires an initialized geometry mapping");
154 assert(primary_space().geometry->n_bases == p2n.size() && "Optimization requires first-order geometry bases");
155 std::vector<int> indices(p2n.size());
156 for (int i = 0; i < p2n.size(); ++i)
157 {
158 assert(p2n[i] >= 0 && p2n[i] < indices.size() && "Primitive-to-node entries must be valid node indices");
159 indices[p2n[i]] = i;
160 }
161 return indices;
162 }
163
164 void DifferentiableVarForm::get_elements(Eigen::MatrixXi &elements) const
165 {
166 if (!get_mesh().is_simplicial())
167 log_and_throw_error("Element extraction requires a simplicial mesh.");
168 const std::vector<int> n2p = node_to_primitive();
169 const auto &geometry_bases = primary_space().geometry_basis_list();
170 elements.resize(geometry_bases.size(), get_mesh().dimension() + 1);
171 for (int e = 0; e < geometry_bases.size(); ++e)
172 {
173 int i = 0;
174 for (const auto &basis : geometry_bases[e].bases)
175 elements(e, i++) = n2p[basis.global()[0].index];
176 }
177 }
178
180 {
181 const FESpace &space = primary_space();
182 assert(space.disc_orders.size() > 0 && "Boundary quadrature requires initialized FE orders");
183 assert(space.geometry && "Boundary quadrature requires an initialized geometry mapping");
184 assert(space.geometry->disc_orders.size() > 0 && "Boundary quadrature requires initialized geometry orders");
185 const int geometry_discr_order = get_mesh().orders().size() <= 0 ? 1 : get_mesh().orders().maxCoeff();
186 return boundary_samples(space.disc_orders.maxCoeff(), space.disc_ordersq.maxCoeff(), geometry_discr_order);
187 }
188
189 void DifferentiableVarForm::set_vertex_positions(const Eigen::MatrixXd &vertices)
190 {
191 mesh::Mesh &mesh = mutable_mesh();
192 if (vertices.rows() != mesh.n_vertices() || vertices.cols() != mesh.dimension())
194 "Invalid vertex matrix shape ({}, {}), expected ({}, {}).",
195 vertices.rows(), vertices.cols(), mesh.n_vertices(), mesh.dimension());
196 for (int i = 0; i < vertices.rows(); ++i)
197 mesh.set_point(i, vertices.row(i));
199 }
200
201 void DifferentiableVarForm::set_lame_parameters(const Eigen::VectorXd &lambda, const Eigen::VectorXd &mu)
202 {
203 if (lambda.size() != get_mesh().n_elements() || mu.size() != get_mesh().n_elements())
204 log_and_throw_error("Lamé parameter vectors must contain one value per element.");
205 const_cast<assembler::Assembler &>(primary_assembler()).update_lame_params(lambda, mu);
207 }
208
210 {
211 get_args()["contact"]["friction_coefficient"] = coefficient;
213 }
214
215 void DifferentiableVarForm::set_damping_coefficients(const double psi, const double phi)
216 {
217 auto update_material = [psi, phi](json &material) {
218 material["psi"] = psi;
219 material["phi"] = phi;
220 };
221 if (get_args()["materials"].is_array())
222 {
223 for (auto &material : get_args()["materials"])
224 update_material(material);
225 }
226 else
227 update_material(get_args()["materials"]);
229 }
230
231 void DifferentiableVarForm::set_dirichlet_boundary(const int boundary_id, const int time_step, const Eigen::VectorXd &value)
232 {
233 auto *tensor_problem = dynamic_cast<assembler::GenericTensorProblem *>(&get_problem());
234 if (!tensor_problem)
235 log_and_throw_error("Dirichlet boundary updates require a generic tensor problem.");
236 tensor_problem->update_dirichlet_boundary(boundary_id, time_step, value);
238 }
239
240 void DifferentiableVarForm::set_dirichlet_nodes(const Eigen::VectorXi &input_nodes, const Eigen::MatrixXd &values)
241 {
242 auto *tensor_problem = dynamic_cast<assembler::GenericTensorProblem *>(&get_problem());
243 if (!tensor_problem)
244 log_and_throw_error("Nodal Dirichlet updates require a generic tensor problem.");
245 tensor_problem->update_dirichlet_nodes(primary_space().space_in_node_to_node, input_nodes, values);
247 }
248
249 void DifferentiableVarForm::set_pressure_boundary(const int boundary_id, const int time_step, const double value)
250 {
251 auto *tensor_problem = dynamic_cast<assembler::GenericTensorProblem *>(&get_problem());
252 if (!tensor_problem)
253 log_and_throw_error("Pressure updates require a generic tensor problem.");
254 tensor_problem->update_pressure_boundary(boundary_id, time_step, value);
256 }
257} // 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:71
virtual bool is_linear() const =0
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
Definition Mesh.hpp:50
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:268
int dimension() const
utily for dimension
Definition Mesh.hpp:138
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 void replace_mesh(const std::string &path)
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:49
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