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 &params, 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 &param : 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 &param : 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 &param : 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 &param : 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 &param : 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 &params, 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 &params,
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 &params,
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 &params,
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 &params,
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 &params,
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 &params,
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 &params,
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 &params,
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