Skip to content

Commit

Permalink
Add utilities for building UnitInput from CsgTree (celeritas-proj…
Browse files Browse the repository at this point in the history
…ect#1155)

* Add geo setup
* Add find_sorted
* Refactor `build_postfix` into a function that takes a remapping function
* Further refactor postfix construction to split faces from logic
* Explicitly use node type for csg tree size for documentation
* Rename exterior volume name and add global universe
* Add exterior bounding box helper
* Move postfix builder to a separate file
* Add internal surface mapper
  • Loading branch information
sethrj committed Mar 21, 2024
1 parent 71b7a9e commit edf7937
Show file tree
Hide file tree
Showing 23 changed files with 893 additions and 180 deletions.
29 changes: 29 additions & 0 deletions src/corecel/math/Algorithms.hh
Expand Up @@ -253,6 +253,35 @@ CELER_FORCEINLINE_FUNCTION ForwardIt upper_bound(ForwardIt first,
return ::celeritas::upper_bound(first, last, value, Less<>{});
}

//---------------------------------------------------------------------------//
/*!
* Find the given element in a sorted range.
*/
template<class ForwardIt, class T, class Compare>
inline CELER_FUNCTION ForwardIt
find_sorted(ForwardIt first, ForwardIt last, T const& value, Compare comp)
{
auto iter = ::celeritas::lower_bound(first, last, value, comp);
if (iter == last || comp(*iter, value) || comp(value, *iter))
{
// Insertion point is off the end, or value is not equal
return last;
}
return iter;
}

//---------------------------------------------------------------------------//
/*!
* Find the given element in a sorted range.
*/
template<class ForwardIt, class T>
CELER_FORCEINLINE_FUNCTION ForwardIt find_sorted(ForwardIt first,
ForwardIt last,
T const& value)
{
return ::celeritas::find_sorted(first, last, value, Less<>{});
}

//---------------------------------------------------------------------------//
/*!
* Partition elements in the given range, "true" before "false".
Expand Down
3 changes: 3 additions & 0 deletions src/orange/CMakeLists.txt
Expand Up @@ -39,8 +39,11 @@ list(APPEND SOURCES
orangeinp/detail/BuildConvexRegion.cc
orangeinp/detail/ConvexSurfaceState.cc
orangeinp/detail/CsgUnitBuilder.cc
orangeinp/detail/InternalSurfaceFlagger.cc
orangeinp/detail/LocalSurfaceInserter.cc
orangeinp/detail/NodeSimplifier.cc
orangeinp/detail/PostfixLogicBuilder.cc
orangeinp/detail/ProtoMap.cc
orangeinp/detail/TransformInserter.cc
orangeinp/detail/VolumeBuilder.cc
surf/ConeAligned.cc
Expand Down
7 changes: 5 additions & 2 deletions src/orange/OrangeData.hh
Expand Up @@ -27,8 +27,11 @@ namespace celeritas
// PARAMS
//---------------------------------------------------------------------------//

// VolumeId of exterior volume for all universe types
static inline constexpr LocalVolumeId local_orange_outside_volume{0};
//! Local ID of exterior volume for unit-type universes
static inline constexpr LocalVolumeId orange_exterior_volume{0};

//! ID of the top-level (global/world, level=0) universe (scene)
static inline constexpr UniverseId orange_global_universe{0};

//---------------------------------------------------------------------------//
/*!
Expand Down
4 changes: 2 additions & 2 deletions src/orange/OrangeTrackView.hh
Expand Up @@ -439,7 +439,7 @@ CELER_FUNCTION bool OrangeTrackView::is_outside() const
// Zeroth volume in outermost universe is always the exterior by
// construction in ORANGE
auto lsa = this->make_lsa(LevelId{0});
return lsa.vol() == local_orange_outside_volume;
return lsa.vol() == orange_exterior_volume;
}

//---------------------------------------------------------------------------//
Expand Down Expand Up @@ -629,7 +629,7 @@ CELER_FUNCTION void OrangeTrackView::cross_boundary()
// rather than segfaulting
// TODO: error correction or more graceful failure than losing
// energy
tinit.volume = local_orange_outside_volume;
tinit.volume = orange_exterior_volume;
tinit.surface = {};
}

Expand Down
2 changes: 1 addition & 1 deletion src/orange/detail/UnitInserter.cc
Expand Up @@ -288,7 +288,7 @@ UniverseId UnitInserter::operator()(UnitInput const& inp)

// Simple safety if all volumes provide support, excluding the external
// volume, which appears first in the list
static_assert(local_orange_outside_volume == LocalVolumeId{0});
static_assert(orange_exterior_volume == LocalVolumeId{0});
unit.simple_safety = std::all_of(
vol_records.begin() + 1, vol_records.end(), [](VolumeRecord const& v) {
return supports_simple_safety(v.flags);
Expand Down
2 changes: 1 addition & 1 deletion src/orange/orangeinp/CsgTree.hh
Expand Up @@ -64,7 +64,7 @@ class CsgTree
inline Insertion insert(LocalSurfaceId s);

//! Number of nodes
size_type size() const { return nodes_.size(); }
NodeId::size_type size() const { return nodes_.size(); }

// Get a node
inline Node const& operator[](NodeId node_id) const;
Expand Down
16 changes: 0 additions & 16 deletions src/orange/orangeinp/CsgTreeUtils.cc
Expand Up @@ -16,7 +16,6 @@

#include "detail/InfixStringBuilder.hh"
#include "detail/NodeReplacementInserter.hh"
#include "detail/PostfixLogicBuilder.hh"

namespace celeritas
{
Expand Down Expand Up @@ -103,21 +102,6 @@ void simplify(CsgTree* tree, NodeId start)
}
}

//---------------------------------------------------------------------------//
/*!
* Convert a node to postfix notation.
*/
[[nodiscard]] std::vector<LocalSurfaceId::size_type>
build_postfix(CsgTree const& tree, NodeId n)
{
CELER_EXPECT(n < tree.size());
std::vector<LocalSurfaceId::size_type> result;
detail::PostfixLogicBuilder build_impl{tree, &result};

build_impl(n);
return result;
}

//---------------------------------------------------------------------------//
/*!
* Convert a node to an infix string expression.
Expand Down
4 changes: 0 additions & 4 deletions src/orange/orangeinp/CsgTreeUtils.hh
Expand Up @@ -31,10 +31,6 @@ orangeinp::NodeId simplify_up(CsgTree* tree, orangeinp::NodeId start);
// Simplify the tree iteratively
void simplify(CsgTree* tree, orangeinp::NodeId start);

// Convert a node to postfix notation
[[nodiscard]] std::vector<LocalSurfaceId::size_type>
build_postfix(CsgTree const& tree, orangeinp::NodeId n);

// Transform a CSG node into a string expression
[[nodiscard]] std::string
build_infix_string(CsgTree const& tree, orangeinp::NodeId n);
Expand Down
11 changes: 7 additions & 4 deletions src/orange/orangeinp/ProtoInterface.hh
Expand Up @@ -17,7 +17,11 @@ namespace celeritas
namespace orangeinp
{
class ObjectInterface;
class GlobalBuilder;

namespace detail
{
class InputBuilder;
} // namespace detail

//---------------------------------------------------------------------------//
/*!
Expand All @@ -31,8 +35,6 @@ class GlobalBuilder;
* - a list of daughter Protos that are placed inside the current one.
*
* The graph of Proto daughters must be acyclic.
*
* \todo GLOBAL BUILDER IS NOT YET IMPLEMENTED.
*/
class ProtoInterface
{
Expand All @@ -42,6 +44,7 @@ class ProtoInterface
using SPConstObject = std::shared_ptr<ObjectInterface const>;
using SPConstProto = std::shared_ptr<ProtoInterface const>;
using VecProto = std::vector<ProtoInterface const*>;
using InputBuilder = detail::InputBuilder;
//!@}

public:
Expand All @@ -55,7 +58,7 @@ class ProtoInterface
virtual VecProto daughters() const = 0;

//! Construct a universe input from this object
virtual void build(GlobalBuilder&) const = 0;
virtual void build(InputBuilder&) const = 0;

protected:
//!@{
Expand Down
11 changes: 5 additions & 6 deletions src/orange/orangeinp/UnitProto.cc
Expand Up @@ -9,6 +9,9 @@

#include <algorithm>

#include "orange/OrangeData.hh"
#include "orange/OrangeInput.hh"

#include "CsgObject.hh"
#include "CsgTree.hh"
#include "CsgTreeUtils.hh"
Expand Down Expand Up @@ -86,16 +89,12 @@ auto UnitProto::daughters() const -> VecProto
* Construction is done from highest masking precedence to lowest (reverse
* zorder): exterior, then holes, then arrays, then media.
*/
void UnitProto::build(GlobalBuilder&) const
void UnitProto::build(InputBuilder&) const
{
// Transform CsgUnit to OrangeInput
// - Map CSG nodes to volume IDs
// - Map used CSG nodes to surface IDs
// - Map universe IDs (index in daughter list to actual universe ID)
// - Remap surface indices, removing unused surfaces
// - Set up "interior" cell if needed (build volume and "all surfaces")
// - Construct postfix logic definitions
// - Copy bounding boxes
CELER_NOT_IMPLEMENTED("global builder");
}

Expand Down Expand Up @@ -130,7 +129,7 @@ auto UnitProto::build(Tol const& tol, ExteriorBoundary ext) const -> Unit
}
auto ext_vol
= build_volume(NegatedObject("[EXTERIOR]", input_.boundary.interior));
CELER_ASSERT(ext_vol == local_orange_outside_volume);
CELER_ASSERT(ext_vol == orange_exterior_volume);

// Build daughters
UniverseId daughter_id{0};
Expand Down
2 changes: 1 addition & 1 deletion src/orange/orangeinp/UnitProto.hh
Expand Up @@ -146,7 +146,7 @@ class UnitProto : public ProtoInterface
VecProto daughters() const final;

// Construct a universe input from this object
void build(GlobalBuilder&) const final;
void build(InputBuilder&) const final;

//// HELPER FUNCTIONS ////

Expand Down
14 changes: 14 additions & 0 deletions src/orange/orangeinp/detail/BoundingZone.cc
Expand Up @@ -196,6 +196,20 @@ BoundingZone calc_union(BoundingZone const& a, BoundingZone const& b)
return result;
}

//---------------------------------------------------------------------------//
/*!
* Get an infinite bbox if "negated", else get the exterior.
*/
BBox get_exterior_bbox(BoundingZone const& bz)
{
if (bz.negated)
{
// Everything "outside" a finite region: infinite
return BBox::from_infinite();
}
return bz.exterior;
}

//---------------------------------------------------------------------------//
} // namespace detail
} // namespace orangeinp
Expand Down
3 changes: 3 additions & 0 deletions src/orange/orangeinp/detail/BoundingZone.hh
Expand Up @@ -115,6 +115,9 @@ BoundingZone calc_intersection(BoundingZone const& a, BoundingZone const& b);
// Calculate the union of two bounding zones
BoundingZone calc_union(BoundingZone const& a, BoundingZone const& b);

// Get an infinite bbox if "negated", else get the exterior
BBox get_exterior_bbox(BoundingZone const&);

//---------------------------------------------------------------------------//
/*!
* Flip inside and outside.
Expand Down
100 changes: 100 additions & 0 deletions src/orange/orangeinp/detail/InternalSurfaceFlagger.cc
@@ -0,0 +1,100 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2024 UT-Battelle, LLC, and other Celeritas developers.
// See the top-level COPYRIGHT file for details.
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
//---------------------------------------------------------------------------//
//! \file orange/orangeinp/detail/InternalSurfaceFlagger.cc
//---------------------------------------------------------------------------//
#include "InternalSurfaceFlagger.hh"

namespace celeritas
{
namespace orangeinp
{
namespace detail
{
//---------------------------------------------------------------------------//
/*!
* Construct from a tree.
*/
InternalSurfaceFlagger::InternalSurfaceFlagger(CsgTree const& tree)
: tree_{tree}, cache_(tree.size(), Status::unknown)
{
}

//---------------------------------------------------------------------------//
/*!
* Visit a node, using the cache, to determine its flag.
*/
bool InternalSurfaceFlagger::operator()(NodeId const& n)
{
CELER_EXPECT(n < cache_.size());
Status& status = cache_[n.get()];
if (status == Status::unknown)
{
Node const& node = tree_[n];
CELER_ASSUME(!node.valueless_by_exception());
status = static_cast<Status>(std::visit(*this, node));
}
CELER_ENSURE(status >= 0);
return status;
}

//---------------------------------------------------------------------------//
/*!
* Aliased nodes forward to the aliased node.
*/
bool InternalSurfaceFlagger::operator()(Aliased const& n)
{
return (*this)(n.node);
}

//---------------------------------------------------------------------------//
/*!
* Visit a negated node.
*
* Negated "and" nodes are *not* simple. Negated "or" nodes might be, but we
* ignore that for now.
*/
bool InternalSurfaceFlagger::operator()(Negated const& n)
{
if (auto* j = std::get_if<Joined>(&tree_[n.node]))
{
// Pointee is a "joined" node
CELER_DISCARD(j);
return Status::internal;
}

// Otherwise forward on the result (for simplified trees, this should just
// be a surface or "true")
return (*this)(n.node);
}

//---------------------------------------------------------------------------//
/*!
* Intersections of "simple" nodes are simple; unions are never.
*/
bool InternalSurfaceFlagger::operator()(Joined const& n)
{
CELER_EXPECT(n.nodes.size() > 1);

if (n.op == op_or)
{
return Status::internal;
}

for (NodeId const& d : n.nodes)
{
if ((*this)(d) == Status::internal)
{
return Status::internal;
}
}

return Status::simple;
}

//---------------------------------------------------------------------------//
} // namespace detail
} // namespace orangeinp
} // namespace celeritas

0 comments on commit edf7937

Please sign in to comment.