1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
2 // Copyright (c) Lawrence Livermore National Security, LLC and other Ascent
3 // Project developers. See top-level LICENSE AND COPYRIGHT files for dates and
4 // other details. No copyright assignment is required to contribute to Ascent.
5 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~//
6
7
8 //-----------------------------------------------------------------------------
9 ///
10 /// file: ascent_runtime_dray_filters.cpp
11 ///
12 //-----------------------------------------------------------------------------
13
14 #include "ascent_runtime_dray_filters.hpp"
15
16 //-----------------------------------------------------------------------------
17 // thirdparty includes
18 //-----------------------------------------------------------------------------
19
20 // conduit includes
21 #include <conduit.hpp>
22 #include <conduit_blueprint.hpp>
23
24 //-----------------------------------------------------------------------------
25 // ascent includes
26 //-----------------------------------------------------------------------------
27 #include <ascent_logging.hpp>
28 #include <ascent_string_utils.hpp>
29 #include <ascent_runtime_param_check.hpp>
30 #include <ascent_metadata.hpp>
31 #include <ascent_runtime_utils.hpp>
32 #include <ascent_resources.hpp>
33 #include <ascent_png_encoder.hpp>
34 #include <flow_graph.hpp>
35 #include <flow_workspace.hpp>
36
37 // mpi
38 #ifdef ASCENT_MPI_ENABLED
39 #include <mpi.h>
40 #endif
41
42 #if defined(ASCENT_MFEM_ENABLED)
43 #include <ascent_mfem_data_adapter.hpp>
44 #endif
45
46 #include <runtimes/ascent_data_object.hpp>
47
48 #include <dray/dray.hpp>
49 #include <dray/data_model/data_set.hpp>
50 #include <dray/filters/mesh_boundary.hpp>
51
52 #include <dray/data_model/collection.hpp>
53
54 #include <dray/filters/reflect.hpp>
55 #include <dray/filters/mesh_boundary.hpp>
56 #include <dray/filters/volume_balance.hpp>
57 #include <dray/filters/vector_component.hpp>
58 #include <dray/exports.hpp>
59 #include <dray/transform_3d.hpp>
60 #include <dray/rendering/renderer.hpp>
61 #include <dray/rendering/surface.hpp>
62 #include <dray/rendering/slice_plane.hpp>
63 #include <dray/rendering/scalar_renderer.hpp>
64 #include <dray/io/blueprint_reader.hpp>
65
66 using namespace conduit;
67 using namespace std;
68
69 using namespace flow;
70
71 //-----------------------------------------------------------------------------
72 // -- begin ascent:: --
73 //-----------------------------------------------------------------------------
74 namespace ascent
75 {
76
77 //-----------------------------------------------------------------------------
78 // -- begin ascent::runtime --
79 //-----------------------------------------------------------------------------
80 namespace runtime
81 {
82
83 //-----------------------------------------------------------------------------
84 // -- begin ascent::runtime::filters --
85 //-----------------------------------------------------------------------------
86 namespace filters
87 {
88
89 namespace detail
90 {
is_same(const dray::AABB<3> & b1,const dray::AABB<3> & b2)91 bool is_same(const dray::AABB<3> &b1, const dray::AABB<3> &b2)
92 {
93 return
94 b1.m_ranges[0].min() == b2.m_ranges[0].min() &&
95 b1.m_ranges[1].min() == b2.m_ranges[1].min() &&
96 b1.m_ranges[2].min() == b2.m_ranges[2].min() &&
97 b1.m_ranges[0].max() == b2.m_ranges[0].max() &&
98 b1.m_ranges[1].max() == b2.m_ranges[1].max() &&
99 b1.m_ranges[2].max() == b2.m_ranges[2].max();
100 }
101
default_light(dray::Camera & camera)102 dray::PointLight default_light(dray::Camera &camera)
103 {
104 dray::Vec<float32,3> look_at = camera.get_look_at();
105 dray::Vec<float32,3> pos = camera.get_pos();
106 dray::Vec<float32,3> up = camera.get_up();
107 up.normalize();
108 dray::Vec<float32,3> look = look_at - pos;
109 dray::float32 mag = look.magnitude();
110 dray::Vec<float32,3> right = cross (look, up);
111 right.normalize();
112
113 dray::Vec<float32, 3> miner_up = cross (right, look);
114 miner_up.normalize();
115 dray::Vec<float32, 3> light_pos = pos + .1f * mag * miner_up;
116 dray::PointLight light;
117 light.m_pos = light_pos;
118 return light;
119 }
120
frame_buffer_to_node(dray::Framebuffer & fb,conduit::Node & mesh)121 void frame_buffer_to_node(dray::Framebuffer &fb, conduit::Node &mesh)
122 {
123 mesh.reset();
124 mesh["coordsets/coords/type"] = "uniform";
125 mesh["coordsets/coords/dims/i"] = fb.width();
126 mesh["coordsets/coords/dims/j"] = fb.height();
127
128 const int size = fb.width() * fb.height();
129
130 mesh["topologies/topo/coordset"] = "coords";
131 mesh["topologies/topo/type"] = "uniform";
132
133 const std::string path = "fields/colors/";
134 mesh[path + "association"] = "vertex";
135 mesh[path + "topology"] = "topo";
136 const float *colors = (float*)fb.colors().get_host_ptr_const();
137 mesh[path + "values"].set(colors, size*4);
138
139 mesh["fields/depth/association"] = "vertex";
140 mesh["fields/depth/topology"] = "topo";
141 const float32 *depths = fb.depths().get_host_ptr_const();
142 mesh["fields/depth/values"].set(depths, size);
143
144 conduit::Node verify_info;
145 bool ok = conduit::blueprint::mesh::verify(mesh,verify_info);
146 if(!ok)
147 {
148 verify_info.print();
149 }
150 }
151
boundary(dray::Collection & collection)152 dray::Collection boundary(dray::Collection &collection)
153 {
154 dray::MeshBoundary bounder;
155 return bounder.execute(collection);
156 }
157
158 std::string
dray_color_table_surprises(const conduit::Node & color_table)159 dray_color_table_surprises(const conduit::Node &color_table)
160 {
161 std::string surprises;
162
163 std::vector<std::string> valid_paths;
164 valid_paths.push_back("name");
165 valid_paths.push_back("reverse");
166
167 std::vector<std::string> ignore_paths;
168 ignore_paths.push_back("control_points");
169
170 surprises += surprise_check(valid_paths, ignore_paths, color_table);
171 if(color_table.has_path("control_points"))
172 {
173 std::vector<std::string> c_valid_paths;
174 c_valid_paths.push_back("type");
175 c_valid_paths.push_back("alpha");
176 c_valid_paths.push_back("color");
177 c_valid_paths.push_back("position");
178
179 const conduit::Node &control_points = color_table["control_points"];
180 const int num_points = control_points.number_of_children();
181 for(int i = 0; i < num_points; ++i)
182 {
183 const conduit::Node &point = control_points.child(i);
184 surprises += surprise_check(c_valid_paths, point);
185 }
186 }
187
188 return surprises;
189 }
190
191 std::string
dray_load_balance_surprises(const conduit::Node & load_balance)192 dray_load_balance_surprises(const conduit::Node &load_balance)
193 {
194 std::string surprises;
195
196 std::vector<std::string> valid_paths;
197 valid_paths.push_back("enabled");
198 valid_paths.push_back("factor");
199 valid_paths.push_back("threshold");
200 valid_paths.push_back("use_prefix");
201
202 surprises += surprise_check(valid_paths, load_balance);
203
204 return surprises;
205 }
206
207 dray::Vec<float,3>
planes(const conduit::Node & params,const dray::AABB<3> bounds)208 planes(const conduit::Node ¶ms, const dray::AABB<3> bounds)
209 {
210
211 using Vec3f = dray::Vec<float,3>;
212 Vec3f center = bounds.center();
213 Vec3f point = center;
214
215 const float eps = 1e-5; // ensure that the slice is always inside the data set
216 if(params.has_path("x_offset"))
217 {
218 float offset = params["x_offset"].to_float32();
219 std::max(-1.f, std::min(1.f, offset));
220 float t = (offset + 1.f) / 2.f;
221 t = std::max(0.f + eps, std::min(1.f - eps, t));
222 point[0] = bounds.m_ranges[0].min() + t * (bounds.m_ranges[0].length());
223 }
224
225 if(params.has_path("y_offset"))
226 {
227 float offset = params["y_offset"].to_float32();
228 std::max(-1.f, std::min(1.f, offset));
229 float t = (offset + 1.f) / 2.f;
230 t = std::max(0.f + eps, std::min(1.f - eps, t));
231 point[1] = bounds.m_ranges[1].min() + t * (bounds.m_ranges[1].length());
232 }
233
234 if(params.has_path("z_offset"))
235 {
236 float offset = params["z_offset"].to_float32();
237 std::max(-1.f, std::min(1.f, offset));
238 float t = (offset + 1.f) / 2.f;
239 t = std::max(0.f + eps, std::min(1.f - eps, t));
240 point[2] = bounds.m_ranges[2].min() + t * (bounds.m_ranges[2].length());
241 }
242
243 return point;
244 }
245
246 void
parse_plane(const conduit::Node & plane,dray::PlaneDetector & plane_d)247 parse_plane(const conduit::Node &plane, dray::PlaneDetector &plane_d)
248 {
249 typedef dray::Vec<float,3> Vec3f;
250
251 if(plane.has_child("center"))
252 {
253 conduit::Node n;
254 plane["center"].to_float64_array(n);
255 const float64 *coords = n.as_float64_ptr();
256 Vec3f vec = {{float(coords[0]), float(coords[1]), float(coords[2])}};
257 plane_d.m_center = vec;
258 }
259 else
260 {
261 ASCENT_ERROR("Plane definition missing 'center'");
262 }
263
264 if(plane.has_child("up"))
265 {
266 conduit::Node n;
267 plane["up"].to_float64_array(n);
268 const float64 *coords = n.as_float64_ptr();
269 Vec3f vec = {{float(coords[0]), float(coords[1]), float(coords[2])}};
270 vec.normalize();
271 plane_d.m_up = vec;
272 }
273 else
274 {
275 ASCENT_ERROR("Plane definition missing 'up'");
276 }
277
278 if(plane.has_child("normal"))
279 {
280 conduit::Node n;
281 plane["normal"].to_float64_array(n);
282 const float64 *coords = n.as_float64_ptr();
283 Vec3f vec = {{float(coords[0]), float(coords[1]), float(coords[2])}};
284 vec.normalize();
285 plane_d.m_view = vec;
286 }
287 else
288 {
289 ASCENT_ERROR("Plane definition missing 'normal'");
290 }
291
292 if(plane.has_child("width"))
293 {
294 plane_d.m_plane_width = plane["width"].to_float64();
295 }
296 else
297 {
298 ASCENT_ERROR("Plane definition missing 'width'");
299 }
300
301 if(plane.has_child("height"))
302 {
303 plane_d.m_plane_height = plane["height"].to_float64();
304 }
305 else
306 {
307 ASCENT_ERROR("Plane definition missing 'height'");
308 }
309
310 }
311
312 void
parse_camera(const conduit::Node camera_node,dray::Camera & camera)313 parse_camera(const conduit::Node camera_node, dray::Camera &camera)
314 {
315 typedef dray::Vec<float,3> Vec3f;
316 //
317 // Get the optional camera parameters
318 //
319 if(camera_node.has_child("look_at"))
320 {
321 conduit::Node n;
322 camera_node["look_at"].to_float64_array(n);
323 const float64 *coords = n.as_float64_ptr();
324 Vec3f look_at{float(coords[0]), float(coords[1]), float(coords[2])};
325 camera.set_look_at(look_at);
326 }
327
328 if(camera_node.has_child("position"))
329 {
330 conduit::Node n;
331 camera_node["position"].to_float64_array(n);
332 const float64 *coords = n.as_float64_ptr();
333 Vec3f position{float(coords[0]), float(coords[1]), float(coords[2])};
334 camera.set_pos(position);
335 }
336
337 if(camera_node.has_child("up"))
338 {
339 conduit::Node n;
340 camera_node["up"].to_float64_array(n);
341 const float64 *coords = n.as_float64_ptr();
342 Vec3f up{float(coords[0]), float(coords[1]), float(coords[2])};
343 up.normalize();
344 camera.set_up(up);
345 }
346
347 if(camera_node.has_child("fov"))
348 {
349 camera.set_fov(camera_node["fov"].to_float64());
350 }
351
352
353 // this is an offset from the current azimuth
354 if(camera_node.has_child("azimuth"))
355 {
356 double azimuth = camera_node["azimuth"].to_float64();
357 camera.azimuth(azimuth);
358 }
359 if(camera_node.has_child("elevation"))
360 {
361 double elevation = camera_node["elevation"].to_float64();
362 camera.elevate(elevation);
363 }
364
365 if(camera_node.has_child("zoom"))
366 {
367 float zoom = camera_node["zoom"].to_float32();
368 camera.set_zoom(zoom);
369 }
370 }
371
372 dray::ColorTable
parse_color_table(const conduit::Node & color_table_node)373 parse_color_table(const conduit::Node &color_table_node)
374 {
375 // default name
376 std::string color_map_name = "cool2warm";
377
378 if(color_table_node.number_of_children() == 0)
379 {
380 ASCENT_INFO("Color table node is empty (no children). Defaulting to "
381 <<color_map_name);
382 }
383
384 bool name_provided = false;
385 if(color_table_node.has_child("name"))
386 {
387 std::string name = color_table_node["name"].as_string();
388 name_provided = true;
389 std::vector<std::string> valid_names = dray::ColorTable::get_presets();
390 auto loc = find(valid_names.begin(), valid_names.end(), name);
391 if(loc != valid_names.end())
392 {
393 color_map_name = name;
394 }
395 else
396 {
397 std::stringstream ss;
398 ss<<"[";
399 for(int i = 0; i < valid_names.size(); ++i)
400 {
401 ss<<valid_names[i];
402 if(i==valid_names.size()-1)
403 {
404 ss<<"]";
405 }
406 else
407 {
408 ss<<",";
409 }
410 }
411 ASCENT_INFO("Invalid color table name '"<<name
412 <<"'. Defaulting to "<<color_map_name
413 <<". known names: "<<ss.str());
414 }
415 }
416
417 dray::ColorTable color_table(color_map_name);
418
419 if(color_table_node.has_child("control_points"))
420 {
421 bool clear = false;
422 bool clear_alphas = false;
423 // check to see if we have rgb points and clear the table
424 NodeConstIterator itr = color_table_node.fetch("control_points").children();
425 while(itr.has_next())
426 {
427 const Node &peg = itr.next();
428 if (peg["type"].as_string() == "rgb")
429 {
430 clear = true;
431 }
432 if (peg["type"].as_string() == "alpha")
433 {
434 clear_alphas = true;
435 }
436 }
437
438 if(clear && !name_provided)
439 {
440 color_table.clear_colors();
441 }
442
443 if(clear_alphas)
444 {
445 color_table.clear_alphas();
446 }
447
448 itr = color_table_node.fetch("control_points").children();
449 while(itr.has_next())
450 {
451 const Node &peg = itr.next();
452 if(!peg.has_child("position"))
453 {
454 ASCENT_WARN("Color map control point must have a position");
455 }
456
457 float64 position = peg["position"].to_float64();
458
459 if(position > 1.0 || position < 0.0)
460 {
461 ASCENT_WARN("Cannot add color map control point position "
462 << position
463 << ". Must be a normalized scalar.");
464 }
465
466 if (peg["type"].as_string() == "rgb")
467 {
468 conduit::Node n;
469 peg["color"].to_float32_array(n);
470 const float *color = n.as_float32_ptr();
471
472 dray::Vec<float,3> ecolor({color[0], color[1], color[2]});
473
474 for(int i = 0; i < 3; ++i)
475 {
476 ecolor[i] = std::min(1.f, std::max(ecolor[i], 0.f));
477 }
478
479 color_table.add_point(position, ecolor);
480 }
481 else if (peg["type"].as_string() == "alpha")
482 {
483 float alpha = peg["alpha"].to_float32();
484 alpha = std::min(1.f, std::max(alpha, 0.f));
485 color_table.add_alpha(position, alpha);
486 }
487 else
488 {
489 ASCENT_WARN("Unknown color table control point type " << peg["type"].as_string()<<
490 "\nValid types are 'alpha' and 'rgb'");
491 }
492 }
493 }
494
495 if(color_table_node.has_child("reverse"))
496 {
497 if(color_table_node["reverse"].as_string() == "true")
498 {
499 color_table.reverse();
500 }
501 }
502 return color_table;
503 }
504
505
506 class DrayCinemaManager
507 {
508 protected:
509 std::vector<dray::Camera> m_cameras;
510 std::vector<std::string> m_image_names;
511 std::vector<float> m_phi_values;
512 std::vector<float> m_theta_values;
513 std::vector<float> m_times;
514 std::string m_csv;
515
516 dray::AABB<3> m_bounds;
517 const int m_phi;
518 const int m_theta;
519 std::string m_image_name;
520 std::string m_image_path;
521 std::string m_db_path;
522 std::string m_base_path;
523 float m_time;
524
525 std::map<std::string, std::vector<float>> m_additional_params;
526
527 public:
528
529 DrayCinemaManager(dray::AABB<3> bounds,
530 const int phi,
531 const int theta,
532 const std::string image_name,
533 const std::string path,
534 const std::map<std::string, std::vector<float>> & additional_params
535 = std::map<std::string,std::vector<float>>())
536 : m_bounds(bounds),
537 m_phi(phi),
538 m_theta(theta),
539 m_image_name(image_name),
540 m_time(0.f),
541 m_additional_params(additional_params)
542 {
543 if(additional_params.size() > 1)
544 {
545 ASCENT_ERROR("only tested with 1 param");
546 }
547
548 this->create_cinema_cameras(bounds);
549
550 m_csv = "phi,theta,";
551 for(const auto ¶m : m_additional_params)
552 {
553 m_csv += param.first + ",";
554 if(param.second.size() < 1)
555 {
556 ASCENT_ERROR("Additional cinema parameter must have at least 1 value");
557 }
558 }
559 m_csv += "time,FILE\n";
560
561 m_base_path = conduit::utils::join_file_path(path, "cinema_databases");
562 }
563
DrayCinemaManager()564 DrayCinemaManager()
565 : m_phi(0),
566 m_theta(0)
567 {
568 ASCENT_ERROR("Cannot create un-initialized CinemaManger");
569 }
570
db_path()571 std::string db_path()
572 {
573 return conduit::utils::join_file_path(m_base_path, m_image_name);
574 }
575
set_bounds(dray::AABB<3> & bounds)576 void set_bounds(dray::AABB<3> &bounds)
577 {
578 if(!is_same(bounds, m_bounds))
579 {
580 this->create_cinema_cameras(bounds);
581 m_bounds = bounds;
582 }
583 }
584
add_time_step()585 void add_time_step()
586 {
587 m_times.push_back(m_time);
588
589 int rank = 0;
590 #ifdef ASCENT_MPI_ENABLED
591 MPI_Comm mpi_comm = MPI_Comm_f2c(Workspace::default_mpi_comm());
592 MPI_Comm_rank(mpi_comm, &rank);
593 #endif
594 if(rank == 0 && !conduit::utils::is_directory(m_base_path))
595 {
596 conduit::utils::create_directory(m_base_path);
597 }
598
599 // add a database path
600 m_db_path = db_path();
601
602 // note: there is an implicit assumption here that these
603 // resources are static and only need to be generated one
604 if(rank == 0 && !conduit::utils::is_directory(m_db_path))
605 {
606 conduit::utils::create_directory(m_db_path);
607
608 // load cinema web resources from compiled in resource tree
609 Node cinema_rc;
610 ascent::resources::load_compiled_resource_tree("cinema_web",
611 cinema_rc);
612 if(cinema_rc.dtype().is_empty())
613 {
614 ASCENT_ERROR("Failed to load compiled resources for cinema_web");
615 }
616
617 ascent::resources::expand_resource_tree_to_file_system(cinema_rc,
618 m_db_path);
619 }
620
621 std::stringstream ss;
622 ss<<fixed<<showpoint;
623 ss<<std::setprecision(1)<<m_time;
624 // add a time step path
625 m_image_path = conduit::utils::join_file_path(m_db_path,ss.str());
626
627 if(!conduit::utils::is_directory(m_image_path))
628 {
629 conduit::utils::create_directory(m_image_path);
630 }
631
632 m_time += 1.f;
633 }
634
635 // if we have an additional parameter then the ordering is
636 // going to be param / phi_theta in the output vectors
637
fill_cameras(std::vector<dray::Camera> & cameras,std::vector<std::string> & image_names,const conduit::Node & n_camera)638 void fill_cameras(std::vector<dray::Camera> &cameras,
639 std::vector<std::string> &image_names,
640 const conduit::Node &n_camera)
641 {
642 cameras.clear();
643 image_names.clear();
644 conduit::Node n_camera_copy = n_camera;
645
646 // allow zoom to be ajusted
647 float zoom = 1.f;
648 if(n_camera_copy.has_path("zoom"))
649 {
650 zoom = n_camera_copy["zoom"].to_float64();
651 }
652
653
654 std::string tmp_name = "";
655 const int num_renders = m_image_names.size();
656
657 if(m_additional_params.size() == 1)
658 {
659 // enforced to be a max of 1
660 for(const auto ¶m : m_additional_params)
661 {
662 const int param_size = param.second.size();
663 for(int p = 0; p < param_size; ++p)
664 {
665 const int precision = 2;
666 std::string p_string = get_string(param.second[p], precision);
667 for(int i = 0; i < num_renders; ++i)
668 {
669 dray::Camera camera = m_cameras[i];
670 camera.set_zoom(zoom);
671 cameras.push_back(camera);
672 // image names do not include the additional parameter so we add it here
673 std::string image_name = p_string + "_" + m_image_names[i];
674 image_name = conduit::utils::join_file_path(m_image_path , image_name);
675 image_names.push_back(image_name);
676 }
677 }
678 }
679 }
680 else
681 {
682 for(int i = 0; i < num_renders; ++i)
683 {
684 dray::Camera camera = m_cameras[i];
685 camera.set_zoom(zoom);
686 cameras.push_back(camera);
687 std::string image_name = conduit::utils::join_file_path(m_image_path , m_image_names[i]);
688 image_names.push_back(image_name);
689
690 }
691 }
692 }
693
694
get_string(const float value,int precision=1)695 std::string get_string(const float value, int precision = 1)
696 {
697 std::stringstream ss;
698 ss<<std::fixed<<std::setprecision(precision)<<value;
699 return ss.str();
700 }
701
write_metadata()702 void write_metadata()
703 {
704 int rank = 0;
705 #ifdef ASCENT_MPI_ENABLED
706 MPI_Comm mpi_comm = MPI_Comm_f2c(Workspace::default_mpi_comm());
707 MPI_Comm_rank(mpi_comm, &rank);
708 #endif
709 if(rank != 0)
710 {
711 return;
712 }
713 conduit::Node meta;
714 meta["type"] = "simple";
715 meta["version"] = "1.1";
716 meta["metadata/type"] = "parametric-image-stack";
717 std::string name_pattern = "{time}/";
718 for(const auto ¶m : m_additional_params)
719 {
720 name_pattern += "{" + param.first + "}_";
721 }
722 name_pattern += "{phi}_{theta}_";
723 meta["name_pattern"] = name_pattern + m_image_name + ".png";
724
725 conduit::Node times;
726 times["default"] = get_string(m_times[0]);
727 times["label"] = "time";
728 times["type"] = "range";
729 // we have to make sure that this maps to a json array
730 const int t_size = m_times.size();
731 for(int i = 0; i < t_size; ++i)
732 {
733 times["values"].append().set(get_string(m_times[i]));
734 }
735
736 meta["arguments/time"] = times;
737
738 conduit::Node phis;
739 phis["default"] = get_string(m_phi_values[0]);
740 phis["label"] = "phi";
741 phis["type"] = "range";
742 const int phi_size = m_phi_values.size();
743 for(int i = 0; i < phi_size; ++i)
744 {
745 phis["values"].append().set(get_string(m_phi_values[i]));
746 }
747
748 meta["arguments/phi"] = phis;
749
750 conduit::Node thetas;
751 thetas["default"] = get_string(m_theta_values[0]);
752 thetas["label"] = "theta";
753 thetas["type"] = "range";
754 const int theta_size = m_theta_values.size();
755 for(int i = 0; i < theta_size; ++i)
756 {
757 thetas["values"].append().set(get_string(m_theta_values[i]));
758 }
759
760 meta["arguments/theta"] = thetas;
761
762 for(const auto ¶m : m_additional_params)
763 {
764 // One note here: if the values are normalized, then
765 // bad things will happen with moving meshes. For example,
766 // if a slice is based on some offset and the mesh is moving,
767 // then the same offset will be constantly changing
768 std::string name = param.first;
769 conduit::Node add_param;
770 const int precision = 2;
771 add_param["default"] = get_string(param.second[0],precision);
772 add_param["label"] = name;
773 add_param["type"] = "range";
774 const int param_size = param.second.size();
775 for(int i = 0; i < param_size; ++i)
776 {
777 const int precision = 2;
778 add_param["values"].append().set(get_string(param.second[i],precision));
779 }
780 meta["arguments/"+name] = add_param;
781 }
782
783 meta.save(m_db_path + "/info.json","json");
784
785 // also generate info.js, a simple javascript variant of
786 // info.json that our index.html reads directly to
787 // avoid ajax
788
789 std::ofstream out_js(m_db_path + "/info.js");
790 out_js<<"var info =";
791 meta.to_json_stream(out_js);
792 out_js.close();
793
794 //append current data to our csv file
795 std::stringstream csv;
796
797 csv<<m_csv;
798 std::string current_time = get_string(m_times[t_size - 1]);
799 for(int p = 0; p < phi_size; ++p)
800 {
801 std::string phi = get_string(m_phi_values[p]);
802 for(int t = 0; t < theta_size; ++t)
803 {
804 std::string theta = get_string(m_theta_values[t]);
805
806 if(m_additional_params.size() > 0)
807 {
808
809 // we are only allowing one currently, enforced
810 // in the constructor
811 for(const auto ¶m : m_additional_params)
812 {
813 const int precision = 2;
814 const int param_size = param.second.size();
815 for(int i = 0; i < param_size; ++i)
816 {
817 const int precision = 2;
818 std::string param_val = get_string(param.second[i], precision);
819 csv<<phi<<",";
820 csv<<theta<<",";
821 csv<<current_time<<",";
822 csv<<param_val<<",";
823 csv<<current_time<<"/"<<param_val<<"_"<<phi<<"_"<<theta<<"_"<<m_image_name<<".png\n";
824 }
825 }
826 }
827 else
828 {
829 csv<<phi<<",";
830 csv<<theta<<",";
831 csv<<current_time<<",";
832 csv<<current_time<<"/"<<phi<<"_"<<theta<<"_"<<m_image_name<<".png\n";
833 }
834 }
835 }
836
837 m_csv = csv.str();
838 std::ofstream out(m_db_path + "/data.csv");
839 out<<m_csv;
840 out.close();
841
842 }
843
844 private:
create_cinema_cameras(dray::AABB<3> bounds)845 void create_cinema_cameras(dray::AABB<3> bounds)
846 {
847 m_cameras.clear();
848 m_image_names.clear();
849 using Vec3f = dray::Vec<float,3>;
850 Vec3f center = bounds.center();
851 Vec3f totalExtent;
852 totalExtent[0] = float(bounds.m_ranges[0].length());
853 totalExtent[1] = float(bounds.m_ranges[1].length());
854 totalExtent[2] = float(bounds.m_ranges[2].length());
855
856 float radius = totalExtent.magnitude() * 2.5 / 2.0;
857
858 const double pi = 3.141592653589793;
859 double phi_inc = 360.0 / double(m_phi);
860 double theta_inc = 180.0 / double(m_theta);
861 for(int p = 0; p < m_phi; ++p)
862 {
863 float phi = -180.f + phi_inc * p;
864 m_phi_values.push_back(phi);
865
866 for(int t = 0; t < m_theta; ++t)
867 {
868 float theta = theta_inc * t;
869 if (p == 0)
870 {
871 m_theta_values.push_back(theta);
872 }
873
874 const int i = p * m_theta + t;
875
876 dray::Camera camera;
877 camera.reset_to_bounds(bounds);
878
879 //
880 // spherical coords start (r=1, theta = 0, phi = 0)
881 // (x = 0, y = 0, z = 1)
882 //
883
884 Vec3f pos = {{0.f,0.f,1.f}};
885 Vec3f up = {{0.f,1.f,0.f}};
886
887 dray::Matrix<float,4,4> phi_rot;
888 dray::Matrix<float,4,4> theta_rot;
889 dray::Matrix<float,4,4> rot;
890
891 phi_rot = dray::rotate_z(phi);
892 theta_rot = dray::rotate_x(theta);
893 rot = phi_rot * theta_rot;
894
895 up = dray::transform_vector(rot, up);
896 up.normalize();
897
898 pos = dray::transform_point(rot, pos);
899 pos = pos * radius + center;
900
901 camera.set_up(up);
902 camera.set_look_at(center);
903 camera.set_pos(pos);
904 //camera.Zoom(0.2f);
905
906 std::stringstream ss;
907 ss<<get_string(phi)<<"_"<<get_string(theta)<<"_";
908
909 m_image_names.push_back(ss.str() + m_image_name);
910 m_cameras.push_back(camera);
911
912 } // theta
913 } // phi
914 }
915
916 }; // DrayCinemaManager
917
918 class DrayCinemaDatabases
919 {
920 private:
921 static std::map<std::string, DrayCinemaManager> m_databases;
922 public:
923
db_exists(std::string db_name)924 static bool db_exists(std::string db_name)
925 {
926 auto it = m_databases.find(db_name);
927 return it != m_databases.end();
928 }
929
930 static void create_db(dray::AABB<3> &bounds,
931 const int phi,
932 const int theta,
933 std::string db_name,
934 std::string path,
935 const std::map<std::string, std::vector<float>> & additional_params
936 = std::map<std::string,std::vector<float>>())
937 {
938 if(db_exists(db_name))
939 {
940 ASCENT_ERROR("Creation failed: dray cinema database already exists");
941 }
942
943 m_databases.emplace(std::make_pair(db_name, DrayCinemaManager(bounds,
944 phi,
945 theta,
946 db_name,
947 path,
948 additional_params)));
949 }
950
get_db(std::string db_name)951 static DrayCinemaManager& get_db(std::string db_name)
952 {
953 if(!db_exists(db_name))
954 {
955 ASCENT_ERROR("DRAY Cinema db '"<<db_name<<"' does not exist.");
956 }
957
958 return m_databases[db_name];
959 }
960 }; // DrayCinemaDatabases
961
962 std::map<std::string, DrayCinemaManager> DrayCinemaDatabases::m_databases;
963
964
965
check_image_names(const conduit::Node & params,conduit::Node & info)966 bool check_image_names(const conduit::Node ¶ms, conduit::Node &info)
967 {
968 bool res = true;
969 if(!params.has_path("image_prefix") &&
970 !params.has_path("camera/db_name"))
971 {
972 res = false;
973 info.append() = "Devil ray rendering paths must include either "
974 "a 'image_prefix' (if its a single image) or a "
975 "'camera/db_name' (if using a cinema camere)";
976 }
977 if(params.has_path("image_prefix") &&
978 params.has_path("camera/db_name"))
979 {
980 res = false;
981 info.append() = "Devil ray rendering paths cannot use both "
982 "a 'image_prefix' (if its a single image) and a "
983 "'camera/db_name' (if using a cinema camere)";
984 }
985 return res;
986 }
987
988 void
parse_params(const conduit::Node & params,dray::Collection * dcol,const conduit::Node * meta,std::vector<dray::Camera> & cameras,dray::ColorMap & color_map,std::string & field_name,std::vector<std::string> & image_names)989 parse_params(const conduit::Node ¶ms,
990 dray::Collection *dcol,
991 const conduit::Node *meta,
992 std::vector<dray::Camera> &cameras,
993 dray::ColorMap &color_map,
994 std::string &field_name,
995 std::vector<std::string> &image_names)
996 {
997 field_name = params["field"].as_string();
998
999 int width = 512;
1000 int height = 512;
1001
1002 if(params.has_path("image_width"))
1003 {
1004 width = params["image_width"].to_int32();
1005 }
1006
1007 if(params.has_path("image_height"))
1008 {
1009 height = params["image_height"].to_int32();
1010 }
1011
1012 dray::AABB<3> bounds = dcol->bounds();
1013
1014 if(params.has_path("camera"))
1015 {
1016 bool is_cinema = false;
1017
1018 const conduit::Node &n_camera = params["camera"];
1019 if(n_camera.has_path("type"))
1020 {
1021 if(n_camera["type"].as_string() == "cinema")
1022 {
1023 is_cinema = true;
1024 }
1025 }
1026
1027 if(is_cinema)
1028 {
1029 if(!n_camera.has_path("phi") || !n_camera.has_path("theta"))
1030 {
1031 ASCENT_ERROR("Cinema must have 'phi' and 'theta'");
1032 }
1033
1034 int phi = n_camera["phi"].to_int32();
1035 int theta = n_camera["theta"].to_int32();
1036
1037 std::string output_path = default_dir();
1038
1039 if(!n_camera.has_path("db_name"))
1040 {
1041 ASCENT_ERROR("Cinema must specify a 'db_name'");
1042 }
1043
1044 std::string db_name = n_camera["db_name"].as_string();
1045 bool exists = detail::DrayCinemaDatabases::db_exists(db_name);
1046 if(!exists)
1047 {
1048 detail::DrayCinemaDatabases::create_db(bounds,phi,theta, db_name, output_path);
1049 }
1050
1051 detail::DrayCinemaManager &manager = detail::DrayCinemaDatabases::get_db(db_name);
1052 manager.set_bounds(bounds);
1053 manager.add_time_step();
1054 manager.fill_cameras(cameras, image_names, n_camera);
1055 manager.write_metadata();
1056 }
1057 else
1058 {
1059 dray::Camera camera;
1060 camera.set_width(width);
1061 camera.set_height(height);
1062 camera.reset_to_bounds(bounds);
1063
1064 detail::parse_camera(n_camera, camera);
1065 cameras.push_back(camera);
1066 }
1067 }
1068
1069 int cycle = 0;
1070
1071 if(meta->has_path("cycle"))
1072 {
1073 cycle = (*meta)["cycle"].as_int32();
1074 }
1075
1076 if(params.has_path("image_prefix"))
1077 {
1078
1079 std::string image_name = params["image_prefix"].as_string();
1080 image_name = expand_family_name(image_name, cycle);
1081 image_name = output_dir(image_name);
1082 image_names.push_back(image_name);
1083 }
1084
1085 dray::Range scalar_range = dcol->range(field_name);
1086 dray::Range range;
1087 if(params.has_path("min_value"))
1088 {
1089 range.include(params["min_value"].to_float32());
1090 }
1091 else
1092 {
1093 range.include(scalar_range.min());
1094 }
1095
1096 if(params.has_path("max_value"))
1097 {
1098 range.include(params["max_value"].to_float32());
1099 }
1100 else
1101 {
1102 range.include(scalar_range.max());
1103 }
1104
1105 color_map.scalar_range(range);
1106
1107 bool log_scale = false;
1108 if(params.has_path("log_scale"))
1109 {
1110 if(params["log_scale"].as_string() == "true")
1111 {
1112 log_scale = true;
1113 }
1114 }
1115
1116 color_map.log_scale(log_scale);
1117
1118 if(params.has_path("color_table"))
1119 {
1120 color_map.color_table(parse_color_table(params["color_table"]));
1121 }
1122
1123
1124 }
1125
1126 }; // namespace detail
1127
1128 //-----------------------------------------------------------------------------
DRayPseudocolor()1129 DRayPseudocolor::DRayPseudocolor()
1130 :Filter()
1131 {
1132 // empty
1133 }
1134
1135 //-----------------------------------------------------------------------------
~DRayPseudocolor()1136 DRayPseudocolor::~DRayPseudocolor()
1137 {
1138 // empty
1139 }
1140
1141 //-----------------------------------------------------------------------------
1142 void
declare_interface(Node & i)1143 DRayPseudocolor::declare_interface(Node &i)
1144 {
1145 i["type_name"] = "dray_pseudocolor";
1146 i["port_names"].append() = "in";
1147 i["output_port"] = "false";
1148 }
1149
1150 //-----------------------------------------------------------------------------
1151 bool
verify_params(const conduit::Node & params,conduit::Node & info)1152 DRayPseudocolor::verify_params(const conduit::Node ¶ms,
1153 conduit::Node &info)
1154 {
1155 info.reset();
1156
1157 bool res = true;
1158
1159 res &= check_string("field",params, info, true);
1160 res &= detail::check_image_names(params, info);
1161 res &= check_numeric("min_value",params, info, false);
1162 res &= check_numeric("max_value",params, info, false);
1163 res &= check_numeric("image_width",params, info, false);
1164 res &= check_numeric("image_height",params, info, false);
1165 res &= check_string("log_scale",params, info, false);
1166 res &= check_string("annotations",params, info, false);
1167
1168 std::vector<std::string> valid_paths;
1169 std::vector<std::string> ignore_paths;
1170
1171 valid_paths.push_back("field");
1172 valid_paths.push_back("image_prefix");
1173 valid_paths.push_back("min_value");
1174 valid_paths.push_back("max_value");
1175 valid_paths.push_back("image_width");
1176 valid_paths.push_back("image_height");
1177 valid_paths.push_back("log_scale");
1178 valid_paths.push_back("annotations");
1179
1180 // filter knobs
1181 valid_paths.push_back("draw_mesh");
1182 valid_paths.push_back("line_thickness");
1183 valid_paths.push_back("line_color");
1184 res &= check_numeric("line_color",params, info, false);
1185 res &= check_numeric("line_thickness",params, info, false);
1186 res &= check_string("draw_mesh",params, info, false);
1187
1188 ignore_paths.push_back("camera");
1189 ignore_paths.push_back("color_table");
1190
1191 std::string surprises = surprise_check(valid_paths, ignore_paths, params);
1192
1193 if(params.has_path("color_table"))
1194 {
1195 surprises += detail::dray_color_table_surprises(params["color_table"]);
1196 }
1197
1198 if(surprises != "")
1199 {
1200 res = false;
1201 info["errors"].append() = surprises;
1202 }
1203 return res;
1204 }
1205
1206 //-----------------------------------------------------------------------------
1207 void
execute()1208 DRayPseudocolor::execute()
1209 {
1210 if(!input(0).check_type<DataObject>())
1211 {
1212 ASCENT_ERROR("dray pseudocolor input must be a DataObject");
1213 }
1214
1215 DataObject *d_input = input<DataObject>(0);
1216 if(!d_input->is_valid())
1217 {
1218 return;
1219 }
1220
1221 dray::Collection *dcol = d_input->as_dray_collection().get();
1222 int comm_id = -1;
1223 #ifdef ASCENT_MPI_ENABLED
1224 comm_id = flow::Workspace::default_mpi_comm();
1225 #endif
1226 bool is_3d = dcol->topo_dims() == 3;
1227
1228 dray::Collection faces = detail::boundary(*dcol);
1229
1230 std::vector<dray::Camera> cameras;
1231 dray::ColorMap color_map("cool2warm");
1232 std::string field_name;
1233 std::vector<std::string> image_names;
1234 conduit::Node meta = Metadata::n_metadata;
1235
1236 detail::parse_params(params(),
1237 &faces,
1238 &meta,
1239 cameras,
1240 color_map,
1241 field_name,
1242 image_names);
1243
1244 bool draw_mesh = false;
1245 if(params().has_path("draw_mesh"))
1246 {
1247 if(params()["draw_mesh"].as_string() == "true")
1248 {
1249 draw_mesh = true;
1250 }
1251 }
1252 float line_thickness = 0.05f;
1253 if(params().has_path("line_thickness"))
1254 {
1255 line_thickness = params()["line_thickness"].to_float32();
1256 }
1257
1258 dray::Vec<float,4> vcolor = {0.f, 0.f, 0.f, 1.f};
1259 if(params().has_path("line_color"))
1260 {
1261 conduit::Node n;
1262 params()["line_color"].to_float32_array(n);
1263 if(n.dtype().number_of_elements() != 4)
1264 {
1265 ASCENT_ERROR("line_color is expected to be 4 floating "
1266 "point values (RGBA)");
1267 }
1268 const float32 *color = n.as_float32_ptr();
1269 vcolor[0] = color[0];
1270 vcolor[1] = color[1];
1271 vcolor[2] = color[2];
1272 vcolor[3] = color[3];
1273 }
1274
1275 std::vector<dray::Array<dray::Vec<dray::float32,4>>> color_buffers;
1276 std::vector<dray::Array<dray::float32>> depth_buffers;
1277
1278 dray::Array<dray::Vec<dray::float32,4>> color_buffer;
1279
1280 std::shared_ptr<dray::Surface> surface = std::make_shared<dray::Surface>(faces);
1281 surface->field(field_name);
1282 surface->color_map(color_map);
1283 surface->line_thickness(line_thickness);
1284 surface->line_color(vcolor);
1285 surface->draw_mesh(draw_mesh);
1286
1287 dray::Renderer renderer;
1288 renderer.add(surface);
1289 renderer.use_lighting(is_3d);
1290 bool annotations = true;
1291 if(params().has_path("annotations"))
1292 {
1293 annotations = params()["annotations"].as_string() != "false";
1294 }
1295
1296 renderer.screen_annotations(annotations);
1297
1298 const int num_images = cameras.size();
1299 for(int i = 0; i < num_images; ++i)
1300 {
1301 dray::Camera &camera = cameras[i];
1302 dray::Framebuffer fb = renderer.render(camera);
1303
1304 if(dray::dray::mpi_rank() == 0)
1305 {
1306 fb.composite_background();
1307 fb.save(image_names[i]);
1308 }
1309 }
1310
1311 }
1312
1313 //-----------------------------------------------------------------------------
DRay3Slice()1314 DRay3Slice::DRay3Slice()
1315 :Filter()
1316 {
1317 // empty
1318 }
1319
1320 //-----------------------------------------------------------------------------
~DRay3Slice()1321 DRay3Slice::~DRay3Slice()
1322 {
1323 // empty
1324 }
1325
1326 //-----------------------------------------------------------------------------
1327 void
declare_interface(Node & i)1328 DRay3Slice::declare_interface(Node &i)
1329 {
1330 i["type_name"] = "dray_3slice";
1331 i["port_names"].append() = "in";
1332 i["output_port"] = "false";
1333 }
1334
1335 //-----------------------------------------------------------------------------
1336 bool
verify_params(const conduit::Node & params,conduit::Node & info)1337 DRay3Slice::verify_params(const conduit::Node ¶ms,
1338 conduit::Node &info)
1339 {
1340 info.reset();
1341
1342 bool res = true;
1343
1344 res &= check_string("field",params, info, true);
1345 res &= detail::check_image_names(params, info);
1346 res &= check_numeric("min_value",params, info, false);
1347 res &= check_numeric("max_value",params, info, false);
1348 res &= check_numeric("image_width",params, info, false);
1349 res &= check_numeric("image_height",params, info, false);
1350 res &= check_string("log_scale",params, info, false);
1351 res &= check_string("annotations",params, info, false);
1352
1353 std::vector<std::string> valid_paths;
1354 std::vector<std::string> ignore_paths;
1355
1356 valid_paths.push_back("field");
1357 valid_paths.push_back("image_prefix");
1358 valid_paths.push_back("min_value");
1359 valid_paths.push_back("max_value");
1360 valid_paths.push_back("annotations");
1361 valid_paths.push_back("image_width");
1362 valid_paths.push_back("image_height");
1363 valid_paths.push_back("log_scale");
1364
1365 // filter knobs
1366 res &= check_numeric("x_offset",params, info, false);
1367 res &= check_numeric("y_offset",params, info, false);
1368 res &= check_numeric("z_offset",params, info, false);
1369
1370 res &= check_numeric("sweep/count",params, info, false);
1371 res &= check_string("sweep/axis",params, info, false);
1372
1373 valid_paths.push_back("x_offset");
1374 valid_paths.push_back("y_offset");
1375 valid_paths.push_back("z_offset");
1376
1377 valid_paths.push_back("sweep/count");
1378 valid_paths.push_back("sweep/axis");
1379
1380 ignore_paths.push_back("camera");
1381 ignore_paths.push_back("color_table");
1382
1383 std::string surprises = surprise_check(valid_paths, ignore_paths, params);
1384
1385 if(params.has_path("color_table"))
1386 {
1387 surprises += detail::dray_color_table_surprises(params["color_table"]);
1388 }
1389
1390 if(surprises != "")
1391 {
1392 res = false;
1393 info["errors"].append() = surprises;
1394 }
1395 return res;
1396 }
1397
1398
1399 //-----------------------------------------------------------------------------
1400 void
execute()1401 DRay3Slice::execute()
1402 {
1403 if(!input(0).check_type<DataObject>())
1404 {
1405 ASCENT_ERROR("dray 3slice input must be a DataObject");
1406 }
1407
1408 DataObject *d_input = input<DataObject>(0);
1409 if(!d_input->is_valid())
1410 {
1411 return;
1412 }
1413
1414 dray::Collection *dcol = d_input->as_dray_collection().get();
1415
1416 std::vector<dray::Camera> cameras;
1417 dray::ColorMap color_map("cool2warm");
1418 std::string field_name;
1419 std::vector<std::string> image_names;
1420 conduit::Node meta = Metadata::n_metadata;
1421
1422 conduit::Node params_copy = params();
1423 bool is_cinema = false;
1424 // let it parse everything besides the camera
1425 // if we aren't doing cinema
1426 if(params_copy.has_path("camera"))
1427 {
1428 if(params_copy.has_path("camera/type"))
1429 {
1430 if(params_copy["camera/type"].as_string() == "cinema")
1431 {
1432 is_cinema = true;
1433 }
1434 }
1435
1436 if(is_cinema)
1437 {
1438 params_copy.remove_child("camera");
1439 }
1440 }
1441
1442 detail::parse_params(params_copy,
1443 dcol,
1444 &meta,
1445 cameras,
1446 color_map,
1447 field_name,
1448 image_names);
1449
1450 dray::AABB<3> bounds = dcol->bounds();
1451
1452 using Vec3f = dray::Vec<float,3>;
1453 Vec3f x_normal({1.f, 0.f, 0.f});
1454 Vec3f y_normal({0.f, 1.f, 0.f});
1455 Vec3f z_normal({0.f, 0.f, 1.f});
1456
1457 int count = 0;
1458 int axis = 0;
1459 std::vector<float> axis_sweep;
1460 bool is_sweep = false;
1461
1462 if(params().has_path("sweep"))
1463 {
1464 is_sweep = true;
1465 const conduit::Node &n_sweep = params()["sweep"];
1466
1467 if(!n_sweep.has_path("axis"))
1468 {
1469 ASCENT_ERROR("Dray 3slice param sweep requires string parameter 'axis'");
1470 }
1471
1472 if(!n_sweep.has_path("count"))
1473 {
1474 ASCENT_ERROR("Dray 3slice param sweep requires integer parameter 'count'");
1475 }
1476
1477 count = n_sweep["count"].to_int32();
1478 if(count < 1)
1479 {
1480 ASCENT_ERROR("Dray 3slice param sweep integer parameter 'count' "
1481 <<"must be greater than 0.");
1482 }
1483 std::string s_axis = n_sweep["axis"].as_string();
1484 if(s_axis == "x")
1485 {
1486 axis = 0;
1487 }
1488 else if (s_axis == "y")
1489 {
1490 axis = 1;
1491 }
1492 else if (s_axis == "z")
1493 {
1494 axis = 2;
1495 }
1496 else
1497 {
1498 ASCENT_ERROR("Dray 3slice param 'axis' invalid value '"<<s_axis<<"'"
1499 <<" Valid values are 'x', 'y', or 'z'");
1500 }
1501
1502 // this is kinda weird but lets start here. This supports a count of 1
1503 // which will put the value at the center of the range. This method will
1504 // always exclude the min and max value, and spread the values out equally.
1505 // With an infinite count, then first and last values will converge to
1506 // the min and max of the range. My initial assumption is that the extremes
1507 // will likely contain the least interesting data.
1508 double axis_inc = 1.f / double(count+1);
1509 for(int a = 1; a < count+1; ++a)
1510 {
1511 float val = axis_inc * a;
1512 axis_sweep.push_back(val);
1513 }
1514
1515 }
1516
1517 if(is_sweep && !is_cinema)
1518 {
1519 ASCENT_ERROR("3slice sweep only supported with cinema");
1520 }
1521
1522 Vec3f point = detail::planes(params(), bounds);
1523
1524 struct WorkItem
1525 {
1526 dray::Camera m_camera;
1527 std::string m_image_name;
1528 Vec3f m_point;
1529 };
1530
1531 std::vector<WorkItem> work;
1532
1533 int width = 512;
1534 int height = 512;
1535
1536 if(params().has_path("image_width"))
1537 {
1538 width = params()["image_width"].to_int32();
1539 }
1540
1541 if(params().has_path("image_height"))
1542 {
1543 height = params()["image_height"].to_int32();
1544 }
1545
1546 if(is_cinema)
1547 {
1548 cameras.clear();
1549 image_names.clear();
1550
1551 const conduit::Node &n_camera = params()["camera"];
1552 if(!n_camera.has_path("phi") || !n_camera.has_path("theta"))
1553 {
1554 ASCENT_ERROR("Cinema must have 'phi' and 'theta'");
1555 }
1556
1557 int phi = n_camera["phi"].to_int32();
1558 int theta = n_camera["theta"].to_int32();
1559
1560 std::string output_path = default_dir();
1561
1562 if(!n_camera.has_path("db_name"))
1563 {
1564 ASCENT_ERROR("Cinema must specify a 'db_name'");
1565 }
1566
1567 std::string db_name = n_camera["db_name"].as_string();
1568 bool exists = detail::DrayCinemaDatabases::db_exists(db_name);
1569
1570 if(!exists)
1571 {
1572 if(!is_sweep)
1573 {
1574 detail::DrayCinemaDatabases::create_db(bounds,phi,theta, db_name, output_path);
1575 }
1576 else
1577 {
1578 std::map<std::string, std::vector<float>> add_params;
1579 std::string s_axis = params()["sweep/axis"].as_string() + "_offset";
1580 add_params[s_axis] = axis_sweep;
1581 detail::DrayCinemaDatabases::create_db(bounds,phi,theta, db_name, output_path, add_params);
1582 }
1583 }
1584
1585 detail::DrayCinemaManager &manager = detail::DrayCinemaDatabases::get_db(db_name);
1586 manager.set_bounds(bounds);
1587 manager.add_time_step();
1588 manager.fill_cameras(cameras, image_names, n_camera);
1589 manager.write_metadata();
1590
1591 if(is_sweep)
1592 {
1593 // we need to match up the image names to the actual
1594 // parameters used for 3slice. This is why all of this
1595 // code is so ugly. Ultimately this is not the best way to do
1596 // this kind of thing (parametric image stack). The better way to
1597 // do this is to create composable images (depth buffers), and
1598 // this would allow you to compose any combinations of parameters
1599 // and not be combinatorial, but we are limited by the kinds of
1600 // viewers that LANL makes/supports.
1601 const int size = cameras.size();
1602 const int sweep_size = size / axis_sweep.size();
1603 for(int i = 0; i < size; ++i)
1604 {
1605 WorkItem work_item;
1606 work_item.m_camera = cameras[i];
1607 work_item.m_camera.set_width(width);
1608 work_item.m_camera.set_height(height);
1609 work_item.m_image_name = image_names[i];
1610 work_item.m_point = point;
1611 int sweep_idx = i / sweep_size;
1612 // axis_sweep values are normalized so we have to
1613 // un-normalize here
1614 float min_val = bounds.m_ranges[axis].min();
1615 float value = min_val
1616 + bounds.m_ranges[axis].length() * axis_sweep[sweep_idx];
1617 work_item.m_point[axis] = value;
1618 work.push_back(work_item);
1619 }
1620 }
1621 else
1622 {
1623 // normal cinema path
1624 const int size = cameras.size();
1625 for(int i = 0; i < size; ++i)
1626 {
1627 WorkItem work_item;
1628 work_item.m_camera = cameras[i];
1629 work_item.m_camera.set_width(width);
1630 work_item.m_camera.set_height(height);
1631 work_item.m_image_name = image_names[i];
1632 work_item.m_point = point;
1633 work.push_back(work_item);
1634 }
1635 }
1636 }
1637 else
1638 {
1639 WorkItem work_item;
1640 work_item.m_image_name = image_names[0];
1641 work_item.m_point = point;
1642 work_item.m_camera = cameras[0];
1643 work_item.m_camera.set_width(width);
1644 work_item.m_camera.set_height(height);
1645 work.push_back(work_item);
1646 }
1647
1648 std::shared_ptr<dray::SlicePlane> slicer_x
1649 = std::make_shared<dray::SlicePlane>(*dcol);
1650
1651 std::shared_ptr<dray::SlicePlane> slicer_y
1652 = std::make_shared<dray::SlicePlane>(*dcol);
1653
1654 std::shared_ptr<dray::SlicePlane> slicer_z
1655 = std::make_shared<dray::SlicePlane>(*dcol);
1656
1657 slicer_x->field(field_name);
1658 slicer_y->field(field_name);
1659 slicer_z->field(field_name);
1660
1661 slicer_x->color_map(color_map);
1662 slicer_y->color_map(color_map);
1663 slicer_z->color_map(color_map);
1664
1665 slicer_x->point(point);
1666 slicer_x->normal(x_normal);
1667
1668 slicer_y->point(point);
1669 slicer_y->normal(y_normal);
1670
1671 slicer_z->point(point);
1672 slicer_z->normal(z_normal);
1673
1674 dray::Renderer renderer;
1675
1676 bool annotations = true;
1677
1678 if(params().has_path("annotations"))
1679 {
1680 annotations = params()["annotations"].as_string() != "false";
1681 }
1682
1683 renderer.screen_annotations(annotations);
1684
1685 renderer.add(slicer_x);
1686 renderer.add(slicer_y);
1687 renderer.add(slicer_z);
1688
1689 const int work_amount = work.size();
1690 for(int i = 0; i < work_amount; ++i)
1691 {
1692
1693 slicer_x->point(work[i].m_point);
1694 slicer_y->point(work[i].m_point);
1695 slicer_z->point(work[i].m_point);
1696
1697 dray::Camera &camera = work[i].m_camera;
1698 dray::Framebuffer fb = renderer.render(camera);
1699
1700 if(dray::dray::mpi_rank() == 0)
1701 {
1702 fb.composite_background();
1703 fb.save(work[i].m_image_name);
1704 }
1705 }
1706 }
1707
1708 //-----------------------------------------------------------------------------
DRayVolume()1709 DRayVolume::DRayVolume()
1710 :Filter()
1711 {
1712 // empty
1713 }
1714
1715 //-----------------------------------------------------------------------------
~DRayVolume()1716 DRayVolume::~DRayVolume()
1717 {
1718 // empty
1719 }
1720
1721 //-----------------------------------------------------------------------------
1722 void
declare_interface(Node & i)1723 DRayVolume::declare_interface(Node &i)
1724 {
1725 i["type_name"] = "dray_volume";
1726 i["port_names"].append() = "in";
1727 i["output_port"] = "false";
1728 }
1729
1730 //-----------------------------------------------------------------------------
1731 bool
verify_params(const conduit::Node & params,conduit::Node & info)1732 DRayVolume::verify_params(const conduit::Node ¶ms,
1733 conduit::Node &info)
1734 {
1735 info.reset();
1736
1737 bool res = true;
1738
1739 res &= check_string("field",params, info, true);
1740 res &= detail::check_image_names(params, info);
1741 res &= check_numeric("min_value",params, info, false);
1742 res &= check_numeric("max_value",params, info, false);
1743 res &= check_numeric("image_width",params, info, false);
1744 res &= check_numeric("image_height",params, info, false);
1745 res &= check_string("log_scale",params, info, false);
1746 res &= check_string("annotations",params, info, false);
1747
1748 std::vector<std::string> valid_paths;
1749 std::vector<std::string> ignore_paths;
1750
1751 valid_paths.push_back("field");
1752 valid_paths.push_back("image_prefix");
1753 valid_paths.push_back("min_value");
1754 valid_paths.push_back("max_value");
1755 valid_paths.push_back("image_width");
1756 valid_paths.push_back("image_height");
1757 valid_paths.push_back("log_scale");
1758 valid_paths.push_back("annotations");
1759
1760 // filter knobs
1761 res &= check_numeric("samples",params, info, false);
1762 res &= check_string("use_lighing",params, info, false);
1763
1764 valid_paths.push_back("samples");
1765 valid_paths.push_back("use_lighting");
1766
1767 ignore_paths.push_back("camera");
1768 ignore_paths.push_back("color_table");
1769 ignore_paths.push_back("load_balancing");
1770
1771 std::string surprises = surprise_check(valid_paths, ignore_paths, params);
1772
1773 if(params.has_path("color_table"))
1774 {
1775 surprises += detail::dray_color_table_surprises(params["color_table"]);
1776 }
1777
1778 if(params.has_path("load_balancing"))
1779 {
1780 surprises += detail::dray_load_balance_surprises(params["load_balancing"]);
1781 }
1782
1783 if(surprises != "")
1784 {
1785 res = false;
1786 info["errors"].append() = surprises;
1787 }
1788 return res;
1789 }
1790
1791 //-----------------------------------------------------------------------------
1792 void
execute()1793 DRayVolume::execute()
1794 {
1795 if(!input(0).check_type<DataObject>())
1796 {
1797 ASCENT_ERROR("dray 3slice input must be a DataObject");
1798 }
1799
1800 DataObject *d_input = input<DataObject>(0);
1801 if(!d_input->is_valid())
1802 {
1803 return;
1804 }
1805
1806 dray::Collection *dcol = d_input->as_dray_collection().get();
1807
1808 dray::Collection dataset = *dcol;
1809
1810 std::vector<dray::Camera> cameras;
1811
1812 dray::ColorMap color_map("cool2warm");
1813 std::string field_name;
1814 std::vector<std::string> image_names;
1815 conduit::Node meta = Metadata::n_metadata;
1816
1817 detail::parse_params(params(),
1818 dcol,
1819 &meta,
1820 cameras,
1821 color_map,
1822 field_name,
1823 image_names);
1824
1825 if(color_map.color_table().number_of_alpha_points() == 0)
1826 {
1827 color_map.color_table().add_alpha (0.f, 0.00f);
1828 color_map.color_table().add_alpha (0.1f, 0.00f);
1829 color_map.color_table().add_alpha (0.3f, 0.05f);
1830 color_map.color_table().add_alpha (0.4f, 0.21f);
1831 color_map.color_table().add_alpha (1.0f, 0.9f);
1832 }
1833
1834 bool use_lighting = false;
1835 if(params().has_path("use_lighting"))
1836 {
1837 if(params()["use_lighting"].as_string() == "true")
1838 {
1839 use_lighting = true;
1840 }
1841 }
1842
1843 int samples = 100;
1844 if(params().has_path("samples"))
1845 {
1846 samples = params()["samples"].to_int32();
1847 }
1848
1849 if(params().has_path("load_balancing"))
1850 {
1851 const conduit::Node &load = params()["load_balancing"];
1852 bool enabled = true;
1853 if(load.has_path("enabled") &&
1854 load["enabled"].as_string() == "false")
1855 {
1856 enabled = false;
1857 }
1858
1859 if(enabled)
1860 {
1861 float piece_factor = 0.75f;
1862 float threshold = 2.0f;
1863 bool prefix = true;
1864 if(load.has_path("factor"))
1865 {
1866 piece_factor = load["factor"].to_float32();
1867 }
1868 if(load.has_path("threshold"))
1869 {
1870 threshold = load["threshold"].to_float32();
1871 }
1872
1873 if(load.has_path("use_prefix"))
1874 {
1875 prefix = load["use_prefix"].as_string() != "false";
1876 }
1877 dray::VolumeBalance balancer;
1878 balancer.threshold(threshold);
1879 balancer.prefix_balancing(prefix);
1880 balancer.piece_factor(piece_factor);
1881
1882 // We should have at least one camera so just use that for load
1883 // balancing. Matt: this could be bad but right now the only case
1884 // we use multiple images for is cinema
1885 dataset = balancer.execute(dataset, cameras[0], samples);
1886
1887 }
1888
1889 }
1890
1891 std::shared_ptr<dray::Volume> volume
1892 = std::make_shared<dray::Volume>(dataset);
1893
1894 volume->color_map() = color_map;
1895 volume->samples(samples);
1896 volume->field(field_name);
1897 dray::Renderer renderer;
1898 renderer.volume(volume);
1899
1900 bool annotations = true;
1901 if(params().has_path("annotations"))
1902 {
1903 annotations = params()["annotations"].as_string() != "false";
1904 }
1905 renderer.screen_annotations(annotations);
1906
1907 const int num_images = cameras.size();
1908 for(int i = 0; i < num_images; ++i)
1909 {
1910 dray::Camera &camera = cameras[i];
1911 dray::Framebuffer fb = renderer.render(camera);
1912
1913 if(dray::dray::mpi_rank() == 0)
1914 {
1915 fb.composite_background();
1916 fb.save(image_names[i]);
1917 }
1918 }
1919
1920 }
1921
1922 //-----------------------------------------------------------------------------
DRayReflect()1923 DRayReflect::DRayReflect()
1924 :Filter()
1925 {
1926 // empty
1927 }
1928
1929 //-----------------------------------------------------------------------------
~DRayReflect()1930 DRayReflect::~DRayReflect()
1931 {
1932 // empty
1933 }
1934
1935 //-----------------------------------------------------------------------------
1936 void
declare_interface(Node & i)1937 DRayReflect::declare_interface(Node &i)
1938 {
1939 i["type_name"] = "dray_reflect";
1940 i["port_names"].append() = "in";
1941 i["output_port"] = "true";
1942 }
1943
1944 //-----------------------------------------------------------------------------
1945 bool
verify_params(const conduit::Node & params,conduit::Node & info)1946 DRayReflect::verify_params(const conduit::Node ¶ms,
1947 conduit::Node &info)
1948 {
1949 info.reset();
1950
1951 bool res = true;
1952
1953 res &= check_numeric("point/x",params, info, true);
1954 res &= check_numeric("point/y",params, info, true);
1955 res &= check_numeric("point/z",params, info, false);
1956 res &= check_numeric("normal/x",params, info, true);
1957 res &= check_numeric("normal/y",params, info, true);
1958 res &= check_numeric("normal/z",params, info, false);
1959
1960 std::vector<std::string> valid_paths;
1961 std::vector<std::string> ignore_paths;
1962
1963 valid_paths.push_back("point/x");
1964 valid_paths.push_back("point/y");
1965 valid_paths.push_back("point/z");
1966 valid_paths.push_back("normal/x");
1967 valid_paths.push_back("normal/y");
1968 valid_paths.push_back("normal/z");
1969
1970
1971 std::string surprises = surprise_check(valid_paths, params);
1972
1973 if(surprises != "")
1974 {
1975 res = false;
1976 info["errors"].append() = surprises;
1977 }
1978 return res;
1979 }
1980
1981 //-----------------------------------------------------------------------------
1982 void
execute()1983 DRayReflect::execute()
1984 {
1985 if(!input(0).check_type<DataObject>())
1986 {
1987 ASCENT_ERROR("dray reflect input must be a DataObject");
1988 }
1989
1990 DataObject *d_input = input<DataObject>(0);
1991 if(!d_input->is_valid())
1992 {
1993 set_output<DataObject>(d_input);
1994 return;
1995 }
1996
1997 dray::Collection *dcol = d_input->as_dray_collection().get();
1998
1999 dray::Vec<float,3> point = {0.f, 0.f, 0.f};
2000 point[0] = params()["point/x"].to_float32();
2001 point[1] = params()["point/y"].to_float32();
2002 if(params().has_path("point/z"))
2003 {
2004 point[2] = params()["point/z"].to_float32();
2005 }
2006
2007 dray::Vec<float,3> normal= {0.f, 1.f, 0.f};
2008 normal[0] = params()["normal/x"].to_float32();
2009 normal[1] = params()["normal/y"].to_float32();
2010 if(params().has_path("normal/z"))
2011 {
2012 normal[2] = params()["normal/z"].to_float32();
2013 }
2014
2015 dray::Reflect reflector;
2016 reflector.plane(point,normal);
2017
2018 dray::Collection output = reflector.execute(*dcol);
2019
2020 for(int i = 0; i < dcol->local_size(); ++i)
2021 {
2022 dray::DataSet dset = dcol->domain(i);
2023 output.add_domain(dset);
2024 }
2025
2026 dray::Collection *output_ptr = new dray::Collection();
2027 *output_ptr = output;
2028
2029 DataObject *res = new DataObject(output_ptr);
2030 set_output<DataObject>(res);
2031 }
2032
2033
2034 //-----------------------------------------------------------------------------
DRayProject2d()2035 DRayProject2d::DRayProject2d()
2036 :Filter()
2037 {
2038 // empty
2039 }
2040
2041 //-----------------------------------------------------------------------------
~DRayProject2d()2042 DRayProject2d::~DRayProject2d()
2043 {
2044 // empty
2045 }
2046
2047 //-----------------------------------------------------------------------------
2048 void
declare_interface(Node & i)2049 DRayProject2d::declare_interface(Node &i)
2050 {
2051 i["type_name"] = "dray_project_2d";
2052 i["port_names"].append() = "in";
2053 i["output_port"] = "true";
2054 }
2055
2056 //-----------------------------------------------------------------------------
2057 bool
verify_params(const conduit::Node & params,conduit::Node & info)2058 DRayProject2d::verify_params(const conduit::Node ¶ms,
2059 conduit::Node &info)
2060 {
2061 info.reset();
2062
2063 bool res = true;
2064
2065 res &= check_numeric("image_width",params, info, false);
2066 res &= check_numeric("image_height",params, info, false);
2067
2068 std::vector<std::string> valid_paths;
2069 std::vector<std::string> ignore_paths;
2070
2071 valid_paths.push_back("image_width");
2072 valid_paths.push_back("image_height");
2073 valid_paths.push_back("fields");
2074
2075 ignore_paths.push_back("camera");
2076 ignore_paths.push_back("plane");
2077 ignore_paths.push_back("fields");
2078
2079 std::string surprises = surprise_check(valid_paths, ignore_paths, params);
2080
2081 if(surprises != "")
2082 {
2083 res = false;
2084 info["errors"].append() = surprises;
2085 }
2086 return res;
2087 }
2088
2089 //-----------------------------------------------------------------------------
2090 void
execute()2091 DRayProject2d::execute()
2092 {
2093 if(!input(0).check_type<DataObject>())
2094 {
2095 ASCENT_ERROR("dray_project2d input must be a DataObject");
2096 }
2097
2098 DataObject *d_input = input<DataObject>(0);
2099 if(!d_input->is_valid())
2100 {
2101 set_output<DataObject>(d_input);
2102 return;
2103 }
2104
2105 dray::Collection *dcol = d_input->as_dray_collection().get();
2106
2107 dray::Collection faces = detail::boundary(*dcol);
2108
2109 std::string image_name;
2110
2111 conduit::Node meta = Metadata::n_metadata;
2112 int width = 512;
2113 int height = 512;
2114
2115 if(params().has_path("image_width"))
2116 {
2117 width = params()["image_width"].to_int32();
2118 }
2119
2120 if(params().has_path("image_height"))
2121 {
2122 height = params()["image_height"].to_int32();
2123 }
2124
2125 std::vector<std::string> field_selection;
2126 if(params().has_path("fields"))
2127 {
2128 const conduit::Node &flist = params()["fields"];
2129 const int num_fields = flist.number_of_children();
2130 if(num_fields == 0)
2131 {
2132 ASCENT_ERROR("dray_project_2d field selection list must be non-empty");
2133 }
2134 for(int i = 0; i < num_fields; ++i)
2135 {
2136 const conduit::Node &f = flist.child(i);
2137 if(!f.dtype().is_string())
2138 {
2139 ASCENT_ERROR("relay_io_save field selection list values must be a string");
2140 }
2141 field_selection.push_back(f.as_string());
2142 }
2143 }
2144
2145 dray::Camera camera;
2146 camera.set_width(width);
2147 camera.set_height(height);
2148 dray::AABB<3> bounds = dcol->bounds();
2149 camera.reset_to_bounds(bounds);
2150
2151 dray::PlaneDetector plane;
2152 bool use_plane = false;
2153 if(params().has_path("plane"))
2154 {
2155 use_plane = true;
2156 detail::parse_plane(params()["plane"], plane);
2157 plane.m_x_res = width;
2158 plane.m_y_res = height;
2159 }
2160 else if(params().has_path("camera"))
2161 {
2162 const conduit::Node &n_camera = params()["camera"];
2163 detail::parse_camera(n_camera, camera);
2164 }
2165
2166 std::vector<dray::ScalarBuffer> buffers;
2167
2168
2169 std::vector<std::string> field_names;
2170
2171 std::shared_ptr<dray::Surface> surface = std::make_shared<dray::Surface>(faces);
2172 dray::ScalarRenderer renderer(surface);
2173
2174 if(field_selection.size() == 0)
2175 {
2176 field_names = faces.domain(0).fields();
2177 }
2178 else
2179 {
2180 field_names = field_selection;
2181 }
2182
2183 renderer.field_names(field_names);
2184 dray::ScalarBuffer sb;
2185 if(use_plane)
2186 {
2187 sb = renderer.render(plane);
2188 }
2189 else
2190 {
2191 sb = renderer.render(camera);
2192 }
2193
2194 conduit::Node *output = new conduit::Node();
2195 if(dray::dray::mpi_rank() == 0)
2196 {
2197 conduit::Node &dom = output->append();
2198
2199 sb.to_node(dom);
2200
2201 dom["state/domain_id"] = 0;
2202
2203 int cycle = 0;
2204
2205 if(meta.has_path("cycle"))
2206 {
2207 cycle = meta["cycle"].to_int32();
2208 }
2209 dom["state/cycle"] = cycle;
2210 if(meta.has_path("time"))
2211 {
2212 dom["state/time"] = meta["time"].to_float64();
2213 }
2214
2215 }
2216
2217 DataObject *res = new DataObject(output);
2218 set_output<DataObject>(res);
2219
2220 }
2221
2222 //-----------------------------------------------------------------------------
DRayProjectColors2d()2223 DRayProjectColors2d::DRayProjectColors2d()
2224 :Filter()
2225 {
2226 // empty
2227 }
2228
2229 //-----------------------------------------------------------------------------
~DRayProjectColors2d()2230 DRayProjectColors2d::~DRayProjectColors2d()
2231 {
2232 // empty
2233 }
2234
2235 //-----------------------------------------------------------------------------
2236 void
declare_interface(Node & i)2237 DRayProjectColors2d::declare_interface(Node &i)
2238 {
2239 i["type_name"] = "dray_project_colors_2d";
2240 i["port_names"].append() = "in";
2241 i["output_port"] = "true";
2242 }
2243
2244 //-----------------------------------------------------------------------------
2245 bool
verify_params(const conduit::Node & params,conduit::Node & info)2246 DRayProjectColors2d::verify_params(const conduit::Node ¶ms,
2247 conduit::Node &info)
2248 {
2249 info.reset();
2250
2251 bool res = true;
2252
2253 res &= check_numeric("image_width",params, info, false);
2254 res &= check_numeric("image_height",params, info, false);
2255 res &= check_string("field",params, info, true);
2256
2257 res &= check_numeric("min_value",params, info, false);
2258 res &= check_numeric("max_value",params, info, false);
2259 res &= check_numeric("image_width",params, info, false);
2260 res &= check_numeric("image_height",params, info, false);
2261 res &= check_string("log_scale",params, info, false);
2262
2263 std::vector<std::string> valid_paths;
2264 std::vector<std::string> ignore_paths;
2265
2266 valid_paths.push_back("image_width");
2267 valid_paths.push_back("image_height");
2268 valid_paths.push_back("min_value");
2269 valid_paths.push_back("max_value");
2270 valid_paths.push_back("log_scale");
2271 valid_paths.push_back("field");
2272
2273 ignore_paths.push_back("camera");
2274 ignore_paths.push_back("color_table");
2275
2276 std::string surprises = surprise_check(valid_paths, ignore_paths, params);
2277
2278 if(params.has_path("color_table"))
2279 {
2280 surprises += detail::dray_color_table_surprises(params["color_table"]);
2281 }
2282
2283 if(surprises != "")
2284 {
2285 res = false;
2286 info["errors"].append() = surprises;
2287 }
2288 return res;
2289 }
2290
2291 //-----------------------------------------------------------------------------
2292 void
execute()2293 DRayProjectColors2d::execute()
2294 {
2295 if(!input(0).check_type<DataObject>())
2296 {
2297 ASCENT_ERROR("dray_project2d input must be a DataObject");
2298 }
2299
2300 DataObject *d_input = input<DataObject>(0);
2301 if(!d_input->is_valid())
2302 {
2303 set_output<DataObject>(d_input);
2304 return;
2305 }
2306
2307 dray::Collection *dcol = d_input->as_dray_collection().get();
2308
2309 dray::Collection faces = detail::boundary(*dcol);
2310
2311 std::vector<dray::Camera> cameras;
2312 dray::ColorMap color_map("cool2warm");
2313 std::string field_name;
2314 std::vector<std::string> image_names;
2315 conduit::Node meta = Metadata::n_metadata;
2316
2317 detail::parse_params(params(),
2318 &faces,
2319 &meta,
2320 cameras,
2321 color_map,
2322 field_name,
2323 image_names);
2324
2325 if(cameras.size() != 1)
2326 {
2327 ASCENT_ERROR("DrayProjectColors: only one camera is supported (no cinema)");
2328 }
2329
2330 dray::Camera camera = cameras[0];
2331
2332 const int num_domains = faces.local_size();
2333
2334 dray::Framebuffer framebuffer (camera.get_width(), camera.get_height());
2335 std::shared_ptr<dray::Surface> surface = std::make_shared<dray::Surface>(faces);
2336
2337 dray::Array<dray::PointLight> lights;
2338 lights.resize(1);
2339 dray::PointLight light = detail::default_light(camera);
2340 dray::PointLight* light_ptr = lights.get_host_ptr();
2341 light_ptr[0] = light;
2342
2343 dray::Array<dray::Ray> rays;
2344 camera.create_rays (rays);
2345
2346 conduit::Node* image_data = new conduit::Node();
2347
2348 for(int i = 0; i < num_domains; ++i)
2349 {
2350 framebuffer.clear();
2351 surface->active_domain(i);
2352 surface->field(field_name);
2353 dray::Array<dray::RayHit> hits = surface->nearest_hit(rays);
2354 dray::Array<dray::Fragment> fragments = surface->fragments(hits);
2355 surface->shade(rays, hits, fragments, lights, framebuffer);
2356 conduit::Node &img = image_data->append();
2357 detail::frame_buffer_to_node(framebuffer, img);
2358 }
2359
2360 DataObject *res = new DataObject(image_data);
2361 set_output<DataObject>(res);
2362
2363 }
2364
2365 //-----------------------------------------------------------------------------
DRayVectorComponent()2366 DRayVectorComponent::DRayVectorComponent()
2367 :Filter()
2368 {
2369 // empty
2370 }
2371
2372 //-----------------------------------------------------------------------------
~DRayVectorComponent()2373 DRayVectorComponent::~DRayVectorComponent()
2374 {
2375 // empty
2376 }
2377
2378 //-----------------------------------------------------------------------------
2379 void
declare_interface(Node & i)2380 DRayVectorComponent::declare_interface(Node &i)
2381 {
2382 i["type_name"] = "dray_vector_component";
2383 i["port_names"].append() = "in";
2384 i["output_port"] = "true";
2385 }
2386
2387 //-----------------------------------------------------------------------------
2388 bool
verify_params(const conduit::Node & params,conduit::Node & info)2389 DRayVectorComponent::verify_params(const conduit::Node ¶ms,
2390 conduit::Node &info)
2391 {
2392 info.reset();
2393
2394 bool res = check_string("field",params, info, true);
2395 res &= check_numeric("component",params, info, true);
2396 res &= check_string("output_name",params, info, true);
2397
2398 std::vector<std::string> valid_paths;
2399 valid_paths.push_back("field");
2400 valid_paths.push_back("component");
2401 valid_paths.push_back("output_name");
2402
2403 std::string surprises = surprise_check(valid_paths, params);
2404
2405 if(surprises != "")
2406 {
2407 res = false;
2408 info["errors"].append() = surprises;
2409 }
2410
2411 return res;
2412 }
2413
2414 //-----------------------------------------------------------------------------
2415 void
execute()2416 DRayVectorComponent::execute()
2417 {
2418
2419 if(!input(0).check_type<DataObject>())
2420 {
2421 ASCENT_ERROR("dray_vector_component input must be a data object");
2422 }
2423
2424 // grab the data collection and ask for a vtkh collection
2425 // which is one vtkh data set per topology
2426 DataObject *data_object = input<DataObject>(0);
2427 if(!data_object->is_valid())
2428 {
2429 set_output<DataObject>(data_object);
2430 return;
2431 }
2432
2433 dray::Collection *dcol = data_object->as_dray_collection().get();
2434
2435 std::string field_name = params()["field"].as_string();
2436 // not really doing invalid results for dray atm
2437 //if(!collection->has_field(field_name))
2438 //{
2439 // // this creates a data object with an invalid soource
2440 // set_output<DataObject>(new DataObject());
2441 // return;
2442 //}
2443 int component = params()["component"].to_int32();
2444 std::string res_name = params()["output_name"].as_string();
2445
2446 dray::VectorComponent comp;
2447
2448 comp.field(field_name);
2449 comp.component(component);
2450 comp.output_name(res_name);
2451
2452 dray::Collection comp_output = comp.execute(*dcol);
2453 dray::Collection *output_ptr = new dray::Collection();
2454 *output_ptr = comp_output;
2455
2456 DataObject *res = new DataObject(output_ptr);
2457 set_output<DataObject>(res);
2458
2459 }
2460
2461 //-----------------------------------------------------------------------------
2462 };
2463 //-----------------------------------------------------------------------------
2464 // -- end ascent::runtime::filters --
2465 //-----------------------------------------------------------------------------
2466
2467
2468 //-----------------------------------------------------------------------------
2469 };
2470 //-----------------------------------------------------------------------------
2471 // -- end ascent::runtime --
2472 //-----------------------------------------------------------------------------
2473
2474
2475 //-----------------------------------------------------------------------------
2476 };
2477 //-----------------------------------------------------------------------------
2478 // -- end ascent:: --
2479 //-----------------------------------------------------------------------------
2480
2481
2482
2483
2484
2485