From d2df63e178960d82051b5c47fd224b4aeb82fd3e Mon Sep 17 00:00:00 2001 From: Joana Niermann Date: Thu, 19 Oct 2023 17:09:25 +0200 Subject: [PATCH] Implement visualization tool, that reads a generic detector and displays it as svg and dot --- core/include/detray/tools/generators.hpp | 20 ++- .../plugins/svgtools/conversion/landmark.hpp | 4 +- .../plugins/svgtools/conversion/volume.hpp | 2 +- .../detray/plugins/svgtools/illustrator.hpp | 145 ++++++++------- .../plugins/svgtools/styling/styling.hpp | 64 ++++++- .../detray/plugins/svgtools/writer.hpp | 24 ++- tests/unit_tests/svgtools/detectors.cpp | 11 +- tests/unit_tests/svgtools/grids.cpp | 6 +- tests/unit_tests/svgtools/groups.cpp | 10 +- tests/unit_tests/svgtools/intersections.cpp | 5 +- tests/unit_tests/svgtools/landmarks.cpp | 5 +- tests/unit_tests/svgtools/masks.cpp | 16 +- tests/unit_tests/svgtools/surfaces.cpp | 8 +- tests/unit_tests/svgtools/trajectories.cpp | 11 +- tests/unit_tests/svgtools/volumes.cpp | 9 +- tests/unit_tests/svgtools/web.cpp | 3 +- tests/validation/CMakeLists.txt | 1 + .../python/run_ray_scan_validation.py | 2 + tests/validation/src/CMakeLists.txt | 23 ++- tests/validation/src/detector_display.cpp | 168 ++++++++++++++++++ 20 files changed, 393 insertions(+), 144 deletions(-) create mode 100644 tests/validation/src/detector_display.cpp diff --git a/core/include/detray/tools/generators.hpp b/core/include/detray/tools/generators.hpp index 7f5d80f4e..dfd97c2d3 100644 --- a/core/include/detray/tools/generators.hpp +++ b/core/include/detray/tools/generators.hpp @@ -213,6 +213,24 @@ dvector vertices( return {lh_lc, rh_lc, rh_uc, lh_uc}; } +/** Generate vertices, specialized for masks: line + * + * @note template types are simply forwarded to mask + * + * @param sf is the surface that generates vertices + * @param ls is the number of line segments if + * + * @return a generated list of vertices + */ +template typename intersector_t, typename links_t, + typename transform3_t> +dvector vertices(const mask, + links_t, transform3_t> & /*line_mask*/, + unsigned int /*lseg*/) { + return {}; +} + /// Functor to produce vertices on a mask collection in a mask tuple container. template struct vertexer { @@ -271,4 +289,4 @@ std::vector r_phi_polygon(scalar_t rmin, scalar_t rmax, return r_phi_poly; } -} // namespace detray \ No newline at end of file +} // namespace detray diff --git a/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp index 16ae22f24..f3c5f3131 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/conversion/landmark.hpp @@ -26,7 +26,7 @@ inline auto landmark( d_intersection) { const auto position = svgtools::utils::intersection_point(context, detector, d_intersection); - return svgtools::conversion::landmark(position); + return svgtools::conversion::landmark(position); } /// @returns The proto landmark of a detray point. @@ -38,4 +38,4 @@ inline auto landmark(d_point3_t& position) { return p_lm; } -} // namespace detray::svgtools::conversion \ No newline at end of file +} // namespace detray::svgtools::conversion diff --git a/plugins/svgtools/include/detray/plugins/svgtools/conversion/volume.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/volume.hpp index f46e51a18..4b005a93a 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/conversion/volume.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/conversion/volume.hpp @@ -75,4 +75,4 @@ auto volume(const typename detector_t::geometry_context& context, surfaces); } -} // namespace detray::svgtools::conversion \ No newline at end of file +} // namespace detray::svgtools::conversion diff --git a/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp b/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp index 75b57e5c9..4ce5c0a3a 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp @@ -33,11 +33,14 @@ namespace detray::svgtools { -/// @brief SVG generator for a detector and related entities. Provides an easy -/// interface for displaying typical objects in a detector. For more -/// flexibility, use the tools in svgtools::conversion to convert detray objects -/// to their respective proto object. Use functions in svgtools::meta::display -/// and actsvg::display to display the proto objects. +/// @brief SVG generator for a detector and related entities. +/// +/// Provides an easy interface for displaying typical objects in a detector. +/// For more flexibility, use the tools in svgtools::conversion to convert +/// detray objects to their respective proto object. +/// Use functions in svgtools::meta::display and actsvg::display to display +/// the proto objects. +/// /// @note Avoid using ids containing spaces or dashes as this seems to cause /// issues (for instance regarding information boxes). Furthermore, to view /// information boxes, they must be enabled in the constructor. Furthermore the @@ -49,30 +52,14 @@ class illustrator { illustrator() = delete; /// @param detector the detector - /// @param context the geometry context + /// @param name_map naming scheme of the detector + /// @param style display style /// @note information boxes are enabled by default - illustrator(const detector_t& detector, const geometry_context& context) - : _detector{detector}, _context{context} {} - - /// @param detector the detector - /// @param context the geometry context - /// @param show_info boolean to choose if information boxes should be - /// included - illustrator(const detector_t& detector, const geometry_context& context, - const bool show_info) - : _detector{detector}, _context{context}, _show_info{show_info} {} - - /// @param detector the detector - /// @param context the geometry context - /// @param show_info boolean to choose if information boxes should be - /// included - /// @param style the styling options to apply - illustrator(const detector_t& detector, const geometry_context& context, - const bool show_info, const styling::style& style) - : _detector{detector}, - _context{context}, - _show_info{show_info}, - _style{style} {} + illustrator(const detector_t& detector, + const typename detector_t::name_map& name_map, + const styling::style& style = + detray::svgtools::styling::tableau_colorblind) + : _detector{detector}, _name_map{name_map}, _style{style} {} /// @brief Converts a detray surface in the detector to an svg. /// @param identification the id of the svg object. @@ -80,9 +67,10 @@ class illustrator { /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's surface. template - inline auto draw_surface(const std::string& identification, - const std::size_t index, - const view_t& view) const { + inline auto draw_surface( + const std::string& identification, const std::size_t index, + const view_t& view, + const typename detector_t::geometry_context& gctx = {}) const { const auto surface = detray::surface{ _detector, _detector.surface_lookup()[static_cast(index)]}; @@ -90,25 +78,35 @@ class illustrator { actsvg::svg::object svg_sur; std::array color; if (surface.is_portal()) { - auto p_portal = svgtools::conversion::portal( - _context, _detector, surface); - svgtools::styling::apply_style(p_portal, - _style._volume_style._portal_style); - std::copy(p_portal._surface._fill._fc._rgb.begin(), - p_portal._surface._fill._fc._rgb.end(), color.begin()); - svg_sur = actsvg::display::portal(identification, p_portal, view); - } else { - auto p_surface = svgtools::conversion::surface( - _context, surface); + if (!_hide_portals) { + auto p_portal = svgtools::conversion::portal( + gctx, _detector, surface); + + svgtools::styling::apply_style( + p_portal, _style._volume_style._portal_style, + _style._do_random_coloring); + + std::copy(p_portal._surface._fill._fc._rgb.begin(), + p_portal._surface._fill._fc._rgb.end(), + color.begin()); + + svg_sur = + actsvg::display::portal(identification, p_portal, view); + } + } else if (!(surface.is_passive() && _hide_passives)) { + auto p_surface = + svgtools::conversion::surface(gctx, surface); svgtools::styling::apply_style(p_surface, - _style._volume_style._surface_style); + _style._volume_style._surface_style, + _style._do_random_coloring); std::copy(p_surface._fill._fc._rgb.begin(), p_surface._fill._fc._rgb.end(), color.begin()); svg_sur = actsvg::display::surface(identification, p_surface, view); } - if (_show_info) { + if (_show_info && + !(_hide_portals && _hide_passives && !surface.is_sensitive())) { auto p_information_section = - svgtools::conversion::information_section(_context, + svgtools::conversion::information_section(gctx, surface); std::copy(color.begin(), color.end(), p_information_section._color.begin()); @@ -128,14 +126,15 @@ class illustrator { /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's surfaces. template - inline auto draw_surfaces(const std::string& identification, - const iterator_t& indices, - const view_t& view) const { + inline auto draw_surfaces( + const std::string& identification, const iterator_t& indices, + const view_t& view, + const typename detector_t::geometry_context& gctx = {}) const { auto ret = svgtools::utils::group(identification); for (const auto index : indices) { const auto svg = draw_surface( identification + "_surface" + std::to_string(index), index, - view); + view, gctx); ret.add_object(svg); } return ret; @@ -147,11 +146,13 @@ class illustrator { /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's volume. template - inline auto draw_volume(const std::string& identification, - const std::size_t index, const view_t& view) const { + inline auto draw_volume( + const std::string& identification, const std::size_t index, + const view_t& view, + const typename detector_t::geometry_context& gctx = {}) const { const auto surface_indices = svgtools::utils::surface_indices(_detector, index); - return draw_surfaces(identification, surface_indices, view); + return draw_surfaces(identification, surface_indices, view, gctx); } /// @brief Converts a collection of detray volumes in the detector to an @@ -162,14 +163,15 @@ class illustrator { /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's volumes. template - inline auto draw_volumes(const std::string& identification, - const iterator_t& indices, - const view_t& view) const { + inline auto draw_volumes( + const std::string& identification, const iterator_t& indices, + const view_t& view, + const typename detector_t::geometry_context& gctx = {}) const { auto ret = svgtools::utils::group(identification); for (const auto index : indices) { const auto svg = draw_volume(identification + "_volume" + std::to_string(index), - index, view); + index, view, gctx); ret.add_object(svg); } return ret; @@ -180,11 +182,12 @@ class illustrator { /// @param view the display view. /// @returns @c actsvg::svg::object of the detector. template - inline auto draw_detector(const std::string& identification, - const view_t& view) const { + inline auto draw_detector( + const std::string& identification, const view_t& view, + const typename detector_t::geometry_context& gctx = {}) const { auto indices = detray::views::iota(std::size_t{0u}, _detector.volumes().size()); - return draw_volumes(identification, indices, view); + return draw_volumes(identification, indices, view, gctx); } /// @brief Converts a point to an svg. @@ -214,9 +217,10 @@ class illustrator { detray::intersection2D>>& intersection_record, - const view_t& view) const { + const view_t& view, + const typename detector_t::geometry_context& gctx = {}) const { auto p_ir = svgtools::conversion::intersection_record( - _context, _detector, intersection_record); + gctx, _detector, intersection_record); svgtools::styling::apply_style(p_ir, _style._intersection_style); return svgtools::meta::display::intersection_record(identification, p_ir, view); @@ -271,14 +275,14 @@ class illustrator { detray::intersection2D>>& intersection_record, - const trajectory_t& trajectory, - const view_t& view) const { + const trajectory_t& trajectory, const view_t& view, + const typename detector_t::geometry_context& gctx = {}) const { auto ret = svgtools::utils::group(identification); auto i_style = svgtools::styling::copy_fill_colors( _style._intersection_style, _style._trajectory_style); auto p_ir = svgtools::conversion::intersection_record( - _context, _detector, intersection_record); + gctx, _detector, intersection_record); svgtools::styling::apply_style(p_ir, i_style); ret.add_object( draw_trajectory(identification + "_trajectory", trajectory, view)); @@ -299,6 +303,13 @@ class illustrator { return {}; } + /// Toggle info boxes + void show_info(bool toggle = true) { _show_info = toggle; } + /// Toggle portal surfaces + void hide_portals(bool toggle = true) { _hide_portals = toggle; } + /// Toggle passive surfaces + void hide_passives(bool toggle = true) { _hide_passives = toggle; } + private: using point3 = std::array; using point3_container = std::vector; @@ -306,9 +317,11 @@ class illustrator { const actsvg::point2 _info_screen_offset{-300, 300}; const detector_t& _detector; - const geometry_context& _context; - const bool _show_info = true; + const typename detector_t::name_map& _name_map; + bool _show_info = true; + bool _hide_portals = false; + bool _hide_passives = false; const styling::style _style = styling::style1; }; -} // namespace detray::svgtools \ No newline at end of file +} // namespace detray::svgtools diff --git a/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp b/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp index 8981c2be3..fc81d0ba1 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/styling/styling.hpp @@ -29,6 +29,10 @@ auto pick_random(container_t container) { // Black constexpr std::array black{0, 0, 0}; +constexpr std::array dark_grey{171, 171, 171}; +constexpr std::array mortar{89, 89, 89}; +constexpr std::array suva_grey{137, 137, 137}; +constexpr std::array very_light_grey{207, 207, 207}; // Red tones constexpr std::array cardinal{167, 51, 63}; @@ -36,13 +40,19 @@ constexpr std::array madder{165, 28, 48}; constexpr std::array auburn{167, 51, 63}; constexpr std::array burgundy{116, 18, 29}; constexpr std::array chocolate_cosmos{88, 12, 31}; +constexpr std::array macaroni_and_cheese{255, 188, 121}; +constexpr std::array pumpkin{255, 128, 14}; +constexpr std::array tenne{200, 82, 0}; // Blue tones constexpr std::array celestial_blue{62, 146, 204}; +constexpr std::array cerulean{0, 107, 164}; constexpr std::array lapis_lazulli{42, 98, 143}; +constexpr std::array picton_blue{95, 158, 209}; constexpr std::array prussian_blue1{19, 41, 61}; constexpr std::array prussian_blue2{22, 50, 79}; constexpr std::array indigo_dye{24, 67, 90}; +constexpr std::array sail{162, 200, 236}; // Green tones constexpr std::array celadon{190, 230, 206}; @@ -79,6 +89,27 @@ std::vector green_theme(const actsvg::scalar opacity) { {shamrock_green, opacity}}; } +// Same color circle that is used in matplot plugin +struct tableau_colorblind10 { + static std::vector grey_tones( + const actsvg::scalar opacity) { + return {{dark_grey, opacity}, + {mortar, opacity}, + {suva_grey, opacity}, + {very_light_grey, opacity}}; + } + static std::vector blue_tones( + const actsvg::scalar opacity) { + return {{cerulean, opacity}, {picton_blue, opacity}, {sail, opacity}}; + } + static std::vector red_tones( + const actsvg::scalar opacity) { + return {{tenne, opacity}, + {pumpkin, opacity}, + {macaroni_and_cheese, opacity}}; + } +}; + } // namespace colors struct grid_style { @@ -123,20 +154,27 @@ struct style { trajectory_style _trajectory_style; grid_style _grid_style; landmark_style _landmark_style; + bool _do_random_coloring = true; }; const surface_style surface_style1{colors::blue_theme(0.5f), 3.f}; - const surface_style surface_style2{colors::red_theme(0.5f), 3.f}; +const surface_style surface_style3{ + colors::tableau_colorblind10::grey_tones(0.8f), 1.f}; +const surface_style surface_style4{ + colors::tableau_colorblind10::blue_tones(0.3f), 1.5f}; +const surface_style surface_style5{ + colors::tableau_colorblind10::red_tones(0.4f), 1.f}; const link_style link_style1{1.2f}; const portal_style portal_style1{surface_style2, link_style1, false}; +const portal_style portal_style2{surface_style4, link_style1, false}; const volume_style volume_style1{surface_style1, portal_style1}; +const volume_style volume_style2{surface_style5, portal_style2}; const landmark_style landmark_style1{colors::black_theme(1.f), 1.f, 5.f, "x"}; - const landmark_style landmark_style2{colors::black_theme(1.f), 1.f, 3.f, "o"}; const grid_style grid_style1{2.f}; @@ -145,12 +183,17 @@ const trajectory_style trajectory_style1{colors::green_theme(1.f), 3.f}; const style style1{volume_style1, landmark_style1, trajectory_style1, grid_style1, landmark_style2}; +const style tableau_colorblind{volume_style2, landmark_style1, + trajectory_style1, grid_style1, + landmark_style2, false}; /// @brief Sets the style of the proto surface. template void apply_style(actsvg::proto::surface& p_surface, - const surface_style& styling) { - auto fill_color = colors::pick_random(styling._fill_colors); + const surface_style& styling, bool do_random_coloring = true) { + auto fill_color = do_random_coloring + ? colors::pick_random(styling._fill_colors) + : styling._fill_colors.front(); p_surface._fill = actsvg::style::fill(fill_color); p_surface._stroke = actsvg::style::stroke(fill_color, styling._stroke_width); @@ -167,8 +210,11 @@ void apply_style( /// @brief Sets the style of the proto portal. template void apply_style(actsvg::proto::portal& p_portal, - const portal_style& styling) { - auto fill_color = colors::pick_random(styling._surface_style._fill_colors); + const portal_style& styling, bool do_random_coloring = true) { + auto fill_color = + do_random_coloring + ? colors::pick_random(styling._surface_style._fill_colors) + : styling._surface_style._fill_colors.front(); p_portal._surface._fill = actsvg::style::fill(fill_color); p_portal._surface._stroke = actsvg::style::stroke(fill_color, styling._surface_style._stroke_width); @@ -183,12 +229,12 @@ void apply_style(actsvg::proto::portal& p_portal, /// @brief Sets the style of the proto volume. template void apply_style(actsvg::proto::volume& p_volume, - const volume_style& styling) { + const volume_style& styling, bool do_random_coloring) { for (auto& p_surface : p_volume._v_surfaces) { - apply_style(p_surface, styling._surface_style); + apply_style(p_surface, styling._surface_style, do_random_coloring); } for (auto& p_portals : p_volume._portals) { - apply_style(p_portals, styling._portal_style); + apply_style(p_portals, styling._portal_style, do_random_coloring); } } diff --git a/plugins/svgtools/include/detray/plugins/svgtools/writer.hpp b/plugins/svgtools/include/detray/plugins/svgtools/writer.hpp index f2711fa62..c8f58aea7 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/writer.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/writer.hpp @@ -9,40 +9,46 @@ // Project include(s) #include "detray/io/common/detail/file_handle.hpp" -#include "detray/io/common/detector_writer.hpp" // Actsvg include(s) #include "actsvg/core.hpp" // System include(s) +#include +#include #include namespace detray::svgtools { /// @brief Writes a collection of svgs objects to a single file. template -inline void write_svg(const std::string& path, const container_t& svgs) { +inline void write_svg(const std::string& path, const container_t& svgs, + bool replace = true) { actsvg::svg::file file; for (const actsvg::svg::object& obj : svgs) { file.add_object(obj); } - detray::io::detail::file_handle stream{path, "", - std::ios::out | std::ios::trunc}; + std::ios_base::openmode io_mode = + replace ? std::ios::out | std::ios::trunc : std::ios::out; + + detray::io::detail::file_handle stream{path, ".svg", io_mode}; *stream << file; } /// @brief Writes an svg object to a file. /// @note To avoid conflict, the ids of the svg objects must be unique. -inline void write_svg(const std::string& path, const actsvg::svg::object& svg) { - write_svg(path, std::array{svg}); +inline void write_svg(const std::string& path, const actsvg::svg::object& svg, + bool replace = true) { + write_svg(path, std::array{svg}, replace); } /// @brief Writes an svg objects to a file. /// @note To avoid conflict, the ids of the svg objects must be unique. inline void write_svg(const std::string& path, - const std::initializer_list& svgs) { + const std::initializer_list& svgs, + bool replace = true) { std::vector arg = svgs; - write_svg(path, arg); + write_svg(path, arg, replace); } -} // namespace detray::svgtools \ No newline at end of file +} // namespace detray::svgtools diff --git a/tests/unit_tests/svgtools/detectors.cpp b/tests/unit_tests/svgtools/detectors.cpp index 26a9c10f8..56ee88807 100644 --- a/tests/unit_tests/svgtools/detectors.cpp +++ b/tests/unit_tests/svgtools/detectors.cpp @@ -38,21 +38,18 @@ int main(int, char**) { // Creating the detector and geomentry context. vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - using detector_t = decltype(det); - detector_t::geometry_context context{}; // Creating the svg generator for the detector. - detray::svgtools::illustrator il{det, context}; + detray::svgtools::illustrator il{det, names}; + il.show_info(true); // Get the svg of the toy detetector in x-y view. const auto svg_xy = il.draw_detector("detector_xy", xy); // Write the svg of toy detector. - detray::svgtools::write_svg("test_svgtools_detector_xy.svg", - {xy_axis, svg_xy}); + detray::svgtools::write_svg("test_svgtools_detector_xy", {xy_axis, svg_xy}); // Get the svg of the toy detetector in z-r view. const auto svg_zr = il.draw_detector("detector_zr", zr); // Write the svg of toy detector in z-r view - detray::svgtools::write_svg("test_svgtools_detector_zr.svg", - {zr_axis, svg_zr}); + detray::svgtools::write_svg("test_svgtools_detector_zr", {zr_axis, svg_zr}); } diff --git a/tests/unit_tests/svgtools/grids.cpp b/tests/unit_tests/svgtools/grids.cpp index f2e9daa52..4420ac954 100644 --- a/tests/unit_tests/svgtools/grids.cpp +++ b/tests/unit_tests/svgtools/grids.cpp @@ -25,14 +25,12 @@ int main(int, char**) { // Creating the detector and geomentry context. vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - using detector_t = decltype(det); - detector_t::geometry_context context{}; // Creating the view. const actsvg::views::x_y view; // Creating the svg generator for the detector. - detray::svgtools::illustrator il{det, context, true}; + detray::svgtools::illustrator il{det, names}; // In this example we want to draw the grids of the volumes with indices 0, // 1, ... in the detector. @@ -53,4 +51,4 @@ int main(int, char**) { {volume_svg, *grid_svg_ptr}); } } -} \ No newline at end of file +} diff --git a/tests/unit_tests/svgtools/groups.cpp b/tests/unit_tests/svgtools/groups.cpp index 95cb21d7a..451c0c3ef 100644 --- a/tests/unit_tests/svgtools/groups.cpp +++ b/tests/unit_tests/svgtools/groups.cpp @@ -36,18 +36,16 @@ int main(int, char**) { // Creating the detector and geomentry context. vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - using detector_t = decltype(det); - detector_t::geometry_context context{}; // Creating the svg generator for the detector. - const detray::svgtools::illustrator il{det, context}; + const detray::svgtools::illustrator il{det, names}; // Visualisation of a group of surfaces. const std::array surface_group_indices{1UL, 100UL, 10UL, 200UL}; const auto svg_surface_group_xy = il.draw_surfaces("my_surface_group1_xy", surface_group_indices, xy); - detray::svgtools::write_svg("test_svgtools_surface_group_xy.svg", + detray::svgtools::write_svg("test_svgtools_surface_group_xy", {axes, svg_surface_group_xy}); const auto svg_surface_group_zr = @@ -60,12 +58,12 @@ int main(int, char**) { const auto svg_volume_group_xy = il.draw_volumes("my_volume_group1_xy", volume_group_indices, xy); - detray::svgtools::write_svg("test_svgtools_volume_group_xy.svg", + detray::svgtools::write_svg("test_svgtools_volume_group_xy", {axes, svg_volume_group_xy}); const auto svg_volume_group_zr = il.draw_volumes("my_volume_group1_zr", volume_group_indices, zr); - detray::svgtools::write_svg("test_svgtools_volume_group_zr.svg", + detray::svgtools::write_svg("test_svgtools_volume_group_zr", {axes, svg_volume_group_zr}); // We can also use the svgtools::utils to group actsvg::svg::objects into diff --git a/tests/unit_tests/svgtools/intersections.cpp b/tests/unit_tests/svgtools/intersections.cpp index 8c763b5d4..065b4458a 100644 --- a/tests/unit_tests/svgtools/intersections.cpp +++ b/tests/unit_tests/svgtools/intersections.cpp @@ -45,12 +45,11 @@ int main(int, char**) { vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); using detector_t = decltype(det); - detector_t::geometry_context context{}; using transform3_t = typename detector_t::transform3; // Creating the illustrator. - const detray::svgtools::illustrator il{det, context}; + const detray::svgtools::illustrator il{det, names}; // Drawing the detector. const auto svg_det = il.draw_detector("detector", view); @@ -76,7 +75,7 @@ int main(int, char**) { const auto svg_ir = il.draw_intersections(name, intersection_record, view); - detray::svgtools::write_svg(name + ".svg", {axes, svg_det, svg_ir}); + detray::svgtools::write_svg(name, {axes, svg_det, svg_ir}); index++; } diff --git a/tests/unit_tests/svgtools/landmarks.cpp b/tests/unit_tests/svgtools/landmarks.cpp index 792e84c44..de1a73328 100644 --- a/tests/unit_tests/svgtools/landmarks.cpp +++ b/tests/unit_tests/svgtools/landmarks.cpp @@ -35,12 +35,11 @@ int main(int, char**) { vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); using detector_t = decltype(det); - detector_t::geometry_context context{}; using point = typename detector_t::point3; // Creating the illustrator class. - const detray::svgtools::illustrator il{det, context}; + const detray::svgtools::illustrator il{det, names}; // Sometimes its useful to be able to just draw a point while debugging. // For this the draw_landmark function is available. @@ -50,4 +49,4 @@ int main(int, char**) { const auto svg_zr = il.draw_landmark("landmark", test_point, zr); detray::svgtools::write_svg("test_svgtools_landmark.svg", {svg_xy, svg_zr, axes}); -} \ No newline at end of file +} diff --git a/tests/unit_tests/svgtools/masks.cpp b/tests/unit_tests/svgtools/masks.cpp index 9b18c3251..69b7eb628 100644 --- a/tests/unit_tests/svgtools/masks.cpp +++ b/tests/unit_tests/svgtools/masks.cpp @@ -50,8 +50,7 @@ int main(int, char**) { detray::svgtools::conversion::surface(transform, ann2D); const auto ann2D_svg = actsvg::display::surface("", ann2D_proto, view); - detray::svgtools::write_svg("test_svgtools_annulus2D.svg", - {axes, ann2D_svg}); + detray::svgtools::write_svg("test_svgtools_annulus2D", {axes, ann2D_svg}); // Visualize a 2D cylinder. // e_r, e_n_half_z, e_p_half_z, e_size @@ -60,8 +59,7 @@ int main(int, char**) { detray::svgtools::conversion::surface(transform, cyl2D); const auto cyl2D_svg = actsvg::display::surface("", cyl2D_proto, view); - detray::svgtools::write_svg("test_svgtools_cylinder2D.svg", - {axes, cyl2D_svg}); + detray::svgtools::write_svg("test_svgtools_cylinder2D", {axes, cyl2D_svg}); // Visualize a 2D rectangle. // e_half_x, e_half_y, e_size @@ -70,8 +68,7 @@ int main(int, char**) { detray::svgtools::conversion::surface(transform, rec2D); const auto rec2D_svg = actsvg::display::surface("", rec2D_proto, view); - detray::svgtools::write_svg("test_svgtools_rectangle2D.svg", - {axes, rec2D_svg}); + detray::svgtools::write_svg("test_svgtools_rectangle2D", {axes, rec2D_svg}); // Visualize a 2D ring. // e_inner_r, e_outer_r, e_size @@ -80,7 +77,7 @@ int main(int, char**) { detray::svgtools::conversion::surface(transform, rin2D); const auto rin2D_svg = actsvg::display::surface("", rin2D_proto, view); - detray::svgtools::write_svg("test_svgtools_ring2D.svg", {axes, rin2D_svg}); + detray::svgtools::write_svg("test_svgtools_ring2D", {axes, rin2D_svg}); // Visualize a 2D trapezoid. // e_half_length_0, e_half_length_1, e_half_length_2, e_divisor, e_size @@ -89,8 +86,7 @@ int main(int, char**) { detray::svgtools::conversion::surface(transform, tra2D); const auto tra2D_svg = actsvg::display::surface("", tra2D_proto, view); - detray::svgtools::write_svg("test_svgtools_trapezoid2D.svg", - {axes, tra2D_svg}); + detray::svgtools::write_svg("test_svgtools_trapezoid2D", {axes, tra2D_svg}); // Visualize a line. // e_cross_section, e_half_z @@ -99,5 +95,5 @@ int main(int, char**) { detray::svgtools::conversion::surface(transform, lin2D); const auto lin2D_svg = actsvg::display::surface("", lin2D_proto, view); - detray::svgtools::write_svg("test_svgtools_line2D.svg", {axes, lin2D_svg}); + detray::svgtools::write_svg("test_svgtools_line2D", {axes, lin2D_svg}); } diff --git a/tests/unit_tests/svgtools/surfaces.cpp b/tests/unit_tests/svgtools/surfaces.cpp index 457464fd1..1b25d92b5 100644 --- a/tests/unit_tests/svgtools/surfaces.cpp +++ b/tests/unit_tests/svgtools/surfaces.cpp @@ -40,11 +40,9 @@ int main(int, char**) { // Creating the detector and geomentry context. vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - using detector_t = decltype(det); - detector_t::geometry_context context{}; // Creating the svg generator for the detector. - const detray::svgtools::illustrator il{det, context}; + const detray::svgtools::illustrator il{det, names}; // Indexes of the surfaces in the detector to be visualized. std::array indices{200UL, 201UL, 202UL, 203UL, 204UL}; @@ -53,8 +51,8 @@ int main(int, char**) { std::string name = "test_svgtools_surface" + std::to_string(i); // Visualization of surface/portal i: const auto svg_xy = il.draw_surface(name, i, xy); - detray::svgtools::write_svg(name + "_xy.svg", {axes, svg_xy}); + detray::svgtools::write_svg(name + "_xy", {axes, svg_xy}); const auto svg_zr = il.draw_surface(name, i, zr); - detray::svgtools::write_svg(name + "_zr.svg", {axes, svg_zr}); + detray::svgtools::write_svg(name + "_zr", {axes, svg_zr}); } } diff --git a/tests/unit_tests/svgtools/trajectories.cpp b/tests/unit_tests/svgtools/trajectories.cpp index 11dd009a5..3c74155f6 100644 --- a/tests/unit_tests/svgtools/trajectories.cpp +++ b/tests/unit_tests/svgtools/trajectories.cpp @@ -45,10 +45,9 @@ int main(int, char**) { vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); using detector_t = decltype(det); - detector_t::geometry_context context{}; // Creating the illustrator. - const detray::svgtools::illustrator il{det, context, true}; + const detray::svgtools::illustrator il{det, names}; // Show the relevant volumes in the detector. const auto svg_volumes = @@ -59,7 +58,7 @@ int main(int, char**) { using vector3 = typename detector_t::vector3; const typename detector_t::point3 ori{0.f, 0.f, 80.f}; - const typename detector_t::point3 dir{0, 1, 1}; + const typename detector_t::point3 dir{0, 1.f, 1.f}; const detray::detail::ray ray(ori, 0.f, dir, 0.f); const auto ray_ir = detray::particle_gun::shoot_particle(det, ray); @@ -70,7 +69,7 @@ int main(int, char**) { // Draw the intersections. const auto svg_ray_ir = il.draw_intersections("record", ray_ir, view); - detray::svgtools::write_svg("test_svgtools_ray.svg", + detray::svgtools::write_svg("test_svgtools_ray", {svg_volumes, svg_ray, svg_ray_ir}); // Creating a helix trajectory. @@ -89,6 +88,6 @@ int main(int, char**) { // Draw the intersections. const auto svg_helix_ir = il.draw_intersections("record", helix_ir, view); - detray::svgtools::write_svg("test_svgtools_helix.svg", + detray::svgtools::write_svg("test_svgtools_helix", {svg_volumes, svg_helix, svg_helix_ir}); -} \ No newline at end of file +} diff --git a/tests/unit_tests/svgtools/volumes.cpp b/tests/unit_tests/svgtools/volumes.cpp index 22325eb10..5fa1915ac 100644 --- a/tests/unit_tests/svgtools/volumes.cpp +++ b/tests/unit_tests/svgtools/volumes.cpp @@ -40,22 +40,21 @@ int main(int, char**) { // Creating the detector and geomentry context. vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); - using detector_t = decltype(det); - detector_t::geometry_context context{}; // Creating the svg generator for the detector. - const detray::svgtools::illustrator il{det, context}; + const detray::svgtools::illustrator il{det, names}; // Indexes of the volumes in the detector to be visualized. std::array indices{0UL, 1UL, 2UL, 3UL, 4UL, 5UL, 6UL, 7UL, 8UL, 9UL, 10UL, 11UL, 12UL, 13UL, 14UL, 15UL, 16UL, 17UL, 18UL, 19UL}; + for (std::size_t i : indices) { std::string name = "test_svgtools_volume" + std::to_string(i); // Visualization of volume i: const auto svg_xy = il.draw_volume(name, i, xy); - detray::svgtools::write_svg(name + "_xy.svg", {axes, svg_xy}); + detray::svgtools::write_svg(name + "_xy", {axes, svg_xy}); const auto svg_zr = il.draw_volume(name, i, zr); - detray::svgtools::write_svg(name + "_zr.svg", {axes, svg_zr}); + detray::svgtools::write_svg(name + "_zr", {axes, svg_zr}); } } diff --git a/tests/unit_tests/svgtools/web.cpp b/tests/unit_tests/svgtools/web.cpp index 5223d16b7..5ea01fdfe 100644 --- a/tests/unit_tests/svgtools/web.cpp +++ b/tests/unit_tests/svgtools/web.cpp @@ -43,13 +43,12 @@ int main(int, char**) { vecmem::host_memory_resource host_mr; const auto [det, names] = detray::create_toy_geometry(host_mr); using detector_t = decltype(det); - detector_t::geometry_context context{}; using transform3_t = typename detector_t::transform3; using vector3 = typename detector_t::vector3; // Creating the svg generator for the detector. - const detray::svgtools::illustrator il{det, context}; + const detray::svgtools::illustrator il{det, names}; // The vector of svgs that we want to include on the webpage. std::vector svgs; diff --git a/tests/validation/CMakeLists.txt b/tests/validation/CMakeLists.txt index 39727deed..1676a980c 100644 --- a/tests/validation/CMakeLists.txt +++ b/tests/validation/CMakeLists.txt @@ -9,6 +9,7 @@ include( CMakeFindDependencyMacro ) find_dependency( Boost COMPONENTS program_options ) add_library( detray_validation INTERFACE ) +add_library( detray::validation ALIAS detray_validation ) target_include_directories( detray_validation INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include" ) diff --git a/tests/validation/python/run_ray_scan_validation.py b/tests/validation/python/run_ray_scan_validation.py index ca10cc894..1bac732d2 100644 --- a/tests/validation/python/run_ray_scan_validation.py +++ b/tests/validation/python/run_ray_scan_validation.py @@ -46,8 +46,10 @@ def __main__(): help=("z range for the xy-view."), default = [-50, 50], type=float) parser.add_argument("--hide_portals", + help=("Hide intersections with portal surfaces."), action="store_true", default=False) parser.add_argument("--hide_passives", + help=("Hide intersections with passive surfaces."), action="store_true", default=False) args = parser.parse_args() diff --git a/tests/validation/src/CMakeLists.txt b/tests/validation/src/CMakeLists.txt index b28206d1f..030159e5e 100644 --- a/tests/validation/src/CMakeLists.txt +++ b/tests/validation/src/CMakeLists.txt @@ -4,26 +4,39 @@ # #Mozilla Public License Version 2.0 +# Silence actsvg internal warnings +include_directories( SYSTEM $ ) +include_directories( SYSTEM $ ) + +# Build the visualization executable. +detray_add_executable(detector_display + "detector_display.cpp" + LINK_LIBRARIES GTest::gtest GTest::gtest_main Boost::program_options + detray::utils detray::core_array detray::svgtools) + # Build the validation executable. detray_add_executable(detector_validation "detector_validation.cpp" LINK_LIBRARIES GTest::gtest GTest::gtest_main - detray_validation) + detray::validation) detray_add_executable(material_validation "material_validation.cpp" LINK_LIBRARIES GTest::gtest GTest::gtest_main - detray_validation) + detray::validation) # Build the CI tests detray_add_test(telescope_detector "telescope_detector_validation.cpp" - LINK_LIBRARIES GTest::gtest GTest::gtest_main detray_validation) + LINK_LIBRARIES GTest::gtest GTest::gtest_main + detray::validation) detray_add_test(toy_detector "toy_detector_validation.cpp" - LINK_LIBRARIES GTest::gtest GTest::gtest_main detray_validation) + LINK_LIBRARIES GTest::gtest GTest::gtest_main + detray::validation) detray_add_test(wire_chamber "wire_chamber_validation.cpp" - LINK_LIBRARIES GTest::gtest GTest::gtest_main detray_validation) + LINK_LIBRARIES GTest::gtest GTest::gtest_main + detray::validation) diff --git a/tests/validation/src/detector_display.cpp b/tests/validation/src/detector_display.cpp new file mode 100644 index 000000000..1f81373f0 --- /dev/null +++ b/tests/validation/src/detector_display.cpp @@ -0,0 +1,168 @@ +/** Detray library, part of the ACTS project (R&D line) + * + * (c) 2023 CERN for the benefit of the ACTS project + * + * Mozilla Public License Version 2.0 + */ + +// Project include(s) +#include "detray/core/detector.hpp" +#include "detray/geometry/volume_graph.hpp" +#include "detray/io/common/detector_reader.hpp" +#include "detray/plugins/svgtools/illustrator.hpp" +#include "detray/plugins/svgtools/writer.hpp" + +// Vecmem include(s) +#include + +// Actsvg include(s) +#include "actsvg/core.hpp" + +// GTest include(s) +#include + +// Boost +#include + +// System include(s) +#include +#include +#include +#include + +namespace po = boost::program_options; +using namespace detray; + +int main(int argc, char **argv) { + + // Use the most general type to be able to read in all detector files + using detector_t = detray::detector<>; + + // Visualization style to be applied to the svgs + auto style = detray::svgtools::styling::tableau_colorblind; + + // Filter out the google test flags + ::testing::InitGoogleTest(&argc, argv); + + // Options parsing + po::options_description desc("\ndetray detector validation options"); + + std::vector volumes, surfaces; + desc.add_options()("help", "produce help message")( + "outdir", po::value(), "Output directory for plots")( + "geometry_file", po::value(), "Geometry input file")( + "volumes", po::value>(&volumes)->multitoken(), + "List of volumes that should be displayed")( + "surfaces", po::value>(&surfaces)->multitoken(), + "List of surfaces that should be displayed")( + "hide_portals", "Hide portal surfaces")("hide_passives", + "Hide passive surfaces")( + "show_info", "Show info boxes")("write_volume_graph", + "Writes the volume graph to file"); + + po::variables_map vm; + po::store(parse_command_line(argc, argv, desc, + po::command_line_style::unix_style ^ + po::command_line_style::allow_short), + vm); + po::notify(vm); + + // Configs to be filled + detray::io::detector_reader_config reader_cfg{}; + + // Help message + if (vm.count("help")) { + std::cout << desc << std::endl; + return EXIT_FAILURE; + } + + // General options + std::string outdir{vm.count("outdir") ? vm["outdir"].as() + : "./plots/"}; + auto path = std::filesystem::path(outdir); + if (not std::filesystem::exists(path)) { + std::error_code err; + if (!std::filesystem::create_directories(path, err)) { + throw std::runtime_error(err.message()); + } + } + + // Input files + if (vm.count("geometry_file")) { + reader_cfg.add_file(vm["geometry_file"].as()); + } else { + std::stringstream err_stream{}; + err_stream << "Please specify a geometry input file!\n\n" << desc; + + throw std::invalid_argument(err_stream.str()); + } + + // Read the detector geometry + vecmem::host_memory_resource host_mr; + + const auto [det, names] = + detray::io::read_detector(host_mr, reader_cfg); + detector_t::geometry_context gctx{}; + + // Creating the svg generator for the detector. + detray::svgtools::illustrator il{det, names, style}; + il.show_info(vm.count("show_info")); + il.hide_portals(vm.count("hide_portals")); + il.hide_passives(vm.count("hide_passives")); + + actsvg::style::stroke stroke_black = actsvg::style::stroke(); + + // x-y axis. + auto xy_axis = actsvg::draw::x_y_axes("axes", {-250, 250}, {-250, 250}, + stroke_black, "x", "y"); + // z-r axis. + auto zr_axis = actsvg::draw::x_y_axes("axes", {-2000, 2000}, {-5, 250}, + stroke_black, "z", "r"); + + // Creating the views. + const actsvg::views::x_y xy; + const actsvg::views::z_r zr; + + // Display the volumes + if (not volumes.empty()) { + std::string name_xy = names.at(0) + "_volume_display_xy"; + const auto vol_xy_svg = il.draw_volumes(name_xy, volumes, xy, gctx); + detray::svgtools::write_svg(path / name_xy, {xy_axis, vol_xy_svg}); + + std::string name_zr = names.at(0) + "_volume_display_zr"; + const auto vol_zr_svg = il.draw_volumes(name_zr, volumes, zr, gctx); + detray::svgtools::write_svg(path / name_zr, {zr_axis, vol_zr_svg}); + } + + // Display the surfaces + if (not surfaces.empty()) { + std::string name_xy = names.at(0) + "_surface_display_xy"; + const auto sf_xy_svg = il.draw_surfaces(name_xy, surfaces, xy, gctx); + detray::svgtools::write_svg(name_xy, {xy_axis, sf_xy_svg}); + + std::string name_zr = names.at(0) + "_surface_display_zr"; + const auto sf_zr_svg = il.draw_surfaces(name_zr, surfaces, zr, gctx); + detray::svgtools::write_svg(path / name_zr, {zr_axis, sf_zr_svg}); + } + + // If nothing was specified, display the whole detector + if (volumes.empty() and surfaces.empty()) { + std::string name_xy = names.at(0) + "_display_xy"; + const auto det_xy_svg = il.draw_detector(name_xy, xy, gctx); + detray::svgtools::write_svg(path / name_xy, {xy_axis, det_xy_svg}); + + std::string name_zr = names.at(0) + "_display_zr"; + const auto det_zr_svg = il.draw_detector(name_zr, zr, gctx); + detray::svgtools::write_svg(path / name_zr, {zr_axis, det_zr_svg}); + } + + // Display the detector volume graph + if (vm.count("write_volume_graph")) { + detray::volume_graph graph(det); + + detray::io::detail::file_handle stream{ + path / (names.at(0) + "_volume_graph.dot"), + std::ios::out | std::ios::trunc}; + *stream << graph.to_dot_string(); + } +}