#include "openmc/mgxs_interface.h" #include #include #include "openmc/cell.h" #include "openmc/cross_sections.h" #include "openmc/container_util.h" #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/geometry_aux.h" #include "openmc/hdf5_interface.h" #include "openmc/material.h" #include "openmc/math_functions.h" #include "openmc/nuclide.h" #include "openmc/settings.h" namespace openmc { //============================================================================== // Mgxs data loading interface methods //============================================================================== namespace data { MgxsInterface mg; } MgxsInterface::MgxsInterface(const std::string& path_cross_sections, const std::vector xs_to_read, const std::vector> xs_temps) { read_header(path_cross_sections); set_nuclides_and_temperatures(xs_to_read, xs_temps); init(); } void MgxsInterface::set_nuclides_and_temperatures( std::vector xs_to_read, std::vector> xs_temps) { // Check to remove all duplicates xs_to_read_ = xs_to_read; xs_temps_to_read_ = xs_temps; if (xs_to_read_.size() != xs_temps.size()) fatal_error("The list of macro XS temperatures to read does not " "correspond in length to the number of XS names. "); } void MgxsInterface::init() { // Check that at least some data was set to be read if (xs_to_read_.size() == 0) warning("No MGXS nuclides were set to be read."); // Check if MGXS Library exists if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file fatal_error("Cross sections HDF5 file '" + cross_sections_path_ + "' does not exist."); } write_message("Loading cross section data...", 5); // Open file for reading hid_t file_id = file_open(cross_sections_path_, 'r'); // Read filetype std::string type; read_attribute(file_id, "filetype", type); if (type != "mgxs") { fatal_error("Provided MGXS Library is not a MGXS Library file."); } // Read revision number for the MGXS Library file and make sure it matches // with the current version std::array array; read_attribute(file_id, "version", array); if (array != VERSION_MGXS_LIBRARY) { fatal_error("MGXS Library file version does not match current version " "supported by OpenMC."); } // ========================================================================== // READ ALL MGXS CROSS SECTION TABLES for (unsigned i_nuc=0; i_nuc& temperature) { write_message("Loading " + std::string(name) + " data...", 6); // Check to make sure cross section set exists in the library hid_t xs_grp; if (object_exists(file_id, name.c_str())) { xs_grp = open_group(file_id, name.c_str()); } else { fatal_error("Data for " + std::string(name) + " does not exist in " + "provided MGXS Library"); } nuclides_.emplace_back(xs_grp, temperature, num_energy_groups_, num_delayed_groups_); close_group(xs_grp); } //============================================================================== void MgxsInterface::create_macro_xs() { // Get temperatures to read for each material auto kTs = get_mat_kTs(); // Force all nuclides in a material to be the same representation. // Therefore type(nuclides[mat->nuclide_[0]]) dictates type(macroxs). // At the same time, we will find the scattering type, as that will dictate // how we allocate the scatter object within macroxs. for (int i = 0; i < model::materials.size(); ++i) { if (kTs[i].size() > 0) { // Convert atom_densities to a vector auto& mat {model::materials[i]}; std::vector atom_densities(mat->atom_density_.begin(), mat->atom_density_.end()); // Build array of pointers to nuclides's Mgxs objects needed for this // material std::vector mgxs_ptr; for (int i_nuclide : mat->nuclide_) { mgxs_ptr.push_back(&nuclides_[i_nuclide]); } macro_xs_.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities, num_energy_groups_, num_delayed_groups_); } else { // Preserve the ordering of materials by including a blank entry macro_xs_.emplace_back(); } } } //============================================================================== std::vector> MgxsInterface::get_mat_kTs() { std::vector> kTs(model::materials.size()); for (const auto& cell : model::cells) { // Skip non-material cells if (cell->fill_ != C_NONE) continue; for (int j = 0; j < cell->material_.size(); ++j) { // Skip void materials int i_material = cell->material_[j]; if (i_material == MATERIAL_VOID) continue; // Get temperature of cell (rounding to nearest integer) double sqrtkT = cell->sqrtkT_.size() == 1 ? cell->sqrtkT_[j] : cell->sqrtkT_[0]; double kT = sqrtkT * sqrtkT; // Add temperature if it hasn't already been added if (!contains(kTs[i_material], kT)) { kTs[i_material].push_back(kT); } } } return kTs; } //============================================================================== void MgxsInterface::read_header(const std::string& path_cross_sections) { // Save name of HDF5 file to be read to struct data cross_sections_path_ = path_cross_sections; // Check if MGXS Library exists if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file fatal_error("Cross sections HDF5 file '" + cross_sections_path_ + "' does not exist."); } write_message("Reading cross sections HDF5 file...", 5); // Open file for reading hid_t file_id = file_open(cross_sections_path_, 'r', true); ensure_exists(file_id, "energy_groups", true); read_attribute(file_id, "energy_groups", num_energy_groups_); if (attribute_exists(file_id, "delayed_groups")) { read_attribute(file_id, "delayed_groups", num_delayed_groups_); } else { num_delayed_groups_ = 0; } ensure_exists(file_id, "group structure", true); read_attribute(file_id, "group structure", rev_energy_bins_); // Reverse energy bins std::copy(rev_energy_bins_.crbegin(), rev_energy_bins_.crend(), std::back_inserter(energy_bins_)); // Create average energies for (int i = 0; i < energy_bins_.size() - 1; ++i) { energy_bin_avg_.push_back(0.5* (energy_bins_[i] + energy_bins_[i+1])); } // Add entries into libraries for MG data xs_names_ = group_names(file_id); if (xs_names_.empty()) { fatal_error("At least one MGXS data set must be present in mgxs " "library file!"); } // Close MGXS HDF5 file file_close(file_id); } void put_mgxs_header_data_to_globals() { // Get the minimum and maximum energies int neutron = static_cast(Particle::Type::neutron); data::energy_min[neutron] = data::mg.energy_bins_.back(); data::energy_max[neutron] = data::mg.energy_bins_.front(); // Save available XS names to library list, so that when // materials are read, the specified mgxs can be confirmed // as present for (auto& name : data::mg.xs_names_) { Library lib {}; lib.type_ = Library::Type::neutron; lib.materials_.push_back(name); data::libraries.push_back(lib); } } void set_mg_interface_nuclides_and_temps() { // Get temperatures from global data std::vector> nuc_temps(data::nuclide_map.size()); std::vector> dummy; get_temperatures(nuc_temps, dummy); // Build vector of nuclide names which are to be read std::vector nuclide_names(data::nuclide_map.size()); for (const auto& kv : data::nuclide_map) { nuclide_names[kv.second] = kv.first; } std::unordered_set already_read; // Loop over materials to find xs and temperature to be read for (const auto& mat : model::materials) { for (int i_nuc : mat->nuclide_) { std::string& name = nuclide_names[i_nuc]; if (already_read.find(name) == already_read.end()) { data::mg.xs_to_read_.push_back(name); data::mg.xs_temps_to_read_.push_back(nuc_temps[i_nuc]); already_read.insert(name); } } } } void mark_fissionable_mgxs_materials() { // Loop over all files for (const auto& mat : model::materials) { for (int i_nuc : mat->nuclide_) { if (data::mg.nuclides_[i_nuc].fissionable) { mat->fissionable_ = true; } } } } } // namespace openmc