diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index f4a6dcc33e..eecb06a204 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -41,6 +41,8 @@ namespace openmc { // Global variables //============================================================================== +extern "C" const bool libmesh_enabled; + class Mesh; namespace model { @@ -277,17 +279,12 @@ public: class UnstructuredMesh : public Mesh { public: - // constructors + // Constructors UnstructuredMesh() {}; UnstructuredMesh(pugi::xml_node node); UnstructuredMesh(const std::string& filename); - std::string bin_label(int bin) const override; - - //! Write mesh data to an HDF5 group. - // - //! \param[in] group HDF5 group - void to_hdf5(hid_t group) const; + // Methods //! Add a variable to the mesh instance virtual void add_score(const std::string& var_name) = 0; @@ -297,14 +294,31 @@ public: std::vector values, std::vector std_dev) = 0; + //! Write the unstructured mesh to file + // + // + //! \param[in] filename Name of the file to write virtual void write(std::string filename) const = 0; + //! Retrieve a centroid for the mesh cell + // + //! \param[in] bin Bin to return the centroid for + //! \return The centroid of the bin virtual Position centroid(int bin) const = 0; + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return The volume of the bin virtual double volume(int bin) const = 0; + //! Get the library used for this unstructured mesh virtual std::string library() const = 0; + std::string bin_label(int bin) const override; + + void to_hdf5(hid_t group) const override; + // Data members std::string filename_; //!< Path to unstructured mesh file }; @@ -331,27 +345,18 @@ public: // //! \param[in] p Particle to check //! \param[out] bins Surface bins that were crossed - void surface_bins_crossed(const Particle& p, std::vector& bins) const; + void surface_bins_crossed(const Particle* p, std::vector& bins) const; - //! Get bin at a given position. - // - //! \param[in] r Position to get bin for - //! \return Mesh bin int get_bin(Position r) const; - std::string library() const override; - int n_bins() const override; int n_surface_bins() const override; - //! Retrieve a centroid for the mesh cell - // - // \param[in] bin Bin to return the volume for - // \return The centroid of the element - Position centroid(int bin) const override; + std::pair, std::vector> + plot(Position plot_ll, Position plot_ur) const override; - double volume(int bin) const override; + std::string library() const override; //! Add a score to the mesh instance void add_score(const std::string& score); @@ -372,7 +377,9 @@ public: //! Write the mesh with any current tally data void write(std::string base_filename) const; - bool intersects(Position& r0, Position r1, int* ijk); + Position centroid(int bin) const override; + + double volume(int bin) const override; private: @@ -468,7 +475,7 @@ private: std::pair get_score_tags(std::string score) const; - // data members + // Data members moab::Range ehs_; //!< Range of tetrahedra EntityHandle's in the mesh moab::EntityHandle tetset_; //!< EntitySet containing all tetrahedra moab::EntityHandle kdtree_root_; //!< Root of the MOAB KDTree @@ -490,40 +497,35 @@ public: LibMesh(const std::string& filename); // Methods - - // standard mesh functions void bins_crossed(const Particle* p, std::vector& bins, std::vector& lengths) const override; - int get_bin(Position r) const override; + void surface_bins_crossed(const Particle* p, std::vector& bins) const override; - std::string library() const override; + int get_bin(Position r) const override; int n_bins() const override; int n_surface_bins() const override; - void surface_bins_crossed(const Particle* p, - std::vector& bins) const override; - std::pair, std::vector> plot(Position plot_ll, Position plot_ur) const override; - void write(std::string filename) const override; - - //! Add a variable to the libmesh mesh instance void add_score(const std::string& var_name) override; - //! Set the value of a bin for a variable on the libmesh mesh instance void set_score_data(const std::string& var_name, std::vector values, std::vector std_dev) override; + void write(std::string filename) const override; + Position centroid(int bin) const override; double volume(int bin) const override; + std::string library() const override; + private: //! Setup method for the mesh. Builds data structures, @@ -536,43 +538,14 @@ private: //! Translate an element pointer to a bin value int get_bin_from_element(const libMesh::Elem* elem) const; - //! Check whether if a point moving in a given direction - //! is inside the element - // - //! \param[in] r In: point to be checked - //! \param[in] u In: direction (this is arbitrary, any normalized direction will do) - //! \param[in] e In: libmesh element in question - //! \return whether or not the point is in the tet - bool inside_tet(const libMesh::Point& r, - const libMesh::Point& u, - const libMesh::Elem* e) const; - - //! Check if a point moving in a given direction - //! is inside the element - // - //! \param[in] r In: point to be checked - //! \param[in] u In: direction (this is arbitrary, any normalized direction will do) - //! \param[in] e In: libmesh element in question - //! \return whether or not the point is in the tet - bool inside_tet(const libMesh::Point& r, - const libMesh::Point& u, - std::unique_ptr e) const; - - double first(const libMesh::Node& a, - const libMesh::Node& b) const; - // Data members - -private: std::unique_ptr m_; //!< pointer to the libmesh mesh instance std::vector> point_locators_; //!< pointers to locators for each thread std::unique_ptr equation_systems_; //!< pointer to the equation systems of the mesh (for result output) std::map variable_map_; //!< mapping of variable names (scores) to their numbers on the mesh libMesh::BoundingBox bbox_; //!< bounding box of the mesh - libMesh::Sphere bsphere_; // boundary_elements_; // mesh_map; @@ -2205,25 +2212,10 @@ void LibMesh::initialize() { point_locators_[i]->enable_out_of_mesh_mode(); } - // will need mesh neighbors to walk the mesh - m_->find_neighbors(); - first_element_ = *m_->elements_begin(); // bounding box for the mesh bbox_ = libMesh::MeshTools::create_bounding_box(*m_); - bsphere_ = libMesh::MeshTools::bounding_sphere(*m_); - - // determine boundary elements and create bounding box - for (int i = 0; i < m_->n_elem(); i++) { - auto e = m_->elem_ptr(i); - - for (int k = 0; k < e->n_neighbors(); k++) { - if (!e->neighbor_ptr(k)) { - boundary_elements_.insert(e); - } - } - } } int LibMesh::n_bins() const { @@ -2243,15 +2235,6 @@ LibMesh::surface_bins_crossed(const Particle* p, throw std::runtime_error{"Unstructured mesh surface tallies are not implemented."}; } -std::pair, std::vector> -LibMesh::plot(Position plot_ll, - Position plot_ur) const { return {}; } - -const libMesh::Elem* -LibMesh::get_element_from_bin(int bin) const { - return m_->elem_ptr(bin); -} - void LibMesh::add_score(const std::string& var_name) { // check if this is a new varaible @@ -2309,7 +2292,7 @@ LibMesh::set_score_data(const std::string& var_name, void LibMesh::write(std::string filename) const { libMesh::ExodusII_IO exo(*m_); std::set systems_out = {eq_system_name_}; - exo.write_discontinuous_exodusII(filename, *equation_systems_, &systems_out); + exo.write_discontinuous_exodusII(filename + ".e", *equation_systems_, &systems_out); } void @@ -2328,11 +2311,10 @@ LibMesh::get_bin(Position r) const libMesh::Point p(r.x, r.y, r.z); // quick rejection check - // if (bsphere_.above_surface(p) || !bbox_.contains_point(p)) { return -1; } if (!bbox_.contains_point(p)) { return -1; } - int thread = omp_get_thread_num(); - auto e = (*point_locators_[thread])(p); + int thread = omp_get_thread_num(); + auto e = (*point_locators_[thread])(p, false); if (!e) { return -1; } else { @@ -2343,29 +2325,19 @@ LibMesh::get_bin(Position r) const int LibMesh::get_bin_from_element(const libMesh::Elem* elem) const { int bin = elem->id() - first_element_->id(); - if (bin >= n_bins()) { - std::stringstream s; - s << "Invalid bin: " << bin; - fatal_error(s); + if (bin >= n_bins() || bin < 0) { + fatal_error(fmt::format("Invalid bin: {}", bin)); } return bin; } -bool -LibMesh::inside_tet(const libMesh::Point& r, - const libMesh::Point& u, - std::unique_ptr e) const -{ - return inside_tet(r, u, e.get()); -} +std::pair, std::vector> +LibMesh::plot(Position plot_ll, + Position plot_ur) const { return {}; } - -bool -LibMesh::inside_tet(const libMesh::Point& r, - const libMesh::Point& u, - const libMesh::Elem* e) const -{ - return e->contains_point(r, FP_COINCIDENT); +const libMesh::Elem* +LibMesh::get_element_from_bin(int bin) const { + return m_->elem_ptr(bin); } double LibMesh::volume(int bin) const { return m_->elem_ref(bin).volume(); } diff --git a/tests/regression_tests/unstructured_mesh/inputs_true0.dat b/tests/regression_tests/unstructured_mesh/inputs_true0.dat index 897d79917f..916b77f0fb 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true0.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true0.dat @@ -70,8 +70,8 @@ -10.0 -10.0 -10.0 10.0 10.0 10.0 - - test_mesh_tets_w_holes.h5m + + test_mesh_tets_w_holes.exo 1 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true1.dat b/tests/regression_tests/unstructured_mesh/inputs_true1.dat index 5461b8df1f..a8633ab75d 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true1.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true1.dat @@ -70,8 +70,8 @@ -10.0 -10.0 -10.0 10.0 10.0 10.0 - - test_mesh_tets.h5m + + test_mesh_tets.exo 3 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true10.dat b/tests/regression_tests/unstructured_mesh/inputs_true10.dat new file mode 100644 index 0000000000..cb5a96a0ce --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true10.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 13 + + + 14 + + + 13 + flux + collision + + + 14 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true11.dat b/tests/regression_tests/unstructured_mesh/inputs_true11.dat new file mode 100644 index 0000000000..f721422f1d --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true11.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 15 + + + 16 + + + 15 + flux + collision + + + 16 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true12.dat b/tests/regression_tests/unstructured_mesh/inputs_true12.dat new file mode 100644 index 0000000000..f29b4ca6af --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true12.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 17 + + + 18 + + + 17 + flux + tracklength + + + 18 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true13.dat b/tests/regression_tests/unstructured_mesh/inputs_true13.dat new file mode 100644 index 0000000000..e2337e1ae0 --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true13.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 19 + + + 20 + + + 19 + flux + tracklength + + + 20 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true14.dat b/tests/regression_tests/unstructured_mesh/inputs_true14.dat new file mode 100644 index 0000000000..b8f90877fa --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true14.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 21 + + + 22 + + + 21 + flux + tracklength + + + 22 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true15.dat b/tests/regression_tests/unstructured_mesh/inputs_true15.dat new file mode 100644 index 0000000000..4ef681bc80 --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true15.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 23 + + + 24 + + + 23 + flux + tracklength + + + 24 + flux + tracklength + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true2.dat b/tests/regression_tests/unstructured_mesh/inputs_true2.dat index 3902f36b58..a93b8a160e 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true2.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true2.dat @@ -70,8 +70,8 @@ -10.0 -10.0 -10.0 10.0 10.0 10.0 - - test_mesh_tets_w_holes.h5m + + test_mesh_tets_w_holes.exo 5 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true3.dat b/tests/regression_tests/unstructured_mesh/inputs_true3.dat index 2bb59617bd..baa197a68e 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true3.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true3.dat @@ -70,8 +70,8 @@ -10.0 -10.0 -10.0 10.0 10.0 10.0 - - test_mesh_tets.h5m + + test_mesh_tets.exo 7 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true4.dat b/tests/regression_tests/unstructured_mesh/inputs_true4.dat index ee89864654..a39452da7c 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true4.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true4.dat @@ -71,7 +71,7 @@ 10.0 10.0 10.0 - test_mesh_tets_w_holes.h5m + test_mesh_tets_w_holes.exo 9 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true5.dat b/tests/regression_tests/unstructured_mesh/inputs_true5.dat index 0348bbd68e..288b7d1fcb 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true5.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true5.dat @@ -71,7 +71,7 @@ 10.0 10.0 10.0 - test_mesh_tets.h5m + test_mesh_tets.exo 11 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true6.dat b/tests/regression_tests/unstructured_mesh/inputs_true6.dat index eb7f5e4153..883e6cbf48 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true6.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true6.dat @@ -71,7 +71,7 @@ 10.0 10.0 10.0 - test_mesh_tets_w_holes.h5m + test_mesh_tets_w_holes.exo 13 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true7.dat b/tests/regression_tests/unstructured_mesh/inputs_true7.dat index 931c6a3ee8..267966e3ca 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true7.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true7.dat @@ -71,7 +71,7 @@ 10.0 10.0 10.0 - test_mesh_tets.h5m + test_mesh_tets.exo 15 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true8.dat b/tests/regression_tests/unstructured_mesh/inputs_true8.dat new file mode 100644 index 0000000000..ff3d3dc8d5 --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true8.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets_w_holes.exo + + + 9 + + + 10 + + + 9 + flux + collision + + + 10 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true9.dat b/tests/regression_tests/unstructured_mesh/inputs_true9.dat new file mode 100644 index 0000000000..953750e5ca --- /dev/null +++ b/tests/regression_tests/unstructured_mesh/inputs_true9.dat @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source + 100 + 10 + + + + + 0.0 1.0 + + + 0.0 1.0 + + + + + 15000000.0 1.0 + + + + + + + 10 10 10 + -10.0 -10.0 -10.0 + 10.0 10.0 10.0 + + + test_mesh_tets.exo + + + 11 + + + 12 + + + 11 + flux + collision + + + 12 + flux + collision + + diff --git a/tests/regression_tests/unstructured_mesh/test.py b/tests/regression_tests/unstructured_mesh/test.py index 39259a2fec..d1a013561b 100644 --- a/tests/regression_tests/unstructured_mesh/test.py +++ b/tests/regression_tests/unstructured_mesh/test.py @@ -62,17 +62,20 @@ class UnstructuredMeshTest(PyAPITestHarness): def _cleanup(self): super()._cleanup() output = glob.glob('tally*.vtk') + output += glob.glob('tally*.e') for f in output: if os.path.exists(f): os.remove(f) -param_values = (['collision', 'tracklength'], # estimators +param_values = (['libmesh', 'moab'], # mesh libraries + ['collision', 'tracklength'], # estimators [True, False], # geometry outside of the mesh [(333, 90, 77), None]) # location of holes in the mesh test_cases = [] -for i, (estimator, ext_geom, holes) in enumerate(product(*param_values)): - test_cases.append({'estimator' : estimator, +for i, (lib, estimator, ext_geom, holes) in enumerate(product(*param_values)): + test_cases.append({'library' : lib, + 'estimator' : estimator, 'external_geom' : ext_geom, 'holes' : holes, 'inputs_true' : 'inputs_true{}.dat'.format(i)}) @@ -81,6 +84,11 @@ for i, (estimator, ext_geom, holes) in enumerate(product(*param_values)): @pytest.mark.parametrize("test_opts", test_cases) def test_unstructured_mesh(test_opts): + # skip the tracklength test for libmesh + if test_opts['library'] == 'libmesh' and \ + test_opts['estimator'] == 'tracklength': + pytest.skip("Tracklength tallies are not supported using libmesh.") + ### Materials ### materials = openmc.Materials() @@ -185,12 +193,12 @@ def test_unstructured_mesh(test_opts): regular_mesh_filter = openmc.MeshFilter(mesh=regular_mesh) if test_opts['holes']: - mesh_filename = "test_mesh_tets_w_holes.h5m" + mesh_filename = "test_mesh_tets_w_holes.exo" else: - mesh_filename = "test_mesh_tets.h5m" + mesh_filename = "test_mesh_tets.exo" uscd_mesh = openmc.UnstructuredMesh(mesh_filename) - uscd_mesh.library = 'moab' + uscd_mesh.library = test_opts['library'] uscd_filter = openmc.MeshFilter(mesh=uscd_mesh) # create tallies diff --git a/tests/regression_tests/unstructured_mesh/test_mesh_tets.exo b/tests/regression_tests/unstructured_mesh/test_mesh_tets.exo new file mode 100644 index 0000000000..90e7473603 Binary files /dev/null and b/tests/regression_tests/unstructured_mesh/test_mesh_tets.exo differ diff --git a/tests/regression_tests/unstructured_mesh/test_mesh_tets.h5m b/tests/regression_tests/unstructured_mesh/test_mesh_tets.h5m deleted file mode 100644 index dc573142f6..0000000000 Binary files a/tests/regression_tests/unstructured_mesh/test_mesh_tets.h5m and /dev/null differ diff --git a/tests/regression_tests/unstructured_mesh/test_mesh_tets_w_holes.exo b/tests/regression_tests/unstructured_mesh/test_mesh_tets_w_holes.exo new file mode 100644 index 0000000000..3c30a55dc8 Binary files /dev/null and b/tests/regression_tests/unstructured_mesh/test_mesh_tets_w_holes.exo differ diff --git a/tests/regression_tests/unstructured_mesh/test_mesh_tets_w_holes.h5m b/tests/regression_tests/unstructured_mesh/test_mesh_tets_w_holes.h5m deleted file mode 100644 index 971de0ad3c..0000000000 Binary files a/tests/regression_tests/unstructured_mesh/test_mesh_tets_w_holes.h5m and /dev/null differ