PolyFEM
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1#include <filesystem>
2
3#include <CLI/CLI.hpp>
4
5#include <polyfem/State.hpp>
6#ifdef POLYFEM_WITH_OPTIMIZATION
8#endif
9
16
17using namespace polyfem;
18using namespace solver;
19
20bool has_arg(const CLI::App &command_line, const std::string &value)
21{
22 const auto *opt = command_line.get_option_no_throw(value.size() == 1 ? ("-" + value) : ("--" + value));
23 if (!opt)
24 return false;
25
26 return opt->count() > 0;
27}
28
29int forward_simulation(const CLI::App &command_line,
30 const io::ResourceIO &resources,
31 const std::string &output_dir,
32 const unsigned max_threads,
33 const bool is_strict,
34 const bool fallback_solver,
35 const spdlog::level::level_enum &log_level,
36 json &in_args);
37
38int forward_simulation(const CLI::App &command_line,
39 const io::CheckpointReader &checkpoint,
40 const std::string &output_dir,
41 unsigned max_threads,
42 bool is_strict,
43 bool fallback_solver,
44 const spdlog::level::level_enum &log_level,
45 json &in_args);
46
47#ifdef POLYFEM_WITH_OPTIMIZATION
48int optimization_simulation(const CLI::App &command_line,
49 const io::ResourceIO &resources,
50 const unsigned max_threads,
51 const bool is_strict,
52 const spdlog::level::level_enum &log_level,
53 json &opt_args);
54#endif
55
57
59 json &in_args,
60 const bool is_strict)
61{
62 State state;
63 state.init(in_args, resources, is_strict);
64 return run_forward_simulation(state);
65}
66
68 const json &in_args,
69 const bool is_strict)
70{
71 State state;
72 state.init(in_args, checkpoint, is_strict);
73 return run_forward_simulation(state);
74}
75
77{
78 state.load_mesh();
79
80 Eigen::MatrixXd sol;
81 state.solve(sol);
82
83 state.variational_formulation->compute_errors(sol);
84
85 io::OutRuntimeData timings = state.variational_formulation->output_timings();
86 logger().info("total time: {}s", timings.total_time());
87
88 state.variational_formulation->save_json(sol);
89 state.variational_formulation->export_data(sol);
90
91 return EXIT_SUCCESS;
92}
93
94int main(int argc, char **argv)
95{
96 using namespace polyfem;
97
98 CLI::App command_line{"polyfem"};
99
100 command_line.ignore_case();
101 command_line.ignore_underscore();
102
103 // Eigen::setNbThreads(1);
104 unsigned max_threads = std::numeric_limits<unsigned>::max();
105 command_line.add_option("--max_threads", max_threads, "Maximum number of threads");
106
107 auto input = command_line.add_option_group("input");
108
109 std::string json_file = "";
110 input->add_option("-j,--json", json_file, "Simulation JSON file")->check(CLI::ExistingFile);
111
112 std::string yaml_file = "";
113 input->add_option("-y,--yaml", yaml_file, "Simulation YAML file")->check(CLI::ExistingFile);
114
115 std::string hdf5_file = "";
116 input->add_option("--hdf5", hdf5_file, "Simulation HDF5 file")->check(CLI::ExistingFile);
117
118 std::string checkpoint_file = "";
119 auto *checkpoint_option = input->add_option("--checkpoint", checkpoint_file, "Versioned PolyFEM checkpoint")->check(CLI::ExistingFile);
120 bool checkpoint_reorder = false;
121 command_line.add_flag(
122 "--checkpoint-reorder", checkpoint_reorder,
123 "Reorder checkpoint state from its saved input-node ordering")
124 ->needs(checkpoint_option);
125
126 input->require_option(1);
127
128 std::string output_dir = "";
129 command_line.add_option("-o,--output_dir", output_dir, "Directory for output files")->check(CLI::ExistingDirectory | CLI::NonexistentPath);
130
131 bool is_strict = true;
132 command_line.add_flag("-s,--strict_validation,!--ns,!--no_strict_validation", is_strict, "Disables strict validation of input JSON");
133
134 bool fallback_solver = false;
135 command_line.add_flag("--enable_overwrite_solver", fallback_solver, "If solver in input is not present, falls back to default.");
136
137 const std::vector<std::pair<std::string, spdlog::level::level_enum>>
138 SPDLOG_LEVEL_NAMES_TO_LEVELS = {
139 {"trace", spdlog::level::trace},
140 {"debug", spdlog::level::debug},
141 {"info", spdlog::level::info},
142 {"warning", spdlog::level::warn},
143 {"error", spdlog::level::err},
144 {"critical", spdlog::level::critical},
145 {"off", spdlog::level::off}};
146 spdlog::level::level_enum log_level = spdlog::level::debug;
147 command_line.add_option("--log_level", log_level, "Log level")
148 ->transform(CLI::CheckedTransformer(SPDLOG_LEVEL_NAMES_TO_LEVELS, CLI::ignore_case));
149
150 CLI11_PARSE(command_line, argc, argv);
151
152 json in_args = json({});
153 if (!json_file.empty() || !yaml_file.empty())
154 {
155 const io::LoadedInput loaded = !json_file.empty()
156 ? io::load_json_input(json_file)
157 : io::load_yaml_input(yaml_file);
158 in_args = loaded.config;
159
160 if (in_args.contains("states"))
161 {
162#ifndef POLYFEM_WITH_OPTIMIZATION
163 log_and_throw_error("PolyFEM was built without optimization support.");
164#else
165 return optimization_simulation(command_line, *loaded.resources, max_threads, is_strict, log_level, in_args);
166#endif
167 }
168 else
169 return forward_simulation(command_line, *loaded.resources, output_dir, max_threads,
170 is_strict, fallback_solver, log_level, in_args);
171 }
172 else if (!hdf5_file.empty())
173 {
174 const io::LoadedInput loaded = io::load_hdf5_input(hdf5_file);
175 in_args = loaded.config;
176 return forward_simulation(command_line, *loaded.resources, output_dir, max_threads,
177 is_strict, fallback_solver, log_level, in_args);
178 }
179 else
180 {
181 io::CheckpointReader checkpoint(checkpoint_file);
182 in_args = checkpoint.config();
183 return forward_simulation(command_line, checkpoint, output_dir, max_threads,
184 is_strict, fallback_solver, log_level, in_args);
185 }
186}
187
188int forward_simulation(const CLI::App &command_line,
189 const io::ResourceIO &resources,
190 const std::string &output_dir,
191 const unsigned max_threads,
192 const bool is_strict,
193 const bool fallback_solver,
194 const spdlog::level::level_enum &log_level,
195 json &in_args)
196{
197 if (in_args.empty())
198 {
199 logger().error("No input file specified!");
200 return command_line.exit(CLI::RequiredError("--json or --hdf5"));
201 }
202
203 json tmp = json::object();
204 if (has_arg(command_line, "log_level"))
205 tmp["/output/log/level"_json_pointer] = int(log_level);
206 if (has_arg(command_line, "max_threads"))
207 tmp["/solver/max_threads"_json_pointer] = max_threads;
208 if (has_arg(command_line, "output_dir"))
209 tmp["/output/directory"_json_pointer] = std::filesystem::absolute(output_dir);
210 if (has_arg(command_line, "enable_overwrite_solver"))
211 tmp["/solver/linear/enable_overwrite_solver"_json_pointer] = fallback_solver;
212 assert(tmp.is_object());
213 in_args.merge_patch(tmp);
214
215 const std::string checkpoint_path =
216 in_args.contains("/input/checkpoint/path"_json_pointer)
217 ? in_args["/input/checkpoint/path"_json_pointer].get<std::string>()
218 : std::string();
219 if (!checkpoint_path.empty())
220 {
221 const std::filesystem::path path = std::filesystem::path(checkpoint_path).is_absolute()
222 ? std::filesystem::path(checkpoint_path)
223 : resources.host_directory() / checkpoint_path;
224 io::CheckpointReader checkpoint(path.lexically_normal());
225 json continuation = checkpoint.config();
226 continuation["input"]["checkpoint"]["path"] = "";
227 continuation["input"]["checkpoint"]["reorder"] =
228 in_args.contains("/input/checkpoint/reorder"_json_pointer)
229 ? in_args["/input/checkpoint/reorder"_json_pointer].get<bool>()
230 : false;
231 return forward_simulation(
232 command_line, checkpoint, output_dir, max_threads,
233 is_strict, fallback_solver, log_level, continuation);
234 }
235
236 return forward_simulation_with_varform_state(resources, in_args, is_strict);
237}
238
239int forward_simulation(const CLI::App &command_line,
240 const io::CheckpointReader &checkpoint,
241 const std::string &output_dir,
242 const unsigned max_threads,
243 const bool is_strict,
244 const bool fallback_solver,
245 const spdlog::level::level_enum &log_level,
246 json &in_args)
247{
248 json tmp = json::object();
249 if (has_arg(command_line, "log_level"))
250 tmp["/output/log/level"_json_pointer] = int(log_level);
251 if (has_arg(command_line, "max_threads"))
252 tmp["/solver/max_threads"_json_pointer] = max_threads;
253 if (has_arg(command_line, "output_dir"))
254 tmp["/output/directory"_json_pointer] = std::filesystem::absolute(output_dir);
255 if (has_arg(command_line, "enable_overwrite_solver"))
256 tmp["/solver/linear/enable_overwrite_solver"_json_pointer] = fallback_solver;
257 if (has_arg(command_line, "checkpoint-reorder"))
258 tmp["/input/checkpoint/reorder"_json_pointer] = true;
259 in_args.merge_patch(tmp);
260
261 return forward_simulation_with_varform_state(checkpoint, in_args, is_strict);
262}
263
264#ifdef POLYFEM_WITH_OPTIMIZATION
265int optimization_simulation(const CLI::App &command_line,
266 const io::ResourceIO &resources,
267 const unsigned max_threads,
268 const bool is_strict,
269 const spdlog::level::level_enum &log_level,
270 json &opt_args)
271{
272 json tmp = json::object();
273 if (has_arg(command_line, "log_level"))
274 tmp["/output/log/level"_json_pointer] = int(log_level);
275 if (has_arg(command_line, "max_threads"))
276 tmp["/solver/max_threads"_json_pointer] = max_threads;
277 opt_args.merge_patch(tmp);
278
279 OptState opt_state;
280 return opt_state.run(opt_args, resources, is_strict);
281}
282#endif
Main class containing the PolyFEM adjoint solver and its optimization data.
Definition OptState.hpp:30
int run(json args, const bool strict_validation)
Run optimization, including remeshing restarts when the selected trigger requests them.
Definition OptState.cpp:277
VarForm-only simulation state.
Definition State.hpp:37
std::shared_ptr< varform::VarForm > variational_formulation
active variational formulation
Definition State.hpp:71
void init(const json &args, bool strict_validation, bool is_adjoint_optimization=false)
initialize the polyfem solver with a json settings
Definition State.cpp:263
void solve(Eigen::MatrixXd &sol)
solves the problem, call other methods
Definition State.cpp:526
void load_mesh(bool non_conforming=false)
loads the mesh from the json arguments
Definition State.cpp:470
const json & config() const
std::unique_ptr< const ResourceIO > resources
timers from polyfem.
double total_time() const
computes total time
Read-only interface to a hierarchical collection of simulation resources.
virtual const std::filesystem::path & host_directory() const =0
Host directory used only as the base for ordinary filesystem outputs.
int run_forward_simulation(State &state)
Definition main.cpp:76
int main(int argc, char **argv)
Definition main.cpp:94
int forward_simulation_with_varform_state(const io::ResourceIO &resources, json &in_args, const bool is_strict)
Definition main.cpp:58
int forward_simulation(const CLI::App &command_line, const io::ResourceIO &resources, const std::string &output_dir, const unsigned max_threads, const bool is_strict, const bool fallback_solver, const spdlog::level::level_enum &log_level, json &in_args)
Definition main.cpp:188
bool has_arg(const CLI::App &command_line, const std::string &value)
Definition main.cpp:20
list tmp
Definition p_bases.py:366
LoadedInput load_json_input(const std::filesystem::path &path)
LoadedInput load_hdf5_input(const std::filesystem::path &path)
LoadedInput load_yaml_input(const std::filesystem::path &path)
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