Skip to content

Commit

Permalink
Add proto-universe and CSG Unit construction (celeritas-project#1148)
Browse files Browse the repository at this point in the history
* Add test for recursive simplify
* Remove exterior from CSG unit
* Allow null-op transforms
* Add proto interface
* Pass transformed argument by reference
* Add background to CSG unit
* Add zorder to string
* Add unit proto
* Use local_orange_outside_volume
* Use enum instead of bool
* Add fuzziness test
* Add doc
* Fix single-precision failure
* Remove proto sorting for this PR
* Address review feedback
  • Loading branch information
sethrj committed Mar 15, 2024
1 parent 5262670 commit 291393e
Show file tree
Hide file tree
Showing 19 changed files with 929 additions and 57 deletions.
1 change: 1 addition & 0 deletions src/orange/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ list(APPEND SOURCES
orangeinp/Shape.cc
orangeinp/Solid.cc
orangeinp/Transformed.cc
orangeinp/UnitProto.cc
orangeinp/detail/BoundingZone.cc
orangeinp/detail/BuildConvexRegion.cc
orangeinp/detail/ConvexSurfaceState.cc
Expand Down
2 changes: 1 addition & 1 deletion src/orange/OrangeTrackView.hh
Original file line number Diff line number Diff line change
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 = LocalVolumeId{0};
tinit.volume = local_orange_outside_volume;
tinit.surface = {};
}

Expand Down
26 changes: 26 additions & 0 deletions src/orange/OrangeTypes.cc
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,32 @@ char const* to_cstring(TransformType value)
return to_cstring_impl(value);
}

//---------------------------------------------------------------------------//
/*!
* Get a string corresponding to a transform type.
*/
char const* to_cstring(ZOrder zo)
{
switch (zo)
{
case ZOrder::invalid:
return "invalid";
case ZOrder::background:
return "background";
case ZOrder::media:
return "media";
case ZOrder::array:
return "array";
case ZOrder::hole:
return "hole";
case ZOrder::implicit_exterior:
return "implicit_exterior";
case ZOrder::exterior:
return "exterior";
};
CELER_VALIDATE(false, << "invalid ZOrder");
}

//---------------------------------------------------------------------------//
/*!
* Get a printable character corresponding to a z ordering.
Expand Down
3 changes: 3 additions & 0 deletions src/orange/OrangeTypes.hh
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,9 @@ inline constexpr char to_char(OperatorToken tok)
}
} // namespace logic

// Get a string corresponding to a z ordering
char const* to_cstring(ZOrder);

// Get a printable character corresponding to a z ordering
char to_char(ZOrder z);

Expand Down
3 changes: 3 additions & 0 deletions src/orange/orangeinp/ConvexRegion.hh
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ class Prism final : public ConvexRegionInterface
//---------------------------------------------------------------------------//
/*!
* A sphere centered on the origin.
*
* \note Be aware there's also a sphere *surface* at orange/surf/Sphere.hh in a
* different namespace.
*/
class Sphere final : public ConvexRegionInterface
{
Expand Down
71 changes: 71 additions & 0 deletions src/orange/orangeinp/ProtoInterface.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
//----------------------------------*-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/ProtoInterface.hh
//---------------------------------------------------------------------------//
#pragma once

#include <memory>
#include <vector>

#include "orange/OrangeInput.hh"

namespace celeritas
{
namespace orangeinp
{
class ObjectInterface;
class GlobalBuilder;

//---------------------------------------------------------------------------//
/*!
* Construct a universe as part of an ORANGE geometry.
*
* Each Proto (for proto-universe) will result in a unique UniverseId and can
* be placed into multiple other universes. Each universe has:
* - a label for descriptive output,
* - an "interior" CSG object that describes its boundary, so that it can be
* placed in other universes, and
* - 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
{
public:
//!@{
//! \name Type aliases
using SPConstObject = std::shared_ptr<ObjectInterface const>;
using SPConstProto = std::shared_ptr<ProtoInterface const>;
using VecProto = std::vector<ProtoInterface const*>;
//!@}

public:
//! Short unique name of this object
virtual std::string_view label() const = 0;

//! Get the boundary of this universe as an object
virtual SPConstObject interior() const = 0;

//! Get a non-owning set of all daughters referenced by this proto
virtual VecProto daughters() const = 0;

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

protected:
//!@{
//! Allow construction and assignment only through subclasses
ProtoInterface() = default;
virtual ~ProtoInterface() = default;
CELER_DEFAULT_COPY_MOVE(ProtoInterface);
//!@}
};

//---------------------------------------------------------------------------//
} // namespace orangeinp
} // namespace celeritas
11 changes: 2 additions & 9 deletions src/orange/orangeinp/Transformed.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,11 @@ namespace orangeinp
//---------------------------------------------------------------------------//
/*!
* Construct with daughter object and transform.
*
* The input transform should *not* be "no transform" because that would be
* silly.
*
* TODO: require that the input is simplified as well?
*/
Transformed::Transformed(SPConstObject obj, VariantTransform&& transform)
: obj_{std::move(obj)}, transform_{std::move(transform)}
Transformed::Transformed(SPConstObject obj, VariantTransform const& transform)
: obj_{std::move(obj)}, transform_{transform}
{
CELER_EXPECT(obj_);
CELER_EXPECT(!transform_.valueless_by_exception());
CELER_EXPECT(!std::holds_alternative<NoTransformation>(transform_));
}

//---------------------------------------------------------------------------//
Expand Down
2 changes: 1 addition & 1 deletion src/orange/orangeinp/Transformed.hh
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Transformed final : public ObjectInterface
{
public:
// Construct with daughter object and transform
Transformed(SPConstObject obj, VariantTransform&& transform);
Transformed(SPConstObject obj, VariantTransform const& transform);

//! Access the daughter object
SPConstObject const& daughter() const { return obj_; }
Expand Down
182 changes: 182 additions & 0 deletions src/orange/orangeinp/UnitProto.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
//----------------------------------*-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/UnitProto.cc
//---------------------------------------------------------------------------//
#include "UnitProto.hh"

#include <algorithm>

#include "CsgObject.hh"
#include "CsgTree.hh"
#include "CsgTreeUtils.hh"
#include "Transformed.hh"

#include "detail/CsgUnit.hh"
#include "detail/CsgUnitBuilder.hh"
#include "detail/VolumeBuilder.hh"

namespace celeritas
{
namespace orangeinp
{
//---------------------------------------------------------------------------//
/*!
* Construct with required input data.
*/
UnitProto::UnitProto(Input&& inp) : input_{std::move(inp)}
{
CELER_VALIDATE(input_, << "no fill, daughters, or volumes are defined");
CELER_VALIDATE(std::all_of(input_.materials.begin(),
input_.materials.begin(),
[](MaterialInput const& m) {
return static_cast<bool>(m);
}),
<< "incomplete material definition(s)");
CELER_VALIDATE(std::all_of(input_.daughters.begin(),
input_.daughters.begin(),
[](DaughterInput const& d) {
return static_cast<bool>(d);
}),
<< "incomplete daughter definition(s)");
CELER_VALIDATE(input_.boundary.zorder == ZOrder::media
|| input_.boundary.zorder == ZOrder::exterior,
<< "invalid exterior zorder '"
<< to_cstring(input_.boundary.zorder) << "'");
}

//---------------------------------------------------------------------------//
/*!
* Short unique name of this object.
*/
std::string_view UnitProto::label() const
{
return input_.label;
}

//---------------------------------------------------------------------------//
/*!
* Get the boundary of this universe as an object.
*/
auto UnitProto::interior() const -> SPConstObject
{
return input_.boundary.interior;
}

//---------------------------------------------------------------------------//
/*!
* Get a list of all daughter protos.
*/
auto UnitProto::daughters() const -> VecProto
{
VecProto result;
for (auto const& d : input_.daughters)
{
result.push_back(d.fill.get());
}
return result;
}

//---------------------------------------------------------------------------//
/*!
* Construct a universe input from this object.
*
* Construction is done from highest masking precedence to lowest (reverse
* zorder): exterior, then holes, then arrays, then media.
*/
void UnitProto::build(GlobalBuilder&) 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");
}

//---------------------------------------------------------------------------//
/*!
* Construct a standalone unit for testing or external interface.
*
* The universe ID in the resulting "fill" is the index into the input \c
* daughters list, which is the same ordering as the array of \c
* this->daughters().
*
* The "exterior boundary" argument determines whether the outer boundary needs
* to be deleted (assumed inside, implicit from the parent universe's boundary)
* or preserved.
*/
auto UnitProto::build(Tol const& tol, ExteriorBoundary ext) const -> Unit
{
CELER_EXPECT(tol);
detail::CsgUnit result;
detail::CsgUnitBuilder unit_builder(&result, tol);

auto build_volume = [ub = &unit_builder](ObjectInterface const& obj) {
detail::VolumeBuilder vb{ub};
auto final_node = obj.build(vb);
return ub->insert_volume(final_node);
};

// Build exterior volume and optional background fill
if (input_.boundary.zorder != ZOrder::media && !input_.fill)
{
CELER_NOT_IMPLEMENTED("implicit exterior without background fill");
}
auto ext_vol
= build_volume(NegatedObject("[EXTERIOR]", input_.boundary.interior));
CELER_ASSERT(ext_vol == local_orange_outside_volume);

// Build daughters
UniverseId daughter_id{0};
for (auto const& d : input_.daughters)
{
if (d.zorder != ZOrder::media)
{
CELER_NOT_IMPLEMENTED("volume masking using different z orders");
}
auto lv = build_volume(*d.make_interior());
unit_builder.fill_volume(lv, daughter_id++);
}

// Build materials
for (auto const& m : input_.materials)
{
auto lv = build_volume(*m.interior);
unit_builder.fill_volume(lv, m.fill);
}

// Build background fill (optional)
result.background = input_.fill;

if (ext == ExteriorBoundary::is_daughter)
{
// Replace "exterior" with "False" (i.e. interior with true)
NodeId ext_node = result.volumes[ext_vol.unchecked_get()];
auto min_node = replace_down(&result.tree, ext_node, False{});
// Simplify recursively
simplify(&result.tree, min_node);
}

return result;
}

//---------------------------------------------------------------------------//
/*!
* Construct the daughter's shape in this unit's reference frame.
*/
std::shared_ptr<Transformed> UnitProto::DaughterInput::make_interior() const
{
CELER_EXPECT(*this);
return std::make_shared<Transformed>(this->fill->interior(),
VariantTransform{this->transform});
}

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

0 comments on commit 291393e

Please sign in to comment.