34#include <polysolve/linear/Solver.hpp>
37#include <Eigen/Sparse>
39#include <spdlog/sinks/basic_file_sink.h>
41#include <ipc/collision_mesh.hpp>
42#include <ipc/utils/logger.hpp>
46#include <unordered_map>
68 class ViscousDampingPrev;
87 using UserPostStepCallback = std::function<void(
int step,
State &state,
const Eigen::MatrixXd &sol,
const Eigen::MatrixXd *disp_grad,
const Eigen::MatrixXd *pressure)>;
125 void set_max_threads(
const int max_threads = std::numeric_limits<int>::max());
130 void init(
const json &
args,
const bool strict_validation);
148 const std::string &log_file,
149 const spdlog::level::level_enum log_level,
150 const spdlog::level::level_enum file_log_level,
151 const bool is_quiet);
156 void init_logger(std::ostream &os,
const spdlog::level::level_enum log_level);
160 void set_log_level(
const spdlog::level::level_enum log_level);
165 std::string
get_log(
const Eigen::MatrixXd &sol)
167 std::stringstream ss;
174 void init_logger(
const std::vector<spdlog::sink_ptr> &sinks,
const spdlog::level::level_enum log_level);
190 std::shared_ptr<assembler::Assembler>
assembler =
nullptr;
207 std::vector<basis::ElementBases>
bases;
221 std::map<int, Eigen::MatrixXd>
polys;
223 std::map<int, std::pair<Eigen::MatrixXd, Eigen::MatrixXi>>
polys_3d;
286 const std::vector<basis::ElementBases> &
bases,
296 const std::vector<basis::ElementBases> &bases_)
const;
307 const int n_b_samples_j =
args[
"space"][
"advanced"][
"n_boundary_samples"];
308 const int gdiscr_order =
mesh->orders().size() <= 0 ? 1 :
mesh->orders().maxCoeff();
309 const int discr_order = std::max(
disc_orders.maxCoeff(), gdiscr_order);
313 return {{n_b_samples, n_b_samples}};
318 const int actual_dim =
problem->is_scalar() ? 1 :
mesh->dimension();
336 void set_materials(std::vector<std::shared_ptr<assembler::Assembler>> &assemblers)
const;
352 Eigen::MatrixXd &pressure,
354 const InitialConditionOverride *ic_override =
nullptr);
362 Eigen::MatrixXd &pressure,
368 logger().error(
"Load the mesh first!");
396 Eigen::MatrixXd &pressure,
407 Eigen::MatrixXd &sol,
408 Eigen::MatrixXd &pressure,
421 Eigen::MatrixXd &sol,
422 Eigen::MatrixXd &pressure,
436 Eigen::MatrixXd &sol,
437 Eigen::MatrixXd &pressure,
439 const InitialConditionOverride *ic_override =
nullptr);
451 Eigen::MatrixXd &sol,
453 const InitialConditionOverride *ic_override =
nullptr);
460 const double t = 1.0,
461 const bool init_time_integrator =
true,
462 const InitialConditionOverride *ic_override =
nullptr);
468 const double t = 1.0,
469 const InitialConditionOverride *ic_override =
nullptr);
474 void initial_solution(Eigen::MatrixXd &solution,
const InitialConditionOverride *ic_override =
nullptr)
const;
478 void initial_velocity(Eigen::MatrixXd &velocity,
const InitialConditionOverride *ic_override =
nullptr)
const;
482 void initial_acceleration(Eigen::MatrixXd &acceleration,
const InitialConditionOverride *ic_override =
nullptr)
const;
503 std::shared_ptr<polysolve::nonlinear::Solver>
make_nl_solver(
bool for_al)
const;
509 return args[
"boundary_conditions"][
"periodic_boundary"][
"enabled"].get<
bool>();
523 const std::unique_ptr<polysolve::linear::Solver> &solver,
526 const bool compute_spectrum,
551 std::unordered_map<int, std::array<bool, 3>>
594 std::unique_ptr<mesh::Mesh>
mesh;
603 void load_mesh(
bool non_conforming =
false,
604 const std::vector<std::string> &names = std::vector<std::string>(),
605 const std::vector<Eigen::MatrixXi> &cells = std::vector<Eigen::MatrixXi>(),
606 const std::vector<Eigen::MatrixXd> &vertices = std::vector<Eigen::MatrixXd>());
613 void load_mesh(GEO::Mesh &meshin,
const std::function<
int(
const size_t,
const std::vector<int> &,
const RowVectorNd &,
bool)> &boundary_marker,
bool non_conforming =
false,
bool skip_boundary_sideset =
false);
619 void load_mesh(
const Eigen::MatrixXd &
V,
const Eigen::MatrixXi &
F,
bool non_conforming =
false)
631#ifdef POLYFEM_WITH_ITR
637 bool remesh(
const double time,
const double dt, Eigen::MatrixXd &sol);
643 vertices.setZero(
mesh->n_vertices(),
mesh->dimension());
645 for (
int v = 0; v <
mesh->n_vertices(); v++)
646 vertices.row(v) =
mesh->point(v);
652 assert(
mesh->is_simplicial());
657 int dim =
mesh->dimension();
658 elements.setZero(gbases.size(), dim + 1);
659 for (
int e = 0; e < gbases.size(); e++)
662 for (
const auto &gbs : gbases[e].bases)
663 elements(e, i++) = node_to_primitive_map[gbs.global()[0].index];
683 const std::vector<basis::ElementBases> &
bases,
684 const std::vector<basis::ElementBases> &
geom_bases,
710 return args[
"contact"][
"enabled"];
718 return args[
"contact"][
"adhesion"][
"adhesion_enabled"];
726 return (
args[
"boundary_conditions"][
"pressure_boundary"].size() > 0)
727 || (
args[
"boundary_conditions"][
"pressure_cavity"].size() > 0);
754 void export_data(
const Eigen::MatrixXd &sol,
const Eigen::MatrixXd &pressure);
763 void save_timestep(
const double time,
const int t,
const double t0,
const double dt,
const Eigen::MatrixXd &sol,
const Eigen::MatrixXd &pressure);
770 void save_subsolve(
const int i,
const int t,
const Eigen::MatrixXd &sol,
const Eigen::MatrixXd &pressure);
775 void save_json(
const Eigen::MatrixXd &sol, std::ostream &out);
779 void save_json(
const Eigen::MatrixXd &sol);
797 std::string
resolve_input_path(
const std::string &path,
const bool only_if_exists =
false)
const;
822 return args[
"boundary_conditions"][
"periodic_boundary"][
"linear_displacement_offset"].size() > 0;
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...
Caches basis evaluation and geometric mapping at every element.
void compute_mesh_stats(const polyfem::mesh::Mesh &mesh)
compute stats (counts els type, mesh lenght, etc), step 1 of solve
Runtime override for initial-condition histories.
Eigen::MatrixXd solution
ndof by H (history size) matrix where each col is solution from a time step.
bool is_empty() const
Returns true when no quantity is overridden.
Eigen::MatrixXd velocity
ndof by H (history size) matrix where each col is velocity from a time step.
Eigen::MatrixXd acceleration
ndof by H (history size) matrix where each col is acceleration from a time step.
main class that contains the polyfem solver and all its state
void solve_transient_navier_stokes(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves transient navier stokes with FEM
std::shared_ptr< assembler::Problem > problem
current problem, it contains rhs and bc
void save_subsolve(const int i, const int t, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &pressure)
saves a subsolve when save_solve_sequence_debug is true
bool iso_parametric() const
check if using iso parametric bases
void reset_mesh()
Resets the mesh.
StiffnessMatrix pure_mass
void init(const json &args, const bool strict_validation)
initialize the polyfem solver with a json settings
void solve_transient_tensor_nonlinear(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol, UserPostStepCallback user_post_step={}, const InitialConditionOverride *ic_override=nullptr)
solves transient tensor nonlinear problem
const std::vector< basis::ElementBases > & geom_bases() const
Get a constant reference to the geometry mapping bases.
ipc::CollisionMesh collision_mesh
IPC collision mesh.
StiffnessMatrix mass
Mass matrix, it is computed only for time dependent problems.
bool has_dhat
stores if input json contains dhat
std::vector< RowVectorNd > dirichlet_nodes_position
std::string resolve_input_path(const std::string &path, const bool only_if_exists=false) const
Resolve input path relative to root_path() if the path is not absolute.
std::unordered_map< int, std::array< bool, 3 > > boundary_conditions_ids(const std::string &bc_type) const
Construct a vector of boundary conditions ids with their dimension flags.
void build_collision_mesh()
extracts the boundary mesh for collision, called in build_basis
std::vector< mesh::LocalBoundary > local_boundary
mapping from elements to nodes for dirichlet boundary conditions
std::vector< mesh::LocalBoundary > local_pressure_boundary
mapping from elements to nodes for pressure boundary conditions
std::vector< int > dirichlet_nodes
per node dirichlet
std::shared_ptr< polyfem::mesh::MeshNodes > mesh_nodes
Mapping from input nodes to FE nodes.
void compute_errors(const Eigen::MatrixXd &sol)
computes all errors
Eigen::VectorXi in_primitive_to_primitive
maps in vertices/edges/faces/cells to polyfem vertices/edges/faces/cells
void solve_tensor_nonlinear(int step, Eigen::MatrixXd &sol, const bool init_lagging=true, UserPostStepCallback user_post_step={})
solves nonlinear problems
std::shared_ptr< assembler::Mass > mass_matrix_assembler
std::vector< int > pressure_boundary_nodes
list of neumann boundary nodes
void init_solve(Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, const InitialConditionOverride *ic_override=nullptr)
initialize solver
std::unordered_map< int, std::vector< mesh::LocalBoundary > > local_pressure_cavity
mapping from elements to nodes for pressure boundary conditions
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
Eigen::MatrixXd rhs
System right-hand side.
void build_node_mapping()
build the mapping from input nodes to polyfem nodes
std::unique_ptr< polysolve::linear::Solver > static_linear_solver_cache
Linear solver instance from the most recent static linear solve.
void init_linear_solve(Eigen::MatrixXd &sol, const double t=1.0, const InitialConditionOverride *ic_override=nullptr)
initialize the linear solve
void initial_acceleration(Eigen::MatrixXd &acceleration, const InitialConditionOverride *ic_override=nullptr) const
Load or compute the initial acceleration.
void build_mesh_matrices(Eigen::MatrixXd &V, Eigen::MatrixXi &F)
Build the mesh matrices (vertices and elements) from the mesh using the bases node ordering.
io::OutStatsData stats
Other statistics.
bool optimization_enabled
json args
main input arguments containing all defaults
void build_polygonal_basis()
builds bases for polygons, called inside build_basis
assembler::AssemblyValsCache pure_mass_ass_vals_cache
std::vector< basis::ElementBases > geom_bases_
Geometric mapping bases, if the elements are isoparametric, this list is empty.
std::vector< RowVectorNd > neumann_nodes_position
void load_mesh(bool non_conforming=false, const std::vector< std::string > &names=std::vector< std::string >(), const std::vector< Eigen::MatrixXi > &cells=std::vector< Eigen::MatrixXi >(), const std::vector< Eigen::MatrixXd > &vertices=std::vector< Eigen::MatrixXd >())
loads the mesh from the json arguments
Eigen::VectorXi disc_ordersq
std::map< int, Eigen::MatrixXd > polys
polygons, used since poly have no geom mapping
void solve_transient_navier_stokes_split(const int time_steps, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves transient navier stokes with operator splitting
void sol_to_pressure(Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure)
splits the solution in solution and pressure for mixed problems
void solve_homogenization(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol, UserPostStepCallback user_post_step={})
int n_pressure_bases
number of pressure bases
void set_max_threads(const int max_threads=std::numeric_limits< int >::max())
assembler::AssemblyValsCache pressure_ass_vals_cache
used to store assembly values for pressure for small problems
int n_bases
number of bases
void solve_homogenization_step(int step, Eigen::MatrixXd &sol, bool adaptive_initial_weight=false, UserPostStepCallback user_post_step={})
In Elasticity PDE, solve for "min W(disp_grad + \grad u)" instead of "min W(\grad u)".
void set_log_level(const spdlog::level::level_enum log_level)
change log level
void assemble_mass_mat()
assemble mass, step 4 of solve build mass matrix based on defined basis modifies mass (and maybe more...
double starting_min_edge_length
std::shared_ptr< polyfem::mesh::MeshNodes > geom_mesh_nodes
std::string resolve_output_path(const std::string &path) const
Resolve output path relative to output_dir if the path is not absolute.
double min_boundary_edge_length
io::OutRuntimeData timings
runtime statistics
void build_stiffness_mat(StiffnessMatrix &stiffness)
utility that builds the stiffness matrix and collects stats, used only for linear problems
bool has_constraints() const
void save_restart_json(const double t0, const double dt, const int t) const
Save a JSON sim file for restarting the simulation at time t.
std::shared_ptr< assembler::ViscousDamping > damping_assembler
std::vector< basis::ElementBases > pressure_bases
FE pressure bases for mixed elements, the size is #elements.
mesh::Obstacle obstacle
Obstacles used in collisions.
std::string root_path() const
Get the root path for the state (e.g., args["root_path"] or ".")
std::shared_ptr< assembler::ViscousDampingPrev > damping_prev_assembler
std::shared_ptr< assembler::Assembler > pressure_assembler
std::string formulation() const
return the formulation (checks if the problem is scalar or not and deals with multiphysics)
Eigen::VectorXi disc_orders
vector of discretization orders, used when not all elements have the same degree, one per element
assembler::AssemblyValsCache ass_vals_cache
used to store assembly values for small problems
void solve_navier_stokes(int step, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves a navier stokes
void solve_transient_linear(const int time_steps, const double t0, const double dt, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={}, const InitialConditionOverride *ic_override=nullptr)
solves transient linear problem
std::shared_ptr< utils::PeriodicBoundary > periodic_bc
periodic BC and periodic mesh utils
io::OutGeometryData out_geom
visualization stuff
void init_homogenization_solve(const double t)
std::string get_log(const Eigen::MatrixXd &sol)
gets the output log as json this is not what gets printed but more informative information,...
assembler::AssemblyValsCache mass_ass_vals_cache
QuadratureOrders n_boundary_samples() const
quadrature used for projecting boundary conditions
bool use_avg_pressure
use average pressure for stokes problem to fix the additional dofs, true by default if false,...
double characteristic_length
void export_data(const Eigen::MatrixXd &sol, const Eigen::MatrixXd &pressure)
saves all data on the disk according to the input params
std::shared_ptr< assembler::Assembler > assembler
assemblers
void build_basis()
builds the bases step 2 of solve modifies bases, pressure_bases, geom_bases_, boundary_nodes,...
std::map< int, basis::InterfaceData > poly_edge_to_data
nodes on the boundary of polygonal elements, used for harmonic bases
double avg_mass
average system mass, used for contact with IPC
void set_materials(std::vector< std::shared_ptr< assembler::Assembler > > &assemblers) const
set the material and the problem dimension
void save_json(const Eigen::MatrixXd &sol, std::ostream &out)
saves the output statistic to a stream
std::vector< basis::ElementBases > bases
FE bases, the size is #elements.
void initial_velocity(Eigen::MatrixXd &velocity, const InitialConditionOverride *ic_override=nullptr) const
Load or compute the initial velocity.
void solve_linear(int step, Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={})
solves a linear problem
std::shared_ptr< assembler::PressureAssembler > elasticity_pressure_assembler
void build_periodic_collision_mesh()
void init_logger(const std::string &log_file, const spdlog::level::level_enum log_level, const spdlog::level::level_enum file_log_level, const bool is_quiet)
initializing the logger
std::map< int, std::pair< Eigen::MatrixXd, Eigen::MatrixXi > > polys_3d
polyhedra, used since poly have no geom mapping
bool is_adhesion_enabled() const
does the simulation have adhesion
std::string output_dir
Directory for output files.
void solve(Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={}, const InitialConditionOverride *ic_override=nullptr)
solves the problem, call other methods
bool is_pressure_enabled() const
does the simulation has pressure
void get_vertices(Eigen::MatrixXd &vertices) const
Gather geometry vertices into a dense matrix.
bool has_periodic_bc() const
ipc::CollisionMesh periodic_collision_mesh
IPC collision mesh under periodic BC.
std::vector< int > neumann_nodes
per node neumann
Eigen::VectorXi periodic_collision_mesh_to_basis
index mapping from periodic 2x2 collision mesh to FE periodic mesh
void load_mesh(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F, bool non_conforming=false)
loads the mesh from V and F,
std::shared_ptr< polyfem::mesh::MeshNodes > pressure_mesh_nodes
assembler::MacroStrainValue macro_strain_constraint
std::shared_ptr< assembler::RhsAssembler > build_rhs_assembler() const
build a RhsAssembler for the problem
bool is_problem_linear() const
Returns whether the system is linear. Collisions and pressure add nonlinearity to the problem.
std::shared_ptr< assembler::PressureAssembler > build_pressure_assembler() const
void init_time()
initialize time settings if args contains "time"
bool is_obstacle_vertex(const size_t vi) const
checks if vertex is obstacle
std::vector< mesh::LocalBoundary > total_local_boundary
mapping from elements to nodes for all mesh
std::shared_ptr< polysolve::nonlinear::Solver > make_nl_solver(bool for_al) const
factory to create the nl solver depending on input
int n_geom_bases
number of geometric bases
void save_timestep(const double time, const int t, const double t0, const double dt, const Eigen::MatrixXd &sol, const Eigen::MatrixXd &pressure)
saves a timestep
spdlog::sink_ptr console_sink_
logger sink to stdout
std::shared_ptr< assembler::HRZMass > pure_mass_matrix_assembler
void initial_solution(Eigen::MatrixXd &solution, const InitialConditionOverride *ic_override=nullptr) const
Load or compute the initial solution.
void init_nonlinear_tensor_solve(Eigen::MatrixXd &sol, const double t=1.0, const bool init_time_integrator=true, const InitialConditionOverride *ic_override=nullptr)
initialize the nonlinear solver
void assemble_rhs()
compute rhs, step 3 of solve build rhs vector based on defined basis and given rhs of the problem mod...
void solve_problem(Eigen::MatrixXd &sol, Eigen::MatrixXd &pressure, UserPostStepCallback user_post_step={}, const InitialConditionOverride *ic_override=nullptr)
solves the problems
void get_elements(Eigen::MatrixXi &elements) const
Gather geometry elements into a dense matrix.
double starting_max_edge_length
std::vector< mesh::LocalBoundary > local_neumann_boundary
mapping from elements to nodes for neumann boundary conditions
std::vector< int > primitive_to_node() const
std::vector< int > boundary_nodes
list of boundary nodes
solver::SolveData solve_data
timedependent stuff cached
std::vector< int > node_to_primitive() const
spdlog::sink_ptr file_sink_
Eigen::VectorXi in_node_to_node
Inpute nodes (including high-order) to polyfem nodes, only for isoparametric.
double characteristic_force_density
bool is_homogenization() const
std::function< void(int, int, double, double)> time_callback
bool is_contact_enabled() const
does the simulation have contact
std::shared_ptr< assembler::MixedAssembler > mixed_assembler
Utilies related to export of geometry.
Abstract mesh class to capture 2d/3d conforming and non-conforming meshes.
static std::unique_ptr< Mesh > create(const std::string &path, const bool non_conforming=false)
factory to build the proper mesh
class to store time stepping data
std::function< void(int step, State &state, const Eigen::MatrixXd &sol, const Eigen::MatrixXd *disp_grad, const Eigen::MatrixXd *pressure)> UserPostStepCallback
User callback at the end of every solver step.
polyfem::legacy::State State
spdlog::logger & logger()
Retrieves the current logger.
std::array< int, 2 > QuadratureOrders
Eigen::Matrix< double, 1, Eigen::Dynamic, Eigen::RowMajor, 1, 3 > RowVectorNd
Eigen::SparseMatrix< double, Eigen::ColMajor > StiffnessMatrix