Skip to content

Commit

Permalink
Merge pull request #119 from DARMA-tasking/61-create-configuration-va…
Browse files Browse the repository at this point in the history
…lidator

#61: Create configuration validator
  • Loading branch information
maxime-bfsquall authored Sep 27, 2024
2 parents 8229063 + 7589afd commit 6617f3a
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 31 deletions.
43 changes: 43 additions & 0 deletions bindings/python/config_validator.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#include "config_validator.h"

namespace vt::tv::bindings::python {

/**
* Check if the configuration file is valid
*
* @return true if the configuration is valid
*/
bool ConfigValidator::isValid()
{
bool is_valid = true;
for (std::string parameter: required_parameters) {
if (!config[parameter]) {
is_valid = false;
break;
}
}
return is_valid;
}


/**
* Get the list of missing parameters
*
* @return A string containing the list of the missing parameters
*/
std::string ConfigValidator::getMissingRequiredParameters()
{
std::string parameters;
for (std::string parameter: required_parameters) {
if (!config[parameter]) {
if (parameters.empty()) {
parameters = parameter;
} else {
parameters = parameters + ", " + parameter;
}
}
}
return parameters;
}

} /* end namespace vt::tv::bindings::python */
64 changes: 64 additions & 0 deletions bindings/python/config_validator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
//@HEADER
// *****************************************************************************
//
// config_validator.h
// DARMA/vt-tv => Virtual Transport -- Task Visualizer
//
// Copyright 2019-2024 National Technology & Engineering Solutions of Sandia, LLC
// (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
// Government retains certain rights in this software.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from this
// software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact [email protected]
//
// *****************************************************************************
//@HEADER
*/
#ifndef vt_tv_config_validator_h
#define vt_tv_config_validator_h

#include <yaml-cpp/yaml.h>

namespace vt::tv::bindings::python {
/**
* ConfigValidator Class
*/
class ConfigValidator
{
public:
std::array<std::string, 2> required_parameters = {"output_visualization_dir", "output_visualization_file_stem"};
YAML::Node config;
bool isValid();
std::string getMissingRequiredParameters();
ConfigValidator(YAML::Node in_config)
:config(in_config) {}
};
}

#endif
59 changes: 41 additions & 18 deletions bindings/python/tv.cc
Original file line number Diff line number Diff line change
@@ -1,22 +1,42 @@
#include "tv.h"
#include "config_validator.h"

namespace vt::tv::bindings::python {

void tvFromJson(const std::vector<std::string>& input_json_per_rank_list, const std::string& input_yaml_params_str, uint64_t num_ranks) {
std::string startup_logo = std::string(" __ __\n")
+ std::string(" _ __/ /_ / /__ __\n")
+ std::string("| | / / __/ _____ / __/ | / /\n")
+ std::string("| |/ / / /____/ / /_ | |/ /\n")
+ std::string("|___/\\__/ \\__/ |___/\n");
fmt::print("==============================\n");
fmt::print(startup_logo);
fmt::print("==============================\n");
std::string startup_logo = std::string(" __ __\n")
+ std::string(" _ __/ /_ / /__ __\n")
+ std::string("| | / / __/ _____ / __/ | / /\n")
+ std::string("| |/ / / /____/ / /_ | |/ /\n")
+ std::string("|___/\\__/ \\__/ |___/\n");
fmt::print("==============================\n");
fmt::print(startup_logo);
fmt::print("==============================\n");

YAML::Node viz_config;
try {
// Load the configuration from serialized YAML
viz_config = YAML::Load(input_yaml_params_str);
} catch (std::exception const& e) {
throw std::runtime_error(fmt::format(
"vt-tv: Error reading the configuration file: {}",
e.what()
));
}

// Config Validator
ConfigValidator config_validator(viz_config);

// parse the input yaml parameters
try {
// Load the configuration from serialized YAML
YAML::Node viz_config = YAML::Load(input_yaml_params_str);
// Check configuration
bool is_config_valid = config_validator.isValid();

// Throw error if configuration is invalid
if (!is_config_valid) {
throw std::runtime_error(fmt::format(
"vt-tv: Error validating the configuration file: {}",
config_validator.getMissingRequiredParameters()
));
}

std::array<std::string, 3> qoi_request = {
viz_config["rank_qoi"].as<std::string>(),
Expand All @@ -41,10 +61,16 @@ void tvFromJson(const std::vector<std::string>& input_json_per_rank_list, const

// Throw an error if the output directory does not exist or is not absolute
if (!std::filesystem::exists(output_path)) {
throw std::runtime_error(fmt::format("Visualization output directory does not exist at {}", output_dir));
throw std::runtime_error(fmt::format(
"vt-tv: Visualization output directory does not exist at {}",
output_dir
));
}
if (!output_path.is_absolute()) {
throw std::runtime_error("Visualization output directory must be absolute.");
throw std::runtime_error(fmt::format(
"vt-tv: Visualization output directory must be absolute: {}",
output_dir
));
}

// append / to avoid problems with file stems
Expand Down Expand Up @@ -123,11 +149,8 @@ void tvFromJson(const std::vector<std::string>& input_json_per_rank_list, const
output_dir, output_file_stem, 1.0, save_meshes, save_pngs, std::numeric_limits<PhaseType>::max()
);
render.generate(font_size, win_size);
} catch (std::exception const& e) {
throw std::runtime_error(fmt::format("vt-tv: Error reading the configuration file: {}", e.what()));
}

fmt::print("vt-tv: Done.\n");
fmt::print("vt-tv: Done.\n");
}

namespace nb = nanobind;
Expand Down
36 changes: 23 additions & 13 deletions tests/test_bindings.py
Original file line number Diff line number Diff line change
@@ -1,38 +1,48 @@
"""This module calls vttv module to test that vttv bindings work as expected"""
import json
import os

import json
import sys
import yaml
import vttv


# source dir is the directory a level above this file
source_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

with open(f'{source_dir}/tests/test_bindings_conf.yaml', 'r', encoding='utf-8') as stream:
# Read the YAML config file
with open(f"{source_dir}/tests/test_bindings_conf.yaml", "r", encoding="utf-8") as stream:
try:
params = yaml.safe_load(stream)
except yaml.YAMLError as exc:
print(exc)
exit(1)

# Check main key is "visualization"
if "visualization" not in params:
print(
"The YAML configuration file is not valid: "+\
"missing required paramater \"visualization\""
)
sys.exit(1)

# make output_visualization_dir directory parameter absolute
if not os.path.isabs(params["visualization"]["output_visualization_dir"]):
params["visualization"]["output_visualization_dir"] = source_dir + \
"/" + params["visualization"]["output_visualization_dir"]
if "output_visualization_dir" in params["visualization"]:
if not os.path.isabs(params["visualization"]["output_visualization_dir"]):
params["visualization"]["output_visualization_dir"] = source_dir + \
"/" + params["visualization"]["output_visualization_dir"]

# Serialize visualization parameters
params_serialized = yaml.dump(params["visualization"])

# Calculate n_ranks
n_ranks = params["visualization"]["x_ranks"] * \
params["visualization"]["y_ranks"] * params["visualization"]["z_ranks"]
rank_data = []

rank_data = []
for rank in range(n_ranks):
with open(f'{source_dir}/data/lb_test_data/data.{rank}.json', 'r', encoding='utf-8') as f:
with open(f"{source_dir}/data/lb_test_data/data.{rank}.json", "r", encoding="utf-8") as f:
data = json.load(f)

data_serialized = json.dumps(data)

rank_data.append((data_serialized))
# Add serialized data into the rank
rank_data.append((json.dumps(data)))

# Launch VT TV from JSON data
vttv.tvFromJson(rank_data, params_serialized, n_ranks)

0 comments on commit 6617f3a

Please sign in to comment.