diff --git a/app/demo-loop/simple-cms.json b/app/demo-loop/simple-cms.json new file mode 100644 index 0000000000..874428e5b4 --- /dev/null +++ b/app/demo-loop/simple-cms.json @@ -0,0 +1,224 @@ +{ +"_format": "SCALE ORANGE", +"_version": 0, +"materials": { +"cell_to_mat": [ +-1, +5, +0, +1, +2, +3, +4, +5 +], +"names": [ +"si", +"pb", +"c", +"ti", +"fe", +"galactic" +] +}, +"universes": [ +{ +"_type": "simple unit", +"bbox": [ +[ +-1000.0, +-1000.0, +-2000.0 +], +[ +1000.0, +1000.0, +2000.0 +] +], +"cell_names": [ +"[EXTERIOR]", +"guide_tube", +"silicon_tracker", +"crystal_em_calorimeter", +"hadron_calorimeter", +"superconducting_solenoid", +"iron_muon_chambers", +"fill" +], +"cells": [ +{ +"faces": [ +0, +1, +2, +3, +4, +5 +], +"flags": 1, +"logic": "0 1 ~ & 2 & 3 ~ & 4 & 5 ~ & ~", +"num_intersections": 6, +"zorder": 1 +}, +{ +"faces": [ +6, +7, +8 +], +"logic": "0 ~ 1 & 2 ~ &", +"num_intersections": 4, +"zorder": 1 +}, +{ +"faces": [ +6, +7, +8, +9 +], +"flags": 1, +"logic": "0 ~ 1 & 2 ~ & ~ 1 2 ~ & 3 ~ & &", +"num_intersections": 6, +"zorder": 1 +}, +{ +"faces": [ +7, +8, +9, +10 +], +"flags": 1, +"logic": "0 1 ~ & 2 ~ & ~ 0 1 ~ & 3 ~ & &", +"num_intersections": 6, +"zorder": 1 +}, +{ +"faces": [ +7, +8, +10, +11 +], +"flags": 1, +"logic": "0 1 ~ & 2 ~ & ~ 0 1 ~ & 3 ~ & &", +"num_intersections": 6, +"zorder": 1 +}, +{ +"faces": [ +7, +8, +11, +12 +], +"flags": 1, +"logic": "0 1 ~ & 2 ~ & ~ 0 1 ~ & 3 ~ & &", +"num_intersections": 6, +"zorder": 1 +}, +{ +"faces": [ +7, +8, +12, +13 +], +"flags": 1, +"logic": "0 1 ~ & 2 ~ & ~ 0 1 ~ & 3 ~ & &", +"num_intersections": 6, +"zorder": 1 +}, +{ +"faces": [ +0, +1, +2, +3, +4, +5, +7, +8, +13 +], +"flags": 1, +"logic": "0 1 ~ & 2 & 3 ~ & 4 & 5 ~ & 6 7 ~ & 8 ~ & ~ &", +"num_intersections": 10, +"zorder": 1 +} +], +"md": { +"name": "global", +"provenance": "simple-cms.org.omn:17" +}, +"surface_names": [ +"world_box.mx", +"world_box.px", +"world_box.my", +"world_box.py", +"world_box.mz", +"world_box.pz", +"guide_tube.coz", +"crystal_em_calorimeter_outer.mz", +"crystal_em_calorimeter_outer.pz", +"silicon_tracker_outer.coz", +"crystal_em_calorimeter_outer.coz", +"hadron_calorimeter_outer.coz", +"superconducting_solenoid_outer.coz", +"iron_muon_chambers_outer.coz" +], +"surfaces": { +"data": [ +-1000.0, +1000.0, +-1000.0, +1000.0, +-2000.0, +2000.0, +900.0, +-700.0, +700.0, +15625.0, +30625.0, +75625.0, +140625.0, +490000.0 +], +"sizes": [ +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1, +1 +], +"types": [ +"px", +"px", +"py", +"py", +"pz", +"pz", +"czc", +"pz", +"pz", +"czc", +"czc", +"czc", +"czc", +"czc" +] +} +} +] +} \ No newline at end of file diff --git a/app/demo-loop/simple-cms.org.omn b/app/demo-loop/simple-cms.org.omn new file mode 100644 index 0000000000..171d0561dd --- /dev/null +++ b/app/demo-loop/simple-cms.org.omn @@ -0,0 +1,87 @@ +!############################################################################## +! File : Geometria/orange/test/data/simple-cms.org.omn +! +! Simplified Compact Muon Solenoid proxy geometry +!############################################################################## + +[GEOMETRY] +global "global" +comp : matid + si 0 + pb 1 + c 2 + ti 3 + fe 4 + galactic 5 + +[UNIVERSE=general global] +interior "world_box" + +!############################################################################## +! SHAPES ("solids") +!############################################################################## + +[UNIVERSE][SHAPE=cyl guide_tube] +axis z +radius 30 +length 1400 + +[UNIVERSE][SHAPE=cyl silicon_tracker_outer] +axis z +radius 125 +length 1400 + +[UNIVERSE][SHAPE=cyl crystal_em_calorimeter_outer] +axis z +radius 175 +length 1400 + +[UNIVERSE][SHAPE=cyl hadron_calorimeter_outer] +axis z +radius 275 +length 1400 + +[UNIVERSE][SHAPE=cyl superconducting_solenoid_outer] +axis z +radius 375 +length 1400 + +[UNIVERSE][SHAPE=cyl iron_muon_chambers_outer] +axis z +radius 700 +length 1400 + +[UNIVERSE][SHAPE=box world_box] +widths 2000 2000 4000 + +!############################################################################## +! CELLS ("volumes") +!############################################################################## + +[UNIVERSE][CELL guide_tube] +comp galactic +shapes guide_tube + +[UNIVERSE][CELL silicon_tracker] +comp si +shapes silicon_tracker_outer ~guide_tube + +[UNIVERSE][CELL crystal_em_calorimeter] +comp pb +shapes crystal_em_calorimeter_outer ~silicon_tracker_outer + +[UNIVERSE][CELL hadron_calorimeter] +comp c +shapes hadron_calorimeter_outer ~crystal_em_calorimeter_outer + +[UNIVERSE][CELL superconducting_solenoid] +comp ti +shapes superconducting_solenoid_outer ~hadron_calorimeter_outer + +[UNIVERSE][CELL iron_muon_chambers] +comp fe +shapes iron_muon_chambers_outer ~superconducting_solenoid_outer + +[UNIVERSE][CELL fill] +comp galactic +shapes -world_box +iron_muon_chambers_outer diff --git a/scripts/dev/celeritas-gen.py b/scripts/dev/celeritas-gen.py index 908aee0e84..e00d007f87 100755 --- a/scripts/dev/celeritas-gen.py +++ b/scripts/dev/celeritas-gen.py @@ -274,6 +274,43 @@ class {name}Test : public celeritas::Test ''' +OMN_TOP = '''\ +! Copyright {year} UT-Battelle, LLC and other Celeritas Developers. +! See the top-level COPYRIGHT file for details. +! SPDX-License-Identifier: (Apache-2.0 OR MIT) +''' + +ORANGE_FILE = ''' +[GEOMETRY] +global "global" +comp : matid + galactic 0 + detector 1 + +!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! + +[UNIVERSE=general global] +interior "world_box" + +[UNIVERSE][SHAPE=box world_box] +widths 10000 10000 10000 ! note: units are in cm + +[UNIVERSE][SHAPE=cyl mycyl] +axis z +radius 10 +length 20 + +!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! + +[UNIVERSE][CELL detector] +comp detector +shapes mycyl + +[UNIVERSE][CELL world_fill] +comp galactic +shapes world_box ~mycyl +''' + YEAR = datetime.today().year TEMPLATES = { @@ -293,6 +330,7 @@ class {name}Test : public celeritas::Test 'CMakeLists.txt': CMAKELISTS_FILE, 'py': PYTHON_FILE, 'sh': SHELL_FILE, + 'org.omn': ORANGE_FILE, } LANG = { @@ -306,6 +344,7 @@ class {name}Test : public celeritas::Test 'CMakeLists.txt': "CMake", 'py': "Python", 'sh': "Shell", + 'omn': "Omnibus", } TOPS = { @@ -315,6 +354,7 @@ class {name}Test : public celeritas::Test 'CMake': CMAKE_TOP, 'Python': PYTHON_TOP, 'Shell': SHELL_TOP, + 'Omnibus': OMN_TOP, } HEXT = { diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c1b507e4aa..30755dc669 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,7 @@ list(APPEND SOURCES geometry/detail/ScopedTimeAndRedirect.cc orange/Types.cc orange/construct/SurfaceInserter.cc + orange/construct/VolumeInserter.cc orange/surfaces/SurfaceIO.cc io/ImportProcess.cc io/ImportPhysicsTable.cc @@ -133,6 +134,8 @@ if(CELERITAS_USE_JSON) list(APPEND SOURCES comm/DeviceIO.json.cc comm/KernelDiagnosticsIO.json.cc + orange/construct/SurfaceInputIO.json.cc + orange/construct/VolumeInputIO.json.cc ) list(APPEND PUBLIC_DEPS nlohmann_json::nlohmann_json) endif() diff --git a/src/base/Collection.hh b/src/base/Collection.hh index 8896a132f7..40783e3948 100644 --- a/src/base/Collection.hh +++ b/src/base/Collection.hh @@ -184,6 +184,7 @@ class Collection using const_reference_type = typename CollectionTraitsT::const_reference_type; using size_type = typename I::size_type; + using value_type = T; using ItemIdT = I; using ItemRangeT = Range; using AllItemsT = AllItems; diff --git a/src/io/EventReader.cc b/src/io/EventReader.cc index 46547f6950..8284684c4d 100644 --- a/src/io/EventReader.cc +++ b/src/io/EventReader.cc @@ -7,11 +7,12 @@ //---------------------------------------------------------------------------// #include "EventReader.hh" +#include +#include + #include "base/ArrayUtils.hh" #include "comm/Logger.hh" #include "physics/base/Units.hh" -#include "HepMC3/GenEvent.h" -#include "HepMC3/ReaderFactory.h" namespace celeritas { diff --git a/src/orange/Data.hh b/src/orange/Data.hh index 036a02e78f..6ca9d63410 100644 --- a/src/orange/Data.hh +++ b/src/orange/Data.hh @@ -17,7 +17,7 @@ namespace celeritas // PARAMS //---------------------------------------------------------------------------// /*! - * Data for surface definitions. + * Data for type-deleted surface definitions. * * Surfaces each have a compile-time number of real data needed to define them. * (These usually are the nonzero coefficients of the quadric equation.) A @@ -40,6 +40,9 @@ struct SurfaceData //// METHODS //// + //! Number of surfaces + CELER_FUNCTION SurfaceId::size_type size() const { return types.size(); } + //! True if sizes are valid explicit CELER_FUNCTION operator bool() const { @@ -59,5 +62,115 @@ struct SurfaceData } }; +//---------------------------------------------------------------------------// +/*! + * Data for a single volume definition. + * + * \sa VolumeView + */ +struct VolumeDef +{ + ItemRange faces; + ItemRange logic; + + logic_int num_intersections{0}; + logic_int flags{0}; + + //! Flag values (bit field) + enum Flags : logic_int + { + internal_surfaces = 0x1 + }; +}; + +//---------------------------------------------------------------------------// +/*! + * Data for volume definitions. + */ +template +struct VolumeData +{ + //// TYPES //// + + template + using Items = Collection; + + //// DATA //// + + Items defs; + + // Storage + Collection faces; + Collection logic; + + //// METHODS //// + + //! Number of volumes + CELER_FUNCTION VolumeId::size_type size() const { return defs.size(); } + + //! True if sizes are valid + explicit CELER_FUNCTION operator bool() const { return !defs.empty(); } + + //! Assign from another set of data + template + VolumeData& operator=(const VolumeData& other) + { + CELER_EXPECT(other); + + defs = other.defs; + faces = other.faces; + logic = other.logic; + + return *this; + } +}; + +//---------------------------------------------------------------------------// +/*! + * Scalar values particular to an ORANGE geometry instance. + */ +struct OrangeParamsScalars +{ + size_type max_level{}; + size_type max_faces{}; + size_type max_intersections{}; + + // TODO: fuzziness/length scale +}; + +//---------------------------------------------------------------------------// +/*! + * Data to persistent data used by ORANGE implementation. + */ +template +struct OrangeParamsData +{ + //// DATA //// + + SurfaceData surfaces; + VolumeData volumes; + + OrangeParamsScalars scalars; + + //// METHODS //// + + //! True if assigned + explicit CELER_FUNCTION operator bool() const + { + return surfaces && volumes; + } + + //! Assign from another set of data + template + OrangeParamsData& operator=(const OrangeParamsData& other) + { + CELER_EXPECT(other); + surfaces = other.surfaces; + volumes = other.volumes; + scalars = other.scalars; + return *this; + } +}; + //---------------------------------------------------------------------------// } // namespace celeritas diff --git a/src/orange/Types.hh b/src/orange/Types.hh index 1d8fb8695a..a60b00153c 100644 --- a/src/orange/Types.hh +++ b/src/orange/Types.hh @@ -126,6 +126,28 @@ enum class SurfaceState : bool on = true }; +//---------------------------------------------------------------------------// +/*! + * Volume logic encoding. + * + * This uses an *unscoped* enum inside a *namespace* so that its values can be + * freely intermingled with other integers that represent face IDs. + */ +namespace logic +{ +//! Special logical Evaluator tokens. +// The enum values are set to the highest 4 values of logic_int. +enum OperatorToken : logic_int +{ + lbegin = logic_int(~logic_int(4)), + ltrue = lbegin, //!< Push 'true' + lor, //!< Binary logical OR + land, //!< Binary logical AND + lnot, //!< Unary negation + lend +}; +} // namespace logic + //---------------------------------------------------------------------------// // HELPER FUNCTIONS (HOST/DEVICE) //---------------------------------------------------------------------------// @@ -202,10 +224,19 @@ CELER_CONSTEXPR_FUNCTION real_type no_intersection() return numeric_limits::infinity(); } +//---------------------------------------------------------------------------// +namespace logic +{ +//! Whether an integer is a special logic token. +CELER_CONSTEXPR_FUNCTION bool is_operator_token(logic_int lv) +{ + return (lv >= lbegin); +} +} // namespace logic + //---------------------------------------------------------------------------// // HELPER FUNCTIONS (HOST) //---------------------------------------------------------------------------// - //! Get a printable character corresponding to a sense. inline static constexpr char to_char(Sense s) { @@ -221,6 +252,15 @@ inline static constexpr char to_char(Axis ax) // Get a string corresponding to a surface type const char* to_cstring(SurfaceType); +//! Get a printable character corresponding to an operator. +namespace logic +{ +inline static constexpr char to_char(OperatorToken tok) +{ + return is_operator_token(tok) ? "*|&~"[tok - lbegin] : '\a'; +} +} // namespace logic + //---------------------------------------------------------------------------// } // namespace celeritas diff --git a/src/orange/construct/SurfaceInput.hh b/src/orange/construct/SurfaceInput.hh new file mode 100644 index 0000000000..4933d18144 --- /dev/null +++ b/src/orange/construct/SurfaceInput.hh @@ -0,0 +1,29 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file SurfaceInput.hh +//---------------------------------------------------------------------------// +#pragma once + +#include +#include "../Data.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Compressed input for all surface definitions in a universe. + * + * Including the sizes of each surface is redundant but safer. + */ +struct SurfaceInput +{ + std::vector types; //!< Surface type enums + std::vector data; //!< Compressed surface data + std::vector sizes; //!< Size of each surface's data +}; + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/orange/construct/SurfaceInputIO.json.cc b/src/orange/construct/SurfaceInputIO.json.cc new file mode 100644 index 0000000000..9737a87fce --- /dev/null +++ b/src/orange/construct/SurfaceInputIO.json.cc @@ -0,0 +1,74 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file SurfaceInputIO.json.cc +//---------------------------------------------------------------------------// +#include "SurfaceInputIO.json.hh" + +#include +#include +#include "base/Range.hh" + +namespace celeritas +{ +namespace +{ +//---------------------------------------------------------------------------// +/*! + * Build a vector of strings for each surface type. + */ +std::vector make_surface_strings() +{ + std::vector result(static_cast(SurfaceType::size_)); + for (auto surf_type : range(SurfaceType::size_)) + { + result[static_cast(surf_type)] = to_cstring(surf_type); + } + return result; +} + +//---------------------------------------------------------------------------// +/*! + * Convert a surface type string to an enum for I/O. + */ +SurfaceType to_surface_type(const std::string& s) +{ + // The number of surface types will be short, and presumably each string is + // small enough to fit inside string's static allocation. Therefore the + // string search will be on a small-ish, nearly contiguous block of memory, + // so it's preferable than using unordered_map or a more heavyweight + // container. + static const auto surface_string = make_surface_strings(); + + auto iter = std::find(surface_string.begin(), surface_string.end(), s); + CELER_VALIDATE(iter != surface_string.end(), + << "invalid surface string '" << s << "'"); + + unsigned int result_int = iter - surface_string.begin(); + CELER_EXPECT(result_int < static_cast(SurfaceType::size_)); + return static_cast(result_int); +} +} // namespace + +//---------------------------------------------------------------------------// +/*! + * I/O routine for JSON. + */ +void from_json(const nlohmann::json& j, SurfaceInput& value) +{ + // Read and convert types + auto type_labels = j.at("types").get>(); + value.types.resize(type_labels.size()); + std::transform(type_labels.begin(), + type_labels.end(), + value.types.begin(), + &to_surface_type); + + j.at("data").get_to(value.data); + j.at("sizes").get_to(value.sizes); +} + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/orange/construct/SurfaceInputIO.json.hh b/src/orange/construct/SurfaceInputIO.json.hh new file mode 100644 index 0000000000..4daca3d04f --- /dev/null +++ b/src/orange/construct/SurfaceInputIO.json.hh @@ -0,0 +1,20 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file SurfaceInputIO.json.hh +//---------------------------------------------------------------------------// +#pragma once + +#include +#include "SurfaceInput.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// + +void from_json(const nlohmann::json& j, SurfaceInput& value); + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/orange/construct/SurfaceInserter.cc b/src/orange/construct/SurfaceInserter.cc index 76da09bf9b..58fdeddabf 100644 --- a/src/orange/construct/SurfaceInserter.cc +++ b/src/orange/construct/SurfaceInserter.cc @@ -8,9 +8,28 @@ #include "SurfaceInserter.hh" #include "base/CollectionBuilder.hh" +#include "base/Range.hh" +#include "orange/surfaces/SurfaceAction.hh" namespace celeritas { +namespace +{ +//---------------------------------------------------------------------------// +// HELPER FUNCTIONS +//---------------------------------------------------------------------------// +template +struct SurfaceDataSize +{ + constexpr size_type operator()() const noexcept + { + return T::Storage::extent; + } +}; + +//---------------------------------------------------------------------------// +} // namespace + //---------------------------------------------------------------------------// /*! * Construct with a reference to empty surfaces. @@ -45,5 +64,59 @@ SurfaceId SurfaceInserter::operator()(GenericSurfaceRef generic_surf) return SurfaceId{new_id}; } +//---------------------------------------------------------------------------// +/*! + * Insert all surfaces at once. + */ +auto SurfaceInserter::operator()(const SurfaceInput& s) -> SurfaceRange +{ + //// Check input consistency //// + + CELER_VALIDATE(s.types.size() == s.sizes.size(), + << "inconsistent surfaces input: number of types (" + << s.types.size() << ") must match number of sizes (" + << s.sizes.size() << ")"); + + auto get_data_size = make_static_surface_action(); + + size_type accum_size = 0; + for (auto i : range(s.types.size())) + { + size_type expected_size = get_data_size(s.types[i]); + CELER_VALIDATE(expected_size == s.sizes[i], + << "inconsistent surface data size (" << s.sizes[i] + << ") for entry " << i << ": " + << "surface type " << to_cstring(s.types[i]) + << " should have " << expected_size); + accum_size += expected_size; + } + + CELER_VALIDATE(accum_size == s.data.size(), + << "incorrect surface data size (" << s.data.size() + << "): should match accumulated sizes (" << accum_size + << ")"); + + //// Insert data //// + + SurfaceId start_id{surface_data_->types.size()}; + size_type start_offset = surface_data_->reals.size(); + + auto types = make_builder(&surface_data_->types); + auto offsets = make_builder(&surface_data_->offsets); + auto reals = make_builder(&surface_data_->reals); + + types.insert_back(s.types.begin(), s.types.end()); + reals.insert_back(s.data.begin(), s.data.end()); + + offsets.reserve(offsets.size() + s.sizes.size()); + for (auto single_size : s.sizes) + { + offsets.push_back(OpaqueId{start_offset}); + start_offset += single_size; + } + + return {start_id, SurfaceId{types.size()}}; +} + //---------------------------------------------------------------------------// } // namespace celeritas diff --git a/src/orange/construct/SurfaceInserter.hh b/src/orange/construct/SurfaceInserter.hh index 9daab7945a..ac09e9ba9d 100644 --- a/src/orange/construct/SurfaceInserter.hh +++ b/src/orange/construct/SurfaceInserter.hh @@ -7,6 +7,7 @@ //---------------------------------------------------------------------------// #pragma once +#include "SurfaceInput.hh" #include "../Data.hh" namespace celeritas @@ -30,6 +31,7 @@ class SurfaceInserter //!@{ //! Type aliases using Data = SurfaceData; + using SurfaceRange = ItemRange; //!@} //! Type-deleted reference to a surface @@ -43,7 +45,7 @@ class SurfaceInserter public: // Construct with reference to surfaces to build - explicit SurfaceInserter(Data* surfaces_); + explicit SurfaceInserter(Data* surfaces); // Add a new surface template @@ -52,6 +54,9 @@ class SurfaceInserter // Append a generic surface view to the vector SurfaceId operator()(GenericSurfaceRef generic_surf); + // Create a bunch of surfaces (experimental) + SurfaceRange operator()(const SurfaceInput& all_surfaces); + private: Data* surface_data_; }; diff --git a/src/orange/construct/VolumeInput.hh b/src/orange/construct/VolumeInput.hh new file mode 100644 index 0000000000..e4a83382cf --- /dev/null +++ b/src/orange/construct/VolumeInput.hh @@ -0,0 +1,39 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file VolumeInput.hh +//---------------------------------------------------------------------------// +#pragma once + +#include "base/Span.hh" +#include "../Data.hh" +#include "../Types.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Input definition for a single volume. + */ +struct VolumeInput +{ + using Flags = VolumeDef::Flags; + + //! Sorted list of surface IDs in this cell + std::vector faces{}; + //! RPN region definition for this cell, using local surface index + std::vector logic{}; + + //! Total number of surface intersections possible in this volume + logic_int num_intersections{0}; + //! Special flags + logic_int flags{0}; + + //! Whether the volume definition is valid + explicit operator bool() const { return !logic.empty(); } +}; + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/orange/construct/VolumeInputIO.json.cc b/src/orange/construct/VolumeInputIO.json.cc new file mode 100644 index 0000000000..8604e55791 --- /dev/null +++ b/src/orange/construct/VolumeInputIO.json.cc @@ -0,0 +1,98 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file VolumeInputIO.json.cc +//---------------------------------------------------------------------------// +#include "VolumeInputIO.json.hh" + +namespace celeritas +{ +namespace +{ +//---------------------------------------------------------------------------// +/*! + * Build a cell from a C string. + * + * This used by JSON input processing and will eventually be used in unit + * tests. A valid string satisfies the regex "[0-9~!| ]+", but the result may + * not be a valid logic expression. (The volume inserter will ensure that the + * logic expression at least is consistent for a CSG region definition.) + * + * Example: + * \code + + parse_logic("4 ~ 5 & 6 &"); + + \endcode + */ +std::vector parse_logic(const char* c) +{ + std::vector result; + logic_int s = 0; + while (char v = *c++) + { + if (v >= '0' && v <= '9') + { + // Parse a surface number. 'Push' this digit onto the surface ID by + // multiplying the existing ID by 10. + s = 10 * s + (v - '0'); + + const char next = *c; + if (next == ' ' || next == '\0') + { + // Next char is end of word or end of string + result.push_back(s); + s = 0; + } + } + else + { + // Parse a logic token + switch (v) + { + // clang-format off + case ' ': break; + case '*': result.push_back(logic::ltrue); break; + case '|': result.push_back(logic::lor); break; + case '&': result.push_back(logic::land); break; + case '~': result.push_back(logic::lnot); break; + default: CELER_ASSERT_UNREACHABLE(); + // clang-format on + } + } + } + return result; +} +//---------------------------------------------------------------------------// +} // namespace + +//---------------------------------------------------------------------------// +/*! + * I/O routine for JSON. + */ +void from_json(const nlohmann::json& j, VolumeInput& value) +{ + // Convert faces to OpaqueId + std::vector temp_faces; + j.at("faces").get_to(temp_faces); + value.faces.reserve(temp_faces.size()); + for (auto surfid : temp_faces) + { + CELER_ASSERT(surfid != SurfaceId{}.unchecked_get()); + value.faces.emplace_back(surfid); + } + + // Convert logic string to vector + auto temp_logic = j.at("logic").get(); + value.logic = parse_logic(temp_logic.c_str()); + + // Read scalars, including optional flags + j.at("num_intersections").get_to(value.num_intersections); + auto flag_iter = j.find("flags"); + value.flags = (flag_iter == j.end() ? 0 : flag_iter->get()); +} + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/orange/construct/VolumeInputIO.json.hh b/src/orange/construct/VolumeInputIO.json.hh new file mode 100644 index 0000000000..72e12fcc37 --- /dev/null +++ b/src/orange/construct/VolumeInputIO.json.hh @@ -0,0 +1,20 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file VolumeInputIO.json.hh +//---------------------------------------------------------------------------// +#pragma once + +#include +#include "VolumeInput.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// + +void from_json(const nlohmann::json& j, VolumeInput& value); + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/orange/construct/VolumeInserter.cc b/src/orange/construct/VolumeInserter.cc new file mode 100644 index 0000000000..3f82530a7b --- /dev/null +++ b/src/orange/construct/VolumeInserter.cc @@ -0,0 +1,98 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file VolumeInserter.cc +//---------------------------------------------------------------------------// +#include "VolumeInserter.hh" + +#include +#include "base/CollectionBuilder.hh" + +namespace celeritas +{ +namespace +{ +//---------------------------------------------------------------------------// +/*! + * Calculate the maximum logic depth of a volume definition. + * + * Return 0 if the definition is invalid so that we can raise an assertion in + * the caller with more context. + */ +int calc_max_depth(Span logic) +{ + CELER_EXPECT(!logic.empty()); + // Calculate max depth + int max_depth = 1; + int cur_depth = 0; + + for (auto id : logic) + { + if (!logic::is_operator_token(id) || id == logic::ltrue) + { + ++cur_depth; + } + else if (id == logic::land || id == logic::lor) + { + max_depth = std::max(cur_depth, max_depth); + --cur_depth; + } + } + if (cur_depth != 1) + { + // Input definition is invalid; return a sentinel value + max_depth = 0; + } + return max_depth; +} +//---------------------------------------------------------------------------// +} // namespace + +//---------------------------------------------------------------------------// +/*! + * Construct with a reference to empty volume data. + */ +VolumeInserter::VolumeInserter(Data* volumes) : volume_data_(volumes) +{ + CELER_EXPECT(volume_data_ && volume_data_->defs.empty()); +} + +//---------------------------------------------------------------------------// +/*! + * Insert a volume. + * + * TODO: add consistancy checks with number of surfaces? + */ +VolumeId VolumeInserter::operator()(const VolumeInput& input) +{ + CELER_EXPECT(input); + CELER_EXPECT(std::is_sorted(input.faces.begin(), input.faces.end())); + + VolumeId::size_type new_id = volume_data_->defs.size(); + + // Calculate the maximum stack depth of the volume definition + int this_max_depth = calc_max_depth(make_span(input.logic)); + CELER_VALIDATE(this_max_depth > 0, + << "invalid logic definition in volume " << new_id + << ": operators do not balance"); + max_logic_depth_ = std::max(max_logic_depth_, this_max_depth); + + auto defs = make_builder(&volume_data_->defs); + auto faces = make_builder(&volume_data_->faces); + auto logic = make_builder(&volume_data_->logic); + + VolumeDef output; + output.faces = faces.insert_back(input.faces.begin(), input.faces.end()); + output.logic = logic.insert_back(input.logic.begin(), input.logic.end()); + output.num_intersections = input.num_intersections; + output.flags = input.flags; + defs.push_back(output); + + CELER_ENSURE(defs.size() == new_id + 1); + return VolumeId{new_id}; +} + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/src/orange/construct/VolumeInserter.hh b/src/orange/construct/VolumeInserter.hh new file mode 100644 index 0000000000..d3f4b0c212 --- /dev/null +++ b/src/orange/construct/VolumeInserter.hh @@ -0,0 +1,52 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file VolumeInserter.hh +//---------------------------------------------------------------------------// +#pragma once + +#include "../Data.hh" +#include "VolumeInput.hh" + +namespace celeritas +{ +//---------------------------------------------------------------------------// +/*! + * Construct volumes on the host. + * + * Currently this requires the full volume attribute exported from + * SCALE-ORANGE, but it can be reworked in the future to calculate attributes + * (such as number of intersections) at construction time. We can also + * implement deduplication of the logic references to reduce memory + * storage and improve locality. Finally, when we add support for multiple + * universes, we might need to add a surface ID mapping for the volume input, + * since the face IDs from one universe won't match the stored global face IDs + * inside Celeritas-ORANGE. + */ +class VolumeInserter +{ + public: + //!@{ + //! Type aliases + using Data = VolumeData; + //!@} + + public: + // Construct with defaults + explicit VolumeInserter(Data* volumes); + + // Append a volume + VolumeId operator()(const VolumeInput& vol_def); + + //! Get the maximum stack depth of any volume definition + int max_logic_depth() const { return max_logic_depth_; } + + private: + Data* volume_data_{nullptr}; + int max_logic_depth_{0}; +}; + +//---------------------------------------------------------------------------// +} // namespace celeritas diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f7faf91f72..89a734c28e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -183,6 +183,9 @@ endif() celeritas_setup_tests(SERIAL PREFIX orange) +celeritas_add_test(orange/construct/SurfaceInserter.test.cc) +celeritas_add_test(orange/construct/VolumeInserter.test.cc) + celeritas_add_test(orange/surfaces/detail/QuadraticSolver.test.cc) celeritas_add_test(orange/surfaces/CylCentered.test.cc) celeritas_add_test(orange/surfaces/GeneralQuadric.test.cc) diff --git a/test/orange/construct/SurfaceInserter.test.cc b/test/orange/construct/SurfaceInserter.test.cc new file mode 100644 index 0000000000..fd58cb4e79 --- /dev/null +++ b/test/orange/construct/SurfaceInserter.test.cc @@ -0,0 +1,94 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file SurfaceInserter.test.cc +//---------------------------------------------------------------------------// +#include "orange/construct/SurfaceInserter.hh" + +#include + +#include "celeritas_config.h" +#include "celeritas_test.hh" +#include "orange/construct/SurfaceInput.hh" +#include "orange/surfaces/PlaneAligned.hh" +#include "orange/surfaces/CylCentered.hh" +#include "orange/surfaces/GeneralQuadric.hh" +#include "orange/surfaces/Sphere.hh" + +#if CELERITAS_USE_JSON +# include "orange/construct/SurfaceInputIO.json.hh" +#endif + +using namespace celeritas; + +//---------------------------------------------------------------------------// +// TEST HARNESS +//---------------------------------------------------------------------------// + +class SurfaceInserterTest : public celeritas::Test +{ + protected: + SurfaceData surface_data_; +}; + +//---------------------------------------------------------------------------// +// TESTS +//---------------------------------------------------------------------------// + +TEST_F(SurfaceInserterTest, manual) +{ + SurfaceInserter insert(&surface_data_); + EXPECT_EQ(SurfaceId{0}, insert(PlaneX(1))); + EXPECT_EQ(SurfaceId{1}, insert(CCylX(2))); + EXPECT_EQ(SurfaceId{2}, insert(Sphere({1, 2, 3}, 4))); + EXPECT_EQ(SurfaceId{3}, + insert(GeneralQuadric({0, 1, 2}, {3, 4, 5}, {6, 7, 8}, 9))); + + EXPECT_EQ(4, surface_data_.types.size()); + EXPECT_EQ(4, surface_data_.offsets.size()); + + const double expected_reals[] + = {1, 4, 1, 2, 3, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + EXPECT_VEC_SOFT_EQ(expected_reals, + surface_data_.reals[AllItems{}]); +} + +TEST_F(SurfaceInserterTest, from_input) +{ + SurfaceInput input; + input.types = {SurfaceType::px, SurfaceType::s}; + input.data = {1.25, 4, 0, 1, 2}; + input.sizes = {1, 4}; + + SurfaceInserter insert(&surface_data_); + + // Initial insert + auto surface_range = insert(input); + EXPECT_EQ(SurfaceId{0}, *surface_range.begin()); + EXPECT_EQ(2, surface_range.size()); + + // Insert again + surface_range = insert(input); + EXPECT_EQ(SurfaceId{2}, *surface_range.begin()); + EXPECT_EQ(2, surface_range.size()); +} + +TEST_F(SurfaceInserterTest, from_json) +{ + SurfaceInserter insert(&surface_data_); + std::ifstream infile( + this->test_data_path("orange", "five-volumes.org.json")); + +#if !CELERITAS_USE_JSON + GTEST_SKIP() << "JSON is not enabled"; +#else + auto full_inp = nlohmann::json::parse(infile); + const auto& surfaces = full_inp["universes"][0]["surfaces"]; + + auto surface_range = insert(surfaces.get()); + EXPECT_EQ(SurfaceId{0}, *surface_range.begin()); + EXPECT_EQ(12, surface_range.size()); +#endif +} diff --git a/test/orange/construct/VolumeInserter.test.cc b/test/orange/construct/VolumeInserter.test.cc new file mode 100644 index 0000000000..91edc936a0 --- /dev/null +++ b/test/orange/construct/VolumeInserter.test.cc @@ -0,0 +1,94 @@ +//----------------------------------*-C++-*----------------------------------// +// Copyright 2021 UT-Battelle, LLC, and other Celeritas developers. +// See the top-level COPYRIGHT file for details. +// SPDX-License-Identifier: (Apache-2.0 OR MIT) +//---------------------------------------------------------------------------// +//! \file VolumeInserter.test.cc +//---------------------------------------------------------------------------// +#include "orange/construct/VolumeInserter.hh" + +#include + +#include "celeritas_config.h" +#include "celeritas_test.hh" +#include "orange/construct/VolumeInput.hh" + +#if CELERITAS_USE_JSON +# include "orange/construct/VolumeInputIO.json.hh" +#endif + +using namespace celeritas; + +//---------------------------------------------------------------------------// +// TEST HARNESS +//---------------------------------------------------------------------------// + +class VolumeInserterTest : public celeritas::Test +{ + protected: + VolumeData volume_data_; +}; + +//---------------------------------------------------------------------------// +// TESTS +//---------------------------------------------------------------------------// + +TEST_F(VolumeInserterTest, manual) +{ + VolumeInserter insert(&volume_data_); + + { + // Empty volume + VolumeInput input; + input.logic = {logic::ltrue}; + EXPECT_EQ(VolumeId{0}, insert(input)); + EXPECT_EQ(1, insert.max_logic_depth()); + } + + { + // Volume with one face + VolumeInput input; + input.faces = {SurfaceId{0}}; + input.logic = {0}; + EXPECT_EQ(VolumeId{1}, insert(input)); + EXPECT_EQ(1, insert.max_logic_depth()); + } + + { + // Volume with two joined face + VolumeInput input; + input.faces = {SurfaceId{0}, SurfaceId{1}}; + input.logic = {0, logic::lnot, 1, logic::land}; + EXPECT_EQ(VolumeId{2}, insert(input)); + EXPECT_EQ(2, insert.max_logic_depth()); + } + + { + // Invalid definition (needs 'and'/'or') + VolumeInput input; + input.faces = {SurfaceId{0}, SurfaceId{1}}; + input.logic = {0, logic::lnot, 1}; + EXPECT_THROW(insert(input), RuntimeError); + } +} + +TEST_F(VolumeInserterTest, from_json) +{ + VolumeInserter insert(&volume_data_); + std::ifstream infile( + this->test_data_path("orange", "five-volumes.org.json")); + +#if !CELERITAS_USE_JSON + GTEST_SKIP() << "JSON is not enabled"; +#else + auto full_inp = nlohmann::json::parse(infile); + + VolumeId::size_type volid = 0; + for (const auto& vol_inp : full_inp["universes"][0]["cells"]) + { + auto id = insert(vol_inp.get()); + EXPECT_EQ(volid, id.unchecked_get()); + ++volid; + } +#endif +} diff --git a/test/orange/data/.gitignore b/test/orange/data/.gitignore new file mode 100644 index 0000000000..7501b45c75 --- /dev/null +++ b/test/orange/data/.gitignore @@ -0,0 +1 @@ +*.org.xml diff --git a/test/orange/data/five-volumes.ipynb b/test/orange/data/five-volumes.ipynb new file mode 100644 index 0000000000..fc9b70367e --- /dev/null +++ b/test/orange/data/five-volumes.ipynb @@ -0,0 +1,248 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import os.path\n", + "import sys\n", + "\n", + "%matplotlib inline\n", + "%load_ext wurlitzer\n", + "%config Completer.use_jedi = False\n", + "build_dir = '/rnsdhpc/code/_build/scale-orange'\n", + "sys.path[:0] = [os.path.join(build_dir, subdir)\n", + " for subdir in ['python', 'src/nemesis', 'src/transcore', 'src/robus', 'src/geometria']]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import geometria" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "

Loading Omnibus tools from Exnihilo version 6.3.pre-0 (branch 'celeritas-json-update' #12304ffe on 2021NOV09) [debug] [DBC=7]

" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from omnibus.raytrace.imager import Imager\n", + "from omnibus.raytrace.load import load_orange" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Five boring volumes" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Generating ORANGE model XML input file from .org.omn...\n", + " ...finished generating ORANGE model XML input file from .org.omn\n" + ] + } + ], + "source": [ + "m = load_orange(\"five-volumes.org.omn\")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "************************************************\n", + "\"global\" (five-volumes.org.omn:9)\n", + "************************************************\n", + ":Type: simple unit\n", + ":# Cells: 6 (offset = 0)\n", + ":# Surfaces: 12 (offset = 0)\n", + ":Bounding box: ``{-100 -100 -100 to 100 100 100}``\n", + "\n", + "======= ========== ============================================================\n", + "Cell Name Surface logic\n", + "======= ========== ============================================================\n", + "0 [EXTERIOR] 0\n", + " (from ``five-volumes.org.omn:9``)\n", + "1 a 1 2 ~ & 3 & 4 ~ & 5 & 6 ~ & 7 &\n", + " (from ``five-volumes.org.omn:34``)\n", + "2 b 7 3 ~ 5 & 6 ~ & 8 & 9 ~ & 10 & &\n", + " (from ``five-volumes.org.omn:38``)\n", + "3 c 7 ~ 11 &\n", + " (from ``five-volumes.org.omn:42``)\n", + "4 d 0 ~ 1 2 ~ & 3 & 4 ~ & 5 & 6 ~ & ~ & 7 & 3 ~ 5 & 6 ~ & 8 & 9\n", + " ~ & 10 & ~ &\n", + " (from ``five-volumes.org.omn:46``)\n", + "5 e 11 ~\n", + " (from ``five-volumes.org.omn:50``)\n", + "======= ========== ============================================================\n", + "\n", + "Cells with reentrant surface tracking: \"a\", \"b\", \"c\", \"d\"\n", + "\n", + "======= ========= ============================================================\n", + "Surface Name Description\n", + "======= ========= ============================================================\n", + "0 Sphere: r=100\n", + " outer.s (from ``five-volumes.org.omn:14``)\n", + "1 Plane: x=-1\n", + " alpha.mx (from ``five-volumes.org.omn:18``)\n", + "2 Plane: x=0\n", + " alpha.px (from ``five-volumes.org.omn:18``)\n", + "3 Plane: y=0\n", + " alpha.my (from ``five-volumes.org.omn:18``)\n", + " beta.py (from ``five-volumes.org.omn:21``)\n", + "4 Plane: y=1\n", + " alpha.py (from ``five-volumes.org.omn:18``)\n", + "5 Plane: z=-0.5\n", + " alpha.mz (from ``five-volumes.org.omn:18``)\n", + " beta.mz (from ``five-volumes.org.omn:21``)\n", + "6 Plane: z=0.5\n", + " alpha.pz (from ``five-volumes.org.omn:18``)\n", + " beta.pz (from ``five-volumes.org.omn:21``)\n", + "7 Sphere: r=0.75\n", + " gamma.s (from ``five-volumes.org.omn:24``)\n", + "8 Plane: x=0.5\n", + " beta.mx (from ``five-volumes.org.omn:21``)\n", + "9 Plane: x=1.5\n", + " beta.px (from ``five-volumes.org.omn:21``)\n", + "10 Plane: y=-1\n", + " beta.my (from ``five-volumes.org.omn:21``)\n", + "11 Sphere: r=0.25 at -0.25 -0.25 0\n", + " epsilon.s (from ``five-volumes.org.omn:28``)\n", + "======= ========= ============================================================\n", + "\n", + "========== ====================================================================\n", + "Cell Fill\n", + "========== ====================================================================\n", + "[EXTERIOR] ---\n", + "a Material 0\n", + "b Material 1\n", + "c Material 2\n", + "d Material 3\n", + "e Material 4\n", + "========== ====================================================================\n", + "\n", + "\n" + ] + } + ], + "source": [ + "print(m.geometry.describe())" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "imager = Imager.from_extents(m.geometry, z=0, max_pixels=512, trace='cell')\n", + "imager.plot();" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "imager.scale(50)\n", + "plots = imager.plot()\n", + "ax = plots['ax']\n", + "ax.set_xticks(np.linspace(-2, 2, 8 + 1))\n", + "ax.set_yticks(np.linspace(-2, 2, 8 + 1))\n", + "ax.grid()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/test/orange/data/five-volumes.org.json b/test/orange/data/five-volumes.org.json new file mode 100644 index 0000000000..bd741164a7 --- /dev/null +++ b/test/orange/data/five-volumes.org.json @@ -0,0 +1,188 @@ +{ +"_format": "SCALE ORANGE", +"_version": 0, +"materials": { +"cell_to_mat": [ +-1, +0, +1, +2, +3, +4 +], +"names": [ +"0", +"1", +"2", +"3", +"4" +] +}, +"universes": [ +{ +"_type": "simple unit", +"bbox": [ +[ +-100.000000000001, +-100.000000000001, +-100.000000000001 +], +[ +100.000000000001, +100.000000000001, +100.000000000001 +] +], +"cell_names": [ +"[EXTERIOR]", +"a", +"b", +"c", +"d", +"e" +], +"cells": [ +{ +"faces": [ +0 +], +"logic": "0", +"num_intersections": 2, +"zorder": 1 +}, +{ +"faces": [ +1, +2, +3, +4, +5, +6, +7 +], +"flags": 1, +"logic": "0 1 ~ & 2 & 3 ~ & 4 & 5 ~ & 6 &", +"num_intersections": 8, +"zorder": 1 +}, +{ +"faces": [ +3, +5, +6, +7, +8, +9, +10 +], +"flags": 1, +"logic": "3 0 ~ 1 & 2 ~ & 4 & 5 ~ & 6 & &", +"num_intersections": 8, +"zorder": 1 +}, +{ +"faces": [ +7, +11 +], +"flags": 1, +"logic": "0 ~ 1 &", +"num_intersections": 4, +"zorder": 1 +}, +{ +"faces": [ +0, +1, +2, +3, +4, +5, +6, +7, +8, +9, +10 +], +"flags": 1, +"logic": "0 ~ 1 2 ~ & 3 & 4 ~ & 5 & 6 ~ & ~ & 7 & 3 ~ 5 & 6 ~ & 8 & 9 ~ & 10 & ~ &", +"num_intersections": 13, +"zorder": 1 +}, +{ +"faces": [ +11 +], +"logic": "0 ~", +"num_intersections": 2, +"zorder": 1 +} +], +"md": { +"name": "global", +"provenance": "five-volumes.org.omn:9" +}, +"surface_names": [ +"outer.s", +"alpha.mx", +"alpha.px", +"alpha.my", +"alpha.py", +"alpha.mz", +"alpha.pz", +"gamma.s", +"beta.mx", +"beta.px", +"beta.my", +"epsilon.s" +], +"surfaces": { +"data": [ +0,0,0, 10000, +-1.0, +0.0, +0.0, +1.0, +-0.5, +0.5, +0,0,0, 0.5625, +0.5, +1.5, +-1.0, +-0.25, +-0.25, +0.0, +0.0625 +], +"sizes": [ +4, +1, +1, +1, +1, +1, +1, +4, +1, +1, +1, +4 +], +"types": [ +"s", +"px", +"px", +"py", +"py", +"pz", +"pz", +"s", +"px", +"px", +"py", +"s" +] +} +} +] +} diff --git a/test/orange/data/five-volumes.org.omn b/test/orange/data/five-volumes.org.omn new file mode 100644 index 0000000000..6cf48a39d0 --- /dev/null +++ b/test/orange/data/five-volumes.org.omn @@ -0,0 +1,53 @@ +! Copyright 2021 UT-Battelle, LLC and other Celeritas Developers. +! See the top-level COPYRIGHT file for details. +! SPDX-License-Identifier: (Apache-2.0 OR MIT) +[GEOMETRY] +global "global" + +!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! + +[UNIVERSE=general global] +interior "outer" + +!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! + +[UNIVERSE][SHAPE=sphere outer] +r 100 +origin 0 0 0 + +[UNIVERSE][SHAPE=cuboid alpha] +faces -1 0 0 1 -.5 .5 + +[UNIVERSE][SHAPE=cuboid beta] +faces 0.5 1.5 -1 0 -.5 .5 + +[UNIVERSE][SHAPE=sphere gamma] +r 0.75 +origin 0 0 0 + +[UNIVERSE][SHAPE=sphere epsilon] +r 0.25 +origin -.25 -.25 0 + +!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~! + +[UNIVERSE][CELL a] +comp 0 +shapes -alpha +gamma + +[UNIVERSE][CELL b] +comp 1 +shapes -beta +gamma + +[UNIVERSE][CELL c] +comp 2 +shapes -gamma +epsilon + +[UNIVERSE][CELL d] +comp 3 +shapes +alpha +beta +gamma -outer + +[UNIVERSE][CELL e] +comp 4 +shapes -epsilon +