PolyFEM
Loading...
Searching...
No Matches
ImplicitTimeIntegrator.cpp
Go to the documentation of this file.
2
6
11
12#include <fstream>
13
14namespace polyfem
15{
16 using namespace io;
17 namespace time_integrator
18 {
20 const Eigen::MatrixXd &x_prevs,
21 const Eigen::MatrixXd &v_prevs,
22 const Eigen::MatrixXd &a_prevs,
23 double dt)
24 {
25 assert(x_prevs.cols() > 0 && x_prevs.cols() <= max_steps());
26 assert(x_prevs.cols() == v_prevs.cols());
27 assert(x_prevs.cols() == a_prevs.cols());
28
29 x_prevs_.clear();
30 v_prevs_.clear();
31 a_prevs_.clear();
32
33 const int n = std::min(int(x_prevs.cols()), max_steps());
34 for (int i = 0; i < n; i++)
35 {
36 x_prevs_.push_back(x_prevs.col(i));
37 v_prevs_.push_back(v_prevs.col(i));
38 a_prevs_.push_back(a_prevs.col(i));
39 }
40
41 assert(dt > 0);
42 dt_ = dt;
43 }
44
45 void ImplicitTimeIntegrator::save_state(const std::string &state_path) const
46 {
47 const int ndof = x_prev().size();
48 const int history = x_prevs().size();
49 Eigen::MatrixXd values(ndof, history);
50 for (int i = 0; i < history; ++i)
51 values.col(i) = x_prevs()[i];
52 write_matrix(state_path, "u", values, true);
53 for (int i = 0; i < history; ++i)
54 values.col(i) = v_prevs()[i];
55 write_matrix(state_path, "v", values, false);
56 for (int i = 0; i < history; ++i)
57 values.col(i) = a_prevs()[i];
58 write_matrix(state_path, "a", values, false);
59 }
60
61 void ImplicitTimeIntegrator::serialize_checkpoint(io::CheckpointWriter &writer, const std::string &group) const
62 {
63 if (x_prevs_.empty() || x_prevs_.size() != v_prevs_.size() || x_prevs_.size() != a_prevs_.size())
64 log_and_throw_error("Cannot checkpoint an uninitialized or inconsistent time integrator.");
65 const int ndof = x_prevs_.front().size();
66 const int history = x_prevs_.size();
67 Eigen::MatrixXd x(ndof, history), v(ndof, history), a(ndof, history);
68 for (int i = 0; i < history; ++i)
69 {
70 if (x_prevs_[i].size() != ndof || v_prevs_[i].size() != ndof || a_prevs_[i].size() != ndof)
71 log_and_throw_error("Cannot checkpoint inconsistent time-integrator history dimensions.");
72 x.col(i) = x_prevs_[i];
73 v.col(i) = v_prevs_[i];
74 a.col(i) = a_prevs_[i];
75 }
76 writer.write_matrix(group + "/x", x);
77 writer.write_matrix(group + "/v", v);
78 writer.write_matrix(group + "/a", a);
79 writer.write_long(group + "/dynamic_order", dynamic_order_ == DynamicOrder::First ? 1 : 2);
80 writer.write_long(group + "/history_length", history);
81 writer.write_double(group + "/dt", dt_);
82 }
83
85 const io::CheckpointReader &reader,
86 const std::string &group,
87 const double expected_dt,
88 const std::function<void(Eigen::MatrixXd &)> &transform)
89 {
90 for (const std::string &key : {"x", "v", "a", "dynamic_order", "history_length", "dt"})
91 if (!reader.exists(group + "/" + key))
92 log_and_throw_error("Checkpoint integrator group {} is missing {}.", group, key);
93 const long order = reader.read_long(group + "/dynamic_order");
94 if (order != (dynamic_order_ == DynamicOrder::First ? 1 : 2))
95 log_and_throw_error("Checkpoint dynamic order is incompatible with {}.", group);
96 const long history = reader.read_long(group + "/history_length");
97 if (history < 1 || history > max_steps())
98 log_and_throw_error("Checkpoint history length {} is incompatible with {}.", history, group);
99 const double stored_dt = reader.read_double(group + "/dt");
100 if (std::abs(stored_dt - expected_dt) > 1e-12 * std::max({1.0, std::abs(stored_dt), std::abs(expected_dt)}))
101 log_and_throw_error("Checkpoint dt {} does not match configured dt {}.", stored_dt, expected_dt);
102 Eigen::MatrixXd x = reader.read_matrix(group + "/x");
103 Eigen::MatrixXd v = reader.read_matrix(group + "/v");
104 Eigen::MatrixXd a = reader.read_matrix(group + "/a");
105 if (x.rows() == 0 || x.cols() != history || v.rows() != x.rows() || a.rows() != x.rows()
106 || v.cols() != history || a.cols() != history)
107 log_and_throw_error("Checkpoint integrator history dimensions are invalid in {}.", group);
108 const int expected_rows = x_prevs_.empty() ? -1 : x_prevs_.front().size();
109 if (expected_rows >= 0 && x.rows() != expected_rows)
111 "Checkpoint integrator {} has {} rows; expected {}.",
112 group, x.rows(), expected_rows);
113 if (transform)
114 {
115 transform(x);
116 transform(v);
117 transform(a);
118 }
119 init(x, v, a, stored_dt);
120 }
121
122 std::shared_ptr<ImplicitTimeIntegrator> ImplicitTimeIntegrator::construct_time_integrator(
123 const json &params,
124 const DynamicOrder dynamic_order)
125 {
126 const std::string type = params.is_object() ? params["type"] : params;
127
128 std::shared_ptr<ImplicitTimeIntegrator> integrator;
129 if (type == "implict_euler" || type == "ImplicitEuler")
130 {
131 integrator = std::make_shared<ImplicitEuler>(dynamic_order);
132 }
133 else if (type == "implict_newmark" || type == "ImplicitNewmark")
134 {
135 integrator = std::make_shared<ImplicitNewmark>(dynamic_order);
136 }
137 else if (utils::StringUtils::startswith(type, "BDF"))
138 {
139 integrator = std::make_shared<BDF>(type == "BDF" ? 1 : std::stoi(type.substr(3)), dynamic_order);
140 }
141 else
142 {
143 logger().error("Unknown time integrator ({})", type);
144 throw std::runtime_error(fmt::format("Unknown time integrator ({})", type));
145 }
146
147 if (params.is_object())
148 integrator->set_parameters(params);
149
150 return integrator;
151 }
152
154 const json &params,
155 const DynamicOrder dynamic_order)
156 {
157 const std::string type = params.is_object() ? params["type"] : params;
158 if (type != "implict_euler" && type != "ImplicitEuler"
159 && !utils::StringUtils::startswith(type, "BDF"))
160 {
162 "BDF-specific transient formulations require ImplicitEuler or BDF, got {}.",
163 type);
164 }
165
166 auto integrator = std::make_shared<BDF>(
167 utils::StringUtils::startswith(type, "BDF") && type != "BDF"
168 ? std::stoi(type.substr(3))
169 : 1,
171 if (params.is_object() && params.contains("steps"))
172 integrator->set_parameters(params);
173 return integrator;
174 }
175
177 {
178 static const std::vector<std::string> names = {
179 std::string("ImplicitEuler"),
180 std::string("ImplicitNewmark"),
181 std::string("BDF"),
182 };
183 return names;
184 }
185 } // namespace time_integrator
186} // 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 Eigen::VectorXd & x_prev() const
Get the most recent previous solution value.
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.
virtual void save_state(const std::string &state_path) const
Legacy State persistence. Non-legacy code uses serialize_checkpoint().
bool write_matrix(const std::string &path, const Mat &mat)
Writes a matrix to a file. Determines the file format based on the path's extension.
Definition MatrixIO.cpp:43
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