Skip to content

Conversation

@osanstrong
Copy link
Contributor

Add z aligned, elliptical toroid surface.

Adds the surface class Toroid, representing an elliptical toroid with ellipse radii a and b, revolved at major radius r around a z-aligned axis at an origin o:

       ___   _________   ___
     /  |  \           /     \
    /   b   \         /       \
   |    |    |       |         |
   |-a--+    |   o-----r--+    |
   |         |       |         |
    \       /         \       /
     \     /           \     /
       ⁻⁻⁻   ⁻⁻⁻⁻⁻⁻⁻⁻⁻   ⁻⁻⁻

This PR does not fully integrate the Toroid surface, only adding the Toroid class (using prior Ferrari quartic solver implementation), an accompanying test file, and required SurfaceIO details.

@github-actions
Copy link

github-actions bot commented Dec 15, 2025

Test summary

  254 files    410 suites   9s ⏱️
1 318 tests 1 304 ✅ 14 💤 0 ❌
1 352 runs  1 348 ✅  4 💤 0 ❌

Results for commit 109dd84.

♻️ This comment has been updated with latest results.

@osanstrong
Copy link
Contributor Author

osanstrong commented Dec 15, 2025

Update: both questions resolved
Two immediate questions: I wrote this referencing #1295 , but #1295 used CELER_NOT_IMPLEMENTED for surface_type() to avoid fully integrating the surface all at once. I considered using this, but wasn't able to replicate the use without it throwing compile-time errors (the function surface_type() is elsewhere defined using CELER_CONSTEXPR_FUNCTION but it seems like CELER_NOT_IMPLEMENTED is not constexpr itself. at least from compiler error below, so I'm not sure how the initial Involute implementation used that)

[2/4] Building CXX object test/orange/CMakeFiles/orange_surf_Toroid.dir/surf/Toroid.test.cc.o
FAILED: test/orange/CMakeFiles/orange_surf_Toroid.dir/surf/Toroid.test.cc.o
/usr/bin/c++ -DGTEST_LINKED_AS_SHARED_LIBRARY=1 -I/home/oss/ORNL/celeritas/celeritas/src -I/home/oss/ORNL/celeritas/celeritas/build/include -I/home/oss/ORNL/celeritas/celeritas/test -I/home/oss/ORNL/celeritas/celeritas/build/test -isystem /home/oss/spack/var/spack/environments/celeritas/.spack-env/view/include -g -std=c++17 -fPIE -MD -MT test/orange/CMakeFiles/orange_surf_Toroid.dir/surf/Toroid.test.cc.o -MF test/orange/CMakeFiles/orange_surf_Toroid.dir/surf/Toroid.test.cc.o.d -o test/orange/CMakeFiles/orange_surf_Toroid.dir/surf/Toroid.test.cc.o -c /home/oss/ORNL/celeritas/celeritas/test/orange/surf/Toroid.test.cc
In file included from /home/oss/ORNL/celeritas/celeritas/src/corecel/cont/detail/SpanImpl.hh:12,
                 from /home/oss/ORNL/celeritas/celeritas/src/corecel/cont/Span.hh:16,
                 from /home/oss/ORNL/celeritas/celeritas/src/corecel/cont/SpanIO.hh:12,
                 from /home/oss/ORNL/celeritas/celeritas/src/corecel/cont/ArrayIO.hh:14,
                 from /home/oss/ORNL/celeritas/celeritas/src/orange/surf/Toroid.hh:12,
                 from /home/oss/ORNL/celeritas/celeritas/src/orange/surf/Toroid.cc:7,
                 from /home/oss/ORNL/celeritas/celeritas/test/orange/surf/Toroid.test.cc:7:
/home/oss/ORNL/celeritas/celeritas/src/orange/surf/Toroid.hh: In static member function ‘static constexpr celeritas::SurfaceType celeritas::Toroid::surface_type()’:
/home/oss/ORNL/celeritas/celeritas/src/corecel/Assert.hh:186:41: error: call to non-‘constexpr’ function ‘void celeritas::throw_runtime_error(celeritas::RuntimeErrorDetails&&)’
  186 |         ::celeritas::throw_runtime_error({         \
      |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~
  187 |             WHICH,                                 \
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  188 |             WHAT,                                  \
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  189 |             COND,                                  \
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  190 |             __FILE__,                              \
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  191 |             __LINE__,                              \
      |             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  192 |         })
      |         ~~
/home/oss/ORNL/celeritas/celeritas/src/corecel/Assert.hh:245:5: note: in expansion of macro ‘CELER_RUNTIME_THROW’
  245 |     CELER_RUNTIME_THROW(::celeritas::RuntimeError::not_impl_err_str, WHAT, {})
      |     ^~~~~~~~~~~~~~~~~~~
/home/oss/ORNL/celeritas/celeritas/src/orange/surf/Toroid.hh:63:9: note: in expansion of macro ‘CELER_NOT_IMPLEMENTED’
   63 |         CELER_NOT_IMPLEMENTED("runtime toroid");
      |         ^~~~~~~~~~~~~~~~~~~~~
/home/oss/ORNL/celeritas/celeritas/src/corecel/Assert.hh:382:19: note: ‘void celeritas::throw_runtime_error(celeritas::RuntimeErrorDetails&&)’ declared here
  382 | [[noreturn]] void throw_runtime_error(RuntimeErrorDetails&&);
      |                   ^~~~~~~~~~~~~~~~~~~
ninja: build stopped: cannot make progress due to previous errors.

As for the second question, I'm still new to linking & header files: how are the surfaces set up so you only need to include <name>.hh? (E.g. SimpleQuadric.test.cc: #include "orange/surf/SimpleQuadric.hh"). When I set up my test file, the compiler couldn't find the constructor definition in Toroid.cc if I included #include "orange/surf/Toroid.hh", and I had to instead include #include "orange/surf/Toroid.cc", but this feels like a cop-out solution/I'm missing something, since the other surfaces don't do that.

@sethrj sethrj added enhancement New feature or request orange Work on ORANGE geometry engine labels Dec 15, 2025
Copy link
Member

@sethrj sethrj left a comment

Choose a reason for hiding this comment

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

This is really amazing work @osanstrong ! I have a couple of comments so far from a quick review, but I think what you've got is practically perfect.

/*!
* Shorthand for subtracting vector b from vector a
*/
CELER_FUNCTION Real3 Toroid::sub(Real3 const& a, Real3 const& b)
Copy link
Member

Choose a reason for hiding this comment

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

This and sq can be CELER_CONSTEXPR_FUNCTION; you can also include ArrayOperator.hh (which we discourage by default because it's easy to write surprisingly inefficient expressions like (x = a - b + c * d)) and just use a - b.

{
auto [x0, y0, z0] = sub(pos, origin_);

real_type d = std::sqrt(sq(x0) + sq(y0));
Copy link
Member

Choose a reason for hiding this comment

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

Use hypot from corecel/math/Algorithms.hh

Suggested change
real_type d = std::sqrt(sq(x0) + sq(y0));
real_type d = hypot(x0, y0);

Comment on lines +222 to +223
real_type A0 = 4 * sq(r_);
real_type B0 = sq(r_) - sq(a_);
Copy link
Member

Choose a reason for hiding this comment

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

We try to keep to the variable formatting standards even for math equations (no uppercase), and it looks like you might even be able to easily eliminate these two variables since they're only used once (q, u)


real_type f = 1 - sq(az);
real_type g = f + p * sq(az);
real_type l = 2 * (x0 * ax + y0 * ay);
Copy link
Member

Choose a reason for hiding this comment

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

l is also dangerous since it looks like 1 and I 🙃

Comment on lines +170 to +175
if (val < 0)
return SignedSense::inside;
else if (val > 0)
return SignedSense::outside;
else
return SignedSense::on;
Copy link
Member

Choose a reason for hiding this comment

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

From orange/SenseUtils.hh, use real_to_sense

Suggested change
if (val < 0)
return SignedSense::inside;
else if (val > 0)
return SignedSense::outside;
else
return SignedSense::on;
return real_to_sense(val);

@sethrj sethrj mentioned this pull request Dec 15, 2025
5 tasks
Copy link
Contributor

@elliottbiondo elliottbiondo left a comment

Choose a reason for hiding this comment

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

Looks great @osanstrong! Just a couple of things.

* \f[
* (x^2 + y^2 + p*y^2 + B_0) - A_0 * (x^2 + y^2) = 0
* \f]
* where \f[p = a^2/b^2, A_0 = 4*r^2, and B_0 = (r^2-a^2)\f].
Copy link
Contributor

Choose a reason for hiding this comment

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

For inline LaTeX use \f$ ... \f$

Copy link
Member

Choose a reason for hiding this comment

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

Let's also add this to the user docs

namespace celeritas
{
//---------------------------------------------------------------------------//
/**
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
/**
/*

Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/**
/*!

{
//---------------------------------------------------------------------------//
/**
* Construct toroid from origin point and radii
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Construct toroid from origin point and radii
* Construct toroid from origin point and radii.

/**
* Construct toroid from origin point and radii
*
* \param origin 3d origin of the toroid.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* \param origin 3d origin of the toroid.
* \param Origin 3d origin of the toroid.

Copy link
Member

Choose a reason for hiding this comment

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

No, origin is the name of the parameter, which should be lowercase

, a_(ellipse_xy_radius)
, b_(ellipse_z_radius)
{
CELER_EXPECT(major_radius > 0);
Copy link
Contributor

Choose a reason for hiding this comment

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

It doesn't matter too much, but usually we validate the member data rather than the arguments

Copy link
Member

Choose a reason for hiding this comment

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

The reason I validate data is it'll also catch the error or forgetting to initialize it :)

* around a central axis. This shape can be used in everything from pipe bends
* to tokamaks in fusion reactors. Possesses a major radius r, and ellipse
* radii a and b, as shown in the below diagram:
* ___ _________ ___
Copy link
Contributor

Choose a reason for hiding this comment

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

Put ASCII art in a \verbatim block

CELER_FUNCTION real_type ellipse_z_radius() const { return b_; }

//! View of data for type-deleted storage
CELER_FUNCTION StorageSpan data() const { return {&origin_[0], 4}; }
Copy link
Contributor

Choose a reason for hiding this comment

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

The length should be 6: i.e., 3 for origin_ then r_, a_, b_.

@sethrj this is non-standard C++ and not actually guaranteed to work. Seems like a short function for manually serializing these would be better.

Copy link
Member

Choose a reason for hiding this comment

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

I think it's legal and we use it for the other shapes, but I agree an insert mechanism like the recent work with @amandalund is better. But for now let's stick with this.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah it's fine here. For posterity, I don't think it's legal in the general case; see the layout section here:

https://en.cppreference.com/w/cpp/language/data_members.html

"Alignment requirements may necessitate padding between members, or after the last member of a class."

Since these members are are all standard-sized POD, specifically doubles, the compiler is not going to add padding, but it strictly speaking doing so would be legal.

Copy link
Member

Choose a reason for hiding this comment

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

Well it seems you're right; this is an old class and I had just been working in C so perhaps I misunderstood a C rule. Okeydoke, I'll add a construction utility to the to-do list 🙃

* Calculate the coefficients of the polynomial corresponding to the given
* ray's intersections with the toroid.
*
* Written referencing Graphics Gems II.
Copy link
Contributor

Choose a reason for hiding this comment

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

Add the citation key arvo_graphics-gems_1995

}
}

Real3 add(Real3 const a, Real3 const b)
Copy link
Contributor

Choose a reason for hiding this comment

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

Use ArrayOperator.hh

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request orange Work on ORANGE geometry engine

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants