PolyFEM
Loading...
Searching...
No Matches
LocalRelaxationData.cpp
Go to the documentation of this file.
2
12
13namespace polyfem::mesh
14{
15 template <typename M>
17 const State &state,
18 LocalMesh<M> &local_mesh,
19 const double current_time,
20 const bool contact_enabled)
21 : local_mesh(local_mesh)
22 {
23 problem = std::make_shared<assembler::GenericTensorProblem>("GenericTensor");
24
25 init_mesh(state);
26 init_bases(state);
28 init_assembler(state);
29 init_mass_matrix(state);
30 init_solve_data(state, current_time, contact_enabled);
31 }
32
33 template <typename M>
35 {
36 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_mesh");
37
38 mesh = Mesh::create(local_mesh.rest_positions(), local_mesh.elements());
39 assert(mesh->n_vertices() == local_mesh.num_vertices());
40
41 std::vector<int> boundary_ids(mesh->n_boundary_elements(), -1);
42 if constexpr (std::is_same_v<M, WildTriRemesher>)
43 {
44 const auto local_boundary_ids = std::get<Remesher::EdgeMap<int>>(local_mesh.boundary_ids());
45 for (int i = 0; i < mesh->n_edges(); i++)
46 {
47 const size_t e0 = mesh->edge_vertex(i, 0);
48 const size_t e1 = mesh->edge_vertex(i, 1);
49 boundary_ids[i] = local_boundary_ids.at({{e0, e1}});
50 }
51 }
52 else
53 {
54 const auto local_boundary_ids = std::get<Remesher::FaceMap<int>>(local_mesh.boundary_ids());
55 for (int i = 0; i < mesh->n_faces(); i++)
56 {
57 std::array<size_t, 3> f = {{
58 (size_t)mesh->face_vertex(i, 0),
59 (size_t)mesh->face_vertex(i, 1),
60 (size_t)mesh->face_vertex(i, 2),
61 }};
62 boundary_ids[i] = local_boundary_ids.at(f);
63 }
64 }
65
66 mesh->set_boundary_ids(boundary_ids);
67 mesh->set_body_ids(local_mesh.body_ids());
68 }
69
70 template <typename M>
72 {
73 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_bases");
74
75 Eigen::VectorXi vertex_to_basis;
76 m_n_bases = Remesher::build_bases(
77 *mesh, state.formulation(), bases, local_boundary, vertex_to_basis);
78
79 assert(m_n_bases == local_mesh.num_local_vertices());
80 m_n_bases = local_mesh.num_vertices(); // the real n_bases includes the global boundary nodes
81 assert(vertex_to_basis.size() == m_n_bases);
82
83 const int start_i = local_mesh.num_local_vertices();
84 if (start_i < m_n_bases)
85 {
86 // set tail to range [start_i, n_bases)
87 std::iota(vertex_to_basis.begin() + start_i, vertex_to_basis.end(), start_i);
88 }
89
90 assert(std::all_of(vertex_to_basis.begin(), vertex_to_basis.end(), [](const int basis_id) {
91 return basis_id >= 0;
92 }));
93
94 // State::build_node_mapping();
95 local_mesh.reorder_vertices(vertex_to_basis);
96 problem->update_nodes(vertex_to_basis);
97 mesh->update_nodes(vertex_to_basis);
98 }
99
100 template <typename M>
102 {
103 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_boundary_conditions");
104
105 assert(mesh != nullptr);
106 state.problem->init(*mesh);
107
108 std::vector<int> pressure_boundary_nodes;
109 state.problem->setup_bc(
110 *mesh, n_bases() - state.obstacle.n_vertices(), bases, /*geom_bases=*/bases,
111 /*pressure_bases=*/std::vector<basis::ElementBases>(), local_boundary,
112 boundary_nodes, local_neumann_boundary, pressure_boundary_nodes,
113 dirichlet_nodes, neumann_nodes);
114
115 auto find_node_position = [&](const int n_id) {
116 for (const auto &bs : bases)
117 for (const auto &b : bs.bases)
118 for (const auto &lg : b.global())
119 if (lg.index == n_id)
120 return lg.node;
121 log_and_throw_error("Node not found");
122 };
123
124 // setup nodal values
125 dirichlet_nodes_position.resize(dirichlet_nodes.size());
126 for (int n = 0; n < dirichlet_nodes.size(); ++n)
127 dirichlet_nodes_position[n] = find_node_position(dirichlet_nodes[n]);
128
129 neumann_nodes_position.resize(neumann_nodes.size());
130 for (int n = 0; n < neumann_nodes.size(); ++n)
131 neumann_nodes_position[n] = find_node_position(neumann_nodes[n]);
132
133 // Add fixed boundary DOF
134 for (const int vi : local_mesh.fixed_vertices())
135 {
136 for (int d = 0; d < dim(); ++d)
137 {
138 boundary_nodes.push_back(vi * dim() + d);
139 }
140 }
141
142 std::sort(boundary_nodes.begin(), boundary_nodes.end());
143 auto it = std::unique(boundary_nodes.begin(), boundary_nodes.end());
144 boundary_nodes.erase(it, boundary_nodes.end());
145 }
146
147 template <typename M>
149 {
150 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_assembler");
151 assert(utils::is_param_valid(state.args, "materials"));
152
154 assert(assembler->name() == state.formulation());
155 assembler->set_size(dim());
156 assembler->set_materials(local_mesh.body_ids(), state.args["materials"], state.units);
157
158 mass_matrix_assembler = std::make_shared<assembler::Mass>();
159 mass_matrix_assembler->set_size(dim());
160 mass_matrix_assembler->set_materials(local_mesh.body_ids(), state.args["materials"], state.units);
161 }
162
163 template <typename M>
165 {
166 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_mass_matrix");
167
168 // Assemble the mass matrix.
169 mass_assembly_vals_cache.init(
170 is_volume(), bases, /*gbases=*/bases, /*is_mass=*/true);
171 assert(mass_matrix_assembler != nullptr);
172 mass_matrix_assembler->assemble(
173 is_volume(), n_bases(), bases, /*gbases=*/bases,
174 mass_assembly_vals_cache,
175 /*t=*/0, // TODO: time-dependent mass matrix
176 mass, /*is_mass=*/true);
177
178 // Set the mass of the codimensional fixed vertices to the average mass.
179 const int local_ndof = dim() * local_mesh.num_local_vertices();
180 for (int i = local_ndof; i < ndof(); ++i)
181 mass.coeffRef(i, i) = state.avg_mass;
182 }
183
184 template <typename M>
186 const State &state,
187 const double current_time,
188 const bool contact_enabled)
189 {
190 // Current solution.
191 const Eigen::MatrixXd target_x = this->sol();
192
193 // Assemble the stiffness matrix.
194 assembly_vals_cache.init(is_volume(), bases, /*gbases=*/bases, /*is_mass=*/false);
195
196 // Create collision mesh.
197 if (contact_enabled)
198 {
199 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> create collision mesh");
200
201 collision_mesh = ipc::CollisionMesh::build_from_full_mesh(
202 local_mesh.rest_positions(), local_mesh.boundary_edges(),
203 local_mesh.boundary_faces());
204
205 // Ignore all collisions between fixed elements.
206 std::vector<bool> is_vertex_fixed(local_mesh.num_vertices(), false);
207 for (const int vi : local_mesh.fixed_vertices())
208 is_vertex_fixed[vi] = true;
209 collision_mesh.can_collide = [is_vertex_fixed, this](size_t vi, size_t vj) {
210 return !is_vertex_fixed[this->collision_mesh.to_full_vertex_id(vi)]
211 || !is_vertex_fixed[this->collision_mesh.to_full_vertex_id(vj)];
212 };
213 }
214
215 // Initialize time integrator
216 if (state.problem->is_time_dependent())
217 {
218 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> create time integrator");
219 solve_data.time_integrator =
221 state.args["time"]["integrator"]);
222 Eigen::MatrixXd x_prevs, v_prevs, a_prevs;
224 local_mesh.projection_quantities(), dim(), x_prevs, v_prevs, a_prevs);
225 solve_data.time_integrator->init(
226 x_prevs, v_prevs, a_prevs, state.args["time"]["dt"]);
227 }
228
229 // Initialize solve_data.rhs_assembler
230 {
231 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> create RHS assembler");
232
233 json rhs_solver_params = state.args["solver"]["linear"];
234 if (!rhs_solver_params.contains("Pardiso"))
235 rhs_solver_params["Pardiso"] = {};
236 rhs_solver_params["Pardiso"]["mtype"] = -2; // matrix type for Pardiso (2 = SPD)
237
238 const int size = state.problem->is_scalar() ? 1 : dim();
239 solve_data.rhs_assembler = std::make_shared<assembler::RhsAssembler>(
240 *assembler, *mesh, Obstacle(), dirichlet_nodes, neumann_nodes,
241 dirichlet_nodes_position, neumann_nodes_position, n_bases(),
242 dim(), bases, /*geom_bases=*/bases, mass_assembly_vals_cache,
243 *state.problem, state.args["space"]["advanced"]["bc_method"],
244 rhs_solver_params);
245
246 solve_data.rhs_assembler->assemble(mass_matrix_assembler->density(), rhs);
247 rhs *= -1;
248 }
249
250 std::vector<std::shared_ptr<solver::Form>> forms;
251 {
252 POLYFEM_REMESHER_SCOPED_TIMER("LocalRelaxationData::init_solve_data -> init forms");
253 forms = solve_data.init_forms(
254 // General
255 state.units, dim(), current_time,
256 // Elastic form
257 n_bases(), bases, /*geom_bases=*/bases, *assembler,
258 assembly_vals_cache, assembly_vals_cache,
259 // Body form
260 /*n_pressure_bases=*/0, boundary_nodes, local_boundary,
261 local_neumann_boundary, state.n_boundary_samples(), rhs,
262 target_x, mass_matrix_assembler->density(),
263 // Inertia form
264 state.args.value("/time/quasistatic"_json_pointer, true), mass,
265 /*damping_assembler=*/nullptr,
266 // Lagged regularization form
267 state.args["solver"]["advanced"]["lagged_regularization_weight"],
268 state.args["solver"]["advanced"]["lagged_regularization_iterations"],
269 // Augmented lagrangian form
270 /*obstacle_ndof=*/0,
271 // Contact form
272 contact_enabled, collision_mesh, state.args["contact"]["dhat"],
273 state.avg_mass, state.args["contact"]["use_convergent_formulation"],
274 contact_enabled ? state.solve_data.contact_form->barrier_stiffness() : 0,
275 state.args["solver"]["contact"]["CCD"]["broad_phase"],
276 state.args["solver"]["contact"]["CCD"]["tolerance"],
277 state.args["solver"]["contact"]["CCD"]["max_iterations"],
278 /*enable_shape_derivatives=*/false,
279 // Friction form
280 state.args["contact"]["friction_coefficient"],
281 state.args["contact"]["epsv"],
282 state.args["solver"]["contact"]["friction_iterations"],
283 // Rayleigh damping form
284 state.args["solver"]["rayleigh_damping"]);
285
286 // Remove AL forms because we do not need them in the remeshing process.
287 forms.erase(std::remove(forms.begin(), forms.end(), solve_data.al_lagr_form), forms.end());
288 forms.erase(std::remove(forms.begin(), forms.end(), solve_data.al_pen_form), forms.end());
289 solve_data.al_lagr_form = nullptr;
290 solve_data.al_pen_form = nullptr;
291 }
292
293 solve_data.nl_problem = std::make_shared<polyfem::solver::StaticBoundaryNLProblem>(
294 ndof(), boundary_nodes, target_x, forms);
295
296 assert(solve_data.time_integrator != nullptr);
297 solve_data.nl_problem->update_quantities(current_time, solve_data.time_integrator->x_prev());
298 solve_data.nl_problem->init(target_x);
299 solve_data.nl_problem->init_lagging(solve_data.time_integrator->x_prev());
300 solve_data.nl_problem->update_lagging(target_x, /*iter_num=*/0);
301 }
302
303 // -------------------------------------------------------------------------
304 // Template instantiations
307} // namespace polyfem::mesh
#define POLYFEM_REMESHER_SCOPED_TIMER(name)
Definition Remesher.hpp:15
main class that contains the polyfem solver and all its state
Definition State.hpp:79
std::string formulation() const
return the formulation (checks if the problem is scalar or not and deals with multiphysics)
Definition State.cpp:387
int n_boundary_samples() const
quadrature used for projecting boundary conditions
Definition State.hpp:263
mesh::Obstacle obstacle
Obstacles used in collisions.
Definition State.hpp:468
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
Definition State.hpp:168
json args
main input arguments containing all defaults
Definition State.hpp:101
double avg_mass
average system mass, used for contact with IPC
Definition State.hpp:204
solver::SolveData solve_data
timedependent stuff cached
Definition State.hpp:324
static std::shared_ptr< Assembler > make_assembler(const std::string &formulation)
void init_solve_data(const State &state, const double current_time, const bool contact_enabled)
LocalRelaxationData(const State &state, LocalMesh< M > &local_mesh, const double current_time, const bool contact_enabled)
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
void init_boundary_conditions(const State &state)
static std::unique_ptr< Mesh > create(const std::string &path, const bool non_conforming=false)
factory to build the proper mesh
Definition Mesh.cpp:173
static int build_bases(const Mesh &mesh, const std::string &assembler_formulation, std::vector< polyfem::basis::ElementBases > &bases, std::vector< LocalBoundary > &local_boundary, Eigen::VectorXi &vertex_to_basis)
Build bases for a given mesh (V, F)
Definition Remesher.cpp:254
static void split_time_integrator_quantities(const Eigen::MatrixXd &quantities, const int dim, Eigen::MatrixXd &x_prevs, Eigen::MatrixXd &v_prevs, Eigen::MatrixXd &a_prevs)
Split the quantities of a time integrator into separate vectors.
Definition Remesher.cpp:396
std::shared_ptr< solver::ContactForm > contact_form
static std::shared_ptr< ImplicitTimeIntegrator > construct_time_integrator(const json &params)
Factory method for constructing implicit time integrators from the name of the integrator.
bool is_param_valid(const json &params, const std::string &key)
Determine if a key exists and is non-null in a json object.
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:71