Newer
Older
#include "nlohmann/json.hpp"
#include <filesystem>
#include <fstream>
/// Load a JSON file from a specified file
inline nlohmann::json load_a_JSON_file(const std::string& path) {
if (!std::filesystem::is_regular_file(path)) {
throw std::invalid_argument("Path to be loaded does not exist: " + path);
}
auto stream = std::ifstream(path);
if (!stream) {
throw std::invalid_argument("File stream cannot be opened from: " + path);
}
try {
return nlohmann::json::parse(stream);
}
catch (...) {
throw std::invalid_argument("File at " + path + " is not valid JSON");
}
}
inline auto all_same_length(const nlohmann::json& j, const std::vector<std::string>& ks) {
std::set<decltype(j[0].size())> lengths;
for (auto k : ks) { lengths.insert(j.at(k).size()); }
return lengths.size() == 1;
}
inline auto build_square_matrix = [](const nlohmann::json& j){
if (j.is_null() || (j.is_array() && j.size() == 0)){
return Eigen::ArrayXXd(0, 0);
}
try{
const std::valarray<std::valarray<double>> m = j;
// First assume that the matrix is square, resize
Eigen::ArrayXXd mat(m.size(), m.size());
if (m.size() == 0){
return mat;
}
// Then copy elements over
for (auto i = 0; i < m.size(); ++i){
auto row = m[i];
if (row.size() != mat.rows()){
throw std::invalid_argument("provided matrix is not square");
}
for (auto j = 0; j < row.size(); ++j){
mat(i, j) = row[j];
}
}
return mat;
}
catch(const nlohmann::json::exception&){
throw teqp::InvalidArgument("Unable to convert this kmat to a 2x2 matrix of doubles:" + j.dump(2));
}
};
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
A method for loading something from a nlohmann::json node. Thing to be operated on can be:
0. empty, in which case the file at the default_path is loaded
1. An object node, in which case it is returned
2. A path as a string. If this file exists, it will be loaded
3. A JSON-encoded string
*/
inline auto multilevel_JSON_load(const nlohmann::json &j, const std::string& default_path){
auto is_valid_path = [](const std::string & s){
try{
std::filesystem::is_regular_file(s);
return true;
}
catch(...){
return false;
}
};
// If not provided (NULL, empty array or empty string), load from the default path provided
if (j.is_null() || (j.is_array() && j.empty()) || (j.is_string() && j.get<std::string>().empty())){
return load_a_JSON_file(default_path);
}
else if (j.is_object()){
// Assume we are already providing the thing
return j;
}
else if (j.is_string()){
// If a string, either data in JSON format, or a path-like thing
std::string s = j.get<std::string>();
// If path to existing file, use it
if (is_valid_path(s) && std::filesystem::is_regular_file(s)){
return load_a_JSON_file(s);
}
// Or assume it is a string in JSON format
else{
return nlohmann::json::parse(s);
}
}
else{
throw teqp::InvalidArgument("Unable to load the argument to multilevel_JSON_load");
}