Skip to content

Commit

Permalink
Add support for YAML input. (#322)
Browse files Browse the repository at this point in the history
* Convert YAML to JSON

* Fix YAML CMake

* Add YAML to JSON to main
  • Loading branch information
zfergus committed Mar 7, 2024
1 parent edfab57 commit 0dfa159
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,10 @@ target_link_libraries(polyfem PUBLIC Glob::Glob)
include(units)
target_link_libraries(polyfem PUBLIC units::units)

# YAML library
include(yaml)
target_link_libraries(polyfem PUBLIC yaml-cpp::yaml-cpp)

# FCPW
# include(fcpw)
# target_link_libraries(polyfem PUBLIC fcpw::fcpw)
Expand Down
11 changes: 11 additions & 0 deletions cmake/recipes/yaml.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# yaml-cpp (https://github.com/jbeder/yaml-cpp)
# License: MIT

if(TARGET yaml-cpp::yaml-cpp)
return()
endif()

message(STATUS "Third-party: creating target 'yaml-cpp::yaml-cpp'")

include(CPM)
CPMAddPackage("gh:jbeder/yaml-cpp#0.8.0")
6 changes: 5 additions & 1 deletion src/polyfem/io/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
set(SOURCES
Evaluator.cpp
Evaluator.hpp
MatrixIO.cpp
MatrixIO.hpp
MshReader.cpp
Expand All @@ -9,8 +11,10 @@ set(SOURCES
OBJReader.hpp
OBJWriter.cpp
OBJWriter.hpp
Evaluator.cpp
OutData.cpp
OutData.hpp
YamlToJson.cpp
YamlToJson.hpp
)

source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" PREFIX "Source Files" FILES ${SOURCES})
Expand Down
67 changes: 67 additions & 0 deletions src/polyfem/io/YamlToJson.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Original source code from https://github.com/mircodezorzi/tojson (MIT License)

#include "YamlToJson.hpp"

#include <yaml-cpp/yaml.h>

namespace polyfem::io
{
namespace
{
inline nlohmann::json parse_scalar(const YAML::Node &node)
{
int i;
double d;
bool b;
std::string s;

if (YAML::convert<int>::decode(node, i))
return i;
if (YAML::convert<double>::decode(node, d))
return d;
if (YAML::convert<bool>::decode(node, b))
return b;
if (YAML::convert<std::string>::decode(node, s))
return s;

return nullptr;
}

/// @todo refactor and pass nlohmann::json down by reference instead of returning it
inline nlohmann::json yaml_to_json(const YAML::Node &root)
{
nlohmann::json j{};

switch (root.Type())
{
case YAML::NodeType::Null:
break;
case YAML::NodeType::Scalar:
return parse_scalar(root);
case YAML::NodeType::Sequence:
for (auto &&node : root)
j.emplace_back(yaml_to_json(node));
break;
case YAML::NodeType::Map:
for (auto &&it : root)
j[it.first.as<std::string>()] = yaml_to_json(it.second);
break;
default:
break;
}
return j;
}
} // namespace

json yaml_string_to_json(const std::string &yaml_str)
{
YAML::Node root = YAML::Load(yaml_str);
return yaml_to_json(root);
}

json yaml_file_to_json(const std::string &yaml_filepath)
{
YAML::Node root = YAML::LoadFile(yaml_filepath);
return yaml_to_json(root);
}
} // namespace polyfem::io
12 changes: 12 additions & 0 deletions src/polyfem/io/YamlToJson.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once

#include <polyfem/Common.hpp>

namespace polyfem::io
{
/// @brief Convert YAML string to JSON.
json yaml_string_to_json(const std::string &yaml_str);

/// @brief Load a YAML file to JSON.
json yaml_file_to_json(const std::string &yaml_filepath);
} // namespace polyfem::io
45 changes: 34 additions & 11 deletions src/polyfem/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <polyfem/utils/JSONUtils.hpp>
#include <polyfem/utils/Logger.hpp>
#include <polyfem/io/YamlToJson.hpp>

using namespace polyfem;
using namespace solver;
Expand Down Expand Up @@ -37,17 +38,32 @@ bool load_json(const std::string &json_file, json &out)
return true;
}

bool load_yaml(const std::string &yaml_file, json &out)
{
try
{
out = io::yaml_file_to_json(yaml_file);
if (!out.contains("root_path"))
out["root_path"] = yaml_file;
}
catch (...)
{
return false;
}
return true;
}

int forward_simulation(const CLI::App &command_line,
const std::string &hdf5_file,
const std::string output_dir,
const size_t max_threads,
const unsigned max_threads,
const bool is_strict,
const bool fallback_solver,
const spdlog::level::level_enum &log_level,
json &in_args);

int optimization_simulation(const CLI::App &command_line,
const size_t max_threads,
const unsigned max_threads,
const bool is_strict,
const spdlog::level::level_enum &log_level,
json &opt_args);
Expand All @@ -62,14 +78,21 @@ int main(int argc, char **argv)
command_line.ignore_underscore();

// Eigen::setNbThreads(1);
size_t max_threads = std::numeric_limits<size_t>::max();
unsigned max_threads = std::numeric_limits<unsigned>::max();
command_line.add_option("--max_threads", max_threads, "Maximum number of threads");

auto input = command_line.add_option_group("input");

std::string json_file = "";
command_line.add_option("-j,--json", json_file, "Simulation JSON file")->check(CLI::ExistingFile);
input->add_option("-j,--json", json_file, "Simulation JSON file")->check(CLI::ExistingFile);

std::string yaml_file = "";
input->add_option("-y,--yaml", yaml_file, "Simulation YAML file")->check(CLI::ExistingFile);

std::string hdf5_file = "";
command_line.add_option("--hdf5", hdf5_file, "Simulation hdf5 file")->check(CLI::ExistingFile);
input->add_option("--hdf5", hdf5_file, "Simulation HDF5 file")->check(CLI::ExistingFile);

input->require_option(1);

std::string output_dir = "";
command_line.add_option("-o,--output_dir", output_dir, "Directory for output files")->check(CLI::ExistingDirectory | CLI::NonexistentPath);
Expand All @@ -78,7 +101,7 @@ int main(int argc, char **argv)
command_line.add_flag("-s,--strict_validation,!--ns,!--no_strict_validation", is_strict, "Disables strict validation of input JSON");

bool fallback_solver = false;
command_line.add_flag("--enable_overwrite_solver", fallback_solver, "If solver in json is not present, falls back to default");
command_line.add_flag("--enable_overwrite_solver", fallback_solver, "If solver in input is not present, falls back to default.");

const std::vector<std::pair<std::string, spdlog::level::level_enum>>
SPDLOG_LEVEL_NAMES_TO_LEVELS = {
Expand All @@ -97,9 +120,9 @@ int main(int argc, char **argv)

json in_args = json({});

if (!json_file.empty())
if (!json_file.empty() || !yaml_file.empty())
{
const bool ok = load_json(json_file, in_args);
const bool ok = !json_file.empty() ? load_json(json_file, in_args) : load_yaml(yaml_file, in_args);

if (!ok)
log_and_throw_error(fmt::format("unable to open {} file", json_file));
Expand All @@ -118,7 +141,7 @@ int main(int argc, char **argv)
int forward_simulation(const CLI::App &command_line,
const std::string &hdf5_file,
const std::string output_dir,
const size_t max_threads,
const unsigned max_threads,
const bool is_strict,
const bool fallback_solver,
const spdlog::level::level_enum &log_level,
Expand Down Expand Up @@ -148,7 +171,7 @@ int forward_simulation(const CLI::App &command_line,
cells.resize(names.size());
vertices.resize(names.size());

for (size_t i = 0; i < names.size(); ++i)
for (int i = 0; i < names.size(); ++i)
{
const std::string &name = names[i];
cells[i] = file.readDataset<MatrixXl>("/meshes/" + name + "/c").cast<int>();
Expand Down Expand Up @@ -202,7 +225,7 @@ int forward_simulation(const CLI::App &command_line,
}

int optimization_simulation(const CLI::App &command_line,
const size_t max_threads,
const unsigned max_threads,
const bool is_strict,
const spdlog::level::level_enum &log_level,
json &opt_args)
Expand Down

0 comments on commit 0dfa159

Please sign in to comment.