diff --git a/core/include/detray/tools/generators.hpp b/core/include/detray/tools/generators.hpp index 7f5d80f4e0..dfd97c2d36 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/volume.hpp b/plugins/svgtools/include/detray/plugins/svgtools/conversion/volume.hpp index f46e51a18b..4b005a93a7 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 401e123658..38b2a68373 100644 --- a/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp +++ b/plugins/svgtools/include/detray/plugins/svgtools/illustrator.hpp @@ -43,16 +43,8 @@ class illustrator { illustrator(const detector_t& detector, const typename detector_t::name_map& name_map, - const bool show_info) - : _detector{detector}, _name_map{name_map}, _show_info{show_info} {} - - illustrator(const detector_t& detector, - const typename detector_t::name_map& name_map, - const bool show_info, const styling::style& style) - : _detector{detector}, - _name_map{name_map}, - _show_info{show_info}, - _style{style} {} + const styling::style& style) + : _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. @@ -74,18 +66,24 @@ 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 { + if (not _hide_portals) { + auto p_portal = svgtools::conversion::portal( + context, _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 (not(surface.is_passive() and _hide_passives)) { auto p_surface = svgtools::conversion::surface( context, 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); @@ -147,8 +145,8 @@ class illustrator { _detector.volume_by_index(static_cast(index)); auto surface_descs = svgtools::utils::surface_lookup(_detector, d_volume); - for (std::size_t i = 0; i < surface_descs.size(); i++) { - const auto surface_index = surface_descs[i].index(); + for (const auto& sf_desc : surface_descs) { + const auto surface_index = sf_desc.index(); ret.add_object(draw_surface( identification + "_surface" + std::to_string(surface_index), context, surface_index, view)); @@ -164,11 +162,11 @@ class illustrator { /// convert. /// @param view the display view. /// @returns @c actsvg::svg::object of the detector's volumes. - template + template inline auto draw_volumes( const std::string& identification, const typename detector_t::geometry_context& context, - const iterator_t& indices, const view_t& view) const { + const range_t& indices, const view_t& view) const { actsvg::svg::object ret; ret._tag = "g"; ret._id = identification; @@ -272,6 +270,13 @@ class illustrator { return ret; } + /// 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; @@ -279,8 +284,10 @@ class illustrator { const actsvg::point2 _info_screen_offset{-400, 400}; const detector_t& _detector; const typename detector_t::name_map& _name_map; - const bool _show_info = false; + bool _show_info = false; + 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 6fc29d024a..763241dfa0 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 landmark_style { @@ -115,29 +146,41 @@ struct style { volume_style _volume_style; landmark_style _intersection_style; trajectory_style _trajectory_style; + bool _do_random_coloring = true; }; const surface_style surface_style1{colors::blue_theme(0.8f), 3.f}; - const surface_style surface_style2{colors::red_theme(0.8f), 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(0.8f), 5.f}; const trajectory_style trajectory_style1{colors::green_theme(1.f), 1.f}; -const style style1{volume_style1, landmark_style1, trajectory_style1}; +const style style1{volume_style1, landmark_style1, trajectory_style1, true}; +const style tableau_colorblind{volume_style2, landmark_style1, + trajectory_style1, 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); @@ -154,8 +197,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); @@ -170,12 +216,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 f2711fa625..c8f58aea70 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 527913df3b..420ca4d93d 100644 --- a/tests/unit_tests/svgtools/detectors.cpp +++ b/tests/unit_tests/svgtools/detectors.cpp @@ -42,17 +42,16 @@ int main(int, char**) { toy_detector_t::geometry_context context{}; // Creating the svg generator for the detector. - detray::svgtools::illustrator il{det, names, true}; + 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", context, 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", context, 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/groups.cpp b/tests/unit_tests/svgtools/groups.cpp index b540f945b1..1f29f4e656 100644 --- a/tests/unit_tests/svgtools/groups.cpp +++ b/tests/unit_tests/svgtools/groups.cpp @@ -45,12 +45,12 @@ int main(int, char**) { const auto svg_surface_group_xy = il.draw_surfaces( "my_surface_group1_xy", context, 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 = il.draw_surfaces( "my_surface_group1_zr", context, surface_group_indices, zr); - detray::svgtools::write_svg("test_svgtools_surface_group_zr.svg", + detray::svgtools::write_svg("test_svgtools_surface_group_zr", {axes, svg_surface_group_zr}); // Visualisation of a group of volumes. @@ -58,18 +58,18 @@ int main(int, char**) { const auto svg_volume_group_xy = il.draw_volumes( "my_volume_group1_xy", context, 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", context, 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}); // Writing SVGs to a combined file. // NOTE: The all svg object's identification must be unique in the // file! detray::svgtools::write_svg( - "test_svgtools_volume_and_surface_group.svg", + "test_svgtools_volume_and_surface_group", {axes, svg_surface_group_xy, svg_volume_group_zr}); } diff --git a/tests/unit_tests/svgtools/intersections.cpp b/tests/unit_tests/svgtools/intersections.cpp index 00efe6c5a6..7ee8dae993 100644 --- a/tests/unit_tests/svgtools/intersections.cpp +++ b/tests/unit_tests/svgtools/intersections.cpp @@ -65,7 +65,7 @@ int main(int, char**) { const auto svg_ir = il.draw_intersections(name, context, intersection_record, view); - detray::svgtools::write_svg(name + ".svg", {svg_det, svg_ir}); + detray::svgtools::write_svg(name, {svg_det, svg_ir}); index++; } diff --git a/tests/unit_tests/svgtools/masks.cpp b/tests/unit_tests/svgtools/masks.cpp index 7b1d1b6357..489bf040e5 100644 --- a/tests/unit_tests/svgtools/masks.cpp +++ b/tests/unit_tests/svgtools/masks.cpp @@ -48,8 +48,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}); // e_r, e_n_half_z, e_p_half_z, e_size detray::mask> cyl2D{0u, 100.f, -10.f, 10.f}; @@ -57,8 +56,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}); // e_half_x, e_half_y, e_size detray::mask> rec2D{0u, 100.f, 100.f}; @@ -66,8 +64,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}); // e_inner_r, e_outer_r, e_size detray::mask> rin2D{0u, 50.f, 100.f}; @@ -75,7 +72,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}); // e_half_length_0, e_half_length_1, e_half_length_2, e_divisor, e_size detray::mask> tra2D{0u, 100.f, 50.f, 200.f}; @@ -83,8 +80,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}); // e_cross_section, e_half_z detray::mask> lin2D{0u, 1.f, 100.f}; @@ -92,5 +88,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 b0be55ca9f..7b8fa004c9 100644 --- a/tests/unit_tests/svgtools/surfaces.cpp +++ b/tests/unit_tests/svgtools/surfaces.cpp @@ -47,8 +47,8 @@ int main(int, char**) { std::string name = "test_svgtools_surface" + std::to_string(i); // Visualization of portal i: const auto svg_xy = il.draw_surface(name, context, 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, context, 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 96bcfeba7f..be27a54cfe 100644 --- a/tests/unit_tests/svgtools/trajectories.cpp +++ b/tests/unit_tests/svgtools/trajectories.cpp @@ -58,7 +58,7 @@ int main(int, char**) { const auto svg_ray = il.draw_trajectory("trajectory", ray, view); const auto svg_ray_ir = il.draw_intersections("record", context, ray_ir, view); - detray::svgtools::write_svg("ray.svg", {svg_det, svg_ray, svg_ray_ir}); + detray::svgtools::write_svg("ray", {svg_det, svg_ray, svg_ray_ir}); // Constant magnetic field vector3 B{1.f * detray::unit::T, @@ -71,6 +71,5 @@ int main(int, char**) { const auto svg_helix = il.draw_trajectory("trajectory", helix, view); const auto svg_helix_ir = il.draw_intersections("record", context, helix_ir, view); - detray::svgtools::write_svg("helix.svg", - {svg_det, svg_helix, svg_helix_ir}); -} \ No newline at end of file + detray::svgtools::write_svg("helix", {svg_det, svg_helix, svg_helix_ir}); +} diff --git a/tests/unit_tests/svgtools/volumes.cpp b/tests/unit_tests/svgtools/volumes.cpp index 4c5050f284..b0d4771272 100644 --- a/tests/unit_tests/svgtools/volumes.cpp +++ b/tests/unit_tests/svgtools/volumes.cpp @@ -46,8 +46,8 @@ int main(int, char**) { std::string name = "test_svgtools_volume" + std::to_string(i); // Visualization of volume i: const auto svg_xy = il.draw_volume(name, context, 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, context, 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/validation/CMakeLists.txt b/tests/validation/CMakeLists.txt index 39727deed7..1676a980c1 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 ca10cc894a..1bac732d22 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 b28206d1f1..f991dcd010 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_visualization + "detector_visualization.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_visualization.cpp b/tests/validation/src/detector_visualization.cpp new file mode 100644 index 0000000000..8fefb05fc1 --- /dev/null +++ b/tests/validation/src/detector_visualization.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, gctx, volumes, xy); + 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, gctx, volumes, zr); + 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, gctx, surfaces, xy); + 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, gctx, surfaces, zr); + 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, gctx, xy); + 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, gctx, zr); + 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(); + } +}