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