34#include <spdlog/fmt/fmt.h>
39 const std::string &state_path,
40 const std::string &x_name,
42 const Eigen::VectorXi &in_node_to_node,
46 if (state_path.empty())
51 logger().debug(
"Unable to read initial {} from file ({})", x_name, state_path);
57 const int ndof = in_node_to_node.size() * dim;
67 bool should_use_iso_parametric(
const mesh::Mesh &mesh,
const json &args)
72 if (args[
"space"][
"basis_type"] ==
"Bernstein")
75 if (args[
"space"][
"basis_type"] ==
"Spline")
81 if (args[
"space"][
"use_p_ref"])
84 if (args[
"boundary_conditions"][
"periodic_boundary"][
"enabled"].get<bool>())
87 if (mesh.
orders().size() <= 0)
89 if (args[
"space"][
"discr_order"] == 1)
91 return args[
"space"][
"advanced"][
"isoparametric"];
94 if (mesh.
orders().minCoeff() != mesh.
orders().maxCoeff())
97 if (args[
"space"][
"discr_order"] == mesh.
orders().minCoeff())
100 return args[
"space"][
"advanced"][
"isoparametric"];
104 void build_in_node_to_in_primitive(
const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
105 Eigen::VectorXi &in_node_to_in_primitive,
106 Eigen::VectorXi &in_node_offset)
108 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
109 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
110 const int num_face_nodes = mesh_nodes.num_face_nodes();
111 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
113 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
115 const long n_vertices = num_vertex_nodes;
116 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
117 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
119 in_node_to_in_primitive.resize(num_nodes);
120 in_node_offset.resize(num_nodes);
123 in_node_to_in_primitive.head(num_vertex_nodes).setLinSpaced(num_vertex_nodes, 0, num_vertex_nodes - 1);
124 in_node_offset.head(num_vertex_nodes).setZero();
126 int prim_offset = n_vertices;
127 int node_offset = num_vertex_nodes;
128 auto foo = [&](
const int num_prims,
const int num_prim_nodes) {
129 if (num_prims <= 0 || num_prim_nodes <= 0)
131 const Eigen::VectorXi range = Eigen::VectorXi::LinSpaced(num_prim_nodes, 0, num_prim_nodes - 1);
133 const int node_per_prim = num_prim_nodes / num_prims;
135 in_node_to_in_primitive.segment(node_offset, num_prim_nodes) =
136 range.array() / node_per_prim + prim_offset;
138 in_node_offset.segment(node_offset, num_prim_nodes) =
139 range.unaryExpr([&](
const int x) {
return x % node_per_prim; });
141 prim_offset += num_prims;
142 node_offset += num_prim_nodes;
145 foo(mesh.n_edges(), num_edge_nodes);
146 foo(mesh.n_faces(), num_face_nodes);
147 foo(mesh.n_cells(), num_cell_nodes);
150 bool build_in_primitive_to_primitive(
151 const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
152 const Eigen::VectorXi &in_ordered_vertices,
153 const Eigen::MatrixXi &in_ordered_edges,
154 const Eigen::MatrixXi &in_ordered_faces,
155 Eigen::VectorXi &in_primitive_to_primitive)
158 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
159 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
160 const int num_face_nodes = mesh_nodes.num_face_nodes();
161 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
162 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
164 const long n_vertices = num_vertex_nodes;
165 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
166 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
168 in_primitive_to_primitive.setLinSpaced(num_in_primitives, 0, num_in_primitives - 1);
176 if (in_ordered_vertices.rows() != n_vertices)
178 logger().warn(
"Node ordering disabled, in_ordered_vertices != n_vertices, {} != {}", in_ordered_vertices.rows(), n_vertices);
182 in_primitive_to_primitive.head(n_vertices) = in_ordered_vertices;
184 int in_offset = n_vertices;
185 int offset = mesh.n_vertices();
191 logger().trace(
"Building Mesh edges to IDs...");
193 const auto edges_to_ids = mesh.edges_to_ids();
194 if (in_ordered_edges.rows() != edges_to_ids.size())
196 logger().warn(
"Node ordering disabled, in_ordered_edges != edges_to_ids, {} != {}", in_ordered_edges.rows(), edges_to_ids.size());
200 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
202 logger().trace(
"Building in-edge to edge mapping...");
204 for (
int in_ei = 0; in_ei < in_ordered_edges.rows(); in_ei++)
206 const std::pair<int, int> in_edge(
207 in_ordered_edges.row(in_ei).minCoeff(),
208 in_ordered_edges.row(in_ei).maxCoeff());
209 in_primitive_to_primitive[in_offset + in_ei] =
210 offset + edges_to_ids.at(in_edge);
213 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
215 in_offset += mesh.n_edges();
216 offset += mesh.n_edges();
222 if (mesh.is_volume())
224 logger().trace(
"Building Mesh faces to IDs...");
226 const auto faces_to_ids = mesh.faces_to_ids();
227 if (in_ordered_faces.rows() != faces_to_ids.size())
229 logger().warn(
"Node ordering disabled, in_ordered_faces != faces_to_ids, {} != {}", in_ordered_faces.rows(), faces_to_ids.size());
233 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
235 logger().trace(
"Building in-face to face mapping...");
237 for (
int in_fi = 0; in_fi < in_ordered_faces.rows(); in_fi++)
239 std::vector<int> in_face(in_ordered_faces.cols());
240 for (
int i = 0; i < in_face.size(); i++)
241 in_face[i] = in_ordered_faces(in_fi, i);
242 std::sort(in_face.begin(), in_face.end());
244 in_primitive_to_primitive[in_offset + in_fi] =
245 offset + faces_to_ids.at(in_face);
248 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
250 in_offset += mesh.n_faces();
251 offset += mesh.n_faces();
261 const int n_b_samples_j =
args[
"space"][
"advanced"][
"n_boundary_samples"];
262 const int boundary_order = std::max(discr_order, gdiscr_order);
264 return {{n_b_samples, n_b_samples}};
297 mesh_ = std::move(mesh);
314 mesh_->prepare_mesh();
324 const bool iso_parametric,
325 const Eigen::VectorXi &disc_orders,
326 const std::string &basis_type,
327 const std::string &poly_basis_type,
330 const int quadrature_order,
331 const int mass_quadrature_order,
332 const bool use_corner_quadrature,
333 const int n_harmonic_samples,
334 const int integral_constraints,
337 std::shared_ptr<GeometryMapping> geometry)
339 using namespace mesh;
341 const std::string space_assembler_name = space_assembler.
name();
342 const bool build_geom_mapping = geometry ==
nullptr;
349 space.
bases = std::make_shared<std::vector<basis::ElementBases>>();
350 space.
geometry = build_geom_mapping ? std::make_shared<GeometryMapping>() : std::move(geometry);
356 Eigen::MatrixXi geom_disc_orders;
357 if (build_geom_mapping && !iso_parametric)
359 if (mesh.
orders().size() <= 0)
362 geom_disc_orders.setConstant(1);
365 geom_disc_orders = mesh.
orders();
367 space.
geometry->bases = std::make_shared<std::vector<basis::ElementBases>>();
368 space.
geometry->disc_orders = geom_disc_orders;
371 Eigen::MatrixXi geom_disc_ordersq = geom_disc_orders;
373 logger().info(
"Building {} basis...", (build_geom_mapping ? (iso_parametric ?
"isoparametric" :
"not isoparametric") :
"finite-element"));
378 const bool has_polys = mesh.
has_poly();
379 std::map<int, basis::InterfaceData> poly_edge_to_data_geom;
381 const bool use_continuous_gbasis =
true;
385 const Mesh3D &tmp_mesh =
dynamic_cast<const Mesh3D &
>(mesh);
387 if (basis_type ==
"Spline")
390 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
395 if (build_geom_mapping && !iso_parametric)
397 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
398 geom_disc_orders, geom_disc_ordersq,
false,
false, has_polys,
399 !use_continuous_gbasis, use_corner_quadrature,
404 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
406 basis_type ==
"Bernstein",
407 basis_type ==
"Serendipity",
408 has_polys,
false, use_corner_quadrature,
414 const Mesh2D &tmp_mesh =
dynamic_cast<const Mesh2D &
>(mesh);
416 if (basis_type ==
"Spline")
419 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
424 if (build_geom_mapping && !iso_parametric)
426 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
427 geom_disc_orders,
false,
false, has_polys,
428 !use_continuous_gbasis, use_corner_quadrature,
433 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
435 basis_type ==
"Bernstein",
436 basis_type ==
"Serendipity",
437 has_polys,
false, use_corner_quadrature,
442 const bool use_fe_space_as_geometry = build_geom_mapping ? iso_parametric : space.
is_iso_parametric();
444 use_fe_space_as_geometry,
446 mass_quadrature_order,
448 integral_constraints,
452 if (build_geom_mapping)
455 space.
geometry->init_from_fe_space(space);
459 assert(space.
geometry->n_bases > 0);
467 if (build_geom_mapping)
470 logger().debug(
"Building node mapping...");
474 logger().debug(
"Done (took {}s)", timer2.getElapsedTime());
487 const std::string &poly_basis_type,
490 const int quadrature_order,
491 const int mass_quadrature_order,
492 const int n_harmonic_samples,
493 const int integral_constraints,
503 const std::string space_assembler_name = space_assembler.
name();
507 logger().info(
"Computing polygonal basis...");
515 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
519 assert(linear_assembler);
526 mass_quadrature_order,
527 integral_constraints,
536 if (poly_basis_type ==
"MeanValue")
539 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
541 mass_quadrature_order,
544 else if (poly_basis_type ==
"Wachspress")
547 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
549 mass_quadrature_order,
555 assert(linear_assembler);
562 mass_quadrature_order,
563 integral_constraints,
577 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
581 assert(linear_assembler);
588 mass_quadrature_order,
589 integral_constraints,
598 if (poly_basis_type ==
"MeanValue")
601 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
603 mass_quadrature_order,
606 else if (poly_basis_type ==
"Wachspress")
609 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
611 mass_quadrature_order,
617 assert(linear_assembler);
624 mass_quadrature_order,
625 integral_constraints,
649 const std::string &basis_type,
651 Eigen::VectorXi &space_in_node_to_node,
652 Eigen::VectorXi &space_in_primitive_to_primitive)
const
654 space_in_node_to_node.resize(0);
655 space_in_primitive_to_primitive.resize(0);
657 if (basis_type ==
"Spline")
659 logger().warn(
"Node ordering disabled, it dosent work for splines!");
665 logger().warn(
"Node ordering disabled, it works only for p < 4 and uniform order!");
671 logger().warn(
"Node ordering disabled, not supported for non-conforming meshes!");
677 logger().warn(
"Node ordering disabled, not supported for polygonal meshes!");
683 logger().warn(
"Node ordering disabled, input vertices/edges/faces not computed!");
689 logger().warn(
"Node ordering disabled, FE space does not expose mesh nodes!");
693 const int num_vertex_nodes = space.
mesh_nodes->num_vertex_nodes();
694 const int num_edge_nodes = space.
mesh_nodes->num_edge_nodes();
695 const int num_face_nodes = space.
mesh_nodes->num_face_nodes();
696 const int num_cell_nodes = space.
mesh_nodes->num_cell_nodes();
698 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
699 const long n_vertices = num_vertex_nodes;
705 logger().trace(
"Building in-node to in-primitive mapping...");
707 Eigen::VectorXi in_node_to_in_primitive;
708 Eigen::VectorXi in_node_offset;
709 build_in_node_to_in_primitive(mesh, *space.
mesh_nodes, in_node_to_in_primitive, in_node_offset);
711 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
713 logger().trace(
"Building in-primitive to primitive mapping...");
715 bool ok = build_in_primitive_to_primitive(
720 space_in_primitive_to_primitive);
722 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
726 space_in_node_to_node.resize(0);
727 space_in_primitive_to_primitive.resize(0);
731 const auto &tmp = space.
mesh_nodes->in_ordered_vertices();
734 max_tmp = std::max(max_tmp, v);
736 space_in_node_to_node.resize(max_tmp + 1);
737 for (
int i = 0; i < tmp.size(); ++i)
740 space_in_node_to_node[tmp[i]] = i;
753 if (discr_order.is_number_integer())
755 disc_orders.setConstant(discr_order);
757 else if (discr_order.is_string())
762 assert(tmp.size() == disc_orders.size());
763 assert(tmp.cols() == 1);
766 else if (discr_order.is_array())
768 disc_orders.setOnes();
769 std::map<int, int> b_orders;
770 bool has_matching_order =
false;
771 for (
const json &entry : discr_order)
773 if (entry.contains(
"fe_space"))
775 const int entry_space_id = entry[
"fe_space"].get<
int>();
776 if (entry_space_id >= 0 && fe_space_id < 0)
778 if (entry_space_id >= 0 && entry_space_id != fe_space_id)
782 has_matching_order =
true;
783 const int order = entry[
"order"];
784 if (!entry.contains(
"id") || (entry[
"id"].is_number_integer() && entry[
"id"].get<
int>() < 0))
786 disc_orders.setConstant(order);
790 for (
const int id : utils::json_as_array<int>(entry[
"id"]))
792 b_orders[id] = order;
793 logger().trace(
"bid {}, discr {}",
id, order);
797 if (!has_matching_order)
803 const auto order = b_orders.find(bid);
804 if (order != b_orders.end())
805 disc_orders[e] = order->second;
810 logger().error(
"space/discr_order must be either a number a path or an array");
811 throw std::runtime_error(
"invalid json");
818 if (out_path.empty())
821 std::ofstream file(out_path);
824 logger().error(
"Unable to save simulation JSON to {}", out_path);
832 assert(
mesh_ !=
nullptr);
838 std::vector<int> body_ids(
mesh_->n_elements());
839 for (
int i = 0; i <
mesh_->n_elements(); ++i)
840 body_ids[i] =
mesh_->get_body_id(i);
874 sample.requested_fields.empty() ? fields : sample.requested_fields});
892 const bool rest_mesh_written)
const
896 if (!state_path.empty() && time_integrator)
902 void VarForm::save_timestep(
const double time,
const int t,
const double t0,
const double dt,
const Eigen::MatrixXd &solution)
const
905 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_time_sequence"])
908 if (global_t %
args[
"output"][
"paraview"][
"skip_frame"].get<int>())
913 logger().trace(
"Saving VTU...");
914 const std::string step_name =
args[
"output"][
"advanced"][
"timestep_prefix"];
923 [step_name](
int i) {
return fmt::format(step_name +
"{:d}.vtm", i); },
924 global_t, t0, dt,
args[
"output"][
"paraview"][
"skip_frame"].get<
int>());
930 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_solve_sequence_debug"].get<
bool>())
933 const bool has_time =
args.contains(
"time") && !
args[
"time"].is_null();
936 dt =
args[
"time"][
"dt"];
949 time_callback(t, time_steps, t0 + dt * t, t0 + dt * time_steps);
954 const std::string restart_json_path =
args[
"output"][
"restart_json"];
955 if (restart_json_path.empty())
963 restart_json[
"time"] = {{
"t0", t0 + dt * t}};
964 restart_json[
"output"] = {{
"data", {{
"file_index_offset", global_t}}}};
966 restart_json[
"space"] = R
"({
969 "abs_max_edge_length": -1,
970 "rel_max_edge_length": -1
976 restart_json[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"] = std::min(
977 args[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"].get<double>(),
978 starting_min_edge_length *
args[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"].get<double>());
979 restart_json[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"] = std::numeric_limits<float>::max();
981 std::string rest_mesh_path =
args[
"output"][
"data"][
"rest_mesh"].get<std::string>();
982 if (!rest_mesh_path.empty())
984 if (!rest_mesh_written)
985 logger().warn(
"Restart JSON for {} references a rest mesh that this formulation does not write.",
name());
989 std::vector<json> patch;
990 if (
args[
"geometry"].is_array())
992 const std::vector<json> in_geometry =
args[
"geometry"];
993 for (
int i = 0; i < in_geometry.size(); ++i)
995 if (!in_geometry[i][
"is_obstacle"].get<bool>())
999 {
"path", fmt::format(
"/geometry/{}", i)},
1004 const int remaining_geometry = in_geometry.size() - patch.size();
1005 assert(remaining_geometry >= 0);
1009 {
"path", fmt::format(
"/geometry/{}", remaining_geometry > 0 ?
"0" :
"-")},
1012 {
"mesh", rest_mesh_path},
1018 assert(
args[
"geometry"].is_object());
1021 {
"path",
"/geometry"},
1025 {
"path",
"/geometry"},
1028 {
"mesh", rest_mesh_path},
1033 restart_json[
"patch"] = patch;
1036 restart_json[
"input"] = {{
1044 file << restart_json;
1049 return t +
args[
"output"][
"data"][
"file_index_offset"].get<
int>();
1059 if (
output_path.empty() || path.empty() || std::filesystem::path(path).is_absolute())
1063 return std::filesystem::weakly_canonical(std::filesystem::path(
output_path) / path).string();
1067 const std::vector<basis::ElementBases> &bases,
1068 const std::vector<int> &node_ids,
1069 std::vector<RowVectorNd> &positions)
1071 positions.resize(node_ids.size());
1072 for (
int n = 0; n < int(node_ids.size()); ++n)
1074 const int node_id = node_ids[n];
1076 for (
const auto &bs : bases)
1078 for (
const auto &b : bs.bases)
1080 for (
const auto &lg : b.global())
1082 if (lg.index == node_id)
1084 positions[n] = lg.node;
virtual bool is_tensor() const
virtual std::string name() const =0
virtual void set_size(const int size)
void set_materials(const std::vector< int > &body_ids, const json &body_params, const Units &units, const std::string &root_path)
static int quadrature_order(const std::string &assembler, const int basis_degree, const BasisType &b_type, const int dim)
utility for retrieving the needed quadrature order to precisely integrate the given form on the given...
assemble matrix based on the local assembler local assembler is eg Laplace, LinearElasticity etc
static int build_bases(const mesh::Mesh2D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, const int discr_order, const bool bernstein, const bool serendipity, const bool has_polys, const bool is_geom_bases, const bool use_corner_quadrature, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_edge_to_data, std::shared_ptr< mesh::MeshNodes > &mesh_nodes)
Builds FE basis functions over the entire mesh (P1, P2 over triangles, Q1, Q2 over quads).
static int build_bases(const mesh::Mesh3D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, const int discr_orderp, const int discr_orderq, const bool bernstein, const bool serendipity, const bool has_polys, const bool is_geom_bases, const bool use_corner_quadrature, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_face_to_data, std::shared_ptr< mesh::MeshNodes > &mesh_nodes)
Builds FE basis functions over the entire mesh (P1, P2 over tets, Q1, Q2 over hes).
static int build_bases(const std::string &assembler_name, const int dim, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, Eigen::MatrixXd > &mapped_boundary)
static int build_bases(const assembler::LinearAssembler &assembler, const int n_samples_per_edge, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, const int integral_constraints, std::vector< ElementBases > &bases, const std::vector< ElementBases > &gbases, const std::map< int, InterfaceData > &poly_edge_to_data, std::map< int, Eigen::MatrixXd > &mapped_boundary)
Build bases over the remaining polygons of a mesh.
static int build_bases(const assembler::LinearAssembler &assembler, const int n_samples_per_edge, const mesh::Mesh3D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, const int integral_constraints, std::vector< ElementBases > &bases, const std::vector< ElementBases > &gbases, const std::map< int, InterfaceData > &poly_face_to_data, std::map< int, std::pair< Eigen::MatrixXd, Eigen::MatrixXi > > &mapped_boundary)
Build bases over the remaining polygons of a mesh.
static int build_bases(const mesh::Mesh2D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_edge_to_data)
static int build_bases(const mesh::Mesh3D &mesh, const std::string &assembler, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, InterfaceData > &poly_face_to_data)
static int build_bases(const std::string &assembler_name, const int dim, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, std::vector< ElementBases > &bases, std::vector< mesh::LocalBoundary > &local_boundary, std::map< int, Eigen::MatrixXd > &mapped_boundary)
void build_grid(const polyfem::mesh::Mesh &mesh, const double spacing)
builds the grid to export the solution
void save_pvd(const std::string &name, const std::function< std::string(int)> &vtu_names, int time_steps, double t0, double dt, int skip_frame=1) const
save a PVD of a time dependent simulation
void save_vtu(const std::string &path, const OutputSpace &space, const OutputFieldFunction &output_fields, const double t, const double dt, const ExportOptions &opts) const
saves the vtu file for time t
void init_sampler(const polyfem::mesh::Mesh &mesh, const double vismesh_rel_area)
unitalize the ref element sampler
double loading_mesh_time
time to load the mesh
double building_basis_time
time to construct the basis
double computing_poly_basis_time
time to build the polygonal/polyhedral bases
void reset()
clears all stats
void compute_mesh_stats(const polyfem::mesh::Mesh &mesh)
compute stats (counts els type, mesh lenght, etc), step 1 of solve
double min_edge_length
min edge lenght
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
virtual int n_vertices() const =0
number of vertices
virtual int get_body_id(const int primitive) const
Get the volume selection of an element (cell in 3d, face in 2d)
const Eigen::MatrixXi & in_ordered_edges() const
Order of the input edges.
bool is_rational() const
check if curved mesh has rational polynomials elements
virtual bool is_conforming() const =0
if the mesh is conforming
const Eigen::MatrixXi & orders() const
order of each element
bool has_prism() const
checks if the mesh has prisms
bool is_linear() const
check if the mesh is linear
virtual bool is_volume() const =0
checks if mesh is volume
bool has_poly() const
checks if the mesh has polytopes
const Eigen::VectorXi & in_ordered_vertices() const
Order of the input vertices.
int dimension() const
utily for dimension
virtual int n_cells() const =0
number of cells
virtual int n_faces() const =0
number of faces
const Eigen::MatrixXi & in_ordered_faces() const
Order of the input edges.
virtual int n_edges() const =0
number of edges
Implicit time integrator of a second order ODE (equivently a system of coupled first order ODEs).
virtual void save_state(const std::string &state_path) const
Save the values of , , and .
bool read_matrix(const std::string &path, Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > &mat)
Reads a matrix from a file. Determines the file format based on the path's extension.
std::function< std::vector< OutputField >(const OutputSample &)> OutputFieldFunction
Eigen::MatrixXd reorder_matrix(const Eigen::MatrixXd &in, const Eigen::VectorXi &in_to_out, int out_blocks=-1, const int block_size=1)
Reorder row blocks in a matrix.
std::string resolve_path(const std::string &path, const std::string &input_file_path, const bool only_if_exists=false)
bool is_param_valid(const json ¶ms, const std::string &key)
Determine if a key exists and is non-null in a json object.
spdlog::logger & logger()
Retrieves the current logger.
std::array< int, 2 > QuadratureOrders
void log_and_throw_error(const std::string &msg)
std::vector< std::string > fields