Skip to content

Commit

Permalink
Fix CSG tree simplification needed by tilecal (#1256)
Browse files Browse the repository at this point in the history
* Add solid converter test for barrel
* Add label extension to intersect region
* Demonstrate tilecal bug
* Return simplified result
* Add boolean node test
* Add repl
* Implement fix
* Update test from simplified nodes
* Revert debug code
* Add missing max length parameter to celer-geo output
* Demonstrate polycone failure
* Fix polycone failure
* Simplify unknowns too
* Remove unused is_literal_node
* Update documentation
* Revert pv converter changes
* Revert changes to csg/dot script since they're updated on the metadata branch
* Improve nomenclature
  • Loading branch information
sethrj authored Jun 7, 2024
1 parent 01c7528 commit 98d6ce3
Show file tree
Hide file tree
Showing 17 changed files with 462 additions and 262 deletions.
17 changes: 16 additions & 1 deletion src/corecel/OpaqueId.hh
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,27 @@ class OpaqueId
//! Post-increment of the ID
CELER_FUNCTION OpaqueId operator++(int)
{
CELER_EXPECT(*this);
OpaqueId old{*this};
++*this;
return old;
}

//! Pre-decrement of the ID
CELER_FUNCTION OpaqueId& operator--()
{
CELER_EXPECT(*this && value_ > 0);
value_ -= 1;
return *this;
}

//! Post-decrement of the ID
CELER_FUNCTION OpaqueId operator--(int)
{
OpaqueId old{*this};
--*this;
return old;
}

//! Get the ID's value
CELER_FORCEINLINE_FUNCTION size_type get() const
{
Expand Down
1 change: 1 addition & 0 deletions src/geocel/rasterize/ImageIO.json.cc
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void to_json(nlohmann::json& j, ImageParams const& p)
CELER_JSON_PAIR(scalars, right),
CELER_JSON_PAIR(scalars, pixel_width),
CELER_JSON_PAIR(scalars, dims),
CELER_JSON_PAIR(scalars, max_length),
{"_units", to_cstring(UnitSystem::native)},
};
}
Expand Down
10 changes: 7 additions & 3 deletions src/orange/orangeinp/CsgTree.cc
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,16 @@ auto CsgTree::exchange(NodeId node_id, Node&& n) -> Node
/*!
* Perform a simplification of a node in-place.
*
* \return Whether simplification took place
* \return Simplified node
*/
bool CsgTree::simplify(NodeId node_id)
auto CsgTree::simplify(NodeId node_id) -> Simplification
{
auto repl = this->exchange(node_id, Node{this->at(node_id)});
return repl != this->at(node_id);
if (repl == this->at(node_id))
{
return {};
}
return Simplification{std::move(repl)};
}

//---------------------------------------------------------------------------//
Expand Down
6 changes: 5 additions & 1 deletion src/orange/orangeinp/CsgTree.hh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#pragma once

#include <iostream>
#include <optional>
#include <unordered_map>
#include <variant>
#include <vector>
Expand Down Expand Up @@ -51,6 +52,7 @@ class CsgTree
using NodeId = orangeinp::NodeId;
using size_type = NodeId::size_type;
using Insertion = std::pair<NodeId, bool>;
using Simplification = std::optional<Node>;
//!@}

public:
Expand All @@ -73,11 +75,13 @@ class CsgTree
Node exchange(NodeId node_id, Node&& n);

// Simplify a single node in-place [O(1)]
bool simplify(NodeId);
Simplification simplify(NodeId);

//// STATIC HELPERS ////

//! Special ID of a node that's always 'true'
static constexpr NodeId true_node_id() { return NodeId{0}; }
//! Special ID of a node that's always 'false'
static constexpr NodeId false_node_id() { return NodeId{1}; }

private:
Expand Down
85 changes: 71 additions & 14 deletions src/orange/orangeinp/CsgTreeUtils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,13 @@
#include "corecel/cont/Range.hh"

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

namespace celeritas
{
namespace orangeinp
{

//---------------------------------------------------------------------------//
/*!
* Replace the given node ID with the replacement node.
Expand All @@ -34,27 +35,83 @@ namespace orangeinp
* - surface: "true"
* - constant: check for contradiction
*
* This operation is at worst O((number of nodes) * (depth of graph)).
*
* \return Node ID of the lowest node that required simplification.
*/
NodeId replace_down(CsgTree* tree, NodeId n, Node repl)
void replace_and_simplify(CsgTree* tree, NodeId repl_key, Node repl_value)
{
CELER_EXPECT(is_boolean_node(repl));
CELER_EXPECT(tree);
CELER_EXPECT(repl_key < tree->size());
CELER_ASSUME(is_boolean_node(repl_value));

detail::NodeReplacementInserter::VecNode stack{{n, std::move(repl)}};
using detail::NodeReplacer;

NodeId lowest_node{n};
NodeId max_node{repl_key};
NodeReplacer::VecRepl state{tree->size(), NodeReplacer::unvisited};
state[CsgTree::true_node_id().get()] = NodeReplacer::known_true;
state[CsgTree::false_node_id().get()] = NodeReplacer::known_false;

while (!stack.empty())
state[repl_key.get()] = (std::holds_alternative<True>(repl_value)
? NodeReplacer::known_true
: NodeReplacer::known_false);

bool simplifying{true};
do
{
n = std::move(stack.back().first);
repl = std::move(stack.back().second);
stack.pop_back();
lowest_node = std::min(n, lowest_node);
// Sweep backward, updating known state
simplifying = false;
for (auto n = max_node; n > CsgTree::false_node_id(); --n)
{
bool updated
= std::visit(detail::NodeReplacer{&state, n}, (*tree)[n]);
simplifying = simplifying || updated;
}

Node prev = tree->exchange(n, std::move(repl));
std::visit(detail::NodeReplacementInserter{&stack, repl}, prev);
// Replace literals and simplify
for (auto n : range(CsgTree::false_node_id() + 1, NodeId{tree->size()}))
{
auto repl_value = state[n.get()];
if ((repl_value == NodeReplacer::known_true
|| repl_value == NodeReplacer::known_false)
&& std::holds_alternative<Surface>((*tree)[n]))
{
max_node = std::max(max_node, n);
tree->exchange(n,
repl_value == NodeReplacer::known_true
? Node{True{}}
: Node{False{}});
}
else if (auto simplified = tree->simplify(n))
{
max_node = std::max(max_node, n);
simplifying = true;
}
}
} while (simplifying);

// Replace nonliterals
for (auto n : range(CsgTree::false_node_id() + 1, NodeId{tree->size()}))
{
if (std::holds_alternative<Surface>((*tree)[n]))
{
continue;
}

auto repl_value = state[n.get()];
if (repl_value == NodeReplacer::known_true)
{
tree->exchange(n, Node{True{}});
}
else if (repl_value == NodeReplacer::known_false)
{
tree->exchange(n, Node{False{}});
}
else
{
tree->simplify(n);
}
}
return lowest_node;
}

//---------------------------------------------------------------------------//
Expand All @@ -72,7 +129,7 @@ NodeId simplify_up(CsgTree* tree, NodeId start)
NodeId result;
for (auto node_id : range(start, NodeId{tree->size()}))
{
bool simplified = tree->simplify(node_id);
auto simplified = tree->simplify(node_id);
if (simplified && !result)
{
result = node_id;
Expand Down
5 changes: 3 additions & 2 deletions src/orange/orangeinp/CsgTreeUtils.hh
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@ class CsgTree;
//---------------------------------------------------------------------------//

// Replace a node in the tree with a boolean constant
orangeinp::NodeId
replace_down(CsgTree* tree, orangeinp::NodeId n, orangeinp::Node repl_node);
void replace_and_simplify(CsgTree* tree,
orangeinp::NodeId n,
orangeinp::Node replacement);

// Simplify the tree by sweeping
orangeinp::NodeId simplify_up(CsgTree* tree, orangeinp::NodeId start);
Expand Down
5 changes: 1 addition & 4 deletions src/orange/orangeinp/UnitProto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -378,10 +378,7 @@ auto UnitProto::build(Tol const& tol, BBox const& bbox) const -> Unit
{
// 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);
replace_and_simplify(&result.tree, ext_node, False{});
}

return result;
Expand Down
9 changes: 5 additions & 4 deletions src/orange/orangeinp/detail/BuildIntersectRegion.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,17 @@ NodeId build_intersect_region(VolumeBuilder& vb,
IntersectSurfaceState css;
css.transform = &vb.local_transform();
css.object_name = std::move(label);
css.make_face_name = FaceNamer{std::move(face_prefix)};
css.make_face_name = FaceNamer{std::string{face_prefix}};

// Construct surfaces
auto sb = IntersectSurfaceBuilder(&vb.unit_builder(), &css);
region.build(sb);

// Intersect the given surfaces to create a new CSG node
return vb.insert_region(Label{std::move(css.object_name)},
Joined{op_and, std::move(css.nodes)},
calc_merged_bzone(css));
return vb.insert_region(
Label{std::move(css.object_name), std::move(face_prefix)},
Joined{op_and, std::move(css.nodes)},
calc_merged_bzone(css));
}

//---------------------------------------------------------------------------//
Expand Down
2 changes: 1 addition & 1 deletion src/orange/orangeinp/detail/InfixStringBuilder.hh
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class InfixStringBuilder
// Construct with tree and a stream to write to
inline InfixStringBuilder(CsgTree const& tree, std::ostream* os);

//! Build from a node ID
// Build from a node ID
inline void operator()(NodeId const& n);

//!@{
Expand Down
Loading

0 comments on commit 98d6ce3

Please sign in to comment.