diff --git a/CMakeLists.txt b/CMakeLists.txt index f85d111a4..3e3a9250e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,7 +340,6 @@ add_library(libopenmc SHARED src/state_point.F90 src/stl_vector.F90 src/string.F90 - src/summary.F90 src/surface_header.F90 src/timer_header.F90 src/tracking.F90 diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index d4b6f48e5..6881cac77 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -358,6 +358,12 @@ write_attribute(hid_t obj_id, const char* name, const char* buffer) write_attr_string(obj_id, name, buffer); } +inline void +write_attribute(hid_t obj_id, const char* name, const std::string& buffer) +{ + write_attr_string(obj_id, name, buffer.c_str()); +} + template inline void write_attribute(hid_t obj_id, const char* name, const std::array& buffer) { @@ -398,6 +404,29 @@ write_dataset(hid_t obj_id, const char* name, const std::array& buffer) write_dataset(obj_id, 1, dims, name, H5TypeMap::type_id, buffer.data(), false); } +inline void +write_dataset(hid_t obj_id, const char* name, const std::vector& buffer) +{ + auto n {buffer.size()}; + hsize_t dims[] {n}; + + // Determine length of longest string, including \0 + size_t m = 1; + for (const auto& s : buffer) { + m = std::max(m, s.size() + 1); + } + + // Copy data into contiguous buffer + char temp[n][m]; + std::fill(temp[0], temp[0] + n*m, '\0'); + for (int i = 0; i < n; ++i) { + std::copy(buffer[i].begin(), buffer[i].end(), temp[i]); + } + + // Write 2D data + write_string(obj_id, 1, dims, m, name, temp[0], false); +} + template inline void write_dataset(hid_t obj_id, const char* name, const std::vector& buffer) { diff --git a/include/openmc/material.h b/include/openmc/material.h index eda102d22..ee645c287 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -6,6 +6,7 @@ #include #include +#include #include "pugixml.hpp" #include "xtensor/xtensor.hpp" @@ -58,6 +59,9 @@ public: //! Set total density of the material int set_density(double density, std::string units); + //! Write material data to HDF5 + void to_hdf5(hid_t group) const; + // Data int32_t id_; //!< Unique ID std::string name_; //!< Name of material diff --git a/include/openmc/summary.h b/include/openmc/summary.h new file mode 100644 index 000000000..819fdf95c --- /dev/null +++ b/include/openmc/summary.h @@ -0,0 +1,17 @@ +#ifndef OPENMC_SUMMARY_H +#define OPENMC_SUMMARY_H + +#include + +namespace openmc { + +void write_summary(); +void write_header(hid_t file); +void write_nuclides(hid_t file); +void write_geometry(hid_t file); +void write_materials(hid_t file); + + +} + +#endif // OPENMC_SUMMARY_H diff --git a/src/initialize.cpp b/src/initialize.cpp index 36abfa718..aaa318946 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -25,6 +25,7 @@ #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/string_utils.h" +#include "openmc/summary.h" #include "openmc/thermal.h" #include "openmc/timer.h" @@ -37,7 +38,6 @@ extern "C" void read_geometry_xml(); extern "C" void read_materials_xml(); extern "C" void read_plots_xml(); extern "C" void read_tallies_xml(); -extern "C" void write_summary(); // Paths to various files extern "C" { diff --git a/src/input_xml.F90 b/src/input_xml.F90 index b716c0692..9b8e2f08e 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -28,7 +28,6 @@ module input_xml use string, only: to_lower, to_str, str_to_int, str_to_real, & starts_with, ends_with, split_string, & zero_padded, to_c_string - use summary, only: write_summary use tally use tally_header, only: openmc_extend_tallies use tally_derivative_header diff --git a/src/material.cpp b/src/material.cpp index 3b3570b2f..a732d9191 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -14,6 +14,7 @@ #include "openmc/cross_sections.h" #include "openmc/container_util.h" #include "openmc/error.h" +#include "openmc/hdf5_interface.h" #include "openmc/math_functions.h" #include "openmc/message_passing.h" #include "openmc/mgxs_interface.h" @@ -804,6 +805,61 @@ int Material::set_density(double density, std::string units) return 0; } +void Material::to_hdf5(hid_t group) const +{ + hid_t material_group = create_group(group, "material " + std::to_string(id_)); + + write_attribute(material_group, "depletable", static_cast(depletable_)); + if (volume_ > 0.0) { + write_attribute(material_group, "volume", volume_); + } + write_dataset(material_group, "name", name_); + write_dataset(material_group, "atom_density", density_); + + // Copy nuclide/macro name for each nuclide to vector + std::vector nuc_names; + std::vector macro_names; + std::vector nuc_densities; + if (settings::run_CE) { + for (int i = 0; i < nuclide_.size(); ++i) { + int i_nuc = nuclide_[i]; + nuc_names.push_back(data::nuclides[i_nuc]->name_); + nuc_densities.push_back(atom_density_(i)); + } + } else { + for (int i = 0; i < nuclide_.size(); ++i) { + int i_nuc = nuclide_[i_nuc]; + if (data::nuclides_MG[i_nuc].awr != MACROSCOPIC_AWR) { + nuc_names.push_back(data::nuclides_MG[i_nuc].name); + nuc_densities.push_back(atom_density_(i)); + } else { + macro_names.push_back(data::nuclides_MG[i_nuc].name); + } + } + } + + // Write vector to 'nuclides' + if (!nuc_names.empty()) { + write_dataset(material_group, "nuclides", nuc_names); + write_dataset(material_group, "nuclide_densities", nuc_densities); + } + + // Write vector to 'macroscopics' + if (!macro_names.empty()) { + write_dataset(material_group, "macroscopics", macro_names); + } + + if (!thermal_tables_.empty()) { + std::vector sab_names; + for (const auto& table : thermal_tables_) { + sab_names.push_back(data::thermal_scatt[table.index_table]->name_); + } + write_dataset(material_group, "sab_names", sab_names); + } + + close_group(material_group); +} + //============================================================================== // Non-method functions //============================================================================== diff --git a/src/summary.F90 b/src/summary.F90 deleted file mode 100644 index 0bcdd11d8..000000000 --- a/src/summary.F90 +++ /dev/null @@ -1,288 +0,0 @@ -module summary - - use constants - use endf, only: reaction_name - use error, only: write_message - use geometry_header - use hdf5_interface - use material_header, only: Material, n_materials, openmc_material_get_volume - use message_passing - use mgxs_interface - use nuclide_header - use output, only: time_stamp - use settings, only: run_CE - use surface_header - use string, only: to_str - use tally_header, only: TallyObject - - implicit none - private - - public :: write_summary - -contains - -!=============================================================================== -! WRITE_SUMMARY -!=============================================================================== - - subroutine write_summary() bind(C) - - interface - subroutine write_geometry(file_id) bind(C) - import HID_T - integer(HID_T), intent(in), value :: file_id - end subroutine write_geometry - end interface - - integer(HID_T) :: file_id - - ! Display output message - call write_message("Writing summary.h5 file...", 5) - - ! Create a new file using default properties. - file_id = file_open("summary.h5", 'w') - - call write_header(file_id) - call write_nuclides(file_id) - call write_geometry(file_id) - call write_materials(file_id) - - ! Terminate access to the file. - call file_close(file_id) - - end subroutine write_summary - -!=============================================================================== -! WRITE_HEADER -!=============================================================================== - - subroutine write_header(file_id) - integer(HID_T), intent(in) :: file_id - - ! Write filetype and version info - call write_attribute(file_id, "filetype", "summary") - call write_attribute(file_id, "version", VERSION_SUMMARY) - call write_attribute(file_id, "openmc_version", VERSION) -#ifdef GIT_SHA1 - call write_attribute(file_id, "git_sha1", GIT_SHA1) -#endif - - ! Write current date and time - call write_attribute(file_id, "date_and_time", time_stamp()) - - end subroutine write_header - -!=============================================================================== -! WRITE_NUCLIDES -!=============================================================================== - - subroutine write_nuclides(file_id) - integer(HID_T), intent(in) :: file_id - integer(HID_T) :: nuclide_group - integer(HID_T) :: macro_group - integer :: i - character(kind=C_CHAR, len=20), allocatable :: nuc_names(:) - character(kind=C_CHAR, len=20), allocatable :: macro_names(:) - real(C_DOUBLE), allocatable :: awrs(:) - integer :: num_nuclides - integer :: num_macros - integer :: j - integer :: k - - ! Find how many of these nuclides are macroscopic objects - if (run_CE) then - ! Then none are macroscopic - num_nuclides = n_nuclides - num_macros = 0 - else - num_nuclides = 0 - num_macros = 0 - do i = 1, n_nuclides - if (get_awr_c(i) /= MACROSCOPIC_AWR) then - num_nuclides = num_nuclides + 1 - else - num_macros = num_macros + 1 - end if - end do - end if - - ! Build array of nuclide names and awrs while only sorting nuclides from - ! macroscopics - if (num_nuclides > 0) then - allocate(nuc_names(num_nuclides)) - allocate(awrs(num_nuclides)) - end if - if (num_macros > 0) then - allocate(macro_names(num_macros)) - end if - - j = 1 - k = 1 - do i = 1, n_nuclides - if (run_CE) then - nuc_names(i) = nuclides(i) % name - awrs(i) = nuclides(i) % awr - else - if (get_awr_c(i) /= MACROSCOPIC_AWR) then - call get_name_c(i, len(nuc_names(j)), nuc_names(j)) - nuc_names(j) = trim(nuc_names(j)) - awrs(j) = get_awr_c(i) - j = j + 1 - else - call get_name_c(i, len(macro_names(k)), macro_names(k)) - macro_names(k) = trim(macro_names(k)) - k = k + 1 - end if - end if - end do - - nuclide_group = create_group(file_id, "nuclides") - call write_attribute(nuclide_group, "n_nuclides", num_nuclides) - macro_group = create_group(file_id, "macroscopics") - call write_attribute(macro_group, "n_macroscopics", num_macros) - ! Write nuclide names and awrs - if (num_nuclides > 0) then - ! Write useful data from nuclide objects - call write_dataset(nuclide_group, "names", nuc_names) - call write_dataset(nuclide_group, "awrs", awrs) - end if - if (num_macros > 0) then - ! Write useful data from macroscopic objects - call write_dataset(macro_group, "names", macro_names) - end if - call close_group(nuclide_group) - call close_group(macro_group) - - - if (allocated(nuc_names)) deallocate(nuc_names, awrs) - if (allocated(macro_names)) deallocate(macro_names) - - end subroutine write_nuclides - -!=============================================================================== -! WRITE_MATERIALS -!=============================================================================== - - subroutine write_materials(file_id) - integer(HID_T), intent(in) :: file_id - - integer :: i - integer :: j - integer :: k - integer :: n - integer :: err - character(kind=C_CHAR, len=20), allocatable :: nuc_names(:) - character(kind=C_CHAR, len=20), allocatable :: macro_names(:) - real(8) :: volume - real(8), allocatable :: nuc_densities(:) - integer :: num_nuclides - integer :: num_macros - integer(HID_T) :: materials_group - integer(HID_T) :: material_group - type(Material), pointer :: m - - materials_group = create_group(file_id, "materials") - - ! write number of materials - call write_dataset(file_id, "n_materials", n_materials) - - ! Write information on each material - do i = 1, n_materials - m => materials(i) - material_group = create_group(materials_group, "material " // & - trim(to_str(m%id()))) - - if (m % depletable) then - call write_attribute(material_group, "depletable", 1) - else - call write_attribute(material_group, "depletable", 0) - end if - - err = openmc_material_get_volume(i, volume) - if (err == 0 .and. volume > ZERO) then - call write_attribute(material_group, "volume", volume) - end if - - ! Write name for this material - call write_dataset(material_group, "name", m % name) - - ! Write atom density with units - call write_dataset(material_group, "atom_density", m % density) - - if (run_CE) then - num_nuclides = m % n_nuclides - num_macros = 0 - else - ! Find the number of macroscopic and nuclide data in this material - num_nuclides = 0 - num_macros = 0 - do j = 1, m % n_nuclides - if (get_awr_c(m % nuclide(j)) /= MACROSCOPIC_AWR) then - num_nuclides = num_nuclides + 1 - else - num_macros = num_macros + 1 - end if - end do - end if - - ! Copy ZAID or macro name for each nuclide to temporary array - if (num_nuclides > 0) then - allocate(nuc_names(num_nuclides)) - allocate(nuc_densities(num_nuclides)) - end if - if (run_CE) then - do j = 1, m % n_nuclides - nuc_names(j) = nuclides(m%nuclide(j))%name - nuc_densities(j) = m % atom_density(j) - end do - else - if (num_macros > 0) then - allocate(macro_names(num_macros)) - end if - - k = 1 - n = 1 - do j = 1, m % n_nuclides - if (get_awr_c(m % nuclide(j)) /= MACROSCOPIC_AWR) then - call get_name_c(m % nuclide(j), len(nuc_names(k)), nuc_names(k)) - nuc_names(k) = trim(nuc_names(k)) - nuc_densities(k) = m % atom_density(j) - k = k + 1 - else - call get_name_c(m % nuclide(j), len(macro_names(n)), macro_names(n)) - macro_names(n) = trim(macro_names(n)) - n = n + 1 - end if - end do - end if - - ! Write temporary array to 'nuclides' - if (num_nuclides > 0) then - call write_dataset(material_group, "nuclides", nuc_names) - ! Deallocate temporary array - deallocate(nuc_names) - ! Write nuclide atom densities - call write_dataset(material_group, "nuclide_densities", nuc_densities) - deallocate(nuc_densities) - end if - - ! Write temporary array to 'macroscopics' - if (num_macros > 0) then - call write_dataset(material_group, "macroscopics", macro_names) - ! Deallocate temporary array - deallocate(macro_names) - end if - - if (m%n_sab > 0) then - call write_dataset(material_group, "sab_names", m%sab_names) - end if - - call close_group(material_group) - end do - - call close_group(materials_group) - - end subroutine write_materials - -end module summary diff --git a/src/summary.cpp b/src/summary.cpp index 398f304fb..1eeab5d04 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -1,15 +1,93 @@ +#include "openmc/summary.h" + #include "openmc/cell.h" #include "openmc/hdf5_interface.h" #include "openmc/lattice.h" +#include "openmc/material.h" +#include "openmc/mgxs_interface.h" +#include "openmc/nuclide.h" +#include "openmc/output.h" #include "openmc/surface.h" #include "openmc/settings.h" namespace openmc { -extern "C" void -write_geometry(hid_t file_id) { +void write_summary() +{ + // Display output message + write_message("Writing summary.h5 file...", 5); - auto geom_group = create_group(file_id, "geometry"); + // Create a new file using default properties. + hid_t file = file_open("summary.h5", 'w'); + + write_header(file); + write_nuclides(file); + write_geometry(file); + write_materials(file); + + // Terminate access to the file. + file_close(file); +} + +void write_header(hid_t file) +{ + // Write filetype and version info + write_attribute(file, "filetype", "summary"); + write_attribute(file, "version", VERSION_SUMMARY); + write_attribute(file, "openmc_version", VERSION); +#ifdef GIT_SHA1 + write_attribute(file, "git_sha1", GIT_SHA1); +#endif + + // Write current date and time + write_attribute(file, "date_and_time", time_stamp()); +} + +void write_nuclides(hid_t file) +{ + // Build vectors of nuclide names and awrs while only sorting nuclides from + // macroscopics + std::vector nuc_names; + std::vector macro_names; + std::vector awrs; + + for (int i = 0; i < data::nuclides.size(); ++i) { + if (settings::run_CE) { + const auto& nuc {data::nuclides[i]}; + nuc_names.push_back(nuc->name_); + awrs.push_back(nuc->awr_); + } else { + const auto& nuc {data::nuclides_MG[i]}; + if (nuc.awr != MACROSCOPIC_AWR) { + nuc_names.push_back(nuc.name); + awrs.push_back(nuc.awr); + } else { + macro_names.push_back(nuc.name); + } + } + } + + hid_t nuclide_group = create_group(file, "nuclides"); + write_attribute(nuclide_group, "n_nuclides", nuc_names.size()); + hid_t macro_group = create_group(file, "macroscopics"); + write_attribute(macro_group, "n_macroscopics", macro_names.size()); + // Write nuclide names and awrs + if (!nuc_names.empty()) { + // Write useful data from nuclide objects + write_dataset(nuclide_group, "names", nuc_names); + write_dataset(nuclide_group, "awrs", awrs); + } + if (!macro_names.empty()) { + // Write useful data from macroscopic objects + write_dataset(macro_group, "names", macro_names); + } + close_group(nuclide_group); + close_group(macro_group); +} + +void write_geometry(hid_t file) +{ + auto geom_group = create_group(file, "geometry"); #ifdef DAGMC if (settings::dagmc) { @@ -42,4 +120,16 @@ write_geometry(hid_t file_id) { close_group(geom_group); } +void write_materials(hid_t file) +{ + // write number of materials + write_dataset(file, "n_materials", model::materials.size()); + + hid_t materials_group = create_group(file, "materials"); + for (const auto& mat : model::materials) { + mat->to_hdf5(materials_group); + } + close_group(materials_group); +} + } // namespace openmc