Wildmeshing Toolkit
Loading...
Searching...
No Matches
integration_test.cpp
Go to the documentation of this file.
1
2#include <catch2/catch_test_macros.hpp>
3#include <polysolve/Utils.hpp>
4
6
8
10
11#include <filesystem>
12#include <fstream>
13#include <iostream>
15
16using json = nlohmann::json;
17using namespace wmtk;
18
20
21namespace {
22
23bool load_json(const std::string& json_file, json& out)
24{
25 std::ifstream file(json_file);
26
27 if (!file.is_open()) return false;
28
29 file >> out;
30
31 return true;
32}
33
34
35bool contains_results(const json& in_args)
36{
37 if (!in_args.contains("tests")) {
38 return false;
39 }
40
41 const auto& tests = in_args["tests"];
42 for (const auto& type : {"meshes", "vertices", "edges", "faces", "tetrahedra"}) {
43 if (!(tests.contains(type) && (tests[type].is_number() || tests[type].is_array()))) {
44 spdlog::info(
45 "Test must have type {} = {} and test is an (array type = {} or number type {})",
46 tests.contains(type),
47 type,
48 tests[type].is_number(),
49 tests[type].is_array());
50 return false;
51 }
52 }
53 return true;
54}
55
56bool missing_tests_data(const json& j)
57{
58 return !j.contains("tests") || !j.at("tests").contains("meshes");
59}
60
61IntegrationTestResult authenticate_json(const std::string& json_file, const bool compute_validation)
62{
63 json in_args;
64 if (!load_json(json_file, in_args)) {
65 wmtk::logger().error("unable to open {} file", json_file);
67 }
68
69 in_args["root_path"] = json_file;
70
72 auto cache = wmtk::components::run_components(in_args, true);
73
74 if (!compute_validation) {
75 if (missing_tests_data(in_args)) {
76 wmtk::logger().error("JSON file missing \"tests\" or meshes key.");
78 }
79
80 REQUIRE(contains_results(in_args));
81
82 wmtk::logger().info("Authenticating...");
83
84 const std::vector<std::string> meshes = in_args["tests"]["meshes"];
85
86 if (in_args["tests"].contains("skip_check") && in_args["tests"]["skip_check"]) {
87 wmtk::logger().warn("Skpping checks for {}", json_file);
89 }
90
91 const auto vertices = in_args["tests"]["vertices"];
92 const auto edges = in_args["tests"]["edges"];
93 const auto faces = in_args["tests"]["faces"];
94 const auto tetrahedra = in_args["tests"]["tetrahedra"];
95 if (meshes.size() != vertices.size() || meshes.size() != edges.size() ||
96 meshes.size() != faces.size() || meshes.size() != tetrahedra.size()) {
97 wmtk::logger().error(
98 "JSON size missmatch between meshes and vertices, edges, faces, or tetrahedra.");
100 }
101
102 for (int64_t i = 0; i < meshes.size(); ++i) {
103 const std::shared_ptr<Mesh> mesh = cache.read_mesh(meshes[i]);
104
105 const int64_t expected_vertices = vertices[i];
106 const int64_t expected_edges = edges[i];
107 const int64_t expected_faces = faces[i];
108 const int64_t expected_tetrahedra = tetrahedra[i];
109
110 const int64_t n_vertices = mesh->get_all(PrimitiveType::Vertex).size();
111 const int64_t n_edges = mesh->get_all(PrimitiveType::Edge).size();
112 const int64_t n_faces = mesh->get_all(PrimitiveType::Triangle).size();
113 const int64_t n_tetrahedra = mesh->get_all(PrimitiveType::Tetrahedron).size();
114
115 if (n_vertices != expected_vertices) {
116 wmtk::logger().error(
117 "Violating Authenticate in mesh `{}` for vertices {} != {}",
118 meshes[i],
119 n_vertices,
120 expected_vertices);
122 }
123 if (n_edges != expected_edges) {
124 wmtk::logger().error(
125 "Violating Authenticate in mesh `{}` for edges {} != {}",
126 meshes[i],
127 n_edges,
128 expected_edges);
130 }
131 if (n_faces != expected_faces) {
132 wmtk::logger().error(
133 "Violating Authenticate in mesh `{}` for faces {} != {}",
134 meshes[i],
135 n_faces,
136 expected_faces);
138 }
139 if (n_tetrahedra != expected_tetrahedra) {
140 wmtk::logger().error(
141 "Violating Authenticate in mesh `{}` for tetrahedra {} != {}",
142 meshes[i],
143 n_tetrahedra,
144 expected_tetrahedra);
146 }
147 }
148
149 wmtk::logger().info("Authenticated ✅");
150 } else {
151 if (contains_results(in_args)) {
152 wmtk::logger().error(
153 "JSON file contains results even though the test was run in `computation "
154 "mode`. Set DO_VALIDATION to false to compare with saved results or remove "
155 "results from JSON to re-compute them.");
157 }
158
159 wmtk::logger().warn("Appending JSON...");
160
161 const std::vector<std::string> meshes = cache.mesh_names();
162 in_args["tests"]["meshes"] = meshes;
163
164 std::vector<int64_t> expected_vertices, expected_edges, expected_faces, expected_tetrahedra;
165
166 for (int64_t i = 0; i < meshes.size(); ++i) {
167 const std::shared_ptr<Mesh> mesh = cache.read_mesh(meshes[i]);
168
169
170 const int64_t n_vertices = mesh->get_all(PrimitiveType::Vertex).size();
171 const int64_t n_edges = mesh->get_all(PrimitiveType::Edge).size();
172 const int64_t n_faces = mesh->get_all(PrimitiveType::Triangle).size();
173 const int64_t n_tetrahedra = mesh->get_all(PrimitiveType::Tetrahedron).size();
174
175 expected_vertices.push_back(n_vertices);
176 expected_edges.push_back(n_edges);
177 expected_faces.push_back(n_faces);
178 expected_tetrahedra.push_back(n_tetrahedra);
179 }
180
181 in_args["tests"]["vertices"] = expected_vertices;
182 in_args["tests"]["edges"] = expected_edges;
183 in_args["tests"]["faces"] = expected_faces;
184 in_args["tests"]["tetrahedra"] = expected_tetrahedra;
185 in_args.erase("root_path");
186 in_args.erase("settings");
187
188 std::ofstream file(json_file);
189 file << in_args;
190 }
191
193}
194} // namespace
195namespace {
196#if defined(NDEBUG)
197std::string tagsrun = "[integration]";
198#else
199std::string tagsrun = "[.][integration]";
200#endif
201} // namespace
202
203#define WMTK_INTEGRATION_BODY(NAME, DO_VALIDATION) \
204 { \
205 std::string path = std::string("unit_test/") + NAME + ".json"; \
206 bool compute_validation = DO_VALIDATION; \
207 wmtk::logger().info("Processing {}", NAME); \
208 auto flag = authenticate_json(WMTK_DATA_DIR "/" + path, compute_validation); \
209 REQUIRE(flag == IntegrationTestResult::Success); \
210 }
211
212#define WMTK_INTEGRATION(NAME, DO_VALIDATION) \
213 TEST_CASE(std::string("integration_") + NAME, tagsrun) \
214 WMTK_INTEGRATION_BODY(NAME, DO_VALIDATION)
215
216
217WMTK_INTEGRATION("input", false);
218WMTK_INTEGRATION("to_points", false);
219WMTK_INTEGRATION("delaunay", false);
220WMTK_INTEGRATION("insertion", false);
221WMTK_INTEGRATION("insertion_open", false);
222WMTK_INTEGRATION("multimesh", false);
223WMTK_INTEGRATION("multimesh_boundary_2d", false);
224WMTK_INTEGRATION("multimesh_boundary_3d", false);
225WMTK_INTEGRATION("isotropic_remeshing", false);
226WMTK_INTEGRATION("isotropic_remeshing_mm", false);
227WMTK_INTEGRATION("disk_fan_mm", false);
228WMTK_INTEGRATION("grid", false);
229// WMTK_INTEGRATION("wildmeshing_2d", true);
230WMTK_INTEGRATION("wildmeshing_3d", false);
231// WMTK_INTEGRATION("marching", false);
232
233
234TEST_CASE("integration_benchmark", "[.][benchmark][integration]")
235{
236 double total_time = 0;
237 int count = 0;
238 double prod = 1;
239
240 nlohmann::json js;
241 auto run = [&](const std::string& name) {
242 double time = 0;
243 {
244 POLYSOLVE_SCOPED_STOPWATCH("Benchmark " + name, time, logger());
245 WMTK_INTEGRATION_BODY(name, false)
246 }
247 js[name] = time;
248 prod *= time;
249 count++;
250 };
251 // run("wildmeshing_2d_timing");
252 {
253 POLYSOLVE_SCOPED_STOPWATCH("Benchmark total time", total_time, logger());
254 run("wildmeshing_3d");
255 run("isotropic_remeshing_mm_timing");
256 }
257 js["total_time"] = total_time;
258 js["geometric_mean_time"] = std::pow(prod, 1.0 / count);
259
260 fmt::print("{}\n", js.dump());
261}
IntegrationTestResult
@ InvalidInput
@ Success
TEST_CASE("integration_benchmark", "[.][benchmark][integration]")
#define WMTK_INTEGRATION(NAME, DO_VALIDATION)
#define WMTK_INTEGRATION_BODY(NAME, DO_VALIDATION)
wmtk::io::Cache run_components(const nlohmann::json &json_input_file, bool strict)
std::vector< Tuple > vertices(const Mesh &m, const Simplex &simplex)
std::vector< Tuple > edges(const Mesh &m, const Simplex &simplex)
SimplexCollection faces(const Mesh &mesh, const Simplex &simplex, const bool sort_and_clean)
Returns all faces of a simplex.
Definition faces.cpp:10
void set_random_seed(uint64_t val)
spdlog::logger & logger()
Retrieves the current logger.
Definition Logger.cpp:58
nlohmann::json json
Definition input.cpp:9