35#include <spdlog/fmt/fmt.h>
40 const std::string &state_path,
41 const std::string &x_name,
43 const Eigen::VectorXi &in_node_to_node,
47 if (state_path.empty())
52 logger().debug(
"Unable to read initial {} from file ({})", x_name, state_path);
58 const int ndof = in_node_to_node.size() * dim;
68 bool should_use_iso_parametric(
const mesh::Mesh &mesh,
const json &args)
73 if (args[
"space"][
"basis_type"] ==
"Bernstein")
76 if (args[
"space"][
"basis_type"] ==
"Spline")
82 if (args[
"space"][
"use_p_ref"])
85 if (args[
"boundary_conditions"][
"periodic_boundary"][
"enabled"].get<bool>())
88 if (mesh.
orders().size() <= 0)
90 if (args[
"space"][
"discr_order"] == 1)
92 return args[
"space"][
"advanced"][
"isoparametric"];
95 if (mesh.
orders().minCoeff() != mesh.
orders().maxCoeff())
98 if (args[
"space"][
"discr_order"] == mesh.
orders().minCoeff())
101 return args[
"space"][
"advanced"][
"isoparametric"];
105 void build_in_node_to_in_primitive(
const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
106 Eigen::VectorXi &in_node_to_in_primitive,
107 Eigen::VectorXi &in_node_offset)
109 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
110 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
111 const int num_face_nodes = mesh_nodes.num_face_nodes();
112 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
114 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
116 const long n_vertices = num_vertex_nodes;
117 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
118 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
120 in_node_to_in_primitive.resize(num_nodes);
121 in_node_offset.resize(num_nodes);
124 in_node_to_in_primitive.head(num_vertex_nodes).setLinSpaced(num_vertex_nodes, 0, num_vertex_nodes - 1);
125 in_node_offset.head(num_vertex_nodes).setZero();
127 int prim_offset = n_vertices;
128 int node_offset = num_vertex_nodes;
129 auto foo = [&](
const int num_prims,
const int num_prim_nodes) {
130 if (num_prims <= 0 || num_prim_nodes <= 0)
132 const Eigen::VectorXi range = Eigen::VectorXi::LinSpaced(num_prim_nodes, 0, num_prim_nodes - 1);
134 const int node_per_prim = num_prim_nodes / num_prims;
136 in_node_to_in_primitive.segment(node_offset, num_prim_nodes) =
137 range.array() / node_per_prim + prim_offset;
139 in_node_offset.segment(node_offset, num_prim_nodes) =
140 range.unaryExpr([&](
const int x) {
return x % node_per_prim; });
142 prim_offset += num_prims;
143 node_offset += num_prim_nodes;
146 foo(mesh.n_edges(), num_edge_nodes);
147 foo(mesh.n_faces(), num_face_nodes);
148 foo(mesh.n_cells(), num_cell_nodes);
151 bool build_in_primitive_to_primitive(
152 const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
153 const Eigen::VectorXi &in_ordered_vertices,
154 const Eigen::MatrixXi &in_ordered_edges,
155 const Eigen::MatrixXi &in_ordered_faces,
156 Eigen::VectorXi &in_primitive_to_primitive)
159 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
160 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
161 const int num_face_nodes = mesh_nodes.num_face_nodes();
162 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
163 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
165 const long n_vertices = num_vertex_nodes;
166 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
167 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
169 in_primitive_to_primitive.setLinSpaced(num_in_primitives, 0, num_in_primitives - 1);
177 if (in_ordered_vertices.rows() != n_vertices)
179 logger().warn(
"Node ordering disabled, in_ordered_vertices != n_vertices, {} != {}", in_ordered_vertices.rows(), n_vertices);
183 in_primitive_to_primitive.head(n_vertices) = in_ordered_vertices;
185 int in_offset = n_vertices;
186 int offset = mesh.n_vertices();
192 logger().trace(
"Building Mesh edges to IDs...");
194 const auto edges_to_ids = mesh.edges_to_ids();
195 if (in_ordered_edges.rows() != edges_to_ids.size())
197 logger().warn(
"Node ordering disabled, in_ordered_edges != edges_to_ids, {} != {}", in_ordered_edges.rows(), edges_to_ids.size());
201 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
203 logger().trace(
"Building in-edge to edge mapping...");
205 for (
int in_ei = 0; in_ei < in_ordered_edges.rows(); in_ei++)
207 const std::pair<int, int> in_edge(
208 in_ordered_edges.row(in_ei).minCoeff(),
209 in_ordered_edges.row(in_ei).maxCoeff());
210 in_primitive_to_primitive[in_offset + in_ei] =
211 offset + edges_to_ids.at(in_edge);
214 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
216 in_offset += mesh.n_edges();
217 offset += mesh.n_edges();
223 if (mesh.is_volume())
225 logger().trace(
"Building Mesh faces to IDs...");
227 const auto faces_to_ids = mesh.faces_to_ids();
228 if (in_ordered_faces.rows() != faces_to_ids.size())
230 logger().warn(
"Node ordering disabled, in_ordered_faces != faces_to_ids, {} != {}", in_ordered_faces.rows(), faces_to_ids.size());
234 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
236 logger().trace(
"Building in-face to face mapping...");
238 for (
int in_fi = 0; in_fi < in_ordered_faces.rows(); in_fi++)
240 std::vector<int> in_face(in_ordered_faces.cols());
241 for (
int i = 0; i < in_face.size(); i++)
242 in_face[i] = in_ordered_faces(in_fi, i);
243 std::sort(in_face.begin(), in_face.end());
245 in_primitive_to_primitive[in_offset + in_fi] =
246 offset + faces_to_ids.at(in_face);
249 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
251 in_offset += mesh.n_faces();
252 offset += mesh.n_faces();
262 const int n_b_samples_j =
args[
"space"][
"advanced"][
"n_boundary_samples"];
263 const int boundary_order = std::max(discr_order, gdiscr_order);
265 return {{n_b_samples, n_b_samples}};
298 mesh_ = std::move(mesh);
315 mesh_->prepare_mesh();
325 const bool iso_parametric,
326 const Eigen::VectorXi &disc_orders,
327 const std::string &basis_type,
328 const std::string &poly_basis_type,
331 const int quadrature_order,
332 const int mass_quadrature_order,
333 const bool use_corner_quadrature,
334 const int n_harmonic_samples,
335 const int integral_constraints,
338 std::shared_ptr<GeometryMapping> geometry)
340 using namespace mesh;
342 const std::string space_assembler_name = space_assembler.
name();
343 const bool build_geom_mapping = geometry ==
nullptr;
350 space.
bases = std::make_shared<std::vector<basis::ElementBases>>();
351 space.
geometry = build_geom_mapping ? std::make_shared<GeometryMapping>() : std::move(geometry);
357 Eigen::MatrixXi geom_disc_orders;
358 if (build_geom_mapping && !iso_parametric)
360 if (mesh.
orders().size() <= 0)
363 geom_disc_orders.setConstant(1);
366 geom_disc_orders = mesh.
orders();
368 space.
geometry->bases = std::make_shared<std::vector<basis::ElementBases>>();
369 space.
geometry->disc_orders = geom_disc_orders;
372 Eigen::MatrixXi geom_disc_ordersq = geom_disc_orders;
374 logger().info(
"Building {} basis...", (build_geom_mapping ? (iso_parametric ?
"isoparametric" :
"not isoparametric") :
"finite-element"));
379 const bool has_polys = mesh.
has_poly();
380 std::map<int, basis::InterfaceData> poly_edge_to_data_geom;
382 const bool use_continuous_gbasis =
true;
386 const Mesh3D &tmp_mesh =
dynamic_cast<const Mesh3D &
>(mesh);
388 if (basis_type ==
"Spline")
391 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
396 if (build_geom_mapping && !iso_parametric)
398 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
399 geom_disc_orders, geom_disc_ordersq,
false,
false, has_polys,
400 !use_continuous_gbasis, use_corner_quadrature,
405 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
407 basis_type ==
"Bernstein",
408 basis_type ==
"Serendipity",
409 has_polys,
false, use_corner_quadrature,
415 const Mesh2D &tmp_mesh =
dynamic_cast<const Mesh2D &
>(mesh);
417 if (basis_type ==
"Spline")
420 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
425 if (build_geom_mapping && !iso_parametric)
427 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
428 geom_disc_orders,
false,
false, has_polys,
429 !use_continuous_gbasis, use_corner_quadrature,
434 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
436 basis_type ==
"Bernstein",
437 basis_type ==
"Serendipity",
438 has_polys,
false, use_corner_quadrature,
443 const bool use_fe_space_as_geometry = build_geom_mapping ? iso_parametric : space.
is_iso_parametric();
445 use_fe_space_as_geometry,
447 mass_quadrature_order,
449 integral_constraints,
453 if (build_geom_mapping)
456 space.
geometry->init_from_fe_space(space);
460 assert(space.
geometry->n_bases > 0);
468 if (build_geom_mapping)
471 logger().debug(
"Building node mapping...");
475 logger().debug(
"Done (took {}s)", timer2.getElapsedTime());
488 const std::string &poly_basis_type,
491 const int quadrature_order,
492 const int mass_quadrature_order,
493 const int n_harmonic_samples,
494 const int integral_constraints,
504 const std::string space_assembler_name = space_assembler.
name();
508 logger().info(
"Computing polygonal basis...");
516 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
520 assert(linear_assembler);
527 mass_quadrature_order,
528 integral_constraints,
537 if (poly_basis_type ==
"MeanValue")
540 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
542 mass_quadrature_order,
545 else if (poly_basis_type ==
"Wachspress")
548 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
550 mass_quadrature_order,
556 assert(linear_assembler);
563 mass_quadrature_order,
564 integral_constraints,
578 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
582 assert(linear_assembler);
589 mass_quadrature_order,
590 integral_constraints,
599 if (poly_basis_type ==
"MeanValue")
602 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
604 mass_quadrature_order,
607 else if (poly_basis_type ==
"Wachspress")
610 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
612 mass_quadrature_order,
618 assert(linear_assembler);
625 mass_quadrature_order,
626 integral_constraints,
650 const std::string &basis_type,
652 Eigen::VectorXi &space_in_node_to_node,
653 Eigen::VectorXi &space_in_primitive_to_primitive)
const
655 space_in_node_to_node.resize(0);
656 space_in_primitive_to_primitive.resize(0);
658 if (basis_type ==
"Spline")
660 logger().warn(
"Node ordering disabled, it dosent work for splines!");
666 logger().warn(
"Node ordering disabled, it works only for p < 4 and uniform order!");
672 logger().warn(
"Node ordering disabled, not supported for non-conforming meshes!");
678 logger().warn(
"Node ordering disabled, not supported for polygonal meshes!");
684 logger().warn(
"Node ordering disabled, input vertices/edges/faces not computed!");
690 logger().warn(
"Node ordering disabled, FE space does not expose mesh nodes!");
694 const int num_vertex_nodes = space.
mesh_nodes->num_vertex_nodes();
695 const int num_edge_nodes = space.
mesh_nodes->num_edge_nodes();
696 const int num_face_nodes = space.
mesh_nodes->num_face_nodes();
697 const int num_cell_nodes = space.
mesh_nodes->num_cell_nodes();
699 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
700 const long n_vertices = num_vertex_nodes;
706 logger().trace(
"Building in-node to in-primitive mapping...");
708 Eigen::VectorXi in_node_to_in_primitive;
709 Eigen::VectorXi in_node_offset;
710 build_in_node_to_in_primitive(mesh, *space.
mesh_nodes, in_node_to_in_primitive, in_node_offset);
712 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
714 logger().trace(
"Building in-primitive to primitive mapping...");
716 bool ok = build_in_primitive_to_primitive(
721 space_in_primitive_to_primitive);
723 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
727 space_in_node_to_node.resize(0);
728 space_in_primitive_to_primitive.resize(0);
732 const auto &tmp = space.
mesh_nodes->in_ordered_vertices();
735 max_tmp = std::max(max_tmp, v);
737 space_in_node_to_node.resize(max_tmp + 1);
738 for (
int i = 0; i < tmp.size(); ++i)
741 space_in_node_to_node[tmp[i]] = i;
749 if (discr_order.is_number_integer())
751 disc_orders.setConstant(discr_order);
753 else if (discr_order.is_string())
758 assert(tmp.size() == disc_orders.size());
759 assert(tmp.cols() == 1);
762 else if (discr_order.is_array())
764 const auto b_discr_orders = discr_order;
766 std::map<int, int> b_orders;
767 for (
size_t i = 0; i < b_discr_orders.size(); ++i)
769 assert(b_discr_orders[i][
"id"].is_array() || b_discr_orders[i][
"id"].is_number_integer());
771 const int order = b_discr_orders[i][
"order"];
772 for (
const int id : utils::json_as_array<int>(b_discr_orders[i][
"id"]))
774 b_orders[id] = order;
775 logger().trace(
"bid {}, discr {}",
id, order);
782 const auto order = b_orders.find(bid);
783 if (order == b_orders.end())
785 logger().debug(
"Missing discretization order for body {}; using 1", bid);
791 disc_orders[e] = order->second;
797 logger().error(
"space/discr_order must be either a number a path or an array");
798 throw std::runtime_error(
"invalid json");
805 if (out_path.empty())
808 std::ofstream file(out_path);
811 logger().error(
"Unable to save simulation JSON to {}", out_path);
819 assert(
mesh_ !=
nullptr);
825 std::vector<int> body_ids(
mesh_->n_elements());
826 for (
int i = 0; i <
mesh_->n_elements(); ++i)
827 body_ids[i] =
mesh_->get_body_id(i);
861 sample.requested_fields.empty() ? fields : sample.requested_fields});
876 const json &config =
args[
"time"][
"integrator"];
877 const std::string type = config.is_object() ? config.at(
"type").get<std::string>() : config.get<std::string>();
879 if (type ==
"ImplicitEuler" || type ==
"implict_euler")
880 return std::make_shared<time_integrator::BDF>();
883 log_and_throw_error(
"First-order transient formulations require ImplicitEuler or BDF, got {}.", type);
885 auto integrator = std::make_shared<time_integrator::BDF>(
886 type ==
"BDF" ? 1 : std::stoi(type.substr(3)));
887 if (config.is_object() && config.contains(
"steps"))
888 integrator->set_parameters(config);
897 const bool rest_mesh_written)
const
901 if (!state_path.empty() && time_integrator)
907 void VarForm::save_timestep(
const double time,
const int t,
const double t0,
const double dt,
const Eigen::MatrixXd &solution)
const
910 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_time_sequence"])
913 if (global_t %
args[
"output"][
"paraview"][
"skip_frame"].get<int>())
918 logger().trace(
"Saving VTU...");
919 const std::string step_name =
args[
"output"][
"advanced"][
"timestep_prefix"];
928 [step_name](
int i) {
return fmt::format(step_name +
"{:d}.vtm", i); },
929 global_t, t0, dt,
args[
"output"][
"paraview"][
"skip_frame"].get<
int>());
935 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_solve_sequence_debug"].get<
bool>())
938 const bool has_time =
args.contains(
"time") && !
args[
"time"].is_null();
941 dt =
args[
"time"][
"dt"];
954 time_callback(t, time_steps, t0 + dt * t, t0 + dt * time_steps);
959 const std::string restart_json_path =
args[
"output"][
"restart_json"];
960 if (restart_json_path.empty())
968 restart_json[
"time"] = {{
"t0", t0 + dt * t}};
969 restart_json[
"output"] = {{
"data", {{
"file_index_offset", global_t}}}};
971 restart_json[
"space"] = R
"({
974 "abs_max_edge_length": -1,
975 "rel_max_edge_length": -1
981 restart_json[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"] = std::min(
982 args[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"].get<double>(),
983 starting_min_edge_length *
args[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"].get<double>());
984 restart_json[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"] = std::numeric_limits<float>::max();
986 std::string rest_mesh_path =
args[
"output"][
"data"][
"rest_mesh"].get<std::string>();
987 if (!rest_mesh_path.empty())
989 if (!rest_mesh_written)
990 logger().warn(
"Restart JSON for {} references a rest mesh that this formulation does not write.",
name());
994 std::vector<json> patch;
995 if (
args[
"geometry"].is_array())
997 const std::vector<json> in_geometry =
args[
"geometry"];
998 for (
int i = 0; i < in_geometry.size(); ++i)
1000 if (!in_geometry[i][
"is_obstacle"].get<bool>())
1004 {
"path", fmt::format(
"/geometry/{}", i)},
1009 const int remaining_geometry = in_geometry.size() - patch.size();
1010 assert(remaining_geometry >= 0);
1014 {
"path", fmt::format(
"/geometry/{}", remaining_geometry > 0 ?
"0" :
"-")},
1017 {
"mesh", rest_mesh_path},
1023 assert(
args[
"geometry"].is_object());
1026 {
"path",
"/geometry"},
1030 {
"path",
"/geometry"},
1033 {
"mesh", rest_mesh_path},
1038 restart_json[
"patch"] = patch;
1041 restart_json[
"input"] = {{
1049 file << restart_json;
1054 return t +
args[
"output"][
"data"][
"file_index_offset"].get<
int>();
1064 if (
output_path.empty() || path.empty() || std::filesystem::path(path).is_absolute())
1068 return std::filesystem::weakly_canonical(std::filesystem::path(
output_path) / path).string();
1072 const std::vector<basis::ElementBases> &bases,
1073 const std::vector<int> &node_ids,
1074 std::vector<RowVectorNd> &positions)
1076 positions.resize(node_ids.size());
1077 for (
int n = 0; n < int(node_ids.size()); ++n)
1079 const int node_id = node_ids[n];
1081 for (
const auto &bs : bases)
1083 for (
const auto &b : bs.bases)
1085 for (
const auto &lg : b.global())
1087 if (lg.index == node_id)
1089 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
bool startswith(const std::string &str, const std::string &prefix)
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