Skip to content

Commit 8e00bfc

Browse files
committed
#175: Use new configuration handling in bindings
1 parent 38ddf97 commit 8e00bfc

File tree

5 files changed

+360
-201
lines changed

5 files changed

+360
-201
lines changed

bindings/python/tv.cc

Lines changed: 158 additions & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -3,154 +3,164 @@
33

44
namespace vt::tv::bindings::python {
55

6-
void tvFromJson(const std::vector<std::string>& input_json_per_rank_list, const std::string& input_yaml_params_str, uint64_t num_ranks) {
7-
std::string startup_logo = std::string(" __ __\n")
8-
+ std::string(" _ __/ /_ / /__ __\n")
9-
+ std::string("| | / / __/ _____ / __/ | / /\n")
10-
+ std::string("| |/ / / /____/ / /_ | |/ /\n")
11-
+ std::string("|___/\\__/ \\__/ |___/\n");
12-
fmt::print("==============================\n");
13-
fmt::print(startup_logo);
14-
fmt::print("==============================\n");
15-
16-
YAML::Node viz_config;
17-
try {
18-
// Load the configuration from serialized YAML
19-
viz_config = YAML::Load(input_yaml_params_str);
20-
} catch (std::exception const& e) {
21-
throw std::runtime_error(fmt::format(
22-
"vt-tv: Error reading the configuration file: {}",
23-
e.what()
24-
));
25-
}
26-
27-
// Config Validator
28-
ConfigValidator config_validator(viz_config);
29-
30-
// Check configuration
31-
bool is_config_valid = config_validator.isValid();
32-
33-
// Throw error if configuration is invalid
34-
if (!is_config_valid) {
35-
throw std::runtime_error(fmt::format(
36-
"vt-tv: Error validating the configuration file: {}",
37-
config_validator.getMissingRequiredParameters()
38-
));
39-
}
40-
41-
std::array<std::string, 3> qoi_request = {
42-
viz_config["rank_qoi"].as<std::string>(),
43-
"",
44-
viz_config["object_qoi"].as<std::string>()
45-
};
46-
47-
bool save_meshes = viz_config["save_meshes"].as<bool>();
48-
bool save_pngs = true; // lbaf always saves pngs
49-
bool continuous_object_qoi = viz_config["force_continuous_object_qoi"].as<bool>();
50-
51-
std::array<uint64_t, 3> grid_size = {
52-
viz_config["x_ranks"].as<uint64_t>(),
53-
viz_config["y_ranks"].as<uint64_t>(),
54-
viz_config["z_ranks"].as<uint64_t>()
55-
};
56-
57-
double object_jitter = viz_config["object_jitter"].as<double>();
58-
59-
std::string output_dir = viz_config["output_visualization_dir"].as<std::string>();
60-
std::filesystem::path output_path(output_dir);
61-
62-
// Throw an error if the output directory does not exist or is not absolute
63-
if (!std::filesystem::exists(output_path)) {
64-
throw std::runtime_error(fmt::format(
65-
"vt-tv: Visualization output directory does not exist at {}",
66-
output_dir
67-
));
68-
}
69-
if (!output_path.is_absolute()) {
70-
throw std::runtime_error(fmt::format(
71-
"vt-tv: Visualization output directory must be absolute: {}",
72-
output_dir
73-
));
74-
}
75-
76-
// append / to avoid problems with file stems
77-
if (!output_dir.empty() && output_dir.back() != '/') {
78-
output_dir += '/';
79-
}
80-
81-
std::string output_file_stem = viz_config["output_visualization_file_stem"].as<std::string>();
82-
83-
uint64_t win_size = 2000;
84-
if (viz_config["window_size"]) {
85-
win_size = viz_config["window_size"].as<uint64_t>();
86-
}
87-
88-
// Use automatic font size if not defined by user
89-
// 0.025 is the factor of the window size determined to be ideal for the font size
90-
uint64_t font_size = 0.025 * win_size;
91-
if (viz_config["font_size"]) {
92-
font_size = viz_config["font_size"].as<uint64_t>();
93-
}
94-
95-
// print all saved configuration parameters
96-
fmt::print("Input Configuration Parameters:\n");
97-
fmt::print(" x_ranks: {}\n", grid_size[0]);
98-
fmt::print(" y_ranks: {}\n", grid_size[1]);
99-
fmt::print(" z_ranks: {}\n", grid_size[2]);
100-
fmt::print(" object_jitter: {}\n", object_jitter);
101-
fmt::print(" rank_qoi: {}\n", qoi_request[0]);
102-
fmt::print(" object_qoi: {}\n", qoi_request[2]);
103-
fmt::print(" save_meshes: {}\n", save_meshes);
104-
fmt::print(" save_pngs: {}\n", save_pngs);
105-
fmt::print(" force_continuous_object_qoi: {}\n", continuous_object_qoi);
106-
fmt::print(" output_visualization_dir: {}\n", output_dir);
107-
fmt::print(" output_visualization_file_stem: {}\n", output_file_stem);
108-
fmt::print(" window_size: {}\n", win_size);
109-
fmt::print(" font_size: {}\n", font_size);
110-
111-
using json = nlohmann::json;
112-
113-
assert(input_json_per_rank_list.size() == num_ranks && "Must have the same number of json files as ranks");
114-
115-
// Initialize the info object, that will hold data for all ranks for all phases
116-
std::unique_ptr<Info> info = std::make_unique<Info>();
117-
118-
#ifdef VT_TV_N_THREADS
119-
const int threads = VT_TV_N_THREADS;
120-
#else
121-
const int threads = 2;
122-
#endif
123-
#ifdef VT_TV_OPENMP_ENABLED
124-
#if VT_TV_OPENMP_ENABLED
125-
omp_set_num_threads(threads);
126-
// print number of threads
127-
fmt::print("vt-tv: Using {} threads\n", threads);
128-
# pragma omp parallel for
129-
#endif
130-
#endif
131-
for (int64_t rank_id = 0; rank_id < num_ranks; rank_id++) {
132-
fmt::print("Reading file for rank {}\n", rank_id);
133-
std::string rank_json_str = input_json_per_rank_list[rank_id];
134-
utility::JSONReader reader{static_cast<NodeType>(rank_id)};
135-
reader.readString(rank_json_str);
136-
auto tmpInfo = reader.parse();
137-
#ifdef VT_TV_OPENMP_ENABLED
138-
#if VT_TV_OPENMP_ENABLED
139-
#pragma omp critical
140-
#endif
141-
#endif
142-
{
143-
info->addInfo(tmpInfo->getObjectInfo(), tmpInfo->getRank(rank_id));
144-
}
145-
}
146-
// Instantiate render
147-
Render render(
148-
qoi_request, continuous_object_qoi, *info, grid_size, object_jitter,
149-
output_dir, output_file_stem, 1.0, save_meshes, save_pngs, std::numeric_limits<PhaseType>::max()
150-
);
151-
render.generate(font_size, win_size);
152-
153-
fmt::print("vt-tv: Done.\n");
6+
void tvFromJson(
7+
const std::vector<std::string>& input_json_per_rank_list,
8+
const std::string& input_yaml_params_str,
9+
uint64_t num_ranks) {
10+
std::string startup_logo = std::string(" __ __\n") +
11+
std::string(" _ __/ /_ / /__ __\n") +
12+
std::string("| | / / __/ _____ / __/ | / /\n") +
13+
std::string("| |/ / / /____/ / /_ | |/ /\n") +
14+
std::string("|___/\\__/ \\__/ |___/\n");
15+
fmt::print("==============================\n");
16+
fmt::print(startup_logo);
17+
fmt::print("==============================\n");
18+
19+
YAML::Node viz_config;
20+
try {
21+
// Load the configuration from serialized YAML
22+
viz_config = YAML::Load(input_yaml_params_str);
23+
} catch (std::exception const& e) {
24+
throw std::runtime_error(
25+
fmt::format("vt-tv: Error reading the configuration file: {}", e.what()));
26+
}
27+
28+
// Config Validator
29+
ConfigValidator config_validator(viz_config);
30+
31+
// Check configuration
32+
bool is_config_valid = config_validator.isValid();
33+
34+
// Throw error if configuration is invalid
35+
if (!is_config_valid) {
36+
throw std::runtime_error(
37+
fmt::format(
38+
"vt-tv: Error validating the configuration file: {}",
39+
config_validator.getMissingRequiredParameters()));
40+
}
41+
42+
std::array<std::string, 3> qoi_request = {
43+
viz_config["rank_qoi"].as<std::string>(),
44+
"",
45+
viz_config["object_qoi"].as<std::string>()};
46+
47+
bool save_meshes = viz_config["save_meshes"].as<bool>();
48+
bool save_pngs = true; // lbaf always saves pngs
49+
bool continuous_object_qoi =
50+
viz_config["force_continuous_object_qoi"].as<bool>();
51+
52+
std::array<uint64_t, 3> grid_size = {
53+
viz_config["x_ranks"].as<uint64_t>(),
54+
viz_config["y_ranks"].as<uint64_t>(),
55+
viz_config["z_ranks"].as<uint64_t>()};
56+
57+
double object_jitter = viz_config["object_jitter"].as<double>();
58+
59+
std::string output_dir =
60+
viz_config["output_visualization_dir"].as<std::string>();
61+
std::filesystem::path output_path(output_dir);
62+
63+
// Throw an error if the output directory does not exist or is not absolute
64+
if (!std::filesystem::exists(output_path)) {
65+
throw std::runtime_error(
66+
fmt::format(
67+
"vt-tv: Visualization output directory does not exist at {}",
68+
output_dir));
69+
}
70+
if (!output_path.is_absolute()) {
71+
throw std::runtime_error(
72+
fmt::format(
73+
"vt-tv: Visualization output directory must be absolute: {}",
74+
output_dir));
75+
}
76+
77+
// append / to avoid problems with file stems
78+
if (!output_dir.empty() && output_dir.back() != '/') {
79+
output_dir += '/';
80+
}
81+
82+
std::string output_file_stem =
83+
viz_config["output_visualization_file_stem"].as<std::string>();
84+
85+
uint64_t win_size = 2000;
86+
if (viz_config["window_size"]) {
87+
win_size = viz_config["window_size"].as<uint64_t>();
88+
}
89+
90+
// Use automatic font size if not defined by user
91+
// 0.025 is the factor of the window size determined to be ideal for the font size
92+
uint64_t font_size = 0.025 * win_size;
93+
if (viz_config["font_size"]) {
94+
font_size = viz_config["font_size"].as<uint64_t>();
95+
}
96+
97+
// print all saved configuration parameters
98+
fmt::print("Input Configuration Parameters:\n");
99+
fmt::print(" x_ranks: {}\n", grid_size[0]);
100+
fmt::print(" y_ranks: {}\n", grid_size[1]);
101+
fmt::print(" z_ranks: {}\n", grid_size[2]);
102+
fmt::print(" object_jitter: {}\n", object_jitter);
103+
fmt::print(" rank_qoi: {}\n", qoi_request[0]);
104+
fmt::print(" object_qoi: {}\n", qoi_request[2]);
105+
fmt::print(" save_meshes: {}\n", save_meshes);
106+
fmt::print(" save_pngs: {}\n", save_pngs);
107+
fmt::print(" force_continuous_object_qoi: {}\n", continuous_object_qoi);
108+
fmt::print(" output_visualization_dir: {}\n", output_dir);
109+
fmt::print(" output_visualization_file_stem: {}\n", output_file_stem);
110+
fmt::print(" window_size: {}\n", win_size);
111+
fmt::print(" font_size: {}\n", font_size);
112+
113+
using json = nlohmann::json;
114+
115+
assert(
116+
input_json_per_rank_list.size() == num_ranks &&
117+
"Must have the same number of json files as ranks");
118+
119+
// Initialize the info object, that will hold data for all ranks for all phases
120+
std::unique_ptr<Info> info = std::make_unique<Info>();
121+
122+
#ifdef VT_TV_N_THREADS
123+
const int threads = VT_TV_N_THREADS;
124+
#else
125+
const int threads = 2;
126+
#endif
127+
#ifdef VT_TV_OPENMP_ENABLED
128+
#if VT_TV_OPENMP_ENABLED
129+
omp_set_num_threads(threads);
130+
// print number of threads
131+
fmt::print("vt-tv: Using {} threads\n", threads);
132+
#pragma omp parallel for
133+
#endif
134+
#endif
135+
for (int64_t rank_id = 0; rank_id < num_ranks; rank_id++) {
136+
fmt::print("Reading file for rank {}\n", rank_id);
137+
std::string rank_json_str = input_json_per_rank_list[rank_id];
138+
utility::JSONReader reader{static_cast<NodeType>(rank_id)};
139+
reader.readString(rank_json_str);
140+
auto tmpInfo = reader.parse();
141+
#ifdef VT_TV_OPENMP_ENABLED
142+
#if VT_TV_OPENMP_ENABLED
143+
#pragma omp critical
144+
#endif
145+
#endif
146+
{ info->addInfo(tmpInfo->getObjectInfo(), tmpInfo->getRank(rank_id)); }
147+
}
148+
// Instantiate render
149+
Render render(
150+
qoi_request,
151+
continuous_object_qoi,
152+
*info,
153+
grid_size,
154+
object_jitter,
155+
output_dir,
156+
output_file_stem,
157+
1.0,
158+
save_meshes,
159+
save_pngs,
160+
std::numeric_limits<PhaseType>::max());
161+
render.generate(font_size, win_size);
162+
163+
fmt::print("vt-tv: Done.\n");
154164
}
155165

156166
namespace nb = nanobind;

src/vt-tv/utility/config_reader.cc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,78 @@ ConfigReader ConfigReader::from_file(const std::string& filename) {
5656
return cfg;
5757
}
5858

59+
ConfigReader ConfigReader::from_binding_inputs(
60+
const std::string& viz_yaml_fragment,
61+
uint64_t num_ranks)
62+
{
63+
YAML::Node root_in;
64+
try {
65+
root_in = YAML::Load(viz_yaml_fragment);
66+
} catch (const std::exception& e) {
67+
throw ValidationError(std::string("Failed to parse binding YAML: ") + e.what());
68+
}
69+
70+
YAML::Node vis = root_in["visualization"];
71+
if (!vis || !vis.IsMap()) {
72+
throw ValidationError("Binding config must have 'visualization' map at top level.");
73+
}
74+
75+
YAML::Node synthetic;
76+
// input
77+
synthetic["input"]["directory"] = ""; // dummy, not used (no filesystem discovery)
78+
synthetic["input"]["n_ranks"] = num_ranks;
79+
// no file_stem in this mode
80+
81+
// viz
82+
if (vis["x_ranks"]) synthetic["viz"]["x_ranks"] = vis["x_ranks"];
83+
if (vis["y_ranks"]) synthetic["viz"]["y_ranks"] = vis["y_ranks"];
84+
if (vis["z_ranks"]) synthetic["viz"]["z_ranks"] = vis["z_ranks"];
85+
if (vis["object_jitter"]) synthetic["viz"]["object_jitter"] = vis["object_jitter"];
86+
if (vis["rank_qoi"]) synthetic["viz"]["rank_qoi"] = vis["rank_qoi"];
87+
if (vis["object_qoi"]) synthetic["viz"]["object_qoi"] = vis["object_qoi"];
88+
if (vis["save_meshes"]) synthetic["viz"]["save_meshes"] = vis["save_meshes"];
89+
// binding always renders PNGs
90+
synthetic["viz"]["save_pngs"] = true;
91+
if (vis["force_continuous_object_qoi"]) {
92+
synthetic["viz"]["force_continuous_object_qoi"] =
93+
vis["force_continuous_object_qoi"];
94+
}
95+
96+
// output
97+
// required in binding mode:
98+
if (!vis["output_visualization_dir"] ||
99+
!vis["output_visualization_dir"].IsScalar()) {
100+
throw ValidationError("Binding config missing required 'output_visualization_dir'.");
101+
}
102+
if (!vis["output_visualization_file_stem"] ||
103+
!vis["output_visualization_file_stem"].IsScalar()) {
104+
throw ValidationError("Binding config missing required 'output_visualization_file_stem'.");
105+
}
106+
107+
synthetic["output"]["directory"] =
108+
vis["output_visualization_dir"].as<std::string>();
109+
synthetic["output"]["file_stem"] =
110+
vis["output_visualization_file_stem"].as<std::string>();
111+
112+
if (vis["window_size"]) synthetic["output"]["window_size"] = vis["window_size"];
113+
if (vis["font_size"]) synthetic["output"]["font_size"] = vis["font_size"];
114+
115+
// In binding mode we require absolute output directory
116+
{
117+
std::string outdir = synthetic["output"]["directory"].as<std::string>();
118+
std::filesystem::path p(outdir);
119+
if (!p.is_absolute()) {
120+
throw SemanticError("Visualization output directory must be absolute: " + outdir);
121+
}
122+
// We don't prepend SRC_DIR in this mode
123+
}
124+
125+
// Give adapted config to regular config parser
126+
ConfigReader cfg = ConfigReader::parse(synthetic);
127+
cfg.compute_grid();
128+
return cfg;
129+
}
130+
59131
ConfigReader ConfigReader::parse(const YAML::Node& root) {
60132
ConfigReader cfg;
61133

0 commit comments

Comments
 (0)