From 4e92988433229aab4324510d78f9ce28ed954546 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Fri, 31 Aug 2018 18:18:01 -0400 Subject: [PATCH 01/12] Saving state --- include/openmc/constants.h | 5 - include/openmc/hdf5_interface.h | 27 +- include/openmc/mgxs.h | 26 +- include/openmc/scattdata.h | 52 +-- include/openmc/xsdata.h | 24 +- src/hdf5_interface.cpp | 192 ++++++++-- src/mgxs.cpp | 172 ++++----- src/scattdata.cpp | 137 +++---- src/xsdata.cpp | 359 ++++++++---------- .../mgxs_library_ce_to_mg/test.py | 9 +- 10 files changed, 536 insertions(+), 467 deletions(-) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 12dc21b71..0b66f355c 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -16,11 +16,6 @@ typedef std::vector double_1dvec; typedef std::vector > double_2dvec; typedef std::vector > > double_3dvec; typedef std::vector > > > double_4dvec; -typedef std::vector > > > > double_5dvec; -typedef std::vector > > > > > double_6dvec; -typedef std::vector int_1dvec; -typedef std::vector > int_2dvec; -typedef std::vector > > int_3dvec; // ============================================================================ // VERSIONING NUMBERS diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 48ce41d0e..74f5ae581 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -46,37 +46,36 @@ hid_t file_open(const std::string& filename, char mode, bool parallel=false); void write_string(hid_t group_id, const char* name, const std::string& buffer, bool indep); +void +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have = false); + void read_nd_vector(hid_t obj_id, const char* name, std::vector& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have = false); + +void +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); std::vector attribute_shape(hid_t obj_id, const char* name); diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 40746c291..e80355bee 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -7,6 +7,8 @@ #include #include +#include "xtensor/xtensor.hpp" + #include "openmc/constants.h" #include "openmc/hdf5_interface.h" #include "openmc/xsdata.h" @@ -35,7 +37,7 @@ struct CacheData { class Mgxs { private: - double_1dvec kTs; // temperature in eV (k * T) + xt::xtensor kTs; // temperature in eV (k * T) int scatter_format; // flag for if this is legendre, histogram, or tabular int num_delayed_groups; // number of delayed neutron groups int num_groups; // number of energy groups @@ -44,8 +46,8 @@ class Mgxs { bool is_isotropic; // used to skip search for angle indices if isotropic int n_pol; int n_azi; - double_1dvec polar; - double_1dvec azimuthal; + std::vector polar; + std::vector azimuthal; //! \brief Initializes the Mgxs object metadata //! @@ -62,10 +64,10 @@ class Mgxs { //! @param in_polar Polar angle grid. //! @param in_azimuthal Azimuthal angle grid. void - init(const std::string& in_name, double in_awr, const double_1dvec& in_kTs, + init(const std::string& in_name, double in_awr, const std::vector& in_kTs, bool in_fissionable, int in_scatter_format, int in_num_groups, int in_num_delayed_groups, bool in_is_isotropic, - const double_1dvec& in_polar, const double_1dvec& in_azimuthal); + const std::vector& in_polar, const std::vector& in_azimuthal); //! \brief Initializes the Mgxs object metadata from the HDF5 file //! @@ -80,8 +82,8 @@ class Mgxs { //! @param method Method of choosing nearest temperatures. void metadata_from_hdf5(hid_t xs_id, int in_num_groups, - int in_num_delayed_groups, const double_1dvec& temperature, - double tolerance, int_1dvec& temps_to_read, int& order_dim, + int in_num_delayed_groups, const std::vector& temperature, + double tolerance, std::vector& temps_to_read, int& order_dim, int& method); //! \brief Performs the actual act of combining the microscopic data for a @@ -93,8 +95,8 @@ class Mgxs { //! corresponds to the temperature of interest. //! @param this_t The temperature index of the macroscopic object. void - combine(const std::vector& micros, const double_1dvec& scalars, - const int_1dvec& micro_ts, int this_t); + combine(const std::vector& micros, const std::vector& scalars, + const std::vector& micro_ts, int this_t); //! \brief Checks to see if this and that are able to be combined //! @@ -128,7 +130,7 @@ class Mgxs { //! provides the number of points to use in the tabular representation. //! @param method Method of choosing nearest temperatures. Mgxs(hid_t xs_id, int energy_groups, - int delayed_groups, const double_1dvec& temperature, double tolerance, + int delayed_groups, const std::vector& temperature, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points, int& method); @@ -141,8 +143,8 @@ class Mgxs { //! @param atom_densities Atom densities of those microscopic quantities. //! @param tolerance Tolerance of temperature selection method. //! @param method Method of choosing nearest temperatures. - Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, - const std::vector& micros, const double_1dvec& atom_densities, + Mgxs(const std::string& in_name, const std::vector& mat_kTs, + const std::vector& micros, const std::vector& atom_densities, double tolerance, int& method); //! \brief Provides a cross section value given certain parameters diff --git a/include/openmc/scattdata.h b/include/openmc/scattdata.h index 980238aeb..7e73224b9 100644 --- a/include/openmc/scattdata.h +++ b/include/openmc/scattdata.h @@ -6,6 +6,8 @@ #include +#include "xtensor/xtensor.hpp" + #include "openmc/constants.h" namespace openmc { @@ -25,23 +27,25 @@ class ScattData { protected: //! \brief Initializes the attributes of the base class. void - base_init(int order, const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_energy, const double_2dvec& in_mult); + base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, + const double_2dvec& in_mult); //! \brief Combines microscopic ScattDatas into a macroscopic one. void base_combine(int max_order, const std::vector& those_scatts, - const double_1dvec& scalars, int_1dvec& in_gmin, int_1dvec& in_gmax, - double_2dvec& sparse_mult, double_3dvec& sparse_scatter); + const double_1dvec& scalars, xt::xtensor& in_gmin, + xt::xtensor& in_gmax, double_2dvec& sparse_mult, + double_3dvec& sparse_scatter); public: - double_2dvec energy; // Normalized p0 matrix for sampling Eout - double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) - double_3dvec dist; // Angular distribution - int_1dvec gmin; // minimum outgoing group - int_1dvec gmax; // maximum outgoing group - double_1dvec scattxs; // Isotropic Sigma_{s,g_{in}} + double_2dvec energy; // Normalized p0 matrix for sampling Eout + double_2dvec mult; // nu-scatter multiplication (nu-scatt/scatt) + double_3dvec dist; // Angular distribution + xt::xtensor gmin; // minimum outgoing group + xt::xtensor gmax; // maximum outgoing group + xt::xtensor scattxs; // Isotropic Sigma_{s,g_{in}} //! \brief Calculates the value of normalized f(mu). //! @@ -72,7 +76,7 @@ class ScattData { //! @param in_mult Input sparse multiplicity matrix //! @param coeffs Input sparse scattering matrix virtual void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) = 0; //! \brief Combines the microscopic data. @@ -97,7 +101,7 @@ class ScattData { //! @param max_order If Legendre this is the maximum value of "n" in "Pn" //! requested; ignored otherwise. //! @return The dense scattering matrix. - virtual double_3dvec + virtual xt::xtensor get_matrix(int max_order) = 0; //! \brief Samples the outgoing energy from the ScattData info. @@ -142,7 +146,7 @@ class ScattDataLegendre: public ScattData { public: void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs); void @@ -163,7 +167,7 @@ class ScattDataLegendre: public ScattData { int get_order() {return dist[0][0].size() - 1;}; - double_3dvec + xt::xtensor get_matrix(int max_order); }; @@ -176,14 +180,14 @@ class ScattDataHistogram: public ScattData { protected: - double_1dvec mu; // Angle distribution mu bin boundaries - double dmu; // Quick storage of the spacing between the mu bin points - double_3dvec fmu; // The angular distribution histogram + xt::xtensor mu; // Angle distribution mu bin boundaries + double dmu; // Quick storage of the mu spacing + double_3dvec fmu; // The angular distribution histogram public: void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs); void @@ -199,7 +203,7 @@ class ScattDataHistogram: public ScattData { int get_order() {return dist[0][0].size();}; - double_3dvec + xt::xtensor get_matrix(int max_order); }; @@ -212,9 +216,9 @@ class ScattDataTabular: public ScattData { protected: - double_1dvec mu; // Angle distribution mu grid points - double dmu; // Quick storage of the spacing between the mu points - double_3dvec fmu; // The angular distribution function + xt::xtensor mu; // Angle distribution mu grid points + double dmu; // Quick storage of the mu spacing + double_3dvec fmu; // The angular distribution function // Friend convert_legendre_to_tabular so it has access to protected // parameters @@ -225,7 +229,7 @@ class ScattDataTabular: public ScattData { public: void - init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, + init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs); void @@ -241,7 +245,7 @@ class ScattDataTabular: public ScattData { int get_order() {return dist[0][0].size();}; - double_3dvec get_matrix(int max_order); + xt::xtensor get_matrix(int max_order); }; //============================================================================== diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 156708c78..9a602c8b7 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -7,6 +7,8 @@ #include #include +#include "xtensor/xtensor.hpp" + #include "openmc/hdf5_interface.h" #include "openmc/scattdata.h" @@ -35,26 +37,26 @@ class XsData { // The following quantities have the following dimensions: // [angle][incoming group] - double_2dvec total; - double_2dvec absorption; - double_2dvec nu_fission; - double_2dvec prompt_nu_fission; - double_2dvec kappa_fission; - double_2dvec fission; - double_2dvec inverse_velocity; + xt::xtensor total; + xt::xtensor absorption; + xt::xtensor nu_fission; + xt::xtensor prompt_nu_fission; + xt::xtensor kappa_fission; + xt::xtensor fission; + xt::xtensor inverse_velocity; // decay_rate has the following dimensions: // [angle][delayed group] - double_2dvec decay_rate; + xt::xtensor decay_rate; // delayed_nu_fission has the following dimensions: // [angle][incoming group][delayed group] - double_3dvec delayed_nu_fission; + xt::xtensor delayed_nu_fission; // chi_prompt has the following dimensions: // [angle][incoming group][outgoing group] - double_3dvec chi_prompt; + xt::xtensor chi_prompt; // chi_delayed has the following dimensions: // [angle][incoming group][outgoing group][delayed group] - double_4dvec chi_delayed; + xt::xtensor chi_delayed; // scatter has the following dimensions: [angle] std::vector > scatter; diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 5056e5f78..db987cc02 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -5,6 +5,9 @@ #include #include +#include "xtensor/xtensor.hpp" +#include "xtensor/xarray.hpp" + #include "hdf5.h" #include "hdf5_hl.h" #ifdef OPENMC_MPI @@ -474,6 +477,106 @@ read_dataset(hid_t obj_id, const char* name, hid_t mem_type_id, if (name) H5Dclose(dset); } +// //***************************************************************************** + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// read_double(obj_id, name, result.data(), true); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_double(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_int(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +// void +// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +// bool must_have) +// { +// if (object_exists(obj_id, name)) { +// xt::xarray temp; +// read_int(obj_id, name, temp.data(), true); + +// result = xt::adapt(temp, result.shape()); +// } else if (must_have) { +// fatal_error(std::string("Must provide " + std::string(name) + "!")); +// } +// } + +//***************************************************************************** void read_double(hid_t obj_id, const char* name, double* buffer, bool indep) @@ -545,19 +648,38 @@ read_nd_vector(hid_t obj_id, const char* name, std::vector& result, void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, bool must_have) +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); + int dim1 = result.shape()[0]; + double temp_arr[dim1]; + read_double(obj_id, name, temp_arr, true); + + int temp_idx = 0; + for (int i = 0; i < dim1; i++) { + result(i) = temp_arr[temp_idx++]; + } + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + + +void +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have) +{ + if (object_exists(obj_id, name)) { + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; double temp_arr[dim1 * dim2]; read_double(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { - result[i][j] = temp_arr[temp_idx++]; + result(i, j) = temp_arr[temp_idx++]; } } } else if (must_have) { @@ -567,19 +689,19 @@ read_nd_vector(hid_t obj_id, const char* name, void -read_nd_vector(hid_t obj_id, const char* name, - std::vector >& result, bool must_have) +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; int temp_arr[dim1 * dim2]; read_int(obj_id, name, temp_arr, true); int temp_idx = 0; for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { - result[i][j] = temp_arr[temp_idx++]; + result(i, j) = temp_arr[temp_idx++]; } } } else if (must_have) { @@ -589,14 +711,13 @@ read_nd_vector(hid_t obj_id, const char* name, void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; double temp_arr[dim1 * dim2 * dim3]; read_double(obj_id, name, temp_arr, true); @@ -604,7 +725,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { for (int k = 0; k < dim3; k++) { - result[i][j][k] = temp_arr[temp_idx++]; + result(i, j, k) = temp_arr[temp_idx++]; } } } @@ -614,14 +735,13 @@ read_nd_vector(hid_t obj_id, const char* name, } void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; int temp_arr[dim1 * dim2 * dim3]; read_int(obj_id, name, temp_arr, true); @@ -629,7 +749,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int i = 0; i < dim1; i++) { for (int j = 0; j < dim2; j++) { for (int k = 0; k < dim3; k++) { - result[i][j][k] = temp_arr[temp_idx++]; + result(i, j, k) = temp_arr[temp_idx++]; } } } @@ -639,15 +759,14 @@ read_nd_vector(hid_t obj_id, const char* name, } void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); - int dim4 = result[0][0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; + int dim4 = result.shape()[3]; double temp_arr[dim1 * dim2 * dim3 * dim4]; read_double(obj_id, name, temp_arr, true); @@ -656,7 +775,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int j = 0; j < dim2; j++) { for (int k = 0; k < dim3; k++) { for (int l = 0; l < dim4; l++) { - result[i][j][k][l] = temp_arr[temp_idx++]; + result(i, j, k, l) = temp_arr[temp_idx++]; } } } @@ -667,16 +786,15 @@ read_nd_vector(hid_t obj_id, const char* name, } void -read_nd_vector(hid_t obj_id, const char* name, - std::vector > > > >& result, +read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) { if (object_exists(obj_id, name)) { - int dim1 = result.size(); - int dim2 = result[0].size(); - int dim3 = result[0][0].size(); - int dim4 = result[0][0][0].size(); - int dim5 = result[0][0][0][0].size(); + int dim1 = result.shape()[0]; + int dim2 = result.shape()[1]; + int dim3 = result.shape()[2]; + int dim4 = result.shape()[3]; + int dim5 = result.shape()[4]; double temp_arr[dim1 * dim2 * dim3 * dim4 * dim5]; read_double(obj_id, name, temp_arr, true); @@ -686,7 +804,7 @@ read_nd_vector(hid_t obj_id, const char* name, for (int k = 0; k < dim3; k++) { for (int l = 0; l < dim4; l++) { for (int m = 0; m < dim5; m++) { - result[i][j][k][l][m] = temp_arr[temp_idx++]; + result(i, j, k, l, m) = temp_arr[temp_idx++]; } } } diff --git a/src/mgxs.cpp b/src/mgxs.cpp index eb13a55f6..ed68a12e9 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -3,12 +3,17 @@ #include #include #include -#include +#include #ifdef _OPENMP #include #endif +#include "xtensor/xmath.hpp" +#include "xtensor/xsort.hpp" +#include "xtensor/xadapt.hpp" +#include "xtensor/xview.hpp" + #include "openmc/error.h" #include "openmc/math_functions.h" #include "openmc/random_lcg.h" @@ -28,14 +33,15 @@ std::vector macro_xs; void Mgxs::init(const std::string& in_name, double in_awr, - const double_1dvec& in_kTs, bool in_fissionable, int in_scatter_format, + const std::vector& in_kTs, bool in_fissionable, int in_scatter_format, int in_num_groups, int in_num_delayed_groups, bool in_is_isotropic, - const double_1dvec& in_polar, const double_1dvec& in_azimuthal) + const std::vector& in_polar, const std::vector& in_azimuthal) { // Set the metadata name = in_name; awr = in_awr; - kTs = in_kTs; + //TODO: Remove adapt when in_KTs is an xtensor + kTs = xt::adapt(in_kTs); fissionable = in_fissionable; scatter_format = in_scatter_format; num_groups = in_num_groups; @@ -61,8 +67,8 @@ Mgxs::init(const std::string& in_name, double in_awr, void Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, - int in_num_delayed_groups, const double_1dvec& temperature, - double tolerance, int_1dvec& temps_to_read, int& order_dim, int& method) + int in_num_delayed_groups, const std::vector& temperature, + double tolerance, std::vector& temps_to_read, int& order_dim, int& method) { // get name char char_name[MAX_WORD_LEN]; @@ -87,7 +93,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, dset_names[i] = new char[151]; } get_datasets(kT_group, dset_names); - double_1dvec available_temps(num_temps); + xt::xarray available_temps(num_temps); for (int i = 0; i < num_temps; i++) { read_double(kT_group, dset_names[i], &available_temps[i], true); @@ -110,24 +116,20 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, switch(method) { case TEMPERATURE_NEAREST: - // Find the minimum difference - for (int i = 0; i < temperature.size(); i++) { - std::valarray temp_diff(available_temps.data(), - available_temps.size()); - temp_diff = std::abs(temp_diff - temperature[i]); - int i_closest = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - - std::begin(temp_diff); + // Determine actual temperatures to read + for (const auto& T : temperature) { + auto i_closest = xt::argmin(xt::abs(available_temps - T))[0]; double temp_actual = available_temps[i_closest]; - - if (std::abs(temp_actual - temperature[i]) < tolerance) { - if (std::find(temps_to_read.begin(), temps_to_read.end(), - std::round(temp_actual)) == temps_to_read.end()) { + if (std::fabs(temp_actual - T) < tolerance) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual)) + == temps_to_read.end()) { temps_to_read.push_back(std::round(temp_actual)); - } else { - fatal_error("MGXS Library does not contain cross section for " + - in_name + " at or near " + - std::to_string(std::round(temperature[i])) + " K."); } + } else { + std::stringstream msg; + msg << "MGXS library does not contain cross sections for " + << in_name << " at or near " << std::round(T) << " K."; + fatal_error(msg); } } break; @@ -160,7 +162,7 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, // Get the library's temperatures int n_temperature = temps_to_read.size(); - double_1dvec in_kTs(n_temperature); + std::vector in_kTs(n_temperature); for (int i = 0; i < n_temperature; i++) { std::string temp_str(std::to_string(temps_to_read[i]) + "K"); @@ -254,12 +256,12 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, } // Set the angular bins to use equally-spaced bins - double_1dvec in_polar(in_n_pol); + std::vector in_polar(in_n_pol); double dangle = PI / in_n_pol; for (int p = 0; p < in_n_pol; p++) { in_polar[p] = (p + 0.5) * dangle; } - double_1dvec in_azimuthal(in_n_azi); + std::vector in_azimuthal(in_n_azi); dangle = 2. * PI / in_n_azi; for (int a = 0; a < in_n_azi; a++) { in_azimuthal[a] = (a + 0.5) * dangle - PI; @@ -274,12 +276,12 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, int in_num_groups, //============================================================================== Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups, - const double_1dvec& temperature, double tolerance, int max_order, + const std::vector& temperature, double tolerance, int max_order, bool legendre_to_tabular, int legendre_to_tabular_points, int& method) { // Call generic data gathering routine (will populate the metadata) int order_data; - int_1dvec temps_to_read; + std::vector temps_to_read; metadata_from_hdf5(xs_id, energy_groups, delayed_groups, temperature, tolerance, temps_to_read, order_data, method); @@ -310,8 +312,8 @@ Mgxs::Mgxs(hid_t xs_id, int energy_groups, int delayed_groups, //============================================================================== -Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, - const std::vector& micros, const double_1dvec& atom_densities, +Mgxs::Mgxs(const std::string& in_name, const std::vector& mat_kTs, + const std::vector& micros, const std::vector& atom_densities, double tolerance, int& method) { // Get the minimum data needed to initialize: @@ -328,8 +330,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, int in_num_groups = micros[0]->num_groups; int in_num_delayed_groups = micros[0]->num_delayed_groups; bool in_is_isotropic = micros[0]->is_isotropic; - double_1dvec in_polar = micros[0]->polar; - double_1dvec in_azimuthal = micros[0]->azimuthal; + std::vector in_polar = micros[0]->polar; + std::vector in_azimuthal = micros[0]->azimuthal; init(in_name, in_awr, mat_kTs, in_fissionable, in_scatter_format, in_num_groups, in_num_delayed_groups, in_is_isotropic, in_polar, @@ -345,33 +347,27 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, // Create the list of temperature indices and interpolation factors for // each microscopic data at the material temperature - int_1dvec micro_t(micros.size(), 0); - double_1dvec micro_t_interp(micros.size(), 0.); + std::vector micro_t(micros.size(), 0); + std::vector micro_t_interp(micros.size(), 0.); for (int m = 0; m < micros.size(); m++) { switch(method) { case TEMPERATURE_NEAREST: { - // Find the nearest temperature - std::valarray temp_diff(micros[m]->kTs.data(), - micros[m]->kTs.size()); - temp_diff = std::abs(temp_diff - temp_desired); - micro_t[m] = std::min_element(std::begin(temp_diff), - std::end(temp_diff)) - - std::begin(temp_diff); - double temp_actual = micros[m]->kTs[micro_t[m]]; + micro_t[m] = xt::argmin(xt::abs(micros[m]->kTs - temp_desired))[0]; + auto temp_actual = micros[m]->kTs[micro_t[m]]; if (std::abs(temp_actual - temp_desired) >= K_BOLTZMANN * tolerance) { - fatal_error("MGXS Library does not contain cross section for " + - name + " at or near " + - std::to_string(std::round(temp_desired / K_BOLTZMANN)) - + " K."); + std::stringstream msg; + msg << "MGXS Library does not contain cross section for " << name + << " at or near " << std::round(temp_desired / K_BOLTZMANN) << "K."; + fatal_error(msg); } } break; case TEMPERATURE_INTERPOLATION: // Get a list of bounding temperatures for each actual temperature // present in the model - for (int k = 0; k < micros[m]->kTs.size() - 1; k++) { + for (int k = 0; k < micros[m]->kTs.shape()[0] - 1; k++) { if ((micros[m]->kTs[k] <= temp_desired) && (temp_desired < micros[m]->kTs[k + 1])) { micro_t[m] = k; @@ -394,8 +390,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, int num_interp_points = 2; if (method == TEMPERATURE_NEAREST) num_interp_points = 1; for (int interp_point = 0; interp_point < num_interp_points; interp_point++) { - double_1dvec interp(micros.size()); - double_1dvec temp_indices(micros.size()); + std::vector interp(micros.size()); + std::vector temp_indices(micros.size()); for (int m = 0; m < micros.size(); m++) { interp[m] = (1. - micro_t_interp[m]) * atom_densities[m]; temp_indices[m] = micro_t[m] + interp_point; @@ -409,8 +405,8 @@ Mgxs::Mgxs(const std::string& in_name, const double_1dvec& mat_kTs, //============================================================================== void -Mgxs::combine(const std::vector& micros, const double_1dvec& scalars, - const int_1dvec& micro_ts, int this_t) +Mgxs::combine(const std::vector& micros, const std::vector& scalars, + const std::vector& micro_ts, int this_t) { // Build the vector of pointers to the xs objects within micros std::vector those_xs(micros.size()); @@ -441,19 +437,19 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) double val; switch(xstype) { case MG_GET_XS_TOTAL: - val = xs_t->total[a][gin]; + val = xs_t->total(a, gin); break; case MG_GET_XS_NU_FISSION: - val = fissionable ? xs_t->nu_fission[a][gin] : 0.; + val = fissionable ? xs_t->nu_fission(a, gin) : 0.; break; case MG_GET_XS_ABSORPTION: - val = xs_t->absorption[a][gin]; + val = xs_t->absorption(a, gin);; break; case MG_GET_XS_FISSION: - val = fissionable ? xs_t->fission[a][gin] : 0.; + val = fissionable ? xs_t->fission(a, gin) : 0.; break; case MG_GET_XS_KAPPA_FISSION: - val = fissionable ? xs_t->kappa_fission[a][gin] : 0.; + val = fissionable ? xs_t->kappa_fission(a, gin) : 0.; break; case MG_GET_XS_SCATTER: case MG_GET_XS_SCATTER_MULT: @@ -462,16 +458,16 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) val = xs_t->scatter[a]->get_xs(xstype, gin, gout, mu); break; case MG_GET_XS_PROMPT_NU_FISSION: - val = fissionable ? xs_t->prompt_nu_fission[a][gin] : 0.; + val = fissionable ? xs_t->prompt_nu_fission(a, gin) : 0.; break; case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs_t->delayed_nu_fission[a][gin][*dg]; + val = xs_t->delayed_nu_fission(a, gin, *dg); } else { val = 0.; - for (auto& num : xs_t->delayed_nu_fission[a][gin]) { - val += num; + for (int d = 0; d < xs_t->delayed_nu_fission.shape()[2]; d++) { + val += xs_t->delayed_nu_fission(a, gin, d); } } } else { @@ -481,12 +477,12 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) case MG_GET_XS_CHI_PROMPT: if (fissionable) { if (gout != nullptr) { - val = xs_t->chi_prompt[a][gin][*gout]; + val = xs_t->chi_prompt(a, gin, *gout); } else { // provide an outgoing group-wise sum val = 0.; - for (auto& num : xs_t->chi_prompt[a][gin]) { - val += num; + for (int g = 0; g < xs_t->chi_prompt.shape()[2]; g++) { + val += xs_t->chi_prompt(a, gin, g); } } } else { @@ -497,21 +493,21 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs_t->chi_delayed[a][gin][*gout][*dg]; + val = xs_t->chi_delayed(a, gin, *gout, *dg); } else { - val = xs_t->chi_delayed[a][gin][*gout][0]; + val = xs_t->chi_delayed(a, gin, *gout, 0); } } else { if (dg != nullptr) { val = 0.; - for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) { - val += xs_t->chi_delayed[a][gin][i][*dg]; + for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { + val += xs_t->delayed_nu_fission(a, gin, g, *dg); } } else { val = 0.; - for (int i = 0; i < xs_t->chi_delayed[a][gin].size(); i++) { - for (auto& num : xs_t->chi_delayed[a][gin][i]) { - val += num; + for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { + for (int d = 0; d < xs_t->delayed_nu_fission.shape()[3]; d++) { + val += xs_t->delayed_nu_fission(a, gin, g, d); } } } @@ -521,13 +517,13 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) } break; case MG_GET_XS_INVERSE_VELOCITY: - val = xs_t->inverse_velocity[a][gin]; + val = xs_t->inverse_velocity(a, gin); break; case MG_GET_XS_DECAY_RATE: if (dg != nullptr) { - val = xs_t->decay_rate[a][*dg + 1]; + val = xs_t->decay_rate(a, *dg + 1); } else { - val = xs_t->decay_rate[a][0]; + val = xs_t->decay_rate(a, 0); } break; default: @@ -548,11 +544,11 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) int tid = 0; #endif XsData* xs_t = &xs[cache[tid].t]; - double nu_fission = xs_t->nu_fission[cache[tid].a][gin]; + double nu_fission = xs_t->nu_fission(cache[tid].a, gin); // Find the probability of having a prompt neutron double prob_prompt = - xs_t->prompt_nu_fission[cache[tid].a][gin]; + xs_t->prompt_nu_fission(cache[tid].a, gin); // sample random numbers double xi_pd = prn() * nu_fission; @@ -568,10 +564,10 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs_t->chi_prompt[cache[tid].a][gin][gout]; + xs_t->chi_prompt(cache[tid].a, gin, gout); while (prob_gout < xi_gout) { gout++; - prob_gout += xs_t->chi_prompt[cache[tid].a][gin][gout]; + prob_gout += xs_t->chi_prompt(cache[tid].a, gin, gout); } } else { @@ -582,7 +578,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs_t->delayed_nu_fission[cache[tid].a][gin][dg]; + xs_t->delayed_nu_fission(cache[tid].a, gin, dg); } // adjust dg in case of round-off error @@ -591,11 +587,11 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs_t->chi_delayed[cache[tid].a][gin][gout][dg]; + xs_t->chi_delayed(cache[tid].a, gin, gout, dg); while (prob_gout < xi_gout) { gout++; prob_gout += - xs_t->chi_delayed[cache[tid].a][gin][gout][dg]; + xs_t->chi_delayed(cache[tid].a, gin, gout, dg); } } } @@ -630,10 +626,10 @@ Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], set_temperature_index(sqrtkT); set_angle_index(uvw); XsData* xs_t = &xs[cache[tid].t]; - total_xs = xs_t->total[cache[tid].a][gin]; - abs_xs = xs_t->absorption[cache[tid].a][gin]; + total_xs = xs_t->total(cache[tid].a, gin); + abs_xs = xs_t->absorption(cache[tid].a, gin); - nu_fiss_xs = fissionable ? xs_t->nu_fission[cache[tid].a][gin] : 0.; + nu_fiss_xs = fissionable ? xs_t->nu_fission(cache[tid].a, gin) : 0.; } //============================================================================== @@ -662,17 +658,7 @@ Mgxs::set_temperature_index(double sqrtkT) int tid = 0; #endif if (sqrtkT != cache[tid].sqrtkT) { - double kT = sqrtkT * sqrtkT; - - // initialize vector for storage of the differences - std::valarray temp_diff(kTs.data(), kTs.size()); - - // Find the minimum difference of kT and kTs - temp_diff = std::abs(temp_diff - kT); - cache[tid].t = std::min_element(std::begin(temp_diff), std::end(temp_diff)) - - std::begin(temp_diff); - - // store this temperature as the last one used + cache[tid].t = xt::argmin(xt::abs(kTs - sqrtkT * sqrtkT))[0]; cache[tid].sqrtkT = sqrtkT; } } diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 3e18c168f..69eb20d8e 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -4,6 +4,8 @@ #include #include +#include "xtensor/xbuilder.hpp" + #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/math_functions.h" @@ -16,8 +18,8 @@ namespace openmc { //============================================================================== void -ScattData::base_init(int order, const int_1dvec& in_gmin, - const int_1dvec& in_gmax, const double_2dvec& in_energy, +ScattData::base_init(int order, const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_energy, const double_2dvec& in_mult) { int groups = in_energy.size(); @@ -53,16 +55,15 @@ ScattData::base_init(int order, const int_1dvec& in_gmin, void ScattData::base_combine(int max_order, const std::vector& those_scatts, const double_1dvec& scalars, - int_1dvec& in_gmin, int_1dvec& in_gmax, double_2dvec& sparse_mult, + xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) { int groups = those_scatts[0] -> energy.size(); // Now allocate and zero our storage spaces - double_3dvec this_matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(max_order, 0.))); - double_2dvec mult_numer(groups, double_1dvec(groups, 0.)); - double_2dvec mult_denom(groups, double_1dvec(groups, 0.)); + xt::xtensor this_matrix({groups, groups, max_order}, 0.); + xt::xtensor mult_numer({groups, groups}, 0.); + xt::xtensor mult_denom({groups, groups}, 0.); // Build the dense scattering and multiplicity matrices // Get the multiplicity_matrix @@ -80,26 +81,26 @@ ScattData::base_combine(int max_order, ScattData* that = those_scatts[i]; // Build the dense matrix for that object - double_3dvec that_matrix = that->get_matrix(max_order); + xt::xtensor that_matrix = that->get_matrix(max_order); // Now add that to this for the scattering and multiplicity for (int gin = 0; gin < groups; gin++) { // Only spend time adding that's gmin to gmax data since the rest will // be zeros int i_gout = 0; - for (int gout = that->gmin[gin]; gout <= that->gmax[gin]; gout++) { + for (int gout = that->gmin(gin); gout <= that->gmax(gin); gout++) { // Do the scattering matrix for (int l = 0; l < max_order; l++) { - this_matrix[gin][gout][l] += scalars[i] * that_matrix[gin][gout][l]; + this_matrix(gin, gout, l) += scalars[i] * that_matrix(gin, gout, l); } // Incorporate that's contribution to the multiplicity matrix data - double nuscatt = that->scattxs[gin] * that->energy[gin][i_gout]; - mult_numer[gin][gout] += scalars[i] * nuscatt; + double nuscatt = that->scattxs(gin) * that->energy[gin][i_gout]; + mult_numer(gin, gout) += scalars[i] * nuscatt; if (that->mult[gin][i_gout] > 0.) { - mult_denom[gin][gout] += scalars[i] * nuscatt / that->mult[gin][i_gout]; + mult_denom(gin, gout) += scalars[i] * nuscatt / that->mult[gin][i_gout]; } else { - mult_denom[gin][gout] += scalars[i]; + mult_denom(gin, gout) += scalars[i]; } i_gout++; } @@ -107,16 +108,14 @@ ScattData::base_combine(int max_order, } // Combine mult_numer and mult_denom into the combined multiplicity matrix - double_2dvec this_mult(groups, double_1dvec(groups, 1.)); + xt::xtensor this_mult = xt::ones({groups, groups}); for (int gin = 0; gin < groups; gin++) { for (int gout = 0; gout < groups; gout++) { - if (mult_denom[gin][gout] > 0.) { - this_mult[gin][gout] = mult_numer[gin][gout] / mult_denom[gin][gout]; + if (mult_denom(gin, gout) > 0.) { + this_mult(gin, gout) = mult_numer(gin, gout) / mult_denom(gin, gout); } } } - mult_numer.clear(); - mult_denom.clear(); // We have the data, now we need to convert to a jagged array and then use // the initialize function to store it on the object. @@ -125,8 +124,8 @@ ScattData::base_combine(int max_order, int gmin_; for (gmin_ = 0; gmin_ < groups; gmin_++) { bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmin_].size(); l++) { - if (this_matrix[gin][gmin_][l] != 0.) { + for (int l = 0; l < this_matrix.shape()[2]; l++) { + if (this_matrix(gin, gmin_, l) != 0.) { non_zero = true; break; } @@ -136,8 +135,8 @@ ScattData::base_combine(int max_order, int gmax_; for (gmax_ = groups - 1; gmax_ >= 0; gmax_--) { bool non_zero = false; - for (int l = 0; l < this_matrix[gin][gmax_].size(); l++) { - if (this_matrix[gin][gmax_][l] != 0.) { + for (int l = 0; l < this_matrix.shape()[2]; l++) { + if (this_matrix(gin, gmax_, l) != 0.) { non_zero = true; break; } @@ -160,8 +159,11 @@ ScattData::base_combine(int max_order, sparse_mult[gin].resize(gmax_ - gmin_ + 1); int i_gout = 0; for (int gout = gmin_; gout <= gmax_; gout++) { - sparse_scatter[gin][i_gout] = this_matrix[gin][gout]; - sparse_mult[gin][i_gout] = this_mult[gin][gout]; + sparse_scatter[gin][i_gout].resize(this_matrix.shape()[2]); + for (int l = 0; l < this_matrix.shape()[2]; l++) { + sparse_scatter[gin][i_gout][l] = this_matrix(gin, gout, l); + } + sparse_mult[gin][i_gout] = this_mult(gin, gout); i_gout++; } } @@ -241,8 +243,9 @@ ScattData::get_xs(int xstype, int gin, const int* gout, const double* mu) //============================================================================== void -ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs) +ScattDataLegendre::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -252,10 +255,9 @@ ScattDataLegendre::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, // Get the scattering cross section value by summing the un-normalized P0 // coefficient in the variable matrix over all outgoing groups. - scattxs.resize(groups); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { int num_groups = in_gmax[gin] - in_gmin[gin] + 1; - scattxs[gin] = 0.; for (int i_gout = 0; i_gout < num_groups; i_gout++) { scattxs[gin] += matrix[gin][i_gout][0]; } @@ -401,8 +403,8 @@ ScattDataLegendre::combine(const std::vector& those_scatts, int groups = those_scatts[0] -> energy.size(); - int_1dvec in_gmin(groups); - int_1dvec in_gmax(groups); + xt::xtensor in_gmin({groups}); + xt::xtensor in_gmax({groups}); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -418,20 +420,19 @@ ScattDataLegendre::combine(const std::vector& those_scatts, //============================================================================== -double_3dvec +xt::xtensor ScattDataLegendre::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); int order_dim = max_order + 1; - double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(order_dim, 0.))); + xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * dist[gin][i_gout][l]; } } @@ -444,8 +445,9 @@ ScattDataLegendre::get_matrix(int max_order) //============================================================================== void -ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs) +ScattDataHistogram::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -455,9 +457,8 @@ ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, // Get the scattering cross section value by summing the distribution // over all the histogram bins in angle and outgoing energy groups - scattxs.resize(groups); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { - scattxs[gin] = 0.; for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { scattxs[gin] += std::accumulate(matrix[gin][i_gout].begin(), matrix[gin][i_gout].end(), 0.); @@ -484,12 +485,8 @@ ScattDataHistogram::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, ScattData::base_init(order, in_gmin, in_gmax, in_energy, in_mult); // Build the angular distribution mu values - mu = double_1dvec(order); + mu = xt::linspace(-1., 1., order + 1); dmu = 2. / order; - mu[0] = -1.; - for (int imu = 1; imu < order; imu++) { - mu[imu] = -1. + imu * dmu; - } // Calculate f(mu) and integrate it so we can avoid rejection sampling fmu.resize(groups); @@ -581,21 +578,20 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== -double_3dvec +xt::xtensor ScattDataHistogram::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations int order_dim = get_order(); - double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(order_dim, 0.))); + xt::xtensor matrix = xt::zeros({groups, groups, order_dim}); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * fmu[gin][i_gout][l]; } } @@ -624,8 +620,8 @@ ScattDataHistogram::combine(const std::vector& those_scatts, int groups = those_scatts[0] -> energy.size(); - int_1dvec in_gmin(groups); - int_1dvec in_gmax(groups); + xt::xtensor in_gmin({groups}); + xt::xtensor in_gmax({groups}); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -633,7 +629,7 @@ ScattDataHistogram::combine(const std::vector& those_scatts, // so we use a base class method to sum up xs and create new energy and mult // matrices ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, - sparse_mult, sparse_scatter); + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -644,8 +640,9 @@ ScattDataHistogram::combine(const std::vector& those_scatts, //============================================================================== void -ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, - const double_2dvec& in_mult, const double_3dvec& coeffs) +ScattDataTabular::init(const xt::xtensor& in_gmin, + const xt::xtensor& in_gmax, const double_2dvec& in_mult, + const double_3dvec& coeffs) { int groups = coeffs.size(); int order = coeffs[0][0].size(); @@ -654,19 +651,13 @@ ScattDataTabular::init(const int_1dvec& in_gmin, const int_1dvec& in_gmax, double_3dvec matrix = coeffs; // Build the angular distribution mu values - mu = double_1dvec(order); + mu = xt::linspace(-1., 1., order); dmu = 2. / (order - 1); - mu[0] = -1.; - for (int imu = 1; imu < order - 1; imu++) { - mu[imu] = -1. + imu * dmu; - } - mu[order - 1] = 1.; // Get the scattering cross section value by integrating the distribution // over all mu points and then combining over all outgoing groups - scattxs.resize(groups); + scattxs = xt::zeros({groups}); for (int gin = 0; gin < groups; gin++) { - scattxs[gin] = 0.; for (int i_gout = 0; i_gout < matrix[gin].size(); i_gout++) { for (int imu = 1; imu < order; imu++) { scattxs[gin] += 0.5 * dmu * (matrix[gin][i_gout][imu - 1] + @@ -743,7 +734,7 @@ ScattDataTabular::calc_f(int gin, int gout, double mu) int imu; if (mu == 1.) { // use size -2 to have the index one before the end - imu = this->mu.size() - 2; + imu = this->mu.shape()[0] - 2; } else { imu = std::floor((mu + 1.) / dmu + 1.) - 1; } @@ -764,7 +755,7 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) sample_energy(gin, gout, i_gout); // Determine the outgoing cosine bin - int NP = this->mu.size(); + int NP = this->mu.shape()[0]; double xi = prn(); double c_k = dist[gin][i_gout][0]; @@ -804,21 +795,20 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== -double_3dvec +xt::xtensor ScattDataTabular::get_matrix(int max_order) { // Get the sizes and initialize the data to 0 int groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations int order_dim = get_order(); - double_3dvec matrix = double_3dvec(groups, double_2dvec(groups, - double_1dvec(order_dim, 0.))); + xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { int gout = i_gout + gmin[gin]; for (int l = 0; l < order_dim; l++) { - matrix[gin][gout][l] = scattxs[gin] * energy[gin][i_gout] * + matrix(gin, gout, l) = scattxs[gin] * energy[gin][i_gout] * fmu[gin][i_gout][l]; } } @@ -847,8 +837,8 @@ ScattDataTabular::combine(const std::vector& those_scatts, int groups = those_scatts[0] -> energy.size(); - int_1dvec in_gmin(groups); - int_1dvec in_gmax(groups); + xt::xtensor in_gmin({groups}); + xt::xtensor in_gmax({groups}); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -856,7 +846,7 @@ ScattDataTabular::combine(const std::vector& those_scatts, // so we use a base class method to sum up xs and create new energy and mult // matrices ScattData::base_combine(max_order, those_scatts, scalars, in_gmin, in_gmax, - sparse_mult, sparse_scatter); + sparse_mult, sparse_scatter); // Got everything we need, store it. init(in_gmin, in_gmax, sparse_mult, sparse_scatter); @@ -885,13 +875,8 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, tab.scattxs = leg.scattxs; // Build mu and dmu - tab.mu = double_1dvec(n_mu); + tab.mu = xt::linspace(-1., 1., n_mu); tab.dmu = 2. / (n_mu - 1); - tab.mu[0] = -1.; - for (int imu = 1; imu < n_mu - 1; imu++) { - tab.mu[imu] = -1. + imu * tab.dmu; - } - tab.mu[n_mu - 1] = 1.; // Calculate f(mu) and integrate it so we can avoid rejection sampling int groups = tab.energy.size(); diff --git a/src/xsdata.cpp b/src/xsdata.cpp index d9863694a..0a48dce2b 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -5,6 +5,9 @@ #include #include +#include "xtensor/xbuilder.hpp" +#include "xtensor/xview.hpp" + #include "openmc/constants.h" #include "openmc/error.h" #include "openmc/math_functions.h" @@ -20,7 +23,7 @@ namespace openmc { XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, int scatter_format, int n_pol, int n_azi) { - int n_ang = n_pol * n_azi; + size_t n_ang = n_pol * n_azi; // check to make sure scatter format is OK before we allocate if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && @@ -28,31 +31,33 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, fatal_error("Invalid scatter_format!"); } // allocate all [temperature][phi][theta][in group] quantities - total = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - absorption = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - inverse_velocity = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + std::vector shape = {n_ang, energy_groups}; + total = xt::zeros(shape); + absorption = xt::zeros(shape); + inverse_velocity = xt::zeros(shape); if (fissionable) { - fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - prompt_nu_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); - kappa_fission = double_2dvec(n_ang, double_1dvec(energy_groups, 0.)); + fission = xt::zeros(shape); + nu_fission = xt::zeros(shape); + prompt_nu_fission = xt::zeros(shape); + kappa_fission = xt::zeros(shape); } // allocate decay_rate; [temperature][phi][theta][delayed group] - decay_rate = double_2dvec(n_ang, double_1dvec(num_delayed_groups, 0.)); + shape[1] = num_delayed_groups; + decay_rate = xt::zeros(shape); if (fissionable) { + shape = {n_ang, energy_groups, num_delayed_groups}; // allocate delayed_nu_fission; [temperature][phi][theta][in group][delay group] - delayed_nu_fission = double_3dvec(n_ang, double_2dvec(energy_groups, - double_1dvec(num_delayed_groups, 0.))); + delayed_nu_fission = xt::zeros(shape); - // chi_prompt; [temperature][phi][theta][in group][delayed group] - chi_prompt = double_3dvec(n_ang, double_2dvec(energy_groups, - double_1dvec(energy_groups, 0.))); + // chi_prompt; [temperature][phi][theta][in group][out group] + shape = {n_ang, energy_groups, energy_groups}; + chi_prompt = xt::zeros(shape); // chi_delayed; [temperature][phi][theta][in group][out group][delay group] - chi_delayed = double_4dvec(n_ang, double_3dvec(energy_groups, - double_2dvec(energy_groups, double_1dvec(num_delayed_groups, 0.)))); + shape = {n_ang, energy_groups, energy_groups, num_delayed_groups}; + chi_delayed = xt::zeros(shape); } @@ -79,8 +84,8 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, { // Reconstruct the dimension information so it doesn't need to be passed int n_ang = n_pol * n_azi; - int energy_groups = total[0].size(); - int delayed_groups = decay_rate[0].size(); + int energy_groups = total.shape()[1]; + int delayed_groups = decay_rate.shape()[1]; // Set the fissionable-specific data if (fissionable) { @@ -100,7 +105,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, // denominator in tally methods for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - if (absorption[a][gin] == 0.) absorption[a][gin] = 1.e-10; + if (absorption(a, gin) == 0.) absorption(a, gin) = 1.e-10; } } @@ -110,7 +115,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, } else { for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - total[a][gin] = absorption[a][gin] + scatter[a]->scattxs[gin]; + total(a, gin) = absorption(a, gin) + scatter[a]->scattxs[gin]; } } } @@ -118,7 +123,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, // Fix if total is 0, since it is in the denominator when tallying for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - if (total[a][gin] == 0.) total[a][gin] = 1.e-10; + if (total(a, gin) == 0.) total(a, gin) = 1.e-10; } } } @@ -129,14 +134,13 @@ void XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, int delayed_groups, bool is_isotropic) { - int n_ang = n_pol * n_azi; + size_t n_ang = n_pol * n_azi; // Get the fission and kappa_fission data xs; these are optional read_nd_vector(xsdata_grp, "fission", fission); read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); // Set/get beta - double_3dvec temp_beta =double_3dvec(n_ang, double_2dvec(energy_groups, - double_1dvec(delayed_groups, 0.))); + xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); if (object_exists(xsdata_grp, "beta")) { hid_t xsdata = open_dataset(xsdata_grp, "beta"); int ndims = dataset_ndims(xsdata); @@ -146,7 +150,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // Beta is input as [delayed group] - double_1dvec temp_arr(n_pol * n_azi * delayed_groups); + std::vector temp_arr({n_pol * n_azi * delayed_groups}); read_nd_vector(xsdata_grp, "beta", temp_arr); // Broadcast to all incoming groups @@ -154,9 +158,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int a = 0; a < n_ang; a++) { for (int dg = 0; dg < delayed_groups; dg++) { // Set the first group index and copy the rest - temp_beta[a][0][dg] = temp_arr[temp_idx++]; + temp_beta(a, 0, dg) = temp_arr[temp_idx++]; for (int gin = 1; gin < energy_groups; gin++) { - temp_beta[a][gin] = temp_beta[a][0]; + temp_beta(a, gin, dg) = temp_beta(a, 0, dg); } } } @@ -170,29 +174,33 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi is provided, set chi-prompt and chi-delayed if (object_exists(xsdata_grp, "chi")) { - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr ({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "chi", temp_arr); for (int a = 0; a < n_ang; a++) { // First set the first group for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][0][gout] = temp_arr[a][gout]; + chi_prompt(a, 0, gout) = temp_arr(a, gout); } // Now normalize this data - double chi_sum = std::accumulate(chi_prompt[a][0].begin(), - chi_prompt[a][0].end(), - 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_prompt(a, 0, gout); + } + if (chi_sum <= 0.) { fatal_error("Encountered chi for a group that is <= 0!"); } for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][0][gout] /= chi_sum; + chi_prompt(a, 0, gout) /= chi_sum; } // And extend to the remaining incoming groups for (int gin = 1; gin < energy_groups; gin++) { - chi_prompt[a][gin] = chi_prompt[a][0]; + for (int gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = chi_prompt(a, 0, gout); + } } // Finally set chi-delayed equal to chi-prompt @@ -200,8 +208,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for(int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[a][gin][gout][dg] = - chi_prompt[a][gin][gout]; + chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } } @@ -224,15 +231,18 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { for (int dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission[a][gin][dg] = - temp_beta[a][gin][dg] * prompt_nu_fission[a][gin]; + delayed_nu_fission(a, gin, dg) = + temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); } // Correct the prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { - double beta_sum = std::accumulate(temp_beta[a][gin].begin(), - temp_beta[a][gin].end(), 0.); - prompt_nu_fission[a][gin] *= (1. - beta_sum); + double beta_sum = 0.; + for (int gin = 0; gin < energy_groups; gin++) { + beta_sum += temp_beta(a, gin); + } + + prompt_nu_fission(a, gin) *= (1. - beta_sum); } } } @@ -244,14 +254,17 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Normalize the chi info so the CDF is 1. for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - double chi_sum = std::accumulate(chi_prompt[a][gin].begin(), - chi_prompt[a][gin].end(), 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_prompt(a, gin, gout); + } + // Set the vector nu-fission from the matrix nu-fission - prompt_nu_fission[a][gin] = chi_sum; + prompt_nu_fission(a, gin) = chi_sum; if (chi_sum >= 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] /= chi_sum; + chi_prompt(a, gin, gout) /= chi_sum; } } else { fatal_error("Encountered chi for a group that is <= 0!"); @@ -262,8 +275,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[a][gin][gout][dg] = - chi_prompt[a][gin][gout]; + chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } } @@ -271,16 +283,17 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Set the delayed-nu-fission and correct prompt-nu-fission with beta for (int gin = 0; gin < energy_groups; gin++) { for (int dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission[a][gin][dg] = - temp_beta[a][gin][dg] * - prompt_nu_fission[a][gin]; + delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * + prompt_nu_fission(a, gin); } // Correct prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { - double beta_sum = std::accumulate(temp_beta[a][gin].begin(), - temp_beta[a][gin].end(), 0.); - prompt_nu_fission[a][gin] *= (1. - beta_sum); + double beta_sum = 0.; + for (int dg = 0; dg < delayed_groups; dg++) { + beta_sum += temp_beta(a, gin, dg); + } + prompt_nu_fission(a, gin) *= (1. - beta_sum); } } } @@ -293,21 +306,24 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi-prompt is provided, set chi-prompt if (object_exists(xsdata_grp, "chi-prompt")) { - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] = temp_arr[a][gout]; + chi_prompt(a, gin, gout) = temp_arr(a, gout); } // Normalize chi so its CDF goes to 1 - double chi_sum = std::accumulate(chi_prompt[a][gin].begin(), - chi_prompt[a][gin].end(), 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += chi_prompt(a, gin, gout); + } + if (chi_sum >= 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] /= chi_sum; + chi_prompt(a, gin, gout) /= chi_sum; } } else { fatal_error("Encountered chi-prompt for a group that is <= 0.!"); @@ -326,13 +342,16 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // chi-delayed is a [in group] vector - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); for (int a = 0; a < n_ang; a++) { // normalize the chi CDF to 1 - double chi_sum = std::accumulate(temp_arr[a].begin(), - temp_arr[a].end(), 0.); + double chi_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + chi_sum += temp_arr(a, gout); + } + if (chi_sum <= 0.) { fatal_error("Encountered chi-delayed for a group that is <= 0!"); } @@ -341,7 +360,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { for (int gout = 0; gout < energy_groups; gout++) { for (int dg = 0; dg < delayed_groups; dg++) { - chi_delayed[a][gin][gout][dg] = temp_arr[a][gout] / chi_sum; + chi_delayed(a, gin, gout, dg) = temp_arr(a, gout) / chi_sum; } } } @@ -356,12 +375,12 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { double chi_sum = 0.; for (int gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_delayed[a][gin][gout][dg]; + chi_sum += chi_delayed(a, gin, gout, dg); } if (chi_sum > 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_delayed[a][gin][gout][dg] /= chi_sum; + chi_delayed(a, gin, gout, dg) /= chi_sum; } } else { fatal_error("Encountered chi-delayed for a group that is <= 0!"); @@ -384,29 +403,30 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // prompt-nu-fission is a [in group] vector - read_nd_vector(xsdata_grp, "prompt-nu-fission", - prompt_nu_fission); + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission); } else if (ndims == 4) { // prompt nu fission is a matrix, // so set prompt_nu_fiss & chi_prompt - double_3dvec temp_arr(n_ang, double_2dvec(energy_groups, - double_1dvec(energy_groups))); + xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); // The prompt_nu_fission vector from the matrix form for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - double prompt_sum = std::accumulate(temp_arr[a][gin].begin(), - temp_arr[a][gin].end(), 0.); - prompt_nu_fission[a][gin] = prompt_sum; + double prompt_sum = 0.; + for (int gout = 0; gout < energy_groups; gout++) { + prompt_sum += temp_arr(a, gin, gout); + } + + prompt_nu_fission(a, gin) = prompt_sum; } // The chi_prompt data is just the normalized fission matrix for (int gin= 0; gin < energy_groups; gin++) { - if (prompt_nu_fission[a][gin] > 0.) { + if (prompt_nu_fission(a, gin) > 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_prompt[a][gin][gout] = - temp_arr[a][gin][gout] / prompt_nu_fission[a][gin]; + chi_prompt(a, gin, gout) = + temp_arr(a, gin, gout) / prompt_nu_fission(a, gin); } } else { fatal_error("Encountered chi-prompt for a group that is <= 0!"); @@ -429,19 +449,19 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, if (ndims == 3) { // delayed-nu-fission is an [in group] vector - if (temp_beta[0][0][0] == 0.) { + if (temp_beta(0, 0, 0) == 0.) { fatal_error("cannot set delayed-nu-fission with a 1D array if " "beta is not provided"); } - double_2dvec temp_arr(n_ang, double_1dvec(energy_groups)); + xt::xtensor temp_arr({n_ang, energy_groups}); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { for (int dg = 0; dg < delayed_groups; dg++) { // Set delayed-nu-fission using beta - delayed_nu_fission[a][gin][dg] = - temp_beta[a][gin][dg] * temp_arr[a][gin]; + delayed_nu_fission(a, gin, dg) = + temp_beta(a, gin, dg) * temp_arr(a, gin); } } } @@ -451,9 +471,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, delayed_nu_fission); } else if (ndims == 5) { - // This will contain delayed-nu-fision and chi-delayed data - double_4dvec temp_arr(n_ang, double_3dvec(energy_groups, - double_2dvec(energy_groups, double_1dvec(delayed_groups)))); + // This will contain delayed-nu-fission and chi-delayed data + xt::xtensor temp_arr({n_ang, energy_groups, energy_groups, + delayed_groups}); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); // Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix @@ -463,14 +483,14 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, for (int gin = 0; gin < energy_groups; gin++) { double gout_sum = 0.; for (int gout = 0; gout < energy_groups; gout++) { - gout_sum += temp_arr[a][gin][gout][dg]; - chi_delayed[a][gin][gout][dg] = temp_arr[a][gin][gout][dg]; + gout_sum += temp_arr(a, gin, gout, dg); + chi_delayed(a, gin, gout, dg) = temp_arr(a, gin, gout, dg); } - delayed_nu_fission[a][gin][dg] = gout_sum; + delayed_nu_fission(a, gin, dg) = gout_sum; // Normalize chi-delayed if (gout_sum > 0.) { for (int gout = 0; gout < energy_groups; gout++) { - chi_delayed[a][gin][gout][dg] /= gout_sum; + chi_delayed(a, gin, gout, dg) /= gout_sum; } } else { fatal_error("Encountered chi-delayed for a group that is <= 0!"); @@ -488,10 +508,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Combine prompt_nu_fission and delayed_nu_fission into nu_fission for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - nu_fission[a][gin] = - std::accumulate(delayed_nu_fission[a][gin].begin(), - delayed_nu_fission[a][gin].end(), - prompt_nu_fission[a][gin]); + nu_fission(a, gin) = prompt_nu_fission(a, gin); + for (int dg = 0; dg < delayed_groups; dg++) { + nu_fission(a, gin) += delayed_nu_fission(a, gin, dg); + } } } } @@ -503,94 +523,92 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, int scatter_format, int final_scatter_format, int order_data, int max_order, int legendre_to_tabular_points) { - int n_ang = n_pol * n_azi; + size_t n_ang = n_pol * n_azi; if (!object_exists(xsdata_grp, "scatter_data")) { fatal_error("Must provide scatter_data group!"); } hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - int_2dvec gmin(n_ang, int_1dvec(energy_groups)); + xt::xtensor gmin({n_ang, energy_groups}); read_nd_vector(scatt_grp, "g_min", gmin, true); - int_2dvec gmax(n_ang, int_1dvec(energy_groups)); + xt::xtensor gmax({n_ang, energy_groups}); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - gmin[a][gin] -= 1; - gmax[a][gin] -= 1; - } - } + gmin -= 1; + gmax -= 1; // Now use this info to find the length of a vector to hold the flattened // data. int length = 0; for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - length += order_data * (gmax[a][gin] - gmin[a][gin] + 1); + length += order_data * (gmax(a, gin) - gmin(a, gin) + 1); } } - double_1dvec temp_arr(length); - read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); - // Compare the number of orders given with the max order of the problem; - // strip off the superfluous orders if needed - int order_dim; - if (scatter_format == ANGLE_LEGENDRE) { - order_dim = std::min(order_data - 1, max_order) + 1; - } else { - order_dim = order_data; - } - - // convert the flattened temp_arr to a jagged array for passing to - // scatt data double_4dvec input_scatt(n_ang, double_3dvec(energy_groups)); + //temp_arr scope + { + std::vector temp_arr(length); + read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - input_scatt[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); - for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { - input_scatt[a][gin][i_gout].resize(order_dim); - for (int l = 0; l < order_dim; l++) { - input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; + // Compare the number of orders given with the max order of the problem; + // strip off the superfluous orders if needed + int order_dim; + if (scatter_format == ANGLE_LEGENDRE) { + order_dim = std::min(order_data - 1, max_order) + 1; + } else { + order_dim = order_data; + } + + // convert the flattened temp_arr to a jagged array for passing to + // scatt data + int temp_idx = 0; + for (int a = 0; a < n_ang; a++) { + for (int gin = 0; gin < energy_groups; gin++) { + input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); + for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { + input_scatt[a][gin][i_gout].resize(order_dim); + for (int l = 0; l < order_dim; l++) { + input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; + } + // Adjust index for the orders we didnt take + temp_idx += (order_data - order_dim); } - // Adjust index for the orders we didnt take - temp_idx += (order_data - order_dim); } } } - temp_arr.clear(); // Get multiplication matrix double_3dvec temp_mult(n_ang, double_2dvec(energy_groups)); if (object_exists(scatt_grp, "multiplicity_matrix")) { - temp_arr.resize(length / order_data); + std::vector temp_arr(length / order_data); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); // convert the flat temp_arr to a jagged array for passing to scatt data int temp_idx = 0; for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); + temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = temp_arr[temp_idx++]; } } } + temp_arr.clear(); } else { // Use a default: multiplicities are 1.0. for (int a = 0; a < n_ang; a++) { for (int gin = 0; gin < energy_groups; gin++) { - temp_mult[a][gin].resize(gmax[a][gin] - gmin[a][gin] + 1); + temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = 1.; } } } } - temp_arr.clear(); close_group(scatt_grp); // Finally, convert the Legendre data to tabular, if needed @@ -598,7 +616,10 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, final_scatter_format == ANGLE_TABULAR) { for (int a = 0; a < n_ang; a++) { ScattDataLegendre legendre_scatt; - legendre_scatt.init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]); + xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); + xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); + legendre_scatt.init(in_gmin, in_gmax, + temp_mult[a], input_scatt[a]); // Now create a tabular version of legendre_scatt convert_legendre_to_tabular(legendre_scatt, @@ -611,7 +632,9 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // We are sticking with the current representation // Initialize the ScattData object with this data for (int a = 0; a < n_ang; a++) { - scatter[a]->init(gmin[a], gmax[a], temp_mult[a], input_scatt[a]); + scatter[a]->init(xt::view(gmin, a, xt::all()), + xt::view(gmax, a, xt::all()), + temp_mult[a], input_scatt[a]); } } } @@ -627,70 +650,25 @@ XsData::combine(const std::vector& those_xs, XsData* that = those_xs[i]; if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!"); double scalar = scalars[i]; - for (int a = 0; a < total.size(); a++) { - for (int gin = 0; gin < total[a].size(); gin++) { - total[a][gin] += scalar * that->total[a][gin]; - absorption[a][gin] += scalar * that->absorption[a][gin]; - if (i == 0) { - inverse_velocity[a][gin] = that->inverse_velocity[a][gin]; - } - if (that->prompt_nu_fission.size() > 0) { - nu_fission[a][gin] += scalar * that->nu_fission[a][gin]; - prompt_nu_fission[a][gin] += - scalar * that->prompt_nu_fission[a][gin]; - kappa_fission[a][gin] += scalar * that->kappa_fission[a][gin]; - fission[a][gin] += scalar * that->fission[a][gin]; - - for (int dg = 0; dg < delayed_nu_fission[a][gin].size(); dg++) { - delayed_nu_fission[a][gin][dg] += - scalar * that->delayed_nu_fission[a][gin][dg]; - } - - for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) { - chi_prompt[a][gin][gout] += - scalar * that->chi_prompt[a][gin][gout]; - - for (int dg = 0; dg < chi_delayed[a][gin][gout].size(); dg++) { - chi_delayed[a][gin][gout][dg] += - scalar * that->chi_delayed[a][gin][gout][dg]; - } - } - } - } - - for (int dg = 0; dg < decay_rate[a].size(); dg++) { - decay_rate[a][dg] += scalar * that->decay_rate[a][dg]; - } - - // Normalize chi - if (chi_prompt.size() > 0) { - for (int gin = 0; gin < chi_prompt[a].size(); gin++) { - double norm = std::accumulate(chi_prompt[a][gin].begin(), - chi_prompt[a][gin].end(), 0.); - if (norm > 0.) { - for (int gout = 0; gout < chi_prompt[a][gin].size(); gout++) { - chi_prompt[a][gin][gout] /= norm; - } - } - - for (int dg = 0; dg < chi_delayed[a][gin][0].size(); dg++) { - norm = 0.; - for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) { - norm += chi_delayed[a][gin][gout][dg]; - } - if (norm > 0.) { - for (int gout = 0; gout < chi_delayed[a][gin].size(); gout++) { - chi_delayed[a][gin][gout][dg] /= norm; - } - } - } - } - } + total += scalar * that->total; + absorption += scalar * that->absorption; + if (i == 0) { + inverse_velocity = that->inverse_velocity; } + if (that->prompt_nu_fission.shape()[0] > 0) { + nu_fission += scalar * that->nu_fission; + prompt_nu_fission += scalar * that->prompt_nu_fission; + kappa_fission += scalar * that->kappa_fission; + fission += scalar * that->fission; + delayed_nu_fission += scalar * that->delayed_nu_fission; + chi_prompt += scalar * that->chi_prompt; + chi_delayed += scalar * that->chi_delayed; + } + decay_rate += scalar * that->decay_rate; } // Allow the ScattData object to combine itself - for (int a = 0; a < total.size(); a++) { + for (int a = 0; a < total.shape()[0]; a++) { // Build vector of the scattering objects to incorporate std::vector those_scatts(those_xs.size()); for (int i = 0; i < those_xs.size(); i++) { @@ -707,8 +685,7 @@ XsData::combine(const std::vector& those_xs, bool XsData::equiv(const XsData& that) { - return ((absorption.size() == that.absorption.size()) && - (absorption[0].size() == that.absorption[0].size())); + return (absorption.shape() == that.absorption.shape()); } } //namespace openmc diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index 72f052e68..473596198 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -71,10 +71,11 @@ class MGXSTestHarness(PyAPITestHarness): openmc.run(openmc_exec=config['exe']) def _cleanup(self): - super()._cleanup() - f = 'mgxs.h5' - if os.path.exists(f): - os.remove(f) + pass + # super()._cleanup() + # f = 'mgxs.h5' + # if os.path.exists(f): + # os.remove(f) def test_mgxs_library_ce_to_mg(): From 35def7aac244bf6134f6272cbeeedb45a0eddff1 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 1 Sep 2018 11:01:56 -0400 Subject: [PATCH 02/12] Got it all working, next would like to take advantage of the xtensor features to reduce lines of code --- include/openmc/constants.h | 2 - include/openmc/hdf5_interface.h | 4 - include/openmc/scattdata.h | 29 +- include/openmc/xsdata.h | 10 +- src/hdf5_interface.cpp | 112 ------- src/mgxs_interface.cpp | 6 +- src/scattdata.cpp | 78 ++--- src/xsdata.cpp | 282 +++++++++--------- .../mgxs_library_ce_to_mg/test.py | 9 +- 9 files changed, 200 insertions(+), 332 deletions(-) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 0b66f355c..b8c5c8548 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -11,8 +11,6 @@ namespace openmc { -// TODO: Replace with xtensor/other library? -typedef std::vector double_1dvec; typedef std::vector > double_2dvec; typedef std::vector > > double_3dvec; typedef std::vector > > > double_4dvec; diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 74f5ae581..3ab2014c1 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -50,10 +50,6 @@ void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); -void -read_nd_vector(hid_t obj_id, const char* name, std::vector& result, - bool must_have = false); - void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); diff --git a/include/openmc/scattdata.h b/include/openmc/scattdata.h index 7e73224b9..8ea81f252 100644 --- a/include/openmc/scattdata.h +++ b/include/openmc/scattdata.h @@ -33,8 +33,8 @@ class ScattData { //! \brief Combines microscopic ScattDatas into a macroscopic one. void - base_combine(int max_order, const std::vector& those_scatts, - const double_1dvec& scalars, xt::xtensor& in_gmin, + base_combine(size_t max_order, const std::vector& those_scatts, + const std::vector& scalars, xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter); @@ -85,7 +85,7 @@ class ScattData { //! @param scalars Scalars to multiply the microscopic data by. virtual void combine(const std::vector& those_scatts, - const double_1dvec& scalars) = 0; + const std::vector& scalars) = 0; //! \brief Getter for the dimensionality of the scattering order. //! @@ -93,7 +93,7 @@ class ScattData { //! of points, and for Histogram this is the number of bins. //! //! @return The order. - virtual int + virtual size_t get_order() = 0; //! \brief Builds a dense scattering matrix from the constituent parts @@ -102,7 +102,7 @@ class ScattData { //! requested; ignored otherwise. //! @return The dense scattering matrix. virtual xt::xtensor - get_matrix(int max_order) = 0; + get_matrix(size_t max_order) = 0; //! \brief Samples the outgoing energy from the ScattData info. //! @@ -151,7 +151,7 @@ class ScattDataLegendre: public ScattData { void combine(const std::vector& those_scatts, - const double_1dvec& scalars); + const std::vector& scalars); //! \brief Find the maximal value of the angular distribution to use as a // bounding box with rejection sampling. @@ -164,11 +164,11 @@ class ScattDataLegendre: public ScattData { void sample(int gin, int& gout, double& mu, double& wgt); - int + size_t get_order() {return dist[0][0].size() - 1;}; xt::xtensor - get_matrix(int max_order); + get_matrix(size_t max_order); }; //============================================================================== @@ -192,7 +192,7 @@ class ScattDataHistogram: public ScattData { void combine(const std::vector& those_scatts, - const double_1dvec& scalars); + const std::vector& scalars); double calc_f(int gin, int gout, double mu); @@ -200,11 +200,11 @@ class ScattDataHistogram: public ScattData { void sample(int gin, int& gout, double& mu, double& wgt); - int + size_t get_order() {return dist[0][0].size();}; xt::xtensor - get_matrix(int max_order); + get_matrix(size_t max_order); }; //============================================================================== @@ -234,7 +234,7 @@ class ScattDataTabular: public ScattData { void combine(const std::vector& those_scatts, - const double_1dvec& scalars); + const std::vector& scalars); double calc_f(int gin, int gout, double mu); @@ -242,10 +242,11 @@ class ScattDataTabular: public ScattData { void sample(int gin, int& gout, double& mu, double& wgt); - int + size_t get_order() {return dist[0][0].size();}; - xt::xtensor get_matrix(int max_order); + xt::xtensor + get_matrix(size_t max_order); }; //============================================================================== diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 9a602c8b7..d156de9d9 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -24,14 +24,14 @@ class XsData { private: //! \brief Reads scattering data from the HDF5 file void - scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, + scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, int scatter_format, int final_scatter_format, int order_data, int max_order, int legendre_to_tabular_points); //! \brief Reads fission data from the HDF5 file void - fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, int energy_groups, - int delayed_groups, bool is_isotropic); + fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, + size_t delayed_groups, bool is_isotropic); public: @@ -70,7 +70,7 @@ class XsData { //! @param scatter_format The scattering representation of the file. //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. - XsData(int num_groups, int num_delayed_groups, bool fissionable, + XsData(size_t num_groups, size_t num_delayed_groups, bool fissionable, int scatter_format, int n_pol, int n_azi); //! \brief Loads the XsData object from the HDF5 file @@ -103,7 +103,7 @@ class XsData { //! @param micros Microscopic objects to combine. //! @param scalars Scalars to multiply the microscopic data by. void - combine(const std::vector& those_xs, const double_1dvec& scalars); + combine(const std::vector& those_xs, const std::vector& scalars); //! \brief Checks to see if this and that are able to be combined //! diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index db987cc02..52fae8228 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -477,106 +477,6 @@ read_dataset(hid_t obj_id, const char* name, hid_t mem_type_id, if (name) H5Dclose(dset); } -// //***************************************************************************** - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// read_double(obj_id, name, result.data(), true); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_double(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_int(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -// void -// read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, -// bool must_have) -// { -// if (object_exists(obj_id, name)) { -// xt::xarray temp; -// read_int(obj_id, name, temp.data(), true); - -// result = xt::adapt(temp, result.shape()); -// } else if (must_have) { -// fatal_error(std::string("Must provide " + std::string(name) + "!")); -// } -// } - -//***************************************************************************** void read_double(hid_t obj_id, const char* name, double* buffer, bool indep) @@ -635,18 +535,6 @@ read_complex(hid_t obj_id, const char* name, std::complex* buffer, bool } -void -read_nd_vector(hid_t obj_id, const char* name, std::vector& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - read_double(obj_id, name, result.data(), true); - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index f601f3c71..56f3392ff 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -19,7 +19,7 @@ add_mgxs_c(hid_t file_id, const char* name, int energy_groups, int& method) { // Convert temps to a vector for the from_hdf5 function - double_1dvec temperature(temps, temps + n_temps); + std::vector temperature(temps, temps + n_temps); write_message("Loading " + std::string(name) + " data...", 6); @@ -60,10 +60,10 @@ create_macro_xs_c(const char* mat_name, int n_nuclides, const int i_nuclides[], { if (n_temps > 0) { // // Convert temps to a vector - double_1dvec temperature(temps, temps + n_temps); + std::vector temperature(temps, temps + n_temps); // Convert atom_densities to a vector - double_1dvec atom_densities_vec(atom_densities, + std::vector atom_densities_vec(atom_densities, atom_densities + n_nuclides); // Build array of pointers to nuclides_MG's Mgxs objects needed for this diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 69eb20d8e..0ff7969d1 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -22,7 +22,7 @@ ScattData::base_init(int order, const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_energy, const double_2dvec& in_mult) { - int groups = in_energy.size(); + size_t groups = in_energy.size(); gmin = in_gmin; gmax = in_gmax; @@ -53,12 +53,12 @@ ScattData::base_init(int order, const xt::xtensor& in_gmin, //============================================================================== void -ScattData::base_combine(int max_order, - const std::vector& those_scatts, const double_1dvec& scalars, +ScattData::base_combine(size_t max_order, + const std::vector& those_scatts, const std::vector& scalars, xt::xtensor& in_gmin, xt::xtensor& in_gmax, double_2dvec& sparse_mult, double_3dvec& sparse_scatter) { - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); // Now allocate and zero our storage spaces xt::xtensor this_matrix({groups, groups, max_order}, 0.); @@ -108,7 +108,7 @@ ScattData::base_combine(int max_order, } // Combine mult_numer and mult_denom into the combined multiplicity matrix - xt::xtensor this_mult = xt::ones({groups, groups}); + xt::xtensor this_mult({groups, groups}, 1.); for (int gin = 0; gin < groups; gin++) { for (int gout = 0; gout < groups; gout++) { if (mult_denom(gin, gout) > 0.) { @@ -247,8 +247,8 @@ ScattDataLegendre::init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { - int groups = coeffs.size(); - int order = coeffs[0][0].size(); + size_t groups = coeffs.size(); + size_t order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -303,7 +303,7 @@ ScattDataLegendre::init(const xt::xtensor& in_gmin, void ScattDataLegendre::update_max_val() { - int groups = max_val.size(); + size_t groups = max_val.size(); // Step through the polynomial with fixed number of points to identify the // maximal value int Nmu = 1001; @@ -386,25 +386,25 @@ ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) void ScattDataLegendre::combine(const std::vector& those_scatts, - const double_1dvec& scalars) + const std::vector& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order = 0; + size_t max_order = 0; for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataLegendre* that = dynamic_cast(those_scatts[i]); if (!that) { fatal_error("Cannot combine the ScattData objects!"); } - int that_order = that->get_order(); + size_t that_order = that->get_order(); if (that_order > max_order) max_order = that_order; } max_order++; // Add one since this is a Legendre - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); - xt::xtensor in_gmin({groups}); - xt::xtensor in_gmax({groups}); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -421,11 +421,11 @@ ScattDataLegendre::combine(const std::vector& those_scatts, //============================================================================== xt::xtensor -ScattDataLegendre::get_matrix(int max_order) +ScattDataLegendre::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 - int groups = energy.size(); - int order_dim = max_order + 1; + size_t groups = energy.size(); + size_t order_dim = max_order + 1; xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { @@ -449,8 +449,8 @@ ScattDataHistogram::init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { - int groups = coeffs.size(); - int order = coeffs[0][0].size(); + size_t groups = coeffs.size(); + size_t order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -579,13 +579,13 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== xt::xtensor -ScattDataHistogram::get_matrix(int max_order) +ScattDataHistogram::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 - int groups = energy.size(); + size_t groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations - int order_dim = get_order(); - xt::xtensor matrix = xt::zeros({groups, groups, order_dim}); + size_t order_dim = get_order(); + xt::xtensor matrix({groups, groups, order_dim}, 0); for (int gin = 0; gin < groups; gin++) { for (int i_gout = 0; i_gout < energy[gin].size(); i_gout++) { @@ -603,10 +603,10 @@ ScattDataHistogram::get_matrix(int max_order) void ScattDataHistogram::combine(const std::vector& those_scatts, - const double_1dvec& scalars) + const std::vector& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order = those_scatts[0]->get_order(); + size_t max_order = those_scatts[0]->get_order(); for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataHistogram* that = dynamic_cast(those_scatts[i]); @@ -618,10 +618,10 @@ ScattDataHistogram::combine(const std::vector& those_scatts, } } - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); - xt::xtensor in_gmin({groups}); - xt::xtensor in_gmax({groups}); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -644,8 +644,8 @@ ScattDataTabular::init(const xt::xtensor& in_gmin, const xt::xtensor& in_gmax, const double_2dvec& in_mult, const double_3dvec& coeffs) { - int groups = coeffs.size(); - int order = coeffs[0][0].size(); + size_t groups = coeffs.size(); + size_t order = coeffs[0][0].size(); // make a copy of coeffs that we can use to both extract data and normalize double_3dvec matrix = coeffs; @@ -796,12 +796,12 @@ ScattDataTabular::sample(int gin, int& gout, double& mu, double& wgt) //============================================================================== xt::xtensor -ScattDataTabular::get_matrix(int max_order) +ScattDataTabular::get_matrix(size_t max_order) { // Get the sizes and initialize the data to 0 - int groups = energy.size(); + size_t groups = energy.size(); // We ignore the requested order for Histogram and Tabular representations - int order_dim = get_order(); + size_t order_dim = get_order(); xt::xtensor matrix({groups, groups, order_dim}, 0.); for (int gin = 0; gin < groups; gin++) { @@ -820,10 +820,10 @@ ScattDataTabular::get_matrix(int max_order) void ScattDataTabular::combine(const std::vector& those_scatts, - const double_1dvec& scalars) + const std::vector& scalars) { // Find the max order in the data set and make sure we can combine the sets - int max_order = those_scatts[0]->get_order(); + size_t max_order = those_scatts[0]->get_order(); for (int i = 0; i < those_scatts.size(); i++) { // Lets also make sure these items are combineable ScattDataTabular* that = dynamic_cast(those_scatts[i]); @@ -835,10 +835,10 @@ ScattDataTabular::combine(const std::vector& those_scatts, } } - int groups = those_scatts[0] -> energy.size(); + size_t groups = those_scatts[0] -> energy.size(); - xt::xtensor in_gmin({groups}); - xt::xtensor in_gmax({groups}); + xt::xtensor in_gmin({groups}, 0); + xt::xtensor in_gmax({groups}, 0); double_3dvec sparse_scatter(groups); double_2dvec sparse_mult(groups); @@ -879,7 +879,7 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, tab.dmu = 2. / (n_mu - 1); // Calculate f(mu) and integrate it so we can avoid rejection sampling - int groups = tab.energy.size(); + size_t groups = tab.energy.size(); tab.fmu.resize(groups); for (int gin = 0; gin < groups; gin++) { int num_groups = tab.gmax[gin] - tab.gmin[gin] + 1; diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 0a48dce2b..d30bc65f8 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -5,8 +5,10 @@ #include #include -#include "xtensor/xbuilder.hpp" #include "xtensor/xview.hpp" +#include "xtensor/xindex_view.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xbuilder.hpp" #include "openmc/constants.h" #include "openmc/error.h" @@ -20,7 +22,7 @@ namespace openmc { // XsData class methods //============================================================================== -XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, +XsData::XsData(size_t energy_groups, size_t num_delayed_groups, bool fissionable, int scatter_format, int n_pol, int n_azi) { size_t n_ang = n_pol * n_azi; @@ -63,13 +65,10 @@ XsData::XsData(int energy_groups, int num_delayed_groups, bool fissionable, for (int a = 0; a < n_ang; a++) { if (scatter_format == ANGLE_HISTOGRAM) { - // scatter[a] = std::make_unique(ScattDataHistogram); scatter.emplace_back(new ScattDataHistogram); } else if (scatter_format == ANGLE_TABULAR) { - // scatter[a] = std::make_unique(ScattDataTabular); scatter.emplace_back(new ScattDataTabular); } else if (scatter_format == ANGLE_LEGENDRE) { - // scatter[a] = std::make_unique(ScattDataLegendre); scatter.emplace_back(new ScattDataLegendre); } } @@ -83,13 +82,13 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, int legendre_to_tabular_points, bool is_isotropic, int n_pol, int n_azi) { // Reconstruct the dimension information so it doesn't need to be passed - int n_ang = n_pol * n_azi; - int energy_groups = total.shape()[1]; - int delayed_groups = decay_rate.shape()[1]; + size_t n_ang = n_pol * n_azi; + size_t energy_groups = total.shape()[1]; + size_t delayed_groups = decay_rate.shape()[1]; // Set the fissionable-specific data if (fissionable) { - fission_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, delayed_groups, + fission_from_hdf5(xsdata_grp, n_ang, energy_groups, delayed_groups, is_isotropic); } // Get the non-fission-specific data @@ -98,43 +97,34 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, read_nd_vector(xsdata_grp, "inverse-velocity", inverse_velocity); // Get scattering data - scatter_from_hdf5(xsdata_grp, n_pol, n_azi, energy_groups, scatter_format, + scatter_from_hdf5(xsdata_grp, n_ang, energy_groups, scatter_format, final_scatter_format, order_data, max_order, legendre_to_tabular_points); // Check absorption to ensure it is not 0 since it is often the // denominator in tally methods - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - if (absorption(a, gin) == 0.) absorption(a, gin) = 1.e-10; - } - } + xt::filtration(absorption, xt::equal(absorption, 0.)) = 1.e-10; // Get or calculate the total x/s if (object_exists(xsdata_grp, "total")) { read_nd_vector(xsdata_grp, "total", total); } else { - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { total(a, gin) = absorption(a, gin) + scatter[a]->scattxs[gin]; } } } // Fix if total is 0, since it is in the denominator when tallying - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - if (total(a, gin) == 0.) total(a, gin) = 1.e-10; - } - } + xt::filtration(total, xt::equal(total, 0.)) = 1.e-10; } //============================================================================== void -XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int delayed_groups, bool is_isotropic) +XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, + size_t delayed_groups, bool is_isotropic) { - size_t n_ang = n_pol * n_azi; // Get the fission and kappa_fission data xs; these are optional read_nd_vector(xsdata_grp, "fission", fission); read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); @@ -143,23 +133,23 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); if (object_exists(xsdata_grp, "beta")) { hid_t xsdata = open_dataset(xsdata_grp, "beta"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; if (ndims == 3) { // Beta is input as [delayed group] - std::vector temp_arr({n_pol * n_azi * delayed_groups}); + xt::xtensor temp_arr({n_ang * delayed_groups}, 0.); read_nd_vector(xsdata_grp, "beta", temp_arr); // Broadcast to all incoming groups - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { + size_t temp_idx = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { // Set the first group index and copy the rest temp_beta(a, 0, dg) = temp_arr[temp_idx++]; - for (int gin = 1; gin < energy_groups; gin++) { + for (size_t gin = 1; gin < energy_groups; gin++) { temp_beta(a, gin, dg) = temp_beta(a, 0, dg); } } @@ -174,40 +164,40 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi is provided, set chi-prompt and chi-delayed if (object_exists(xsdata_grp, "chi")) { - xt::xtensor temp_arr ({n_ang, energy_groups}); + xt::xtensor temp_arr ({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi", temp_arr); - for (int a = 0; a < n_ang; a++) { + for (size_t a = 0; a < n_ang; a++) { // First set the first group - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, 0, gout) = temp_arr(a, gout); } // Now normalize this data double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_prompt(a, 0, gout); } if (chi_sum <= 0.) { fatal_error("Encountered chi for a group that is <= 0!"); } - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, 0, gout) /= chi_sum; } // And extend to the remaining incoming groups - for (int gin = 1; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gin = 1; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) = chi_prompt(a, 0, gout); } } // Finally set chi-delayed equal to chi-prompt // Set chi-delayed to chi-prompt - for(int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for(size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } @@ -219,7 +209,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // if nu-fission is a matrix, set chi-prompt and chi-delayed. if (object_exists(xsdata_grp, "nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "nu-fission"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; @@ -228,9 +218,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission); // set delayed-nu-fission and correct prompt-nu-fission with beta - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); } @@ -238,7 +228,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Correct the prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { double beta_sum = 0.; - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t gin = 0; gin < energy_groups; gin++) { beta_sum += temp_beta(a, gin); } @@ -252,10 +242,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, read_nd_vector(xsdata_grp, "nu-fission", chi_prompt); // Normalize the chi info so the CDF is 1. - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_prompt(a, gin, gout); } @@ -263,7 +253,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, prompt_nu_fission(a, gin) = chi_sum; if (chi_sum >= 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) /= chi_sum; } } else { @@ -271,18 +261,18 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } } - // set chi-delayed to chi-prompt - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { + // set all of chi-delayed to chi-prompt + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); } } } // Set the delayed-nu-fission and correct prompt-nu-fission with beta - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); } @@ -290,7 +280,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Correct prompt-nu-fission using the delayed neutron fraction if (delayed_groups > 0) { double beta_sum = 0.; - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { beta_sum += temp_beta(a, gin, dg); } prompt_nu_fission(a, gin) *= (1. - beta_sum); @@ -306,23 +296,23 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi-prompt is provided, set chi-prompt if (object_exists(xsdata_grp, "chi-prompt")) { - xt::xtensor temp_arr({n_ang, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) = temp_arr(a, gout); } // Normalize chi so its CDF goes to 1 double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_prompt(a, gin, gout); } if (chi_sum >= 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) /= chi_sum; } } else { @@ -335,20 +325,20 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // If chi-delayed is provided, set chi-delayed if (object_exists(xsdata_grp, "chi-delayed")) { hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; close_dataset(xsdata); if (ndims == 3) { // chi-delayed is a [in group] vector - xt::xtensor temp_arr({n_ang, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); - for (int a = 0; a < n_ang; a++) { + for (size_t a = 0; a < n_ang; a++) { // normalize the chi CDF to 1 double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += temp_arr(a, gout); } @@ -357,9 +347,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } // set chi-delayed - for (int gin = 0; gin < energy_groups; gin++) { - for (int gout = 0; gout < energy_groups; gout++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { chi_delayed(a, gin, gout, dg) = temp_arr(a, gout) / chi_sum; } } @@ -370,16 +360,16 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, read_nd_vector(xsdata_grp, "chi-delayed", chi_delayed); // Normalize the chi info so the CDF is 1. - for (int a = 0; a < n_ang; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double chi_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_sum += chi_delayed(a, gin, gout, dg); } if (chi_sum > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_delayed(a, gin, gout, dg) /= chi_sum; } } else { @@ -396,7 +386,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Get prompt-nu-fission, if present if (object_exists(xsdata_grp, "prompt-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; close_dataset(xsdata); @@ -407,14 +397,14 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else if (ndims == 4) { // prompt nu fission is a matrix, // so set prompt_nu_fiss & chi_prompt - xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); // The prompt_nu_fission vector from the matrix form - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double prompt_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { prompt_sum += temp_arr(a, gin, gout); } @@ -422,9 +412,9 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } // The chi_prompt data is just the normalized fission matrix - for (int gin= 0; gin < energy_groups; gin++) { + for (size_t gin= 0; gin < energy_groups; gin++) { if (prompt_nu_fission(a, gin) > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_prompt(a, gin, gout) = temp_arr(a, gin, gout) / prompt_nu_fission(a, gin); } @@ -442,7 +432,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Get delayed-nu-fission, if present if (object_exists(xsdata_grp, "delayed-nu-fission")) { hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); - int ndims = dataset_ndims(xsdata); + size_t ndims = dataset_ndims(xsdata); close_dataset(xsdata); // raise ndims to make the isotropic ndims the same as angular if (is_isotropic) ndims += 2; @@ -453,12 +443,12 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, fatal_error("cannot set delayed-nu-fission with a 1D array if " "beta is not provided"); } - xt::xtensor temp_arr({n_ang, energy_groups}); + xt::xtensor temp_arr({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { // Set delayed-nu-fission using beta delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * temp_arr(a, gin); @@ -473,23 +463,23 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else if (ndims == 5) { // This will contain delayed-nu-fission and chi-delayed data xt::xtensor temp_arr({n_ang, energy_groups, energy_groups, - delayed_groups}); + delayed_groups}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); // Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix // from the 4D delayed-nu-fission matrix - for (int a = 0; a < n_ang; a++) { - for (int dg = 0; dg < delayed_groups; dg++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + for (size_t gin = 0; gin < energy_groups; gin++) { double gout_sum = 0.; - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { gout_sum += temp_arr(a, gin, gout, dg); chi_delayed(a, gin, gout, dg) = temp_arr(a, gin, gout, dg); } delayed_nu_fission(a, gin, dg) = gout_sum; // Normalize chi-delayed if (gout_sum > 0.) { - for (int gout = 0; gout < energy_groups; gout++) { + for (size_t gout = 0; gout < energy_groups; gout++) { chi_delayed(a, gin, gout, dg) /= gout_sum; } } else { @@ -506,10 +496,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { nu_fission(a, gin) = prompt_nu_fission(a, gin); - for (int dg = 0; dg < delayed_groups; dg++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { nu_fission(a, gin) += delayed_nu_fission(a, gin, dg); } } @@ -519,20 +509,19 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, //============================================================================== void -XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, - int energy_groups, int scatter_format, int final_scatter_format, - int order_data, int max_order, int legendre_to_tabular_points) +XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, + int scatter_format, int final_scatter_format, int order_data, + int max_order, int legendre_to_tabular_points) { - size_t n_ang = n_pol * n_azi; if (!object_exists(xsdata_grp, "scatter_data")) { fatal_error("Must provide scatter_data group!"); } hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - xt::xtensor gmin({n_ang, energy_groups}); + xt::xtensor gmin({n_ang, energy_groups}, 0.); read_nd_vector(scatt_grp, "g_min", gmin, true); - xt::xtensor gmax({n_ang, energy_groups}); + xt::xtensor gmax({n_ang, energy_groups}, 0.); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library @@ -541,42 +530,39 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Now use this info to find the length of a vector to hold the flattened // data. - int length = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + size_t length = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { length += order_data * (gmax(a, gin) - gmin(a, gin) + 1); } } double_4dvec input_scatt(n_ang, double_3dvec(energy_groups)); - //temp_arr scope - { - std::vector temp_arr(length); - read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); + xt::xtensor temp_arr({length}, 0.); + read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); - // Compare the number of orders given with the max order of the problem; - // strip off the superfluous orders if needed - int order_dim; - if (scatter_format == ANGLE_LEGENDRE) { - order_dim = std::min(order_data - 1, max_order) + 1; - } else { - order_dim = order_data; - } + // Compare the number of orders given with the max order of the problem; + // strip off the superfluous orders if needed + int order_dim; + if (scatter_format == ANGLE_LEGENDRE) { + order_dim = std::min(order_data - 1, max_order) + 1; + } else { + order_dim = order_data; + } - // convert the flattened temp_arr to a jagged array for passing to - // scatt data - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { - input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); - for (int i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { - input_scatt[a][gin][i_gout].resize(order_dim); - for (int l = 0; l < order_dim; l++) { - input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; - } - // Adjust index for the orders we didnt take - temp_idx += (order_data - order_dim); + // convert the flattened temp_arr to a jagged array for passing to + // scatt data + size_t temp_idx = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); + for (size_t i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { + input_scatt[a][gin][i_gout].resize(order_dim); + for (size_t l = 0; l < order_dim; l++) { + input_scatt[a][gin][i_gout][l] = temp_arr[temp_idx++]; } + // Adjust index for the orders we didnt take + temp_idx += (order_data - order_dim); } } } @@ -584,26 +570,25 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Get multiplication matrix double_3dvec temp_mult(n_ang, double_2dvec(energy_groups)); if (object_exists(scatt_grp, "multiplicity_matrix")) { - std::vector temp_arr(length / order_data); + temp_arr.resize({length / order_data}); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); // convert the flat temp_arr to a jagged array for passing to scatt data - int temp_idx = 0; - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + size_t temp_idx = 0; + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); - for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { + for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = temp_arr[temp_idx++]; } } } - temp_arr.clear(); } else { // Use a default: multiplicities are 1.0. - for (int a = 0; a < n_ang; a++) { - for (int gin = 0; gin < energy_groups; gin++) { + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); - for (int i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { + for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = 1.; } } @@ -614,10 +599,11 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, // Finally, convert the Legendre data to tabular, if needed if (scatter_format == ANGLE_LEGENDRE && final_scatter_format == ANGLE_TABULAR) { - for (int a = 0; a < n_ang; a++) { + for (size_t a = 0; a < n_ang; a++) { ScattDataLegendre legendre_scatt; xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); + legendre_scatt.init(in_gmin, in_gmax, temp_mult[a], input_scatt[a]); @@ -631,10 +617,10 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, } else { // We are sticking with the current representation // Initialize the ScattData object with this data - for (int a = 0; a < n_ang; a++) { - scatter[a]->init(xt::view(gmin, a, xt::all()), - xt::view(gmax, a, xt::all()), - temp_mult[a], input_scatt[a]); + for (size_t a = 0; a < n_ang; a++) { + xt::xtensor in_gmin = xt::view(gmin, a, xt::all()); + xt::xtensor in_gmax = xt::view(gmax, a, xt::all()); + scatter[a]->init(in_gmin, in_gmax, temp_mult[a], input_scatt[a]); } } } @@ -643,10 +629,10 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, int n_pol, int n_azi, void XsData::combine(const std::vector& those_xs, - const double_1dvec& scalars) + const std::vector& scalars) { // Combine the non-scattering data - for (int i = 0; i < those_xs.size(); i++) { + for (size_t i = 0; i < those_xs.size(); i++) { XsData* that = those_xs[i]; if (!equiv(*that)) fatal_error("Cannot combine the XsData objects!"); double scalar = scalars[i]; @@ -668,10 +654,10 @@ XsData::combine(const std::vector& those_xs, } // Allow the ScattData object to combine itself - for (int a = 0; a < total.shape()[0]; a++) { + for (size_t a = 0; a < total.shape()[0]; a++) { // Build vector of the scattering objects to incorporate std::vector those_scatts(those_xs.size()); - for (int i = 0; i < those_xs.size(); i++) { + for (size_t i = 0; i < those_xs.size(); i++) { those_scatts[i] = those_xs[i]->scatter[a].get(); } diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/test.py b/tests/regression_tests/mgxs_library_ce_to_mg/test.py index 473596198..72f052e68 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/test.py +++ b/tests/regression_tests/mgxs_library_ce_to_mg/test.py @@ -71,11 +71,10 @@ class MGXSTestHarness(PyAPITestHarness): openmc.run(openmc_exec=config['exe']) def _cleanup(self): - pass - # super()._cleanup() - # f = 'mgxs.h5' - # if os.path.exists(f): - # os.remove(f) + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) def test_mgxs_library_ce_to_mg(): From d6f94f7ce8e760033be662d5166148efbbeff10f Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 2 Sep 2018 18:59:28 -0400 Subject: [PATCH 03/12] added specialized fission-getting methods --- include/openmc/mgxs.h | 10 +- include/openmc/xsdata.h | 36 ++ src/input_xml.F90 | 2 +- src/mgxs.cpp | 10 +- src/xsdata.cpp | 611 ++++++++---------- .../regression_tests/mg_benchmark/__init__.py | 0 .../mg_benchmark/inputs_true.dat | 33 + .../mg_benchmark/results_true.dat | 2 + tests/regression_tests/mg_benchmark/test.py | 167 +++++ .../mg_benchmark_delayed/__init__.py | 0 .../mg_benchmark_delayed/test.py | 175 +++++ 11 files changed, 678 insertions(+), 368 deletions(-) create mode 100644 tests/regression_tests/mg_benchmark/__init__.py create mode 100644 tests/regression_tests/mg_benchmark/inputs_true.dat create mode 100644 tests/regression_tests/mg_benchmark/results_true.dat create mode 100644 tests/regression_tests/mg_benchmark/test.py create mode 100644 tests/regression_tests/mg_benchmark_delayed/__init__.py create mode 100644 tests/regression_tests/mg_benchmark_delayed/test.py diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index e80355bee..cd312ea17 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -159,7 +159,7 @@ class Mgxs { //! @param dg delayed group index; use nullptr if irrelevant. //! @return Requested cross section value. double - get_xs(int xstype, int gin, int* gout, double* mu, int* dg); + get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg); //! \brief Samples the fission neutron energy and if prompt or delayed. //! @@ -167,7 +167,7 @@ class Mgxs { //! @param dg Sampled delayed group index. //! @param gout Sampled outgoing energy group. void - sample_fission_energy(int gin, int& dg, int& gout); + sample_fission_energy(const int gin, int& dg, int& gout); //! \brief Samples the outgoing energy and angle from a scatter event. //! @@ -176,7 +176,7 @@ class Mgxs { //! @param mu Sampled cosine of the change-in-angle. //! @param wgt Weight of the particle to be adjusted. void - sample_scatter(int gin, int& gout, double& mu, double& wgt); + sample_scatter(const int gin, int& gout, double& mu, double& wgt); //! \brief Calculates cross section quantities needed for tracking. //! @@ -187,14 +187,14 @@ class Mgxs { //! @param abs_xs Resultant absorption cross section. //! @param nu_fiss_xs Resultant nu-fission cross section. void - calculate_xs(int gin, double sqrtkT, const double uvw[3], + calculate_xs(const int gin, const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); //! \brief Sets the temperature index in cache given a temperature //! //! @param sqrtkT Temperature of the material. void - set_temperature_index(double sqrtkT); + set_temperature_index(const double sqrtkT); //! \brief Sets the angle index in cache given a direction //! diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index d156de9d9..780855ecf 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -33,6 +33,42 @@ class XsData { fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, size_t delayed_groups, bool is_isotropic); + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when beta is provided. + void + fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when beta is not provided. + void + fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as chi and nu-fission vectors from + // the HDF5 file when no delayed data is provided. + void + fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when beta is provided. + void + fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when beta is not provided. + void + fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups); + + //! \brief Reads fission data formatted as a nu-fission matrix from + // the HDF5 file when no delayed data is provided. + void + fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups); + public: // The following quantities have the following dimensions: diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 010e09973..289488c34 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -183,7 +183,7 @@ contains ! Assign temperatures to cells that don't have temperatures already assigned call assign_temperatures() - ! Determine desired txemperatures for each nuclide and S(a,b) table + ! Determine desired temperatures for each nuclide and S(a,b) table call get_temperatures(nuc_temps, sab_temps) ! Check to make sure there are not too many nested coordinate levels in the diff --git a/src/mgxs.cpp b/src/mgxs.cpp index ed68a12e9..93b7d43b7 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -423,7 +423,7 @@ Mgxs::combine(const std::vector& micros, const std::vector& scala //============================================================================== double -Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) +Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -535,7 +535,7 @@ Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) //============================================================================== void -Mgxs::sample_fission_energy(int gin, int& dg, int& gout) +Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -599,7 +599,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) //============================================================================== void -Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) +Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) { // This method assumes that the temperature and angle indices are set // Sample the data @@ -614,7 +614,7 @@ Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) //============================================================================== void -Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], +Mgxs::calculate_xs(const int gin, const double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) { // Set our indices @@ -649,7 +649,7 @@ Mgxs::equiv(const Mgxs& that) //============================================================================== void -Mgxs::set_temperature_index(double sqrtkT) +Mgxs::set_temperature_index(const double sqrtkT) { // See if we need to find the new index #ifdef _OPENMP diff --git a/src/xsdata.cpp b/src/xsdata.cpp index d30bc65f8..18e474987 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -121,6 +121,241 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, //============================================================================== +void +XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided as nu-fission and chi with a beta for delayed info + + // Get chi + xt::xtensor temp_chi({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "chi", temp_chi, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + + // Now every incoming group in prompt_chi and delayed_chi is the normalized + // chi we just made + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = temp_chi(a, gout); + for (size_t dg = 0; dg < delayed_groups; dg++) { + chi_delayed(a, gin, gout, dg) = temp_chi(a, gout); + } + } + } + } + + // Get nu-fission + xt::xtensor temp_nufiss({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "nu-fission", temp_nufiss, true); + + // Get beta + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); + + // Set delayed_nu_fission as beta * nu_fission + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * temp_nufiss(a, gin); + } + } + } +} + +void +XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided separately as prompt + delayed nu-fission and chi + + // Get chi-prompt + xt::xtensor temp_chi_p({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); + + // Get chi-delayed + xt::xtensor temp_chi_d({n_ang, energy_groups, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {1}), xt::all(), + xt::newaxis(), xt::all()); + + // Now assign the prompt and delayed chis by replicating for each incoming group + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = temp_chi_p(a, gout); + for (size_t dg = 0; dg < delayed_groups; dg++) { + chi_delayed(a, gin, gout, dg) = temp_chi_d(a, gout, dg); + } + } + } + } + + // Get prompt and delayed nu-fission directly + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); + read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); +} + +void +XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups) +{ + // No beta is provided and there is no prompt/delay distinction. + // Therefore, the code only considers the data as prompt. + + // Get chi + xt::xtensor temp_chi({n_ang, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "chi", temp_chi, true); + + // Normalize chi by summing over the outgoing groups for each incoming angle + temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + + // Now every incoming group in self.chi is the normalized chi we just made + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + chi_prompt(a, gin, gout) = temp_chi(a, gout); + } + } + } + + // Get nu-fission directly + if (object_exists(xsdata_grp, "prompt-nu-fission")) { + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); + } else { + read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission, true); + } +} + +//============================================================================== + +void +XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided as nu-fission and chi with a beta for delayed info + + // Get nu-fission matrix + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); + + // Get beta + xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_tot) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - xt::sum(temp_beta, {2})); + + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + double out_sum = 0.; + for (size_t gout = 0; gout < energy_groups; gout++) { + out_sum += temp_matrix(a, gin, gout); + } + for (size_t dg = 0; dg < delayed_groups; dg++) { + delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * out_sum; + } + } + } + + // Store chi-prompt + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + double beta = 0.; + for (size_t dg = 0; dg < delayed_groups; dg++) { + beta += temp_beta(a, gin, dg); + } + chi_prompt(a, gin, gout) = (1.0 - beta) * temp_matrix(a, gin, gout); + } + } + } + + // Store chi-delayed + for (size_t a = 0; a < n_ang; a++) { + for (size_t gin = 0; gin < energy_groups; gin++) { + for (size_t gout = 0; gout < energy_groups; gout++) { + for (size_t dg = 0; dg < delayed_groups; dg++) { + chi_delayed(a, gin, gout, dg) = temp_beta(a, gin, dg) * temp_matrix(a, gin, gout); + } + } + } + } + + //Normalize both + chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::newaxis()); + chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {2}), xt::all(), + xt::newaxis(), xt::all()); +} + +void +XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups, size_t delayed_groups) +{ + // Data is provided separately as prompt + delayed nu-fission and chi + + // Get the prompt nu-fission matrix + xt::xtensor temp_matrix_p({n_ang, energy_groups, energy_groups}); + read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); + + // prompt_nu_fission is the sum over outgoing groups + prompt_nu_fission = xt::sum(temp_matrix_p, {2}); + + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_prompt = temp_matrix_p / prompt_nu_fission; + + // Get the delayed nu-fission matrix + xt::xtensor temp_matrix_d({n_ang, energy_groups, energy_groups, + delayed_groups}); + read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); + + // delayed_nu_fission is the sum over outgoing groups + delayed_nu_fission = xt::sum(temp_matrix_d, {2}); + + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_delayed = temp_matrix_d / delayed_nu_fission; +} + +void +XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, + size_t energy_groups) +{ + // No beta is provided and there is no prompt/delay distinction. + // Therefore, the code only considers the data as prompt. + + // Get nu-fission matrix + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + if (object_exists(xsdata_grp, "prompt-nu-fission")) { + read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix, true); + } else { + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); + } + + // prompt_nu_fission is the sum over outgoing groups + prompt_nu_fission = xt::sum(temp_matrix, {2}); + + // chi_prompt is this matrix but normalized over outgoing groups, which we + // have already stored in prompt_nu_fission + chi_prompt = temp_matrix / prompt_nu_fission; +} + +//============================================================================== + void XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, size_t delayed_groups, bool is_isotropic) @@ -129,369 +364,31 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, read_nd_vector(xsdata_grp, "fission", fission); read_nd_vector(xsdata_grp, "kappa-fission", kappa_fission); - // Set/get beta - xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); - if (object_exists(xsdata_grp, "beta")) { - hid_t xsdata = open_dataset(xsdata_grp, "beta"); - size_t ndims = dataset_ndims(xsdata); - - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - - if (ndims == 3) { - // Beta is input as [delayed group] - xt::xtensor temp_arr({n_ang * delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "beta", temp_arr); - - // Broadcast to all incoming groups - size_t temp_idx = 0; - for (size_t a = 0; a < n_ang; a++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - // Set the first group index and copy the rest - temp_beta(a, 0, dg) = temp_arr[temp_idx++]; - for (size_t gin = 1; gin < energy_groups; gin++) { - temp_beta(a, gin, dg) = temp_beta(a, 0, dg); - } - } - } - } else if (ndims == 4) { - // Beta is input as [in group][delayed group] - read_nd_vector(xsdata_grp, "beta", temp_beta); - } else { - fatal_error("beta must be provided as a 3D or 4D array!"); - } - } - - // If chi is provided, set chi-prompt and chi-delayed + // Get the data; the strategy for doing so depends on if the data is provided + // as a nu-fission matrix or a set of chi and nu-fission vectors if (object_exists(xsdata_grp, "chi")) { - xt::xtensor temp_arr ({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "chi", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - // First set the first group - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, 0, gout) = temp_arr(a, gout); - } - - // Now normalize this data - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_prompt(a, 0, gout); - } - - if (chi_sum <= 0.) { - fatal_error("Encountered chi for a group that is <= 0!"); - } - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, 0, gout) /= chi_sum; - } - - // And extend to the remaining incoming groups - for (size_t gin = 1; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = chi_prompt(a, 0, gout); - } - } - - // Finally set chi-delayed equal to chi-prompt - // Set chi-delayed to chi-prompt - for(size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); - } - } - } - } - } - - // If nu-fission is provided, set prompt- and delayed-nu-fission; - // if nu-fission is a matrix, set chi-prompt and chi-delayed. - if (object_exists(xsdata_grp, "nu-fission")) { - hid_t xsdata = open_dataset(xsdata_grp, "nu-fission"); - size_t ndims = dataset_ndims(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - - if (ndims == 3) { - // nu-fission is a 3-d array - read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission); - - // set delayed-nu-fission and correct prompt-nu-fission with beta - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = - temp_beta(a, gin, dg) * prompt_nu_fission(a, gin); - } - - // Correct the prompt-nu-fission using the delayed neutron fraction - if (delayed_groups > 0) { - double beta_sum = 0.; - for (size_t gin = 0; gin < energy_groups; gin++) { - beta_sum += temp_beta(a, gin); - } - - prompt_nu_fission(a, gin) *= (1. - beta_sum); - } - } - } - - } else if (ndims == 4) { - // nu-fission is a matrix - read_nd_vector(xsdata_grp, "nu-fission", chi_prompt); - - // Normalize the chi info so the CDF is 1. - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_prompt(a, gin, gout); - } - - // Set the vector nu-fission from the matrix nu-fission - prompt_nu_fission(a, gin) = chi_sum; - - if (chi_sum >= 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) /= chi_sum; - } - } else { - fatal_error("Encountered chi for a group that is <= 0!"); - } - } - - // set all of chi-delayed to chi-prompt - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = chi_prompt(a, gin, gout); - } - } - } - - // Set the delayed-nu-fission and correct prompt-nu-fission with beta - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = temp_beta(a, gin, dg) * - prompt_nu_fission(a, gin); - } - - // Correct prompt-nu-fission using the delayed neutron fraction - if (delayed_groups > 0) { - double beta_sum = 0.; - for (size_t dg = 0; dg < delayed_groups; dg++) { - beta_sum += temp_beta(a, gin, dg); - } - prompt_nu_fission(a, gin) *= (1. - beta_sum); - } - } - } + if (delayed_groups == 0) { + fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang, energy_groups); } else { - fatal_error("nu-fission must be provided as a 3D or 4D array!"); - } - - close_dataset(xsdata); - } - - // If chi-prompt is provided, set chi-prompt - if (object_exists(xsdata_grp, "chi-prompt")) { - xt::xtensor temp_arr({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "chi-prompt", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_arr(a, gout); - } - - // Normalize chi so its CDF goes to 1 - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_prompt(a, gin, gout); - } - - if (chi_sum >= 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) /= chi_sum; - } - } else { - fatal_error("Encountered chi-prompt for a group that is <= 0.!"); - } + if (object_exists(xsdata_grp, "beta")) { + fission_vector_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); + } else { + fission_vector_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); } } - } - - // If chi-delayed is provided, set chi-delayed - if (object_exists(xsdata_grp, "chi-delayed")) { - hid_t xsdata = open_dataset(xsdata_grp, "chi-delayed"); - size_t ndims = dataset_ndims(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - close_dataset(xsdata); - - if (ndims == 3) { - // chi-delayed is a [in group] vector - xt::xtensor temp_arr({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "chi-delayed", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - // normalize the chi CDF to 1 - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += temp_arr(a, gout); - } - - if (chi_sum <= 0.) { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); - } - - // set chi-delayed - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_arr(a, gout) / chi_sum; - } - } - } - } - } else if (ndims == 4) { - // chi_delayed is a matrix - read_nd_vector(xsdata_grp, "chi-delayed", chi_delayed); - - // Normalize the chi info so the CDF is 1. - for (size_t a = 0; a < n_ang; a++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double chi_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_sum += chi_delayed(a, gin, gout, dg); - } - - if (chi_sum > 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_delayed(a, gin, gout, dg) /= chi_sum; - } - } else { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); - } - } - } - } + } else { + if (delayed_groups == 0) { + fission_matrix_no_delayed_from_hdf5(xsdata_grp, n_ang, energy_groups); } else { - fatal_error("chi-delayed must be provided as a 3D or 4D array!"); - } - } - - // Get prompt-nu-fission, if present - if (object_exists(xsdata_grp, "prompt-nu-fission")) { - hid_t xsdata = open_dataset(xsdata_grp, "prompt-nu-fission"); - size_t ndims = dataset_ndims(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - close_dataset(xsdata); - - if (ndims == 3) { - // prompt-nu-fission is a [in group] vector - read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission); - } else if (ndims == 4) { - // prompt nu fission is a matrix, - // so set prompt_nu_fiss & chi_prompt - xt::xtensor temp_arr({n_ang, energy_groups, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_arr); - - // The prompt_nu_fission vector from the matrix form - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double prompt_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - prompt_sum += temp_arr(a, gin, gout); - } - - prompt_nu_fission(a, gin) = prompt_sum; - } - - // The chi_prompt data is just the normalized fission matrix - for (size_t gin= 0; gin < energy_groups; gin++) { - if (prompt_nu_fission(a, gin) > 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = - temp_arr(a, gin, gout) / prompt_nu_fission(a, gin); - } - } else { - fatal_error("Encountered chi-prompt for a group that is <= 0!"); - } - } + if (object_exists(xsdata_grp, "beta")) { + fission_matrix_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); + } else { + fission_matrix_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, + delayed_groups); } - - } else { - fatal_error("prompt-nu-fission must be provided as a 3D or 4D array!"); - } - } - - // Get delayed-nu-fission, if present - if (object_exists(xsdata_grp, "delayed-nu-fission")) { - hid_t xsdata = open_dataset(xsdata_grp, "delayed-nu-fission"); - size_t ndims = dataset_ndims(xsdata); - close_dataset(xsdata); - // raise ndims to make the isotropic ndims the same as angular - if (is_isotropic) ndims += 2; - - if (ndims == 3) { - // delayed-nu-fission is an [in group] vector - if (temp_beta(0, 0, 0) == 0.) { - fatal_error("cannot set delayed-nu-fission with a 1D array if " - "beta is not provided"); - } - xt::xtensor temp_arr({n_ang, energy_groups}, 0.); - read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - // Set delayed-nu-fission using beta - delayed_nu_fission(a, gin, dg) = - temp_beta(a, gin, dg) * temp_arr(a, gin); - } - } - } - - } else if (ndims == 4) { - read_nd_vector(xsdata_grp, "delayed-nu-fission", - delayed_nu_fission); - - } else if (ndims == 5) { - // This will contain delayed-nu-fission and chi-delayed data - xt::xtensor temp_arr({n_ang, energy_groups, energy_groups, - delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_arr); - - // Set the 3D delayed-nu-fission matrix and 4D chi-delayed matrix - // from the 4D delayed-nu-fission matrix - for (size_t a = 0; a < n_ang; a++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double gout_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - gout_sum += temp_arr(a, gin, gout, dg); - chi_delayed(a, gin, gout, dg) = temp_arr(a, gin, gout, dg); - } - delayed_nu_fission(a, gin, dg) = gout_sum; - // Normalize chi-delayed - if (gout_sum > 0.) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_delayed(a, gin, gout, dg) /= gout_sum; - } - } else { - fatal_error("Encountered chi-delayed for a group that is <= 0!"); - } - } - } - } - - } else { - fatal_error("prompt-nu-fission must be provided as a 3D, 4D, or 5D " - "array!"); } } diff --git a/tests/regression_tests/mg_benchmark/__init__.py b/tests/regression_tests/mg_benchmark/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/regression_tests/mg_benchmark/inputs_true.dat b/tests/regression_tests/mg_benchmark/inputs_true.dat new file mode 100644 index 000000000..8856770dd --- /dev/null +++ b/tests/regression_tests/mg_benchmark/inputs_true.dat @@ -0,0 +1,33 @@ + + + + + + + + + 2g.h5 + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + -929.45 -1e+50 -1e+50 929.45 1e+50 1e+50 + + + + false + + multi-group + + false + + diff --git a/tests/regression_tests/mg_benchmark/results_true.dat b/tests/regression_tests/mg_benchmark/results_true.dat new file mode 100644 index 000000000..33e4d68f7 --- /dev/null +++ b/tests/regression_tests/mg_benchmark/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +9.949396E-01 2.047218E-02 diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_benchmark/test.py new file mode 100644 index 000000000..cc8f5ba34 --- /dev/null +++ b/tests/regression_tests/mg_benchmark/test.py @@ -0,0 +1,167 @@ +import os + +import numpy as np + +import openmc + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Make a version of mat-1 which has a tabular representation of the + # scattering vice Legendre with 33 points + mat_2 = mat_1.convert_scatter_format('tabular', 33) + mat_2.name = 'mat_2' + mg_cross_sections_file.add_xsdata(mat_2) + + # Make a version of mat-1 which has a histogram representation of the + # scattering vice Legendre with 33 bins + mat_3 = mat_1.convert_scatter_format('histogram', 33) + mat_3.name = 'mat_3' + mg_cross_sections_file.add_xsdata(mat_3) + + # Make a version which uses a fission matrix vice chi & nu-fission + mat_4 = openmc.XSdata('mat_4', groups) + mat_4.order = 1 + mat_4.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_4.set_absorption(absorption) + mat_4.set_scatter_matrix(scatter) + mat_4.set_total(total) + mg_cross_sections_file.add_xsdata(mat_4) + + # Make an angle-dependent version of mat_1 with 2 polar and 2 azim. angles + mat_5 = mat_1.convert_representation('angle', 2, 2) + mat_5.name = 'mat_5' + mg_cross_sections_file.add_xsdata(mat_5) + + # Make a copy of mat_1 for testing microscopic cross sections + mat_6 = openmc.XSdata('mat_6', groups) + mat_6.order = 1 + mat_6.set_nu_fission(np.multiply(nu, fiss)) + mat_6.set_absorption(absorption) + mat_6.set_scatter_matrix(scatter) + mat_6.set_total(total) + mat_6.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_6) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +def create_model(): + create_library() + + # # Make Materials + materials_file = openmc.Materials() + + mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', 'base ang'] + macros = [] + mats = [] + for i in range(len(mat_names)): + macros.append(openmc.Macroscopic('mat_' + str(i + 1))) + mats.append(openmc.Material(name=mat_names[i])) + mats[-1].set_density('macro', 1.0) + mats[-1].add_macroscopic(macros[-1]) + + # Add in the microscopic data + mats.append(openmc.Material(name='micro')) + mats[-1].set_density("sum") + mats[-1].add_nuclide("mat_1", 0.5) + mats[-1].add_nuclide("mat_6", 0.5) + + materials_file += mats + + materials_file.cross_sections = '2g.h5' + + # # Make Geometry + rad_outer = 929.45 + # Set a cell boundary to exist for every material above (exclude the 0) + rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] + + # Instantiate Universe + root = openmc.Universe(universe_id=0, name='root universe') + cells = [] + + surfs = [] + surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) + for r, rad in enumerate(rads): + if r == len(rads) - 1: + surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) + else: + surfs.append(openmc.XPlane(x0=rad)) + + # Instantiate Cells + cells = [] + for c in range(len(surfs) - 1): + cells.append(openmc.Cell()) + cells[-1].region = (+surfs[c] & -surfs[c + 1]) + cells[-1].fill = mats[c] + + # Register Cells with Universe + root.add_cells(cells) + + # Instantiate a Geometry, register the root Universe, and export to XML + geometry_file = openmc.Geometry(root) + + # # Make Settings + # Instantiate a Settings object, set all runtime parameters + settings_file = openmc.Settings() + settings_file.energy_mode = "multi-group" + settings_file.tabular_legendre = {'enable': False} + settings_file.batches = 10 + settings_file.inactive = 5 + settings_file.particles = 1000 + + # Build source distribution + INF = 1000. + bounds = [0., -INF, -INF, rads[0], INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + settings_file.source = openmc.source.Source(space=uniform_dist) + + settings_file.output = {'summary': False} + + model = openmc.model.Model() + model.geometry = geometry_file + model.materials = materials_file + model.settings = settings_file + + return model + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g .h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_benchmark(): + model = create_model() + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/mg_benchmark_delayed/__init__.py b/tests/regression_tests/mg_benchmark_delayed/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_benchmark_delayed/test.py new file mode 100644 index 000000000..f9f04110e --- /dev/null +++ b/tests/regression_tests/mg_benchmark_delayed/test.py @@ -0,0 +1,175 @@ +import os + +import numpy as np + +import openmc + +from tests.testing_harness import PyAPITestHarness + + +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + n_dg = 2 + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + mg_cross_sections_file.num_delayed_groups = n_dg + + beta = np.array([0.003, 0.003]) + one_m_beta = 1. - np.sum(beta) + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + # Make the base data that uses chi & nu-fission vectors with a beta + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.num_delayed_groups = 2 + mat_1.set_beta(beta) + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Make a version that uses prompt and delayed version of nufiss and chi + mat_2 = openmc.XSdata('mat_2', groups) + mat_2.order = 1 + mat_2.num_delayed_groups = 2 + mat_2.set_prompt_nu_fission(one_m_beta * np.multiply(nu, fiss)) + delay_nu_fiss = np.zeros((n_dg, groups.num_groups)) + for dg in range(n_dg): + for g in range(groups.num_groups): + delay_nu_fiss[dg, g] = beta[dg] * nu[g] * fiss[g] + mat_2.set_delayed_nu_fission(delay_nu_fiss) + mat_2.set_absorption(absorption) + mat_2.set_scatter_matrix(scatter) + mat_2.set_total(total) + mat_2.set_chi_prompt(chi) + mat_2.set_chi_delayed(np.stack([chi] * n_dg)) + mg_cross_sections_file.add_xsdata(mat_2) + + # Make a version that uses a nu-fission matrix with a beta + mat_3 = openmc.XSdata('mat_3', groups) + mat_3.order = 1 + mat_3.num_delayed_groups = 2 + mat_3.set_beta(beta) + mat_3.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_3.set_absorption(absorption) + mat_3.set_scatter_matrix(scatter) + mat_3.set_total(total) + mg_cross_sections_file.add_xsdata(mat_3) + + # Make a version that uses prompt and delayed version of the nufiss matrix + mat_4 = openmc.XSdata('mat_4', groups) + mat_4.order = 1 + mat_4.num_delayed_groups = 2 + mat_4.set_prompt_nu_fission(one_m_beta * np.outer(np.multiply(nu, fiss), chi)) + delay_nu_fiss = np.zeros((n_dg, groups.num_groups, groups.num_groups)) + for dg in range(n_dg): + for g in range(groups.num_groups): + for go in range(groups.num_groups): + delay_nu_fiss[dg, g, go] = beta[dg] * nu[g] * fiss[g] * chi[go] + mat_4.set_delayed_nu_fission(delay_nu_fiss) + mat_4.set_absorption(absorption) + mat_4.set_scatter_matrix(scatter) + mat_4.set_total(total) + mg_cross_sections_file.add_xsdata(mat_4) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +def create_model(): + create_library() + + # # Make Materials + materials_file = openmc.Materials() + + mat_names = ['vec beta', 'vec no beta', 'matrix beta', 'matrix no beta'] + macros = [] + mats = [] + for i in range(len(mat_names)): + macros.append(openmc.Macroscopic('mat_' + str(i + 1))) + mats.append(openmc.Material(name=mat_names[i])) + mats[-1].set_density('macro', 1.0) + mats[-1].add_macroscopic(macros[-1]) + + materials_file += mats + + materials_file.cross_sections = '2g.h5' + + # # Make Geometry + rad_outer = 929.45 + # Set a cell boundary to exist for every material above (exclude the 0) + rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] + + # Instantiate Universe + root = openmc.Universe(universe_id=0, name='root universe') + cells = [] + + surfs = [] + surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) + for r, rad in enumerate(rads): + if r == len(rads) - 1: + surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) + else: + surfs.append(openmc.XPlane(x0=rad)) + + # Instantiate Cells + cells = [] + for c in range(len(surfs) - 1): + cells.append(openmc.Cell()) + cells[-1].region = (+surfs[c] & -surfs[c + 1]) + cells[-1].fill = mats[c] + + # Register Cells with Universe + root.add_cells(cells) + + # Instantiate a Geometry, register the root Universe, and export to XML + geometry_file = openmc.Geometry(root) + + # # Make Settings + # Instantiate a Settings object, set all runtime parameters + settings_file = openmc.Settings() + settings_file.energy_mode = "multi-group" + settings_file.tabular_legendre = {'enable': False} + settings_file.batches = 10 + settings_file.inactive = 5 + settings_file.particles = 1000 + + # Build source distribution + INF = 1000. + bounds = [0., -INF, -INF, rads[0], INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + settings_file.source = openmc.source.Source(space=uniform_dist) + + settings_file.output = {'summary': False} + + model = openmc.model.Model() + model.geometry = geometry_file + model.materials = materials_file + model.settings = settings_file + + return model + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g .h5' + if os.path.exists(f): + os.remove(f) + + +def test_mg_benchmark(): + model = create_model() + harness = PyAPITestHarness('statepoint.10.h5', model) + harness.main() From c7fa8c05ce017b2c0fec75d7e9dee2f668a5f79b Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sun, 2 Sep 2018 21:10:01 -0400 Subject: [PATCH 04/12] Added delayed test and made code changes so that we pass the tests --- src/mgxs.cpp | 18 +-- src/xsdata.cpp | 146 +++++++----------- .../mg_benchmark/inputs_true.dat | 37 ++++- .../mg_benchmark/results_true.dat | 2 +- tests/regression_tests/mg_benchmark/test.py | 2 +- .../mg_benchmark_delayed/inputs_true.dat | 51 ++++++ .../mg_benchmark_delayed/results_true.dat | 2 + .../mg_benchmark_delayed/test.py | 2 +- 8 files changed, 154 insertions(+), 106 deletions(-) create mode 100644 tests/regression_tests/mg_benchmark_delayed/inputs_true.dat create mode 100644 tests/regression_tests/mg_benchmark_delayed/results_true.dat diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 93b7d43b7..b9e22780a 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -463,11 +463,11 @@ Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) case MG_GET_XS_DELAYED_NU_FISSION: if (fissionable) { if (dg != nullptr) { - val = xs_t->delayed_nu_fission(a, gin, *dg); + val = xs_t->delayed_nu_fission(a, *dg, gin); } else { val = 0.; for (int d = 0; d < xs_t->delayed_nu_fission.shape()[2]; d++) { - val += xs_t->delayed_nu_fission(a, gin, d); + val += xs_t->delayed_nu_fission(a, d, gin); } } } else { @@ -493,21 +493,21 @@ Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) if (fissionable) { if (gout != nullptr) { if (dg != nullptr) { - val = xs_t->chi_delayed(a, gin, *gout, *dg); + val = xs_t->chi_delayed(a, *dg, gin, *gout); } else { - val = xs_t->chi_delayed(a, gin, *gout, 0); + val = xs_t->chi_delayed(a, 0, gin, *gout); } } else { if (dg != nullptr) { val = 0.; for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { - val += xs_t->delayed_nu_fission(a, gin, g, *dg); + val += xs_t->delayed_nu_fission(a, *dg, gin, g); } } else { val = 0.; for (int g = 0; g < xs_t->delayed_nu_fission.shape()[2]; g++) { for (int d = 0; d < xs_t->delayed_nu_fission.shape()[3]; d++) { - val += xs_t->delayed_nu_fission(a, gin, g, d); + val += xs_t->delayed_nu_fission(a, d, gin, g); } } } @@ -578,7 +578,7 @@ Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) while (xi_pd >= prob_prompt) { dg++; prob_prompt += - xs_t->delayed_nu_fission(cache[tid].a, gin, dg); + xs_t->delayed_nu_fission(cache[tid].a, dg, gin); } // adjust dg in case of round-off error @@ -587,11 +587,11 @@ Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; double prob_gout = - xs_t->chi_delayed(cache[tid].a, gin, gout, dg); + xs_t->chi_delayed(cache[tid].a, dg, gin, gout); while (prob_gout < xi_gout) { gout++; prob_gout += - xs_t->chi_delayed(cache[tid].a, gin, gout, dg); + xs_t->chi_delayed(cache[tid].a, dg, gin, gout); } } } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 18e474987..fd849b1c7 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -32,7 +32,7 @@ XsData::XsData(size_t energy_groups, size_t num_delayed_groups, bool fissionable scatter_format != ANGLE_LEGENDRE) { fatal_error("Invalid scatter_format!"); } - // allocate all [temperature][phi][theta][in group] quantities + // allocate all [temperature][angle][in group] quantities std::vector shape = {n_ang, energy_groups}; total = xt::zeros(shape); absorption = xt::zeros(shape); @@ -44,21 +44,21 @@ XsData::XsData(size_t energy_groups, size_t num_delayed_groups, bool fissionable kappa_fission = xt::zeros(shape); } - // allocate decay_rate; [temperature][phi][theta][delayed group] + // allocate decay_rate; [temperature][angle][delayed group] shape[1] = num_delayed_groups; decay_rate = xt::zeros(shape); if (fissionable) { - shape = {n_ang, energy_groups, num_delayed_groups}; - // allocate delayed_nu_fission; [temperature][phi][theta][in group][delay group] + shape = {n_ang, num_delayed_groups, energy_groups}; + // allocate delayed_nu_fission; [temperature][angle][delay group][in group] delayed_nu_fission = xt::zeros(shape); - // chi_prompt; [temperature][phi][theta][in group][out group] + // chi_prompt; [temperature][angle][in group][out group] shape = {n_ang, energy_groups, energy_groups}; chi_prompt = xt::zeros(shape); - // chi_delayed; [temperature][phi][theta][in group][out group][delay group] - shape = {n_ang, energy_groups, energy_groups, num_delayed_groups}; + // chi_delayed; [temperature][angle][delay group][in group][out group] + shape = {n_ang, num_delayed_groups, energy_groups, energy_groups}; chi_delayed = xt::zeros(shape); } @@ -136,16 +136,9 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Now every incoming group in prompt_chi and delayed_chi is the normalized // chi we just made - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_chi(a, gout); - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_chi(a, gout); - } - } - } - } + chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); + chi_delayed = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::newaxis(), + xt::all()); // Get nu-fission xt::xtensor temp_nufiss({n_ang, energy_groups}, 0.); @@ -159,13 +152,9 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); // Set delayed_nu_fission as beta * nu_fission - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * temp_nufiss(a, gin); - } - } - } + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } void @@ -179,27 +168,21 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); + temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), + xt::newaxis()); // Get chi-delayed - xt::xtensor temp_chi_d({n_ang, energy_groups, delayed_groups}, 0.); + xt::xtensor temp_chi_d({n_ang, delayed_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {1}), xt::all(), - xt::newaxis(), xt::all()); + temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {2}), xt::all(), + xt::all(), xt::newaxis()); // Now assign the prompt and delayed chis by replicating for each incoming group - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_chi_p(a, gout); - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_chi_d(a, gout, dg); - } - } - } - } + chi_prompt = xt::view(temp_chi_p, xt::all(), xt::newaxis(), xt::all()); + chi_delayed = xt::view(temp_chi_d, xt::all(), xt::all(), xt::newaxis(), + xt::all()); // Get prompt and delayed nu-fission directly read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); @@ -246,59 +229,40 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Data is provided as nu-fission and chi with a beta for delayed info // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // Get beta - xt::xtensor temp_beta({n_ang, energy_groups, delayed_groups}, 0.); + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); + xt::xtensor temp_beta_sum({n_ang}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); + // prompt_nu_fission is the sum of this matrix over outgoing groups and - // multiplied by (1 - beta_tot) - prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - xt::sum(temp_beta, {2})); + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); // delayed_nu_fission is the sum of this matrix over outgoing groups and // multiplied by beta - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - double out_sum = 0.; - for (size_t gout = 0; gout < energy_groups; gout++) { - out_sum += temp_matrix(a, gin, gout); - } - for (size_t dg = 0; dg < delayed_groups; dg++) { - delayed_nu_fission(a, gin, dg) = temp_beta(a, dg) * out_sum; - } - } - } + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); // Store chi-prompt - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - double beta = 0.; - for (size_t dg = 0; dg < delayed_groups; dg++) { - beta += temp_beta(a, gin, dg); - } - chi_prompt(a, gin, gout) = (1.0 - beta) * temp_matrix(a, gin, gout); - } - } - } + chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), xt::newaxis()) * temp_matrix; // Store chi-delayed - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - for (size_t dg = 0; dg < delayed_groups; dg++) { - chi_delayed(a, gin, gout, dg) = temp_beta(a, gin, dg) * temp_matrix(a, gin, gout); - } - } - } - } + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); //Normalize both - chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::newaxis()); - chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {2}), xt::all(), - xt::newaxis(), xt::all()); + chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), + xt::all(), xt::newaxis()); + + chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {3}), xt::all(), + xt::all(), xt::all(), xt::newaxis()); } void @@ -308,7 +272,7 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Data is provided separately as prompt + delayed nu-fission and chi // Get the prompt nu-fission matrix - xt::xtensor temp_matrix_p({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_matrix_p({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); // prompt_nu_fission is the sum over outgoing groups @@ -316,19 +280,21 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_prompt = temp_matrix_p / prompt_nu_fission; + chi_prompt = temp_matrix_p / + xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); // Get the delayed nu-fission matrix - xt::xtensor temp_matrix_d({n_ang, energy_groups, energy_groups, - delayed_groups}); + xt::xtensor temp_matrix_d({n_ang, delayed_groups, energy_groups, + energy_groups}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); // delayed_nu_fission is the sum over outgoing groups - delayed_nu_fission = xt::sum(temp_matrix_d, {2}); + delayed_nu_fission = xt::sum(temp_matrix_d, {3}); // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_delayed = temp_matrix_d / delayed_nu_fission; + chi_delayed = temp_matrix_d / + xt::view(delayed_nu_fission, xt::all(), xt::all(), xt::all(), xt::newaxis()); } void @@ -339,7 +305,7 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Therefore, the code only considers the data as prompt. // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}); + xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); if (object_exists(xsdata_grp, "prompt-nu-fission")) { read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix, true); } else { @@ -366,7 +332,8 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, // Get the data; the strategy for doing so depends on if the data is provided // as a nu-fission matrix or a set of chi and nu-fission vectors - if (object_exists(xsdata_grp, "chi")) { + if (object_exists(xsdata_grp, "chi") || + object_exists(xsdata_grp, "chi-prompt")) { if (delayed_groups == 0) { fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang, energy_groups); } else { @@ -393,13 +360,10 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - nu_fission(a, gin) = prompt_nu_fission(a, gin); - for (size_t dg = 0; dg < delayed_groups; dg++) { - nu_fission(a, gin) += delayed_nu_fission(a, gin, dg); - } - } + if (delayed_groups == 0) { + nu_fission = prompt_nu_fission; + } else { + nu_fission = prompt_nu_fission + xt::sum(delayed_nu_fission, {1}); } } diff --git a/tests/regression_tests/mg_benchmark/inputs_true.dat b/tests/regression_tests/mg_benchmark/inputs_true.dat index 8856770dd..4f2fd3f0b 100644 --- a/tests/regression_tests/mg_benchmark/inputs_true.dat +++ b/tests/regression_tests/mg_benchmark/inputs_true.dat @@ -1,16 +1,47 @@ + + + + + - + + + + + + 2g.h5 - + + + + + + + + + + + + + + + + + + + + + + @@ -20,7 +51,7 @@ 5 - -929.45 -1e+50 -1e+50 929.45 1e+50 1e+50 + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 diff --git a/tests/regression_tests/mg_benchmark/results_true.dat b/tests/regression_tests/mg_benchmark/results_true.dat index 33e4d68f7..dede97007 100644 --- a/tests/regression_tests/mg_benchmark/results_true.dat +++ b/tests/regression_tests/mg_benchmark/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.949396E-01 2.047218E-02 +1.005345E+00 1.109180E-02 diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_benchmark/test.py index cc8f5ba34..97cef92ad 100644 --- a/tests/regression_tests/mg_benchmark/test.py +++ b/tests/regression_tests/mg_benchmark/test.py @@ -156,7 +156,7 @@ def create_model(): class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() - f = '2g .h5' + f = '2g.h5' if os.path.exists(f): os.remove(f) diff --git a/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat b/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat new file mode 100644 index 000000000..e62e65ab1 --- /dev/null +++ b/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + 2g.h5 + + + + + + + + + + + + + + + + + + + + eigenvalue + 1000 + 10 + 5 + + + 0.0 -1000.0 -1000.0 232.3625 1000.0 1000.0 + + + + false + + multi-group + + false + + diff --git a/tests/regression_tests/mg_benchmark_delayed/results_true.dat b/tests/regression_tests/mg_benchmark_delayed/results_true.dat new file mode 100644 index 000000000..4b425173d --- /dev/null +++ b/tests/regression_tests/mg_benchmark_delayed/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +9.928704E-01 2.679667E-02 diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_benchmark_delayed/test.py index f9f04110e..72bd34e1b 100644 --- a/tests/regression_tests/mg_benchmark_delayed/test.py +++ b/tests/regression_tests/mg_benchmark_delayed/test.py @@ -164,7 +164,7 @@ def create_model(): class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() - f = '2g .h5' + f = '2g.h5' if os.path.exists(f): os.remove(f) From c1652bbdec5a2aaa2aa9fc7f0c7cd19f2d94b666 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 06:48:02 -0400 Subject: [PATCH 05/12] Replacing old slab_mg example model with new one that uses a library that follows the library standard. Also had to update tests accordingly. --- openmc/examples.py | 163 ++++++++++-------- tests/1d_mgxs.h5 | Bin 134432 -> 0 bytes tests/regression_tests/mg_basic/__init__.py | 0 .../regression_tests/mg_basic/inputs_true.dat | 97 ----------- .../mg_basic/results_true.dat | 2 - tests/regression_tests/mg_basic/test.py | 9 - tests/regression_tests/mg_benchmark/test.py | 92 ++-------- .../mg_benchmark_delayed/test.py | 83 +-------- tests/regression_tests/mg_convert/test.py | 2 +- .../mg_legendre/inputs_true.dat | 33 ++-- .../mg_legendre/results_true.dat | 2 +- tests/regression_tests/mg_legendre/test.py | 46 ++++- .../mg_max_order/inputs_true.dat | 36 ++-- .../mg_max_order/results_true.dat | 2 +- tests/regression_tests/mg_max_order/test.py | 47 ++++- tests/regression_tests/mg_nuclide/__init__.py | 0 .../mg_nuclide/inputs_true.dat | 97 ----------- .../mg_nuclide/results_true.dat | 2 - tests/regression_tests/mg_nuclide/test.py | 9 - .../mg_survival_biasing/inputs_true.dat | 90 ++-------- .../mg_survival_biasing/results_true.dat | 2 +- .../mg_survival_biasing/test.py | 45 +++++ .../mg_tallies/inputs_true.dat | 122 ++++--------- .../mg_tallies/results_true.dat | 2 +- tests/regression_tests/mg_tallies/test.py | 51 +++++- 25 files changed, 359 insertions(+), 675 deletions(-) delete mode 100644 tests/1d_mgxs.h5 delete mode 100644 tests/regression_tests/mg_basic/__init__.py delete mode 100644 tests/regression_tests/mg_basic/inputs_true.dat delete mode 100644 tests/regression_tests/mg_basic/results_true.dat delete mode 100644 tests/regression_tests/mg_basic/test.py delete mode 100644 tests/regression_tests/mg_nuclide/__init__.py delete mode 100644 tests/regression_tests/mg_nuclide/inputs_true.dat delete mode 100644 tests/regression_tests/mg_nuclide/results_true.dat delete mode 100644 tests/regression_tests/mg_nuclide/test.py diff --git a/openmc/examples.py b/openmc/examples.py index d48d26839..a5138377e 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -1,3 +1,5 @@ +from numbers import Integral + import numpy as np import openmc @@ -538,20 +540,20 @@ def pwr_assembly(): return model -def slab_mg(reps=None, as_macro=True): - """Create a one-group, 1D slab model. +def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5'): + """Create a 1D slab model. Parameters ---------- - reps : list, optional - List of angular representations. Each item corresponds to materials and - dictates the angular representation of the multi-group cross - sections---isotropic ('iso') or angle-dependent ('ang'), and if Legendre - scattering or tabular scattering ('mu') is used. Thus, items can be - 'ang', 'ang_mu', 'iso', or 'iso_mu'. + num_regions : int, optional + Number of regions in the problem, each with a unique MGXS dataset. + Defaults to 1. - as_macro : bool, optional - Whether :class:`openmc.Macroscopic` is used + mat_names : Iterable of str, optional + List of the material names to use; defaults to ['mat_1', 'mat_2',...]. + + mgxslib_name : str, optional + MGXS Library file to use; defaults to '2g.h5'. Returns ------- @@ -559,71 +561,82 @@ def slab_mg(reps=None, as_macro=True): One-group, 1D slab model """ + + openmc.check_type('num_regions', num_regions, Integral) + openmc.check_greater_than('num_regions', num_regions, 0) + if mat_names is not None: + openmc.check_length('mat_names', mat_names, num_regions) + openmc.check_iterable_type('mat_names', mat_names, str) + else: + mat_names = [] + for i in range(num_regions): + mat_names.append('mat_' + str(i + 1)) + + # # Make Materials + materials_file = openmc.Materials() + macros = [] + mats = [] + for i in range(len(mat_names)): + macros.append(openmc.Macroscopic('mat_' + str(i + 1))) + mats.append(openmc.Material(name=mat_names[i])) + mats[-1].set_density('macro', 1.0) + mats[-1].add_macroscopic(macros[-1]) + + materials_file += mats + + materials_file.cross_sections = mgxslib_name + + # # Make Geometry + rad_outer = 929.45 + # Set a cell boundary to exist for every material above (exclude the 0) + rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] + + # Instantiate Universe + root = openmc.Universe(universe_id=0, name='root universe') + cells = [] + + surfs = [] + surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) + for r, rad in enumerate(rads): + if r == len(rads) - 1: + surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) + else: + surfs.append(openmc.XPlane(x0=rad)) + + # Instantiate Cells + cells = [] + for c in range(len(surfs) - 1): + cells.append(openmc.Cell()) + cells[-1].region = (+surfs[c] & -surfs[c + 1]) + cells[-1].fill = mats[c] + + # Register Cells with Universe + root.add_cells(cells) + + # Instantiate a Geometry, register the root Universe, and export to XML + geometry_file = openmc.Geometry(root) + + # # Make Settings + # Instantiate a Settings object, set all runtime parameters + settings_file = openmc.Settings() + settings_file.energy_mode = "multi-group" + settings_file.tabular_legendre = {'enable': False} + settings_file.batches = 10 + settings_file.inactive = 5 + settings_file.particles = 1000 + + # Build source distribution + INF = 1000. + bounds = [0., -INF, -INF, rads[0], INF, INF] + uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) + settings_file.source = openmc.source.Source(space=uniform_dist) + + settings_file.output = {'summary': False} + model = openmc.model.Model() - - # Define materials needed for 1D/1G slab problem - mat_names = ['uo2', 'clad', 'lwtr'] - mgxs_reps = ['ang', 'ang_mu', 'iso', 'iso_mu'] - - if reps is None: - reps = mgxs_reps - - xs = [] - i = 0 - for mat in mat_names: - for rep in reps: - i += 1 - name = mat + '_' + rep - xs.append(name) - if as_macro: - m = openmc.Material(name=str(i)) - m.set_density('macro', 1.) - m.add_macroscopic(name) - else: - m = openmc.Material(name=str(i)) - m.set_density('atom/b-cm', 1.) - m.add_nuclide(name, 1.0, 'ao') - model.materials.append(m) - - # Define the materials file - model.xs_data = xs - model.materials.cross_sections = "../../1d_mgxs.h5" - - # Define surfaces. - # Assembly/Problem Boundary - left = openmc.XPlane(x0=0.0, boundary_type='reflective') - right = openmc.XPlane(x0=10.0, boundary_type='reflective') - bottom = openmc.YPlane(y0=0.0, boundary_type='reflective') - top = openmc.YPlane(y0=10.0, boundary_type='reflective') - - # for each material add a plane - planes = [openmc.ZPlane(z0=0.0, boundary_type='reflective')] - dz = round(5. / float(len(model.materials)), 4) - for i in range(len(model.materials) - 1): - planes.append(openmc.ZPlane(z0=dz * float(i + 1))) - planes.append(openmc.ZPlane(z0=5.0, boundary_type='reflective')) - - # Define cells for each material - model.geometry.root_universe = openmc.Universe(name='root universe') - xy = +left & -right & +bottom & -top - for i, mat in enumerate(model.materials): - c = openmc.Cell(fill=mat, region=xy & +planes[i] & -planes[i + 1]) - model.geometry.root_universe.add_cell(c) - - model.settings.batches = 10 - model.settings.inactive = 5 - model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( - [0.0, 0.0, 0.0], [10.0, 10.0, 5.])) - model.settings.energy_mode = "multi-group" - - plot = openmc.Plot() - plot.filename = 'mat' - plot.origin = (5.0, 5.0, 2.5) - plot.width = (2.5, 2.5) - plot.basis = 'xz' - plot.pixels = (3000, 3000) - plot.color_by = 'material' - model.plots.append(plot) + model.geometry = geometry_file + model.materials = materials_file + model.settings = settings_file + model.xs_data = macros return model diff --git a/tests/1d_mgxs.h5 b/tests/1d_mgxs.h5 deleted file mode 100644 index 0f747345a8da7c1cee71928d337a5c590dcc0e78..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134432 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ../../1d_mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - 0.0 0.0 0.0 10.0 10.0 5.0 - - - multi-group - diff --git a/tests/regression_tests/mg_basic/results_true.dat b/tests/regression_tests/mg_basic/results_true.dat deleted file mode 100644 index ddb57d00b..000000000 --- a/tests/regression_tests/mg_basic/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.073147E+00 1.602384E-02 diff --git a/tests/regression_tests/mg_basic/test.py b/tests/regression_tests/mg_basic/test.py deleted file mode 100644 index 3c22e6040..000000000 --- a/tests/regression_tests/mg_basic/test.py +++ /dev/null @@ -1,9 +0,0 @@ -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def test_mg_basic(): - model = slab_mg() - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_benchmark/test.py index 97cef92ad..c29c7ca1f 100644 --- a/tests/regression_tests/mg_benchmark/test.py +++ b/tests/regression_tests/mg_benchmark/test.py @@ -3,6 +3,7 @@ import os import numpy as np import openmc +from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness @@ -73,86 +74,6 @@ def create_library(): mg_cross_sections_file.export_to_hdf5('2g.h5') -def create_model(): - create_library() - - # # Make Materials - materials_file = openmc.Materials() - - mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', 'base ang'] - macros = [] - mats = [] - for i in range(len(mat_names)): - macros.append(openmc.Macroscopic('mat_' + str(i + 1))) - mats.append(openmc.Material(name=mat_names[i])) - mats[-1].set_density('macro', 1.0) - mats[-1].add_macroscopic(macros[-1]) - - # Add in the microscopic data - mats.append(openmc.Material(name='micro')) - mats[-1].set_density("sum") - mats[-1].add_nuclide("mat_1", 0.5) - mats[-1].add_nuclide("mat_6", 0.5) - - materials_file += mats - - materials_file.cross_sections = '2g.h5' - - # # Make Geometry - rad_outer = 929.45 - # Set a cell boundary to exist for every material above (exclude the 0) - rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] - - # Instantiate Universe - root = openmc.Universe(universe_id=0, name='root universe') - cells = [] - - surfs = [] - surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) - for r, rad in enumerate(rads): - if r == len(rads) - 1: - surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) - else: - surfs.append(openmc.XPlane(x0=rad)) - - # Instantiate Cells - cells = [] - for c in range(len(surfs) - 1): - cells.append(openmc.Cell()) - cells[-1].region = (+surfs[c] & -surfs[c + 1]) - cells[-1].fill = mats[c] - - # Register Cells with Universe - root.add_cells(cells) - - # Instantiate a Geometry, register the root Universe, and export to XML - geometry_file = openmc.Geometry(root) - - # # Make Settings - # Instantiate a Settings object, set all runtime parameters - settings_file = openmc.Settings() - settings_file.energy_mode = "multi-group" - settings_file.tabular_legendre = {'enable': False} - settings_file.batches = 10 - settings_file.inactive = 5 - settings_file.particles = 1000 - - # Build source distribution - INF = 1000. - bounds = [0., -INF, -INF, rads[0], INF, INF] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.source.Source(space=uniform_dist) - - settings_file.output = {'summary': False} - - model = openmc.model.Model() - model.geometry = geometry_file - model.materials = materials_file - model.settings = settings_file - - return model - - class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() @@ -162,6 +83,15 @@ class MGXSTestHarness(PyAPITestHarness): def test_mg_benchmark(): - model = create_model() + create_library() + mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', + 'base ang', 'micro'] + model = slab_mg(num_regions=6, mat_names=mat_names) + # Modify the last material to be a microscopic combination of nuclides + model.materials[-1] = openmc.Material(name='micro', material_id=6) + model.materials[-1].set_density("sum") + model.materials[-1].add_nuclide("mat_1", 0.5) + model.materials[-1].add_nuclide("mat_6", 0.5) + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_benchmark_delayed/test.py index 72bd34e1b..6c527bbe3 100644 --- a/tests/regression_tests/mg_benchmark_delayed/test.py +++ b/tests/regression_tests/mg_benchmark_delayed/test.py @@ -3,6 +3,7 @@ import os import numpy as np import openmc +from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness @@ -71,7 +72,8 @@ def create_library(): mat_4 = openmc.XSdata('mat_4', groups) mat_4.order = 1 mat_4.num_delayed_groups = 2 - mat_4.set_prompt_nu_fission(one_m_beta * np.outer(np.multiply(nu, fiss), chi)) + mat_4.set_prompt_nu_fission(one_m_beta * + np.outer(np.multiply(nu, fiss), chi)) delay_nu_fiss = np.zeros((n_dg, groups.num_groups, groups.num_groups)) for dg in range(n_dg): for g in range(groups.num_groups): @@ -87,80 +89,6 @@ def create_library(): mg_cross_sections_file.export_to_hdf5('2g.h5') -def create_model(): - create_library() - - # # Make Materials - materials_file = openmc.Materials() - - mat_names = ['vec beta', 'vec no beta', 'matrix beta', 'matrix no beta'] - macros = [] - mats = [] - for i in range(len(mat_names)): - macros.append(openmc.Macroscopic('mat_' + str(i + 1))) - mats.append(openmc.Material(name=mat_names[i])) - mats[-1].set_density('macro', 1.0) - mats[-1].add_macroscopic(macros[-1]) - - materials_file += mats - - materials_file.cross_sections = '2g.h5' - - # # Make Geometry - rad_outer = 929.45 - # Set a cell boundary to exist for every material above (exclude the 0) - rads = np.linspace(0., rad_outer, len(mats) + 1, endpoint=True)[1:] - - # Instantiate Universe - root = openmc.Universe(universe_id=0, name='root universe') - cells = [] - - surfs = [] - surfs.append(openmc.XPlane(x0=0., boundary_type='reflective')) - for r, rad in enumerate(rads): - if r == len(rads) - 1: - surfs.append(openmc.XPlane(x0=rad, boundary_type='vacuum')) - else: - surfs.append(openmc.XPlane(x0=rad)) - - # Instantiate Cells - cells = [] - for c in range(len(surfs) - 1): - cells.append(openmc.Cell()) - cells[-1].region = (+surfs[c] & -surfs[c + 1]) - cells[-1].fill = mats[c] - - # Register Cells with Universe - root.add_cells(cells) - - # Instantiate a Geometry, register the root Universe, and export to XML - geometry_file = openmc.Geometry(root) - - # # Make Settings - # Instantiate a Settings object, set all runtime parameters - settings_file = openmc.Settings() - settings_file.energy_mode = "multi-group" - settings_file.tabular_legendre = {'enable': False} - settings_file.batches = 10 - settings_file.inactive = 5 - settings_file.particles = 1000 - - # Build source distribution - INF = 1000. - bounds = [0., -INF, -INF, rads[0], INF, INF] - uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.source.Source(space=uniform_dist) - - settings_file.output = {'summary': False} - - model = openmc.model.Model() - model.geometry = geometry_file - model.materials = materials_file - model.settings = settings_file - - return model - - class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() @@ -170,6 +98,9 @@ class MGXSTestHarness(PyAPITestHarness): def test_mg_benchmark(): - model = create_model() + create_library() + model = slab_mg(num_regions=4, mat_names=['vec beta', 'vec no beta', + 'matrix beta', 'matrix no beta']) + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_convert/test.py b/tests/regression_tests/mg_convert/test.py index 1ace10c80..4cc6b656a 100755 --- a/tests/regression_tests/mg_convert/test.py +++ b/tests/regression_tests/mg_convert/test.py @@ -17,7 +17,7 @@ def build_mgxs_library(convert): # Instantiate the energy group data groups = openmc.mgxs.EnergyGroups(group_edges=[1e-5, 0.625, 20.0e6]) - # Instantiate the 7-group (C5G7) cross section data + # Instantiate the 2-group (C5G7) cross section data uo2_xsdata = openmc.XSdata('UO2', groups) uo2_xsdata.order = 2 uo2_xsdata.set_total([2., 2.]) diff --git a/tests/regression_tests/mg_legendre/inputs_true.dat b/tests/regression_tests/mg_legendre/inputs_true.dat index 754808095..ad3b434e6 100644 --- a/tests/regression_tests/mg_legendre/inputs_true.dat +++ b/tests/regression_tests/mg_legendre/inputs_true.dat @@ -1,44 +1,31 @@ - - - + - - - - - - - + - ../../1d_mgxs.h5 - + 2g.h5 + - - - - - - - - - + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group false diff --git a/tests/regression_tests/mg_legendre/results_true.dat b/tests/regression_tests/mg_legendre/results_true.dat index d0f8c319e..4a9d98237 100644 --- a/tests/regression_tests/mg_legendre/results_true.dat +++ b/tests/regression_tests/mg_legendre/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.110122E+00 2.549637E-02 +9.934975E-01 2.679669E-02 diff --git a/tests/regression_tests/mg_legendre/test.py b/tests/regression_tests/mg_legendre/test.py index 5a57f758e..b5a05c706 100644 --- a/tests/regression_tests/mg_legendre/test.py +++ b/tests/regression_tests/mg_legendre/test.py @@ -1,10 +1,54 @@ +import os + +import numpy as np + +import openmc from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_legendre(): - model = slab_mg(reps=['iso']) + create_library() + model = slab_mg() model.settings.tabular_legendre = {'enable': False} harness = PyAPITestHarness('statepoint.10.h5', model) diff --git a/tests/regression_tests/mg_max_order/inputs_true.dat b/tests/regression_tests/mg_max_order/inputs_true.dat index 023d468d4..2ac83852c 100644 --- a/tests/regression_tests/mg_max_order/inputs_true.dat +++ b/tests/regression_tests/mg_max_order/inputs_true.dat @@ -1,44 +1,34 @@ - - - + - - - - - - - + - ../../1d_mgxs.h5 - + 2g.h5 + - - - - - - - - - + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group 1 + + false + diff --git a/tests/regression_tests/mg_max_order/results_true.dat b/tests/regression_tests/mg_max_order/results_true.dat index adfcd44a8..4a9d98237 100644 --- a/tests/regression_tests/mg_max_order/results_true.dat +++ b/tests/regression_tests/mg_max_order/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.074551E+00 1.871525E-02 +9.934975E-01 2.679669E-02 diff --git a/tests/regression_tests/mg_max_order/test.py b/tests/regression_tests/mg_max_order/test.py index 20cc4f805..97d3f57d7 100644 --- a/tests/regression_tests/mg_max_order/test.py +++ b/tests/regression_tests/mg_max_order/test.py @@ -1,10 +1,55 @@ +import os + +import numpy as np + +import openmc from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694, 0.003], [0.004555, -0.0003972, 0.00002]], + [[0.00000, 0.00000, 0.000], [0.424100, 0.05439000, 0.0025]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 2 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_max_order(): - model = slab_mg(reps=['iso']) + create_library() + model = slab_mg() model.settings.max_order = 1 + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_nuclide/__init__.py b/tests/regression_tests/mg_nuclide/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tests/regression_tests/mg_nuclide/inputs_true.dat b/tests/regression_tests/mg_nuclide/inputs_true.dat deleted file mode 100644 index e11b9e3f0..000000000 --- a/tests/regression_tests/mg_nuclide/inputs_true.dat +++ /dev/null @@ -1,97 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ../../1d_mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - eigenvalue - 100 - 10 - 5 - - - 0.0 0.0 0.0 10.0 10.0 5.0 - - - multi-group - diff --git a/tests/regression_tests/mg_nuclide/results_true.dat b/tests/regression_tests/mg_nuclide/results_true.dat deleted file mode 100644 index ddb57d00b..000000000 --- a/tests/regression_tests/mg_nuclide/results_true.dat +++ /dev/null @@ -1,2 +0,0 @@ -k-combined: -1.073147E+00 1.602384E-02 diff --git a/tests/regression_tests/mg_nuclide/test.py b/tests/regression_tests/mg_nuclide/test.py deleted file mode 100644 index 44206ef28..000000000 --- a/tests/regression_tests/mg_nuclide/test.py +++ /dev/null @@ -1,9 +0,0 @@ -from openmc.examples import slab_mg - -from tests.testing_harness import PyAPITestHarness - - -def test_mg_nuclide(): - model = slab_mg(as_macro=False) - harness = PyAPITestHarness('statepoint.10.h5', model) - harness.main() diff --git a/tests/regression_tests/mg_survival_biasing/inputs_true.dat b/tests/regression_tests/mg_survival_biasing/inputs_true.dat index 4bc79d48e..5ece3ce9f 100644 --- a/tests/regression_tests/mg_survival_biasing/inputs_true.dat +++ b/tests/regression_tests/mg_survival_biasing/inputs_true.dat @@ -1,98 +1,34 @@ - - - - - - - - - - - - + - - - - - - - - - - - - - - - - + - ../../1d_mgxs.h5 - + 2g.h5 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group true + + false + diff --git a/tests/regression_tests/mg_survival_biasing/results_true.dat b/tests/regression_tests/mg_survival_biasing/results_true.dat index b20d63288..ebe98679f 100644 --- a/tests/regression_tests/mg_survival_biasing/results_true.dat +++ b/tests/regression_tests/mg_survival_biasing/results_true.dat @@ -1,2 +1,2 @@ k-combined: -1.080832E+00 1.336780E-02 +9.979905E-01 6.207495E-03 diff --git a/tests/regression_tests/mg_survival_biasing/test.py b/tests/regression_tests/mg_survival_biasing/test.py index 3c6c77a37..5d75611a9 100644 --- a/tests/regression_tests/mg_survival_biasing/test.py +++ b/tests/regression_tests/mg_survival_biasing/test.py @@ -1,10 +1,55 @@ +import os + +import numpy as np + +import openmc from openmc.examples import slab_mg from tests.testing_harness import PyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(PyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_survival_biasing(): + create_library() model = slab_mg() model.settings.survival_biasing = True + harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mg_tallies/inputs_true.dat b/tests/regression_tests/mg_tallies/inputs_true.dat index 7b5067014..a9b821c56 100644 --- a/tests/regression_tests/mg_tallies/inputs_true.dat +++ b/tests/regression_tests/mg_tallies/inputs_true.dat @@ -1,112 +1,48 @@ - - - - - - - - - - - - + - - - - - - - - - - - - - - - - + - ../../1d_mgxs.h5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + 2g.h5 + + + eigenvalue - 100 + 1000 10 5 - 0.0 0.0 0.0 10.0 10.0 5.0 + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 + + false + multi-group + + false + - 1 1 10 + 10 1 1 0.0 0.0 0.0 - 10 10 5 + 929.45 1000 1000 1 - 1 2 3 4 5 6 7 8 9 10 11 12 + 1 0.0 20000000.0 @@ -115,10 +51,10 @@ 0.0 20000000.0 - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + 0.0 0.625 20000000.0 - 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + 0.0 0.625 20000000.0 5 @@ -170,60 +106,60 @@ 5 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission analog 5 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission tracklength 6 1 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission scatter nu-scatter analog 6 1 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission collision 6 1 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission tracklength 6 1 2 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 scatter nu-scatter nu-fission 6 3 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission scatter nu-scatter analog 6 3 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission collision 6 3 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 total absorption fission nu-fission tracklength 6 3 4 - uo2_ang uo2_ang_mu uo2_iso uo2_iso_mu clad_ang clad_ang_mu clad_iso clad_iso_mu lwtr_ang lwtr_ang_mu lwtr_iso lwtr_iso_mu + mat_1 scatter nu-scatter nu-fission diff --git a/tests/regression_tests/mg_tallies/results_true.dat b/tests/regression_tests/mg_tallies/results_true.dat index 87470bdf4..78a5883fe 100644 --- a/tests/regression_tests/mg_tallies/results_true.dat +++ b/tests/regression_tests/mg_tallies/results_true.dat @@ -1 +1 @@ -9183f8b191f2e62334f992acd865d29e3f4e3f871a6df498e280fc4e2d91f2d2d20c732fbd75fa88e2e8c576f86e744f7655af6bb9da66e9b28b1009c8742899 \ No newline at end of file +41ea1f6b17c58a8141921af2f1d044eda93f3a9bca9463ee023af2e9865da613ace90fc8a25b42edde128ed827182ea9df0fe09d9b7887282d0ec092692cf717 \ No newline at end of file diff --git a/tests/regression_tests/mg_tallies/test.py b/tests/regression_tests/mg_tallies/test.py index 8952cc4ad..26d53c230 100644 --- a/tests/regression_tests/mg_tallies/test.py +++ b/tests/regression_tests/mg_tallies/test.py @@ -1,23 +1,66 @@ +import os + +import numpy as np + import openmc from openmc.examples import slab_mg from tests.testing_harness import HashedPyAPITestHarness +def create_library(): + # Instantiate the energy group data and file object + groups = openmc.mgxs.EnergyGroups(group_edges=[0.0, 0.625, 20.0e6]) + + mg_cross_sections_file = openmc.MGXSLibrary(groups) + + # Make the base, isotropic data + nu = [2.50, 2.50] + fiss = np.array([0.002817, 0.097]) + capture = [0.008708, 0.02518] + absorption = np.add(capture, fiss) + scatter = np.array( + [[[0.31980, 0.06694], [0.004555, -0.0003972]], + [[0.00000, 0.00000], [0.424100, 0.05439000]]]) + total = [0.33588, 0.54628] + chi = [1., 0.] + + mat_1 = openmc.XSdata('mat_1', groups) + mat_1.order = 1 + mat_1.set_nu_fission(np.multiply(nu, fiss)) + mat_1.set_absorption(absorption) + mat_1.set_scatter_matrix(scatter) + mat_1.set_total(total) + mat_1.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_1) + + # Write the file + mg_cross_sections_file.export_to_hdf5('2g.h5') + + +class MGXSTestHarness(HashedPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = '2g.h5' + if os.path.exists(f): + os.remove(f) + + def test_mg_tallies(): - model = slab_mg(as_macro=False) + create_library() + model = slab_mg() # Instantiate a tally mesh mesh = openmc.Mesh(mesh_id=1) mesh.type = 'regular' - mesh.dimension = [1, 1, 10] + mesh.dimension = [10, 1, 1] mesh.lower_left = [0.0, 0.0, 0.0] - mesh.upper_right = [10, 10, 5] + mesh.upper_right = [929.45, 1000, 1000] # Instantiate some tally filters energy_filter = openmc.EnergyFilter([0.0, 20.0e6]) energyout_filter = openmc.EnergyoutFilter([0.0, 20.0e6]) - energies = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] + energies = [0.0, 0.625, 20.0e6] matching_energy_filter = openmc.EnergyFilter(energies) matching_eout_filter = openmc.EnergyoutFilter(energies) mesh_filter = openmc.MeshFilter(mesh) From 5566fc36b631f883844d2cc0ed077cca6d7dd2bd Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 09:25:21 -0400 Subject: [PATCH 06/12] renaming mg_benchmark* to mg_basic* --- tests/regression_tests/{mg_benchmark => mg_basic}/__init__.py | 0 tests/regression_tests/{mg_benchmark => mg_basic}/inputs_true.dat | 0 .../regression_tests/{mg_benchmark => mg_basic}/results_true.dat | 0 tests/regression_tests/{mg_benchmark => mg_basic}/test.py | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/__init__.py | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/inputs_true.dat | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/results_true.dat | 0 .../{mg_benchmark_delayed => mg_basic_delayed}/test.py | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/regression_tests/{mg_benchmark => mg_basic}/__init__.py (100%) rename tests/regression_tests/{mg_benchmark => mg_basic}/inputs_true.dat (100%) rename tests/regression_tests/{mg_benchmark => mg_basic}/results_true.dat (100%) rename tests/regression_tests/{mg_benchmark => mg_basic}/test.py (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/__init__.py (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/inputs_true.dat (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/results_true.dat (100%) rename tests/regression_tests/{mg_benchmark_delayed => mg_basic_delayed}/test.py (100%) diff --git a/tests/regression_tests/mg_benchmark/__init__.py b/tests/regression_tests/mg_basic/__init__.py similarity index 100% rename from tests/regression_tests/mg_benchmark/__init__.py rename to tests/regression_tests/mg_basic/__init__.py diff --git a/tests/regression_tests/mg_benchmark/inputs_true.dat b/tests/regression_tests/mg_basic/inputs_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark/inputs_true.dat rename to tests/regression_tests/mg_basic/inputs_true.dat diff --git a/tests/regression_tests/mg_benchmark/results_true.dat b/tests/regression_tests/mg_basic/results_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark/results_true.dat rename to tests/regression_tests/mg_basic/results_true.dat diff --git a/tests/regression_tests/mg_benchmark/test.py b/tests/regression_tests/mg_basic/test.py similarity index 100% rename from tests/regression_tests/mg_benchmark/test.py rename to tests/regression_tests/mg_basic/test.py diff --git a/tests/regression_tests/mg_benchmark_delayed/__init__.py b/tests/regression_tests/mg_basic_delayed/__init__.py similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/__init__.py rename to tests/regression_tests/mg_basic_delayed/__init__.py diff --git a/tests/regression_tests/mg_benchmark_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/inputs_true.dat rename to tests/regression_tests/mg_basic_delayed/inputs_true.dat diff --git a/tests/regression_tests/mg_benchmark_delayed/results_true.dat b/tests/regression_tests/mg_basic_delayed/results_true.dat similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/results_true.dat rename to tests/regression_tests/mg_basic_delayed/results_true.dat diff --git a/tests/regression_tests/mg_benchmark_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py similarity index 100% rename from tests/regression_tests/mg_benchmark_delayed/test.py rename to tests/regression_tests/mg_basic_delayed/test.py From 3385c8b0a20e0aa27ca2f138ba98813c08babc69 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 14:15:25 -0400 Subject: [PATCH 07/12] some small potential bug fixes and code cleanup --- src/scattdata.cpp | 10 ++-------- src/xsdata.cpp | 19 +++++-------------- tests/regression_tests/mg_basic/test.py | 2 +- .../regression_tests/mg_basic_delayed/test.py | 2 +- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 0ff7969d1..1069ef6e9 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -109,13 +109,7 @@ ScattData::base_combine(size_t max_order, // Combine mult_numer and mult_denom into the combined multiplicity matrix xt::xtensor this_mult({groups, groups}, 1.); - for (int gin = 0; gin < groups; gin++) { - for (int gout = 0; gout < groups; gout++) { - if (mult_denom(gin, gout) > 0.) { - this_mult(gin, gout) = mult_numer(gin, gout) / mult_denom(gin, gout); - } - } - } + this_mult = xt::nan_to_num(mult_numer / mult_denom); // We have the data, now we need to convert to a jagged array and then use // the initialize function to store it on the object. @@ -531,7 +525,7 @@ ScattDataHistogram::calc_f(int gin, int gout, double mu) int imu; if (mu == 1.) { // use size -2 to have the index one before the end - imu = this->mu.size() - 2; + imu = this->mu.shape()[0] - 2; } else { imu = std::floor((mu + 1.) / dmu + 1.) - 1; } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index fd849b1c7..cd53b826e 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include "xtensor/xview.hpp" #include "xtensor/xindex_view.hpp" @@ -204,13 +205,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); // Now every incoming group in self.chi is the normalized chi we just made - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - for (size_t gout = 0; gout < energy_groups; gout++) { - chi_prompt(a, gin, gout) = temp_chi(a, gout); - } - } - } + chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); // Get nu-fission directly if (object_exists(xsdata_grp, "prompt-nu-fission")) { @@ -317,7 +312,8 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, // chi_prompt is this matrix but normalized over outgoing groups, which we // have already stored in prompt_nu_fission - chi_prompt = temp_matrix / prompt_nu_fission; + chi_prompt = temp_matrix / xt::view(prompt_nu_fission, xt::all(), xt::all(), + xt::newaxis()); } //============================================================================== @@ -391,12 +387,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, // Now use this info to find the length of a vector to hold the flattened // data. - size_t length = 0; - for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < energy_groups; gin++) { - length += order_data * (gmax(a, gin) - gmin(a, gin) + 1); - } - } + size_t length = order_data * xt::sum(gmax - gmin + 1)(); double_4dvec input_scatt(n_ang, double_3dvec(energy_groups)); xt::xtensor temp_arr({length}, 0.); diff --git a/tests/regression_tests/mg_basic/test.py b/tests/regression_tests/mg_basic/test.py index c29c7ca1f..7b456bb9d 100644 --- a/tests/regression_tests/mg_basic/test.py +++ b/tests/regression_tests/mg_basic/test.py @@ -82,7 +82,7 @@ class MGXSTestHarness(PyAPITestHarness): os.remove(f) -def test_mg_benchmark(): +def test_mg_basic(): create_library() mat_names = ['base leg', 'base tab', 'base hist', 'base matrix', 'base ang', 'micro'] diff --git a/tests/regression_tests/mg_basic_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py index 6c527bbe3..8fbcaca49 100644 --- a/tests/regression_tests/mg_basic_delayed/test.py +++ b/tests/regression_tests/mg_basic_delayed/test.py @@ -97,7 +97,7 @@ class MGXSTestHarness(PyAPITestHarness): os.remove(f) -def test_mg_benchmark(): +def test_mg_basic_delayed(): create_library() model = slab_mg(num_regions=4, mat_names=['vec beta', 'vec no beta', 'matrix beta', 'matrix no beta']) From 2c20dc0f8333687f9c1e23a2f641a90e8213fad2 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 14:27:04 -0400 Subject: [PATCH 08/12] super minor edit --- src/scattdata.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scattdata.cpp b/src/scattdata.cpp index 1069ef6e9..8d7138624 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -551,7 +551,6 @@ ScattDataHistogram::sample(int gin, int& gout, double& mu, double& wgt) if (xi < dist[gin][i_gout][0]) { imu = 0; } else { - // TODO lower_bound? + 1? imu = std::upper_bound(dist[gin][i_gout].begin(), dist[gin][i_gout].end(), xi) - dist[gin][i_gout].begin(); From be16cb750d05d405ade845fdf8a9954836d3aa9e Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 15:15:05 -0400 Subject: [PATCH 09/12] Added supportfor group-wise betas --- include/openmc/xsdata.h | 4 +- src/xsdata.cpp | 118 +++++++++++++----- .../mg_basic_delayed/inputs_true.dat | 22 +++- .../mg_basic_delayed/results_true.dat | 2 +- .../regression_tests/mg_basic_delayed/test.py | 29 ++++- 5 files changed, 131 insertions(+), 44 deletions(-) diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 780855ecf..0bdeaf818 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -37,7 +37,7 @@ class XsData { // the HDF5 file when beta is provided. void fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups); + size_t energy_groups, size_t delayed_groups, bool is_isotropic); //! \brief Reads fission data formatted as chi and nu-fission vectors from // the HDF5 file when beta is not provided. @@ -55,7 +55,7 @@ class XsData { // the HDF5 file when beta is provided. void fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups); + size_t energy_groups, size_t delayed_groups, bool is_isotropic); //! \brief Reads fission data formatted as a nu-fission matrix from // the HDF5 file when beta is not provided. diff --git a/src/xsdata.cpp b/src/xsdata.cpp index cd53b826e..d89fb1172 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include "xtensor/xview.hpp" #include "xtensor/xindex_view.hpp" @@ -124,7 +123,7 @@ XsData::from_hdf5(hid_t xsdata_grp, bool fissionable, int scatter_format, void XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups) + size_t energy_groups, size_t delayed_groups, bool is_isotropic) { // Data is provided as nu-fission and chi with a beta for delayed info @@ -145,17 +144,35 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::xtensor temp_nufiss({n_ang, energy_groups}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_nufiss, true); - // Get beta - xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "beta", temp_beta, true); + // Get beta (strategy will depend upon the number of dimensions in beta) + hid_t beta_dset = open_dataset(xsdata_grp, "beta"); + int beta_ndims = dataset_ndims(beta_dset); + close_dataset(beta_dset); + int ndim_target = 1; + if (!is_isotropic) ndim_target += 2; + if (beta_ndims == ndim_target) { + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - // Set prompt_nu_fission = (1. - beta_total)*nu_fission - prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); - // Set delayed_nu_fission as beta * nu_fission - delayed_nu_fission = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * - xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + // Set delayed_nu_fission as beta * nu_fission + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + } else if (beta_ndims == ndim_target + 1) { + xt::xtensor temp_beta({n_ang, delayed_groups, energy_groups}, + 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + // Set prompt_nu_fission = (1. - beta_total)*nu_fission + prompt_nu_fission = temp_nufiss * (1. - xt::sum(temp_beta, {1})); + + // Set delayed_nu_fission as beta * nu_fission + delayed_nu_fission = temp_beta * + xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); + } } void @@ -219,7 +236,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, void XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, - size_t energy_groups, size_t delayed_groups) + size_t energy_groups, size_t delayed_groups, bool is_isotropic) { // Data is provided as nu-fission and chi with a beta for delayed info @@ -227,32 +244,65 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); - // Get beta - xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); - read_nd_vector(xsdata_grp, "beta", temp_beta, true); + // Get beta (strategy will depend upon the number of dimensions in beta) + hid_t beta_dset = open_dataset(xsdata_grp, "beta"); + int beta_ndims = dataset_ndims(beta_dset); + close_dataset(beta_dset); + int ndim_target = 1; + if (!is_isotropic) ndim_target += 2; + if (beta_ndims == ndim_target) { + xt::xtensor temp_beta({n_ang, delayed_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); - xt::xtensor temp_beta_sum({n_ang}, 0.); - temp_beta_sum = xt::sum(temp_beta, {1}); + xt::xtensor temp_beta_sum({n_ang}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); - // prompt_nu_fission is the sum of this matrix over outgoing groups and - // multiplied by (1 - beta_sum) - prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); - // delayed_nu_fission is the sum of this matrix over outgoing groups and - // multiplied by beta - delayed_nu_fission = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * - xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); + // Store chi-prompt + chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), + xt::newaxis()) * temp_matrix; - // Store chi-prompt - chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::newaxis(), xt::newaxis()) * temp_matrix; + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + delayed_nu_fission = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); - // Store chi-delayed - chi_delayed = - xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * - xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); + // Store chi-delayed + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); - //Normalize both + } else if (beta_ndims == ndim_target + 1) { + xt::xtensor temp_beta({n_ang, delayed_groups, energy_groups}, 0.); + read_nd_vector(xsdata_grp, "beta", temp_beta, true); + + xt::xtensor temp_beta_sum({n_ang, energy_groups}, 0.); + temp_beta_sum = xt::sum(temp_beta, {1}); + + // prompt_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by (1 - beta_sum) + prompt_nu_fission = xt::sum(temp_matrix, {2}) * (1. - temp_beta_sum); + + // Store chi-prompt + chi_prompt = xt::view(1.0 - temp_beta_sum, xt::all(), xt::all(), + xt::newaxis()) * temp_matrix; + + // delayed_nu_fission is the sum of this matrix over outgoing groups and + // multiplied by beta + delayed_nu_fission = temp_beta * + xt::view(xt::sum(temp_matrix, {2}), xt::all(), xt::newaxis(), xt::all()); + + // Store chi-delayed + chi_delayed = + xt::view(temp_beta, xt::all(), xt::all(), xt::all(), xt::newaxis()) * + xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); + } + + //Normalize both chis chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::all(), xt::newaxis()); @@ -335,7 +385,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, } else { if (object_exists(xsdata_grp, "beta")) { fission_vector_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, - delayed_groups); + delayed_groups, is_isotropic); } else { fission_vector_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, delayed_groups); @@ -347,7 +397,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, size_t energy_groups, } else { if (object_exists(xsdata_grp, "beta")) { fission_matrix_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, - delayed_groups); + delayed_groups, is_isotropic); } else { fission_matrix_no_beta_from_hdf5(xsdata_grp, n_ang, energy_groups, delayed_groups); diff --git a/tests/regression_tests/mg_basic_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat index e62e65ab1..9fb7afe7e 100644 --- a/tests/regression_tests/mg_basic_delayed/inputs_true.dat +++ b/tests/regression_tests/mg_basic_delayed/inputs_true.dat @@ -4,11 +4,15 @@ + + - - - - + + + + + + @@ -29,6 +33,14 @@ + + + + + + + + @@ -38,7 +50,7 @@ 5 - 0.0 -1000.0 -1000.0 232.3625 1000.0 1000.0 + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 diff --git a/tests/regression_tests/mg_basic_delayed/results_true.dat b/tests/regression_tests/mg_basic_delayed/results_true.dat index 4b425173d..85312b8e1 100644 --- a/tests/regression_tests/mg_basic_delayed/results_true.dat +++ b/tests/regression_tests/mg_basic_delayed/results_true.dat @@ -1,2 +1,2 @@ k-combined: -9.928704E-01 2.679667E-02 +1.003463E+00 2.173155E-02 diff --git a/tests/regression_tests/mg_basic_delayed/test.py b/tests/regression_tests/mg_basic_delayed/test.py index 8fbcaca49..f0474a567 100644 --- a/tests/regression_tests/mg_basic_delayed/test.py +++ b/tests/regression_tests/mg_basic_delayed/test.py @@ -85,6 +85,29 @@ def create_library(): mat_4.set_total(total) mg_cross_sections_file.add_xsdata(mat_4) + # Make the base data that uses chi & nu-fiss vectors with a group-wise beta + mat_5 = openmc.XSdata('mat_5', groups) + mat_5.order = 1 + mat_5.num_delayed_groups = 2 + mat_5.set_beta(np.stack([beta] * groups.num_groups)) + mat_5.set_nu_fission(np.multiply(nu, fiss)) + mat_5.set_absorption(absorption) + mat_5.set_scatter_matrix(scatter) + mat_5.set_total(total) + mat_5.set_chi(chi) + mg_cross_sections_file.add_xsdata(mat_5) + + # Make a version that uses a nu-fission matrix with a group-wise beta + mat_6 = openmc.XSdata('mat_6', groups) + mat_6.order = 1 + mat_6.num_delayed_groups = 2 + mat_6.set_beta(np.stack([beta] * groups.num_groups)) + mat_6.set_nu_fission(np.outer(np.multiply(nu, fiss), chi)) + mat_6.set_absorption(absorption) + mat_6.set_scatter_matrix(scatter) + mat_6.set_total(total) + mg_cross_sections_file.add_xsdata(mat_6) + # Write the file mg_cross_sections_file.export_to_hdf5('2g.h5') @@ -99,8 +122,10 @@ class MGXSTestHarness(PyAPITestHarness): def test_mg_basic_delayed(): create_library() - model = slab_mg(num_regions=4, mat_names=['vec beta', 'vec no beta', - 'matrix beta', 'matrix no beta']) + model = slab_mg(num_regions=6, mat_names=['vec beta', 'vec no beta', + 'matrix beta', 'matrix no beta', + 'vec group beta', + 'matrix group beta']) harness = PyAPITestHarness('statepoint.10.h5', model) harness.main() From cd1dfc0d199a122ea479405f9f2825211d99733c Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Mon, 3 Sep 2018 15:34:41 -0400 Subject: [PATCH 10/12] Final cleanup --- src/xsdata.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/xsdata.cpp b/src/xsdata.cpp index d89fb1172..56783a672 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -225,11 +225,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); // Get nu-fission directly - if (object_exists(xsdata_grp, "prompt-nu-fission")) { - read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); - } else { - read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission, true); - } + read_nd_vector(xsdata_grp, "nu-fission", prompt_nu_fission, true); } //============================================================================== @@ -351,11 +347,7 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Get nu-fission matrix xt::xtensor temp_matrix({n_ang, energy_groups, energy_groups}, 0.); - if (object_exists(xsdata_grp, "prompt-nu-fission")) { - read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix, true); - } else { - read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); - } + read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // prompt_nu_fission is the sum over outgoing groups prompt_nu_fission = xt::sum(temp_matrix, {2}); From 4b56c86c50129e840ffd5202bb2b3e9f41ba4c28 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Wed, 5 Sep 2018 20:46:33 -0400 Subject: [PATCH 11/12] Cleaning up code, resolving @paulromano comments --- include/openmc/constants.h | 6 +++--- include/openmc/hdf5_interface.h | 3 --- include/openmc/mgxs.h | 10 +++++----- include/openmc/xsdata.h | 2 +- src/hdf5_interface.cpp | 30 ------------------------------ src/mgxs.cpp | 10 +++++----- src/xsdata.cpp | 25 +++++++++++++------------ 7 files changed, 27 insertions(+), 59 deletions(-) diff --git a/include/openmc/constants.h b/include/openmc/constants.h index b8c5c8548..c77817a14 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -11,9 +11,9 @@ namespace openmc { -typedef std::vector > double_2dvec; -typedef std::vector > > double_3dvec; -typedef std::vector > > > double_4dvec; +using double_2dvec = std::vector>; +using double_3dvec = std::vector>>; +using double_4dvec = std::vector>>>; // ============================================================================ // VERSIONING NUMBERS diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index 3ab2014c1..b791c8d72 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -70,9 +70,6 @@ void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have = false); -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); std::vector attribute_shape(hid_t obj_id, const char* name); std::vector dataset_names(hid_t group_id); diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index cd312ea17..e80355bee 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -159,7 +159,7 @@ class Mgxs { //! @param dg delayed group index; use nullptr if irrelevant. //! @return Requested cross section value. double - get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg); + get_xs(int xstype, int gin, int* gout, double* mu, int* dg); //! \brief Samples the fission neutron energy and if prompt or delayed. //! @@ -167,7 +167,7 @@ class Mgxs { //! @param dg Sampled delayed group index. //! @param gout Sampled outgoing energy group. void - sample_fission_energy(const int gin, int& dg, int& gout); + sample_fission_energy(int gin, int& dg, int& gout); //! \brief Samples the outgoing energy and angle from a scatter event. //! @@ -176,7 +176,7 @@ class Mgxs { //! @param mu Sampled cosine of the change-in-angle. //! @param wgt Weight of the particle to be adjusted. void - sample_scatter(const int gin, int& gout, double& mu, double& wgt); + sample_scatter(int gin, int& gout, double& mu, double& wgt); //! \brief Calculates cross section quantities needed for tracking. //! @@ -187,14 +187,14 @@ class Mgxs { //! @param abs_xs Resultant absorption cross section. //! @param nu_fiss_xs Resultant nu-fission cross section. void - calculate_xs(const int gin, const double sqrtkT, const double uvw[3], + calculate_xs(int gin, double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs); //! \brief Sets the temperature index in cache given a temperature //! //! @param sqrtkT Temperature of the material. void - set_temperature_index(const double sqrtkT); + set_temperature_index(double sqrtkT); //! \brief Sets the angle index in cache given a direction //! diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index 0bdeaf818..fa75b10aa 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -94,7 +94,7 @@ class XsData { // [angle][incoming group][outgoing group][delayed group] xt::xtensor chi_delayed; // scatter has the following dimensions: [angle] - std::vector > scatter; + std::vector> scatter; XsData() = default; diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 52fae8228..514cf6966 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -673,36 +673,6 @@ read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, } } -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - int dim4 = result.shape()[3]; - int dim5 = result.shape()[4]; - double temp_arr[dim1 * dim2 * dim3 * dim4 * dim5]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - for (int l = 0; l < dim4; l++) { - for (int m = 0; m < dim5; m++) { - result(i, j, k, l, m) = temp_arr[temp_idx++]; - } - } - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index b9e22780a..12c73fab4 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -423,7 +423,7 @@ Mgxs::combine(const std::vector& micros, const std::vector& scala //============================================================================== double -Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) +Mgxs::get_xs(int xstype, int gin, int* gout, double* mu, int* dg) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -535,7 +535,7 @@ Mgxs::get_xs(const int xstype, const int gin, int* gout, double* mu, int* dg) //============================================================================== void -Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) +Mgxs::sample_fission_energy(int gin, int& dg, int& gout) { // This method assumes that the temperature and angle indices are set #ifdef _OPENMP @@ -599,7 +599,7 @@ Mgxs::sample_fission_energy(const int gin, int& dg, int& gout) //============================================================================== void -Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) +Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) { // This method assumes that the temperature and angle indices are set // Sample the data @@ -614,7 +614,7 @@ Mgxs::sample_scatter(const int gin, int& gout, double& mu, double& wgt) //============================================================================== void -Mgxs::calculate_xs(const int gin, const double sqrtkT, const double uvw[3], +Mgxs::calculate_xs(int gin, double sqrtkT, const double uvw[3], double& total_xs, double& abs_xs, double& nu_fiss_xs) { // Set our indices @@ -649,7 +649,7 @@ Mgxs::equiv(const Mgxs& that) //============================================================================== void -Mgxs::set_temperature_index(const double sqrtkT) +Mgxs::set_temperature_index(double sqrtkT) { // See if we need to find the new index #ifdef _OPENMP diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 56783a672..8abc1edfd 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -132,7 +132,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); // Now every incoming group in prompt_chi and delayed_chi is the normalized // chi we just made @@ -186,16 +186,15 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_p = temp_chi_p / xt::view(xt::sum(temp_chi_p, {1}), xt::all(), - xt::newaxis()); + temp_chi_p /= xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); // Get chi-delayed xt::xtensor temp_chi_d({n_ang, delayed_groups, energy_groups}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi_d = temp_chi_d / xt::view(xt::sum(temp_chi_d, {2}), xt::all(), - xt::all(), xt::newaxis()); + temp_chi_d /= xt::view(xt::sum(temp_chi_d, {2}), + xt::all(), xt::all(), xt::newaxis()); // Now assign the prompt and delayed chis by replicating for each incoming group chi_prompt = xt::view(temp_chi_p, xt::all(), xt::newaxis(), xt::all()); @@ -203,8 +202,10 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::all()); // Get prompt and delayed nu-fission directly - read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, true); - read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); + read_nd_vector(xsdata_grp, "prompt-nu-fission", prompt_nu_fission, + true); + read_nd_vector(xsdata_grp, "delayed-nu-fission", + delayed_nu_fission, true); } void @@ -219,7 +220,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang, read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle - temp_chi = temp_chi / xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); // Now every incoming group in self.chi is the normalized chi we just made chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); @@ -299,11 +300,11 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, } //Normalize both chis - chi_prompt = chi_prompt / xt::view(xt::sum(chi_prompt, {2}), xt::all(), - xt::all(), xt::newaxis()); + chi_prompt /= xt::view(xt::sum(chi_prompt, {2}), + xt::all(), xt::all(), xt::newaxis()); - chi_delayed = chi_delayed / xt::view(xt::sum(chi_delayed, {3}), xt::all(), - xt::all(), xt::all(), xt::newaxis()); + chi_delayed /= xt::view(xt::sum(chi_delayed, {3}), + xt::all(), xt::all(), xt::all(), xt::newaxis()); } void From 1cf1deb9f0f3420b5966b18d9714a72d52affa3c Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 8 Sep 2018 06:44:49 -0400 Subject: [PATCH 12/12] Templatized read_nd_vector --- include/openmc/hdf5_interface.h | 62 ++++++++------ src/hdf5_interface.cpp | 140 -------------------------------- 2 files changed, 36 insertions(+), 166 deletions(-) diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index b791c8d72..2f5d7cb52 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -14,6 +14,7 @@ #include "xtensor/xarray.hpp" #include "openmc/position.h" +#include "openmc/error.h" namespace openmc { @@ -46,31 +47,6 @@ hid_t file_open(const std::string& filename, char mode, bool parallel=false); void write_string(hid_t group_id, const char* name, const std::string& buffer, bool indep); -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have = false); - - std::vector attribute_shape(hid_t obj_id, const char* name); std::vector dataset_names(hid_t group_id); void ensure_exists(hid_t group_id, const char* name); @@ -228,7 +204,7 @@ read_attribute(hid_t obj_id, const char* name, std::vector& vec) } //============================================================================== -// Templates/overloads for read_dataset +// Templates/overloads for read_dataset and related methods //============================================================================== template @@ -286,6 +262,40 @@ void read_dataset(hid_t obj_id, const char* name, xt::xarray& arr, bool indep close_dataset(dset); } + +template +void read_dataset_as_shape(hid_t obj_id, const char* name, + xt::xtensor& arr, bool indep=false) +{ + hid_t dset = open_dataset(obj_id, name); + + // Allocate new array to read data into + std::size_t size = 1; + for (const auto x : arr.shape()) + size *= x; + T* buffer = new T[size]; + + // Read data from attribute + read_dataset(dset, nullptr, H5TypeMap::type_id, buffer, indep); + + // Adapt into xarray + arr = xt::adapt(buffer, size, xt::acquire_ownership(), arr.shape()); + + close_dataset(dset); +} + + +template +void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, + bool must_have=false) +{ + if (object_exists(obj_id, name)) { + read_dataset_as_shape(obj_id, name, result, true); + } else if (must_have) { + fatal_error(std::string("Must provide " + std::string(name) + "!")); + } +} + //============================================================================== // Templates/overloads for write_attribute //============================================================================== diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 514cf6966..4badc0441 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -14,7 +14,6 @@ #include "mpi.h" #include "openmc/message_passing.h" #endif -#include "openmc/error.h" namespace openmc { @@ -535,145 +534,6 @@ read_complex(hid_t obj_id, const char* name, std::complex* buffer, bool } -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - double temp_arr[dim1]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - result(i) = temp_arr[temp_idx++]; - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - double temp_arr[dim1 * dim2]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - result(i, j) = temp_arr[temp_idx++]; - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int temp_arr[dim1 * dim2]; - read_int(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - result(i, j) = temp_arr[temp_idx++]; - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - double temp_arr[dim1 * dim2 * dim3]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - result(i, j, k) = temp_arr[temp_idx++]; - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - int temp_arr[dim1 * dim2 * dim3]; - read_int(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - result(i, j, k) = temp_arr[temp_idx++]; - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - -void -read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, - bool must_have) -{ - if (object_exists(obj_id, name)) { - int dim1 = result.shape()[0]; - int dim2 = result.shape()[1]; - int dim3 = result.shape()[2]; - int dim4 = result.shape()[3]; - double temp_arr[dim1 * dim2 * dim3 * dim4]; - read_double(obj_id, name, temp_arr, true); - - int temp_idx = 0; - for (int i = 0; i < dim1; i++) { - for (int j = 0; j < dim2; j++) { - for (int k = 0; k < dim3; k++) { - for (int l = 0; l < dim4; l++) { - result(i, j, k, l) = temp_arr[temp_idx++]; - } - } - } - } - } else if (must_have) { - fatal_error(std::string("Must provide " + std::string(name) + "!")); - } -} - - void read_tally_results(hid_t group_id, hsize_t n_filter, hsize_t n_score, double* results) {