diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.cpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.cpp index fa8c76a3c..a3288f702 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.cpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.cpp @@ -58,6 +58,98 @@ bool is_valid_expression(const std::string expr, std::string &err_msg) return res; } +conduit::Node number_schema() +{ + conduit::Node n; + n["type"] = "number"; + return n; +} + +conduit::Node string_schema() +{ + conduit::Node n; + n["type"] = "string"; + return n; +} + +conduit::Node vec3_schema(const std::string var1, const std::string var2, const std::string var3) +{ + conduit::Node n; + n["type"] = "object"; + n["additionalProperties"] = false; + + n["properties/" + var1].set(number_schema()); + n["properties/" + var2].set(number_schema()); + n["properties/" + var3].set(number_schema()); + + n["required"].append() = var1; + n["required"].append() = var2; + n["required"].append() = var3; + + return n; +} + +conduit::Node vec3_schema() +{ + return vec3_schema("x", "y", "z"); +} + +conduit::Node vec3_schema_anyOf(const std::string var1, const std::string var2, const std::string var3) +{ + conduit::Node n; + n["type"] = "object"; + n["additionalProperties"] = false; + + n["properties/" + var1].set(number_schema()); + n["properties/" + var2].set(number_schema()); + n["properties/" + var3].set(number_schema()); + + conduit::Node var1_required; + var1_required["type"] = "object"; + var1_required["required"] = var1; + n["anyOf"].append().set(var1_required); + + conduit::Node var2_required; + var2_required["type"] = "object"; + var2_required["required"] = var1; + n["anyOf"].append().set(var2_required); + + conduit::Node var3_required; + var3_required["type"] = "object"; + var3_required["required"] = var1; + n["anyOf"].append().set(var3_required); + + return n; +} + +conduit::Node vec3_schema_anyOf() +{ + return vec3_schema_anyOf("x", "y", "z"); +} + +conduit::Node array_schema(const conduit::Node &item_schema) +{ + conduit::Node n; + n["type"] = "array"; + n["items"].set(item_schema); + return n; +} + +conduit::Node array_schema() +{ + conduit::Node n; + n["type"] = "array"; + return n; +} + +conduit::Node ignore_schema() +{ + conduit::Node n; + n["type"] = "object"; + n["constraints/skip"] = true; + return n; +} + //----------------------------------------------------------------------------- bool check_numeric(const std::string path, diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.hpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.hpp index c2874fe43..e137446dd 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.hpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_param_check.hpp @@ -41,6 +41,28 @@ namespace runtime namespace filters { +conduit::Node ASCENT_API number_schema(); + +conduit::Node ASCENT_API string_schema(); + +conduit::Node ASCENT_API vec3_schema(); + +conduit::Node ASCENT_API vec3_schema(const std::string var1, + const std::string var2, + const std::string var3); + +conduit::Node ASCENT_API vec3_schema_anyOf(); + +conduit::Node ASCENT_API vec3_schema_anyOf(const std::string var1, + const std::string var2, + const std::string var3); + +conduit::Node ASCENT_API array_schema(); + +conduit::Node ASCENT_API array_schema(const conduit::Node &item_schema); + +conduit::Node ASCENT_API ignore_schema(); + bool ASCENT_API check_numeric(const std::string path, const conduit::Node ¶ms, conduit::Node &info, @@ -77,6 +99,7 @@ void ASCENT_API path_helper(std::vector &paths, std::string ASCENT_API surprise_check(const std::vector &valid_paths, const conduit::Node &node); + // // Ignore paths only ignores top level paths, differing lower level // paths to another surprise check. diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.cpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.cpp index 8079edfc9..60d63013f 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.cpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.cpp @@ -134,40 +134,22 @@ VTKHMarchingCubes::declare_interface(Node &i) i["type_name"] = "vtkh_marchingcubes"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHMarchingCubes::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - bool has_values = check_numeric("iso_values",params, info, false); - bool has_levels = check_numeric("levels",params, info, false); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - if(!has_values && !has_levels) - { - info["errors"].append() = "Missing required numeric parameter. Contour must" - " specify 'iso_values' or 'levels'."; - res = false; - } + param_schema["properties/field"].set(string_schema()); + param_schema["properties/levels"].set(number_schema()); + param_schema["properties/iso_values"].set(number_schema()); + param_schema["properties/use_contour_tree"].set(string_schema()); - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("levels"); - valid_paths.push_back("iso_values"); - valid_paths.push_back("use_contour_tree"); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + param_schema["anyOf"].append() = "levels"; + param_schema["anyOf"].append() = "iso_values"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -245,7 +227,6 @@ VTKHMarchingCubes::execute() set_output(res); } -//----------------------------------------------------------------------------- //----------------------------------------------------------------------------- VTKHExternalSurfaces::VTKHExternalSurfaces() :Filter() @@ -266,31 +247,15 @@ VTKHExternalSurfaces::declare_interface(Node &i) i["type_name"] = "vtkh_external_surfaces"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHExternalSurfaces::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = true; - - res = check_string("topology",params, info, false) && res; - - std::vector valid_paths; - valid_paths.push_back("topology"); - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - return res; + param_schema["properties/topology"].set(string_schema()); + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -360,30 +325,18 @@ VTKHVectorMagnitude::declare_interface(Node &i) i["type_name"] = "vtkh_vector_magnitude"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHVectorMagnitude::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - res = check_string("output_name",params, info, false) && res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - std::string surprises = surprise_check(valid_paths, params); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -464,36 +417,18 @@ VTKH3Slice::declare_interface(Node &i) i["type_name"] = "vtkh_3slice"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKH3Slice::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = true; - std::vector valid_paths; - res &= check_string("topology",params, info, false); - valid_paths.push_back("topology"); - - res &= check_numeric("x_offset",params, info, false, true); - res &= check_numeric("y_offset",params, info, false, true); - res &= check_numeric("z_offset",params, info, false, true); - res = check_string("topology",params, info, false) && res; - - valid_paths.push_back("x_offset"); - valid_paths.push_back("y_offset"); - valid_paths.push_back("z_offset"); - - std::string surprises = surprise_check(valid_paths, params); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - return res; + param_schema["properties/topology"].set(string_schema()); + param_schema["properties/x_offset"].set(number_schema()); + param_schema["properties/y_offset"].set(number_schema()); + param_schema["properties/z_offset"].set(number_schema()); + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -613,32 +548,15 @@ VTKHTriangulate::declare_interface(Node &i) i["type_name"] = "vtkh_triangulate"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHTriangulate::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = true; - - res = check_string("topology",params, info, false) && res; - - std::vector valid_paths; - valid_paths.push_back("topology"); - - std::string surprises = surprise_check(valid_paths, params); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["properties/topology"].set(string_schema()); + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -708,32 +626,16 @@ VTKHCleanGrid::declare_interface(Node &i) i["type_name"] = "vtkh_clean"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHCleanGrid::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = true; - - res = check_string("topology",params, info, false) && res; - - std::vector valid_paths; - valid_paths.push_back("topology"); - - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - return res; + // optional + param_schema["properties/topology"].set(string_schema()); + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -806,138 +708,102 @@ VTKHSlice::declare_interface(Node &i) i["type_name"] = "vtkh_slice"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHSlice::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = true; - res &= check_string("topology",params, info, false); - if(params.has_child("sphere")) - { - res = check_numeric("sphere/center/x",params, info, true, true) && res; - res = check_numeric("sphere/center/y",params, info, true, true) && res; - res = check_numeric("sphere/center/z",params, info, true, true) && res; - res = check_numeric("sphere/radius",params, info, true, true) && res; - } - else if(params.has_child("cylinder")) - { - res = check_numeric("cylinder/center/x",params, info, true, true) && res; - res = check_numeric("cylinder/center/y",params, info, true, true) && res; - res = check_numeric("cylinder/center/z",params, info, true, true) && res; - res = check_numeric("cylinder/axis/x",params, info, true, true) && res; - res = check_numeric("cylinder/axis/y",params, info, true, true) && res; - res = check_numeric("cylinder/axis/z",params, info, true, true) && res; - res = check_numeric("cylinder/radius",params, info, true, true) && res; - } - else if(params.has_child("box")) - { - res = check_numeric("box/min/x",params, info, true, true) && res; - res = check_numeric("box/min/y",params, info, true, true) && res; - res = check_numeric("box/min/z",params, info, true, true) && res; - res = check_numeric("box/max/x",params, info, true, true) && res; - res = check_numeric("box/max/y",params, info, true, true) && res; - res = check_numeric("box/max/z",params, info, true, true) && res; - } - else if(params.has_child("plane")) - { - res = check_numeric("plane/point/x",params, info, true, true) && res; - res = check_numeric("plane/point/y",params, info, true, true) && res; - res = check_numeric("plane/point/z",params, info, true, true) && res; - res = check_numeric("plane/normal/x",params, info, true, true) && res; - res = check_numeric("plane/normal/y",params, info, true, true) && res; - res = check_numeric("plane/normal/z",params, info, true, true) && res; - } - - // old style plane - if(params.has_path("point/x_offset") && params.has_path("point/x")) - { - info["errors"] - .append() = "Cannot specify the plane point as both an offset and explicit point"; - res = false; - } - - if(params.has_path("point/x")) - { - res &= check_numeric("point/x",params, info, true, true); - res = check_numeric("point/y",params, info, true, true) && res; - res = check_numeric("point/z",params, info, true, true) && res; - } - else if(params.has_path("point/x_offset")) - { - res &= check_numeric("point/x_offset",params, info, true, true); - res = check_numeric("point/y_offset",params, info, true, true) && res; - res = check_numeric("point/z_offset",params, info, true, true) && res; - } - // else - // { - // info["errors"] - // .append() = "Slice must specify a point for the plane."; - // res = false; - // } - if(params.has_path("normal/x")) - { - res = check_numeric("normal/x",params, info, true, true) && res; - res = check_numeric("normal/y",params, info, true, true) && res; - res = check_numeric("normal/z",params, info, true, true) && res; - } - - std::vector valid_paths; - // old style plane - valid_paths.push_back("point/x"); - valid_paths.push_back("point/y"); - valid_paths.push_back("point/z"); - valid_paths.push_back("point/x_offset"); - valid_paths.push_back("point/y_offset"); - valid_paths.push_back("point/z_offset"); - valid_paths.push_back("normal/x"); - valid_paths.push_back("normal/y"); - valid_paths.push_back("normal/z"); - valid_paths.push_back("topology"); - - // sphere - valid_paths.push_back("sphere/center/x"); - valid_paths.push_back("sphere/center/y"); - valid_paths.push_back("sphere/center/z"); - valid_paths.push_back("sphere/radius"); - // cylinder - valid_paths.push_back("cylinder/center/x"); - valid_paths.push_back("cylinder/center/y"); - valid_paths.push_back("cylinder/center/z"); - valid_paths.push_back("cylinder/axis/x"); - valid_paths.push_back("cylinder/axis/y"); - valid_paths.push_back("cylinder/axis/z"); - valid_paths.push_back("cylinder/radius"); - // box - valid_paths.push_back("box/min/x"); - valid_paths.push_back("box/min/y"); - valid_paths.push_back("box/min/z"); - valid_paths.push_back("box/max/x"); - valid_paths.push_back("box/max/y"); - valid_paths.push_back("box/max/z"); - // new style plane - valid_paths.push_back("plane/point/x"); - valid_paths.push_back("plane/point/y"); - valid_paths.push_back("plane/point/z"); - valid_paths.push_back("plane/normal/x"); - valid_paths.push_back("plane/normal/y"); - valid_paths.push_back("plane/normal/z"); - - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + param_schema["constraints/exclusiveChildren"].append() = "sphere"; + param_schema["constraints/exclusiveChildren"].append() = "cylinder"; + param_schema["constraints/exclusiveChildren"].append() = "box"; + param_schema["constraints/exclusiveChildren"].append() = "plane"; + param_schema["constraints/exclusiveChildren"].append() = "point"; + param_schema["constraints/allowNoneInExclusiveGroup"] = false; + + // optional + param_schema["properties/topology"].set(string_schema()); + + // --- sphere --- + conduit::Node sphere_schema; + sphere_schema["type"] = "object"; + sphere_schema["additionalProperties"] = false; + sphere_schema["properties/center"].set(vec3_schema()); + sphere_schema["properties/radius"].set(number_schema()); + sphere_schema["required"].append() = "center"; + sphere_schema["required"].append() = "radius"; + param_schema["properties/sphere"].set(sphere_schema); + + // --- cylinder --- + conduit::Node cylinder_schema; + cylinder_schema["type"] = "object"; + cylinder_schema["additionalProperties"] = false; + cylinder_schema["properties/center"].set(vec3_schema()); + cylinder_schema["properties/axis"].set(vec3_schema()); + cylinder_schema["properties/radius"].set(number_schema()); + cylinder_schema["required"].append() = "center"; + cylinder_schema["required"].append() = "axis"; + cylinder_schema["required"].append() = "radius"; + param_schema["properties/cylinder"].set(cylinder_schema); + + // --- box --- + conduit::Node box_schema; + box_schema["type"] = "object"; + box_schema["additionalProperties"] = false; + box_schema["properties/min"].set(vec3_schema()); + box_schema["properties/max"].set(vec3_schema()); + box_schema["required"].append() = "min"; + box_schema["required"].append() = "max"; + param_schema["properties/box"].set(box_schema); + + // --- plane --- + conduit::Node plane_schema; + plane_schema["type"] = "object"; + plane_schema["additionalProperties"] = false; + plane_schema["properties/point"].set(vec3_schema()); + plane_schema["properties/normal"].set(vec3_schema()); + plane_schema["required"].append() = "point"; + plane_schema["required"].append() = "normal"; + param_schema["properties/plane"].set(plane_schema); + + // --- old point style + conduit::Node point_schema; + point_schema["type"] = "object"; + point_schema["additionalProperties"] = false; + + point_schema["properties/x"].set(number_schema()); + point_schema["properties/y"].set(number_schema()); + point_schema["properties/z"].set(number_schema()); + point_schema["properties/x_offset"].set(number_schema()); + point_schema["properties/y_offset"].set(number_schema()); + point_schema["properties/z_offset"].set(number_schema()); + + // Option A: explicit + conduit::Node option_1_explicit; + option_1_explicit["type"] = "object"; + option_1_explicit["required"].append() = "x"; + option_1_explicit["required"].append() = "y"; + option_1_explicit["required"].append() = "z"; + option_1_explicit["constraints/forbid"].append() = "x_offset"; + option_1_explicit["constraints/forbid"].append() = "y_offset"; + option_1_explicit["constraints/forbid"].append() = "z_offset"; + point_schema["oneOf"].append().set(option_1_explicit); + + // Option B: offset + conduit::Node option_2_offset; + option_2_offset["type"] = "object"; + option_2_offset["required"].append() = "x_offset"; + option_2_offset["required"].append() = "y_offset"; + option_2_offset["required"].append() = "z_offset"; + option_2_offset["constraints/forbid"].append() = "x"; + option_2_offset["constraints/forbid"].append() = "y"; + option_2_offset["constraints/forbid"].append() = "z"; + point_schema["oneOf"].append().set(option_2_offset); + + param_schema["properties/point"].set(point_schema); + param_schema["properties/normal"].set(vec3_schema()); + param_schema["constraints/dependencies/normal"].append() = "point"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -1118,48 +984,21 @@ VTKHAutoSliceLevels::declare_interface(Node &i) i["type_name"] = "vtkh_autoslicelevels"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHAutoSliceLevels::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - - if(!params.has_path("levels")) - { - info["errors"] - .append() = "AutoSliceLevels must specify number of slices to consider via 'levels'."; - res = false; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + param_schema["properties/field"].set(string_schema()); + param_schema["properties/normal"].set(vec3_schema()); + param_schema["properties/levels"].set(number_schema()); - res = check_numeric("normal/x",params, info, true, true) && res; - res = check_numeric("normal/y",params, info, true, true) && res; - res = check_numeric("normal/z",params, info, true, true) && res; - - res = check_numeric("levels",params, info, true, true) && res; - - std::vector valid_paths; - valid_paths.push_back("levels"); - valid_paths.push_back("field"); - valid_paths.push_back("normal/x"); - valid_paths.push_back("normal/y"); - valid_paths.push_back("normal/z"); - - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + param_schema["required"].append() = "normal"; + param_schema["required"].append() = "levels"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -1319,33 +1158,21 @@ VTKHGhostStripper::declare_interface(Node &i) i["type_name"] = "vtkh_ghost_stripper"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHGhostStripper::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - res = check_numeric("min_value",params, info, true, true) && res; - res = check_numeric("max_value",params, info, true, true) && res; + param_schema["properties/field"].set(string_schema()); + param_schema["properties/min_value"].set(number_schema()); + param_schema["properties/max_value"].set(number_schema()); - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("min_value"); - valid_paths.push_back("max_value"); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + param_schema["required"].append() = "min_value"; + param_schema["required"].append() = "max_value"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -1432,31 +1259,17 @@ VTKHAddRanks::declare_interface(Node &i) i["type_name"] = "vtkh_add_mpi_ranks"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHAddRanks::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - bool res = check_string("topology",params, info, false); - res = check_string("output",params, info, false); - - std::vector valid_paths; - valid_paths.push_back("output"); - valid_paths.push_back("topology"); - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // optional + param_schema["properties/topology"].set(string_schema()); + param_schema["properties/output"].set(string_schema()); + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -1541,31 +1354,17 @@ VTKHAddDomains::declare_interface(Node &i) i["type_name"] = "vtkh_add_domain_ids"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHAddDomains::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("topology",params, info, false); - res = check_string("output",params, info, false); - - std::vector valid_paths; - valid_paths.push_back("output"); - valid_paths.push_back("topology"); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - return res; + // optional + param_schema["properties/topology"].set(string_schema()); + param_schema["properties/output"].set(string_schema()); + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -1645,177 +1444,86 @@ VTKHThreshold::declare_interface(Node &i) i["type_name"] = "vtkh_threshold"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHThreshold::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = true; - - bool type_present = false; - - if(params.has_child("field")) - { - type_present = true; - } - else if(params.has_child("sphere")) - { - type_present = true; - } - else if(params.has_child("cylinder")) - { - type_present = true; - } - else if(params.has_child("box")) - { - type_present = true; - } - else if(params.has_child("plane")) - { - type_present = true; - } - else if(params.has_child("multi_plane")) - { - type_present = true; - } - if(!type_present) - { - info["errors"].append() = "Missing required parameter. Threshold must specify 'field', 'sphere', 'cylinder', 'box', or 'plane'"; - res = false; - } - else - { - if(params.has_child("sphere")) - { - res = check_numeric("sphere/center/x",params, info, true, true) && res; - res = check_numeric("sphere/center/y",params, info, true, true) && res; - res = check_numeric("sphere/center/z",params, info, true, true) && res; - res = check_numeric("sphere/radius",params, info, true, true) && res; - } - else if(params.has_child("cylinder")) - { - res = check_numeric("cylinder/center/x",params, info, true, true) && res; - res = check_numeric("cylinder/center/y",params, info, true, true) && res; - res = check_numeric("cylinder/center/z",params, info, true, true) && res; - res = check_numeric("cylinder/axis/x",params, info, true, true) && res; - res = check_numeric("cylinder/axis/y",params, info, true, true) && res; - res = check_numeric("cylinder/axis/z",params, info, true, true) && res; - res = check_numeric("cylinder/radius",params, info, true, true) && res; - } - else if(params.has_child("box")) - { - res = check_numeric("box/min/x",params, info, true, true) && res; - res = check_numeric("box/min/y",params, info, true, true) && res; - res = check_numeric("box/min/z",params, info, true, true) && res; - res = check_numeric("box/max/x",params, info, true, true) && res; - res = check_numeric("box/max/y",params, info, true, true) && res; - res = check_numeric("box/max/z",params, info, true, true) && res; - } - else if(params.has_child("plane")) - { - res = check_numeric("plane/point/x",params, info, true, true) && res; - res = check_numeric("plane/point/y",params, info, true, true) && res; - res = check_numeric("plane/point/z",params, info, true, true) && res; - res = check_numeric("plane/normal/x",params, info, true, true) && res; - res = check_numeric("plane/normal/y",params, info, true, true) && res; - res = check_numeric("plane/normal/z",params, info, true, true) && res; - } - else if(params.has_child("multi_plane")) - { - res = check_numeric("multi_plane/point1/x",params, info, true, true) && res; - res = check_numeric("multi_plane/point1/y",params, info, true, true) && res; - res = check_numeric("multi_plane/point1/z",params, info, true, true) && res; - res = check_numeric("multi_plane/normal1/x",params, info, true, true) && res; - res = check_numeric("multi_plane/normal1/y",params, info, true, true) && res; - res = check_numeric("multi_plane/normal1/z",params, info, true, true) && res; - - res = check_numeric("multi_plane/point2/x",params, info, true, true) && res; - res = check_numeric("multi_plane/point2/y",params, info, true, true) && res; - res = check_numeric("multi_plane/point2/z",params, info, true, true) && res; - res = check_numeric("multi_plane/normal2/x",params, info, true, true) && res; - res = check_numeric("multi_plane/normal2/y",params, info, true, true) && res; - res = check_numeric("multi_plane/normal2/z",params, info, true, true) && res; - } - } - - // we either need 'field` or `topology` - if(!params.has_child("field")) - { - res &= check_string("topology",params, info, false); - } - - // field case - res = check_string("field",params, info, false); - res = check_numeric("min_value",params, info, false, true) && res; - res = check_numeric("max_value",params, info, false, true) && res; - - res = check_string("invert",params, info, false) && res; - - std::vector valid_paths; - valid_paths.push_back("invert"); - valid_paths.push_back("field"); - valid_paths.push_back("min_value"); - valid_paths.push_back("max_value"); - - valid_paths.push_back("topology"); - valid_paths.push_back("extract"); - - valid_paths.push_back("sphere/center/x"); - valid_paths.push_back("sphere/center/y"); - valid_paths.push_back("sphere/center/z"); - valid_paths.push_back("sphere/radius"); - - valid_paths.push_back("cylinder/center/x"); - valid_paths.push_back("cylinder/center/y"); - valid_paths.push_back("cylinder/center/z"); - valid_paths.push_back("cylinder/axis/x"); - valid_paths.push_back("cylinder/axis/y"); - valid_paths.push_back("cylinder/axis/z"); - valid_paths.push_back("cylinder/radius"); - - valid_paths.push_back("box/min/x"); - valid_paths.push_back("box/min/y"); - valid_paths.push_back("box/min/z"); - valid_paths.push_back("box/max/x"); - valid_paths.push_back("box/max/y"); - valid_paths.push_back("box/max/z"); - - valid_paths.push_back("plane/point/x"); - valid_paths.push_back("plane/point/y"); - valid_paths.push_back("plane/point/z"); - valid_paths.push_back("plane/normal/x"); - valid_paths.push_back("plane/normal/y"); - valid_paths.push_back("plane/normal/z"); - - valid_paths.push_back("multi_plane/point1/x"); - valid_paths.push_back("multi_plane/point1/y"); - valid_paths.push_back("multi_plane/point1/z"); - valid_paths.push_back("multi_plane/normal1/x"); - valid_paths.push_back("multi_plane/normal1/y"); - valid_paths.push_back("multi_plane/normal1/z"); - - valid_paths.push_back("multi_plane/point2/x"); - valid_paths.push_back("multi_plane/point2/y"); - valid_paths.push_back("multi_plane/point2/z"); - valid_paths.push_back("multi_plane/normal2/x"); - valid_paths.push_back("multi_plane/normal2/y"); - valid_paths.push_back("multi_plane/normal2/z"); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + param_schema["constraints/exclusiveChildren"].append() = "field"; + param_schema["constraints/exclusiveChildren"].append() = "sphere"; + param_schema["constraints/exclusiveChildren"].append() = "cylinder"; + param_schema["constraints/exclusiveChildren"].append() = "box"; + param_schema["constraints/exclusiveChildren"].append() = "plane"; + param_schema["constraints/exclusiveChildren"].append() = "multi_plane"; + param_schema["constraints/allowNoneInExclusiveGroup"] = false; + + // optional + param_schema["properties/field"].set(string_schema()); + param_schema["properties/topology"].set(string_schema()); + param_schema["properties/min_value"].set(number_schema()); + param_schema["properties/max_value"].set(number_schema()); + param_schema["properties/invert"].set(string_schema()); + param_schema["properties/extract"].set(string_schema()); + + // --- sphere --- + conduit::Node sphere_schema; + sphere_schema["type"] = "object"; + sphere_schema["additionalProperties"] = false; + sphere_schema["properties/center"].set(vec3_schema()); + sphere_schema["properties/radius"].set(number_schema()); + sphere_schema["required"].append() = "center"; + sphere_schema["required"].append() = "radius"; + param_schema["properties/sphere"].set(sphere_schema); + + // --- cylinder --- + conduit::Node cylinder_schema; + cylinder_schema["type"] = "object"; + cylinder_schema["additionalProperties"] = false; + cylinder_schema["properties/center"].set(vec3_schema()); + cylinder_schema["properties/axis"].set(vec3_schema()); + cylinder_schema["properties/radius"].set(number_schema()); + cylinder_schema["required"].append() = "center"; + cylinder_schema["required"].append() = "axis"; + cylinder_schema["required"].append() = "radius"; + param_schema["properties/cylinder"].set(cylinder_schema); + + // --- box --- + conduit::Node box_schema; + box_schema["type"] = "object"; + box_schema["additionalProperties"] = false; + box_schema["properties/min"].set(vec3_schema()); + box_schema["properties/max"].set(vec3_schema()); + box_schema["required"].append() = "min"; + box_schema["required"].append() = "max"; + param_schema["properties/box"].set(box_schema); + + // --- plane --- + conduit::Node plane_schema; + plane_schema["type"] = "object"; + plane_schema["additionalProperties"] = false; + plane_schema["properties/point"].set(vec3_schema()); + plane_schema["properties/normal"].set(vec3_schema()); + plane_schema["required"].append() = "point"; + plane_schema["required"].append() = "normal"; + param_schema["properties/plane"].set(plane_schema); + + // --- multi plane --- + conduit::Node multi_plane_schema; + multi_plane_schema["type"] = "object"; + multi_plane_schema["additionalProperties"] = false; + multi_plane_schema["properties/point1"].set(vec3_schema()); + multi_plane_schema["properties/point2"].set(vec3_schema()); + multi_plane_schema["properties/normal1"].set(vec3_schema()); + multi_plane_schema["properties/normal2"].set(vec3_schema()); + multi_plane_schema["required"].append() = "point1"; + multi_plane_schema["required"].append() = "point2"; + multi_plane_schema["required"].append() = "normal1"; + multi_plane_schema["required"].append() = "normal2"; + param_schema["properties/multi_plane"].set(multi_plane_schema); + + i["param_schema"].set(param_schema); } - //----------------------------------------------------------------------------- void VTKHThreshold::execute() @@ -2007,160 +1715,81 @@ VTKHClip::declare_interface(Node &i) i["type_name"] = "vtkh_clip"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHClip::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = true; - - bool type_present = false; - - if(params.has_child("sphere")) - { - type_present = true; - } - else if(params.has_child("cylinder")) - { - type_present = true; - } - else if(params.has_child("box")) - { - type_present = true; - } - else if(params.has_child("plane")) - { - type_present = true; - } - else if(params.has_child("multi_plane")) - { - type_present = true; - } - - if(!type_present) - { - info["errors"].append() = "Missing required parameter. Clip must specify a 'sphere', 'cylinder', 'box', 'plane', or 'mulit_plane'"; - res = false; - } - else - { - - res &= check_string("topology",params, info, false); - if(params.has_child("sphere")) - { - res = check_numeric("sphere/center/x",params, info, true, true) && res; - res = check_numeric("sphere/center/y",params, info, true, true) && res; - res = check_numeric("sphere/center/z",params, info, true, true) && res; - res = check_numeric("sphere/radius",params, info, true, true) && res; - } - else if(params.has_child("cylinder")) - { - res = check_numeric("cylinder/center/x",params, info, true, true) && res; - res = check_numeric("cylinder/center/y",params, info, true, true) && res; - res = check_numeric("cylinder/center/z",params, info, true, true) && res; - res = check_numeric("cylinder/axis/x",params, info, true, true) && res; - res = check_numeric("cylinder/axis/y",params, info, true, true) && res; - res = check_numeric("cylinder/axis/z",params, info, true, true) && res; - res = check_numeric("cylinder/radius",params, info, true, true) && res; - } - else if(params.has_child("box")) - { - res = check_numeric("box/min/x",params, info, true, true) && res; - res = check_numeric("box/min/y",params, info, true, true) && res; - res = check_numeric("box/min/z",params, info, true, true) && res; - res = check_numeric("box/max/x",params, info, true, true) && res; - res = check_numeric("box/max/y",params, info, true, true) && res; - res = check_numeric("box/max/z",params, info, true, true) && res; - } - else if(params.has_child("plane")) - { - res = check_numeric("plane/point/x",params, info, true, true) && res; - res = check_numeric("plane/point/y",params, info, true, true) && res; - res = check_numeric("plane/point/z",params, info, true, true) && res; - res = check_numeric("plane/normal/x",params, info, true, true) && res; - res = check_numeric("plane/normal/y",params, info, true, true) && res; - res = check_numeric("plane/normal/z",params, info, true, true) && res; - } - else if(params.has_child("multi_plane")) - { - res = check_numeric("multi_plane/point1/x",params, info, true, true) && res; - res = check_numeric("multi_plane/point1/y",params, info, true, true) && res; - res = check_numeric("multi_plane/point1/z",params, info, true, true) && res; - res = check_numeric("multi_plane/normal1/x",params, info, true, true) && res; - res = check_numeric("multi_plane/normal1/y",params, info, true, true) && res; - res = check_numeric("multi_plane/normal1/z",params, info, true, true) && res; - - res = check_numeric("multi_plane/point2/x",params, info, true, true) && res; - res = check_numeric("multi_plane/point2/y",params, info, true, true) && res; - res = check_numeric("multi_plane/point2/z",params, info, true, true) && res; - res = check_numeric("multi_plane/normal2/x",params, info, true, true) && res; - res = check_numeric("multi_plane/normal2/y",params, info, true, true) && res; - res = check_numeric("multi_plane/normal2/z",params, info, true, true) && res; - } - } - - res = check_string("invert",params, info, false) && res; - res = check_string("topology",params, info, false) && res; - - std::vector valid_paths; - valid_paths.push_back("topology"); - valid_paths.push_back("invert"); - valid_paths.push_back("sphere/center/x"); - valid_paths.push_back("sphere/center/y"); - valid_paths.push_back("sphere/center/z"); - valid_paths.push_back("sphere/radius"); - - valid_paths.push_back("cylinder/center/x"); - valid_paths.push_back("cylinder/center/y"); - valid_paths.push_back("cylinder/center/z"); - valid_paths.push_back("cylinder/axis/x"); - valid_paths.push_back("cylinder/axis/y"); - valid_paths.push_back("cylinder/axis/z"); - valid_paths.push_back("cylinder/radius"); - - valid_paths.push_back("box/min/x"); - valid_paths.push_back("box/min/y"); - valid_paths.push_back("box/min/z"); - valid_paths.push_back("box/max/x"); - valid_paths.push_back("box/max/y"); - valid_paths.push_back("box/max/z"); - - valid_paths.push_back("plane/point/x"); - valid_paths.push_back("plane/point/y"); - valid_paths.push_back("plane/point/z"); - valid_paths.push_back("plane/normal/x"); - valid_paths.push_back("plane/normal/y"); - valid_paths.push_back("plane/normal/z"); - - valid_paths.push_back("multi_plane/point1/x"); - valid_paths.push_back("multi_plane/point1/y"); - valid_paths.push_back("multi_plane/point1/z"); - valid_paths.push_back("multi_plane/normal1/x"); - valid_paths.push_back("multi_plane/normal1/y"); - valid_paths.push_back("multi_plane/normal1/z"); - - valid_paths.push_back("multi_plane/point2/x"); - valid_paths.push_back("multi_plane/point2/y"); - valid_paths.push_back("multi_plane/point2/z"); - valid_paths.push_back("multi_plane/normal2/x"); - valid_paths.push_back("multi_plane/normal2/y"); - valid_paths.push_back("multi_plane/normal2/z"); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + param_schema["constraints/exclusiveChildren"].append() = "sphere"; + param_schema["constraints/exclusiveChildren"].append() = "cylinder"; + param_schema["constraints/exclusiveChildren"].append() = "box"; + param_schema["constraints/exclusiveChildren"].append() = "plane"; + param_schema["constraints/exclusiveChildren"].append() = "multi_plane"; + param_schema["constraints/allowNoneInExclusiveGroup"] = false; + + // optional + param_schema["properties/topology"].set(string_schema()); + param_schema["properties/invert"].set(string_schema()); + + // --- sphere --- + conduit::Node sphere_schema; + sphere_schema["type"] = "object"; + sphere_schema["additionalProperties"] = false; + sphere_schema["properties/center"].set(vec3_schema()); + sphere_schema["properties/radius"].set(number_schema()); + sphere_schema["required"].append() = "center"; + sphere_schema["required"].append() = "radius"; + param_schema["properties/sphere"].set(sphere_schema); + + // --- cylinder --- + conduit::Node cylinder_schema; + cylinder_schema["type"] = "object"; + cylinder_schema["additionalProperties"] = false; + cylinder_schema["properties/center"].set(vec3_schema()); + cylinder_schema["properties/axis"].set(vec3_schema()); + cylinder_schema["properties/radius"].set(number_schema()); + cylinder_schema["required"].append() = "center"; + cylinder_schema["required"].append() = "axis"; + cylinder_schema["required"].append() = "radius"; + param_schema["properties/cylinder"].set(cylinder_schema); + + // --- box --- + conduit::Node box_schema; + box_schema["type"] = "object"; + box_schema["additionalProperties"] = false; + box_schema["properties/min"].set(vec3_schema()); + box_schema["properties/max"].set(vec3_schema()); + box_schema["required"].append() = "min"; + box_schema["required"].append() = "max"; + param_schema["properties/box"].set(box_schema); + + // --- plane --- + conduit::Node plane_schema; + plane_schema["type"] = "object"; + plane_schema["additionalProperties"] = false; + plane_schema["properties/point"].set(vec3_schema()); + plane_schema["properties/normal"].set(vec3_schema()); + plane_schema["required"].append() = "point"; + plane_schema["required"].append() = "normal"; + param_schema["properties/plane"].set(plane_schema); + + // --- multi plane --- + conduit::Node multi_plane_schema; + multi_plane_schema["type"] = "object"; + multi_plane_schema["additionalProperties"] = false; + multi_plane_schema["properties/point1"].set(vec3_schema()); + multi_plane_schema["properties/point2"].set(vec3_schema()); + multi_plane_schema["properties/normal1"].set(vec3_schema()); + multi_plane_schema["properties/normal2"].set(vec3_schema()); + multi_plane_schema["required"].append() = "point1"; + multi_plane_schema["required"].append() = "point2"; + multi_plane_schema["required"].append() = "normal1"; + multi_plane_schema["required"].append() = "normal2"; + param_schema["properties/multi_plane"].set(multi_plane_schema); + + i["param_schema"].set(param_schema); } - //----------------------------------------------------------------------------- void VTKHClip::execute() @@ -2313,34 +1942,22 @@ VTKHClipWithField::declare_interface(Node &i) i["type_name"] = "vtkh_clip_with_field"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHClipWithField::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_numeric("clip_value",params, info, true, true); - res = check_string("field",params, info, true) && res; - res = check_string("invert",params, info, false) && res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::vector valid_paths; - valid_paths.push_back("clip_value"); - valid_paths.push_back("invert"); - valid_paths.push_back("field"); - std::string surprises = surprise_check(valid_paths, params); + param_schema["properties/clip_value"].set(number_schema()); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/invert"].set(string_schema()); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + param_schema["required"].append() = "clip_value"; + param_schema["required"].append() = "field"; - return res; + i["param_schema"].set(param_schema); } - //----------------------------------------------------------------------------- void VTKHClipWithField::execute() @@ -2425,35 +2042,23 @@ VTKHIsoVolume::declare_interface(Node &i) i["type_name"] = "vtkh_iso_volume"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHIsoVolume::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_numeric("min_value",params, info, true, true); - res = check_numeric("max_value",params, info, true, true) && res; - res = check_string("field",params, info, true) && res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::vector valid_paths; - valid_paths.push_back("min_value"); - valid_paths.push_back("max_value"); - valid_paths.push_back("field"); - std::string surprises = surprise_check(valid_paths, params); + param_schema["properties/min_value"].set(number_schema()); + param_schema["properties/max_value"].set(number_schema()); + param_schema["properties/field"].set(string_schema()); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "min_value"; + param_schema["required"].append() = "max_value"; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } - //----------------------------------------------------------------------------- void VTKHIsoVolume::execute() @@ -2531,44 +2136,31 @@ VTKHLagrangian::declare_interface(Node &i) i["type_name"] = "vtkh_lagrangian"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHLagrangian::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - res &= check_numeric("step_size", params, info, true); - res &= check_numeric("write_frequency", params, info, true); - res &= check_numeric("cust_res", params, info, true); - res &= check_numeric("x_res", params, info, true); - res &= check_numeric("y_res", params, info, true); - res &= check_numeric("z_res", params, info, true); - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("step_size"); - valid_paths.push_back("write_frequency"); - valid_paths.push_back("cust_res"); - valid_paths.push_back("x_res"); - valid_paths.push_back("y_res"); - valid_paths.push_back("z_res"); - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + + param_schema["properties/field"].set(string_schema()); + param_schema["properties/step_size"].set(number_schema()); + param_schema["properties/write_frequency"].set(number_schema()); + param_schema["properties/cust_res"].set(number_schema()); + param_schema["properties/x_res"].set(number_schema()); + param_schema["properties/y_res"].set(number_schema()); + param_schema["properties/z_res"].set(number_schema()); + + param_schema["required"].append() = "field"; + param_schema["required"].append() = "step_size"; + param_schema["required"].append() = "write_frequency"; + param_schema["required"].append() = "cust_res"; + param_schema["required"].append() = "x_res"; + param_schema["required"].append() = "y_res"; + param_schema["required"].append() = "z_res"; + + i["param_schema"].set(param_schema); } - //----------------------------------------------------------------------------- void VTKHLagrangian::execute() @@ -2653,33 +2245,19 @@ VTKHLog::declare_interface(Node &i) i["type_name"] = "vtkh_log"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHLog::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - res &= check_string("output_name",params, info, false); - res &= check_numeric("clamp_min_value",params, info, false, true); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - valid_paths.push_back("clamp_min_value"); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/clamp_min_value"].set(number_schema()); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -2763,33 +2341,19 @@ VTKHLog10::declare_interface(Node &i) i["type_name"] = "vtkh_log10"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHLog10::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - res &= check_string("output_name",params, info, false); - res &= check_numeric("clamp_min_value",params, info, false, true); - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - valid_paths.push_back("clamp_min_value"); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::string surprises = surprise_check(valid_paths, params); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/clamp_min_value"].set(number_schema()); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -2873,33 +2437,19 @@ VTKHLog2::declare_interface(Node &i) i["type_name"] = "vtkh_log2"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHLog2::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - res &= check_string("output_name",params, info, false); - res &= check_numeric("clamp_min_value",params, info, false, true); - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - valid_paths.push_back("clamp_min_value"); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::string surprises = surprise_check(valid_paths, params); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/clamp_min_value"].set(number_schema()); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -2983,31 +2533,19 @@ VTKHRecenter::declare_interface(Node &i) i["type_name"] = "vtkh_recenter"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHRecenter::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - res &= check_string("association",params, info, true); - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("association"); - std::string surprises = surprise_check(valid_paths, params); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + param_schema["properties/field"].set(string_schema()); + param_schema["properties/association"].set(string_schema()); - return res; + param_schema["required"].append() = "field"; + param_schema["required"].append() = "association"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -3097,33 +2635,19 @@ VTKHHistSampling::declare_interface(Node &i) i["type_name"] = "vtkh_hist_sampling"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHHistSampling::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - res &= check_numeric("bins",params, info, false, true); - res &= check_numeric("sample_rate",params, info, false, true); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("bins"); - valid_paths.push_back("sample_rate"); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/bins"].set(number_schema()); + param_schema["properties/sample_rate"].set(number_schema()); - std::string surprises = surprise_check(valid_paths, params); + param_schema["required"].append() = "field"; - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -3250,32 +2774,19 @@ VTKHQCriterion::declare_interface(Node &i) i["type_name"] = "vtkh_qcriterion"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHQCriterion::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - res &= check_string("output_name",params, info, false); - res &= check_string("use_cell_gradient",params, info, false); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - valid_paths.push_back("use_cell_gradient"); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/use_cell_gradient"].set(string_schema()); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -3372,32 +2883,19 @@ VTKHDivergence::declare_interface(Node &i) i["type_name"] = "vtkh_divergence"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHDivergence::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - res &= check_string("output_name",params, info, false); - res &= check_string("use_cell_gradient",params, info, false); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - valid_paths.push_back("use_cell_gradient"); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/use_cell_gradient"].set(string_schema()); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -3493,32 +2991,19 @@ VTKHVorticity::declare_interface(Node &i) i["type_name"] = "vtkh_curl"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHVorticity::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - res &= check_string("output_name",params, info, false); - res &= check_string("use_cell_gradient",params, info, false); - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - valid_paths.push_back("use_cell_gradient"); - std::string surprises = surprise_check(valid_paths, params); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/use_cell_gradient"].set(string_schema()); - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -3614,33 +3099,19 @@ VTKHGradient::declare_interface(Node &i) i["type_name"] = "vtkh_gradient"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHGradient::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("field",params, info, true); - res &= check_string("output_name",params, info, false); - res &= check_string("use_cell_gradient",params, info, false); - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("output_name"); - valid_paths.push_back("use_cell_gradient"); - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - return res; + param_schema["properties/field"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/use_cell_gradient"].set(string_schema()); + + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -3728,69 +3199,23 @@ VTKHUniformGrid::declare_interface(Node &i) i["type_name"] = "vtkh_uniform_grid"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHUniformGrid::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = true; - res &= check_string("field",params, info, false); - res &= check_numeric("dims/i",params, info, false); - res &= check_numeric("dims/j",params, info, false); - res &= check_numeric("dims/k",params, info, false); - res &= check_numeric("origin/x",params, info, false); - res &= check_numeric("origin/y",params, info, false); - res &= check_numeric("origin/z",params, info, false); - res &= check_numeric("spacing/dx",params, info, false); - res &= check_numeric("spacing/dy",params, info, false); - res &= check_numeric("spacing/dz",params, info, false); - res &= check_numeric("invalid_value",params, info, false); - - if(!params.has_child("field") && !params.has_child("fields")) - { - res = false; - info["errors"].append() = "Uniform Grid Sampling requires 'field' or 'fields'"; - } - - if(params.has_child("fields") && !params["fields"].dtype().is_list()) - { - res = false; - info["errors"].append() = "'fields' is not a list"; - } - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("fields"); - valid_paths.push_back("dims/i"); - valid_paths.push_back("dims/j"); - valid_paths.push_back("dims/k"); - valid_paths.push_back("origin/x"); - valid_paths.push_back("origin/y"); - valid_paths.push_back("origin/z"); - valid_paths.push_back("spacing/dx"); - valid_paths.push_back("spacing/dy"); - valid_paths.push_back("spacing/dz"); - valid_paths.push_back("invalid_value"); - - std::string surprises = ""; - - std::vector ignore_paths; - ignore_paths.push_back("fields"); - if(params.number_of_children() != 0) - std::string surprises = surprise_check(valid_paths, ignore_paths, params); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + param_schema["properties/field"].set(string_schema()); + param_schema["properties/fields"].set(array_schema(ignore_schema())); + param_schema["properties/dims"].set(vec3_schema_anyOf("i", "j", "k")); + param_schema["properties/origin"].set(vec3_schema_anyOf()); + param_schema["properties/spacing"].set(vec3_schema_anyOf("dx", "dy", "dz")); + param_schema["properties/invalid_value"].set(number_schema()); - return res; + param_schema["anyOf"].append() = "field"; + param_schema["anyOf"].append() = "fields"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -3959,104 +3384,41 @@ VTKHSample::declare_interface(Node &i) i["type_name"] = "vtkh_sample"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHSample::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = true; - res &= check_string("field",params, info, false); - res &= check_numeric("invalid_value",params, info, false); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + + param_schema["properties/field"].set(string_schema()); + param_schema["properties/fields"].set(array_schema(ignore_schema())); + param_schema["properties/invalid_value"].set(number_schema()); + + // --- Line --- + conduit::Node line_schema; + line_schema["type"] = "object"; + line_schema["additionalProperties"] = false; + line_schema["properties/num_samples"].set(number_schema()); + line_schema["properties/start"].set(vec3_schema_anyOf()); + line_schema["properties/end"].set(vec3_schema_anyOf()); + param_schema["properties/line"].set(line_schema); + + // --- Points --- + param_schema["properties/points"].set(vec3_schema_anyOf()); + + // --- Box --- + conduit::Node box_schema; + box_schema["type"] = "object"; + box_schema["additionalProperties"] = false; + box_schema["properties/dims"].set(vec3_schema_anyOf()); + box_schema["properties/min"].set(vec3_schema_anyOf()); + box_schema["properties/max"].set(vec3_schema_anyOf()); + param_schema["properties/box"].set(box_schema); + + param_schema["anyOf"].append() = "field"; + param_schema["anyOf"].append() = "fields"; - res &= check_numeric("line/num_samples",params, info, false); - res &= check_numeric("line/start/x",params, info, false); - res &= check_numeric("line/start/y",params, info, false); - res &= check_numeric("line/start/z",params, info, false); - res &= check_numeric("line/end/x",params, info, false); - res &= check_numeric("line/end/y",params, info, false); - res &= check_numeric("line/end/z",params, info, false); - - res &= check_numeric("points/x",params, info, false); - res &= check_numeric("points/y",params, info, false); - res &= check_numeric("points/z",params, info, false); - - res &= check_numeric("box/dims/x",params, info, false); - res &= check_numeric("box/dims/y",params, info, false); - res &= check_numeric("box/dims/z",params, info, false); - res &= (check_numeric("box/min/x",params, info, false) - || check_string("box/min/x",params, info, false)); - res &= (check_numeric("box/min/y",params, info, false) - || check_string("box/min/y",params, info, false)); - res &= (check_numeric("box/min/z",params, info, false) - || check_string("box/min/z",params, info, false)); - res &= (check_numeric("box/max/x",params, info, false) - || check_string("box/max/x",params, info, false)); - res &= (check_numeric("box/max/y",params, info, false) - || check_string("box/max/y",params, info, false)); - res &= (check_numeric("box/max/z",params, info, false) - || check_string("box/max/z",params, info, false)); - - - if(!params.has_child("field") && !params.has_child("fields")) - { - res = false; - info["errors"].append() = "Sampling requires 'field' or 'fields'"; - } - - if(params.has_child("fields") && !params["fields"].dtype().is_list()) - { - res = false; - info["errors"].append() = "'fields' is not a list"; - } - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("fields"); - valid_paths.push_back("invalid_value"); - - valid_paths.push_back("line/num_samples"); - valid_paths.push_back("line/start/x"); - valid_paths.push_back("line/start/y"); - valid_paths.push_back("line/start/z"); - valid_paths.push_back("line/end/x"); - valid_paths.push_back("line/end/y"); - valid_paths.push_back("line/end/z"); - - valid_paths.push_back("points/x"); - valid_paths.push_back("points/y"); - valid_paths.push_back("points/z"); - - valid_paths.push_back("box/dims/i"); - valid_paths.push_back("box/dims/j"); - valid_paths.push_back("box/dims/k"); - valid_paths.push_back("box/min/x"); - valid_paths.push_back("box/min/y"); - valid_paths.push_back("box/min/z"); - valid_paths.push_back("box/max/x"); - valid_paths.push_back("box/max/y"); - valid_paths.push_back("box/max/z"); - - std::string surprises = ""; - - std::vector ignore_paths; - ignore_paths.push_back("fields"); - - if(params.number_of_children() != 0) - { - surprises = surprise_check(valid_paths, ignore_paths, params); - } - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -4369,29 +3731,16 @@ VTKHStats::declare_interface(Node &i) i["type_name"] = "vtkh_stats"; i["port_names"].append() = "in"; i["output_port"] = "false"; -} - -//----------------------------------------------------------------------------- -bool -VTKHStats::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - - std::vector valid_paths; - valid_paths.push_back("field"); - - std::string surprises = surprise_check(valid_paths, params); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - return res; + param_schema["properties/field"].set(string_schema()); + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -4463,31 +3812,18 @@ VTKHHistogram::declare_interface(Node &i) i["type_name"] = "vtkh_histogram"; i["port_names"].append() = "in"; i["output_port"] = "false"; -} -//----------------------------------------------------------------------------- -bool -VTKHHistogram::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - res &= check_numeric("bins",params, info, false, true); - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("bins"); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::string surprises = surprise_check(valid_paths, params); + param_schema["properties/field"].set(string_schema()); + param_schema["properties/bins"].set(number_schema()); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -4563,49 +3899,22 @@ VTKHProject2d::declare_interface(Node &i) i["type_name"] = "vtkh_project_2d"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHProject2d::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("topology",params, info, false); - res &= check_numeric("image_width",params, info, false); - res &= check_numeric("image_height",params, info, false); - - if(params.has_child("fields") && !params["fields"].dtype().is_list()) - { - res = false; - info["errors"].append() = "fields is not a list"; - } - - std::vector valid_paths; - std::vector ignore_paths; - valid_paths.push_back("topology"); - valid_paths.push_back("image_width"); - valid_paths.push_back("image_height"); - valid_paths.push_back("dataset_bounds"); - valid_paths.push_back("camera"); - valid_paths.push_back("fields"); - ignore_paths.push_back("camera"); - ignore_paths.push_back("fields"); - ignore_paths.push_back("dataset_bounds"); - - std::string surprises = surprise_check(valid_paths, ignore_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + + param_schema["properties/topology"].set(string_schema()); + param_schema["properties/image_width"].set(number_schema()); + param_schema["properties/image_height"].set(number_schema()); + param_schema["properties/dataset_bounds"].set(ignore_schema()); + param_schema["properties/camera"].set(ignore_schema()); + param_schema["properties/fields"].set(array_schema(ignore_schema())); + + i["param_schema"].set(param_schema); } - //----------------------------------------------------------------------------- void VTKHProject2d::execute() @@ -4745,29 +4054,16 @@ VTKHNoOp::declare_interface(Node &i) i["type_name"] = "vtkh_no_op"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHNoOp::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - - std::vector valid_paths; - valid_paths.push_back("field"); - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - return res; + param_schema["properties/field"].set(string_schema()); + param_schema["required"].append() = "field"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -4843,33 +4139,21 @@ VTKHVectorComponent::declare_interface(Node &i) i["type_name"] = "vtkh_vector_component"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHVectorComponent::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field",params, info, true); - res &= check_numeric("component",params, info, true); - res &= check_string("output_name",params, info, true); - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("component"); - valid_paths.push_back("output_name"); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + param_schema["properties/field"].set(string_schema()); + param_schema["properties/component"].set(number_schema()); + param_schema["properties/output_name"].set(string_schema()); - return res; + param_schema["required"].append() = "field"; + param_schema["required"].append() = "component"; + param_schema["required"].append() = "output_name"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -4949,35 +4233,22 @@ VTKHCompositeVector::declare_interface(Node &i) i["type_name"] = "vtkh_composite_vector"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHCompositeVector::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("field1",params, info, true); - res &= check_string("field2",params, info, true); - res &= check_string("field3",params, info, false); - res &= check_string("output_name",params, info, true); - - std::vector valid_paths; - valid_paths.push_back("field1"); - valid_paths.push_back("field2"); - valid_paths.push_back("field3"); - valid_paths.push_back("output_name"); - std::string surprises = surprise_check(valid_paths, params); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + param_schema["properties/field1"].set(string_schema()); + param_schema["properties/field2"].set(string_schema()); + param_schema["properties/field3"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); - return res; + param_schema["required"].append() = "field1"; + param_schema["required"].append() = "field2"; + param_schema["required"].append() = "output_name"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -5087,33 +4358,9 @@ VTKHScale::declare_interface(Node &i) i["type_name"] = "vtkh_scale_transform"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHScale::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_numeric("x_scale",params, info, true, true); - res &= check_numeric("y_scale",params, info, true, true); - res &= check_numeric("z_scale",params, info, true, true); - std::vector valid_paths; - valid_paths.push_back("x_scale"); - valid_paths.push_back("y_scale"); - valid_paths.push_back("z_scale"); - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema = vec3_schema("x_scale", "y_scale", "z_scale"); } //----------------------------------------------------------------------------- @@ -5187,168 +4434,39 @@ VTKHTransform::declare_interface(Node &i) i["type_name"] = "vtkh_transform"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHTransform::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - -/* - scale/x,y,z - translate/x,y,z - rotate/x,y,z - reflect/x,y,z - transform_matrix: float64 x 16 -*/ - bool res = true; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + param_schema["constraints/exclusiveChildren"].append() = "scale"; + param_schema["constraints/exclusiveChildren"].append() = "translate"; + param_schema["constraints/exclusiveChildren"].append() = "reflect"; + param_schema["constraints/exclusiveChildren"].append() = "rotate"; + param_schema["constraints/exclusiveChildren"].append() = "matrix"; + param_schema["constraints/allowNoneInExclusiveGroup"] = false; + + param_schema["properties/scale"].set(vec3_schema_anyOf()); + param_schema["properties/translate"].set(vec3_schema_anyOf()); + param_schema["properties/reflect"].set(vec3_schema_anyOf()); + + // --- rotate --- + conduit::Node rotate_schema; + rotate_schema["type"] = "object"; + rotate_schema["additionalProperties"] = false; + rotate_schema["properties/angle"].set(number_schema()); + rotate_schema["properties/axis"].set(vec3_schema_anyOf()); + rotate_schema["required"].append() = "angle"; + rotate_schema["required"].append() = "axis"; + param_schema["properties/rotate"].set(rotate_schema); + + // --- matrix --- + conduit::Node matrix_schema = array_schema(number_schema()); + matrix_schema["minItems"] = 16; + matrix_schema["miaxItems"] = 16; + param_schema["properties/matrix"].set(matrix_schema); - std::vector modes = {"scale", - "translate", - "rotate", - "reflect", - "matrix"}; - - index_t mode_count = 0; - for( auto mode : modes) - { - if(params.has_child(mode)) - { - mode_count++; - } - } - - if(mode_count > 1) - { - info["errors"].append() = "transform only supports one of: scale, translate, rotate, reflect, or matrix"; - res = false; - } - - if(mode_count == 0) - { - info["errors"].append() = "transform requires parameters for: scale, translate, rotate, reflect, or matrix"; - res = false; - } - - if(params.has_child("scale")) - { - const Node &p_vals = params["scale"]; - if( ! p_vals.has_child("x") && - ! p_vals.has_child("y") && - ! p_vals.has_child("z") ) - { - res = false; - info["errors"].append()="scale transform requires: scale/x, scale/y, and/or scale/z"; - } - res &= check_numeric("x", p_vals, info, false, true); - res &= check_numeric("y", p_vals, info, false, true); - res &= check_numeric("z", p_vals, info, false, true); - } - - if(params.has_child("translate")) - { - const Node &p_vals = params["translate"]; - if( ! p_vals.has_child("x") && - ! p_vals.has_child("y") && - ! p_vals.has_child("z") ) - { - res = false; - info["errors"].append() = "translate transform requires: translate/x, translate/y, and/or translate/z"; - } - res &= check_numeric("x", p_vals, info, false, true); - res &= check_numeric("y", p_vals, info, false, true); - res &= check_numeric("z", p_vals, info, false, true); - } - - if(params.has_child("rotate")) - { - const Node &p_vals = params["rotate"]; - bool rotate_ok = check_numeric("angle", p_vals, info, true, true); - - if(p_vals.has_child("axis")) - { - const Node &p_axis = p_vals["axis"]; - if( ! p_axis.has_child("x") && - ! p_axis.has_child("y") && - ! p_axis.has_child("z") ) - { - rotate_ok = false; - } - - res &= check_numeric("x", p_axis, info, false, true); - res &= check_numeric("y", p_axis, info, false, true); - res &= check_numeric("z", p_axis, info, false, true); - - } - else - { - rotate_ok = false; - } - - if(!rotate_ok) - { - res = false; - info["errors"].append()="rotate transform requires: rotate/angle and rotate/axis/x, rotate/axis/y, and/or rotate/axis/z"; - } - } - - if(params.has_child("reflect")) - { - const Node &p_vals = params["reflect"]; - if( ! p_vals.has_child("x") && - ! p_vals.has_child("y") && - ! p_vals.has_child("z") ) - { - res = false; - info["errors"].append() = "reflect transform requires: reflect/x, reflect/y, and/or reflect/z"; - } - res &= check_numeric("x", p_vals, info, false, true); - res &= check_numeric("y", p_vals, info, false, true); - res &= check_numeric("z", p_vals, info, false, true); - } - - if(params.has_child("matrix")) - { - res &= check_numeric("matrix",params, info, true, true); - if(res) - { - // make sure it is 16 long - index_t matrix_len = params["matrix"].dtype().number_of_elements(); - if(matrix_len != 16) - { - res = false; - info["errors"].append()="matrix must an array with 16 entries (representing a 4x4 transform matrix)"; - } - } - } - - std::vector valid_paths = { "scale/x", - "scale/y", - "scale/z", - "translate/x", - "translate/y", - "translate/z", - "rotate/angle", - "rotate/axis/x", - "rotate/axis/y", - "rotate/axis/z", - "reflect/x", - "reflect/y", - "reflect/z", - "matrix"}; - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -5563,126 +4681,121 @@ VTKHParticleAdvection::declare_interface(Node &i) i["type_name"] = "vtkh_particle_advection"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHParticleAdvection::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - bool res = check_string("field", params, info, true); - res &= check_numeric("num_steps", params, info, true, true); - res &= check_numeric("step_size", params, info, true, true); - info.reset(); - - if(!params.has_child("seeds")) - { - info["errors"].append() = "Missing required parameter. Particle Advection must specify seeds"; - res = false; - } - else - { - conduit::Node seed_params = params["seeds"]; - if(!seed_params.has_child("type")) - { - info["errors"].append() = "Missing required parameter. Particle Advection must specify seed type"; - res = false; - } - else - { - - res &= check_string("type", seed_params, info, true); - std::string type = seed_params["type"].as_string(); - if(type == "point") - { - res &= check_numeric("location",seed_params,info,true); - } - else if(type == "point_list") - { - res &= check_numeric("location",seed_params,info,true); - } - else if(type == "line") - { - res &= check_numeric("start",seed_params,info,true); - res &= check_numeric("end",seed_params,info,true); - res &= check_numeric("num_seeds",seed_params,info,true); - res &= check_string("sampling_type", seed_params, info, true); - } - else if(type == "box") - { - res &= check_string("sampling_space", seed_params, info, true); - res &= check_string("sampling_type", seed_params, info, true); - string sampling_type = seed_params["sampling_type"].as_string(); - if(sampling_type == "uniform") - { - res &= check_numeric("num_seeds_x",seed_params,info,true); - res &= check_numeric("num_seeds_y",seed_params,info,true); - res &= check_numeric("num_seeds_z",seed_params,info,true); - } - else - { - res &= check_numeric("num_seeds",seed_params,info,true); - } - - if(seed_params.has_child("extents_x")) - { - res &= check_numeric("extents_x",seed_params,info,true); - res &= check_numeric("extents_y",seed_params,info,true); - res &= check_numeric("extents_z",seed_params,info,true); - } - } - else - { - info["errors"].append() = "Unrecognized parameter. Particle Advection supports seed types 'point', 'point_list', 'line', or 'box'."; - res = false; - } - } - } - - if(params.has_child("rendering")) - { - res &= check_string("rendering/enable_tubes", params, info, false); - res &= check_string("rendering/tube_capping", params, info, false); - res &= check_numeric("rendering/tube_size", params, info, false); - res &= check_numeric("rendering/tube_sides", params, info, false); - res &= check_numeric("rendering/tube_value", params, info, false); - res &= check_string("rendering/output_field", params, info, false); - } - - std::vector valid_paths; - valid_paths.push_back("field"); - valid_paths.push_back("num_steps"); - valid_paths.push_back("step_size"); - valid_paths.push_back("seeds/type"); - valid_paths.push_back("seeds/location"); - valid_paths.push_back("seeds/start"); - valid_paths.push_back("seeds/end"); - valid_paths.push_back("seeds/num_seeds"); - valid_paths.push_back("seeds/num_seeds_x"); - valid_paths.push_back("seeds/num_seeds_y"); - valid_paths.push_back("seeds/num_seeds_z"); - valid_paths.push_back("seeds/extents_x"); - valid_paths.push_back("seeds/extents_y"); - valid_paths.push_back("seeds/extents_z"); - valid_paths.push_back("seeds/sampling_type"); - valid_paths.push_back("seeds/sampling_space"); - - valid_paths.push_back("rendering/enable_tubes"); - valid_paths.push_back("rendering/tube_capping"); - valid_paths.push_back("rendering/tube_size"); - valid_paths.push_back("rendering/tube_sides"); - valid_paths.push_back("rendering/tube_value"); - valid_paths.push_back("rendering/output_field"); - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + + param_schema["properties/field"].set(string_schema()); + param_schema["properties/num_steps"].set(number_schema()); + param_schema["properties/step_size"].set(number_schema()); + + // --- seed --- + conduit::Node seed_schema; + seed_schema["type"] = "object"; + seed_schema["additionalProperties"] = false; + seed_schema["properties/type"].set(string_schema()); + seed_schema["properties/location"].set(number_schema()); + seed_schema["properties/start"].set(number_schema()); + seed_schema["properties/end"].set(number_schema()); + seed_schema["properties/num_seeds"].set(number_schema()); + seed_schema["properties/num_seeds_x"].set(number_schema()); + seed_schema["properties/num_seeds_y"].set(number_schema()); + seed_schema["properties/num_seeds_z"].set(number_schema()); + seed_schema["properties/extents_x"].set(number_schema()); + seed_schema["properties/extents_y"].set(number_schema()); + seed_schema["properties/extents_z"].set(number_schema()); + seed_schema["properties/sampling_type"].set(string_schema()); + seed_schema["properties/sampling_space"].set(string_schema()); + seed_schema["required"].append() = "type"; + + seed_schema["constraints/dependencies/extents_x"].append() = "extents_y"; + seed_schema["constraints/dependencies/extents_x"].append() = "extents_z"; + seed_schema["constraints/dependencies/extents_y"].append() = "extents_x"; + seed_schema["constraints/dependencies/extents_y"].append() = "extents_z"; + seed_schema["constraints/dependencies/extents_z"].append() = "extents_x"; + seed_schema["constraints/dependencies/extents_z"].append() = "extents_y"; + + // type == point + conduit::Node point_option; + point_option["type"] = "object"; + point_option["properties/type/type"] = "string"; + point_option["properties/type/constraints/const"] = "point"; + point_option["required"].append() = "type"; + point_option["required"].append() = "location"; + seed_schema["oneOf"].append().set(point_option); + + // type == point_list + conduit::Node point_list_option; + point_list_option["type"] = "object"; + point_list_option["properties/type/type"] = "string"; + point_list_option["properties/type/constraints/const"] = "point_list"; + point_list_option["required"].append() = "type"; + point_list_option["required"].append() = "location"; + seed_schema["oneOf"].append().set(point_list_option); + + // type == line + conduit::Node line_option; + line_option["type"] = "object"; + line_option["properties/type/type"] = "string"; + line_option["properties/type/constraints/const"] = "line"; + line_option["required"].append() = "type"; + line_option["required"].append() = "start"; + line_option["required"].append() = "end"; + line_option["required"].append() = "num_seeds"; + line_option["required"].append() = "sampling_type"; + seed_schema["oneOf"].append().set(line_option); + + // type == box + conduit::Node box_option; + box_option["type"] = "object"; + box_option["properties/type/type"] = "string"; + box_option["properties/type/constraints/const"] = "box"; + box_option["required"].append() = "type"; + box_option["required"].append() = "sampling_space"; + box_option["required"].append() = "sampling_type"; + { + conduit::Node box_option_uniform; + box_option_uniform["type"] = "object"; + box_option_uniform["properties/sampling_type/type"] = "string"; + box_option_uniform["properties/sampling_type/constraints/const"] = "uniform"; + box_option_uniform["required"].append() = "sampling_type"; + box_option_uniform["required"].append() = "num_seeds_x"; + box_option_uniform["required"].append() = "num_seeds_y"; + box_option_uniform["required"].append() = "num_seeds_z"; + box_option["oneOf"].append().set(box_option_uniform); + } + { + conduit::Node box_option_non_uniform; + box_option_non_uniform["type"] = "object"; + box_option_non_uniform["required"].append() = "sampling_type"; + box_option_non_uniform["required"].append() = "num_seeds"; + box_option_non_uniform["constraints/not_const/sampling_type"] = "uniform"; + box_option["oneOf"].append().set(box_option_non_uniform); + } + seed_schema["oneOf"].append().set(box_option); + + param_schema["properties/seed"].set(seed_schema); + + // --- rendering --- + conduit::Node rendering_schema; + rendering_schema["type"] = "object"; + rendering_schema["additionalProperties"] = false; + rendering_schema["properties/enable_tubes"].set(string_schema()); + rendering_schema["properties/tube_capping"].set(string_schema()); + rendering_schema["properties/tube_size"].set(number_schema()); + rendering_schema["properties/tube_sides"].set(number_schema()); + rendering_schema["properties/tube_value"].set(number_schema()); + rendering_schema["properties/output_field"].set(string_schema()); + param_schema["properties/rendering"].set(rendering_schema); + + param_schema["required"].append() = "field"; + param_schema["required"].append() = "num_steps"; + param_schema["required"].append() = "step_size"; + param_schema["required"].append() = "seed"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -6216,55 +5329,35 @@ VTKHWarpXStreamline::declare_interface(Node &i) i["type_name"] = "vtkh_warpx_streamline"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} - -//----------------------------------------------------------------------------- -bool -VTKHWarpXStreamline::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - bool res = check_string("b_field", params, info, false); - res &= check_string("e_field", params, info, false); - res &= check_numeric("num_steps", params, info, true, true); - res &= check_numeric("step_size", params, info, true, true); - if(params.has_child("rendering")) - { - res &= check_string("rendering/enable_tubes", params, info, false); - res &= check_string("rendering/tube_capping", params, info, false); - res &= check_numeric("rendering/tube_size", params, info, false); - res &= check_numeric("rendering/tube_sides", params, info, false); - res &= check_numeric("rendering/tube_value", params, info, false); - res &= check_string("rendering/output_field", params, info, false); - } - - std::vector valid_paths; - valid_paths.push_back("b_field"); - valid_paths.push_back("e_field"); - valid_paths.push_back("charge_field"); - valid_paths.push_back("mass_field"); - valid_paths.push_back("momentum_field"); - valid_paths.push_back("weighting_field"); - valid_paths.push_back("num_steps"); - valid_paths.push_back("step_size"); - valid_paths.push_back("rendering/enable_tubes"); - valid_paths.push_back("rendering/tube_capping"); - valid_paths.push_back("rendering/tube_size"); - valid_paths.push_back("rendering/tube_sides"); - valid_paths.push_back("rendering/tube_value"); - valid_paths.push_back("rendering/output_field"); - - std::string surprises = surprise_check(valid_paths, params); - - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; + + param_schema["properties/b_field"].set(string_schema()); + param_schema["properties/e_field"].set(string_schema()); + param_schema["properties/num_steps"].set(number_schema()); + param_schema["properties/step_size"].set(number_schema()); + + // --- rendering --- + conduit::Node rendering_schema; + rendering_schema["type"] = "object"; + rendering_schema["additionalProperties"] = false; + rendering_schema["properties/enable_tubes"].set(string_schema()); + rendering_schema["properties/tube_capping"].set(string_schema()); + rendering_schema["properties/tube_size"].set(number_schema()); + rendering_schema["properties/tube_sides"].set(number_schema()); + rendering_schema["properties/tube_value"].set(number_schema()); + rendering_schema["properties/output_field"].set(string_schema()); + param_schema["properties/rendering"].set(rendering_schema); + + param_schema["required"].append() = "num_steps"; + param_schema["required"].append() = "step_size"; + + i["param_schema"].set(param_schema); } + //----------------------------------------------------------------------------- void VTKHWarpXStreamline::execute() @@ -6426,38 +5519,18 @@ VTKHVTKFileExtract::declare_interface(Node &i) i["type_name"] = "vtkh_vtk_file_extract"; i["port_names"].append() = "in"; i["output_port"] = "false"; -} - -//----------------------------------------------------------------------------- -bool -VTKHVTKFileExtract::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = true; - - if( !params.has_child("path") ) - { - info["errors"].append() = "missing required entry 'path'"; - res = false; - } - - res = check_string("topology",params, info, false) && res; - - std::vector valid_paths; - valid_paths.push_back("path"); - valid_paths.push_back("topology"); - std::string surprises = surprise_check(valid_paths, params); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } + param_schema["properties/path"].set(string_schema()); + param_schema["properties/topology"].set(string_schema()); - return res; + param_schema["required"].append() = "path"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- @@ -6638,39 +5711,22 @@ VTKHMIR::declare_interface(Node &i) i["type_name"] = "vtkh_mir"; i["port_names"].append() = "in"; i["output_port"] = "true"; -} -//----------------------------------------------------------------------------- -bool -VTKHMIR::verify_params(const conduit::Node ¶ms, - conduit::Node &info) -{ - info.reset(); - - bool res = check_string("matset",params, info, true); - res &= check_string("output_name", params, info, false); - res &= check_numeric("error_scaling", params, info, false); - res &= check_numeric("scaling_decay", params, info, false); - res &= check_numeric("iterations", params, info, false); - res &= check_numeric("max_error", params, info, false); - - std::vector valid_paths; - valid_paths.push_back("matset"); - valid_paths.push_back("output_name"); - valid_paths.push_back("error_scaling"); - valid_paths.push_back("scaling_decay"); - valid_paths.push_back("iterations"); - valid_paths.push_back("max_error"); + // ----------- Define Param Schema ----------- + conduit::Node param_schema; + param_schema["type"] = "object"; + param_schema["additionalProperties"] = false; - std::string surprises = surprise_check(valid_paths, params); + param_schema["properties/matset"].set(string_schema()); + param_schema["properties/output_name"].set(string_schema()); + param_schema["properties/error_scaling"].set(number_schema()); + param_schema["properties/scaling_decay"].set(number_schema()); + param_schema["properties/iterations"].set(number_schema()); + param_schema["properties/max_error"].set(number_schema()); - if(surprises != "") - { - res = false; - info["errors"].append() = surprises; - } - - return res; + param_schema["required"].append() = "matset"; + + i["param_schema"].set(param_schema); } //----------------------------------------------------------------------------- diff --git a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.hpp b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.hpp index b52f95815..96b3484ac 100644 --- a/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.hpp +++ b/src/libs/ascent/runtimes/flow_filters/ascent_runtime_vtkh_filters.hpp @@ -51,8 +51,6 @@ class ASCENT_API VTKHMarchingCubes : public ::flow::Filter virtual ~VTKHMarchingCubes(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -64,8 +62,6 @@ class ASCENT_API VTKHExternalSurfaces : public ::flow::Filter virtual ~VTKHExternalSurfaces(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -77,8 +73,6 @@ class ASCENT_API VTKHVectorMagnitude : public ::flow::Filter virtual ~VTKHVectorMagnitude(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -90,8 +84,6 @@ class ASCENT_API VTKHSlice : public ::flow::Filter virtual ~VTKHSlice(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -103,8 +95,6 @@ class ASCENT_API VTKHAutoSliceLevels : public ::flow::Filter virtual ~VTKHAutoSliceLevels(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; //----------------------------------------------------------------------------- @@ -115,8 +105,6 @@ class ASCENT_API VTKH3Slice : public ::flow::Filter virtual ~VTKH3Slice(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -128,8 +116,6 @@ class ASCENT_API VTKHThreshold : public ::flow::Filter virtual ~VTKHThreshold(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -141,8 +127,6 @@ class ASCENT_API VTKHGhostStripper: public ::flow::Filter virtual ~VTKHGhostStripper(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -154,8 +138,6 @@ class ASCENT_API VTKHAddRanks : public ::flow::Filter virtual ~VTKHAddRanks(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -168,8 +150,6 @@ class ASCENT_API VTKHAddDomains : public ::flow::Filter virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -183,8 +163,6 @@ class ASCENT_API VTKHClip: public ::flow::Filter virtual ~VTKHClip(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -196,8 +174,6 @@ class ASCENT_API VTKHClipWithField : public ::flow::Filter virtual ~VTKHClipWithField(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -209,8 +185,6 @@ class ASCENT_API VTKHIsoVolume : public ::flow::Filter virtual ~VTKHIsoVolume(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -222,8 +196,6 @@ class ASCENT_API VTKHLagrangian : public ::flow::Filter virtual ~VTKHLagrangian(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -235,8 +207,6 @@ class ASCENT_API VTKHLog: public ::flow::Filter virtual ~VTKHLog(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -248,8 +218,6 @@ class ASCENT_API VTKHLog10: public ::flow::Filter virtual ~VTKHLog10(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -261,8 +229,6 @@ class ASCENT_API VTKHLog2: public ::flow::Filter virtual ~VTKHLog2(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -274,8 +240,6 @@ class ASCENT_API VTKHRecenter: public ::flow::Filter virtual ~VTKHRecenter(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -287,8 +251,6 @@ class ASCENT_API VTKHHistSampling : public ::flow::Filter virtual ~VTKHHistSampling(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -300,8 +262,6 @@ class ASCENT_API VTKHQCriterion: public ::flow::Filter virtual ~VTKHQCriterion(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -313,8 +273,6 @@ class ASCENT_API VTKHDivergence: public ::flow::Filter virtual ~VTKHDivergence(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -326,8 +284,6 @@ class ASCENT_API VTKHVorticity: public ::flow::Filter virtual ~VTKHVorticity(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -339,8 +295,6 @@ class ASCENT_API VTKHGradient : public ::flow::Filter virtual ~VTKHGradient(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -352,8 +306,6 @@ class ASCENT_API VTKHNoOp : public ::flow::Filter virtual ~VTKHNoOp(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -365,8 +317,6 @@ class ASCENT_API VTKHVectorComponent : public ::flow::Filter virtual ~VTKHVectorComponent(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -378,8 +328,6 @@ class ASCENT_API VTKHCompositeVector : public ::flow::Filter virtual ~VTKHCompositeVector(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -391,8 +339,6 @@ class ASCENT_API VTKHStats : public ::flow::Filter virtual ~VTKHStats(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -404,8 +350,6 @@ class ASCENT_API VTKHUniformGrid : public ::flow::Filter virtual ~VTKHUniformGrid(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -417,8 +361,6 @@ class ASCENT_API VTKHSample : public ::flow::Filter virtual ~VTKHSample(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -430,8 +372,6 @@ class ASCENT_API VTKHHistogram : public ::flow::Filter virtual ~VTKHHistogram(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -444,8 +384,6 @@ class ASCENT_API VTKHProject2d : public ::flow::Filter virtual ~VTKHProject2d(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -458,8 +396,6 @@ class ASCENT_API VTKHCleanGrid : public ::flow::Filter virtual ~VTKHCleanGrid(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -471,8 +407,6 @@ class ASCENT_API VTKHScale : public ::flow::Filter virtual ~VTKHScale(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -484,8 +418,6 @@ class ASCENT_API VTKHTransform : public ::flow::Filter virtual ~VTKHTransform(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -497,8 +429,6 @@ class ASCENT_API VTKHTriangulate : public ::flow::Filter virtual ~VTKHTriangulate(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -510,8 +440,6 @@ class ASCENT_API VTKHParticleAdvection : public ::flow::Filter virtual ~VTKHParticleAdvection(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); protected: @@ -535,8 +463,6 @@ class ASCENT_API VTKHWarpXStreamline : public ::flow::Filter virtual ~VTKHWarpXStreamline(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); protected: @@ -551,8 +477,6 @@ class ASCENT_API VTKHVTKFileExtract : public ::flow::Filter virtual ~VTKHVTKFileExtract(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; @@ -566,8 +490,6 @@ class ASCENT_API VTKHMIR : public ::flow::Filter virtual ~VTKHMIR(); virtual void declare_interface(conduit::Node &i); - virtual bool verify_params(const conduit::Node ¶ms, - conduit::Node &info); virtual void execute(); }; diff --git a/src/libs/flow/CMakeLists.txt b/src/libs/flow/CMakeLists.txt index c17075196..249af3b54 100644 --- a/src/libs/flow/CMakeLists.txt +++ b/src/libs/flow/CMakeLists.txt @@ -25,6 +25,7 @@ set(flow_sources flow_graph.cpp flow_workspace.cpp flow_timer.cpp + flow_schema_validator.cpp filters/flow_builtin_filters.cpp) set(flow_headers @@ -38,6 +39,7 @@ set(flow_headers flow_graph.hpp flow_workspace.hpp flow_timer.hpp + flow_schema_validator.hpp filters/flow_builtin_filters.hpp) set(flow_thirdparty_libs diff --git a/src/libs/flow/flow_filter.cpp b/src/libs/flow/flow_filter.cpp index 4bce67aa1..9f502c767 100644 --- a/src/libs/flow/flow_filter.cpp +++ b/src/libs/flow/flow_filter.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace conduit; @@ -111,6 +112,10 @@ Filter::init(Graph *g, n_iface["port_names"] = DataType::empty(); } + if( !n_iface.has_child("param_schema") ) + { + n_iface["param_schema"] = DataType::empty(); + } params().update(default_params()); params().update(p); @@ -137,6 +142,13 @@ Filter::default_params() const return properties()["interface/default_params"]; } +//----------------------------------------------------------------------------- +const Node & +Filter::param_schema() const +{ + return properties()["interface/param_schema"]; +} + //----------------------------------------------------------------------------- const Node & Filter::port_names() const @@ -209,10 +221,22 @@ Filter::params() //----------------------------------------------------------------------------- bool -Filter::verify_params(const Node &, // unused: params, +Filter::verify_params(const Node ¶ms, Node &info) { info.reset(); + + if (!param_schema().dtype().is_empty() && !(param_schema().dtype().is_object() && param_schema().number_of_children() == 0)) + { + // std::cout << "\nSlice Properties!!" << std::endl; + // param_schema().print(); + + // std::cout << "\nParams!!" << std::endl; + // params.print(); + + return flow::schema::validate(param_schema(), params, info); + } + return true; } diff --git a/src/libs/flow/flow_filter.hpp b/src/libs/flow/flow_filter.hpp index 7fbccd00c..f5d7258e5 100644 --- a/src/libs/flow/flow_filter.hpp +++ b/src/libs/flow/flow_filter.hpp @@ -138,6 +138,7 @@ class FLOW_API Filter bool output_port() const; const conduit::Node &default_params() const; + const conduit::Node ¶m_schema() const; int number_of_input_ports() const; bool has_port(const std::string &name) const; diff --git a/src/libs/flow/flow_schema_validator.cpp b/src/libs/flow/flow_schema_validator.cpp new file mode 100644 index 000000000..d9faef8be --- /dev/null +++ b/src/libs/flow/flow_schema_validator.cpp @@ -0,0 +1,591 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + +//----------------------------------------------------------------------------- +/// +/// file: flow_schema_validator.cpp +/// +//----------------------------------------------------------------------------- + +#include "flow_schema_validator.hpp" + +// standard lib includes +#include +#include + +//----------------------------------------------------------------------------- +// -- begin flow -- +//----------------------------------------------------------------------------- +namespace flow +{ + +//----------------------------------------------------------------------------- +// -- begin flow::schema -- +//----------------------------------------------------------------------------- +namespace schema +{ + +// ---------- General Helpers ---------- +static void add_error(conduit::Node &info, const std::string &msg) +{ + if(!info.has_child("errors")) + { + info["errors"].reset(); + } + info["errors"].append() = msg; +} + +static std::string get_type_string(const conduit::Node &schema) +{ + if(schema.has_child("type") && schema["type"].dtype().is_string()) + { + return schema["type"].as_string(); + } + return ""; +} + +static bool check_type(const conduit::Node &input, + const conduit::Node &schema, + conduit::Node &info, + const std::string &path) +{ + const std::string schema_defined_type = get_type_string(schema); + if(schema_defined_type.empty()) return true; // schema didn't specify; treat as "accept anything" + + const auto data_type = input.dtype(); + bool ok = true; + + if(schema_defined_type == "object") ok = data_type.is_object(); + else if(schema_defined_type == "string") ok = data_type.is_string(); + else if(schema_defined_type == "number") ok = data_type.is_number(); + else if(schema_defined_type == "array") ok = (data_type.is_list() || (data_type.is_number() && data_type.number_of_elements() >= 1)); + else + { + add_error(info, "At '" + (path.empty() ? std::string("") : path) + + "': unknown schema type '" + schema_defined_type + "'"); + return false; + } + + if(!ok) + { + add_error(info, "Type mismatch at '" + (path.empty() ? std::string("") : path) + + "': expected " + schema_defined_type + ", got " + input.dtype().name()); + } + + return ok; +} + +// ---------- Object-Specific Validation Helpers ---------- +static bool validate_required(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_child("required")) return true; + if(!input.dtype().is_object()) return true; // type error handled elsewhere + + bool ok = true; + const conduit::Node &req = schema["required"]; + for(conduit::index_t i = 0; i < req.number_of_children(); ++i) + { + const std::string k = req.child(i).as_string(); + if(!input.has_child(k)) + { + add_error(info, "Missing required field '" + conduit::utils::join_file_path(path, k) + "'"); + ok = false; + } + } + return ok; +} + +static bool validate_forbid(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_path("constraints/forbid")) return true; + if(!input.dtype().is_object()) return true; + + bool ok = true; + const conduit::Node &forbid = schema["constraints/forbid"]; + for(conduit::index_t i = 0; i < forbid.number_of_children(); ++i) + { + const std::string k = forbid.child(i).as_string(); + if(input.has_child(k)) + { + add_error(info, "Field '" + conduit::utils::join_file_path(path, k) + "' is forbidden by schema"); + ok = false; + } + } + return ok; +} + +static bool validate_const(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_path("constraints/const")) return true; + + const conduit::Node &c = schema["constraints/const"]; + // Only implement string const for now (that’s all we used above) + if(input.dtype().is_string() && c.dtype().is_string()) + { + const std::string got = input.as_string(); + const std::string expect = c.as_string(); + if(got != expect) + { + add_error(info, "Value mismatch at '" + (path.empty() ? std::string("") : path) + + "': expected '" + expect + "', got '" + got + "'"); + return false; + } + } + return true; +} + +static bool validate_not_const_fields(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_path("constraints/not_const")) return true; + if(!input.dtype().is_object()) return true; + + bool ok = true; + const conduit::Node &nc = schema["constraints/not_const"]; + for(conduit::index_t i = 0; i < nc.number_of_children(); ++i) + { + const std::string field = nc[i].name(); + const conduit::Node &forbidden_val = nc[field]; + + if(input.has_child(field) && input[field].dtype().is_string() && forbidden_val.dtype().is_string()) + { + const std::string got = input[field].as_string(); + const std::string bad = forbidden_val.as_string(); + if(got == bad) + { + add_error(info, "Value forbidden at '" + conduit::utils::join_file_path(path, field) + + "': must not be '" + bad + "'"); + ok = false; + } + } + } + return ok; +} + +static bool validate_properties(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_child("properties")) return true; + if(!input.dtype().is_object()) return true; + + bool ok = true; + const conduit::Node &props = schema["properties"]; + for(conduit::index_t i = 0; i < props.number_of_children(); ++i) + { + const std::string k = props[i].name(); + if(input.has_child(k)) + { + ok = validate_node(props[k], input[k], info, conduit::utils::join_file_path(path, k)) && ok; + } + } + return ok; +} + +static bool validate_additional_properties(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!input.dtype().is_object()) return true; + + bool allow_additional = true; + if(schema.has_child("additionalProperties")) + { + allow_additional = schema["additionalProperties"].to_int() != 0; + } + + if(allow_additional) return true; + + const bool has_props = schema.has_child("properties"); + const conduit::Node props_dummy; + const conduit::Node &props = has_props ? schema["properties"] : props_dummy; + + bool ok = true; + for(conduit::index_t i = 0; i < input.number_of_children(); ++i) + { + const std::string k = input[i].name(); + if(!has_props || !props.has_child(k)) + { + add_error(info, "Unexpected field '" + conduit::utils::join_file_path(path, k) + + "' (additionalProperties=false)"); + ok = false; + } + } + return ok; +} + +static bool validate_dependencies(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_path("constraints/dependencies")) return true; + if(!input.dtype().is_object()) return true; + + bool ok = true; + const conduit::Node &deps = schema["constraints/dependencies"]; + + for(conduit::index_t i = 0; i < deps.number_of_children(); ++i) + { + const std::string trigger = deps[i].name(); + if(!input.has_child(trigger)) continue; + + const conduit::Node &reqs = deps[trigger]; + for(conduit::index_t j = 0; j < reqs.number_of_children(); ++j) + { + const std::string needed = reqs.child(j).as_string(); + if(!input.has_child(needed)) + { + add_error(info, "Dependency violation at '" + + (path.empty() ? std::string("") : path) + + "': if '" + trigger + "' is provided, '" + + needed + "' must also be provided"); + ok = false; + } + } + } + return ok; +} + +static bool validate_exclusive_children(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_path("constraints/exclusiveChildren")) return true; + if(!input.dtype().is_object()) return true; + + const conduit::Node &keys = schema["constraints/exclusiveChildren"]; + const bool allow_none = schema.has_path("constraints/allowNoneInExclusiveGroup") + ? (schema["constraints/allowNoneInExclusiveGroup"].to_int() != 0) + : true; + + std::vector present; + present.reserve((size_t)keys.number_of_children()); + + for(conduit::index_t i = 0; i < keys.number_of_children(); ++i) + { + const std::string k = keys.child(i).as_string(); + if(input.has_child(k)) present.push_back(k); + } + + const int count = (int)present.size(); + const bool ok = allow_none ? (count <= 1) : (count == 1); + + if(ok) return true; + + std::ostringstream oss; + oss << "Exclusive-children violation at '" + << (path.empty() ? "" : path) << "': expected " + << (allow_none ? "zero or one" : "exactly one") + << " of {"; + + for(conduit::index_t i = 0; i < keys.number_of_children(); ++i) + { + if(i) oss << ", "; + oss << keys.child(i).as_string(); + } + oss << "}"; + + if(count > 0) + { + oss << ", but found: {"; + for(size_t i = 0; i < present.size(); ++i) + { + if(i) oss << ", "; + oss << present[i]; + } + oss << "}"; + } + else + { + oss << ", but found none"; + } + + add_error(info, oss.str()); + return false; +} + +static bool validate_one_of(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_child("oneOf")) return true; + + const conduit::Node &opts = schema["oneOf"]; + int matches = 0; + + // keep at most one representative failure per option for clarity + std::vector option_msgs; + + for(conduit::index_t i = 0; i < opts.number_of_children(); ++i) + { + const conduit::Node &opt = opts.child(i); + + conduit::Node tmp; + tmp.reset(); + + bool ok = true; + ok = check_type(input, opt, tmp, path) && ok; + ok = validate_required(opt, input, tmp, path) && ok; + ok = validate_forbid(opt, input, tmp, path) && ok; + ok = validate_dependencies(opt, input, tmp, path) && ok; + ok = validate_exclusive_children(opt, input, tmp, path) && ok; + + if(ok) + { + matches++; + } + else + { + // pick first error as representative + if(tmp.has_child("errors") && tmp["errors"].number_of_children() > 0) + { + option_msgs.push_back(tmp["errors"].child(0).as_string()); + } + else + { + option_msgs.push_back("Option " + std::to_string((int)i) + " failed"); + } + } + } + + if(matches == 1) return true; + + std::ostringstream oss; + oss << "oneOf violation at '" << (path.empty() ? "" : path) << "': "; + if(matches == 0) oss << "input did not match any supported schemas"; + else oss << "input matched " << matches << " options (ambiguous)"; + add_error(info, oss.str()); + + // give a couple of hints + for(size_t i = 0; i < option_msgs.size() && i < 2; ++i) + { + add_error(info, std::string(" hint: ") + option_msgs[i]); + } + + return false; +} + +static bool validate_any_of(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if(!schema.has_child("anyOf")) return true; + + const conduit::Node &opts = schema["anyOf"]; + int matches = 0; + + // collect a couple representative failures for hints + std::vector option_msgs; + + for(conduit::index_t i = 0; i < opts.number_of_children(); ++i) + { + const conduit::Node &opt = opts.child(i); + + conduit::Node tmp; + tmp.reset(); + + bool ok = true; + ok = check_type(input, opt, tmp, path) && ok; + ok = validate_required(opt, input, tmp, path) && ok; + ok = validate_forbid(opt, input, tmp, path) && ok; + ok = validate_dependencies(opt, input, tmp, path) && ok; + ok = validate_exclusive_children(opt, input, tmp, path) && ok; + + if(ok) + { + matches++; + } + else if(tmp.has_child("errors") && tmp["errors"].number_of_children() > 0) + { + option_msgs.push_back(tmp["errors"].child(0).as_string()); + } + } + + if(matches >= 1) return true; + + add_error(info, "anyOf violation at '" + (path.empty() ? std::string("") : path) + + "': input did not match any option"); + + for(size_t i = 0; i < option_msgs.size() && i < 2; ++i) + { + add_error(info, std::string(" hint: ") + option_msgs[i]); + } + + return false; +} + +static bool validate_object(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + bool ok = true; + + // Base checks first + ok = validate_required(schema, input, info, path) && ok; + ok = validate_forbid(schema, input, info, path) && ok; + ok = validate_not_const_fields(schema, input, info, path) && ok; + ok = validate_dependencies(schema, input, info, path) && ok; + ok = validate_exclusive_children(schema, input, info, path) && ok; + + // Enforce unknown fields after we know properties + ok = validate_additional_properties(schema, input, info, path) && ok; + + // Recurse into declared properties that exist in input + ok = validate_properties(schema, input, info, path) && ok; + + // Finally, enforce oneOf (treating options as extra constraints on this same object) + ok = validate_one_of(schema, input, info, path) && ok; + ok = validate_any_of(schema, input, info, path) && ok; + + return ok; +} + +static bool validate_array(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + bool ok = true; + + const auto data_type = input.dtype(); + const conduit::index_t count = data_type.is_list() ? input.number_of_children() : data_type.number_of_elements(); + + // Json Schema uses min/max bounds for array length. + if(schema.has_child("minItems")) + { + const conduit::index_t min_items = (conduit::index_t)schema["minItems"].to_int(); + if(count < min_items) + { + add_error(info, + "Array at '" + (path.empty() ? std::string("") : path) + + "' has too few items: expected at least " + + std::to_string((long long)min_items) + ", got " + + std::to_string((long long)count)); + ok = false; + } + } + + if(schema.has_child("maxItems")) + { + const conduit::index_t max_items = (conduit::index_t)schema["maxItems"].to_int(); + if(count > max_items) + { + add_error(info, + "Array at '" + (path.empty() ? std::string("") : path) + + "' has too many items: expected at most " + + std::to_string((long long)max_items) + ", got " + + std::to_string((long long)count)); + ok = false; + } + } + + if(!schema.has_child("items")) return true; // unconstrained items + + const conduit::Node &item_schema = schema["items"]; + if(data_type.is_list()) { + for(conduit::index_t i = 0; i < count; ++i) + { + ok = validate_node(item_schema, input.child(i), info, + path + "[" + std::to_string((int)i) + "]") && ok; + } + } + return ok; +} + +static bool validate_node(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path) +{ + if (schema.has_path("constraints/skip") && schema["constraints/skip"].to_int() != 0) + { + return true; + } + + const std::string schema_defined_type = get_type_string(schema); + if(schema_defined_type == "object" && input.dtype().is_empty()) + { + conduit::Node empty_obj; + empty_obj.set(conduit::DataType::object()); + return validate_object(schema, empty_obj, info, path); + } + if(schema_defined_type == "array" && input.dtype().is_empty()) + { + conduit::Node empty_list; + empty_list.set(conduit::DataType::list()); + return validate_array(schema, empty_list, info, path); + } + + bool ok = true; + + ok = check_type(input, schema, info, path) && ok; + ok = validate_const(schema, input, info, path) && ok; + if(!ok) return false; // type mismatch stops recursion + + + + if(schema_defined_type == "object") + { + return validate_object(schema, input, info, path); + } + if (schema_defined_type == "array") + { + return validate_array(schema, input, info, path); + } + + ok = validate_one_of(schema, input, info, path) && ok; + ok = validate_any_of(schema, input, info, path) && ok; + + return ok; +} + +// ---------- Schema Validation Entry-Point ---------- +bool validate(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info) +{ + info.reset(); + bool ok = validate_node(schema, input, info, ""); + + if(!ok && !info.has_child("errors")) + { + info["errors"].append() = "Validation failed (no details)"; + } + + return ok; +} + + +}; +//----------------------------------------------------------------------------- +// -- end flow::schema -- +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +}; +//----------------------------------------------------------------------------- +// -- end flow -- +//----------------------------------------------------------------------------- diff --git a/src/libs/flow/flow_schema_validator.hpp b/src/libs/flow/flow_schema_validator.hpp new file mode 100644 index 000000000..835081c4e --- /dev/null +++ b/src/libs/flow/flow_schema_validator.hpp @@ -0,0 +1,108 @@ +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// +// Copyright (c) Lawrence Livermore National Security, LLC and other Ascent +// Project developers. See top-level LICENSE AND COPYRIGHT files for dates and +// other details. No copyright assignment is required to contribute to Ascent. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~// + + +//----------------------------------------------------------------------------- +/// +/// file: flow_schema_validator.hpp +/// +//----------------------------------------------------------------------------- + +#ifndef FLOW_SCHEMA_VALIDATOR_HPP +#define FLOW_SCHEMA_VALIDATOR_HPP + +#include + +#include +#include + +//----------------------------------------------------------------------------- +// -- begin flow -- +//----------------------------------------------------------------------------- +namespace flow +{ + +//----------------------------------------------------------------------------- +// -- begin flow::schema -- +//----------------------------------------------------------------------------- +namespace schema +{ + +bool FLOW_API validate(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info); + + +static bool validate_node(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_object(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_one_of(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_exclusive_children(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_dependencies(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_properties(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_additional_properties(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_required(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool validate_forbid(const conduit::Node &schema, + const conduit::Node &input, + conduit::Node &info, + const std::string &path); + +static bool check_type(const conduit::Node &input, + const conduit::Node &schema, + conduit::Node &info, + const std::string &path); + +static std::string get_type_string(const conduit::Node &schema); + +static void add_error(conduit::Node &info, const std::string &msg); + +}; +//----------------------------------------------------------------------------- +// -- end flow::schema -- +//----------------------------------------------------------------------------- + + +//----------------------------------------------------------------------------- +}; +//----------------------------------------------------------------------------- +// -- end flow -- +//----------------------------------------------------------------------------- + +#endif +//----------------------------------------------------------------------------- +// -- end header ifdef guard +//-----------------------------------------------------------------------------