Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-13 10:48:06

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file orange/orangeinp/CsgTree.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include <iostream>
0010 #include <optional>
0011 #include <unordered_map>
0012 #include <vector>
0013 
0014 #include "corecel/OpaqueId.hh"
0015 #include "corecel/math/HashUtils.hh"
0016 
0017 #include "CsgTypes.hh"
0018 
0019 namespace celeritas
0020 {
0021 namespace orangeinp
0022 {
0023 //---------------------------------------------------------------------------//
0024 /*!
0025  * DAG of constructed CSG nodes within a universe.
0026  *
0027  * Inserting a new node performs one local simplification for "join" types
0028  * (removing duplicates, replacing zero- and one- entry special cases); and all
0029  * nodes are inserted into a deduplicated map of nodes that may be further
0030  * simplified later (see \c CsgAlgorithms).
0031  *
0032  * The tree is a topologically sorted graph where the leaves are the lower node
0033  * indices. The intent is for higher nodes to be simplified to boolean values,
0034  * e.g., by representing that all points in space are inside a cylinder by
0035  * replacing a \c Joined node with \c True . To facilitate this while
0036  * preserving node indices, \c True and \c False nodes are automatically
0037  * inserted as the first two node IDs. Because \c False is represented as "not
0038  * true" during evaluation, it actually stores \c Negated{true_node_id()} and
0039  * the deduplication table maps \c False to \c false_node_id() .
0040  *
0041  * \note The node classes use aggregate initialization so cannot be created
0042  * directly as \c Node variant classes using \c std::in_place_type .
0043  */
0044 class CsgTree
0045 {
0046   public:
0047     //!@{
0048     //! \name Type aliases
0049     using Node = orangeinp::Node;
0050     using NodeId = orangeinp::NodeId;
0051     using size_type = NodeId::size_type;
0052     using Insertion = std::pair<NodeId, bool>;
0053     using Simplification = std::optional<Node>;
0054     using VecNodeId = std::vector<NodeId>;
0055     //!@}
0056 
0057   public:
0058     // Construct with no nodes except "true" and "false"
0059     CsgTree();
0060 
0061     // Add a node and return the new ID and whether it's unique
0062     Insertion insert(Node&& n);
0063 
0064     // Add a surface ID and return the new ID
0065     inline Insertion insert(LocalSurfaceId s);
0066 
0067     //! Number of nodes
0068     NodeId::size_type size() const { return nodes_.size(); }
0069 
0070     // Find the node ID of the CSG expression if it exists
0071     NodeId find(Node&& n) const;
0072 
0073     // Get a node
0074     inline Node const& operator[](NodeId node_id) const;
0075 
0076     // Replace a node with a logically equivalent one, simplifying
0077     Node exchange(NodeId node_id, Node&& n);
0078 
0079     // Simplify a single node in-place [O(1)]
0080     Simplification simplify(NodeId);
0081 
0082     // Insert a new volume which root is the node id
0083     inline void insert_volume(NodeId);
0084 
0085     //! List of volumes defined in this tree
0086     VecNodeId const& volumes() const { return volumes_; }
0087 
0088     //// STATIC HELPERS ////
0089 
0090     //! Special ID of a node that's always 'true'
0091     static constexpr NodeId true_node_id() { return NodeId{0}; }
0092     //! Special ID of a node that's always 'false'
0093     static constexpr NodeId false_node_id() { return NodeId{1}; }
0094 
0095     //! Fast check for being a trivial node
0096     static constexpr bool is_boolean_node(NodeId n)
0097     {
0098         return n.unchecked_get() < 2;
0099     }
0100 
0101   private:
0102     // Tree structure: nodes may have been simplified
0103     std::vector<Node> nodes_;
0104 
0105     // Hashed simplified nodes, including eliminated but equivalent nodes
0106     std::unordered_map<Node, NodeId> ids_;
0107 
0108     // CSG node of each volume
0109     VecNodeId volumes_;
0110 
0111     //// HELPER FUNCTIONS ////
0112 
0113     // Get a simplified node expression
0114     bool simplify(Node& n) const;
0115 
0116     // Get a node (only this class can modify the node once added)
0117     Node& at(NodeId node_id);
0118 };
0119 
0120 //---------------------------------------------------------------------------//
0121 // FREE FUNCTIONS
0122 //---------------------------------------------------------------------------//
0123 // Print the tree's contents
0124 std::ostream& operator<<(std::ostream& os, CsgTree const&);
0125 
0126 //---------------------------------------------------------------------------//
0127 // INLINE DEFINITIONS
0128 //---------------------------------------------------------------------------//
0129 /*!
0130  * Add a surface.
0131  */
0132 auto CsgTree::insert(LocalSurfaceId s) -> Insertion
0133 {
0134     return this->insert(orangeinp::Surface{s});
0135 }
0136 
0137 //---------------------------------------------------------------------------//
0138 /*!
0139  * Get a node by ID.
0140  */
0141 auto CsgTree::operator[](NodeId node_id) const -> Node const&
0142 {
0143     CELER_EXPECT(node_id < nodes_.size());
0144     return nodes_[node_id.unchecked_get()];
0145 }
0146 
0147 //---------------------------------------------------------------------------//
0148 /*!
0149  * Insert a new volume which root is the node id.
0150  */
0151 void CsgTree::insert_volume(NodeId node_id)
0152 {
0153     CELER_EXPECT(node_id < nodes_.size());
0154     volumes_.push_back(std::move(node_id));
0155 }
0156 
0157 //---------------------------------------------------------------------------//
0158 }  // namespace orangeinp
0159 }  // namespace celeritas