Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ORANGE surface construction components #1001

Merged
merged 14 commits into from
Nov 3, 2023
Merged
2 changes: 1 addition & 1 deletion scripts/cmake-presets/goldfinger.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
"cacheVariables": {
"CELERITAS_USE_SWIG": {"type": "BOOL", "value": "ON"},
"CMAKE_SWIG_CXX_FLAGS": "-Wno-unused-parameter;-Wno-deprecated-declarations",
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install"
"CMAKE_INSTALL_PREFIX": "${sourceDir}/install",
"CELERITAS_USE_VecGeom": {"type": "BOOL", "value": "OFF"}
}
},
Expand Down
2 changes: 2 additions & 0 deletions src/orange/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ list(APPEND SOURCES
construct/CsgTypes.cc
construct/CsgTreeUtils.cc
construct/DepthCalculator.cc
construct/detail/LocalSurfaceInserter.cc
construct/detail/NodeSimplifier.cc
detail/BIHBuilder.cc
detail/BIHPartitioner.cc
Expand All @@ -31,6 +32,7 @@ list(APPEND SOURCES
detail/UniverseInserter.cc
surf/ConeAligned.cc
surf/CylAligned.cc
surf/FaceNamer.cc
surf/GeneralQuadric.cc
surf/Plane.cc
surf/PlaneAligned.cc
Expand Down
4 changes: 3 additions & 1 deletion src/orange/construct/OrangeInput.hh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ struct VolumeInput

//---------------------------------------------------------------------------//
/*!
* Input definition a daughter universe embedded in a parent cell
* Input definition a daughter universe embedded in a parent cell.
*/
struct DaughterInput
{
Expand All @@ -65,6 +65,8 @@ struct DaughterInput
//---------------------------------------------------------------------------//
/*!
* Input definition for a unit.
*
* \todo Add a CsgTree object and \c vector<NodeId> volumes;
*/
struct UnitInput
{
Expand Down
49 changes: 49 additions & 0 deletions src/orange/construct/detail/LocalSurfaceInserter.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2023 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/construct/detail/LocalSurfaceInserter.cc
//---------------------------------------------------------------------------//
#include "LocalSurfaceInserter.hh"

namespace celeritas
{
namespace detail
{
//---------------------------------------------------------------------------//
/*!
* Construct with defaults.
*/
LocalSurfaceInserter::LocalSurfaceInserter(VecSurface* v,
Tolerance<> const& tol)
: surfaces_{v}, soft_surface_equal_{tol}
{
CELER_EXPECT(surfaces_);
CELER_EXPECT(surfaces_->empty());
}

//---------------------------------------------------------------------------//
/*!
* Look for duplicate surfaces and store equivalency relationship.
*/
LocalSurfaceId
LocalSurfaceInserter::merge_impl(LocalSurfaceId source, LocalSurfaceId target)
{
CELER_EXPECT(source < surfaces_->size());
CELER_EXPECT(target < source);

if (auto iter = merged_.find(target); iter != merged_.end())
{
// Surface was already merged with another: chain them
target = iter->second;
CELER_ENSURE(target < source);
}

merged_.emplace(source, target);
return target;
}

//---------------------------------------------------------------------------//
} // namespace detail
} // namespace celeritas
122 changes: 122 additions & 0 deletions src/orange/construct/detail/LocalSurfaceInserter.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2023 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/construct/detail/LocalSurfaceInserter.hh
//---------------------------------------------------------------------------//
#pragma once

#include <algorithm>
#include <unordered_map>
#include <vector>

#include "orange/OrangeTypes.hh"
#include "orange/surf/SoftSurfaceEqual.hh"
#include "orange/surf/VariantSurface.hh"

namespace celeritas
{
namespace detail
{
//---------------------------------------------------------------------------//
/*!
* Merge local surfaces as they're being built.
*
* This will \em sometimes will return the ID of a previously inserted surface,
* and \em sometimes will push the surface onto the vector of existing ones.
*
* There are three cases to consider:
* - The new surface is entirely unique: we insert and return the new ID.
* - The surface is soft equivalent but not exactly like an existing surface:
* we insert but return an existing ID.
* - The surface is exactly the same: we do \em not insert, and return existing
* id.
*
* The second case adds the surface so that multiple nearby surfaces can be
* \em chained together, even if the tolerance between the furthest apart is
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the purpose of the em-dashes above, but not in this paragraph.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The em is the <em> html tag aka "emphasis" (i.e., italicized).

* greater than the soft equivalence tolerance.
*/
class LocalSurfaceInserter
{
public:
//!@{
//! \name Type aliases
using VecSurface = std::vector<VariantSurface>;
//!@}

public:
// Construct with tolerance and a pointer to the surfaces vector
LocalSurfaceInserter(VecSurface* v, Tolerance<> const& tol);

// Construct a surface with deduplication
template<class S>
inline LocalSurfaceId operator()(S const& surface);

private:
using MapSurfId = std::unordered_map<LocalSurfaceId, LocalSurfaceId>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

>>> TYPES, >>> HELPER FUNCTIONS, >>> DATA for consistency, but not necessary


VecSurface* surfaces_;
SoftSurfaceEqual soft_surface_equal_;
ExactSurfaceEqual exact_surface_equal_;
MapSurfId merged_;

LocalSurfaceId merge_impl(LocalSurfaceId source, LocalSurfaceId target);
};

//---------------------------------------------------------------------------//
// INLINE DEFINITIONS
//---------------------------------------------------------------------------//
/*!
* Construct a surface with deduplication.
*/
template<class S>
LocalSurfaceId LocalSurfaceInserter::operator()(S const& source)
{
VecSurface& all_surf = *surfaces_;

// Test for soft equality against all existing surfaces
auto is_soft_equal = [this, &source](VariantSurface const& vtarget) {
if (S const* target = std::get_if<S>(&vtarget))
{
return soft_surface_equal_(source, *target);
}
return false;
};

// TODO: instead of linear search (making overall unit insertion
// quadratic!) accelerate by mapping surfaces into a hash and comparing all
// neighboring hash cells
auto iter = std::find_if(all_surf.begin(), all_surf.end(), is_soft_equal);
if (iter == all_surf.end())
{
// Surface is completely unique
LocalSurfaceId result(all_surf.size());
all_surf.emplace_back(std::in_place_type<S>, source);
return result;
}

// Surface is soft equivalent to an existing surface at this index
LocalSurfaceId target_id{static_cast<size_type>(iter - all_surf.begin())};

CELER_ASSUME(std::holds_alternative<S>(*iter));
if (exact_surface_equal_(source, std::get<S>(*iter)))
{
// Surfaces are *exactly* equal: don't insert
CELER_ENSURE(target_id < all_surf.size());
return target_id;
}

// Surface is a little bit different, so we still need to insert it
// to chain duplicates
LocalSurfaceId source_id(all_surf.size());
all_surf.emplace_back(std::in_place_type<S>, source);

// Store the equivalency relationship and potentially chain equivalent
// surfaces
return this->merge_impl(source_id, target_id);
}

//---------------------------------------------------------------------------//
} // namespace detail
} // namespace celeritas
144 changes: 144 additions & 0 deletions src/orange/surf/FaceNamer.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
//----------------------------------*-C++-*----------------------------------//
// Copyright 2023 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/surf/FaceNamer.cc
//---------------------------------------------------------------------------//
#include "corecel/Assert.hh"

#include "FaceNamer.hh"
#include "VariantSurface.hh"

namespace celeritas
{
namespace
{
//---------------------------------------------------------------------------//
constexpr char to_pm(Sense s)
{
return s == Sense::inside ? 'p' : 'm';
}

#define ORANGE_INSTANTIATE_OP(IN) \
template std::string FaceNamer::Impl::operator()(IN<Axis::x> const&) \
const; \
template std::string FaceNamer::Impl::operator()(IN<Axis::y> const&) \
const; \
template std::string FaceNamer::Impl::operator()(IN<Axis::z> const&) const

//---------------------------------------------------------------------------//
} // namespace

//---------------------------------------------------------------------------//
/*!
* Apply to a surface with unknown type.
*/
std::string FaceNamer::operator()(Sense s, VariantSurface const& surf)
{
CELER_ASSUME(!surf.valueless_by_exception());
return std::visit(Impl{&state_, s}, surf);
}

//---------------------------------------------------------------------------//
// IMPL DEFINITIONS
//---------------------------------------------------------------------------//
template<Axis T>
std::string FaceNamer::Impl::operator()(PlaneAligned<T> const&) const
{
return {to_pm(sense_), to_char(T)};
}

//! \cond
ORANGE_INSTANTIATE_OP(PlaneAligned);
//! \endcond

//---------------------------------------------------------------------------//
/*!
* Construct a name for a axis-aligned cylinder.
*/
template<Axis T>
std::string FaceNamer::Impl::operator()(CylCentered<T> const&) const
{
return {'c', to_char(T)};
}

//! \cond
ORANGE_INSTANTIATE_OP(CylCentered);
//! \endcond

//---------------------------------------------------------------------------//
/*!
* Construct a name for a sphere.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

centered sphere

*/
std::string FaceNamer::Impl::operator()(SphereCentered const&) const
{
return "s";
}

//---------------------------------------------------------------------------//
/*!
* Construct a name for a axis-aligned cylinder.
*/
template<Axis T>
std::string FaceNamer::Impl::operator()(CylAligned<T> const&) const
{
return {'c', to_char(T)};
}

//! \cond
ORANGE_INSTANTIATE_OP(CylAligned);
//! \endcond

//---------------------------------------------------------------------------//
/*!
* Construct a name for a general plane.
*/
std::string FaceNamer::Impl::operator()(Plane const&) const
{
return "p" + std::to_string(state_->num_planes_++);
}

//---------------------------------------------------------------------------//
/*!
* Construct a name for a sphere.
*/
std::string FaceNamer::Impl::operator()(Sphere const&) const
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are sphere and centered sphere supposed to have the same name?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's how it is in the current SCALE builder. I can't think of any shape that has anything but a single sphere...

{
return "s";
}

//---------------------------------------------------------------------------//
/*!
* Construct a name for a cone.
*/
template<Axis T>
std::string FaceNamer::Impl::operator()(ConeAligned<T> const&) const
{
return {'k', to_char(T)};
}

//! \cond
ORANGE_INSTANTIATE_OP(ConeAligned);
//! \endcond

//---------------------------------------------------------------------------//
/*!
* Construct a name for a simple quadric.
*/
std::string FaceNamer::Impl::operator()(SimpleQuadric const&) const
{
return "sq";
}

//---------------------------------------------------------------------------//
/*!
* Construct a name for a quadric.
*/
std::string FaceNamer::Impl::operator()(GeneralQuadric const&) const
{
return "gq";
}

//---------------------------------------------------------------------------//
} // namespace celeritas
Loading