34#include <spdlog/fmt/fmt.h>
35#include <paraviewo/VTMWriter.hpp>
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 (mesh.
orders().size() <= 0)
87 if (args[
"space"][
"discr_order"] == 1)
89 return args[
"space"][
"advanced"][
"isoparametric"];
92 if (mesh.
orders().minCoeff() != mesh.
orders().maxCoeff())
95 if (args[
"space"][
"discr_order"] == mesh.
orders().minCoeff())
98 return args[
"space"][
"advanced"][
"isoparametric"];
102 void build_in_node_to_in_primitive(
const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
103 Eigen::VectorXi &in_node_to_in_primitive,
104 Eigen::VectorXi &in_node_offset)
106 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
107 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
108 const int num_face_nodes = mesh_nodes.num_face_nodes();
109 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
111 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
113 const long n_vertices = num_vertex_nodes;
114 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
115 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
117 in_node_to_in_primitive.resize(num_nodes);
118 in_node_offset.resize(num_nodes);
121 in_node_to_in_primitive.head(num_vertex_nodes).setLinSpaced(num_vertex_nodes, 0, num_vertex_nodes - 1);
122 in_node_offset.head(num_vertex_nodes).setZero();
124 int prim_offset = n_vertices;
125 int node_offset = num_vertex_nodes;
126 auto foo = [&](
const int num_prims,
const int num_prim_nodes) {
127 if (num_prims <= 0 || num_prim_nodes <= 0)
129 const Eigen::VectorXi range = Eigen::VectorXi::LinSpaced(num_prim_nodes, 0, num_prim_nodes - 1);
131 const int node_per_prim = num_prim_nodes / num_prims;
133 in_node_to_in_primitive.segment(node_offset, num_prim_nodes) =
134 range.array() / node_per_prim + prim_offset;
136 in_node_offset.segment(node_offset, num_prim_nodes) =
137 range.unaryExpr([&](
const int x) {
return x % node_per_prim; });
139 prim_offset += num_prims;
140 node_offset += num_prim_nodes;
143 foo(mesh.n_edges(), num_edge_nodes);
144 foo(mesh.n_faces(), num_face_nodes);
145 foo(mesh.n_cells(), num_cell_nodes);
148 bool build_in_primitive_to_primitive(
149 const mesh::Mesh &mesh,
const mesh::MeshNodes &mesh_nodes,
150 const Eigen::VectorXi &in_ordered_vertices,
151 const Eigen::MatrixXi &in_ordered_edges,
152 const Eigen::MatrixXi &in_ordered_faces,
153 Eigen::VectorXi &in_primitive_to_primitive)
156 const int num_vertex_nodes = mesh_nodes.num_vertex_nodes();
157 const int num_edge_nodes = mesh_nodes.num_edge_nodes();
158 const int num_face_nodes = mesh_nodes.num_face_nodes();
159 const int num_cell_nodes = mesh_nodes.num_cell_nodes();
160 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
162 const long n_vertices = num_vertex_nodes;
163 const int num_in_primitives = n_vertices + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
164 const int num_primitives = mesh.n_vertices() + mesh.n_edges() + mesh.n_faces() + mesh.n_cells();
166 in_primitive_to_primitive.setLinSpaced(num_in_primitives, 0, num_in_primitives - 1);
174 if (in_ordered_vertices.rows() != n_vertices)
176 logger().warn(
"Node ordering disabled, in_ordered_vertices != n_vertices, {} != {}", in_ordered_vertices.rows(), n_vertices);
180 in_primitive_to_primitive.head(n_vertices) = in_ordered_vertices;
182 int in_offset = n_vertices;
183 int offset = mesh.n_vertices();
189 logger().trace(
"Building Mesh edges to IDs...");
191 const auto edges_to_ids = mesh.edges_to_ids();
192 if (in_ordered_edges.rows() != edges_to_ids.size())
194 logger().warn(
"Node ordering disabled, in_ordered_edges != edges_to_ids, {} != {}", in_ordered_edges.rows(), edges_to_ids.size());
198 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
200 logger().trace(
"Building in-edge to edge mapping...");
202 for (
int in_ei = 0; in_ei < in_ordered_edges.rows(); in_ei++)
204 const std::pair<int, int> in_edge(
205 in_ordered_edges.row(in_ei).minCoeff(),
206 in_ordered_edges.row(in_ei).maxCoeff());
207 in_primitive_to_primitive[in_offset + in_ei] =
208 offset + edges_to_ids.at(in_edge);
211 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
213 in_offset += mesh.n_edges();
214 offset += mesh.n_edges();
220 if (mesh.is_volume())
222 logger().trace(
"Building Mesh faces to IDs...");
224 const auto faces_to_ids = mesh.faces_to_ids();
225 if (in_ordered_faces.rows() != faces_to_ids.size())
227 logger().warn(
"Node ordering disabled, in_ordered_faces != faces_to_ids, {} != {}", in_ordered_faces.rows(), faces_to_ids.size());
231 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
233 logger().trace(
"Building in-face to face mapping...");
235 for (
int in_fi = 0; in_fi < in_ordered_faces.rows(); in_fi++)
237 std::vector<int> in_face(in_ordered_faces.cols());
238 for (
int i = 0; i < in_face.size(); i++)
239 in_face[i] = in_ordered_faces(in_fi, i);
240 std::sort(in_face.begin(), in_face.end());
242 in_primitive_to_primitive[in_offset + in_fi] =
243 offset + faces_to_ids.at(in_face);
246 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
248 in_offset += mesh.n_faces();
249 offset += mesh.n_faces();
259 const int n_b_samples_j =
args[
"space"][
"advanced"][
"n_boundary_samples"];
260 const int boundary_order = std::max({discr_order, discr_orderq, gdiscr_order});
262 return {{n_b_samples, n_b_samples}};
295 mesh_ = std::move(mesh);
312 mesh_->prepare_mesh();
322 const bool iso_parametric,
323 const Eigen::VectorXi &disc_orders,
324 const Eigen::VectorXi &disc_ordersq,
325 const std::string &basis_type,
326 const std::string &poly_basis_type,
329 const int quadrature_order,
330 const int mass_quadrature_order,
331 const bool use_corner_quadrature,
332 const int n_harmonic_samples,
333 const int integral_constraints,
336 std::shared_ptr<GeometryMapping> geometry)
338 using namespace mesh;
340 const std::string space_assembler_name = space_assembler.
name();
341 const bool build_geom_mapping = geometry ==
nullptr;
348 space.
bases = std::make_shared<std::vector<basis::ElementBases>>();
349 space.
geometry = build_geom_mapping ? std::make_shared<GeometryMapping>() : std::move(geometry);
355 Eigen::MatrixXi geom_disc_orders;
356 if (build_geom_mapping && !iso_parametric)
358 if (mesh.
orders().size() <= 0)
361 geom_disc_orders.setConstant(1);
364 geom_disc_orders = mesh.
orders();
366 space.
geometry->bases = std::make_shared<std::vector<basis::ElementBases>>();
367 space.
geometry->disc_orders = geom_disc_orders;
370 Eigen::MatrixXi geom_disc_ordersq = geom_disc_orders;
372 logger().info(
"Building {} basis...", (build_geom_mapping ? (iso_parametric ?
"isoparametric" :
"not isoparametric") :
"finite-element"));
377 const bool has_polys = mesh.
has_poly();
378 std::map<int, basis::InterfaceData> poly_edge_to_data_geom;
380 const bool use_continuous_gbasis =
true;
384 const Mesh3D &tmp_mesh =
dynamic_cast<const Mesh3D &
>(mesh);
386 if (basis_type ==
"Spline")
389 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
394 if (build_geom_mapping && !iso_parametric)
396 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
397 geom_disc_orders, geom_disc_ordersq,
false,
false, has_polys,
398 !use_continuous_gbasis, use_corner_quadrature,
403 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
405 basis_type ==
"Bernstein",
406 basis_type ==
"Serendipity",
407 has_polys,
false, use_corner_quadrature,
413 const Mesh2D &tmp_mesh =
dynamic_cast<const Mesh2D &
>(mesh);
415 if (basis_type ==
"Spline")
418 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
423 if (build_geom_mapping && !iso_parametric)
425 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
426 geom_disc_orders,
false,
false, has_polys,
427 !use_continuous_gbasis, use_corner_quadrature,
432 tmp_mesh, space_assembler_name, quadrature_order, mass_quadrature_order,
434 basis_type ==
"Bernstein",
435 basis_type ==
"Serendipity",
436 has_polys,
false, use_corner_quadrature,
441 const bool use_fe_space_as_geometry = build_geom_mapping ? iso_parametric : space.
is_iso_parametric();
443 use_fe_space_as_geometry,
445 mass_quadrature_order,
447 integral_constraints,
451 if (build_geom_mapping)
454 space.
geometry->init_from_fe_space(space);
458 assert(space.
geometry->n_bases > 0);
466 if (build_geom_mapping)
469 logger().debug(
"Building node mapping...");
473 logger().debug(
"Done (took {}s)", timer2.getElapsedTime());
486 const std::string &poly_basis_type,
489 const int quadrature_order,
490 const int mass_quadrature_order,
491 const int n_harmonic_samples,
492 const int integral_constraints,
502 const std::string space_assembler_name = space_assembler.
name();
506 logger().info(
"Computing polygonal basis...");
514 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
518 assert(linear_assembler);
525 mass_quadrature_order,
526 integral_constraints,
535 if (poly_basis_type ==
"MeanValue")
538 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
540 mass_quadrature_order,
543 else if (poly_basis_type ==
"Wachspress")
546 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
548 mass_quadrature_order,
554 assert(linear_assembler);
561 mass_quadrature_order,
562 integral_constraints,
576 if (poly_basis_type ==
"MeanValue" || poly_basis_type ==
"Wachspress")
580 assert(linear_assembler);
587 mass_quadrature_order,
588 integral_constraints,
597 if (poly_basis_type ==
"MeanValue")
600 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
602 mass_quadrature_order,
605 else if (poly_basis_type ==
"Wachspress")
608 space_assembler.
name(), dim, mesh_2d, space.
n_bases,
610 mass_quadrature_order,
616 assert(linear_assembler);
623 mass_quadrature_order,
624 integral_constraints,
648 const std::string &basis_type,
650 Eigen::VectorXi &space_in_node_to_node,
651 Eigen::VectorXi &space_in_primitive_to_primitive)
const
653 space_in_node_to_node.resize(0);
654 space_in_primitive_to_primitive.resize(0);
656 if (basis_type ==
"Spline")
658 logger().warn(
"Node ordering disabled, it dosent work for splines!");
664 logger().warn(
"Node ordering disabled, it works only for p < 4 and uniform order!");
670 logger().warn(
"Node ordering disabled, not supported for non-conforming meshes!");
676 logger().warn(
"Node ordering disabled, not supported for polygonal meshes!");
682 logger().warn(
"Node ordering disabled, input vertices/edges/faces not computed!");
688 logger().warn(
"Node ordering disabled, FE space does not expose mesh nodes!");
692 const int num_vertex_nodes = space.
mesh_nodes->num_vertex_nodes();
693 const int num_edge_nodes = space.
mesh_nodes->num_edge_nodes();
694 const int num_face_nodes = space.
mesh_nodes->num_face_nodes();
695 const int num_cell_nodes = space.
mesh_nodes->num_cell_nodes();
697 const int num_nodes = num_vertex_nodes + num_edge_nodes + num_face_nodes + num_cell_nodes;
698 const long n_vertices = num_vertex_nodes;
704 logger().trace(
"Building in-node to in-primitive mapping...");
706 Eigen::VectorXi in_node_to_in_primitive;
707 Eigen::VectorXi in_node_offset;
708 build_in_node_to_in_primitive(mesh, *space.
mesh_nodes, in_node_to_in_primitive, in_node_offset);
710 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
712 logger().trace(
"Building in-primitive to primitive mapping...");
714 bool ok = build_in_primitive_to_primitive(
719 space_in_primitive_to_primitive);
721 logger().trace(
"Done (took {}s)", timer.getElapsedTime());
725 space_in_node_to_node.resize(0);
726 space_in_primitive_to_primitive.resize(0);
730 const auto &tmp = space.
mesh_nodes->in_ordered_vertices();
733 max_tmp = std::max(max_tmp, v);
735 space_in_node_to_node.resize(max_tmp + 1);
736 for (
int i = 0; i < tmp.size(); ++i)
739 space_in_node_to_node[tmp[i]] = i;
744 const json &space_args,
746 Eigen::VectorXi &disc_orders,
747 Eigen::VectorXi &disc_ordersq)
753 const json &space_args,
754 const int fe_space_id,
756 Eigen::VectorXi &disc_orders,
757 Eigen::VectorXi &disc_ordersq)
759 const auto assign_order = [&](
const json &order_json, Eigen::VectorXi &orders) {
762 if (order_json.is_number_integer())
764 orders.setConstant(order_json);
766 else if (order_json.is_string())
771 assert(tmp.size() == orders.size());
772 assert(tmp.cols() == 1);
775 else if (order_json.is_array())
778 std::map<int, int> body_orders;
779 bool has_matching_order =
false;
780 for (
const json &entry : order_json)
782 if (entry.contains(
"fe_space"))
784 const int entry_space_id = entry[
"fe_space"].get<
int>();
785 if (entry_space_id >= 0 && fe_space_id < 0)
787 if (entry_space_id >= 0 && entry_space_id != fe_space_id)
791 has_matching_order =
true;
792 const int order = entry[
"order"];
793 if (!entry.contains(
"id") || (entry[
"id"].is_number_integer() && entry[
"id"].get<
int>() < 0))
795 orders.setConstant(order);
799 for (
const int id : utils::json_as_array<int>(entry[
"id"]))
801 body_orders[id] = order;
802 logger().trace(
"bid {}, discr {}",
id, order);
806 if (!has_matching_order)
811 const auto order = body_orders.find(mesh.
get_body_id(e));
812 if (order != body_orders.end())
813 orders[e] = order->second;
822 assign_order(space_args[
"discr_order"], disc_orders);
824 const json &discr_orderq = space_args[
"discr_orderq"];
825 if (discr_orderq.is_number_integer() && discr_orderq.get<
int>() < 0)
826 disc_ordersq = disc_orders;
828 assign_order(discr_orderq, disc_ordersq);
830 int max_prism_order = 0;
834 max_prism_order = std::max({max_prism_order, disc_orders[e], disc_ordersq[e]});
837 if (max_prism_order > 0)
842 disc_orders[e] = max_prism_order;
847 "discretization orders: p=[{}, {}], q=[{}, {}]",
848 disc_orders.minCoeff(), disc_orders.maxCoeff(),
849 disc_ordersq.minCoeff(), disc_ordersq.maxCoeff());
855 if (out_path.empty())
858 std::ofstream file(out_path);
861 logger().error(
"Unable to save simulation JSON to {}", out_path);
869 assert(
mesh_ !=
nullptr);
875 std::vector<int> body_ids(
mesh_->n_elements());
876 for (
int i = 0; i <
mesh_->n_elements(); ++i)
877 body_ids[i] =
mesh_->get_body_id(i);
911 sample.requested_fields.empty() ? fields : sample.requested_fields});
929 const bool rest_mesh_written)
const
933 if (!state_path.empty() && time_integrator)
939 void VarForm::save_timestep(
const double time,
const int t,
const double t0,
const double dt,
const Eigen::MatrixXd &solution)
const
941 paraviewo::VTMWriter vtm(time);
946 const std::string step_name =
args[
"output"][
"advanced"][
"timestep_prefix"];
951 [step_name](
int i) {
return fmt::format(step_name +
"{:d}.vtm", i); },
952 global_t, t0, dt,
args[
"output"][
"paraview"][
"skip_frame"].get<
int>());
956 const double time,
const int t,
const double dt,
957 const Eigen::MatrixXd &solution, paraviewo::VTMWriter &vtm,
958 const std::string &block_prefix)
const
961 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_time_sequence"])
964 if (global_t %
args[
"output"][
"paraview"][
"skip_frame"].get<int>())
968 logger().trace(
"Saving VTU...");
969 const std::string step_name =
args[
"output"][
"advanced"][
"timestep_prefix"];
974 opts, vtm, block_prefix);
981 if (!space.
mesh || !
args[
"output"][
"advanced"][
"save_solve_sequence_debug"].get<
bool>())
984 const bool has_time =
args.contains(
"time") && !
args[
"time"].is_null();
987 dt =
args[
"time"][
"dt"];
1000 time_callback(t, time_steps, t0 + dt * t, t0 + dt * time_steps);
1005 const std::string restart_json_path =
args[
"output"][
"restart_json"];
1006 if (restart_json_path.empty())
1014 restart_json[
"time"] = {{
"t0", t0 + dt * t}};
1015 restart_json[
"output"] = {{
"data", {{
"file_index_offset", global_t}}}};
1017 restart_json[
"space"] = R
"({
1020 "abs_max_edge_length": -1,
1021 "rel_max_edge_length": -1
1027 restart_json[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"] = std::min(
1028 args[
"space"][
"remesh"][
"collapse"][
"abs_max_edge_length"].get<double>(),
1029 starting_min_edge_length *
args[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"].get<double>());
1030 restart_json[
"space"][
"remesh"][
"collapse"][
"rel_max_edge_length"] = std::numeric_limits<float>::max();
1032 std::string rest_mesh_path =
args[
"output"][
"data"][
"rest_mesh"].get<std::string>();
1033 if (!rest_mesh_path.empty())
1035 if (!rest_mesh_written)
1036 logger().warn(
"Restart JSON for {} references a rest mesh that this formulation does not write.",
name());
1040 std::vector<json> patch;
1041 if (
args[
"geometry"].is_array())
1043 const std::vector<json> in_geometry =
args[
"geometry"];
1044 for (
int i = 0; i < in_geometry.size(); ++i)
1046 if (!in_geometry[i][
"is_obstacle"].get<bool>())
1050 {
"path", fmt::format(
"/geometry/{}", i)},
1055 const int remaining_geometry = in_geometry.size() - patch.size();
1056 assert(remaining_geometry >= 0);
1060 {
"path", fmt::format(
"/geometry/{}", remaining_geometry > 0 ?
"0" :
"-")},
1063 {
"mesh", rest_mesh_path},
1069 assert(
args[
"geometry"].is_object());
1072 {
"path",
"/geometry"},
1076 {
"path",
"/geometry"},
1079 {
"mesh", rest_mesh_path},
1084 restart_json[
"patch"] = patch;
1087 restart_json[
"input"] = {{
1095 file << restart_json;
1100 return t +
args[
"output"][
"data"][
"file_index_offset"].get<
int>();
1110 if (
output_path.empty() || path.empty() || std::filesystem::path(path).is_absolute())
1114 return std::filesystem::weakly_canonical(std::filesystem::path(
output_path) / path).string();
1118 const std::vector<basis::ElementBases> &bases,
1119 const std::vector<int> &node_ids,
1120 std::vector<RowVectorNd> &positions)
1122 positions.resize(node_ids.size());
1123 for (
int n = 0; n < int(node_ids.size()); ++n)
1125 const int node_id = node_ids[n];
1127 for (
const auto &bs : bases)
1129 for (
const auto &b : bs.bases)
1131 for (
const auto &lg : b.global())
1133 if (lg.index == node_id)
1135 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 is_simplex(const int el_id) const
checks if element is simplex
bool has_prism() const
checks if the mesh has prisms
bool is_prism(const int el_id) const
checks if element is a prism
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
bool is_pyramid(const int el_id) const
checks if element is a pyramid
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