Skip to content

Commit

Permalink
Transform refactoring (celeritas-project#1127)
Browse files Browse the repository at this point in the history
* Use optional bounding zones instead of required bboxes
* Rename surface accessor
* Define a base class for testing objects
* Add transforms to each region
* Add streamable variant
  • Loading branch information
sethrj committed Feb 28, 2024
1 parent 3ded3de commit af25d9b
Show file tree
Hide file tree
Showing 16 changed files with 515 additions and 406 deletions.
69 changes: 69 additions & 0 deletions src/corecel/io/StreamableVariant.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//----------------------------------*-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 corecel/io/StreamableVariant.hh
//---------------------------------------------------------------------------//
#pragma once

#include <ostream>
#include <variant>

#include "corecel/Assert.hh"

namespace celeritas
{
//---------------------------------------------------------------------------//
/*!
* Helper class to print a variant to a stream.
*
* Example:
* \code
std::cout << StreamableVariant{surface} << std::endl;
\endcode
*/
template<class T>
struct StreamableVariant
{
T value;
};

//---------------------------------------------------------------------------//
// Deduction guide
template<class T>
StreamableVariant(T&&) -> StreamableVariant<T>;

//---------------------------------------------------------------------------//
// IMPLEMENTATION
//---------------------------------------------------------------------------//
namespace detail
{
struct GenericToStream
{
std::ostream& os;

template<class T>
void operator()(T&& obj) const
{
this->os << obj;
}
};
} // namespace detail

//---------------------------------------------------------------------------//
// FREE FUNCTIONS
//---------------------------------------------------------------------------//
/*!
* Write a variant object's value to a stream.
*/
template<class T>
std::ostream& operator<<(std::ostream& os, StreamableVariant<T> const& svar)
{
CELER_ASSUME(!svar.value.valueless_by_exception());
std::visit(detail::GenericToStream{os}, svar.value);
return os;
}

//---------------------------------------------------------------------------//
} // namespace celeritas
2 changes: 1 addition & 1 deletion src/orange/orangeinp/ConvexSurfaceBuilder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ void ConvexSurfaceBuilder::insert_transformed(std::string&& extension,
// Update surface's global-reference bounding zone using *deduplicated*
// surface
ClipImpl{&state_->global_bzone}(final_sense,
ub_->get_surface<SurfaceT>(node_id));
ub_->surface<SurfaceT>(node_id));
};

// Construct transformed surface, get back the node ID, update the sense
Expand Down
19 changes: 13 additions & 6 deletions src/orange/orangeinp/detail/CsgUnit.hh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//---------------------------------------------------------------------------//
#pragma once

#include <map>
#include <set>
#include <variant>
#include <vector>
Expand All @@ -17,6 +18,7 @@
#include "orange/surf/VariantSurface.hh"
#include "orange/transform/VariantTransform.hh"

#include "BoundingZone.hh"
#include "../CsgTree.hh"
#include "../CsgTypes.hh"

Expand All @@ -39,7 +41,7 @@ namespace detail
*
* All bounding boxes and transforms are "local" within the CSG unit's
* reference frame, not relative to any other CSG node nor to any parent
* universe. (TODO: add bboxes and transforms only for finite regions)
* universe. (TODO: add bounds and transforms only for finite regions)
*
* TODO: map of SP object to detailed provenance?
*/
Expand All @@ -49,9 +51,15 @@ struct CsgUnit

using Metadata = Label;
using SetMd = std::set<Metadata>;
using BBox = ::celeritas::BoundingBox<>;
using Fill = std::variant<std::monostate, MaterialId, Daughter>;

//! Attributes about a closed volume of space
struct Region
{
BoundingZone bounds; //!< Interior/exterior bbox
TransformId transform_id; //!< Region-to-unit transform
};

//// DATA ////

//!@{
Expand All @@ -65,7 +73,7 @@ struct CsgUnit
//! Vectors are indexed by NodeId.
CsgTree tree; //!< CSG tree
std::vector<SetMd> metadata; //!< CSG node labels
std::vector<BBox> bboxes;
std::map<NodeId, Region> regions; //!< Bounds and transforms
//!@}

//!@{
Expand Down Expand Up @@ -108,8 +116,7 @@ inline constexpr bool is_filled(CsgUnit::Fill const& fill)
*/
CsgUnit::operator bool() const
{
return this->metadata.size() == this->tree.size()
&& this->bboxes.size() == this->tree.size() && !this->volumes.empty()
return this->metadata.size() == this->tree.size() && !this->volumes.empty()
&& this->volumes.size() == this->fills.size();
}

Expand All @@ -120,7 +127,7 @@ CsgUnit::operator bool() const
bool CsgUnit::empty() const
{
return this->surfaces.empty() && this->metadata.empty()
&& this->bboxes.empty() && this->volumes.empty()
&& this->regions.empty() && this->volumes.empty()
&& this->fills.empty() && !this->exterior
&& this->transforms.empty();
}
Expand Down
50 changes: 35 additions & 15 deletions src/orange/orangeinp/detail/CsgUnitBuilder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,43 @@ namespace detail
* Construct with an empty unit (which doesn't yet have any elements).
*/
CsgUnitBuilder::CsgUnitBuilder(CsgUnit* u, Tolerance<> const& tol)
: unit_{u}, tol_{tol}, insert_surface_{&unit_->surfaces, tol}
: unit_{u}
, tol_{tol}
, insert_surface_{&unit_->surfaces, tol}
, insert_transform_{&unit_->transforms}
{
CELER_EXPECT(unit_);
CELER_EXPECT(unit_->empty());

// Resize because the tree comes prepopulated with true/false
unit_->metadata.resize(unit_->tree.size());
unit_->bboxes.resize(unit_->tree.size());
}

//---------------------------------------------------------------------------//
/*!
* Set a bounding box for a node.
* Set a bounding zone and transform for a node.
*/
void CsgUnitBuilder::set_bbox(NodeId n, BBox const& bbox)
void CsgUnitBuilder::insert_region(NodeId n,
BoundingZone const& bzone,
TransformId trans_id)
{
CELER_EXPECT(n < unit_->bboxes.size());
CELER_EXPECT(!unit_->bboxes[n.unchecked_get()]);

unit_->bboxes[n.unchecked_get()] = bbox;
CELER_EXPECT(n < unit_->tree.size());
CELER_EXPECT(trans_id < unit_->transforms.size());

auto&& [iter, inserted]
= unit_->regions.insert({n, CsgUnit::Region{bzone, trans_id}});
if (!inserted)
{
// The existing bounding zone *SHOULD BE IDENTICAL*.
// For now this is a rough check...
CsgUnit::Region const& existing = iter->second;
CELER_ASSERT(bzone.negated == existing.bounds.negated);
CELER_ASSERT(static_cast<bool>(bzone.interior)
== static_cast<bool>(existing.bounds.interior));
CELER_ASSERT(static_cast<bool>(bzone.exterior)
== static_cast<bool>(existing.bounds.exterior));
CELER_ASSERT(trans_id == existing.transform_id);
}
}

//---------------------------------------------------------------------------//
Expand Down Expand Up @@ -76,21 +93,24 @@ void CsgUnitBuilder::fill_volume(LocalVolumeId v, MaterialId m)
/*!
* Fill a volume node with a daughter.
*/
void CsgUnitBuilder::fill_volume(LocalVolumeId v,
UniverseId u,
VariantTransform&& vt)
void CsgUnitBuilder::fill_volume(LocalVolumeId v, UniverseId u)
{
CELER_EXPECT(v < unit_->fills.size());
CELER_EXPECT(!is_filled(unit_->fills[v.unchecked_get()]));
CELER_EXPECT(u);

// Get the region associated with this node ID for the volume
CELER_ASSERT(unit_->volumes.size() == unit_->fills.size());
auto iter = unit_->regions.find(unit_->volumes[v.unchecked_get()]);
// The iterator should be valid since the whole volume should never be a
// pure surface (created outside a convex region)
CELER_ASSERT(iter != unit_->regions.end());

Daughter new_daughter;
new_daughter.universe_id = u;
new_daughter.transform_id
= TransformId{static_cast<size_type>(unit_->transforms.size())};
new_daughter.transform_id = iter->second.transform_id;
CELER_ASSERT(new_daughter.transform_id < unit_->transforms.size());

// Add transform
unit_->transforms.push_back(std::move(vt));
// Save fill
unit_->fills[v.unchecked_get()] = std::move(new_daughter);

Expand Down
45 changes: 36 additions & 9 deletions src/orange/orangeinp/detail/CsgUnitBuilder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "CsgUnit.hh"
#include "LocalSurfaceInserter.hh"
#include "TransformInserter.hh"
#include "../CsgTypes.hh"

namespace celeritas
Expand Down Expand Up @@ -41,7 +42,6 @@ class CsgUnitBuilder
//! \name Type aliases
using Tol = Tolerance<>;
using Metadata = CsgUnit::Metadata;
using BBox = CsgUnit::BBox;
using NodeInsertion = CsgTree::Insertion;
//!@}

Expand All @@ -56,7 +56,10 @@ class CsgUnitBuilder

// Access a typed surface, needed for clipping with deduplicated surface
template<class S>
inline S const& get_surface(NodeId) const;
inline S const& surface(NodeId) const;

// Access a transform by ID
inline VariantTransform const& transform(TransformId) const;

//// MUTATORS ////

Expand All @@ -68,20 +71,23 @@ class CsgUnitBuilder
template<class... Args>
inline NodeInsertion insert_csg(Args&&... args);

//! Insert node metadata
// Insert a transform
inline TransformId insert_transform(VariantTransform&& vt);

// Insert node metadata
inline void insert_md(NodeId node, Metadata&& md);

// Set a bounding box for a node
void set_bbox(NodeId, BBox const&);
// Set a bounding zone and transform for a node
void insert_region(NodeId, BoundingZone const&, TransformId trans_id);

// Mark a CSG node as a volume of real space
LocalVolumeId insert_volume(NodeId);

// Fill a volume node with a material
void fill_volume(LocalVolumeId, MaterialId);

// Fill a volume node with a daughter
void fill_volume(LocalVolumeId, UniverseId, VariantTransform&& vt);
// Fill a volume node with a daughter using the local transform
void fill_volume(LocalVolumeId, UniverseId);

// Set an exterior node
void set_exterior(NodeId);
Expand All @@ -90,9 +96,12 @@ class CsgUnitBuilder
CsgUnit* unit_;
Tol tol_;
LocalSurfaceInserter insert_surface_;
TransformInserter insert_transform_;

// Get a variant surface from a node ID
VariantSurface const& get_surface_impl(NodeId nid) const;

// TODO: cache of weak_ptr<{Transform,ObjectInterface}> -> NodeId?
};

//---------------------------------------------------------------------------//
Expand All @@ -102,13 +111,23 @@ class CsgUnitBuilder
* Access a typed surface, needed for clipping with deduplicated surface.
*/
template<class S>
S const& CsgUnitBuilder::get_surface(NodeId nid) const
S const& CsgUnitBuilder::surface(NodeId nid) const
{
VariantSurface const& vs = this->get_surface_impl(nid);
CELER_ASSUME(std::holds_alternative<S>(vs));
return std::get<S>(vs);
}

//---------------------------------------------------------------------------//
/*!
* Access a transform by ID.
*/
VariantTransform const& CsgUnitBuilder::transform(TransformId tid) const
{
CELER_EXPECT(tid < unit_->transforms.size());
return unit_->transforms[tid.unchecked_get()];
}

//---------------------------------------------------------------------------//
/*!
* Insert a surface by forwarding to the surface inserter.
Expand All @@ -131,11 +150,19 @@ auto CsgUnitBuilder::insert_csg(Args&&... args) -> NodeInsertion
if (result.second)
{
unit_->metadata.resize(unit_->tree.size());
unit_->bboxes.resize(unit_->tree.size());
}
return result;
}

//---------------------------------------------------------------------------//
/*!
* Insert transform with deduplication.
*/
TransformId CsgUnitBuilder::insert_transform(VariantTransform&& vt)
{
return this->insert_transform_(std::move(vt));
}

//---------------------------------------------------------------------------//
/*!
* Insert node metadata.
Expand Down
18 changes: 16 additions & 2 deletions src/orange/orangeinp/detail/VolumeBuilder.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
//---------------------------------------------------------------------------//
#include "VolumeBuilder.hh"

#include "corecel/Assert.hh"

#include "BoundingZone.hh"
#include "CsgUnitBuilder.hh"

Expand All @@ -16,13 +18,25 @@ namespace orangeinp
{
namespace detail
{
//---------------------------------------------------------------------------//
/*!
* Construct with unit builder.
*/
VolumeBuilder::VolumeBuilder(CsgUnitBuilder* ub) : ub_{ub}
{
CELER_EXPECT(ub_);
ub_->insert_transform(NoTransformation{});
}

//---------------------------------------------------------------------------//
/*!
* Add a region to the CSG tree.
*/
NodeId VolumeBuilder::insert_region(Metadata&& md, Joined&& j, BoundingZone&&)
NodeId
VolumeBuilder::insert_region(Metadata&& md, Joined&& j, BoundingZone&& bzone)
{
auto&& [node_id, inserted] = ub_->insert_csg(std::move(j));
auto node_id = ub_->insert_csg(std::move(j)).first;
ub_->insert_region(node_id, std::move(bzone), TransformId{0});

// Always add metadata
ub_->insert_md(node_id, std::move(md));
Expand Down

0 comments on commit af25d9b

Please sign in to comment.