Skip to content

Commit ed433fe

Browse files
authored
Fix performance regression in libMesh unstructured mesh tallies (#3577)
1 parent 8f36ff2 commit ed433fe

File tree

2 files changed

+100
-56
lines changed

2 files changed

+100
-56
lines changed

include/openmc/mesh.h

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -990,25 +990,26 @@ class LibMesh : public UnstructuredMesh {
990990

991991
libMesh::MeshBase* mesh_ptr() const { return m_; };
992992

993-
private:
994-
void initialize() override;
995-
void set_mesh_pointer_from_filename(const std::string& filename);
996-
void build_eqn_sys();
997-
993+
protected:
998994
// Methods
999995

1000996
//! Translate a bin value to an element reference
1001-
const libMesh::Elem& get_element_from_bin(int bin) const;
997+
virtual const libMesh::Elem& get_element_from_bin(int bin) const;
1002998

1003999
//! Translate an element pointer to a bin index
1004-
int get_bin_from_element(const libMesh::Elem* elem) const;
1000+
virtual int get_bin_from_element(const libMesh::Elem* elem) const;
1001+
1002+
libMesh::MeshBase* m_; //!< pointer to libMesh MeshBase instance, always set
1003+
//!< during intialization
1004+
private:
1005+
void initialize() override;
1006+
void set_mesh_pointer_from_filename(const std::string& filename);
1007+
void build_eqn_sys();
10051008

10061009
// Data members
10071010
unique_ptr<libMesh::MeshBase> unique_m_ =
10081011
nullptr; //!< pointer to the libMesh MeshBase instance, only used if mesh is
10091012
//!< created inside OpenMC
1010-
libMesh::MeshBase* m_; //!< pointer to libMesh MeshBase instance, always set
1011-
//!< during intialization
10121013
vector<unique_ptr<libMesh::PointLocatorBase>>
10131014
pl_; //!< per-thread point locators
10141015
unique_ptr<libMesh::EquationSystems>
@@ -1022,8 +1023,34 @@ class LibMesh : public UnstructuredMesh {
10221023
libMesh::BoundingBox bbox_; //!< bounding box of the mesh
10231024
libMesh::dof_id_type
10241025
first_element_id_; //!< id of the first element in the mesh
1026+
};
1027+
1028+
class AdaptiveLibMesh : public LibMesh {
1029+
public:
1030+
// Constructor
1031+
AdaptiveLibMesh(
1032+
libMesh::MeshBase& input_mesh, double length_multiplier = 1.0);
1033+
1034+
// Overridden methods
1035+
int n_bins() const override;
1036+
1037+
void add_score(const std::string& var_name) override;
1038+
1039+
void set_score_data(const std::string& var_name, const vector<double>& values,
1040+
const vector<double>& std_dev) override;
1041+
1042+
void write(const std::string& filename) const override;
1043+
1044+
protected:
1045+
// Overridden methods
1046+
int get_bin_from_element(const libMesh::Elem* elem) const override;
1047+
1048+
const libMesh::Elem& get_element_from_bin(int bin) const override;
1049+
1050+
private:
1051+
// Data members
1052+
const libMesh::dof_id_type num_active_; //!< cached number of active elements
10251053

1026-
const bool adaptive_; //!< whether this mesh has adaptivity enabled or not
10271054
std::vector<libMesh::dof_id_type>
10281055
bin_to_elem_map_; //!< mapping bin indices to dof indices for active
10291056
//!< elements

src/mesh.cpp

Lines changed: 63 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3219,7 +3219,7 @@ void MOABMesh::write(const std::string& base_filename) const
32193219

32203220
const std::string LibMesh::mesh_lib_type = "libmesh";
32213221

3222-
LibMesh::LibMesh(pugi::xml_node node) : UnstructuredMesh(node), adaptive_(false)
3222+
LibMesh::LibMesh(pugi::xml_node node) : UnstructuredMesh(node)
32233223
{
32243224
// filename_ and length_multiplier_ will already be set by the
32253225
// UnstructuredMesh constructor
@@ -3230,7 +3230,6 @@ LibMesh::LibMesh(pugi::xml_node node) : UnstructuredMesh(node), adaptive_(false)
32303230

32313231
// create the mesh from a pointer to a libMesh Mesh
32323232
LibMesh::LibMesh(libMesh::MeshBase& input_mesh, double length_multiplier)
3233-
: adaptive_(input_mesh.n_active_elem() != input_mesh.n_elem())
32343233
{
32353234
if (!dynamic_cast<libMesh::ReplicatedMesh*>(&input_mesh)) {
32363235
fatal_error("At present LibMesh tallies require a replicated mesh. Please "
@@ -3244,7 +3243,6 @@ LibMesh::LibMesh(libMesh::MeshBase& input_mesh, double length_multiplier)
32443243

32453244
// create the mesh from an input file
32463245
LibMesh::LibMesh(const std::string& filename, double length_multiplier)
3247-
: adaptive_(false)
32483246
{
32493247
n_dimension_ = 3;
32503248
set_mesh_pointer_from_filename(filename);
@@ -3307,21 +3305,6 @@ void LibMesh::initialize()
33073305
auto first_elem = *m_->elements_begin();
33083306
first_element_id_ = first_elem->id();
33093307

3310-
// if the mesh is adaptive elements aren't guaranteed by libMesh to be
3311-
// contiguous in ID space, so we need to map from bin indices (defined over
3312-
// active elements) to global dof ids
3313-
if (adaptive_) {
3314-
bin_to_elem_map_.reserve(m_->n_active_elem());
3315-
elem_to_bin_map_.resize(m_->n_elem(), -1);
3316-
for (auto it = m_->active_elements_begin(); it != m_->active_elements_end();
3317-
it++) {
3318-
auto elem = *it;
3319-
3320-
bin_to_elem_map_.push_back(elem->id());
3321-
elem_to_bin_map_[elem->id()] = bin_to_elem_map_.size() - 1;
3322-
}
3323-
}
3324-
33253308
// bounding box for the mesh for quick rejection checks
33263309
bbox_ = libMesh::MeshTools::create_bounding_box(*m_);
33273310
libMesh::Point ll = bbox_.min();
@@ -3379,7 +3362,7 @@ std::string LibMesh::library() const
33793362

33803363
int LibMesh::n_bins() const
33813364
{
3382-
return m_->n_active_elem();
3365+
return m_->n_elem();
33833366
}
33843367

33853368
int LibMesh::n_surface_bins() const
@@ -3402,14 +3385,6 @@ int LibMesh::n_surface_bins() const
34023385

34033386
void LibMesh::add_score(const std::string& var_name)
34043387
{
3405-
if (adaptive_) {
3406-
warning(fmt::format(
3407-
"Exodus output cannot be provided as unstructured mesh {} is adaptive.",
3408-
this->id_));
3409-
3410-
return;
3411-
}
3412-
34133388
if (!equation_systems_) {
34143389
build_eqn_sys();
34153390
}
@@ -3445,14 +3420,6 @@ void LibMesh::remove_scores()
34453420
void LibMesh::set_score_data(const std::string& var_name,
34463421
const vector<double>& values, const vector<double>& std_dev)
34473422
{
3448-
if (adaptive_) {
3449-
warning(fmt::format(
3450-
"Exodus output cannot be provided as unstructured mesh {} is adaptive.",
3451-
this->id_));
3452-
3453-
return;
3454-
}
3455-
34563423
if (!equation_systems_) {
34573424
build_eqn_sys();
34583425
}
@@ -3496,14 +3463,6 @@ void LibMesh::set_score_data(const std::string& var_name,
34963463

34973464
void LibMesh::write(const std::string& filename) const
34983465
{
3499-
if (adaptive_) {
3500-
warning(fmt::format(
3501-
"Exodus output cannot be provided as unstructured mesh {} is adaptive.",
3502-
this->id_));
3503-
3504-
return;
3505-
}
3506-
35073466
write_message(fmt::format(
35083467
"Writing file: {}.e for unstructured mesh {}", filename, this->id_));
35093468
libMesh::ExodusII_IO exo(*m_);
@@ -3537,8 +3496,7 @@ int LibMesh::get_bin(Position r) const
35373496

35383497
int LibMesh::get_bin_from_element(const libMesh::Elem* elem) const
35393498
{
3540-
int bin =
3541-
adaptive_ ? elem_to_bin_map_[elem->id()] : elem->id() - first_element_id_;
3499+
int bin = elem->id() - first_element_id_;
35423500
if (bin >= n_bins() || bin < 0) {
35433501
fatal_error(fmt::format("Invalid bin: {}", bin));
35443502
}
@@ -3553,14 +3511,73 @@ std::pair<vector<double>, vector<double>> LibMesh::plot(
35533511

35543512
const libMesh::Elem& LibMesh::get_element_from_bin(int bin) const
35553513
{
3556-
return adaptive_ ? m_->elem_ref(bin_to_elem_map_.at(bin)) : m_->elem_ref(bin);
3514+
return m_->elem_ref(bin);
35573515
}
35583516

35593517
double LibMesh::volume(int bin) const
35603518
{
35613519
return this->get_element_from_bin(bin).volume();
35623520
}
35633521

3522+
AdaptiveLibMesh::AdaptiveLibMesh(
3523+
libMesh::MeshBase& input_mesh, double length_multiplier)
3524+
: LibMesh(input_mesh, length_multiplier), num_active_(m_->n_active_elem())
3525+
{
3526+
// if the mesh is adaptive elements aren't guaranteed by libMesh to be
3527+
// contiguous in ID space, so we need to map from bin indices (defined over
3528+
// active elements) to global dof ids
3529+
bin_to_elem_map_.reserve(num_active_);
3530+
elem_to_bin_map_.resize(m_->n_elem(), -1);
3531+
for (auto it = m_->active_elements_begin(); it != m_->active_elements_end();
3532+
it++) {
3533+
auto elem = *it;
3534+
3535+
bin_to_elem_map_.push_back(elem->id());
3536+
elem_to_bin_map_[elem->id()] = bin_to_elem_map_.size() - 1;
3537+
}
3538+
}
3539+
3540+
int AdaptiveLibMesh::n_bins() const
3541+
{
3542+
return num_active_;
3543+
}
3544+
3545+
void AdaptiveLibMesh::add_score(const std::string& var_name)
3546+
{
3547+
warning(fmt::format(
3548+
"Exodus output cannot be provided as unstructured mesh {} is adaptive.",
3549+
this->id_));
3550+
}
3551+
3552+
void AdaptiveLibMesh::set_score_data(const std::string& var_name,
3553+
const vector<double>& values, const vector<double>& std_dev)
3554+
{
3555+
warning(fmt::format(
3556+
"Exodus output cannot be provided as unstructured mesh {} is adaptive.",
3557+
this->id_));
3558+
}
3559+
3560+
void AdaptiveLibMesh::write(const std::string& filename) const
3561+
{
3562+
warning(fmt::format(
3563+
"Exodus output cannot be provided as unstructured mesh {} is adaptive.",
3564+
this->id_));
3565+
}
3566+
3567+
int AdaptiveLibMesh::get_bin_from_element(const libMesh::Elem* elem) const
3568+
{
3569+
int bin = elem_to_bin_map_[elem->id()];
3570+
if (bin >= n_bins() || bin < 0) {
3571+
fatal_error(fmt::format("Invalid bin: {}", bin));
3572+
}
3573+
return bin;
3574+
}
3575+
3576+
const libMesh::Elem& AdaptiveLibMesh::get_element_from_bin(int bin) const
3577+
{
3578+
return m_->elem_ref(bin_to_elem_map_.at(bin));
3579+
}
3580+
35643581
#endif // OPENMC_LIBMESH_ENABLED
35653582

35663583
//==============================================================================

0 commit comments

Comments
 (0)