PolyFEM
Loading...
Searching...
No Matches
ImplicitTimeIntegrator.cpp
Go to the documentation of this file.
2
6
10
11namespace polyfem
12{
13 using namespace io;
14 namespace time_integrator
15 {
17 const Eigen::MatrixXd &x_prevs,
18 const Eigen::MatrixXd &v_prevs,
19 const Eigen::MatrixXd &a_prevs,
20 double dt)
21 {
22 assert(x_prevs.cols() > 0 && x_prevs.cols() <= max_steps());
23 assert(x_prevs.cols() == v_prevs.cols());
24 assert(x_prevs.cols() == a_prevs.cols());
25
26 x_prevs_.clear();
27 v_prevs_.clear();
28 a_prevs_.clear();
29
30 const int n = std::min(int(x_prevs.cols()), max_steps());
31 for (int i = 0; i < n; i++)
32 {
33 x_prevs_.push_back(x_prevs.col(i));
34 v_prevs_.push_back(v_prevs.col(i));
35 a_prevs_.push_back(a_prevs.col(i));
36 }
37
38 assert(dt > 0);
39 dt_ = dt;
40 }
41
42 void ImplicitTimeIntegrator::serialize_checkpoint(io::CheckpointWriter &writer, const std::string &group) const
43 {
44 if (x_prevs_.empty() || x_prevs_.size() != v_prevs_.size() || x_prevs_.size() != a_prevs_.size())
45 log_and_throw_error("Cannot checkpoint an uninitialized or inconsistent time integrator.");
46 const int ndof = x_prevs_.front().size();
47 const int history = x_prevs_.size();
48 Eigen::MatrixXd x(ndof, history), v(ndof, history), a(ndof, history);
49 for (int i = 0; i < history; ++i)
50 {
51 if (x_prevs_[i].size() != ndof || v_prevs_[i].size() != ndof || a_prevs_[i].size() != ndof)
52 log_and_throw_error("Cannot checkpoint inconsistent time-integrator history dimensions.");
53 x.col(i) = x_prevs_[i];
54 v.col(i) = v_prevs_[i];
55 a.col(i) = a_prevs_[i];
56 }
57 writer.write_matrix(group + "/x", x);
58 writer.write_matrix(group + "/v", v);
59 writer.write_matrix(group + "/a", a);
60 writer.write_long(group + "/dynamic_order", dynamic_order_ == DynamicOrder::First ? 1 : 2);
61 writer.write_long(group + "/history_length", history);
62 writer.write_double(group + "/dt", dt_);
63 }
64
66 const io::CheckpointReader &reader,
67 const std::string &group,
68 const double expected_dt,
69 const std::function<void(Eigen::MatrixXd &)> &transform)
70 {
71 for (const std::string &key : {"x", "v", "a", "dynamic_order", "history_length", "dt"})
72 if (!reader.exists(group + "/" + key))
73 log_and_throw_error("Checkpoint integrator group {} is missing {}.", group, key);
74 const long order = reader.read_long(group + "/dynamic_order");
75 if (order != (dynamic_order_ == DynamicOrder::First ? 1 : 2))
76 log_and_throw_error("Checkpoint dynamic order is incompatible with {}.", group);
77 const long history = reader.read_long(group + "/history_length");
78 if (history < 1 || history > max_steps())
79 log_and_throw_error("Checkpoint history length {} is incompatible with {}.", history, group);
80 const double stored_dt = reader.read_double(group + "/dt");
81 if (std::abs(stored_dt - expected_dt) > 1e-12 * std::max({1.0, std::abs(stored_dt), std::abs(expected_dt)}))
82 log_and_throw_error("Checkpoint dt {} does not match configured dt {}.", stored_dt, expected_dt);
83 Eigen::MatrixXd x = reader.read_matrix(group + "/x");
84 Eigen::MatrixXd v = reader.read_matrix(group + "/v");
85 Eigen::MatrixXd a = reader.read_matrix(group + "/a");
86 if (x.rows() == 0 || x.cols() != history || v.rows() != x.rows() || a.rows() != x.rows()
87 || v.cols() != history || a.cols() != history)
88 log_and_throw_error("Checkpoint integrator history dimensions are invalid in {}.", group);
89 const int expected_rows = x_prevs_.empty() ? -1 : x_prevs_.front().size();
90 if (expected_rows >= 0 && x.rows() != expected_rows)
92 "Checkpoint integrator {} has {} rows; expected {}.",
93 group, x.rows(), expected_rows);
94 if (transform)
95 {
96 transform(x);
97 transform(v);
98 transform(a);
99 }
100 init(x, v, a, stored_dt);
101 }
102
103 std::shared_ptr<ImplicitTimeIntegrator> ImplicitTimeIntegrator::construct_time_integrator(
104 const json &params,
105 const DynamicOrder dynamic_order)
106 {
107 const std::string type = params.is_object() ? params["type"] : params;
108
109 std::shared_ptr<ImplicitTimeIntegrator> integrator;
110 if (type == "implict_euler" || type == "ImplicitEuler")
111 {
112 integrator = std::make_shared<ImplicitEuler>(dynamic_order);
113 }
114 else if (type == "implict_newmark" || type == "ImplicitNewmark")
115 {
116 integrator = std::make_shared<ImplicitNewmark>(dynamic_order);
117 }
118 else if (utils::StringUtils::startswith(type, "BDF"))
119 {
120 integrator = std::make_shared<BDF>(type == "BDF" ? 1 : std::stoi(type.substr(3)), dynamic_order);
121 }
122 else
123 {
124 logger().error("Unknown time integrator ({})", type);
125 throw std::runtime_error(fmt::format("Unknown time integrator ({})", type));
126 }
127
128 if (params.is_object())
129 integrator->set_parameters(params);
130
131 return integrator;
132 }
133
135 const json &params,
136 const DynamicOrder dynamic_order)
137 {
138 const std::string type = params.is_object() ? params["type"] : params;
139 if (type != "implict_euler" && type != "ImplicitEuler"
140 && !utils::StringUtils::startswith(type, "BDF"))
141 {
143 "BDF-specific transient formulations require ImplicitEuler or BDF, got {}.",
144 type);
145 }
146
147 auto integrator = std::make_shared<BDF>(
148 utils::StringUtils::startswith(type, "BDF") && type != "BDF"
149 ? std::stoi(type.substr(3))
150 : 1,
152 if (params.is_object() && params.contains("steps"))
153 integrator->set_parameters(params);
154 return integrator;
155 }
156
158 {
159 static const std::vector<std::string> names = {
160 std::string("ImplicitEuler"),
161 std::string("ImplicitNewmark"),
162 std::string("BDF"),
163 };
164 return names;
165 }
166 } // namespace time_integrator
167} // namespace polyfem
int x
long read_long(const std::string &path) const
double read_double(const std::string &path) const
Eigen::MatrixXd read_matrix(const std::string &path) const
bool exists(const std::string &path) const
void write_matrix(const std::string &path, const Eigen::MatrixXd &value)
void write_double(const std::string &path, double value)
void write_long(const std::string &path, long value)
const std::deque< Eigen::VectorXd > & v_prevs() const
Get the (relevant) history of previous velocity value.
std::deque< Eigen::VectorXd > x_prevs_
Store the necessary previous values of the solution for single or multi-step integration.
const std::deque< Eigen::VectorXd > & a_prevs() const
Get the (relevant) history of previous acceleration value.
static std::shared_ptr< ImplicitTimeIntegrator > construct_time_integrator(const json &params, DynamicOrder dynamic_order=DynamicOrder::Second)
Factory method for constructing an implicit time integrator.
void serialize_checkpoint(io::CheckpointWriter &writer, const std::string &group) const
virtual int max_steps() const
Get the maximum number of steps to use for integration.
const double & dt() const
Access the time step size.
void deserialize_checkpoint(const io::CheckpointReader &reader, const std::string &group, double expected_dt, const std::function< void(Eigen::MatrixXd &)> &transform={})
std::deque< Eigen::VectorXd > a_prevs_
Store the necessary previous values of the acceleration for single or multi-step integration.
static std::shared_ptr< BDF > construct_bdf_integrator(const json &params, DynamicOrder dynamic_order=DynamicOrder::Second)
Construct a BDF integrator for algorithms using BDF-specific operations.
virtual void init(const Eigen::MatrixXd &x_prevs, const Eigen::MatrixXd &v_prevs, const Eigen::MatrixXd &a_prevs, double dt)
Initialize the time integrator with the previous values for , , and .
const std::deque< Eigen::VectorXd > & x_prevs() const
Get the (relevant) history of previous solution value.
std::deque< Eigen::VectorXd > v_prevs_
Store the necessary previous values of the velocity for single or multi-step integration.
static const std::vector< std::string > & get_time_integrator_names()
Get a vector of the names of possible ImplicitTimeIntegrators.
bool startswith(const std::string &str, const std::string &prefix)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:44
nlohmann::json json
Definition Common.hpp:9
void log_and_throw_error(const std::string &msg)
Definition Logger.cpp:73