1 // Copyright (c) Lawrence Livermore National Security, LLC and other Conduit
2 // Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
3 // other details. No copyright assignment is required to contribute to Conduit.
4
5 //-----------------------------------------------------------------------------
6 ///
7 /// file: t_blueprint_mesh_examples.cpp
8 ///
9 //-----------------------------------------------------------------------------
10
11 #include "conduit.hpp"
12 #include "conduit_blueprint.hpp"
13 #include "conduit_relay.hpp"
14 #include "conduit_log.hpp"
15
16 #include "conduit_fmt/conduit_fmt.h"
17
18 #include <math.h>
19 #include <iostream>
20 #include "gtest/gtest.h"
21
22 using namespace conduit;
23 using namespace conduit::utils;
24
25 //-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_relay,spiral_multi_file)26 TEST(conduit_blueprint_mesh_relay, spiral_multi_file)
27 {
28 Node io_protos;
29 relay::io::about(io_protos["io"]);
30 bool hdf5_enabled = io_protos["io/protocols/hdf5"].as_string() == "enabled";
31 if(!hdf5_enabled)
32 {
33 CONDUIT_INFO("HDF5 disabled, skipping spiral_multi_file test");
34 return;
35 }
36 //
37 // Create an example mesh.
38 //
39 Node data, verify_info;
40
41 // use spiral , with 7 domains
42 conduit::blueprint::mesh::examples::spiral(7,data);
43
44 // lets try with -1 to 8 files.
45
46 // nfiles less than 1 should trigger default case
47 // (n output files = n domains)
48 std::ostringstream oss;
49 for(int nfiles=-1; nfiles < 9; nfiles++)
50 {
51 CONDUIT_INFO("test nfiles = " << nfiles);
52 oss.str("");
53 oss << "tout_relay_sprial_mesh_save_nfiles_" << nfiles;
54 std::string output_base = oss.str();
55 std::string output_dir = output_base + ".cycle_000000";
56 std::string output_root = output_base + ".cycle_000000.root";
57
58 // count the files
59 // file_%06llu.{protocol}:/domain_%06llu/...
60 int nfiles_to_check = nfiles;
61 if(nfiles <=0 || nfiles == 8) // expect 7 files (one per domain)
62 {
63 nfiles_to_check = 7;
64 }
65
66 // remove existing root file, directory and any output files
67 remove_path_if_exists(output_root);
68 for(int i=0;i<nfiles_to_check;i++)
69 {
70
71 std::string fprefix = "file_";
72 if(nfiles_to_check == 7)
73 {
74 // in the n domains == n files case, the file prefix is
75 // domain_
76 fprefix = "domain_";
77 }
78
79 std::string output_file = conduit_fmt::format("{}{:06d}.hdf5",
80 join_file_path(output_base + ".cycle_000000",
81 fprefix),
82 i);
83 remove_path_if_exists(output_file);
84 }
85
86 remove_path_if_exists(output_dir);
87
88 Node opts;
89 opts["number_of_files"] = nfiles;
90 relay::io::blueprint::write_mesh(data, output_base, "hdf5", opts);
91
92 EXPECT_TRUE(is_directory(output_dir));
93 EXPECT_TRUE(is_file(output_root));
94
95 char fmt_buff[64] = {0};
96 for(int i=0;i<nfiles_to_check;i++)
97 {
98
99 std::string fprefix = "file_";
100 if(nfiles_to_check == 7)
101 {
102 // in the n domains == n files case, the file prefix is
103 // domain_
104 fprefix = "domain_";
105 }
106
107 std::string fcheck = conduit_fmt::format("{}{:06d}.hdf5",
108 join_file_path(output_base + ".cycle_000000",
109 fprefix),
110 i);
111
112 std::cout << " checking: " << fcheck << std::endl;
113 EXPECT_TRUE(is_file(fcheck));
114 }
115
116 // read the mesh back in diff to make sure we have the same data
117 Node n_read, info;
118 relay::io::blueprint::read_mesh(output_base + ".cycle_000000.root",
119 n_read);
120
121 // in all cases we expect 7 domains to match
122 for(int dom_idx =0; dom_idx <7; dom_idx++)
123 {
124 EXPECT_FALSE(data.child(dom_idx).diff(n_read.child(dom_idx),info));
125 }
126 }
127 }
128
129
130 //-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_relay,save_read_mesh)131 TEST(conduit_blueprint_mesh_relay, save_read_mesh)
132 {
133 Node io_protos;
134 relay::io::about(io_protos["io"]);
135 bool hdf5_enabled = io_protos["io/protocols/hdf5"].as_string() == "enabled";
136 if(!hdf5_enabled)
137 {
138 CONDUIT_INFO("HDF5 disabled, skipping save_read_mesh test");
139 return;
140 }
141
142 std::string output_base = "tout_relay_mesh_save_load";
143 // spiral with 3 domains
144 Node data;
145 conduit::blueprint::mesh::examples::spiral(3,data);
146
147 // spiral doesn't have domain ids, lets add some so we diff clean
148 data.child(0)["state/domain_id"] = 0;
149 data.child(1)["state/domain_id"] = 1;
150 data.child(2)["state/domain_id"] = 2;
151
152 Node opts;
153 opts["number_of_files"] = -1;
154
155 remove_path_if_exists(output_base + ".cycle_000000.root");
156 remove_path_if_exists(output_base + ".cycle_000000/file_000000.hdf5");
157 remove_path_if_exists(output_base + ".cycle_000000/file_000001.hdf5");
158 remove_path_if_exists(output_base + ".cycle_000000/file_000002.hdf5");
159
160 relay::io::blueprint::write_mesh(data, output_base, "hdf5", opts);
161
162 data.print();
163 Node n_read, info;
164 relay::io::blueprint::read_mesh(output_base + ".cycle_000000.root",
165 n_read);
166
167 n_read.print();
168 // reading back in will add domain_zzzzzz names, check children of read
169
170 EXPECT_FALSE(data.child(0).diff(n_read.child(0),info));
171 EXPECT_FALSE(data.child(1).diff(n_read.child(1),info));
172 EXPECT_FALSE(data.child(2).diff(n_read.child(2),info));
173 }
174
175 //-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_relay,save_read_mesh_truncate)176 TEST(conduit_blueprint_mesh_relay, save_read_mesh_truncate)
177 {
178 Node io_protos;
179 relay::io::about(io_protos["io"]);
180 bool hdf5_enabled = io_protos["io/protocols/hdf5"].as_string() == "enabled";
181 if(!hdf5_enabled)
182 {
183 CONDUIT_INFO("HDF5 disabled, skipping save_read_mesh_truncate test");
184 return;
185 }
186
187 std::string output_base = "tout_relay_mesh_save_load_truncate";
188
189 Node data;
190
191 // 3 doms
192 blueprint::mesh::examples::braid("uniform",
193 2,
194 2,
195 2,
196 data.append());
197
198 blueprint::mesh::examples::braid("uniform",
199 2,
200 2,
201 2,
202 data.append());
203
204 blueprint::mesh::examples::braid("uniform",
205 2,
206 2,
207 2,
208 data.append());
209
210 // set the domain ids
211 data.child(0)["state/domain_id"] = 0;
212 data.child(1)["state/domain_id"] = 1;
213 data.child(2)["state/domain_id"] = 2;
214
215 // 3 doms 2 files
216 Node opts;
217 opts["number_of_files"] = 2;
218
219 remove_path_if_exists(output_base + ".cycle_000100.root");
220 remove_path_if_exists(output_base + ".cycle_000100/file_000000.hdf5");
221 remove_path_if_exists(output_base + ".cycle_000100/file_000001.hdf5");
222
223 relay::io::blueprint::write_mesh(data, output_base, "hdf5", opts);
224
225 // load mesh back back in and diff to check values
226 Node n_read, info;
227 relay::io::blueprint::load_mesh(output_base + ".cycle_000100.root",
228 n_read);
229
230 for(int dom_idx=0; dom_idx < 3; dom_idx++)
231 {
232 data.child(dom_idx).diff(n_read.child(dom_idx),info);
233 }
234
235 // now save diff mesh to same file set, will fail with write_mesh
236 // b/c hdf5 paths won't be compat
237
238 data.reset();
239 // 3 doms
240 blueprint::mesh::examples::braid("uniform",
241 5,
242 5,
243 0,
244 data.append());
245
246 blueprint::mesh::examples::braid("uniform",
247 5,
248 5,
249 0,
250 data.append());
251
252 blueprint::mesh::examples::braid("uniform",
253 5,
254 5,
255 0,
256 data.append());
257
258 // set the domain ids
259 data.child(0)["state/domain_id"] = 0;
260 data.child(1)["state/domain_id"] = 1;
261 data.child(2)["state/domain_id"] = 2;
262
263 // non-trunk will error b/c leaf sizes aren't compat
264 EXPECT_THROW( relay::io::blueprint::write_mesh(data, output_base, "hdf5", opts),Error);
265
266 // trunc will work
267 relay::io::blueprint::save_mesh(data, output_base, "hdf5", opts);
268
269 // load mesh back back in and diff to check values
270 relay::io::blueprint::load_mesh(output_base + ".cycle_000100.root",
271 n_read);
272
273 for(int dom_idx=0; dom_idx < 3; dom_idx++)
274 {
275 EXPECT_FALSE(data.child(dom_idx).diff(n_read.child(dom_idx),info));
276 info.print();
277 }
278 }
279
280
281 //-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_relay,save_read_mesh_truncate_root_only)282 TEST(conduit_blueprint_mesh_relay, save_read_mesh_truncate_root_only)
283 {
284 // test truncate with root only style
285 Node io_protos;
286 relay::io::about(io_protos["io"]);
287 bool hdf5_enabled = io_protos["io/protocols/hdf5"].as_string() == "enabled";
288 if(!hdf5_enabled)
289 {
290 CONDUIT_INFO("HDF5 disabled, skipping save_read_mesh_truncate test");
291 return;
292 }
293
294
295 std::string output_base = "tout_relay_mesh_save_load_truncate";
296
297 Node data;
298
299 blueprint::mesh::examples::braid("uniform",
300 2,
301 2,
302 2,
303 data);
304
305 remove_path_if_exists(output_base + ".cycle_000100.root");
306
307 Node opts;
308 relay::io::blueprint::write_mesh(data, output_base, "hdf5", opts);
309
310 blueprint::mesh::examples::braid("uniform",
311 10,
312 10,
313 10,
314 data);
315
316
317 EXPECT_THROW( relay::io::blueprint::write_mesh(data, output_base, "hdf5", opts),Error);
318 opts["truncate"] = "true";
319 // this will succed
320 relay::io::blueprint::write_mesh(data, output_base, "hdf5", opts);
321
322 }
323
324 //-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_relay,save_read_mesh_opts)325 TEST(conduit_blueprint_mesh_relay, save_read_mesh_opts)
326 {
327 Node io_protos;
328 relay::io::about(io_protos["io"]);
329 bool hdf5_enabled = io_protos["io/protocols/hdf5"].as_string() == "enabled";
330 if(!hdf5_enabled)
331 {
332 CONDUIT_INFO("HDF5 disabled, skipping save_read_mesh_opts test");
333 return;
334 }
335
336 Node data;
337 blueprint::mesh::examples::braid("uniform",
338 2,
339 2,
340 2,
341 data);
342
343 // add a domain_id since one will come back
344 data["state/domain_id"] = 0;
345
346 //
347 // suffix
348 //
349
350 // suffix: default, cycle, none, garbage
351
352 std::string tout_base = "tout_relay_bp_mesh_opts_suffix";
353
354 Node opts;
355 Node n_read, info;
356 opts["file_style"] = "root_only";
357
358 //
359 opts["suffix"] = "default";
360
361 remove_path_if_exists(tout_base + ".cycle_000100.root");
362 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
363 EXPECT_TRUE(is_file(tout_base + ".cycle_000100.root"));
364
365 // load mesh back back in and diff to check values
366 relay::io::blueprint::load_mesh(tout_base + ".cycle_000100.root",
367 n_read);
368 EXPECT_FALSE(data.diff(n_read.child(0),info));
369 data.print();
370 n_read.print();
371 info.print();
372
373 // remove cycle from braid, default behavior will be diff
374 data.remove("state/cycle");
375
376 remove_path_if_exists(tout_base + ".root");
377 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
378 EXPECT_TRUE(is_file( tout_base + ".root"));
379
380 // load mesh back back in and diff to check values
381 relay::io::blueprint::load_mesh(tout_base + ".root",
382 n_read);
383 EXPECT_FALSE(data.diff(n_read.child(0),info));
384
385
386 //
387 opts["suffix"] = "cycle";
388
389 remove_path_if_exists(tout_base + ".cycle_000000.root");
390 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
391 EXPECT_TRUE(is_file( tout_base + ".cycle_000000.root"));
392
393 relay::io::blueprint::load_mesh(tout_base + ".cycle_000000.root",
394 n_read);
395 EXPECT_FALSE(data.diff(n_read.child(0),info));
396
397 //
398 opts["suffix"] = "none";
399
400 remove_path_if_exists(tout_base + ".root");
401 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
402 EXPECT_TRUE(is_file( tout_base + ".root"));
403
404 relay::io::blueprint::load_mesh(tout_base + ".root",
405 n_read);
406 EXPECT_FALSE(data.diff(n_read.child(0),info));
407
408 // this should error
409 opts["suffix"] = "garbage";
410 EXPECT_THROW(relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts),Error);
411
412
413 //
414 // file style
415 //
416 // default, root_only, multi_file, garbage
417
418 tout_base = "tout_relay_bp_mesh_opts_file_style";
419
420 opts["file_style"] = "default";
421 opts["suffix"] = "none";
422
423 remove_path_if_exists(tout_base + ".root");
424 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
425 EXPECT_TRUE(is_file( tout_base + ".root"));
426
427 // load mesh back back in and diff to check values
428 relay::io::blueprint::load_mesh(tout_base + ".root",
429 n_read);
430 EXPECT_FALSE(data.diff(n_read.child(0),info));
431
432 opts["file_style"] = "root_only";
433
434 remove_path_if_exists(tout_base + ".root");
435 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
436 EXPECT_TRUE(is_file( tout_base + ".root"));
437
438 // load mesh back back in and diff to check values
439 relay::io::blueprint::load_mesh(tout_base + ".root",
440 n_read);
441 EXPECT_FALSE(data.diff(n_read.child(0),info));
442
443
444
445 opts["file_style"] = "multi_file";
446
447 remove_path_if_exists(tout_base + ".root");
448 remove_path_if_exists(tout_base);
449 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
450 EXPECT_TRUE(is_file( tout_base + ".root"));
451 EXPECT_TRUE(is_directory(tout_base));
452 EXPECT_TRUE(is_file(join_file_path(tout_base,
453 "domain_000000.hdf5")));
454
455 // load mesh back back in and diff to check values
456 relay::io::blueprint::load_mesh(tout_base + ".root",
457 n_read);
458 EXPECT_FALSE(data.diff(n_read.child(0),info));
459
460
461 opts["file_style"] = "garbage";
462
463 EXPECT_THROW(relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts),Error);
464
465 //
466 // mesh name
467 //
468
469 opts["file_style"] = "default";
470 opts["suffix"] = "none";
471 opts["mesh_name"] = "bananas";
472
473 tout_base = "tout_relay_bp_mesh_opts_mesh_name";
474 remove_path_if_exists(tout_base + ".root");
475 relay::io::blueprint::write_mesh(data, tout_base, "hdf5", opts);
476 EXPECT_TRUE(is_file( tout_base + ".root"));
477
478 // even custom name should work just fine with default
479 // (it will pick the first mesh)
480 relay::io::blueprint::load_mesh(tout_base + ".root", n_read);
481
482 Node load_opts;
483 // now test bad name
484 load_opts["mesh_name"] = "garbage";
485 EXPECT_THROW(relay::io::blueprint::load_mesh(tout_base + ".root",
486 load_opts,
487 n_read),
488 Error);
489
490 // now test expected name
491 load_opts["mesh_name"] = "bananas";
492 relay::io::blueprint::load_mesh(tout_base + ".root", load_opts, n_read);
493
494 // check that
495 // load mesh back back in and diff to check values
496 relay::io::blueprint::load_mesh(tout_base + ".root",
497 n_read);
498 EXPECT_FALSE(data.diff(n_read.child(0),info));
499 }
500
501
502