7#ifdef POLYFEM_WITH_OPTIMIZATION
20using namespace solver;
22bool has_arg(
const CLI::App &command_line,
const std::string &value)
24 const auto *opt = command_line.get_option_no_throw(value.size() == 1 ? (
"-" + value) : (
"--" + value));
28 return opt->count() > 0;
33 const std::string &output_dir,
34 const unsigned max_threads,
36 const bool fallback_solver,
37 const spdlog::level::level_enum &log_level,
42 const std::string &output_dir,
46 const spdlog::level::level_enum &log_level,
49#ifdef POLYFEM_WITH_OPTIMIZATION
50int optimization_simulation(
const CLI::App &command_line,
52 const unsigned max_threads,
54 const spdlog::level::level_enum &log_level,
65 state.
init(in_args, resources, is_strict);
74 state.
init(in_args, checkpoint, is_strict);
97 const std::vector<Eigen::MatrixXi> &cells,
98 const std::vector<Eigen::MatrixXd> &vertices,
100 const bool is_strict)
103 state.
init(in_args, is_strict);
105 logger().warn(
"Running forward simulation with legacy state.");
106 state.
load_mesh(
false, names, cells, vertices);
109 if (state.
mesh ==
nullptr)
123 Eigen::MatrixXd pressure;
141 CLI::App command_line{
"polyfem"};
143 command_line.ignore_case();
144 command_line.ignore_underscore();
147 unsigned max_threads = std::numeric_limits<unsigned>::max();
148 command_line.add_option(
"--max_threads", max_threads,
"Maximum number of threads");
150 auto input = command_line.add_option_group(
"input");
152 std::string json_file =
"";
153 input->add_option(
"-j,--json", json_file,
"Simulation JSON file")->check(CLI::ExistingFile);
155 std::string yaml_file =
"";
156 input->add_option(
"-y,--yaml", yaml_file,
"Simulation YAML file")->check(CLI::ExistingFile);
158 std::string hdf5_file =
"";
159 input->add_option(
"--hdf5", hdf5_file,
"Simulation HDF5 file")->check(CLI::ExistingFile);
161 std::string checkpoint_file =
"";
162 auto *checkpoint_option = input->add_option(
"--checkpoint", checkpoint_file,
"Versioned PolyFEM checkpoint")->check(CLI::ExistingFile);
163 bool checkpoint_reorder =
false;
164 command_line.add_flag(
165 "--checkpoint-reorder", checkpoint_reorder,
166 "Reorder checkpoint state from its saved input-node ordering")
167 ->needs(checkpoint_option);
169 input->require_option(1);
171 std::string output_dir =
"";
172 command_line.add_option(
"-o,--output_dir", output_dir,
"Directory for output files")->check(CLI::ExistingDirectory | CLI::NonexistentPath);
174 bool is_strict =
true;
175 command_line.add_flag(
"-s,--strict_validation,!--ns,!--no_strict_validation", is_strict,
"Disables strict validation of input JSON");
177 bool fallback_solver =
false;
178 command_line.add_flag(
"--enable_overwrite_solver", fallback_solver,
"If solver in input is not present, falls back to default.");
180 const std::vector<std::pair<std::string, spdlog::level::level_enum>>
181 SPDLOG_LEVEL_NAMES_TO_LEVELS = {
182 {
"trace", spdlog::level::trace},
183 {
"debug", spdlog::level::debug},
184 {
"info", spdlog::level::info},
185 {
"warning", spdlog::level::warn},
186 {
"error", spdlog::level::err},
187 {
"critical", spdlog::level::critical},
188 {
"off", spdlog::level::off}};
189 spdlog::level::level_enum log_level = spdlog::level::debug;
190 command_line.add_option(
"--log_level", log_level,
"Log level")
191 ->transform(CLI::CheckedTransformer(SPDLOG_LEVEL_NAMES_TO_LEVELS, CLI::ignore_case));
193 CLI11_PARSE(command_line, argc, argv);
196 if (!json_file.empty() || !yaml_file.empty())
203 if (in_args.contains(
"states"))
205#ifndef POLYFEM_WITH_OPTIMIZATION
208 return optimization_simulation(command_line, *loaded.
resources, max_threads, is_strict, log_level, in_args);
213 is_strict, fallback_solver, log_level, in_args);
215 else if (!hdf5_file.empty())
220 is_strict, fallback_solver, log_level, in_args);
225 in_args = checkpoint.
config();
227 is_strict, fallback_solver, log_level, in_args);
233 const std::string &output_dir,
234 const unsigned max_threads,
235 const bool is_strict,
236 const bool fallback_solver,
237 const spdlog::level::level_enum &log_level,
242 logger().error(
"No input file specified!");
243 return command_line.exit(CLI::RequiredError(
"--json or --hdf5"));
246 json tmp = json::object();
247 if (
has_arg(command_line,
"log_level"))
248 tmp[
"/output/log/level"_json_pointer] = int(log_level);
249 if (
has_arg(command_line,
"max_threads"))
250 tmp[
"/solver/max_threads"_json_pointer] = max_threads;
251 if (
has_arg(command_line,
"output_dir"))
252 tmp[
"/output/directory"_json_pointer] = std::filesystem::absolute(output_dir);
253 if (
has_arg(command_line,
"enable_overwrite_solver"))
254 tmp[
"/solver/linear/enable_overwrite_solver"_json_pointer] = fallback_solver;
255 assert(tmp.is_object());
256 in_args.merge_patch(tmp);
258 const std::string checkpoint_path =
259 in_args.contains(
"/input/checkpoint/path"_json_pointer)
260 ? in_args[
"/input/checkpoint/path"_json_pointer].get<std::string>()
262 if (!checkpoint_path.empty())
264 const std::filesystem::path path = std::filesystem::path(checkpoint_path).is_absolute()
265 ? std::filesystem::path(checkpoint_path)
269 continuation[
"input"][
"checkpoint"][
"path"] =
"";
270 continuation[
"input"][
"checkpoint"][
"reorder"] =
271 in_args.contains(
"/input/checkpoint/reorder"_json_pointer)
272 ? in_args[
"/input/checkpoint/reorder"_json_pointer].get<
bool>()
275 command_line, checkpoint, output_dir, max_threads,
276 is_strict, fallback_solver, log_level, continuation);
282 if (
dynamic_cast<const io::HDF5IO *
>(&resources) !=
nullptr)
284 in_args[
"root_path"] = resources.
describe(
"");
291 const std::string &output_dir,
292 const unsigned max_threads,
293 const bool is_strict,
294 const bool fallback_solver,
295 const spdlog::level::level_enum &log_level,
301 json tmp = json::object();
302 if (
has_arg(command_line,
"log_level"))
303 tmp[
"/output/log/level"_json_pointer] = int(log_level);
304 if (
has_arg(command_line,
"max_threads"))
305 tmp[
"/solver/max_threads"_json_pointer] = max_threads;
306 if (
has_arg(command_line,
"output_dir"))
307 tmp[
"/output/directory"_json_pointer] = std::filesystem::absolute(output_dir);
308 if (
has_arg(command_line,
"enable_overwrite_solver"))
309 tmp[
"/solver/linear/enable_overwrite_solver"_json_pointer] = fallback_solver;
310 if (
has_arg(command_line,
"checkpoint-reorder"))
311 tmp[
"/input/checkpoint/reorder"_json_pointer] =
true;
312 in_args.merge_patch(tmp);
317#ifdef POLYFEM_WITH_OPTIMIZATION
318int optimization_simulation(
const CLI::App &command_line,
320 const unsigned max_threads,
321 const bool is_strict,
322 const spdlog::level::level_enum &log_level,
326 if (
has_arg(command_line,
"log_level"))
327 tmp[
"/output/log/level"_json_pointer] = int(log_level);
328 if (
has_arg(command_line,
"max_threads"))
329 tmp[
"/solver/max_threads"_json_pointer] = max_threads;
330 opt_args.merge_patch(tmp);
333 return opt_state.
run(opt_args, resources, is_strict);
Main class containing the PolyFEM adjoint solver and its optimization data.
int run(json args, const bool strict_validation)
Run optimization, including remeshing restarts when the selected trigger requests them.
VarForm-only simulation state.
std::shared_ptr< varform::VarForm > variational_formulation
active variational formulation
void init(const json &args, bool strict_validation, bool is_adjoint_optimization=false)
initialize the polyfem solver with a json settings
void solve(Eigen::MatrixXd &sol)
solves the problem, call other methods
void load_mesh(bool non_conforming=false)
loads the mesh from the json arguments
const ResourceIO & resources() const
const json & config() const
HDF5 logical paths always use POSIX separators and roots.
double total_time() const
computes total time
void compute_mesh_stats(const polyfem::mesh::Mesh &mesh)
compute stats (counts els type, mesh lenght, etc), step 1 of solve
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.
virtual std::string describe(const std::string &path) const =0
main class that contains the polyfem solver and all its state
void init(const json &args, const bool strict_validation)
initialize the polyfem solver with a json settings
void compute_errors(const Eigen::MatrixXd &sol)
computes all errors
std::unique_ptr< mesh::Mesh > mesh
current mesh, it can be a Mesh2D or Mesh3D
io::OutStatsData stats
Other statistics.
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
void assemble_mass_mat()
assemble mass, step 4 of solve build mass matrix based on defined basis modifies mass (and maybe more...
io::OutRuntimeData timings
runtime statistics
void export_data(const Eigen::MatrixXd &sol, const Eigen::MatrixXd &pressure)
saves all data on the disk according to the input params
void build_basis()
builds the bases step 2 of solve modifies bases, pressure_bases, geom_bases_, boundary_nodes,...
void save_json(const Eigen::MatrixXd &sol, std::ostream &out)
saves the output statistic to a stream
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
int forward_simulation_with_legacy_state(const std::vector< std::string > &names, const std::vector< Eigen::MatrixXi > &cells, const std::vector< Eigen::MatrixXd > &vertices, json &in_args, const bool is_strict)
int run_forward_simulation(State &state)
int main(int argc, char **argv)
int forward_simulation_with_varform_state(const io::ResourceIO &resources, json &in_args, const bool is_strict)
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)
bool has_arg(const CLI::App &command_line, const std::string &value)
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.
void log_and_throw_error(const std::string &msg)