From dea5e46c3c2fe79e000cf53ccabd7ddeb27af709 Mon Sep 17 00:00:00 2001 From: Huw Rhys Jones <43721202+dubway420@users.noreply.github.com> Date: Tue, 2 May 2023 00:51:34 +0100 Subject: [PATCH 01/45] Update neutron_physics.rst (#2504) --- docs/source/methods/neutron_physics.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/methods/neutron_physics.rst b/docs/source/methods/neutron_physics.rst index f1b0a5bde72..70ace4a3532 100644 --- a/docs/source/methods/neutron_physics.rst +++ b/docs/source/methods/neutron_physics.rst @@ -91,7 +91,7 @@ inelastic scattering reactions. The specific multi-group scattering implementation is discussed in the :ref:`multi-group-scatter` section. Elastic scattering refers to the process by which a neutron scatters off a -nucleus and does not leave it in an excited. It is referred to as "elastic" +nucleus and does not leave it in an excited state. It is referred to as "elastic" because in the center-of-mass system, the neutron does not actually lose energy. However, in lab coordinates, the neutron does indeed lose energy. Elastic scattering can be treated exactly in a Monte Carlo code thanks From 0a950eb6236c1524e128a4a4f60114611367e085 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 1 May 2023 22:00:45 -0500 Subject: [PATCH 02/45] Reworking Tally::add_filter a bit (#2501) --- include/openmc/tallies/tally.h | 2 +- src/tallies/tally.cpp | 29 +++++++++------ tests/cpp_unit_tests/CMakeLists.txt | 1 + tests/cpp_unit_tests/test_tally.cpp | 55 +++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 tests/cpp_unit_tests/test_tally.cpp diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index 56a51370a84..e840a0aa144 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -67,7 +67,7 @@ class Tally { //---------------------------------------------------------------------------- // Other methods. - void add_filter(Filter* filter) { set_filters({&filter, 1}); } + void add_filter(Filter* filter); void init_triggers(pugi::xml_node node); diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 0610c8cf133..e29384772f6 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -364,18 +364,25 @@ void Tally::set_filters(gsl::span filters) auto n = filters.size(); filters_.reserve(n); - for (int i = 0; i < n; ++i) { - // Add index to vector of filters - auto& f {filters[i]}; - filters_.push_back(model::filter_map.at(f->id())); - - // Keep track of indices for special filters. - if (dynamic_cast(f)) { - energyout_filter_ = i; - } else if (dynamic_cast(f)) { - delayedgroup_filter_ = i; - } + for (auto* filter : filters) { + add_filter(filter); + } +} + +void Tally::add_filter(Filter* filter) +{ + int32_t filter_idx = model::filter_map.at(filter->id()); + // if this filter is already present, do nothing and return + if (std::find(filters_.begin(), filters_.end(), filter_idx) != filters_.end()) + return; + + // Keep track of indices for special filters + if (dynamic_cast(filter)) { + energyout_filter_ = filters_.size(); + } else if (dynamic_cast(filter)) { + delayedgroup_filter_ = filters_.size(); } + filters_.push_back(filter_idx); } void Tally::set_strides() diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt index e017b870027..50ae9a20821 100644 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -1,6 +1,7 @@ set(TEST_NAMES test_distribution test_file_utils + test_tally # Add additional unit test files here ) diff --git a/tests/cpp_unit_tests/test_tally.cpp b/tests/cpp_unit_tests/test_tally.cpp new file mode 100644 index 00000000000..964d30cc42a --- /dev/null +++ b/tests/cpp_unit_tests/test_tally.cpp @@ -0,0 +1,55 @@ +#include "openmc/tallies/tally.h" +#include + +using namespace openmc; + +TEST_CASE("Test add/set_filter") +{ + // create a new tally object + Tally* tally = Tally::create(); + + // create a new particle filter + Filter* particle_filter = Filter::create("particle"); + + // add the particle filter to the tally + tally->add_filter(particle_filter); + + // the filter should be added to the tally + REQUIRE(tally->filters().size() == 1); + REQUIRE(model::filter_map[particle_filter->id()] == tally->filters(0)); + + // add the particle filter to the tally again + tally->add_filter(particle_filter); + // the tally should have the same number of filters + REQUIRE(tally->filters().size() == 1); + + // create a cell filter + Filter* cell_filter = Filter::create("cell"); + tally->add_filter(cell_filter); + + // now the size of the filters should have increased + REQUIRE(tally->filters().size() == 2); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(1)); + + // if we set the filters explicitly there shouldn't be extra filters hanging + // around + tally->set_filters({&cell_filter, 1}); + + REQUIRE(tally->filters().size() == 1); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); + + // set filters again using both filters + std::vector filters = {cell_filter, particle_filter}; + tally->set_filters(filters); + + REQUIRE(tally->filters().size() == 2); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); + REQUIRE(model::filter_map[particle_filter->id()] == tally->filters(1)); + + // set filters with a duplicate filter, should only add the filter to the tally once + filters = {cell_filter, cell_filter}; + tally->set_filters(filters); + REQUIRE(tally->filters().size() == 1); + REQUIRE(model::filter_map[cell_filter->id()] == tally->filters(0)); + +} \ No newline at end of file From 4248beff1b51cf6d650e95a51769b0dac67f8274 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Tue, 2 May 2023 17:41:25 +0100 Subject: [PATCH 03/45] Auto origin and width for plots (#2492) Co-authored-by: Paul Romano --- openmc/bounding_box.py | 6 ++++++ openmc/universe.py | 32 ++++++++++++++++++++++++++----- tests/unit_tests/test_universe.py | 19 +++++++++++++++++- 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/openmc/bounding_box.py b/openmc/bounding_box.py index d2a49909210..331e831f195 100644 --- a/openmc/bounding_box.py +++ b/openmc/bounding_box.py @@ -27,6 +27,8 @@ class BoundingBox(tuple): The x, y, z coordinates of the upper right corner of the bounding box in [cm] volume : float The volume of the bounding box in [cm^3] + width : iterable of float + The width of the x, y and z axis in [cm] """ def __new__(cls, lower_left: Iterable[float], upper_right: Iterable[float]): @@ -55,3 +57,7 @@ def upper_right(self) -> np.ndarray: @property def volume(self) -> float: return np.abs(np.prod(self[1] - self[0])) + + @property + def width(self): + return self.upper_right - self.lower_left diff --git a/openmc/universe.py b/openmc/universe.py index 3984a0a61d3..afe360094e6 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -300,7 +300,7 @@ def find(self, point): _default_legend_kwargs = {'bbox_to_anchor': ( 1.05, 1), 'loc': 2, 'borderaxespad': 0.0} - def plot(self, origin=(0., 0., 0.), width=(1., 1.), pixels=(200, 200), + def plot(self, origin=None, width=None, pixels=(200, 200), basis='xy', color_by='cell', colors=None, seed=None, openmc_exec='openmc', axes=None, legend=False, legend_kwargs=_default_legend_kwargs, outline=False, @@ -309,10 +309,16 @@ def plot(self, origin=(0., 0., 0.), width=(1., 1.), pixels=(200, 200), Parameters ---------- - origin : Iterable of float - Coordinates at the origin of the plot - width : Iterable of float - Width of the plot in each basis direction + origin : iterable of float + Coordinates at the origin of the plot, if left as None then the + universe.bounding_box.center will be used to attempt to + ascertain the origin. Defaults to (0, 0, 0) if the bounding_box + contains inf values + width : iterable of float + Width of the plot in each basis direction. If left as none then the + universe.bounding_box.width() will be used to attempt to + ascertain the plot width. Defaults to (10, 10) if the bounding_box + contains inf values pixels : Iterable of int Number of pixels to use in each basis direction basis : {'xy', 'xz', 'yz'} @@ -373,6 +379,22 @@ def plot(self, origin=(0., 0., 0.), width=(1., 1.), pixels=(200, 200), elif basis == 'xz': x, y = 0, 2 xlabel, ylabel = 'x [cm]', 'z [cm]' + + # checks to see if bounding box contains -inf or inf values + if True in np.isinf(self.bounding_box): + if origin is None: + origin = (0, 0, 0) + if width is None: + width = (10, 10) + else: + if origin is None: + origin = self.bounding_box.center + if width is None: + bb_width = self.bounding_box.width + x_width = bb_width['xyz'.index(basis[0])] + y_width = bb_width['xyz'.index(basis[1])] + width = (x_width, y_width) + x_min = origin[x] - 0.5*width[0] x_max = origin[x] + 0.5*width[0] y_min = origin[y] - 0.5*width[1] diff --git a/tests/unit_tests/test_universe.py b/tests/unit_tests/test_universe.py index cb4f2b70302..fc92de9c784 100644 --- a/tests/unit_tests/test_universe.py +++ b/tests/unit_tests/test_universe.py @@ -48,8 +48,9 @@ def test_bounding_box(): assert_unbounded(u) -def test_plot(run_in_tmpdir): +def test_plot(run_in_tmpdir, sphere_model): + # model with -inf and inf in the bounding box pincell = openmc.examples.pwr_pin_cell() materials = pincell.materials @@ -69,6 +70,22 @@ def test_plot(run_in_tmpdir): outline=True ) + # model with no inf values in bounding box + m = sphere_model.materials[0] + univ = sphere_model.geometry.root_universe + + colors = {m: 'limegreen'} + + for basis in ('xy', 'yz', 'xz'): + univ.plot( + colors=colors, + color_by="cell", + legend=False, + pixels=(10, 10), + basis=basis, + outline=False + ) + def test_get_nuclides(uo2): c = openmc.Cell(fill=uo2) From 45006584ca1e770273a55b5fdccc15ea0ea18032 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 3 May 2023 09:52:40 -0500 Subject: [PATCH 04/45] Fix meaning of "masking" for plots (#2510) --- openmc/plots.py | 35 ++++++++++++++++--- openmc/plotter.py | 2 +- src/plot.cpp | 14 +++++--- tests/regression_tests/plot/results_true.dat | 2 +- .../plot_overlaps/results_true.dat | 2 +- .../plot_projections/results_true.dat | 2 +- 6 files changed, 44 insertions(+), 13 deletions(-) diff --git a/openmc/plots.py b/openmc/plots.py index c6af5eea12c..67b65440a2c 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -270,7 +270,7 @@ class PlotBase(IDManagerMixin): Name of the plot pixels : Iterable of int Number of pixels to use in each direction - filename : + filename : str Path to write the plot to color_by : {'cell', 'material'} Indicate whether the plot should be colored by cell or by material @@ -279,7 +279,7 @@ class PlotBase(IDManagerMixin): mask_components : Iterable of openmc.Cell or openmc.Material or int The cells or materials (or corresponding IDs) to mask mask_background : Iterable of int or str - Color to apply to all cells/materials not listed in mask_components + Color to apply to all cells/materials listed in mask_components show_overlaps : bool Indicate whether or not overlapping regions are shown overlap_color : Iterable of int or str @@ -515,7 +515,7 @@ def to_xml_element(self): class Plot(PlotBase): - '''Definition of a finite region of space to be plotted. + """Definition of a finite region of space to be plotted. OpenMC is capable of generating two-dimensional slice plots, or three-dimensional voxel or projection plots. Colors that are used in plots can be given as @@ -531,6 +531,33 @@ class Plot(PlotBase): Attributes ---------- + id : int + Unique identifier + name : str + Name of the plot + pixels : Iterable of int + Number of pixels to use in each direction + filename : str + Path to write the plot to + color_by : {'cell', 'material'} + Indicate whether the plot should be colored by cell or by material + background : Iterable of int or str + Color of the background + mask_components : Iterable of openmc.Cell or openmc.Material or int + The cells or materials (or corresponding IDs) to mask + mask_background : Iterable of int or str + Color to apply to all cells/materials listed in mask_components + show_overlaps : bool + Indicate whether or not overlapping regions are shown + overlap_color : Iterable of int or str + Color to apply to overlapping regions + colors : dict + Dictionary indicating that certain cells/materials should be + displayed with a particular color. The keys can be of type + :class:`~openmc.Cell`, :class:`~openmc.Material`, or int (ID for a + cell/material). + level : int + Universe depth to plot at width : Iterable of float Width of the plot in each basis direction origin : tuple or list of ndarray @@ -543,7 +570,7 @@ class Plot(PlotBase): Dictionary defining type, id, linewidth and color of a mesh to be plotted on top of a plot - ''' + """ def __init__(self, plot_id=None, name=''): super().__init__(plot_id, name) diff --git a/openmc/plotter.py b/openmc/plotter.py index d8e06e4fe15..193ba9cbe67 100644 --- a/openmc/plotter.py +++ b/openmc/plotter.py @@ -59,7 +59,7 @@ def _get_legend_label(this, type): """Gets a label for the element or nuclide or material and reaction plotted""" if isinstance(this, str): return f'{this} {type}' - elif this.name is '': + elif this.name == '': return f'Material {this.id} {type}' else: return f'{this.name} {type}' diff --git a/src/plot.cpp b/src/plot.cpp index 1f629e90132..b4c8cad165f 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -5,8 +5,8 @@ #include #include -#include "xtensor/xview.hpp" #include "xtensor/xmanipulation.hpp" +#include "xtensor/xview.hpp" #include #include #ifdef USE_LIBPNG @@ -14,6 +14,7 @@ #endif #include "openmc/constants.h" +#include "openmc/container_util.h" #include "openmc/dagmc.h" #include "openmc/error.h" #include "openmc/file_utils.h" @@ -647,7 +648,7 @@ void PlottableInterface::set_mask(pugi::xml_node plot_node) // Alter colors based on mask information for (int j = 0; j < colors_.size(); j++) { - if (std::find(iarray.begin(), iarray.end(), j) == iarray.end()) { + if (contains(iarray, j)) { if (check_for_node(mask_node, "background")) { vector bg_rgb = get_node_array(mask_node, "background"); colors_[j] = bg_rgb; @@ -1306,12 +1307,15 @@ void ProjectionPlot::create_output() const bool inside_cell = false; int32_t i_surface = std::abs(p.surface()) - 1; - if (i_surface > 0 && model::surfaces[i_surface]->geom_type_ == GeometryType::DAG) { + if (i_surface > 0 && + model::surfaces[i_surface]->geom_type_ == GeometryType::DAG) { #ifdef DAGMC - int32_t i_cell = next_cell(i_surface, p.cell_last(p.n_coord() - 1), p.lowest_coord().universe); + int32_t i_cell = next_cell(i_surface, + p.cell_last(p.n_coord() - 1), p.lowest_coord().universe); inside_cell = i_cell >= 0; #else - fatal_error("Not compiled for DAGMC, but somehow you have a DAGCell!"); + fatal_error( + "Not compiled for DAGMC, but somehow you have a DAGCell!"); #endif } else { inside_cell = exhaustive_find_cell(p); diff --git a/tests/regression_tests/plot/results_true.dat b/tests/regression_tests/plot/results_true.dat index 9174202fbaf..1be60ad4fa1 100644 --- a/tests/regression_tests/plot/results_true.dat +++ b/tests/regression_tests/plot/results_true.dat @@ -1 +1 @@ -f85c20735a0c08525fe48b19a8e075c074539ee6c8860268fa0cb515d842496b7086e5b94305ef78dcf2106bb193abdf438259ac8ff1d0245a2782eb6f5af873 \ No newline at end of file +6385d2969ed54d47a09f75112595fc034a16f551346c92d87ed9e7841881baaee8e56190c347e97c3f919ef677bb5b858960d60fe985a00e2848a3bfbef7a12b \ No newline at end of file diff --git a/tests/regression_tests/plot_overlaps/results_true.dat b/tests/regression_tests/plot_overlaps/results_true.dat index cb04daaa4c6..93ee6769fc7 100644 --- a/tests/regression_tests/plot_overlaps/results_true.dat +++ b/tests/regression_tests/plot_overlaps/results_true.dat @@ -1 +1 @@ -926065ceb2a9b8292fe6270317c38c4373473cfea19d2a8392a32e5ece8e314c04b9f032921d987bd195ae4b6f674d359b0e38302e6ae4c93b4ac9573a384ac6 \ No newline at end of file +125ce40fbff3e02e7f5f36a92a2e37abce9407154c825b6617242a4685dfc33c63041145b1f3114334338fbb86188331195ddc319ffce58fab2943d8e60f6da3 \ No newline at end of file diff --git a/tests/regression_tests/plot_projections/results_true.dat b/tests/regression_tests/plot_projections/results_true.dat index a2cb57b1e96..1a67da3002a 100644 --- a/tests/regression_tests/plot_projections/results_true.dat +++ b/tests/regression_tests/plot_projections/results_true.dat @@ -1 +1 @@ -6448093f8acaa2af02452ec1b29461ffaf89628bb002cc8873a3a6831fe5d613645a197033597e5a064896388f19d0782f05e78ce474354ae2a76c35ff4551d7 \ No newline at end of file +24fb0f41ee018ea086962dbd6bcd0b536d11d4b34644bfef4f0e74f8b462fe41a84af39c7ff79046d5d7cfe209084eac54712fa0ec01038e97eb43df1abd0334 \ No newline at end of file From e3d8982bb91d82a338484e554a656fa2df959d79 Mon Sep 17 00:00:00 2001 From: Yue JIN <40021217+kingyue737@users.noreply.github.com> Date: Thu, 4 May 2023 21:13:00 +0800 Subject: [PATCH 05/45] docs: typo fix (#2514) Co-authored-by: Jonathan Shimwell --- openmc/settings.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/settings.py b/openmc/settings.py index 516cbbc4ae8..aa4276cd52e 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -163,7 +163,7 @@ class Settings: statepoint : dict Options for writing state points. Acceptable keys are: - :batches: list of batches at which to write source + :batches: list of batches at which to write statepoint files surf_source_read : dict Options for reading surface source points. Acceptable keys are: From 1cb22075efdb90570f233a3d26151f7b763f8529 Mon Sep 17 00:00:00 2001 From: Patrick Myers <90068356+myerspat@users.noreply.github.com> Date: Tue, 9 May 2023 11:41:04 -0400 Subject: [PATCH 06/45] Changed xml to lxml (#2489) --- docs/requirements-rtd.txt | 1 + openmc/_xml.py | 6 +- openmc/cell.py | 6 +- openmc/data/library.py | 2 +- openmc/deplete/chain.py | 16 +- openmc/deplete/nuclide.py | 25 +- openmc/element.py | 2 +- openmc/filter.py | 14 +- openmc/filter_expansion.py | 10 +- openmc/geometry.py | 4 +- openmc/lattice.py | 8 +- openmc/material.py | 12 +- openmc/mesh.py | 28 +- openmc/model/model.py | 10 +- openmc/plots.py | 16 +- openmc/settings.py | 4 +- openmc/source.py | 6 +- openmc/stats/multivariate.py | 38 +- openmc/stats/univariate.py | 34 +- openmc/surface.py | 12 +- openmc/tallies.py | 8 +- openmc/tally_derivative.py | 6 +- openmc/trigger.py | 6 +- openmc/universe.py | 6 +- openmc/volume.py | 6 +- openmc/weight_windows.py | 8 +- .../adj_cell_rotation/inputs_true.dat | 32 +- .../asymmetric_lattice/inputs_true.dat | 286 +-- .../cpp_driver/inputs_true.dat | 36 +- .../create_fission_neutrons/inputs_true.dat | 22 +- .../dagmc/external/inputs_true.dat | 14 +- .../dagmc/legacy/inputs_true.dat | 14 +- .../dagmc/refl/inputs_true.dat | 2 +- .../dagmc/universes/inputs_true.dat | 50 +- .../dagmc/uwuw/inputs_true.dat | 2 +- .../last_step_reference_materials.xml | 1804 ++++++++--------- .../diff_tally/inputs_true.dat | 344 ++-- .../distribmat/inputs_true.dat | 32 +- .../eigenvalue_genperbatch/inputs_true.dat | 8 +- .../energy_cutoff/inputs_true.dat | 20 +- .../energy_laws/inputs_true.dat | 16 +- .../external_moab/inputs_true.dat | 66 +- .../filter_cellinstance/inputs_true.dat | 32 +- .../filter_energyfun/inputs_true.dat | 8 +- .../filter_mesh/inputs_true.dat | 32 +- .../filter_translations/inputs_true.dat | 32 +- .../fixed_source/inputs_true.dat | 10 +- .../iso_in_lab/inputs_true.dat | 334 +-- .../lattice_hex_coincident/inputs_true.dat | 76 +- .../lattice_hex_x/inputs_true.dat | 96 +- .../lattice_multiple/inputs_true.dat | 38 +- .../lattice_rotated/inputs_true.dat | 42 +- .../regression_tests/mg_basic/inputs_true.dat | 52 +- .../mg_basic_delayed/inputs_true.dat | 50 +- .../mg_convert/inputs_true.dat | 14 +- .../mg_legendre/inputs_true.dat | 10 +- .../mg_max_order/inputs_true.dat | 10 +- .../mg_survival_biasing/inputs_true.dat | 10 +- .../mg_tallies/inputs_true.dat | 10 +- .../mgxs_library_ce_to_mg/inputs_true.dat | 52 +- .../inputs_true.dat | 52 +- .../mgxs_library_condense/inputs_true.dat | 52 +- .../mgxs_library_correction/inputs_true.dat | 52 +- .../mgxs_library_distribcell/inputs_true.dat | 60 +- .../mgxs_library_hdf5/inputs_true.dat | 52 +- .../mgxs_library_histogram/inputs_true.dat | 52 +- .../mgxs_library_mesh/inputs_true.dat | 32 +- .../mgxs_library_no_nuclides/inputs_true.dat | 52 +- .../mgxs_library_nuclides/inputs_true.dat | 52 +- .../inputs_true.dat | 52 +- .../adj_cell_rotation_inputs_true.dat | 32 +- .../model_xml/energy_laws_inputs_true.dat | 16 +- .../model_xml/inputs_true.dat | 20 +- .../lattice_multiple_inputs_true.dat | 38 +- .../photon_production_inputs_true.dat | 20 +- .../multipole/inputs_true.dat | 30 +- .../regression_tests/ncrystal/inputs_true.dat | 14 +- .../regression_tests/periodic/inputs_true.dat | 30 +- .../periodic_6fold/inputs_true.dat | 24 +- .../periodic_hex/inputs_true.dat | 18 +- .../photon_production/inputs_true.dat | 20 +- .../photon_production_fission/inputs_true.dat | 8 +- .../photon_source/inputs_true.dat | 16 +- .../resonance_scattering/inputs_true.dat | 14 +- .../salphabeta/inputs_true.dat | 68 +- .../score_current/inputs_true.dat | 32 +- tests/regression_tests/source/inputs_true.dat | 66 +- .../source_dlopen/inputs_true.dat | 16 +- .../inputs_true.dat | 16 +- .../surface_source/inputs_true_read.dat | 16 +- .../surface_source/inputs_true_write.dat | 16 +- .../surface_tally/inputs_true.dat | 32 +- .../regression_tests/tallies/inputs_true.dat | 334 +-- .../tally_aggregation/inputs_true.dat | 34 +- .../tally_arithmetic/inputs_true.dat | 24 +- .../tally_slice_merge/inputs_true.dat | 334 +-- tests/regression_tests/torus/inputs_true.dat | 34 +- .../torus/large_major/inputs_true.dat | 20 +- .../inputs_true.dat | 8 +- tests/regression_tests/triso/inputs_true.dat | 788 +++---- .../unstructured_mesh/inputs_true.dat | 66 +- .../unstructured_mesh/inputs_true0.dat | 66 +- .../unstructured_mesh/inputs_true1.dat | 66 +- .../unstructured_mesh/inputs_true10.dat | 66 +- .../unstructured_mesh/inputs_true11.dat | 66 +- .../unstructured_mesh/inputs_true12.dat | 66 +- .../unstructured_mesh/inputs_true13.dat | 66 +- .../unstructured_mesh/inputs_true14.dat | 66 +- .../unstructured_mesh/inputs_true15.dat | 66 +- .../unstructured_mesh/inputs_true2.dat | 66 +- .../unstructured_mesh/inputs_true3.dat | 66 +- .../unstructured_mesh/inputs_true4.dat | 68 +- .../unstructured_mesh/inputs_true5.dat | 68 +- .../unstructured_mesh/inputs_true6.dat | 68 +- .../unstructured_mesh/inputs_true7.dat | 68 +- .../unstructured_mesh/inputs_true8.dat | 66 +- .../unstructured_mesh/inputs_true9.dat | 66 +- tests/regression_tests/void/inputs_true.dat | 206 +- .../volume_calc/inputs_true.dat | 38 +- .../volume_calc/inputs_true_mg.dat | 36 +- .../weightwindows/inputs_true.dat | 48 +- tests/unit_tests/test_cell.py | 2 +- tests/unit_tests/test_deplete_nuclide.py | 4 +- tests/unit_tests/test_geometry.py | 2 +- tests/unit_tests/test_lattice.py | 2 +- tests/unit_tests/test_universe.py | 2 +- 126 files changed, 4023 insertions(+), 4043 deletions(-) diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt index 9591d482f60..df033351705 100644 --- a/docs/requirements-rtd.txt +++ b/docs/requirements-rtd.txt @@ -10,3 +10,4 @@ h5py pandas uncertainties matplotlib +lxml diff --git a/openmc/_xml.py b/openmc/_xml.py index 78bcbc264f5..b40ecb258a9 100644 --- a/openmc/_xml.py +++ b/openmc/_xml.py @@ -43,7 +43,7 @@ def get_text(elem, name, default=None): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element Element from which to search name : str Name of attribute/subelement @@ -68,7 +68,7 @@ def reorder_attributes(root): Parameters ---------- - root : xml.etree.ElementTree.Element + root : lxml.etree._Element Root element """ @@ -86,7 +86,7 @@ def get_elem_tuple(elem, name, dtype=int): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element that should contain a tuple name : str Name of the subelement to obtain tuple from diff --git a/openmc/cell.py b/openmc/cell.py index 67735ef5e92..5797bc0f622 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -2,7 +2,7 @@ from collections.abc import Iterable from math import cos, sin, pi from numbers import Real -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np from uncertainties import UFloat @@ -565,7 +565,7 @@ def create_xml_subelement(self, xml_element, memo=None): Parameters ---------- - xml_element : xml.etree.ElementTree.Element + xml_element : lxml.etree._Element XML element to be added to memo : set or None @@ -653,7 +653,7 @@ def from_xml_element(cls, elem, surfaces, materials, get_universe): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element `` element surfaces : dict Dictionary mapping surface IDs to :class:`openmc.Surface` instances diff --git a/openmc/data/library.py b/openmc/data/library.py index 5cafd196176..210270749ac 100644 --- a/openmc/data/library.py +++ b/openmc/data/library.py @@ -1,5 +1,5 @@ import os -import xml.etree.ElementTree as ET +import lxml.etree as ET import pathlib import h5py diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index 5e3157f9041..d23cf374cdb 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -19,15 +19,7 @@ from openmc.exceptions import DataError from .nuclide import FissionYieldDistribution -# Try to use lxml if it is available. It preserves the order of attributes and -# provides a pretty-printer by default. If not available, -# use OpenMC function to pretty print. -try: - import lxml.etree as ET - _have_lxml = True -except ImportError: - import xml.etree.ElementTree as ET - _have_lxml = False +import lxml.etree as ET import scipy.sparse as sp import openmc.data @@ -565,11 +557,7 @@ def export_to_xml(self, filename): root_elem.append(nuclide.to_xml_element()) tree = ET.ElementTree(root_elem) - if _have_lxml: - tree.write(str(filename), encoding='utf-8', pretty_print=True) - else: - clean_indentation(root_elem) - tree.write(str(filename), encoding='utf-8') + tree.write(str(filename), encoding='utf-8', pretty_print=True) def get_default_fission_yields(self): """Return fission yields at lowest incident neutron energy diff --git a/openmc/deplete/nuclide.py b/openmc/deplete/nuclide.py index 2e9673d5f7a..e2067a8e359 100644 --- a/openmc/deplete/nuclide.py +++ b/openmc/deplete/nuclide.py @@ -1,4 +1,4 @@ -"""Nuclide module. +"""Nuclide module.xml.etree.Ele Contains the per-nuclide components of a depletion chain. """ @@ -8,10 +8,7 @@ from collections import namedtuple, defaultdict from warnings import warn from numbers import Real -try: - import lxml.etree as ET -except ImportError: - import xml.etree.ElementTree as ET +import lxml.etree as ET import numpy as np @@ -212,9 +209,9 @@ def from_xml(cls, element, root=None, fission_q=None): Parameters ---------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element to read nuclide data from - root : xml.etree.ElementTree.Element, optional + root : lxml.etree._Element, optional Root XML element for chain file (only used when fission product yields are borrowed from another parent) fission_q : None or float @@ -297,7 +294,7 @@ def to_xml_element(self): Returns ------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element to write nuclide data to """ @@ -318,13 +315,7 @@ def to_xml_element(self): # Write decay sources if self.sources: for particle, source in self.sources.items(): - # TODO: Ugly hack to deal with the fact that - # 'source.to_xml_element' will return an xml.etree object - # whereas here lxml is being used preferentially. We should just - # switch to use lxml everywhere - import xml.etree.ElementTree as etree - src_elem_xmletree = source.to_xml_element('source') - src_elem = ET.fromstring(etree.tostring(src_elem_xmletree)) + src_elem = source.to_xml_element('source') src_elem.set('particle', particle) elem.append(src_elem) @@ -529,7 +520,7 @@ def from_xml_element(cls, element): Parameters ---------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element to pull fission yield data from Returns @@ -551,7 +542,7 @@ def to_xml_element(self, root): Parameters ---------- - root : xml.etree.ElementTree.Element + root : lxml.etree._Element Element to write distribution data to """ for energy, yield_obj in self.items(): diff --git a/openmc/element.py b/openmc/element.py index f1a5d31d3eb..bc3195aea4b 100644 --- a/openmc/element.py +++ b/openmc/element.py @@ -1,6 +1,6 @@ from collections import OrderedDict import re -from xml.etree import ElementTree as ET +import lxml.etree as ET import openmc.checkvalue as cv import openmc diff --git a/openmc/filter.py b/openmc/filter.py index 5233908c8da..1ad2892783a 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -4,8 +4,8 @@ import hashlib from itertools import product from numbers import Real, Integral +import lxml.etree as ET import warnings -from xml.etree import ElementTree as ET import numpy as np import pandas as pd @@ -229,7 +229,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -247,7 +247,7 @@ def from_xml_element(cls, elem, **kwargs): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element **kwargs Keyword arguments (e.g., mesh information) @@ -662,7 +662,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -938,7 +938,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -1284,7 +1284,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ @@ -2120,7 +2120,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing filter data """ diff --git a/openmc/filter_expansion.py b/openmc/filter_expansion.py index 1c07f58b717..f05f39fe9b6 100644 --- a/openmc/filter_expansion.py +++ b/openmc/filter_expansion.py @@ -1,5 +1,5 @@ from numbers import Integral, Real -from xml.etree import ElementTree as ET +import lxml.etree as ET import openmc.checkvalue as cv from . import Filter @@ -33,7 +33,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Legendre filter data """ @@ -218,7 +218,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Legendre filter data """ @@ -323,7 +323,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spherical harmonics filter data """ @@ -473,7 +473,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Zernike filter data """ diff --git a/openmc/geometry.py b/openmc/geometry.py index dbfce731fc6..9038895b84b 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -6,7 +6,7 @@ from collections.abc import Iterable from pathlib import Path import warnings -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np @@ -172,7 +172,7 @@ def from_xml_element(cls, elem, materials=None) -> Geometry: Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element materials : openmc.Materials or None Materials used to assign to cells. If None, an attempt is made to diff --git a/openmc/lattice.py b/openmc/lattice.py index b067b47a3d0..37faaf00fc2 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -5,7 +5,7 @@ from math import sqrt, floor from numbers import Real import types -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np @@ -833,7 +833,7 @@ def create_xml_subelement(self, xml_element, memo=None): Parameters ---------- - xml_element : xml.etree.ElementTree.Element + xml_element : lxml.etree._Element XML element to be added to memo : set or None @@ -932,7 +932,7 @@ def from_xml_element(cls, elem, get_universe): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element `` element get_universe : function Function returning universe (defined in @@ -1502,7 +1502,7 @@ def from_xml_element(cls, elem, get_universe): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element `` element get_universe : function Function returning universe (defined in diff --git a/openmc/material.py b/openmc/material.py index c84ff8c276d..20041aa53c7 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -8,7 +8,7 @@ import typing # imported separately as py3.8 requires typing.Iterable import warnings from typing import Optional, List, Union, Dict -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np import h5py @@ -1274,7 +1274,7 @@ def to_xml_element(self) -> ET.Element: Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing material data """ @@ -1442,7 +1442,7 @@ def from_xml_element(cls, elem: ET.Element) -> Material: Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1598,7 +1598,7 @@ def _write_xml(self, file, header=True, level=0, spaces_per_level=2, trailing_in element.tail = element.tail.strip(' ') file.write((level+1)*spaces_per_level*' ') reorder_attributes(element) # TODO: Remove when support is Python 3.8+ - ET.ElementTree(element).write(file, encoding='unicode') + file.write(ET.tostring(element, encoding="unicode")) # Write the elements. for material in sorted(self, key=lambda x: x.id): @@ -1607,7 +1607,7 @@ def _write_xml(self, file, header=True, level=0, spaces_per_level=2, trailing_in element.tail = element.tail.strip(' ') file.write((level+1)*spaces_per_level*' ') reorder_attributes(element) # TODO: Remove when support is Python 3.8+ - ET.ElementTree(element).write(file, encoding='unicode') + file.write(ET.tostring(element, encoding="unicode")) # Write the closing tag for the root element. file.write(indentation+'\n') @@ -1644,7 +1644,7 @@ def from_xml_element(cls, elem) -> Material: Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns diff --git a/openmc/mesh.py b/openmc/mesh.py index f606b852613..c4f74437922 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -5,7 +5,7 @@ from numbers import Real, Integral from pathlib import Path import warnings -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np @@ -103,7 +103,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -568,7 +568,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -598,7 +598,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -949,7 +949,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -971,7 +971,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -1239,7 +1239,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -1268,7 +1268,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1488,7 +1488,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -1517,7 +1517,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1940,7 +1940,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mesh data """ @@ -1963,7 +1963,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1984,7 +1984,7 @@ def _read_meshes(elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1998,4 +1998,4 @@ def _read_meshes(elem): mesh = MeshBase.from_xml_element(mesh_elem) out[mesh.id] = mesh - return out \ No newline at end of file + return out diff --git a/openmc/model/model.py b/openmc/model/model.py index 933e1172e49..ede21c64e09 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -7,7 +7,7 @@ from numbers import Integral from tempfile import NamedTemporaryFile import warnings -from xml.etree import ElementTree as ET +import lxml.etree as ET from typing import Optional, Dict import h5py @@ -527,17 +527,17 @@ def export_to_model_xml(self, path='model.xml', remove_surfs=False): # This will write the XML header also materials._write_xml(fh, False, level=1) # Write remaining elements as a tree - ET.ElementTree(geometry_element).write(fh, encoding='unicode') - ET.ElementTree(settings_element).write(fh, encoding='unicode') + fh.write(ET.tostring(geometry_element, encoding="unicode")) + fh.write(ET.tostring(settings_element, encoding="unicode")) if self.tallies: tallies_element = self.tallies.to_xml_element(mesh_memo) xml.clean_indentation(tallies_element, level=1, trailing_indent=self.plots) - ET.ElementTree(tallies_element).write(fh, encoding='unicode') + fh.write(ET.tostring(tallies_element, encoding="unicode")) if self.plots: plots_element = self.plots.to_xml_element() xml.clean_indentation(plots_element, level=1, trailing_indent=False) - ET.ElementTree(plots_element).write(fh, encoding='unicode') + fh.write(ET.tostring(plots_element, encoding="unicode")) fh.write("\n") def import_properties(self, filename): diff --git a/openmc/plots.py b/openmc/plots.py index 67b65440a2c..5d8cf9ba40e 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -1,8 +1,8 @@ from collections.abc import Iterable, Mapping from numbers import Integral, Real from pathlib import Path +import lxml.etree as ET from typing import Optional -from xml.etree import ElementTree as ET import h5py import numpy as np @@ -476,7 +476,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing plot data """ @@ -776,7 +776,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing plot data """ @@ -833,7 +833,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1170,7 +1170,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing plot data """ @@ -1254,7 +1254,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1428,7 +1428,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing all plot elements """ @@ -1469,7 +1469,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns diff --git a/openmc/settings.py b/openmc/settings.py index aa4276cd52e..12703fbfd3a 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -8,7 +8,7 @@ from pathlib import Path import typing # required to prevent typing.Union namespace overwriting Union from typing import Optional -from xml.etree import ElementTree as ET +import lxml.etree as ET import openmc.checkvalue as cv from openmc.stats.multivariate import MeshSpatial @@ -1706,7 +1706,7 @@ def from_xml_element(cls, elem, meshes=None): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element meshes : dict or None A dictionary with mesh IDs as keys and mesh instances as values that diff --git a/openmc/source.py b/openmc/source.py index 7f88bcd527d..9851ea59d3c 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -5,7 +5,7 @@ import typing # imported separately as py3.8 requires typing.Iterable # also required to prevent typing.Union namespace overwriting Union from typing import Optional, Sequence -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np import h5py @@ -228,7 +228,7 @@ def to_xml_element(self) -> ET.Element: Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -263,7 +263,7 @@ def from_xml_element(cls, elem: ET.Element, meshes=None) -> 'openmc.Source': Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element meshes : dict Dictionary with mesh IDs as keys and openmc.MeshBase instaces as diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index 7372020b01c..190dfd64d00 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -2,7 +2,7 @@ from collections.abc import Iterable from math import pi, cos from numbers import Real -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np @@ -121,7 +121,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing angular distribution data """ @@ -139,7 +139,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -168,7 +168,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing isotropic distribution data """ @@ -182,7 +182,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -217,7 +217,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing monodirectional distribution data """ @@ -233,7 +233,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -341,7 +341,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spatial distribution data """ @@ -358,7 +358,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -464,7 +464,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spatial distribution data """ @@ -482,7 +482,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -586,7 +586,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spatial distribution data """ @@ -604,7 +604,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -698,7 +698,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing spatial distribution data """ @@ -719,7 +719,7 @@ def from_xml_element(cls, elem, meshes): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element meshes : dict A dictionary with mesh IDs as keys and openmc.MeshBase instances as @@ -811,7 +811,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing box distribution data """ @@ -831,7 +831,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -883,7 +883,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing point distribution location """ @@ -899,7 +899,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index 240f13d1432..b98b87d6f42 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -5,7 +5,7 @@ import math from numbers import Real from warnings import warn -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np @@ -173,7 +173,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing discrete distribution data """ @@ -191,7 +191,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -316,7 +316,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing uniform distribution data """ @@ -331,7 +331,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -425,7 +425,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing distribution data """ @@ -440,7 +440,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -508,7 +508,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Maxwellian distribution data """ @@ -523,7 +523,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -603,7 +603,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Watt distribution data """ @@ -618,7 +618,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -693,7 +693,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing Watt distribution data """ @@ -708,7 +708,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -957,7 +957,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing tabular distribution data """ @@ -976,7 +976,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -1152,7 +1152,7 @@ def to_xml_element(self, element_name): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing mixture distribution data """ @@ -1174,7 +1174,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns diff --git a/openmc/surface.py b/openmc/surface.py index 5d13b39ff0a..b195c0af2b8 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -4,7 +4,7 @@ from copy import deepcopy import math from numbers import Real -from xml.etree import ElementTree as ET +import lxml.etree as ET from warnings import warn, catch_warnings, simplefilter import numpy as np @@ -393,7 +393,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -417,7 +417,7 @@ def from_xml_element(elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -624,7 +624,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -1280,7 +1280,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ @@ -1802,7 +1802,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing source data """ diff --git a/openmc/tallies.py b/openmc/tallies.py index 1a27e1bd493..492336f7e1c 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -5,7 +5,7 @@ from numbers import Integral, Real import operator from pathlib import Path -from xml.etree import ElementTree as ET +import lxml.etree as ET import h5py import numpy as np @@ -815,7 +815,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing tally data """ @@ -872,7 +872,7 @@ def from_xml_element(cls, elem, **kwargs): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns @@ -3226,7 +3226,7 @@ def from_xml_element(cls, elem, meshes=None): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element meshes : dict or None A dictionary with mesh IDs as keys and mesh instances as values that diff --git a/openmc/tally_derivative.py b/openmc/tally_derivative.py index 05a27681d51..d8e165e8bea 100644 --- a/openmc/tally_derivative.py +++ b/openmc/tally_derivative.py @@ -1,5 +1,5 @@ from numbers import Integral -from xml.etree import ElementTree as ET +import lxml.etree as ET import openmc.checkvalue as cv from .mixin import EqualityMixin, IDManagerMixin @@ -93,7 +93,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing derivative data """ @@ -112,7 +112,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns diff --git a/openmc/trigger.py b/openmc/trigger.py index c5151aa7e03..3f7d8d7d075 100644 --- a/openmc/trigger.py +++ b/openmc/trigger.py @@ -1,6 +1,6 @@ from collections.abc import Iterable from numbers import Real -from xml.etree import ElementTree as ET +import lxml.etree as ET import openmc.checkvalue as cv from .mixin import EqualityMixin @@ -79,7 +79,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing trigger data """ @@ -97,7 +97,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns diff --git a/openmc/universe.py b/openmc/universe.py index afe360094e6..dc88bdb0409 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -6,7 +6,7 @@ from numbers import Integral, Real from pathlib import Path from tempfile import TemporaryDirectory -from xml.etree import ElementTree as ET +import lxml.etree as ET from warnings import warn import h5py @@ -117,7 +117,7 @@ def create_xml_subelement(self, xml_element, memo=None): Parameters ---------- - xml_element : xml.etree.ElementTree.Element + xml_element : lxml.etree._Element XML element to be added to memo : set or None @@ -1048,7 +1048,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element `` element Returns diff --git a/openmc/volume.py b/openmc/volume.py index 5411b3c1d61..363b108c9f2 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -1,7 +1,7 @@ from collections import OrderedDict from collections.abc import Iterable, Mapping from numbers import Real, Integral -from xml.etree import ElementTree as ET +import lxml.etree as ET import warnings import numpy as np @@ -333,7 +333,7 @@ def to_xml_element(self): Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing volume calculation data """ @@ -362,7 +362,7 @@ def from_xml_element(cls, elem): Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element Returns diff --git a/openmc/weight_windows.py b/openmc/weight_windows.py index 2993db089e0..c09e1e862ba 100644 --- a/openmc/weight_windows.py +++ b/openmc/weight_windows.py @@ -5,7 +5,7 @@ import typing from typing import Iterable, List, Optional, Union, Dict -from xml.etree import ElementTree as ET +import lxml.etree as ET import numpy as np import h5py @@ -313,7 +313,7 @@ def to_xml_element(self) -> ET.Element: Returns ------- - element : xml.etree.ElementTree.Element + element : lxml.etree._Element XML element containing the weight window information """ element = ET.Element('weight_windows') @@ -356,9 +356,9 @@ def from_xml_element(cls, elem: ET.Element, root: ET.Element) -> WeightWindows: Parameters ---------- - elem : xml.etree.ElementTree.Element + elem : lxml.etree._Element XML element - root : xml.etree.ElementTree.Element + root : lxml.etree._Element Root element for the file where meshes can be found Returns diff --git a/tests/regression_tests/adj_cell_rotation/inputs_true.dat b/tests/regression_tests/adj_cell_rotation/inputs_true.dat index 1c4516f42dd..48774bb020f 100644 --- a/tests/regression_tests/adj_cell_rotation/inputs_true.dat +++ b/tests/regression_tests/adj_cell_rotation/inputs_true.dat @@ -2,27 +2,27 @@ - - + + - - + + - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/asymmetric_lattice/inputs_true.dat b/tests/regression_tests/asymmetric_lattice/inputs_true.dat index b247412e51c..6a09b10a321 100644 --- a/tests/regression_tests/asymmetric_lattice/inputs_true.dat +++ b/tests/regression_tests/asymmetric_lattice/inputs_true.dat @@ -2,162 +2,162 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + 1.26 1.26 17 17 @@ -190,18 +190,18 @@ 8 8 8 7 7 7 - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/cpp_driver/inputs_true.dat b/tests/regression_tests/cpp_driver/inputs_true.dat index cdace34f057..5d067cb6854 100644 --- a/tests/regression_tests/cpp_driver/inputs_true.dat +++ b/tests/regression_tests/cpp_driver/inputs_true.dat @@ -2,25 +2,25 @@ - - + + - - + + - - - + + + - - - - - + + + + + 4.0 4.0 2 2 @@ -29,12 +29,12 @@ 2 2 2 2 - - - - - - + + + + + + eigenvalue diff --git a/tests/regression_tests/create_fission_neutrons/inputs_true.dat b/tests/regression_tests/create_fission_neutrons/inputs_true.dat index f79ba379c43..8ee6f8b64f7 100644 --- a/tests/regression_tests/create_fission_neutrons/inputs_true.dat +++ b/tests/regression_tests/create_fission_neutrons/inputs_true.dat @@ -2,19 +2,19 @@ - - - + + + - - - - - - - + + + + + + + fixed source @@ -24,7 +24,7 @@ -1 -1 -1 1 1 1 - + false diff --git a/tests/regression_tests/dagmc/external/inputs_true.dat b/tests/regression_tests/dagmc/external/inputs_true.dat index 5547f333cf1..7237f4d4632 100644 --- a/tests/regression_tests/dagmc/external/inputs_true.dat +++ b/tests/regression_tests/dagmc/external/inputs_true.dat @@ -2,18 +2,18 @@ - - + + - - - - + + + + - + eigenvalue diff --git a/tests/regression_tests/dagmc/legacy/inputs_true.dat b/tests/regression_tests/dagmc/legacy/inputs_true.dat index 89d458a2b83..b6e5133a4f6 100644 --- a/tests/regression_tests/dagmc/legacy/inputs_true.dat +++ b/tests/regression_tests/dagmc/legacy/inputs_true.dat @@ -2,18 +2,18 @@ - - + + - - - - + + + + - + eigenvalue diff --git a/tests/regression_tests/dagmc/refl/inputs_true.dat b/tests/regression_tests/dagmc/refl/inputs_true.dat index 894d5010490..126702e3886 100644 --- a/tests/regression_tests/dagmc/refl/inputs_true.dat +++ b/tests/regression_tests/dagmc/refl/inputs_true.dat @@ -3,7 +3,7 @@ - + eigenvalue diff --git a/tests/regression_tests/dagmc/universes/inputs_true.dat b/tests/regression_tests/dagmc/universes/inputs_true.dat index b88e83df408..babf43ff1d8 100644 --- a/tests/regression_tests/dagmc/universes/inputs_true.dat +++ b/tests/regression_tests/dagmc/universes/inputs_true.dat @@ -2,32 +2,32 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - + + 24.0 24.0 2 2 @@ -36,12 +36,12 @@ 1 1 1 1 - - - - - - + + + + + + eigenvalue diff --git a/tests/regression_tests/dagmc/uwuw/inputs_true.dat b/tests/regression_tests/dagmc/uwuw/inputs_true.dat index 07384b62524..e6537a30e03 100644 --- a/tests/regression_tests/dagmc/uwuw/inputs_true.dat +++ b/tests/regression_tests/dagmc/uwuw/inputs_true.dat @@ -3,7 +3,7 @@ - + eigenvalue diff --git a/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml b/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml index d38e8f96f14..fc0b87eb05b 100644 --- a/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml +++ b/tests/regression_tests/deplete_with_transport/last_step_reference_materials.xml @@ -1,1057 +1,1057 @@ - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - + + + + + diff --git a/tests/regression_tests/diff_tally/inputs_true.dat b/tests/regression_tests/diff_tally/inputs_true.dat index 99697a1e9a6..5fad7175d82 100644 --- a/tests/regression_tests/diff_tally/inputs_true.dat +++ b/tests/regression_tests/diff_tally/inputs_true.dat @@ -2,181 +2,181 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 17 17 @@ -277,23 +277,23 @@ 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + eigenvalue @@ -429,10 +429,10 @@ nu-fission scatter 5 - - - - - + + + + + diff --git a/tests/regression_tests/distribmat/inputs_true.dat b/tests/regression_tests/distribmat/inputs_true.dat index adc9bf3fbe1..d002f0beb50 100644 --- a/tests/regression_tests/distribmat/inputs_true.dat +++ b/tests/regression_tests/distribmat/inputs_true.dat @@ -2,24 +2,24 @@ - - - + + + - - + + - - + + - - - - + + + + 2.0 2.0 1 @@ -29,11 +29,11 @@ 11 11 11 11 - - - - - + + + + + eigenvalue diff --git a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat index 225b23ffa63..690cd14e356 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat +++ b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat @@ -2,13 +2,13 @@ - - + + - - + + eigenvalue diff --git a/tests/regression_tests/energy_cutoff/inputs_true.dat b/tests/regression_tests/energy_cutoff/inputs_true.dat index e874a0c7a51..c24164dd8bd 100644 --- a/tests/regression_tests/energy_cutoff/inputs_true.dat +++ b/tests/regression_tests/energy_cutoff/inputs_true.dat @@ -2,18 +2,18 @@ - - + + - - - - - - - + + + + + + + fixed source @@ -23,7 +23,7 @@ -1 -1 -1 1 1 1 - + 4.0 diff --git a/tests/regression_tests/energy_laws/inputs_true.dat b/tests/regression_tests/energy_laws/inputs_true.dat index c89ccc97ee0..4d8e825d1b5 100644 --- a/tests/regression_tests/energy_laws/inputs_true.dat +++ b/tests/regression_tests/energy_laws/inputs_true.dat @@ -2,17 +2,17 @@ - - - - - - + + + + + + - - + + eigenvalue diff --git a/tests/regression_tests/external_moab/inputs_true.dat b/tests/regression_tests/external_moab/inputs_true.dat index 2bcbad0df25..d54f5db0ef2 100644 --- a/tests/regression_tests/external_moab/inputs_true.dat +++ b/tests/regression_tests/external_moab/inputs_true.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -50,7 +50,7 @@ 0.0 0.0 0.0 - + 15000000.0 1.0 diff --git a/tests/regression_tests/filter_cellinstance/inputs_true.dat b/tests/regression_tests/filter_cellinstance/inputs_true.dat index d00aae75d2d..d3e0937ec05 100644 --- a/tests/regression_tests/filter_cellinstance/inputs_true.dat +++ b/tests/regression_tests/filter_cellinstance/inputs_true.dat @@ -2,21 +2,21 @@ - - + + - - + + - - - - - - + + + + + + 2 2 4 4 @@ -27,12 +27,12 @@ 3 3 2 3 3 3 3 2 - - - - - - + + + + + + eigenvalue diff --git a/tests/regression_tests/filter_energyfun/inputs_true.dat b/tests/regression_tests/filter_energyfun/inputs_true.dat index 706c70e34f2..4b7b74d28ec 100644 --- a/tests/regression_tests/filter_energyfun/inputs_true.dat +++ b/tests/regression_tests/filter_energyfun/inputs_true.dat @@ -2,13 +2,13 @@ - - + + - - + + eigenvalue diff --git a/tests/regression_tests/filter_mesh/inputs_true.dat b/tests/regression_tests/filter_mesh/inputs_true.dat index d0b617903f5..a58d58bab95 100644 --- a/tests/regression_tests/filter_mesh/inputs_true.dat +++ b/tests/regression_tests/filter_mesh/inputs_true.dat @@ -2,27 +2,27 @@ - - + + - - + + - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/filter_translations/inputs_true.dat b/tests/regression_tests/filter_translations/inputs_true.dat index 8ed705413e7..a80ccd87675 100644 --- a/tests/regression_tests/filter_translations/inputs_true.dat +++ b/tests/regression_tests/filter_translations/inputs_true.dat @@ -2,27 +2,27 @@ - - + + - - + + - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/fixed_source/inputs_true.dat b/tests/regression_tests/fixed_source/inputs_true.dat index 57dcdb7248d..60043f20c95 100644 --- a/tests/regression_tests/fixed_source/inputs_true.dat +++ b/tests/regression_tests/fixed_source/inputs_true.dat @@ -2,14 +2,14 @@ - - - + + + - - + + fixed source diff --git a/tests/regression_tests/iso_in_lab/inputs_true.dat b/tests/regression_tests/iso_in_lab/inputs_true.dat index 6dd8578fffa..2bb81da6dc6 100644 --- a/tests/regression_tests/iso_in_lab/inputs_true.dat +++ b/tests/regression_tests/iso_in_lab/inputs_true.dat @@ -2,193 +2,193 @@ - - - - - - + + + + + + U234 U235 U238 Xe135 O16 - - - - - - + + + + + + Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - + + + + + + H1 O16 B10 B11 - - - - - - + + + + + + H1 O16 B10 B11 - - - - - - - - - - - + + + + + + + + + + + Fe54 Fe56 Fe57 Fe58 Ni58 Ni60 Mn55 Cr52 C0 Cu63 - - - - - - - - - - - - - + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - - - + + + + + + + + + + + + + H1 O16 B10 B11 Fe54 Fe56 Fe57 Fe58 Ni58 Mn55 Cr52 - - - - - - - - - - - + + + + + + + + + + + H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - - - - - - + + + + + + + + + + + H1 O16 B10 B11 Zr90 Zr91 Zr92 Zr94 Zr96 - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 17 17 @@ -289,23 +289,23 @@ 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat index 639235726cc..c51a38c8938 100644 --- a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat @@ -2,43 +2,43 @@ - - + + - - - + + + - - - - - + + + + + - - + + - - - - - - + + + + + + - - - - - - - - + + + + + + + + 1.4 3 @@ -50,18 +50,18 @@ 2 2 2 - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/lattice_hex_x/inputs_true.dat b/tests/regression_tests/lattice_hex_x/inputs_true.dat index 2cff10f757b..c510120291b 100644 --- a/tests/regression_tests/lattice_hex_x/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_x/inputs_true.dat @@ -2,47 +2,47 @@ - - - - + + + + - - - - - + + + + + - - - - + + + + - - - - - - + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + 1.235 5.0 4 @@ -91,22 +91,22 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/lattice_multiple/inputs_true.dat b/tests/regression_tests/lattice_multiple/inputs_true.dat index 0eed3c2015a..b249d97c40e 100644 --- a/tests/regression_tests/lattice_multiple/inputs_true.dat +++ b/tests/regression_tests/lattice_multiple/inputs_true.dat @@ -2,24 +2,24 @@ - - - + + + - - - - + + + + - - - - - - + + + + + + 1.2 1.2 1 @@ -37,12 +37,12 @@ 4 4 4 4 - - - - - - + + + + + + eigenvalue diff --git a/tests/regression_tests/lattice_rotated/inputs_true.dat b/tests/regression_tests/lattice_rotated/inputs_true.dat index 8e54bdf8847..3a8a0784e09 100644 --- a/tests/regression_tests/lattice_rotated/inputs_true.dat +++ b/tests/regression_tests/lattice_rotated/inputs_true.dat @@ -2,29 +2,29 @@ - - + + - - + + - - - - + + + + - - - - - - - - + + + + + + + + 1.25 30 @@ -51,11 +51,11 @@ 1 1 1 1 1 1 1 1 - - - - - + + + + + eigenvalue diff --git a/tests/regression_tests/mg_basic/inputs_true.dat b/tests/regression_tests/mg_basic/inputs_true.dat index 06406b5f2cf..5ec5ade759d 100644 --- a/tests/regression_tests/mg_basic/inputs_true.dat +++ b/tests/regression_tests/mg_basic/inputs_true.dat @@ -3,45 +3,45 @@ 2g.h5 - - + + - - + + - - + + - - + + - - + + - - - + + + - - - - - - - - - - - - - + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mg_basic_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat index 05108d87dc1..b3f1993d91f 100644 --- a/tests/regression_tests/mg_basic_delayed/inputs_true.dat +++ b/tests/regression_tests/mg_basic_delayed/inputs_true.dat @@ -3,44 +3,44 @@ 2g.h5 - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mg_convert/inputs_true.dat b/tests/regression_tests/mg_convert/inputs_true.dat index 9276a7a7b65..8277ca483aa 100644 --- a/tests/regression_tests/mg_convert/inputs_true.dat +++ b/tests/regression_tests/mg_convert/inputs_true.dat @@ -3,16 +3,16 @@ mgxs.h5 - - + + - - - - - + + + + + eigenvalue diff --git a/tests/regression_tests/mg_legendre/inputs_true.dat b/tests/regression_tests/mg_legendre/inputs_true.dat index d90dfb80292..4b7293d81af 100644 --- a/tests/regression_tests/mg_legendre/inputs_true.dat +++ b/tests/regression_tests/mg_legendre/inputs_true.dat @@ -3,14 +3,14 @@ 2g.h5 - - + + - - - + + + eigenvalue diff --git a/tests/regression_tests/mg_max_order/inputs_true.dat b/tests/regression_tests/mg_max_order/inputs_true.dat index 9bfcd54dfe8..82699d00ec2 100644 --- a/tests/regression_tests/mg_max_order/inputs_true.dat +++ b/tests/regression_tests/mg_max_order/inputs_true.dat @@ -3,14 +3,14 @@ 2g.h5 - - + + - - - + + + eigenvalue diff --git a/tests/regression_tests/mg_survival_biasing/inputs_true.dat b/tests/regression_tests/mg_survival_biasing/inputs_true.dat index a3a2a726f23..2b5801e120c 100644 --- a/tests/regression_tests/mg_survival_biasing/inputs_true.dat +++ b/tests/regression_tests/mg_survival_biasing/inputs_true.dat @@ -3,14 +3,14 @@ 2g.h5 - - + + - - - + + + eigenvalue diff --git a/tests/regression_tests/mg_tallies/inputs_true.dat b/tests/regression_tests/mg_tallies/inputs_true.dat index bdd41c7f85a..b7d362b17eb 100644 --- a/tests/regression_tests/mg_tallies/inputs_true.dat +++ b/tests/regression_tests/mg_tallies/inputs_true.dat @@ -3,14 +3,14 @@ 2g.h5 - - + + - - - + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat index 533160577d7..74067874adf 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat index fe154a01807..13a6ea6d413 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_condense/inputs_true.dat b/tests/regression_tests/mgxs_library_condense/inputs_true.dat index c8f140f8082..ce709576596 100644 --- a/tests/regression_tests/mgxs_library_condense/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_condense/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_correction/inputs_true.dat b/tests/regression_tests/mgxs_library_correction/inputs_true.dat index a1cc111def4..4d9dbecd620 100644 --- a/tests/regression_tests/mgxs_library_correction/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_correction/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat index 895389fb97f..893e0b3bf22 100644 --- a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat @@ -2,37 +2,37 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - + + + + + + + 1.26 1.26 17 17 @@ -56,12 +56,12 @@ 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 - - - - - - + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat index c8f140f8082..ce709576596 100644 --- a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat index 0ea55bb0404..f45b7dbf3ee 100644 --- a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat index b18e9773b17..bb9c99026d0 100644 --- a/tests/regression_tests/mgxs_library_mesh/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_mesh/inputs_true.dat @@ -2,27 +2,27 @@ - - + + - - + + - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat index 54d095ac623..0608d6f966e 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat index 5e9720cedc3..215bb7c9fd5 100644 --- a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat index 938b1c19d1b..907bf43ccc4 100644 --- a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat @@ -2,39 +2,39 @@ - - - - - + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat b/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat index 1c4516f42dd..48774bb020f 100644 --- a/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat +++ b/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat @@ -2,27 +2,27 @@ - - + + - - + + - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/model_xml/energy_laws_inputs_true.dat b/tests/regression_tests/model_xml/energy_laws_inputs_true.dat index c89ccc97ee0..4d8e825d1b5 100644 --- a/tests/regression_tests/model_xml/energy_laws_inputs_true.dat +++ b/tests/regression_tests/model_xml/energy_laws_inputs_true.dat @@ -2,17 +2,17 @@ - - - - - - + + + + + + - - + + eigenvalue diff --git a/tests/regression_tests/model_xml/inputs_true.dat b/tests/regression_tests/model_xml/inputs_true.dat index c408026316c..c1ef1366586 100644 --- a/tests/regression_tests/model_xml/inputs_true.dat +++ b/tests/regression_tests/model_xml/inputs_true.dat @@ -2,18 +2,18 @@ - - + + - - - - - - - + + + + + + + fixed source @@ -23,7 +23,7 @@ 0 0 0 - + 14000000.0 1.0 diff --git a/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat b/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat index 0eed3c2015a..b249d97c40e 100644 --- a/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat +++ b/tests/regression_tests/model_xml/lattice_multiple_inputs_true.dat @@ -2,24 +2,24 @@ - - - + + + - - - - + + + + - - - - - - + + + + + + 1.2 1.2 1 @@ -37,12 +37,12 @@ 4 4 4 4 - - - - - - + + + + + + eigenvalue diff --git a/tests/regression_tests/model_xml/photon_production_inputs_true.dat b/tests/regression_tests/model_xml/photon_production_inputs_true.dat index 0b2b434681a..109b54c6755 100644 --- a/tests/regression_tests/model_xml/photon_production_inputs_true.dat +++ b/tests/regression_tests/model_xml/photon_production_inputs_true.dat @@ -2,18 +2,18 @@ - - + + - - - - - - - + + + + + + + fixed source @@ -23,7 +23,7 @@ 0 0 0 - + 14000000.0 1.0 diff --git a/tests/regression_tests/multipole/inputs_true.dat b/tests/regression_tests/multipole/inputs_true.dat index 3a602b28b8d..5c905afb9cb 100644 --- a/tests/regression_tests/multipole/inputs_true.dat +++ b/tests/regression_tests/multipole/inputs_true.dat @@ -2,21 +2,21 @@ - - - - + + + + - - + + - - - - + + + + 2.0 2.0 1 @@ -26,11 +26,11 @@ 11 11 11 11 - - - - - + + + + + eigenvalue diff --git a/tests/regression_tests/ncrystal/inputs_true.dat b/tests/regression_tests/ncrystal/inputs_true.dat index a609edcae4e..be2336cf08d 100644 --- a/tests/regression_tests/ncrystal/inputs_true.dat +++ b/tests/regression_tests/ncrystal/inputs_true.dat @@ -2,15 +2,15 @@ - - + + - - - - + + + + fixed source @@ -20,7 +20,7 @@ 0 0 -20 - + 0.012 1.0 diff --git a/tests/regression_tests/periodic/inputs_true.dat b/tests/regression_tests/periodic/inputs_true.dat index 9934e2de04b..9d50c2b7287 100644 --- a/tests/regression_tests/periodic/inputs_true.dat +++ b/tests/regression_tests/periodic/inputs_true.dat @@ -2,26 +2,26 @@ - - - - + + + + - - + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/periodic_6fold/inputs_true.dat b/tests/regression_tests/periodic_6fold/inputs_true.dat index 9c2899417ef..795ce818faa 100644 --- a/tests/regression_tests/periodic_6fold/inputs_true.dat +++ b/tests/regression_tests/periodic_6fold/inputs_true.dat @@ -2,23 +2,23 @@ - - - - + + + + - - + + - - - - - - + + + + + + eigenvalue diff --git a/tests/regression_tests/periodic_hex/inputs_true.dat b/tests/regression_tests/periodic_hex/inputs_true.dat index f4869fa58bd..188c8dfa93f 100644 --- a/tests/regression_tests/periodic_hex/inputs_true.dat +++ b/tests/regression_tests/periodic_hex/inputs_true.dat @@ -2,18 +2,18 @@ - - + + - - - - - - - + + + + + + + eigenvalue diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index 0b2b434681a..109b54c6755 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -2,18 +2,18 @@ - - + + - - - - - - - + + + + + + + fixed source @@ -23,7 +23,7 @@ 0 0 0 - + 14000000.0 1.0 diff --git a/tests/regression_tests/photon_production_fission/inputs_true.dat b/tests/regression_tests/photon_production_fission/inputs_true.dat index ea6e9d9ee3c..6a102cfdcea 100644 --- a/tests/regression_tests/photon_production_fission/inputs_true.dat +++ b/tests/regression_tests/photon_production_fission/inputs_true.dat @@ -2,13 +2,13 @@ - - + + - - + + eigenvalue diff --git a/tests/regression_tests/photon_source/inputs_true.dat b/tests/regression_tests/photon_source/inputs_true.dat index 4c61b47fca1..33ace2c700c 100644 --- a/tests/regression_tests/photon_source/inputs_true.dat +++ b/tests/regression_tests/photon_source/inputs_true.dat @@ -2,16 +2,16 @@ - - - - - + + + + + - - + + fixed source @@ -21,7 +21,7 @@ 0 0 0 - + 10000000.0 1.0 diff --git a/tests/regression_tests/resonance_scattering/inputs_true.dat b/tests/regression_tests/resonance_scattering/inputs_true.dat index 7165fa72b6f..6ab82ba245f 100644 --- a/tests/regression_tests/resonance_scattering/inputs_true.dat +++ b/tests/regression_tests/resonance_scattering/inputs_true.dat @@ -2,16 +2,16 @@ - - - - - + + + + + - - + + eigenvalue diff --git a/tests/regression_tests/salphabeta/inputs_true.dat b/tests/regression_tests/salphabeta/inputs_true.dat index 31a81b2c8ca..508624b75a7 100644 --- a/tests/regression_tests/salphabeta/inputs_true.dat +++ b/tests/regression_tests/salphabeta/inputs_true.dat @@ -2,49 +2,49 @@ - - - - + + + + - - - - + + + + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/score_current/inputs_true.dat b/tests/regression_tests/score_current/inputs_true.dat index f9c9ba494de..9ea8e5e4ae1 100644 --- a/tests/regression_tests/score_current/inputs_true.dat +++ b/tests/regression_tests/score_current/inputs_true.dat @@ -2,27 +2,27 @@ - - + + - - + + - - - - - - - - - - - - + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/source/inputs_true.dat b/tests/regression_tests/source/inputs_true.dat index adf60c8145b..460be7077da 100644 --- a/tests/regression_tests/source/inputs_true.dat +++ b/tests/regression_tests/source/inputs_true.dat @@ -2,13 +2,13 @@ - - + + - - + + eigenvalue @@ -17,7 +17,7 @@ 5 - + -4.0 -1.0 3.0 0.2 0.3 0.5 @@ -29,67 +29,67 @@ -1.0 0.0 1.0 0.5 0.25 0.25 - + - + -4.0 -4.0 -4.0 4.0 4.0 4.0 - - + + 1.2 -2.3 0.781 - + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - + 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 - + - + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - + + -2.0 0.0 2.0 0.2 0.3 0.2 - + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - - + + -2.0 0.0 2.0 0.2 0.3 0.2 - + - + - + @@ -100,19 +100,19 @@ - + 0.7071067811865476 0.0 -0.7071067811865475 0.3 0.4 0.3 - + - + - + - + @@ -120,23 +120,23 @@ - diff --git a/tests/regression_tests/source_dlopen/inputs_true.dat b/tests/regression_tests/source_dlopen/inputs_true.dat index 1a447ae3d2c..9d97164adfa 100644 --- a/tests/regression_tests/source_dlopen/inputs_true.dat +++ b/tests/regression_tests/source_dlopen/inputs_true.dat @@ -2,22 +2,22 @@ - - - - - + + + + + - - + + fixed source 1000 10 0 - + diff --git a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat index 208030e2e66..68946359351 100644 --- a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat +++ b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat @@ -2,22 +2,22 @@ - - - - - + + + + + - - + + fixed source 1000 10 0 - + diff --git a/tests/regression_tests/surface_source/inputs_true_read.dat b/tests/regression_tests/surface_source/inputs_true_read.dat index fb843a6d19d..14a55f0bf04 100644 --- a/tests/regression_tests/surface_source/inputs_true_read.dat +++ b/tests/regression_tests/surface_source/inputs_true_read.dat @@ -3,14 +3,14 @@ - - - - - - - - + + + + + + + + fixed source diff --git a/tests/regression_tests/surface_source/inputs_true_write.dat b/tests/regression_tests/surface_source/inputs_true_write.dat index dbdf22395b3..4747fcaf42b 100644 --- a/tests/regression_tests/surface_source/inputs_true_write.dat +++ b/tests/regression_tests/surface_source/inputs_true_write.dat @@ -3,14 +3,14 @@ - - - - - - - - + + + + + + + + fixed source diff --git a/tests/regression_tests/surface_tally/inputs_true.dat b/tests/regression_tests/surface_tally/inputs_true.dat index 1a89079557a..4be5d4e77a7 100644 --- a/tests/regression_tests/surface_tally/inputs_true.dat +++ b/tests/regression_tests/surface_tally/inputs_true.dat @@ -2,27 +2,27 @@ - - - - + + + + - - - - + + + + - - - - - - - - + + + + + + + + eigenvalue diff --git a/tests/regression_tests/tallies/inputs_true.dat b/tests/regression_tests/tallies/inputs_true.dat index e6725024ace..8d2e50af8cc 100644 --- a/tests/regression_tests/tallies/inputs_true.dat +++ b/tests/regression_tests/tallies/inputs_true.dat @@ -2,181 +2,181 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 17 17 @@ -277,23 +277,23 @@ 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/tally_aggregation/inputs_true.dat b/tests/regression_tests/tally_aggregation/inputs_true.dat index bb2dcddc56d..9f4f9565524 100644 --- a/tests/regression_tests/tally_aggregation/inputs_true.dat +++ b/tests/regression_tests/tally_aggregation/inputs_true.dat @@ -2,23 +2,23 @@ - - - - - + + + + + - - - - + + + + - - - + + + 1.2 1.2 1 @@ -28,11 +28,11 @@ 1 1 1 1 - - - - - + + + + + eigenvalue diff --git a/tests/regression_tests/tally_arithmetic/inputs_true.dat b/tests/regression_tests/tally_arithmetic/inputs_true.dat index 41760f3cf40..7669b4d0360 100644 --- a/tests/regression_tests/tally_arithmetic/inputs_true.dat +++ b/tests/regression_tests/tally_arithmetic/inputs_true.dat @@ -2,23 +2,23 @@ - - - - + + + + - - - - + + + + - - - - + + + + eigenvalue diff --git a/tests/regression_tests/tally_slice_merge/inputs_true.dat b/tests/regression_tests/tally_slice_merge/inputs_true.dat index 5b5731efbab..5dff76a6848 100644 --- a/tests/regression_tests/tally_slice_merge/inputs_true.dat +++ b/tests/regression_tests/tally_slice_merge/inputs_true.dat @@ -2,181 +2,181 @@ - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1.26 1.26 17 17 @@ -277,23 +277,23 @@ 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/torus/inputs_true.dat b/tests/regression_tests/torus/inputs_true.dat index c4aa2072a89..a5c7a8d7aee 100644 --- a/tests/regression_tests/torus/inputs_true.dat +++ b/tests/regression_tests/torus/inputs_true.dat @@ -2,28 +2,28 @@ - - + + - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/torus/large_major/inputs_true.dat b/tests/regression_tests/torus/large_major/inputs_true.dat index 8e3c9a9e311..44a67b8aa06 100644 --- a/tests/regression_tests/torus/large_major/inputs_true.dat +++ b/tests/regression_tests/torus/large_major/inputs_true.dat @@ -2,21 +2,21 @@ - - + + - - + + - - - - - - + + + + + + fixed source diff --git a/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat b/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat index d30f24fc0a9..6f0b629eb62 100644 --- a/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat +++ b/tests/regression_tests/trigger_statepoint_restart/inputs_true.dat @@ -2,13 +2,13 @@ - - + + - - + + eigenvalue diff --git a/tests/regression_tests/triso/inputs_true.dat b/tests/regression_tests/triso/inputs_true.dat index c4348388492..606f05f14d1 100644 --- a/tests/regression_tests/triso/inputs_true.dat +++ b/tests/regression_tests/triso/inputs_true.dat @@ -2,239 +2,239 @@ - - - - - + + + + + - - - + + + - - - + + + - - - - - + + + + + - - - + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.3333333333333333 0.3333333333333333 0.3333333333333333 30 @@ -253,180 +253,180 @@ 24 25 26 21 22 23 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue diff --git a/tests/regression_tests/unstructured_mesh/inputs_true.dat b/tests/regression_tests/unstructured_mesh/inputs_true.dat index dba721d7ed4..55fdf825bc9 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true0.dat b/tests/regression_tests/unstructured_mesh/inputs_true0.dat index 7c3b5a53a30..45e15c59715 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true0.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true0.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true1.dat b/tests/regression_tests/unstructured_mesh/inputs_true1.dat index 2a0ca5168ca..d47985ceb2d 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true1.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true1.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true10.dat b/tests/regression_tests/unstructured_mesh/inputs_true10.dat index 1290a983576..943ef2dc8e1 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true10.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true10.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true11.dat b/tests/regression_tests/unstructured_mesh/inputs_true11.dat index 5edb5cf0ff9..d0888b4b8b8 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true11.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true11.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true12.dat b/tests/regression_tests/unstructured_mesh/inputs_true12.dat index d8def3b5b6c..b431b412e66 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true12.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true12.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true13.dat b/tests/regression_tests/unstructured_mesh/inputs_true13.dat index 3afb0ce50ef..f53e733a88c 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true13.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true13.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true14.dat b/tests/regression_tests/unstructured_mesh/inputs_true14.dat index b7de468eaba..05bdf3ae9d3 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true14.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true14.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true15.dat b/tests/regression_tests/unstructured_mesh/inputs_true15.dat index bdb1dd0374b..67c8af42768 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true15.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true15.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true2.dat b/tests/regression_tests/unstructured_mesh/inputs_true2.dat index b2a998786db..78ff40199a7 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true2.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true2.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true3.dat b/tests/regression_tests/unstructured_mesh/inputs_true3.dat index 4a66dc2a6c5..fe551549340 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true3.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true3.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true4.dat b/tests/regression_tests/unstructured_mesh/inputs_true4.dat index 7006c0f4179..843632fdd63 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true4.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true4.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 @@ -56,7 +56,7 @@ 0.0 1.0 - + 15000000.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true5.dat b/tests/regression_tests/unstructured_mesh/inputs_true5.dat index 6c20900fa78..dc9129d98aa 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true5.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true5.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 @@ -56,7 +56,7 @@ 0.0 1.0 - + 15000000.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true6.dat b/tests/regression_tests/unstructured_mesh/inputs_true6.dat index e0be9036024..82bc3070372 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true6.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true6.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 @@ -56,7 +56,7 @@ 0.0 1.0 - + 15000000.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true7.dat b/tests/regression_tests/unstructured_mesh/inputs_true7.dat index 3a4cc1b830b..b982c40d055 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true7.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true7.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 @@ -56,7 +56,7 @@ 0.0 1.0 - + 15000000.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true8.dat b/tests/regression_tests/unstructured_mesh/inputs_true8.dat index bd19a95aea3..1e3b6cb83ea 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true8.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true8.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/unstructured_mesh/inputs_true9.dat b/tests/regression_tests/unstructured_mesh/inputs_true9.dat index 2e595a96c91..cb35eb1867d 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true9.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true9.dat @@ -2,45 +2,45 @@ - - + + - - - - - - + + + + + + - - - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + fixed source @@ -48,7 +48,7 @@ 10 - + 1.0 1.0 diff --git a/tests/regression_tests/void/inputs_true.dat b/tests/regression_tests/void/inputs_true.dat index 443c168bd41..4e996c71d01 100644 --- a/tests/regression_tests/void/inputs_true.dat +++ b/tests/regression_tests/void/inputs_true.dat @@ -2,112 +2,112 @@ - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fixed source diff --git a/tests/regression_tests/volume_calc/inputs_true.dat b/tests/regression_tests/volume_calc/inputs_true.dat index 879e05b8fc3..e3a8162e3b8 100644 --- a/tests/regression_tests/volume_calc/inputs_true.dat +++ b/tests/regression_tests/volume_calc/inputs_true.dat @@ -2,27 +2,27 @@ - - - - - + + + + + - - - + + + - - - - - - - - + + + + + + + + volume @@ -53,7 +53,7 @@ 100 -1.0 -1.0 -6.0 1.0 1.0 6.0 - + material @@ -61,7 +61,7 @@ 100 -1.0 -1.0 -6.0 1.0 1.0 6.0 - + cell @@ -69,7 +69,7 @@ 100 -1.0 -1.0 -6.0 1.0 1.0 6.0 - + diff --git a/tests/regression_tests/volume_calc/inputs_true_mg.dat b/tests/regression_tests/volume_calc/inputs_true_mg.dat index f114bd8c2f0..2ace5cd3c92 100644 --- a/tests/regression_tests/volume_calc/inputs_true_mg.dat +++ b/tests/regression_tests/volume_calc/inputs_true_mg.dat @@ -3,26 +3,26 @@ mg_lib.h5 - - - - + + + + - - - + + + - - - - - - - - + + + + + + + + volume @@ -54,7 +54,7 @@ 100 -1.0 -1.0 -6.0 1.0 1.0 6.0 - + material @@ -62,7 +62,7 @@ 100 -1.0 -1.0 -6.0 1.0 1.0 6.0 - + cell @@ -70,7 +70,7 @@ 100 -1.0 -1.0 -6.0 1.0 1.0 6.0 - + diff --git a/tests/regression_tests/weightwindows/inputs_true.dat b/tests/regression_tests/weightwindows/inputs_true.dat index 16f03a4a0b4..16966ccafeb 100644 --- a/tests/regression_tests/weightwindows/inputs_true.dat +++ b/tests/regression_tests/weightwindows/inputs_true.dat @@ -2,33 +2,33 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - + + + + fixed source diff --git a/tests/unit_tests/test_cell.py b/tests/unit_tests/test_cell.py index cef77f16085..1df3df9c55f 100644 --- a/tests/unit_tests/test_cell.py +++ b/tests/unit_tests/test_cell.py @@ -1,4 +1,4 @@ -import xml.etree. ElementTree as ET +import lxml.etree as ET import numpy as np from uncertainties import ufloat diff --git a/tests/unit_tests/test_deplete_nuclide.py b/tests/unit_tests/test_deplete_nuclide.py index e73af695504..07db57bd6d1 100644 --- a/tests/unit_tests/test_deplete_nuclide.py +++ b/tests/unit_tests/test_deplete_nuclide.py @@ -1,6 +1,6 @@ """Tests for the openmc.deplete.Nuclide class.""" -import xml.etree.ElementTree as ET +import lxml.etree as ET import copy import numpy as np import pytest @@ -345,4 +345,4 @@ def test_deepcopy(): assert copied_nuc == nuc # Mutate the original and verify the copy remains intact nuc *= 2 - assert copied_nuc != nuc \ No newline at end of file + assert copied_nuc != nuc diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index f99232ff251..3b2deee285a 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -1,4 +1,4 @@ -import xml.etree.ElementTree as ET +import lxml.etree as ET from pathlib import Path import numpy as np diff --git a/tests/unit_tests/test_lattice.py b/tests/unit_tests/test_lattice.py index 99bc284b0eb..97cd898435f 100644 --- a/tests/unit_tests/test_lattice.py +++ b/tests/unit_tests/test_lattice.py @@ -1,5 +1,5 @@ from math import sqrt -import xml.etree.ElementTree as ET +import lxml.etree as ET import openmc import pytest diff --git a/tests/unit_tests/test_universe.py b/tests/unit_tests/test_universe.py index fc92de9c784..aedc8143832 100644 --- a/tests/unit_tests/test_universe.py +++ b/tests/unit_tests/test_universe.py @@ -1,4 +1,4 @@ -import xml.etree.ElementTree as ET +import lxml.etree as ET import numpy as np import openmc From eeb8a1f45161afef1029f8ad6ed793323ec72215 Mon Sep 17 00:00:00 2001 From: Paul Wilson Date: Fri, 12 May 2023 13:22:22 -0500 Subject: [PATCH 07/45] skip test that fails if VTK is missing (#2517) --- tests/unit_tests/test_plots.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/unit_tests/test_plots.py b/tests/unit_tests/test_plots.py index 4e34db25edc..5e5e1f22c12 100644 --- a/tests/unit_tests/test_plots.py +++ b/tests/unit_tests/test_plots.py @@ -70,6 +70,8 @@ def myprojectionplot(): def test_voxel_plot(run_in_tmpdir): + # attempt to preload VTK and skip this test if unavailable + vtk = pytest.importorskip('vtk') surf1 = openmc.Sphere(r=500, boundary_type='vacuum') cell1 = openmc.Cell(region=-surf1) geometry = openmc.Geometry([cell1]) From 65618384c926d5c047460dac2c83db4a2de17915 Mon Sep 17 00:00:00 2001 From: Lewis Gross <43077972+lewisgross1296@users.noreply.github.com> Date: Fri, 12 May 2023 19:44:27 -0500 Subject: [PATCH 08/45] reordered list initialization of constructor in plot.cpp to respect header declaration order (#2519) --- src/plot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plot.cpp b/src/plot.cpp index b4c8cad165f..3bcae05ac53 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -705,7 +705,7 @@ PlottableInterface::PlottableInterface(pugi::xml_node plot_node) } Plot::Plot(pugi::xml_node plot_node, PlotType type) - : PlottableInterface(plot_node), index_meshlines_mesh_ {-1}, type_(type) + : PlottableInterface(plot_node), type_(type), index_meshlines_mesh_ {-1} { set_output_path(plot_node); set_basis(plot_node); From d8dbd9bfca5f9e8faf992422149ff0573fb49551 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Mon, 15 May 2023 23:48:45 +0100 Subject: [PATCH 09/45] auto width and origin for edge cases (#2512) Co-authored-by: Paul Romano --- openmc/universe.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openmc/universe.py b/openmc/universe.py index dc88bdb0409..b8abf663d62 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -380,17 +380,20 @@ def plot(self, origin=None, width=None, pixels=(200, 200), x, y = 0, 2 xlabel, ylabel = 'x [cm]', 'z [cm]' + bb = self.bounding_box # checks to see if bounding box contains -inf or inf values - if True in np.isinf(self.bounding_box): + if np.isinf([bb[0][x], bb[1][x], bb[0][y], bb[1][y]]).any(): if origin is None: origin = (0, 0, 0) if width is None: width = (10, 10) else: if origin is None: - origin = self.bounding_box.center + # if nan values in the bb.center they get replaced with 0.0 + # this happens when the bounding_box contains inf values + origin = np.nan_to_num(bb.center) if width is None: - bb_width = self.bounding_box.width + bb_width = bb.width x_width = bb_width['xyz'.index(basis[0])] y_width = bb_width['xyz'.index(basis[1])] width = (x_width, y_width) From ec220fa9899e92869f8a110987c9dd3282fb7ac1 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Wed, 17 May 2023 20:45:04 +0100 Subject: [PATCH 10/45] updated doc string type for tally.nuclide (#2526) --- openmc/tallies.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/tallies.py b/openmc/tallies.py index 492336f7e1c..596b324bb33 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -56,7 +56,7 @@ class Tally(IDManagerMixin): Name of the tally filters : list of openmc.Filter List of specified filters for the tally - nuclides : list of openmc.Nuclide + nuclides : list of str List of nuclides to score results for scores : list of str List of defined scores, e.g. 'flux', 'fission', etc. From d6ebf26ca6ab9b2584fce18ed0669ee3f12faad1 Mon Sep 17 00:00:00 2001 From: Luke Labrie-Cleary Date: Sun, 21 May 2023 05:05:46 +0200 Subject: [PATCH 11/45] update catch2 submodule to latest commit (#2522) --- vendor/Catch2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/Catch2 b/vendor/Catch2 index 41990e0fe62..5a40b2275ca 160000 --- a/vendor/Catch2 +++ b/vendor/Catch2 @@ -1 +1 @@ -Subproject commit 41990e0fe6274d716134eecfd4d780e976c8fbf5 +Subproject commit 5a40b2275caa05cf809bf04df848764a9d7df2e2 From 3a939299ea22d14d69b8297403a94222f51dda3e Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Mon, 22 May 2023 22:32:19 +0100 Subject: [PATCH 12/45] adding BoundingBox.extent and RegularMesh.bounding_box (#2507) --- openmc/bounding_box.py | 26 ++++++++++++++++++++++++++ openmc/mesh.py | 6 ++++++ tests/unit_tests/test_bounding_box.py | 6 ++++++ tests/unit_tests/test_mesh.py | 11 +++++++++++ 4 files changed, 49 insertions(+) diff --git a/openmc/bounding_box.py b/openmc/bounding_box.py index 331e831f195..2c6da10c0d9 100644 --- a/openmc/bounding_box.py +++ b/openmc/bounding_box.py @@ -27,6 +27,9 @@ class BoundingBox(tuple): The x, y, z coordinates of the upper right corner of the bounding box in [cm] volume : float The volume of the bounding box in [cm^3] + extent : dict + A dictionary of basis as keys and the extent (left, right, bottom, top) + as values. Intended use in Matplotlib plots when setting extent width : iterable of float The width of the x, y and z axis in [cm] """ @@ -58,6 +61,29 @@ def upper_right(self) -> np.ndarray: def volume(self) -> float: return np.abs(np.prod(self[1] - self[0])) + @property + def extent(self): + return { + "xy": ( + self.lower_left[0], + self.upper_right[0], + self.lower_left[1], + self.upper_right[1], + ), + "xz": ( + self.lower_left[0], + self.upper_right[0], + self.lower_left[2], + self.upper_right[2], + ), + "yz": ( + self.lower_left[1], + self.upper_right[1], + self.lower_left[2], + self.upper_right[2], + ), + } + @property def width(self): return self.upper_right - self.lower_left diff --git a/openmc/mesh.py b/openmc/mesh.py index c4f74437922..c59f5aaf63d 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -422,6 +422,12 @@ def _grids(self): x1, = self.upper_right return (np.linspace(x0, x1, nx + 1),) + @property + def bounding_box(self): + return openmc.BoundingBox( + np.array(self.lower_left), np.array(self.upper_right) + ) + @dimension.setter def dimension(self, dimension): cv.check_type('mesh dimension', dimension, Iterable, Integral) diff --git a/tests/unit_tests/test_bounding_box.py b/tests/unit_tests/test_bounding_box.py index f053bb2a1d6..1adb1976d31 100644 --- a/tests/unit_tests/test_bounding_box.py +++ b/tests/unit_tests/test_bounding_box.py @@ -75,3 +75,9 @@ def test_bounding_box_input_checking(): # checks that a numpy array with four entries is not accepted with pytest.raises(ValueError): openmc.BoundingBox(np.array([-10, -20, -4]), np.array([1, 2, 3, 4])) + + +def test_bounding_box_extents(): + assert test_bb_1.extent['xy'] == (-10., 1., -20., 2.) + assert test_bb_1.extent['xz'] == (-10., 1., -30., 3.) + assert test_bb_1.extent['yz'] == (-20., 2., -30., 3.) diff --git a/tests/unit_tests/test_mesh.py b/tests/unit_tests/test_mesh.py index 0f9b96b0b35..4a09df0455d 100644 --- a/tests/unit_tests/test_mesh.py +++ b/tests/unit_tests/test_mesh.py @@ -33,3 +33,14 @@ def test_raises_error_when_flat(val_left, val_right): with pytest.raises(ValueError): mesh.upper_right = [25, 25, val_right] mesh.lower_left = [-25, -25, val_left] + + +def test_mesh_bounding_box(): + mesh = openmc.RegularMesh() + mesh.lower_left = [-2, -3 ,-5] + mesh.upper_right = [2, 3, 5] + bb = mesh.bounding_box + assert isinstance(bb, openmc.BoundingBox) + np.testing.assert_array_equal(bb.lower_left, np.array([-2, -3 ,-5])) + np.testing.assert_array_equal(bb.upper_right, np.array([2, 3, 5])) + From d6eac669c8edf4bf29a40c56948f487dab9663ee Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Tue, 23 May 2023 05:25:24 +0100 Subject: [PATCH 13/45] added mkdir to cwd argument in run (#2523) --- openmc/model/model.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openmc/model/model.py b/openmc/model/model.py index ede21c64e09..ee7f3647fd5 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -16,7 +16,7 @@ import openmc._xml as xml from openmc.dummy_comm import DummyCommunicator from openmc.executor import _process_CLI_arguments -from openmc.checkvalue import check_type, check_value +from openmc.checkvalue import check_type, check_value, PathLike from openmc.exceptions import InvalidIDError @@ -24,7 +24,7 @@ def _change_directory(working_dir): """A context manager for executing in a provided working directory""" start_dir = Path.cwd() - Path.mkdir(working_dir, exist_ok=True) + Path.mkdir(working_dir, parents=True, exist_ok=True) os.chdir(working_dir) try: yield @@ -632,7 +632,7 @@ def run(self, particles=None, threads=None, geometry_debug=False, Settings.max_tracks is set. Defaults to False. output : bool, optional Capture OpenMC output from standard out - cwd : str, optional + cwd : PathLike, optional Path to working directory to run in. Defaults to the current working directory. openmc_exec : str, optional From 6c7f857e1e98ce4fd5b39d8be034308596628d7e Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Tue, 23 May 2023 12:28:16 +0100 Subject: [PATCH 14/45] Auto pixel calc for universe plot (#2513) --- openmc/universe.py | 16 +++++++++++++--- tests/unit_tests/test_universe.py | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/openmc/universe.py b/openmc/universe.py index b8abf663d62..7195688292d 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -1,3 +1,4 @@ +import math import typing from abc import ABC, abstractmethod from collections import OrderedDict @@ -300,7 +301,7 @@ def find(self, point): _default_legend_kwargs = {'bbox_to_anchor': ( 1.05, 1), 'loc': 2, 'borderaxespad': 0.0} - def plot(self, origin=None, width=None, pixels=(200, 200), + def plot(self, origin=None, width=None, pixels=40000, basis='xy', color_by='cell', colors=None, seed=None, openmc_exec='openmc', axes=None, legend=False, legend_kwargs=_default_legend_kwargs, outline=False, @@ -319,8 +320,12 @@ def plot(self, origin=None, width=None, pixels=(200, 200), universe.bounding_box.width() will be used to attempt to ascertain the plot width. Defaults to (10, 10) if the bounding_box contains inf values - pixels : Iterable of int - Number of pixels to use in each basis direction + pixels : Iterable of int or int + If iterable of ints provided then this directly sets the number of + pixels to use in each basis direction. If int provided then this + sets the total number of pixels in the plot and the number of + pixels in each basis direction is calculated from this total and + the image aspect ratio. basis : {'xy', 'xz', 'yz'} The basis directions for the plot color_by : {'cell', 'material'} @@ -398,6 +403,11 @@ def plot(self, origin=None, width=None, pixels=(200, 200), y_width = bb_width['xyz'.index(basis[1])] width = (x_width, y_width) + if isinstance(pixels, int): + aspect_ratio = width[0] / width[1] + pixels_y = math.sqrt(pixels / aspect_ratio) + pixels = (int(pixels / pixels_y), int(pixels_y)) + x_min = origin[x] - 0.5*width[0] x_max = origin[x] + 0.5*width[0] y_min = origin[y] - 0.5*width[1] diff --git a/tests/unit_tests/test_universe.py b/tests/unit_tests/test_universe.py index aedc8143832..f4cf43d919b 100644 --- a/tests/unit_tests/test_universe.py +++ b/tests/unit_tests/test_universe.py @@ -81,7 +81,7 @@ def test_plot(run_in_tmpdir, sphere_model): colors=colors, color_by="cell", legend=False, - pixels=(10, 10), + pixels=100, basis=basis, outline=False ) From 16b955f690067d74779aeb7e968f62f7cbb629cc Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 31 May 2023 19:25:26 -0500 Subject: [PATCH 15/45] Fix docstring for MicroXS class (#2540) --- openmc/deplete/microxs.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/openmc/deplete/microxs.py b/openmc/deplete/microxs.py index 7f3a84bf66d..67f6bf49d35 100644 --- a/openmc/deplete/microxs.py +++ b/openmc/deplete/microxs.py @@ -37,8 +37,9 @@ def from_model(cls, dilute_initial=1.0e3, energy_bounds=(0, 20e6), run_kwargs=None): - """Generate a one-group cross-section dataframe using - OpenMC. Note that the ``openmc`` executable must be compiled. + """Generate a one-group cross-section dataframe using OpenMC. + + Note that the ``openmc`` executable must be compiled. Parameters ---------- @@ -55,8 +56,6 @@ def from_model(cls, Initial atom density [atoms/cm^3] to add for nuclides that are zero in initial condition to ensure they exist in the cross section data. Only done for nuclides with reaction rates. - reactions : list of str, optional - Reaction names to tally energy_bound : 2-tuple of float, optional Bounds for the energy group. run_kwargs : dict, optional From 4c69d913bb836df479d9bdea85ae6936d8109089 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 31 May 2023 20:13:52 -0500 Subject: [PATCH 16/45] Add virtual destructor on PlottableInterface (#2541) --- include/openmc/plot.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/include/openmc/plot.h b/include/openmc/plot.h index 225242c702d..deb02180b48 100644 --- a/include/openmc/plot.h +++ b/include/openmc/plot.h @@ -104,6 +104,7 @@ class PlottableInterface { // Public color-related data PlottableInterface(pugi::xml_node plot_node); + virtual ~PlottableInterface() = default; int level_; // Universe level to plot bool color_overlaps_; // Show overlapping cells? PlotColorBy color_by_; // Plot coloring (cell/material) @@ -151,10 +152,10 @@ class SlicePlotBase { // Members public: - Position origin_; //!< Plot origin in geometry - Position width_; //!< Plot width in geometry - PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) - array pixels_; //!< Plot size in pixels + Position origin_; //!< Plot origin in geometry + Position width_; //!< Plot width in geometry + PlotBasis basis_; //!< Plot basis (XY/XZ/YZ) + array pixels_; //!< Plot size in pixels bool slice_color_overlaps_; //!< Show overlapping cells? int slice_level_ {-1}; //!< Plot universe level private: @@ -321,11 +322,11 @@ class ProjectionPlot : public PlottableInterface { // loop: static const int MAX_INTERSECTIONS = 1000000; - std::array pixels_; // pixel dimension of resulting image + std::array pixels_; // pixel dimension of resulting image double horizontal_field_of_view_ {70.0}; // horiz. f.o.v. in degrees - Position camera_position_; // where camera is - Position look_at_; // point camera is centered looking at - Direction up_ {0.0, 0.0, 1.0}; // which way is up + Position camera_position_; // where camera is + Position look_at_; // point camera is centered looking at + Direction up_ {0.0, 0.0, 1.0}; // which way is up // which color IDs should be wireframed. If empty, all cells are wireframed. vector wireframe_ids_; From 74fb2801c26b748eccc76c4a3d584e084b17ed9f Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Fri, 2 Jun 2023 17:44:43 +0100 Subject: [PATCH 17/45] creating parent dirs for output_dir (#2543) --- openmc/deplete/abc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index e871eccfe5d..d4cc1ba4d7f 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -69,7 +69,7 @@ def change_directory(output_dir): """ orig_dir = os.getcwd() try: - output_dir.mkdir(exist_ok=True) + output_dir.mkdir(parents=True, exist_ok=True) os.chdir(output_dir) yield finally: From 19282cb0889ac332441787fa398da67d2be5a2fd Mon Sep 17 00:00:00 2001 From: Lorenzo Chierici Date: Mon, 5 Jun 2023 00:10:47 +0200 Subject: [PATCH 18/45] Remove misleading warn message from deplete.chain.py (#2544) --- openmc/deplete/chain.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index d23cf374cdb..63fde69834c 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -734,9 +734,6 @@ def form_rr_term(self, transfer_rates, materials): if transfer_rates.get_destination_material(material, element) == destination_material: matrix[i, i] = transfer_rates.get_transfer_rate(material, element) else: - warn(f'Material {destination_material} is not defined ' - f'as a destination material for Material {material}. ' - 'Setting transfer rate to 0.0') matrix[i, i] = 0.0 #Nothing else is allowed n = len(self) From 7479a9022a056d697f79ba2caeccb067eb7aee67 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 6 Jun 2023 11:01:59 -0500 Subject: [PATCH 19/45] Fix spherical coords again. (#2538) --- openmc/mesh.py | 8 +++--- tests/unit_tests/test_mesh_to_vtk.py | 42 ++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/openmc/mesh.py b/openmc/mesh.py index c59f5aaf63d..fde9f302dc9 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -1338,7 +1338,7 @@ def write_data_to_vtk(self, filename, datasets, volume_normalization=True): pts_cartesian[:, 0] = r * np.cos(phi) + self.origin[0] pts_cartesian[:, 1] = r * np.sin(phi) + self.origin[1] pts_cartesian[:, 2] += self.origin[2] - + return super().write_data_to_vtk( points=pts_cartesian, filename=filename, @@ -1585,9 +1585,9 @@ def write_data_to_vtk(self, filename, datasets, volume_normalization=True): r, theta, phi = pts_spherical[:, 0], pts_spherical[:, 1], pts_spherical[:, 2] - pts_cartesian[:, 0] = r * np.sin(phi) * np.cos(theta) + self.origin[0] - pts_cartesian[:, 1] = r * np.sin(phi) * np.sin(theta) + self.origin[1] - pts_cartesian[:, 2] = r * np.cos(phi) + self.origin[2] + pts_cartesian[:, 0] = r * np.sin(theta) * np.cos(phi) + self.origin[0] + pts_cartesian[:, 1] = r * np.sin(theta) * np.sin(phi) + self.origin[1] + pts_cartesian[:, 2] = r * np.cos(theta) + self.origin[2] return super().write_data_to_vtk( points=pts_cartesian, diff --git a/tests/unit_tests/test_mesh_to_vtk.py b/tests/unit_tests/test_mesh_to_vtk.py index 4c0a4387745..2e2790e0a5f 100644 --- a/tests/unit_tests/test_mesh_to_vtk.py +++ b/tests/unit_tests/test_mesh_to_vtk.py @@ -273,3 +273,45 @@ def in_geom(cell): # need to get flat index with axes reversed due to ordering passed into the VTK file flat_idx = np.ravel_multi_index(tuple(ijk[::-1]), mesh.dimension[::-1]) assert vtk_data[flat_idx] == 0.0, err_msg + + +def test_sphere_mesh_coordinates(run_in_tmpdir): + mesh = openmc.SphericalMesh() + mesh.r_grid = np.linspace(0.1, 10, 30) + mesh.phi_grid = np.linspace(0, 1.5*np.pi, 25) + mesh.theta_grid = np.linspace(0, np.pi / 2, 15) + + # write the data to a VTK file (no data) + vtk_filename = 'test.vtk' + mesh.write_data_to_vtk(vtk_filename, {}) + + # read file + reader = vtk.vtkStructuredGridReader() + reader.SetFileName(str(vtk_filename)) + reader.Update() + + vtk_grid = reader.GetOutput() + + # create a region that matches the spherical mesh description + x = openmc.XPlane() + z = openmc.ZPlane() + y = openmc.YPlane() + s = openmc.Sphere(r=10.0) + + region = +z & +y & -s | -x & -y & +z & -s + + # the VTK interface will update this list when GetCentroid is called + centroid = np.zeros(3) + + # ensure all centroids of the sphere mesh are inside the cell region + for i in range(vtk_grid.GetNumberOfCells()): + # get the cell from the stuctured mesh object + cell = vtk_grid.GetCell(i) + cell.GetCentroid(centroid) + + # if the coordinate conversion is happening correctly, + # every one of the cell centroids should be in the CSG region + assert centroid in region, \ + f'Cell centroid {centroid} not in equivalent ' \ + f'CSG region for spherical mesh {mesh}' + From a288e42a064604c92d3293157c47ab79e0ac5c8f Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Thu, 8 Jun 2023 18:29:55 +0100 Subject: [PATCH 20/45] corrected pixel index for axis height (#2553) --- openmc/universe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/universe.py b/openmc/universe.py index 7195688292d..458729d5cf1 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -455,7 +455,7 @@ def plot(self, origin=None, width=None, pixels=40000, axes.set_ylabel(ylabel) params = fig.subplotpars width = pixels[0]*px/(params.right - params.left) - height = pixels[0]*px/(params.top - params.bottom) + height = pixels[1]*px/(params.top - params.bottom) fig.set_size_inches(width, height) if outline: From c123ce0fa0053bc3c6c52794467c0dfbde6d7d5f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 9 Jun 2023 07:24:00 -0500 Subject: [PATCH 21/45] New `multiply_density` option on tallies (#2539) --- docs/source/io_formats/statepoint.rst | 2 + docs/source/io_formats/tallies.rst | 6 ++ include/openmc/nuclide.h | 18 ++++- include/openmc/particle.h | 13 ++++ include/openmc/particle_data.h | 3 +- include/openmc/tallies/tally.h | 7 ++ openmc/lib/tally.py | 20 +++++ openmc/statepoint.py | 4 + openmc/tallies.py | 25 +++++- src/material.cpp | 19 ++--- src/nuclide.cpp | 2 +- src/particle.cpp | 31 +++++++- src/state_point.cpp | 6 ++ src/tallies/tally.cpp | 37 +++++++-- src/tallies/tally_scoring.cpp | 76 +++++++++++++------ .../regression_tests/tallies/results_true.dat | 2 +- tests/unit_tests/test_lib.py | 13 ++++ .../unit_tests/test_tally_multiply_density.py | 50 ++++++++++++ 18 files changed, 286 insertions(+), 48 deletions(-) create mode 100644 tests/unit_tests/test_tally_multiply_density.py diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 09b1b114420..89d973a2ba9 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -139,6 +139,8 @@ The current version of the statepoint file format is 17.0. - **internal** (*int*) -- Flag indicating the presence of tally data (0) or absence of tally data (1). All user defined tallies will have a value of 0 unless otherwise instructed. + - **multiply_density** (*int*) -- Flag indicating whether reaction + rates should be multiplied by atom density (1) or not (0). :Datasets: - **n_realizations** (*int*) -- Number of realizations. - **n_filters** (*int*) -- Number of filters used. diff --git a/docs/source/io_formats/tallies.rst b/docs/source/io_formats/tallies.rst index 897941ad406..b88877b8388 100644 --- a/docs/source/io_formats/tallies.rst +++ b/docs/source/io_formats/tallies.rst @@ -69,6 +69,12 @@ The ```` element accepts the following sub-elements: list of valid scores can be found in the :ref:`user's guide `. + :multiply_density: + A boolean that indicates whether reaction rate scores should be computed by + multiplying by the atom density of a nuclide present in a material. + + *Default*: true + :trigger: Precision trigger applied to all filter bins and nuclides for this tally. It must specify the trigger's type, threshold and scores to which it will diff --git a/include/openmc/nuclide.h b/include/openmc/nuclide.h index b05c76bbb86..1cc9d297287 100644 --- a/include/openmc/nuclide.h +++ b/include/openmc/nuclide.h @@ -29,6 +29,7 @@ namespace openmc { class Nuclide { public: + //============================================================================ // Types, aliases using EmissionMode = ReactionProduct::EmissionMode; struct EnergyGrid { @@ -36,18 +37,32 @@ class Nuclide { vector energy; }; + //============================================================================ // Constructors/destructors Nuclide(hid_t group, const vector& temperature); ~Nuclide(); + //============================================================================ + // Methods + //! Initialize logarithmic grid for energy searches void init_grid(); + //! Calculate microscopic cross sections + // + //! \param[in] i_sab Index in data::thermal_scatt + //! \param[in] i_log_union Log-grid search index + //! \param[in] sab_frac S(a,b) table fraction + //! \param[in,out] p Particle object void calculate_xs(int i_sab, int i_log_union, double sab_frac, Particle& p); + //! Calculate thermal scattering cross section + // + //! \param[in] i_sab Index in data::thermal_scatt + //! \param[in] sab_frac S(a,b) table fraction + //! \param[in,out] p Particle object void calculate_sab_xs(int i_sab, double sab_frac, Particle& p); - // Methods double nu(double E, EmissionMode mode, int group = 0) const; void calculate_elastic_xs(Particle& p) const; @@ -69,6 +84,7 @@ class Nuclide { double collapse_rate(int MT, double temperature, gsl::span energy, gsl::span flux) const; + //============================================================================ // Data members std::string name_; //!< Name of nuclide, e.g. "U235" int Z_; //!< Atomic number diff --git a/include/openmc/particle.h b/include/openmc/particle.h index da2f6a61fc8..e3f23fd5b1d 100644 --- a/include/openmc/particle.h +++ b/include/openmc/particle.h @@ -35,6 +35,9 @@ class Particle : public ParticleData { Particle() = default; + //========================================================================== + // Methods + double speed() const; //! create a secondary particle @@ -106,6 +109,16 @@ class Particle : public ParticleData { //! create a particle restart HDF5 file void write_restart() const; + + //! Update microscopic cross section cache + // + //! \param[in] i_nuclide Index in data::nuclides + //! \param[in] i_grid Index on log union grid + //! \param[in] i_sab Index in data::thermal_scatt + //! \param[in] sab_frac S(a,b) table fraction + //! \param[in] ncrystal_xs Thermal scattering xs from NCrystal + void update_neutron_xs(int i_nuclide, int i_grid = C_NONE, int i_sab = C_NONE, + double sab_frac = 0.0, double ncrystal_xs = -1.0); }; //============================================================================ diff --git a/include/openmc/particle_data.h b/include/openmc/particle_data.h index d3d00571a87..c4f959666f2 100644 --- a/include/openmc/particle_data.h +++ b/include/openmc/particle_data.h @@ -218,8 +218,9 @@ struct BoundaryInfo { * https://doi.org/10.1016/j.anucene.2017.11.032. */ class ParticleData { - public: + //---------------------------------------------------------------------------- + // Constructors ParticleData(); private: diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index e840a0aa144..6ad3bef6f3b 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -37,6 +37,8 @@ class Tally { void set_active(bool active) { active_ = active; } + void set_multiply_density(bool value) { multiply_density_ = value; } + void set_writable(bool writable) { writable_ = writable; } void set_scores(pugi::xml_node node); @@ -62,6 +64,8 @@ class Tally { int32_t n_filter_bins() const { return n_filter_bins_; } + bool multiply_density() const { return multiply_density_; } + bool writable() const { return writable_; } //---------------------------------------------------------------------------- @@ -139,6 +143,9 @@ class Tally { int32_t n_filter_bins_ {0}; + //! Whether to multiply by atom density for reaction rates + bool multiply_density_ {true}; + gsl::index index_; }; diff --git a/openmc/lib/tally.py b/openmc/lib/tally.py index 85af8ffff4e..83c28528e49 100644 --- a/openmc/lib/tally.py +++ b/openmc/lib/tally.py @@ -39,6 +39,9 @@ c_int32, POINTER(POINTER(c_int32)), POINTER(c_size_t)] _dll.openmc_tally_get_filters.restype = c_int _dll.openmc_tally_get_filters.errcheck = _error_handler +_dll.openmc_tally_get_multiply_density.argtypes = [c_int32, POINTER(c_bool)] +_dll.openmc_tally_get_multiply_density.restype = c_int +_dll.openmc_tally_get_multiply_density.errcheck = _error_handler _dll.openmc_tally_get_n_realizations.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_n_realizations.restype = c_int _dll.openmc_tally_get_n_realizations.errcheck = _error_handler @@ -75,6 +78,9 @@ _dll.openmc_tally_set_id.argtypes = [c_int32, c_int32] _dll.openmc_tally_set_id.restype = c_int _dll.openmc_tally_set_id.errcheck = _error_handler +_dll.openmc_tally_set_multiply_density.argtypes = [c_int32, c_bool] +_dll.openmc_tally_set_multiply_density.restype = c_int +_dll.openmc_tally_set_multiply_density.errcheck = _error_handler _dll.openmc_tally_set_nuclides.argtypes = [c_int32, c_int, POINTER(c_char_p)] _dll.openmc_tally_set_nuclides.restype = c_int _dll.openmc_tally_set_nuclides.errcheck = _error_handler @@ -174,6 +180,10 @@ class Tally(_FortranObjectWithID): List of tally filters mean : numpy.ndarray An array containing the sample mean for each bin + multiply_density : bool + Whether reaction rates should be multiplied by atom density + + .. versionadded:: 0.13.4 nuclides : list of str List of nuclides to score results for num_realizations : int @@ -363,6 +373,16 @@ def writable(self): def writable(self, writable): _dll.openmc_tally_set_writable(self._index, writable) + @property + def multiply_density(self): + multiply_density = c_bool() + _dll.openmc_tally_get_multiply_density(self._index, multiply_density) + return multiply_density.value + + @multiply_density.setter + def multiply_density(self, multiply_density): + _dll.openmc_tally_set_multiply_density(self._index, multiply_density) + def reset(self): """Reset results and num_realizations of tally""" _dll.openmc_tally_reset(self._index) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 138c0c718de..7c1ecd13773 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -398,6 +398,10 @@ def tallies(self): tally._sp_filename = self._f.filename tally.name = group['name'][()].decode() if 'name' in group else '' + # Check if tally has multiply_density attribute + if "multiply_density" in group.attrs: + tally.multiply_density = group.attrs["multiply_density"].item() > 0 + # Read the number of realizations n_realizations = group['n_realizations'][()] diff --git a/openmc/tallies.py b/openmc/tallies.py index 596b324bb33..85daaa17a1d 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -14,7 +14,7 @@ import openmc import openmc.checkvalue as cv -from ._xml import clean_indentation, reorder_attributes +from ._xml import clean_indentation, reorder_attributes, get_text from .mixin import IDManagerMixin from .mesh import MeshBase @@ -54,6 +54,10 @@ class Tally(IDManagerMixin): Unique identifier for the tally name : str Name of the tally + multiply_density : bool + Whether reaction rates should be multiplied by atom density + + .. versionadded:: 0.13.4 filters : list of openmc.Filter List of specified filters for the tally nuclides : list of str @@ -111,6 +115,7 @@ def __init__(self, tally_id=None, name=''): self._estimator = None self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers') self._derivative = None + self._multiply_density = True self._num_realizations = 0 self._with_summary = False @@ -138,12 +143,17 @@ def __repr__(self): parts.append('{: <15}=\t{}'.format('Nuclides', nuclides)) parts.append('{: <15}=\t{}'.format('Scores', self.scores)) parts.append('{: <15}=\t{}'.format('Estimator', self.estimator)) + parts.append('{: <15}=\t{}'.format('Multiply dens.', self.multiply_density)) return '\n\t'.join(parts) @property def name(self): return self._name + @property + def multiply_density(self): + return self._multiply_density + @property def filters(self): return self._filters @@ -323,6 +333,11 @@ def name(self, name): cv.check_type('tally name', name, str, none_ok=True) self._name = name + @multiply_density.setter + def multiply_density(self, value): + cv.check_type('multiply density', value, bool) + self._multiply_density = value + @derivative.setter def derivative(self, deriv): cv.check_type('tally derivative', deriv, openmc.TallyDerivative, @@ -829,6 +844,10 @@ def to_xml_element(self): if self.name != '': element.set("name", self.name) + # Multiply by density + if not self.multiply_density: + element.set("multiply_density", str(self.multiply_density).lower()) + # Optional Tally filters if len(self.filters) > 0: subelement = ET.SubElement(element, "filters") @@ -885,6 +904,10 @@ def from_xml_element(cls, elem, **kwargs): name = elem.get('name', '') tally = cls(tally_id=tally_id, name=name) + text = get_text(elem, 'multiply_density') + if text is not None: + tally.multiply_density = text in ('true', '1') + # Read filters filters_elem = elem.find('filters') if filters_elem is not None: diff --git a/src/material.cpp b/src/material.cpp index 82dd0d4d9e3..610b54add2a 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -353,7 +353,7 @@ Material::~Material() model::material_map.erase(id_); } -Material & Material::clone() +Material& Material::clone() { std::unique_ptr mat = std::make_unique(); @@ -868,21 +868,12 @@ void Material::calculate_neutron_xs(Particle& p) const // ====================================================================== // CALCULATE MICROSCOPIC CROSS SECTION - // Determine microscopic cross sections for this nuclide + // Get nuclide index int i_nuclide = nuclide_[i]; - // Calculate microscopic cross section for this nuclide - auto& micro {p.neutron_xs(i_nuclide)}; - if (p.E() != micro.last_E || p.sqrtkT() != micro.last_sqrtkT || - i_sab != micro.index_sab || sab_frac != micro.sab_frac) { - data::nuclides[i_nuclide]->calculate_xs(i_sab, i_grid, sab_frac, p); - - // If NCrystal is being used, update micro cross section cache - if (ncrystal_xs >= 0.0) { - data::nuclides[i_nuclide]->calculate_elastic_xs(p); - ncrystal_update_micro(ncrystal_xs, micro); - } - } + // Update microscopic cross section for this nuclide + p.update_neutron_xs(i_nuclide, i_grid, i_sab, sab_frac, ncrystal_xs); + auto& micro = p.neutron_xs(i_nuclide); // ====================================================================== // ADD TO MACROSCOPIC CROSS SECTION diff --git a/src/nuclide.cpp b/src/nuclide.cpp index 99ed44b112b..8f73a530930 100644 --- a/src/nuclide.cpp +++ b/src/nuclide.cpp @@ -471,7 +471,7 @@ void Nuclide::create_derived( xs_cdf_sum += (std::sqrt(E[i]) * xs[i] + std::sqrt(E[i + 1]) * xs[i + 1]) / 2.0 * (E[i + 1] - E[i]); - xs_cdf_[i+1] = xs_cdf_sum; + xs_cdf_[i + 1] = xs_cdf_sum; } } } diff --git a/src/particle.cpp b/src/particle.cpp index 1ec95a4ae67..f455ab83494 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -36,6 +36,10 @@ namespace openmc { +//============================================================================== +// Particle implementation +//============================================================================== + double Particle::speed() const { // Determine mass in eV/c^2 @@ -433,7 +437,9 @@ void Particle::cross_surface() #ifdef DAGMC // in DAGMC, we know what the next cell should be if (surf->geom_type_ == GeometryType::DAG) { - int32_t i_cell = next_cell(i_surface, cell_last(n_coord() - 1), lowest_coord().universe) - 1; + int32_t i_cell = + next_cell(i_surface, cell_last(n_coord() - 1), lowest_coord().universe) - + 1; // save material and temp material_last() = material(); sqrtkT_last() = sqrtkT(); @@ -703,6 +709,29 @@ void Particle::write_restart() const } // #pragma omp critical } +void Particle::update_neutron_xs( + int i_nuclide, int i_grid, int i_sab, double sab_frac, double ncrystal_xs) +{ + // Get microscopic cross section cache + auto& micro = this->neutron_xs(i_nuclide); + + // If the cache doesn't match, recalculate micro xs + if (this->E() != micro.last_E || this->sqrtkT() != micro.last_sqrtkT || + i_sab != micro.index_sab || sab_frac != micro.sab_frac) { + data::nuclides[i_nuclide]->calculate_xs(i_sab, i_grid, sab_frac, *this); + + // If NCrystal is being used, update micro cross section cache + if (ncrystal_xs >= 0.0) { + data::nuclides[i_nuclide]->calculate_elastic_xs(*this); + ncrystal_update_micro(ncrystal_xs, micro); + } + } +} + +//============================================================================== +// Non-method functions +//============================================================================== + std::string particle_type_to_str(ParticleType type) { switch (type) { diff --git a/src/state_point.cpp b/src/state_point.cpp index eefce8fa47b..bff62132060 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -193,6 +193,12 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) continue; } + if (tally->multiply_density()) { + write_attribute(tally_group, "multiply_density", 1); + } else { + write_attribute(tally_group, "multiply_density", 0); + } + if (tally->estimator_ == TallyEstimator::ANALOG) { write_dataset(tally_group, "estimator", "analog"); } else if (tally->estimator_ == TallyEstimator::TRACKLENGTH) { diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index e29384772f6..85d999fd4a6 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -92,6 +92,10 @@ Tally::Tally(pugi::xml_node node) if (check_for_node(node, "name")) name_ = get_node_value(node, "name"); + if (check_for_node(node, "multiply_density")) { + multiply_density_ = get_node_value_bool(node, "multiply_density"); + } + // ======================================================================= // READ DATA FOR FILTERS @@ -564,11 +568,12 @@ void Tally::set_nuclides(const vector& nuclides) nuclides_.push_back(-1); } else { auto search = data::nuclide_map.find(nuc); - if (search == data::nuclide_map.end()) - fatal_error(fmt::format("Could not find the nuclide {} specified in " - "tally {} in any material", - nuc, id_)); - nuclides_.push_back(search->second); + if (search == data::nuclide_map.end()) { + int err = openmc_load_nuclide(nuc.c_str(), nullptr, 0); + if (err < 0) + throw std::runtime_error {openmc_err_msg}; + } + nuclides_.push_back(data::nuclide_map.at(nuc)); } } } @@ -1108,6 +1113,28 @@ extern "C" int openmc_tally_set_writable(int32_t index, bool writable) return 0; } +extern "C" int openmc_tally_get_multiply_density(int32_t index, bool* value) +{ + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *value = model::tallies[index]->multiply_density(); + + return 0; +} + +extern "C" int openmc_tally_set_multiply_density(int32_t index, bool value) +{ + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + model::tallies[index]->set_multiply_density(value); + + return 0; +} + extern "C" int openmc_tally_get_scores(int32_t index, int** scores, int* n) { if (index < 0 || index >= model::tallies.size()) { diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 68eb344af43..3e58fec05b7 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -939,21 +939,17 @@ void score_general_ce_nonanalog(Particle& p, int i_tally, int start_index, if (i_nuclide >= 0) { const auto& micro = p.photon_xs(i_nuclide); - double xs = (score_bin == COHERENT) - ? micro.coherent - : (score_bin == INCOHERENT) ? micro.incoherent - : (score_bin == PHOTOELECTRIC) - ? micro.photoelectric - : micro.pair_production; + double xs = (score_bin == COHERENT) ? micro.coherent + : (score_bin == INCOHERENT) ? micro.incoherent + : (score_bin == PHOTOELECTRIC) ? micro.photoelectric + : micro.pair_production; score = xs * atom_density * flux; } else { - double xs = (score_bin == COHERENT) - ? p.macro_xs().coherent - : (score_bin == INCOHERENT) - ? p.macro_xs().incoherent - : (score_bin == PHOTOELECTRIC) - ? p.macro_xs().photoelectric - : p.macro_xs().pair_production; + double xs = (score_bin == COHERENT) ? p.macro_xs().coherent + : (score_bin == INCOHERENT) ? p.macro_xs().incoherent + : (score_bin == PHOTOELECTRIC) + ? p.macro_xs().photoelectric + : p.macro_xs().pair_production; score = xs * flux; } break; @@ -2308,6 +2304,9 @@ void score_tracklength_tally(Particle& p, double distance) // Determine the tracklength estimate of the flux double flux = p.wgt() * distance; + // Set 'none' value for log union grid index + int i_log_union = C_NONE; + for (auto i_tally : model::active_tracklength_tallies) { const Tally& tally {*model::tallies[i_tally]}; @@ -2331,11 +2330,25 @@ void score_tracklength_tally(Particle& p, double distance) double atom_density = 0.; if (i_nuclide >= 0) { if (p.material() != MATERIAL_VOID) { - auto j = - model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; - if (j == C_NONE) - continue; - atom_density = model::materials[p.material()]->atom_density_(j); + const auto& mat = model::materials[p.material()]; + auto j = mat->mat_nuclide_index_[i_nuclide]; + if (j == C_NONE) { + // Determine log union grid index + if (i_log_union == C_NONE) { + int neutron = static_cast(ParticleType::neutron); + i_log_union = std::log(p.E() / data::energy_min[neutron]) / + simulation::log_spacing; + } + + // Update micro xs cache + if (!tally.multiply_density()) { + p.update_neutron_xs(i_nuclide, i_log_union); + atom_density = 1.0; + } + } else { + atom_density = + tally.multiply_density() ? mat->atom_density_(j) : 1.0; + } } } @@ -2371,6 +2384,9 @@ void score_collision_tally(Particle& p) flux = p.wgt_last() / p.macro_xs().total; } + // Set 'none value for log union grid index + int i_log_union = C_NONE; + for (auto i_tally : model::active_collision_tallies) { const Tally& tally {*model::tallies[i_tally]}; @@ -2393,11 +2409,25 @@ void score_collision_tally(Particle& p) double atom_density = 0.; if (i_nuclide >= 0) { - auto j = - model::materials[p.material()]->mat_nuclide_index_[i_nuclide]; - if (j == C_NONE) - continue; - atom_density = model::materials[p.material()]->atom_density_(j); + const auto& mat = model::materials[p.material()]; + auto j = mat->mat_nuclide_index_[i_nuclide]; + if (j == C_NONE) { + // Determine log union grid index + if (i_log_union == C_NONE) { + int neutron = static_cast(ParticleType::neutron); + i_log_union = std::log(p.E() / data::energy_min[neutron]) / + simulation::log_spacing; + } + + // Update micro xs cache + if (!tally.multiply_density()) { + p.update_neutron_xs(i_nuclide, i_log_union); + atom_density = 1.0; + } + } else { + atom_density = + tally.multiply_density() ? mat->atom_density_(j) : 1.0; + } } // TODO: consider replacing this "if" with pointers or templates diff --git a/tests/regression_tests/tallies/results_true.dat b/tests/regression_tests/tallies/results_true.dat index 6a58c1725f0..673d2143bee 100644 --- a/tests/regression_tests/tallies/results_true.dat +++ b/tests/regression_tests/tallies/results_true.dat @@ -1 +1 @@ -6b1d8d6f4d7a70af6c39cc76b9267a61ba9a9d0c14b75a4df6f83e72a2bfaf1533caaf936c2185f0a158443eb9da266bd5a77b7996020fd638551ea841d821e0 \ No newline at end of file +d1decdbec6cb59df91ba5c42cb37a04f413a34fa7faf7ad1eecfd7d53a14af8cb65b58335c4ede4e88f6d9ab35a1746251983cc991d74eab3e678887c84183bd \ No newline at end of file diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 0633ceb183d..b4dd9197b18 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -366,6 +366,19 @@ def test_tally_activate(lib_simulation_init): assert t.active +def test_tally_multiply_density(lib_simulation_init): + # multiply_density is True by default + t = openmc.lib.tallies[1] + assert t.multiply_density + + # Make sure setting multiply_density works + t.multiply_density = False + assert not t.multiply_density + + # Reset to True + t.multiply_density = True + + def test_tally_writable(lib_simulation_init): t = openmc.lib.tallies[1] assert t.writable diff --git a/tests/unit_tests/test_tally_multiply_density.py b/tests/unit_tests/test_tally_multiply_density.py new file mode 100644 index 00000000000..66ef41e0dac --- /dev/null +++ b/tests/unit_tests/test_tally_multiply_density.py @@ -0,0 +1,50 @@ +import numpy as np +import openmc +import pytest + + +def test_micro_macro_compare(): + # Create simple sphere model with H1 and H2 + mat = openmc.Material() + mat.add_components({'H1': 1.0, 'H2': 1.0}) + mat.set_density('g/cm3', 1.0) + sph = openmc.Sphere(r=10.0, boundary_type='vacuum') + cell = openmc.Cell(fill=mat, region=-sph) + model = openmc.Model() + model.geometry = openmc.Geometry([cell]) + model.settings.run_mode = 'fixed source' + model.settings.particles = 1000 + model.settings.batches = 10 + + # Set up two reaction rate tallies, one that multplies by density and the + # other that doesn't + tally_macro = openmc.Tally() + tally_macro.nuclides = ['H1', 'H2', 'H3'] + tally_macro.scores = ['total', 'elastic'] + tally_micro = openmc.Tally() + tally_micro.nuclides = ['H1', 'H2', 'H3'] + tally_micro.scores = ['total', 'elastic'] + tally_micro.multiply_density = False + model.tallies = [tally_macro, tally_micro] + + sp_filename = model.run() + with openmc.StatePoint(sp_filename) as sp: + tally_macro = sp.tallies[tally_macro.id] + tally_micro = sp.tallies[tally_micro.id] + + # Make sure multply_density attribute from statepoint is set correctly + assert tally_macro.multiply_density + assert not tally_micro.multiply_density + + # Dividing macro by density should give micro + density = mat.get_nuclide_atom_densities() + for nuc in ('H1', 'H2'): + micro_derived = tally_macro.get_values(nuclides=[nuc]) / density[nuc] + micro = tally_micro.get_values(nuclides=[nuc]) + assert micro_derived == pytest.approx(micro) + + # For macro tally, H3 scores should be zero + assert np.all(tally_macro.get_values(nuclides=['H3']) == 0.0) + + # For micro tally, H3 scores should be positive + assert np.all(tally_micro.get_values(nuclides=['H3']) > 0.0) From 610a5d8c3485034626ce54ce87a88eaa8071cc23 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 9 Jun 2023 10:47:27 -0500 Subject: [PATCH 22/45] Global Weight Window Generation via CAPI (#2359) Co-authored-by: Jonathan Shimwell Co-authored-by: Paul Romano --- docs/source/io_formats/index.rst | 1 + docs/source/io_formats/settings.rst | 73 +- docs/source/io_formats/statepoint.rst | 2 + docs/source/io_formats/weight_windows.rst | 39 + docs/source/pythonapi/base.rst | 14 +- docs/source/pythonapi/capi.rst | 2 + include/openmc/capi.h | 33 + include/openmc/constants.h | 3 +- include/openmc/mesh.h | 52 +- include/openmc/output.h | 22 + include/openmc/settings.h | 6 +- include/openmc/tallies/filter_mesh.h | 6 +- include/openmc/tallies/tally.h | 44 + include/openmc/weight_windows.h | 303 ++++-- openmc/lib/__init__.py | 2 + openmc/lib/core.py | 50 +- openmc/lib/filter.py | 18 +- openmc/lib/mesh.py | 9 +- openmc/lib/settings.py | 1 + openmc/lib/tally.py | 24 + openmc/lib/weight_windows.py | 323 ++++++ openmc/settings.py | 68 +- openmc/source.py | 47 +- openmc/tallies.py | 1 - openmc/tracks.py | 3 +- openmc/weight_windows.py | 302 +++++- src/mesh.cpp | 64 +- src/settings.cpp | 29 +- src/simulation.cpp | 17 + src/tallies/filter.cpp | 9 + src/tallies/filter_particle.cpp | 19 + src/tallies/tally.cpp | 61 ++ src/weight_windows.cpp | 928 +++++++++++++++++- .../track_output/results_true.dat | 6 +- .../weightwindows/generators/__init__.py | 0 .../weightwindows/generators/test.py | 54 + tests/unit_tests/weightwindows/test.py | 47 +- tests/unit_tests/weightwindows/test_ww_gen.py | 316 ++++++ 38 files changed, 2808 insertions(+), 190 deletions(-) create mode 100644 docs/source/io_formats/weight_windows.rst create mode 100644 openmc/lib/weight_windows.py create mode 100644 tests/regression_tests/weightwindows/generators/__init__.py create mode 100644 tests/regression_tests/weightwindows/generators/test.py create mode 100644 tests/unit_tests/weightwindows/test_ww_gen.py diff --git a/docs/source/io_formats/index.rst b/docs/source/io_formats/index.rst index 8c89bd2a1d9..4bbaa961a68 100644 --- a/docs/source/io_formats/index.rst +++ b/docs/source/io_formats/index.rst @@ -51,3 +51,4 @@ Output Files track voxel volume + weight_windows diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index 0431c95abd2..2a85ebc8ac8 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -1066,7 +1066,7 @@ sub-elements/attributes: :particle_type: The particle that the weight windows will apply to (e.g., 'neutron') - *Default*: None + *Default*: 'neutron' :energy_bins: Monotonically increasing list of bounding energies in [eV] to be used for @@ -1104,3 +1104,74 @@ sub-elements/attributes: Threshold below which particles will be terminated *Default*: :math:`10^{-38}` + +-------------------------------------- +```` Element +-------------------------------------- + +The ```` element provides information for creating a set of +mesh-based weight windows. + + :mesh: + ID of a mesh that is to be used for the weight windows spatial bins + + *Default*: None + + :energy_bounds: + The weight window energy bounds. If not present, the max/min energy of the + cross section data is applied as a single energy bin. + + *Default*: None + + :particle_type: + The particle that the weight windows will apply to (e.g., 'neutron') + + *Default*: neutron + + :max_realizations: + The number of tally realizations after which the weight windows will stop updating. + + *Default*: 1 + + :update_interval: + The number of tally realizations between weight window updates. + + *Default*: 1 + + :on_the_fly: + Controls whether or not the tally results are reset after a weight window update. + + *Default*: true + + :method: + Method used to update weight window values (currently only 'magic' is supported) + + *Default*: magic + + :update_parameters: + Method-specific update parameters used when generating/updating weight windows. + + For MAGIC: + + :value: + The type of tally value to use when creating weight windows (one of 'mean' or 'rel_err') + + *Default*: 'mean' + + :threshold: + The relative error threshold above which tally results will be ignored. + + *Default*: 1.0 + + :ratio: + The ratio of the lower to upper weight window bounds. + + *Default*: 5.0 + +-------------------------------------- +```` Element +-------------------------------------- + + The ``weight_windows_file`` element has no attributes and contains the path to + a weight windows HDF5 file to load during simulation initialization. + diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 89d973a2ba9..37a379b52cb 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -68,6 +68,8 @@ The current version of the statepoint file format is 17.0. :Attributes: - **n_meshes** (*int*) -- Number of meshes in the problem. - **ids** (*int[]*) -- User-defined unique ID of each mesh. +.. _mesh-spec-hdf5: + **/tallies/meshes/mesh /** :Datasets: - **type** (*char[]*) -- Type of mesh. diff --git a/docs/source/io_formats/weight_windows.rst b/docs/source/io_formats/weight_windows.rst new file mode 100644 index 00000000000..302e893187a --- /dev/null +++ b/docs/source/io_formats/weight_windows.rst @@ -0,0 +1,39 @@ +.. _io_weight_windows: + +==================== +Weight Window Format +==================== + +The current revision of the weight window file format is 1.0. + +**/** + +:Attributes: - **filetype** (*char[]*) -- String indicating the type of file. + - **version** (*int[2]*) -- Major and minor version of the weight + window file format. + +**/weight_windows/** + +:Attributes: - **n_weight_windows** (*int*) -- Number of weight window objects in the file. + - **ids** (*int[]*) -- Unique IDs of weight window objects in the file. + +**/weight_windows/weight_windows_/** + +:Datasets: - **mesh** (*int*) -- ID of the mesh associated with the weight window object. + - **particle_type** (*char[]*) -- Particle type to which the weight windows apply. + - **energy_bounds** (*double[]*) -- Energy bounds of the weight windows in [eV] + - **lower_ww_bounds** (*double[]*) -- Weight window lower bounds. + - **upper_ww_bounds** (*double[]*) -- Weight window upper bounds. + - **survival_ratio** (*double*) -- Weight window survival ratio. + - **max_lower_bound_ratio** (*double*) -- Maximum particle weight to lower weight window bound ratio. + - **max_split** (*int*) -- Maximum number of splits per weight window check. + - **weight_cutoff** (*double*) -- Particle weight cutoff. + +**/meshes/** + +:Attributes: - **n_meshes** (*int*) -- Number of meshes in the file. + - **ids** (*int[]*) -- User-defined unique ID of each mesh. + +**/meshes/mesh /** + +Please see the section on **/tallies/meshes/** in the :doc:`statepoint`. diff --git a/docs/source/pythonapi/base.rst b/docs/source/pythonapi/base.rst index c7304f46241..ffd521a7583 100644 --- a/docs/source/pythonapi/base.rst +++ b/docs/source/pythonapi/base.rst @@ -24,7 +24,6 @@ Simulation Settings openmc.Source openmc.SourceParticle openmc.VolumeCalculation - openmc.WeightWindows openmc.Settings .. autosummary:: @@ -230,6 +229,19 @@ Various classes may be created when performing tally slicing and/or arithmetic: openmc.arithmetic.AggregateNuclide openmc.arithmetic.AggregateFilter +Variance Reduction +------------------ + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myclass + + openmc.WeightWindows + openmc.WeightWindowGenerator + openmc.hdf5_to_wws + + Coarse Mesh Finite Difference Acceleration ------------------------------------------ diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index 89fa167ffe3..bce647ccb12 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -15,6 +15,8 @@ Functions calculate_volumes current_batch export_properties + export_weight_windows + import_weight_windows finalize find_cell find_material diff --git a/include/openmc/capi.h b/include/openmc/capi.h index ce58bed129a..ac69c652fce 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -50,6 +50,7 @@ int openmc_extend_meshes( int openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end); int openmc_filter_get_id(int32_t index, int32_t* id); int openmc_filter_get_type(int32_t index, char* type); +int openmc_filter_get_num_bins(int32_t index, int* n_bins); int openmc_filter_set_id(int32_t index, int32_t id); int openmc_finalize(); int openmc_find_cell(const double* xyz, int32_t* index, int32_t* instance); @@ -163,6 +164,36 @@ int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides); int openmc_tally_set_scores(int32_t index, int n, const char** scores); int openmc_tally_set_type(int32_t index, const char* type); int openmc_tally_set_writable(int32_t index, bool writable); +int openmc_get_weight_windows_index(int32_t id, int32_t* idx); +int openmc_weight_windows_get_id(int32_t index, int32_t* id); +int openmc_weight_windows_set_id(int32_t index, int32_t id); + +//! Updates weight window values using the specified tally +//! \param[in] ww_idx Index of the weight window object +//! \param[in] tally_idx Index of the tally to use for the update +//! \param[in] value Tally value to use for the update (one of 'mean', +//! 'rel_err') \param[in] threshold Relative error threshold for applied results +//! \param[in] ratio Upper to lower weight window bound ratio +int openmc_weight_windows_update_magic(int32_t ww_idx, int32_t tally_idx, + const char* value, double threshold, double ratio); + +int openmc_extend_weight_windows( + int32_t n, int32_t* index_start, int32_t* index_end); +int openmc_weight_windows_get_mesh(int32_t index, int32_t* mesh_idx); +int openmc_weight_windows_set_mesh(int32_t index, int32_t mesh_idx); +int openmc_weight_windows_set_energy_bounds( + int32_t index, double* e_bounds, size_t e_bounds_size); +int openmc_weight_windows_get_energy_bounds( + int32_t index, const double** e_bounds, size_t* e_bounds_size); +int openmc_weight_windows_set_particle(int32_t index, int particle); +int openmc_weight_windows_get_particle(int32_t index, int* particle); +int openmc_weight_windows_get_bounds(int32_t index, const double** lower_bounds, + const double** upper_bounds, size_t* size); +int openmc_weight_windows_set_bounds(int32_t index, const double* lower_bounds, + const double* upper_bounds, size_t size); +size_t openmc_weight_windows_size(); +int openmc_weight_windows_export(const char* filename = nullptr); +int openmc_weight_windows_import(const char* filename = nullptr); int openmc_zernike_filter_get_order(int32_t index, int* order); int openmc_zernike_filter_get_params( int32_t index, double* x, double* y, double* r); @@ -170,6 +201,8 @@ int openmc_zernike_filter_set_order(int32_t index, int order); int openmc_zernike_filter_set_params( int32_t index, const double* x, const double* y, const double* r); +int openmc_particle_filter_get_bins(int32_t idx, int bins[]); + //! Sets the mesh and energy grid for CMFD reweight //! \param[in] meshtyally_id id of CMFD Mesh Tally //! \param[in] cmfd_indices indices storing spatial and energy dimensions of diff --git a/include/openmc/constants.h b/include/openmc/constants.h index b0031fae321..6a77396b76a 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -33,6 +33,7 @@ constexpr array VERSION_VOLUME {1, 0}; constexpr array VERSION_VOXEL {2, 0}; constexpr array VERSION_MGXS_LIBRARY {1, 0}; constexpr array VERSION_PROPERTIES {1, 0}; +constexpr array VERSION_WEIGHT_WINDOWS {1, 0}; // ============================================================================ // ADJUSTABLE PARAMETERS @@ -276,7 +277,7 @@ enum class MgxsType { // ============================================================================ // TALLY-RELATED CONSTANTS -enum class TallyResult { VALUE, SUM, SUM_SQ }; +enum class TallyResult { VALUE, SUM, SUM_SQ, SIZE }; enum class TallyType { VOLUME, MESH_SURFACE, SURFACE }; diff --git a/include/openmc/mesh.h b/include/openmc/mesh.h index cef4e05184d..47f54c023fc 100644 --- a/include/openmc/mesh.h +++ b/include/openmc/mesh.h @@ -88,12 +88,6 @@ class Mesh { //! \return sampled position within tet virtual Position sample(uint64_t* seed, int32_t bin) const = 0; - //! Get the volume of a mesh bin - // - //! \param[in] bin Bin to return the volume for - //! \return Volume of the bin - virtual double volume(int bin) const = 0; - //! Determine which bins were crossed by a particle // //! \param[in] r0 Previous position of the particle @@ -125,6 +119,8 @@ class Mesh { //! Get the number of mesh cell surfaces. virtual int n_surface_bins() const = 0; + int32_t id() const { return id_; } + //! Set the mesh ID void set_id(int32_t id = -1); @@ -149,7 +145,15 @@ class Mesh { //! \param[in] bin Mesh bin to generate a label for virtual std::string bin_label(int bin) const = 0; - //! Return the mesh type + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return Volume of the bin + virtual double volume(int bin) const = 0; + + //! Volumes of all elements in the mesh in bin ordering + vector volumes() const; + virtual std::string get_mesh_type() const = 0; // Data members @@ -181,8 +185,6 @@ class StructuredMesh : public Mesh { Position sample(uint64_t* seed, int32_t bin) const override; - double volume(int bin) const override; - int get_bin(Position r) const override; int n_bins() const override; @@ -260,6 +262,16 @@ class StructuredMesh : public Mesh { //! Get shape as xt::xtensor xt::xtensor get_x_shape() const; + double volume(int bin) const override + { + return this->volume(get_indices_from_bin(bin)); + } + + //! Get the volume of a specified element + //! \param[in] ijk Mesh index to return the volume for + //! \return Volume of the bin + virtual double volume(const MeshIndex& ijk) const = 0; + // Data members xt::xtensor lower_left_; //!< Lower-left coordinates of mesh xt::xtensor upper_right_; //!< Upper-right coordinates of mesh @@ -331,8 +343,12 @@ class RegularMesh : public StructuredMesh { xt::xtensor count_sites( const SourceSite* bank, int64_t length, bool* outside) const; + //! Return the volume for a given mesh index + double volume(const MeshIndex& ijk) const override; + // Data members double volume_frac_; //!< Volume fraction of each mesh element + double element_volume_; //!< Volume of each mesh element xt::xtensor width_; //!< Width of each mesh element }; @@ -370,9 +386,13 @@ class RectilinearMesh : public StructuredMesh { //! \param[in] i Direction index double negative_grid_boundary(const MeshIndex& ijk, int i) const; - array, 3> grid_; + //! Return the volume for a given mesh index + double volume(const MeshIndex& ijk) const override; int set_grid(); + + // Data members + array, 3> grid_; }; class CylindricalMesh : public PeriodicStructuredMesh { @@ -398,6 +418,8 @@ class CylindricalMesh : public PeriodicStructuredMesh { void to_hdf5(hid_t group) const override; + double volume(const MeshIndex& ijk) const override; + array, 3> grid_; int set_grid(); @@ -478,6 +500,8 @@ class SphericalMesh : public PeriodicStructuredMesh { } } + double volume(const MeshIndex& ijk) const override; + inline int sanitize_theta(int idx) const { return sanitize_angular_index(idx, full_theta_, shape_[1]); @@ -634,6 +658,10 @@ class MOABMesh : public UnstructuredMesh { std::vector connectivity(int id) const override; + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return Volume of the bin double volume(int bin) const override; private: @@ -791,6 +819,10 @@ class LibMesh : public UnstructuredMesh { std::vector connectivity(int id) const override; + //! Get the volume of a mesh bin + // + //! \param[in] bin Bin to return the volume for + //! \return Volume of the bin double volume(int bin) const override; libMesh::MeshBase* mesh_ptr() const { return m_; }; diff --git a/include/openmc/output.h b/include/openmc/output.h index cf5b49607c5..1ef95a88792 100644 --- a/include/openmc/output.h +++ b/include/openmc/output.h @@ -59,3 +59,25 @@ void write_tallies(); } // namespace openmc #endif // OPENMC_OUTPUT_H + +////////////////////////////////////// +// Custom formatters +////////////////////////////////////// +namespace fmt { + +template +struct formatter> { + template + constexpr auto parse(ParseContext& ctx) + { + return ctx.begin(); + } + + template + auto format(const std::array& arr, FormatContext& ctx) + { + return format_to(ctx.out(), "({}, {})", arr[0], arr[1]); + } +}; + +} // namespace fmt \ No newline at end of file diff --git a/include/openmc/settings.h b/include/openmc/settings.h index f6cbe3138ee..3ce13c89f90 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -29,7 +29,7 @@ extern bool confidence_intervals; //!< use confidence intervals for results? extern bool create_fission_neutrons; //!< create fission neutrons (fixed source)? extern bool create_delayed_neutrons; //!< create delayed fission neutrons? -extern "C" bool cmfd_run; //!< is a CMFD run? +extern "C" bool cmfd_run; //!< is a CMFD run? extern bool delayed_photon_scaling; //!< Scale fission photon yield to include delayed extern "C" bool entropy_on; //!< calculate Shannon entropy? @@ -58,7 +58,7 @@ extern "C" bool trigger_on; //!< tally triggers enabled? extern bool trigger_predict; //!< predict batches for triggers? extern bool ufs_on; //!< uniform fission site method on? extern bool urr_ptables_on; //!< use unresolved resonance prob. tables? -extern bool weight_windows_on; //!< are weight windows are enabled? +extern "C" bool weight_windows_on; //!< are weight windows are enabled? extern bool write_all_tracks; //!< write track files for every particle? extern bool write_initial_source; //!< write out initial source file? @@ -69,6 +69,8 @@ extern std::string path_output; //!< directory where output files are written extern std::string path_particle_restart; //!< path to a particle restart file extern std::string path_sourcepoint; //!< path to a source file extern std::string path_statepoint; //!< path to a statepoint file +extern std::string weight_windows_file; //!< Location of weight window file to + //!< load on simulation initialization // This is required because the c_str() may not be the first thing in // std::string. Sometimes it is, but it seems libc++ may not be like that diff --git a/include/openmc/tallies/filter_mesh.h b/include/openmc/tallies/filter_mesh.h index e3bcd7c20f5..2f48b6d4d48 100644 --- a/include/openmc/tallies/filter_mesh.h +++ b/include/openmc/tallies/filter_mesh.h @@ -55,9 +55,9 @@ class MeshFilter : public Filter { //---------------------------------------------------------------------------- // Data members - int32_t mesh_; - bool translated_ {false}; - Position translation_ {0.0, 0.0, 0.0}; + int32_t mesh_; //!< Index of the mesh + bool translated_ {false}; //!< Whether or not the filter is translated + Position translation_ {0.0, 0.0, 0.0}; //!< Filter translation }; } // namespace openmc diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index 6ad3bef6f3b..303b1ebb176 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -35,6 +35,8 @@ class Tally { void set_id(int32_t id); + int id() const { return id_; } + void set_active(bool active) { active_ = active; } void set_multiply_density(bool value) { multiply_density_ = value; } @@ -45,16 +47,52 @@ class Tally { void set_scores(const vector& scores); + std::vector scores() const; + + int32_t n_scores() const { return scores_.size(); } + void set_nuclides(pugi::xml_node node); void set_nuclides(const vector& nuclides); + const xt::xtensor& results() const { return results_; } + //! returns vector of indices corresponding to the tally this is called on const vector& filters() const { return filters_; } + //! returns a vector of filter types for the tally + std::vector filter_types() const; + + //! returns a mapping of filter types to index into the tally's filters + std::unordered_map filter_indices() const; + //! \brief Returns the tally filter at index i int32_t filters(int i) const { return filters_[i]; } + //! \brief Return a const pointer to a filter instance based on type. Always + //! returns the first matching filter type + template + const T* get_filter() const + { + const T* out; + for (auto filter_idx : filters_) { + if ((out = dynamic_cast(model::tally_filters[filter_idx].get()))) + return out; + } + return nullptr; + } + + template + const T* get_filter(int idx) const + { + if (const T* out = dynamic_cast(model::tally_filters[filters_.at(idx)])) + return out; + return nullptr; + } + + //! \brief Check if this tally has a specified type of filter + bool has_filter(FilterType filter_type) const; + void set_filters(gsl::span filters); //! Given already-set filters, set the stride lengths @@ -81,6 +119,12 @@ class Tally { void accumulate(); + //! return the index of a score specified by name + int score_index(const std::string& score) const; + + //! Tally results reshaped according to filter sizes + xt::xarray get_reshaped_data() const; + //! A string representing the i-th score on this tally std::string score_name(int score_idx) const; diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index 45c1de91970..75073e917cb 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -11,104 +12,214 @@ #include "openmc/memory.h" #include "openmc/mesh.h" #include "openmc/particle.h" +#include "openmc/tallies/tally.h" #include "openmc/vector.h" -namespace openmc { - -//============================================================================== -// Constants -//============================================================================== - -constexpr double DEFAULT_WEIGHT_CUTOFF {1.0e-38}; // default low weight cutoff - -//============================================================================== -// Non-member functions -//============================================================================== - -//! Apply weight windows to a particle -//! \param[in] p Particle to apply weight windows to -void apply_weight_windows(Particle& p); - -//! Free memory associated with weight windows -void free_memory_weight_windows(); - -//============================================================================== -// Global variables -//============================================================================== - -class WeightWindows; - -namespace variance_reduction { - -extern std::unordered_map ww_map; -extern vector> weight_windows; - -} // namespace variance_reduction - -//============================================================================== -//! Individual weight window information -//============================================================================== - -struct WeightWindow { - double lower_weight {-1}; // -1 indicates invalid state - double upper_weight {1}; - double max_lb_ratio {1}; - double survival_weight {0.5}; - double weight_cutoff {DEFAULT_WEIGHT_CUTOFF}; - int max_split {1}; - - //! Whether the weight window is in a valid state - bool is_valid() const { return lower_weight >= 0.0; } - - //! Adjust the weight window by a constant factor - void scale(double factor) - { - lower_weight *= factor; - upper_weight *= factor; - } -}; - -//============================================================================== -//! Weight window settings -//============================================================================== - -class WeightWindows { -public: - // Constructors - WeightWindows(); - WeightWindows(pugi::xml_node node); - - // Methods - - //! Set the weight window ID - void set_id(int32_t id = -1); - - // NOTE: This is unused for now but may be used in the future - //! Write weight window settings to an HDF5 file - //! \param[in] group HDF5 group to write to - void to_hdf5(hid_t group) const; - - //! Retrieve the weight window for a particle - //! \param[in] p Particle to get weight window for - WeightWindow get_weight_window(const Particle& p) const; - - // Accessors - int32_t id() const { return id_; } - const Mesh& mesh() const { return *model::meshes[mesh_idx_]; } - -private: - // Data members - int32_t id_; //!< Unique ID - ParticleType particle_type_; //!< Particle type to apply weight windows to - vector energy_bounds_; //!< Energy boundaries [eV] - vector lower_ww_; //!< Lower weight window bounds - vector upper_ww_; //!< Upper weight window bounds - double survival_ratio_ {3.0}; //!< Survival weight ratio - double max_lb_ratio_ {1.0}; //!< Maximum lower bound to particle weight ratio - double weight_cutoff_ {DEFAULT_WEIGHT_CUTOFF}; //!< Weight cutoff - int max_split_ {10}; //!< Maximum value for particle splitting - int32_t mesh_idx_; //!< index in meshes vector -}; + namespace openmc +{ + + enum class WeightWindowUpdateMethod { + MAGIC, + }; + + //============================================================================== + // Constants + //============================================================================== + + constexpr double DEFAULT_WEIGHT_CUTOFF {1.0e-38}; // default low weight cutoff + + //============================================================================== + // Non-member functions + //============================================================================== + + //! Apply weight windows to a particle + //! \param[in] p Particle to apply weight windows to + void apply_weight_windows(Particle & p); + + //! Free memory associated with weight windows + void free_memory_weight_windows(); + + //============================================================================== + // Global variables + //============================================================================== + + class WeightWindows; + class WeightWindowsGenerator; + + namespace variance_reduction { + + extern std::unordered_map ww_map; + extern vector> weight_windows; + extern vector> weight_windows_generators; + + } // namespace variance_reduction + + //============================================================================== + //! Individual weight window information + //============================================================================== + + struct WeightWindow { + double lower_weight {-1}; // -1 indicates invalid state + double upper_weight {1}; + double max_lb_ratio {1}; + double survival_weight {0.5}; + double weight_cutoff {DEFAULT_WEIGHT_CUTOFF}; + int max_split {1}; + + //! Whether the weight window is in a valid state + bool is_valid() const { return lower_weight >= 0.0; } + + //! Adjust the weight window by a constant factor + void scale(double factor) + { + lower_weight *= factor; + upper_weight *= factor; + } + }; + + //============================================================================== + //! Weight window settings + //============================================================================== + + class WeightWindows { + public: + //---------------------------------------------------------------------------- + // Constructors + WeightWindows(int32_t id = -1); + WeightWindows(pugi::xml_node node); + ~WeightWindows(); + static WeightWindows* create(int32_t id = -1); + static WeightWindows* from_hdf5( + hid_t wws_group, const std::string& group_name); + + //---------------------------------------------------------------------------- + // Methods + private: + template + void check_bounds(const T& lower, const T& upper) const; + + template + void check_bounds(const T& lower) const; + + void check_tally_update_compatibility(const Tally* tally); + + public: + //! Set the weight window ID + void set_id(int32_t id = -1); + + void set_energy_bounds(gsl::span bounds); + + void set_mesh(const std::unique_ptr& mesh); + + void set_mesh(const Mesh* mesh); + + void set_mesh(int32_t mesh_idx); + + //! Ready the weight window class for use + void set_defaults(); + + //! Update weight window boundaries using tally results + //! \param[in] tally Pointer to the tally whose results will be used to + //! update weight windows \param[in] value String representing the type of + //! value to use for weight window generation (one of "mean" or "rel_err") + //! \param[in] threshold Relative error threshold. Results over this + //! threshold will be ignored \param[in] ratio Ratio of upper to lower + //! weight window bounds + void update_magic(const Tally* tally, const std::string& value = "mean", + double threshold = 1.0, double ratio = 5.0); + + // NOTE: This is unused for now but may be used in the future + //! Write weight window settings to an HDF5 file + //! \param[in] group HDF5 group to write to + void to_hdf5(hid_t group) const; + + //! Retrieve the weight window for a particle + //! \param[in] p Particle to get weight window for + WeightWindow get_weight_window(const Particle& p) const; + + std::array bounds_size() const; + + const vector& energy_bounds() const { return energy_bounds_; } + + void set_bounds(const xt::xtensor& lower_ww_bounds, + const xt::xtensor& upper_bounds); + + void set_bounds(const xt::xtensor& lower_bounds, double ratio); + + void set_bounds(gsl::span lower_bounds, + gsl::span upper_bounds); + + void set_bounds(gsl::span lower_bounds, double ratio); + + void set_particle_type(ParticleType p_type); + + //---------------------------------------------------------------------------- + // Accessors + int32_t id() const { return id_; } + int32_t& id() { return id_; } + + int32_t index() const { return index_; } + + vector& energy_bounds() { return energy_bounds_; } + + const std::unique_ptr& mesh() const + { + return model::meshes[mesh_idx_]; + } + + const xt::xtensor& lower_ww_bounds() const { return lower_ww_; } + xt::xtensor& lower_ww_bounds() { return lower_ww_; } + + const xt::xtensor& upper_ww_bounds() const { return upper_ww_; } + xt::xtensor& upper_ww_bounds() { return upper_ww_; } + + ParticleType particle_type() const { return particle_type_; } + + private: + //---------------------------------------------------------------------------- + // Data members + int32_t id_; //!< Unique ID + gsl::index index_; //!< Index into weight windows vector + ParticleType particle_type_ { + ParticleType::neutron}; //!< Particle type to apply weight windows to + vector energy_bounds_; //!< Energy boundaries [eV] + xt::xtensor lower_ww_; //!< Lower weight window bounds (shape: + //!< energy_bins, mesh_bins (k, j, i)) + xt::xtensor + upper_ww_; //!< Upper weight window bounds (shape: energy_bins, mesh_bins) + double survival_ratio_ {3.0}; //!< Survival weight ratio + double max_lb_ratio_ { + 1.0}; //!< Maximum lower bound to particle weight ratio + double weight_cutoff_ {DEFAULT_WEIGHT_CUTOFF}; //!< Weight cutoff + int max_split_ {10}; //!< Maximum value for particle splitting + int32_t mesh_idx_; //!< Index in meshes vector + }; + + class WeightWindowsGenerator { + public: + // Constructors + WeightWindowsGenerator(pugi::xml_node node); + + // Methods + void update() const; + + // Data members + int32_t + tally_idx_; //!< Index of the tally used to update the weight windows + int32_t ww_idx_; //!< Index of the weight windows object being generated + std::string method_; //!< Method used to update weight window. Only "magic" + //!< is valid for now. + int32_t max_realizations_; //!< Maximum number of tally realizations + int32_t update_interval_; //!< Determines how often updates occur + bool on_the_fly_; //!< Whether or not weight windows + + // MAGIC update parameters + std::string tally_value_ { + "mean"}; // typing.List[WeightWindows]: def weight_windows_on(self) -> bool: return self._weight_windows_on + @property + def weight_windows_file(self) -> Optional[PathLike]: + return self._weight_windows_file + + @weight_windows_file.setter + def weight_windows_file(self, value: PathLike): + cv.check_type('weight windows file', value, (str, Path)) + self._weight_windows_file = value + + @property + def weight_window_generators(self) -> typing.List[WeightWindowGenerator]: + return self._weight_window_generators + + @weight_window_generators.setter + def weight_window_generators(self, wwgs): + if not isinstance(wwgs, MutableSequence): + wwgs = [wwgs] + self._weight_window_generators = cv.CheckedList(WeightWindowGenerator, 'weight window generators', wwgs) + @property def max_splits(self) -> int: return self._max_splits @@ -922,7 +954,7 @@ def weight_windows(self, value: typing.Union[WeightWindows, typing.Iterable[Weig self._weight_windows = cv.CheckedList(WeightWindows, 'weight windows', value) @weight_windows_on.setter - def weight_windows_on(self, value): + def weight_windows_on(self, value: bool): cv.check_type('weight windows on', value, bool) self._weight_windows_on = value @@ -1283,6 +1315,28 @@ def _create_weight_windows_subelement(self, root, mesh_memo=None): elem = ET.SubElement(root, "weight_windows_on") elem.text = str(self._weight_windows_on).lower() + def _create_weight_window_generators_subelement(self, root, mesh_memo=None): + if not self.weight_window_generators: + return + elem = ET.SubElement(root, 'weight_window_generators') + for wwg in self.weight_window_generators: + elem.append(wwg.to_xml_element()) + + # ensure that mesh elements are created if needed + for wwg in self.weight_window_generators: + if mesh_memo is not None and wwg.mesh.id in mesh_memo: + continue + + root.append(wwg.mesh.to_xml_element()) + if mesh_memo is not None: + mesh_memo.add(wwg.mesh) + + def _create_weight_windows_file_element(self, root): + if self.weight_windows_file is not None: + element = ET.Element("weight_windows_file") + element.text = self.weight_windows_file + root.append(element) + def _create_max_splits_subelement(self, root): if self._max_splits is not None: elem = ET.SubElement(root, "max_splits") @@ -1595,6 +1649,11 @@ def _write_initial_source_from_xml_element(self, root): if text is not None: self.write_initial_source = text in ('true', '1') + def _weight_window_generators_from_xml_element(self, root, meshes=None): + for elem in root.iter('weight_windows_generator'): + wwg = WeightWindowGenerator.from_xml_element(elem, meshes) + self.weight_window_generators.append(wwg) + def _weight_windows_from_xml_element(self, root, meshes=None): for elem in root.findall('weight_windows'): ww = WeightWindows.from_xml_element(elem, root) @@ -1671,6 +1730,8 @@ def to_xml_element(self, mesh_memo=None): self._create_log_grid_bins_subelement(element) self._create_write_initial_source_subelement(element) self._create_weight_windows_subelement(element, mesh_memo) + self._create_weight_window_generators_subelement(element, mesh_memo) + self._create_weight_windows_file_element(element) self._create_max_splits_subelement(element) self._create_max_tracks_subelement(element) @@ -1764,6 +1825,7 @@ def from_xml_element(cls, elem, meshes=None): settings._log_grid_bins_from_xml_element(elem) settings._write_initial_source_from_xml_element(elem) settings._weight_windows_from_xml_element(elem, meshes) + settings._weight_window_generators_from_xml_element(elem, meshes) settings._max_splits_from_xml_element(elem) settings._max_tracks_from_xml_element(elem) diff --git a/openmc/source.py b/openmc/source.py index 9851ea59d3c..cc68c9535b1 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -1,11 +1,11 @@ from collections.abc import Iterable -from enum import Enum +from enum import IntEnum from numbers import Real import warnings import typing # imported separately as py3.8 requires typing.Iterable # also required to prevent typing.Union namespace overwriting Union from typing import Optional, Sequence -import lxml.etree as ET +import lxml.etree as ET import numpy as np import h5py @@ -333,12 +333,53 @@ def from_xml_element(cls, elem: ET.Element, meshes=None) -> 'openmc.Source': return source -class ParticleType(Enum): +class ParticleType(IntEnum): + """ + IntEnum class representing a particle type. Type + values mirror those found in the C++ class. + """ NEUTRON = 0 PHOTON = 1 ELECTRON = 2 POSITRON = 3 + @classmethod + def from_string(cls, value: str): + """ + Constructs a ParticleType instance from a string. + + Parameters + ---------- + value : str + The string representation of the particle type. + + Returns + ------- + The corresponding ParticleType instance. + """ + try: + return cls[value.upper()] + except KeyError: + raise ValueError(f"Invalid string for creation of {cls.__name__}: {value}") + + def __repr__(self) -> str: + """ + Returns a string representation of the ParticleType instance. + + Returns: + str: The lowercase name of the ParticleType instance. + """ + return self.name.lower() + + # needed for < Python 3.11 + def __str__(self) -> str: + return self.__repr__() + + # needed for <= 3.7, IntEnum will use the mixed-in type's `__format__` method otherwise + # this forces it to default to the standard object format, relying on __str__ under the hood + def __format__(self, spec): + return object.__format__(self, spec) + class SourceParticle: """Source particle diff --git a/openmc/tallies.py b/openmc/tallies.py index 85daaa17a1d..6f56fbb64dd 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -3222,7 +3222,6 @@ def to_xml_element(self, memo=None): return element - def export_to_xml(self, path='tallies.xml'): """Create a tallies.xml file that can be used for a simulation. diff --git a/openmc/tracks.py b/openmc/tracks.py index 9b4b55247db..61e5a72442e 100644 --- a/openmc/tracks.py +++ b/openmc/tracks.py @@ -25,8 +25,7 @@ """ def _particle_track_repr(self): - name = self.particle.name.lower() - return f"" + return f"" ParticleTrack.__repr__ = _particle_track_repr diff --git a/openmc/weight_windows.py b/openmc/weight_windows.py index c09e1e862ba..2411b83f805 100644 --- a/openmc/weight_windows.py +++ b/openmc/weight_windows.py @@ -2,19 +2,20 @@ from collections.abc import Iterable from numbers import Real, Integral import pathlib -import typing from typing import Iterable, List, Optional, Union, Dict +import warnings import lxml.etree as ET import numpy as np import h5py +import openmc from openmc.filter import _PARTICLES from openmc.mesh import MeshBase, RectilinearMesh, UnstructuredMesh import openmc.checkvalue as cv from openmc.checkvalue import PathLike -from ._xml import get_text +from ._xml import get_text, clean_indentation from .mixin import IDManagerMixin @@ -108,8 +109,8 @@ class WeightWindows(IDManagerMixin): used_ids = set() def __init__( - self, - mesh: MeshBase, + self, + mesh: MeshBase, lower_ww_bounds: Iterable[float], upper_ww_bounds: Optional[Iterable[float]] = None, upper_bound_ratio: Optional[float] = None, @@ -159,7 +160,7 @@ def __init__( def __repr__(self) -> str: string = type(self).__name__ + '\n' string += '{: <16}=\t{}\n'.format('\tID', self._id) - string += '{: <16}=\t{}\n'.format('\tMesh:', self.mesh) + string += '{: <16}=\t{}\n'.format('\tMesh', self.mesh) string += '{: <16}=\t{}\n'.format('\tParticle Type', self._particle_type) string += '{: <16}=\t{}\n'.format('\tEnergy Bounds', self._energy_bounds) string += '{: <16}=\t{}\n'.format('\tLower WW Bounds', self._lower_ww_bounds) @@ -286,7 +287,7 @@ def max_lower_bound_ratio(self) -> float: @max_lower_bound_ratio.setter def max_lower_bound_ratio(self, val: float): cv.check_type('Maximum lower bound ratio', val, Real) - cv.check_greater_than('Maximum lower bound ratio', val, 1.0) + cv.check_greater_than('Maximum lower bound ratio', val, 1.0, equality=True) self._max_lower_bound_ratio = val @property @@ -424,10 +425,15 @@ def from_hdf5(cls, group: h5py.Group, meshes: Dict[int, MeshBase]) -> WeightWind id = int(group.name.split('/')[-1].lstrip('weight_windows')) mesh_id = group['mesh'][()] + mesh = meshes[mesh_id] + ptype = group['particle_type'][()].decode() e_bounds = group['energy_bounds'][()] - lower_ww_bounds = group['lower_ww_bounds'][()] - upper_ww_bounds = group['upper_ww_bounds'][()] + # weight window bounds are stored with the shape (e, k, j, i) + # in C++ and HDF5 -- the opposite of how they are stored here + shape = (e_bounds.size - 1, *mesh.dimension[::-1]) + lower_ww_bounds = group['lower_ww_bounds'][()].reshape(shape).T + upper_ww_bounds = group['upper_ww_bounds'][()].reshape(shape).T survival_ratio = group['survival_ratio'][()] max_lower_bound_ratio = None @@ -438,7 +444,7 @@ def from_hdf5(cls, group: h5py.Group, meshes: Dict[int, MeshBase]) -> WeightWind weight_cutoff = group['weight_cutoff'][()] return cls( - mesh=meshes[mesh_id], + mesh=mesh, lower_ww_bounds=lower_ww_bounds, upper_ww_bounds=upper_ww_bounds, energy_bounds=e_bounds, @@ -622,3 +628,281 @@ def wwinp_to_wws(path: PathLike) -> List[WeightWindows]: wws.append(ww) return wws + + +class WeightWindowGenerator: + """Class passed to setting to govern weight window generation + using the OpenMC executable + + Parameters + ---------- + mesh : :class:`openmc.MeshBase` + Mesh used to represent the weight windows spatially + energy_bounds : Iterable of Real + A list of values for which each successive pair constitutes a range of + energies in [eV] for a single bin + particle_type : {'neutron', 'photon'} + Particle type the weight windows apply to + + Attributes + ---------- + mesh : openmc.MeshBase + Mesh used to represent the weight windows spatially + energy_bounds : Iterable of Real + A list of values for which each successive pair constitutes a range of + energies in [eV] for a single bin + particle_type : {'neutron', 'photon'} + Particle type the weight windows apply to + method : {'magic'} + The weight window generation methodology applied during an update. Only + 'magic' is currently supported. + max_realizations : int + The upper limit for number of tally realizations when generating weight + windows. + update_interval : int + The number of tally realizations between updates. (default: 1) + update_parameters : dict + A set of parameters related to the update. + on_the_fly : bool + Whether or not to apply weight windows on the fly. (default: True) + """ + + _MAGIC_PARAMS = {'value': str, 'threshold': float, 'ratio': float} + + def __init__(self, mesh, energy_bounds=None, particle_type='neutron'): + self.mesh = mesh + if energy_bounds is not None: + self.energy_bounds = energy_bounds + self.particle_type = particle_type + self.max_realizations = 1 + + self._update_parameters = None + + self.method = 'magic' + self.particle_type = particle_type + self.update_interval = 1 + self.on_the_fly = True + + + def __repr__(self): + string = type(self).__name__ + '\n' + string += f'\t{"Mesh":<20}=\t{self.mesh.id}\n' + string += f'\t{"Particle:":<20}=\t{self.particle_type}\n' + string += f'\t{"Energy Bounds:":<20}=\t{self.energy_bounds}\n' + string += f'\t{"Method":<20}=\t{self.method}\n' + string += f'\t{"Max Realizations:":<20}=\t{self.max_realizations}\n' + string += f'\t{"Update Interval:":<20}=\t{self.update_interval}\n' + string += f'\t{"On The Fly:":<20}=\t{self.on_the_fly}\n' + if self.update_parameters is not None: + string += f'\t{"Update Parameters:":<20}\n\t\t\t{self.update_parameters}\n' + string + + return string + + @property + def mesh(self) -> openmc.MeshBase: + return self._mesh + + @mesh.setter + def mesh(self, m: openmc.MeshBase): + cv.check_type('mesh', m, openmc.MeshBase) + self._mesh = m + + @property + def energy_bounds(self) -> Iterable[Real]: + return self._energy_bounds + + @energy_bounds.setter + def energy_bounds(self, eb: Iterable[float]): + cv.check_type('energy bounds', eb, Iterable, Real) + self._energy_bounds = eb + + @property + def particle_type(self) -> str: + return self._particle_type + + @particle_type.setter + def particle_type(self, pt: str): + cv.check_value('particle type', pt, ('neutron', 'photon')) + self._particle_type = pt + + @property + def method(self) -> str: + return self._method + + @method.setter + def method(self, m: str): + cv.check_type('generation method', m, str) + cv.check_value('generation method', m, {'magic'}) + self._method = m + if self._update_parameters is not None: + try: + self._check_update_parameters() + except (TypeError, KeyError): + warnings.warn(f'Update parameters are invalid for the "{m}" method.') + + @property + def max_realizations(self) -> int: + return self._max_realizations + + @max_realizations.setter + def max_realizations(self, m: int): + cv.check_type('max tally realizations', m, Integral) + cv.check_greater_than('max tally realizations', m, 0) + self._max_realizations = m + + @property + def update_interval(self) -> int: + return self._update_interval + + @update_interval.setter + def update_interval(self, ui: int): + cv.check_type('update interval', ui, Integral) + cv.check_greater_than('update interval', ui , 0) + self._update_interval = ui + + @property + def update_parameters(self) -> dict: + return self._update_parameters + + def _check_update_parameters(self, params: dict): + if self.method == 'magic': + check_params = self._MAGIC_PARAMS + + for key, val in params.items(): + if key not in check_params: + raise ValueError(f'Invalid param "{key}" for {self.method} ' + 'weight window generation') + cv.check_type(f'weight window generation param: "{key}"', val, self._MAGIC_PARAMS[key]) + + @update_parameters.setter + def update_parameters(self, params: dict): + self._check_update_parameters(params) + self._update_parameters = params + + @property + def on_the_fly(self) -> bool: + return self._on_the_fly + + @on_the_fly.setter + def on_the_fly(self, otf: bool): + cv.check_type('on the fly generation', otf, bool) + self._on_the_fly = otf + + def _update_parameters_subelement(self, element: ET.Element): + if not self.update_parameters: + return + params_element = ET.SubElement(element, 'update_parameters') + for pname, value in self.update_parameters.items(): + param_element = ET.SubElement(params_element, pname) + param_element.text = str(value) + + @classmethod + def _sanitize_update_parameters(cls, method: str, update_parameters: dict): + """ + Attempt to convert update parameters to their appropriate types + + Parameters + ---------- + method : str + The update method for which these update parameters should comply + update_parameters : dict + The update parameters as-read from the XML node (keys: str, values: str) + """ + if method == 'magic': + check_params = cls._MAGIC_PARAMS + + for param, param_type in check_params.items(): + if param in update_parameters: + update_parameters[param] = param_type(update_parameters[param]) + + def to_xml_element(self): + """Creates a 'weight_window_generator' element to be written to an XML file. + """ + element = ET.Element('weight_windows_generator') + + mesh_elem = ET.SubElement(element, 'mesh') + mesh_elem.text = str(self.mesh.id) + if self.energy_bounds is not None: + subelement = ET.SubElement(element, 'energy_bounds') + subelement.text = ' '.join(str(e) for e in self.energy_bounds) + particle_elem = ET.SubElement(element, 'particle_type') + particle_elem.text = self.particle_type + realizations_elem = ET.SubElement(element, 'max_realizations') + realizations_elem.text = str(self.max_realizations) + update_interval_elem = ET.SubElement(element, 'update_interval') + update_interval_elem.text = str(self.update_interval) + otf_elem = ET.SubElement(element, 'on_the_fly') + otf_elem.text = str(self.on_the_fly).lower() + method_elem = ET.SubElement(element, 'method') + method_elem.text = self.method + if self.update_parameters is not None: + self._update_parameters_subelement(element) + + clean_indentation(element) + + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element, meshes: dict) -> WeightWindowGenerator: + """ + Create a weight window generation object from an XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + meshes : dict + A dictionary with IDs as keys and openmc.MeshBase instances as values + + Returns + ------- + openmc.WeightWindowGenerator + """ + + mesh_id = int(get_text(elem, 'mesh')) + mesh = meshes[mesh_id] + + energy_bounds = [float(x) for x in get_text(elem, 'energy_bounds').split()] + particle_type = get_text(elem, 'particle_type') + + wwg = cls(mesh, energy_bounds, particle_type) + + wwg.max_realizations = int(get_text(elem, 'max_realizations')) + wwg.update_interval = int(get_text(elem, 'update_interval')) + wwg.on_the_fly = bool(get_text(elem, 'on_the_fly')) + wwg.method = get_text(elem, 'method') + + if elem.find('update_parameters'): + update_parameters = {} + params_elem = elem.find('update_parameters') + for entry in params_elem: + update_parameters[entry.tag] = entry.text + + cls._sanitize_update_parameters(wwg.method, update_parameters) + wwg.update_parameters = update_parameters + + return wwg + +def hdf5_to_wws(path='weight_windows.h5'): + """Create WeightWindows instances from a weight windows HDF5 file + + .. versionadded:: 0.13.4 + + Parameters + ---------- + path : cv.PathLike + Path to the weight windows hdf5 file + + Returns + ------- + list of openmc.WeightWindows + """ + + with h5py.File(path) as h5_file: + # read in all of the meshes in the mesh node + meshes = {} + for mesh_group in h5_file['meshes']: + mesh = MeshBase.from_hdf5(h5_file['meshes'][mesh_group]) + meshes[mesh.id] = mesh + return [WeightWindows.from_hdf5(ww, meshes) for ww in h5_file['weight_windows'].values()] \ No newline at end of file diff --git a/src/mesh.cpp b/src/mesh.cpp index e72a5cf7d84..12052bed62f 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -132,6 +132,15 @@ void Mesh::set_id(int32_t id) model::mesh_map[id] = model::meshes.size() - 1; } +vector Mesh::volumes() const +{ + vector volumes(n_bins()); + for (int i = 0; i < n_bins(); i++) { + volumes[i] = this->volume(i); + } + return volumes; +} + //============================================================================== // Structured Mesh implementation //============================================================================== @@ -377,11 +386,6 @@ Position StructuredMesh::sample(uint64_t* seed, int32_t bin) const fatal_error("Position sampling on structured meshes is not yet implemented"); } -double StructuredMesh::volume(int bin) const -{ - fatal_error("Unable to get volume of structured mesh, not yet implemented"); -} - int StructuredMesh::get_bin(Position r) const { // Determine indices @@ -722,6 +726,11 @@ RegularMesh::RegularMesh(pugi::xml_node node) : StructuredMesh {node} // Set volume fraction volume_frac_ = 1.0 / xt::prod(shape)(); + + element_volume_ = 1.0; + for (int i = 0; i < n_dimension_; i++) { + element_volume_ *= width_[i]; + } } int RegularMesh::get_index_in_direction(double r, int i) const @@ -875,6 +884,11 @@ xt::xtensor RegularMesh::count_sites( return counts; } +double RegularMesh::volume(const MeshIndex& ijk) const +{ + return element_volume_; +} + //============================================================================== // RectilinearMesh implementation //============================================================================== @@ -1004,6 +1018,16 @@ void RectilinearMesh::to_hdf5(hid_t group) const close_group(mesh_group); } +double RectilinearMesh::volume(const MeshIndex& ijk) const +{ + double vol {1.0}; + + for (int i = 0; i < n_dimension_; i++) { + vol *= grid_[i][ijk[i] + 1] - grid_[i][ijk[i]]; + } + return vol; +} + //============================================================================== // CylindricalMesh implementation //============================================================================== @@ -1012,7 +1036,6 @@ CylindricalMesh::CylindricalMesh(pugi::xml_node node) : PeriodicStructuredMesh {node} { n_dimension_ = 3; - grid_[0] = get_node_array(node, "r_grid"); grid_[1] = get_node_array(node, "phi_grid"); grid_[2] = get_node_array(node, "z_grid"); @@ -1249,6 +1272,20 @@ void CylindricalMesh::to_hdf5(hid_t group) const close_group(mesh_group); } +double CylindricalMesh::volume(const MeshIndex& ijk) const +{ + double r_i = grid_[0][ijk[0] - 1]; + double r_o = grid_[0][ijk[0]]; + + double phi_i = grid_[1][ijk[1] - 1]; + double phi_o = grid_[1][ijk[1]]; + + double z_i = grid_[2][ijk[2] - 1]; + double z_o = grid_[2][ijk[2]]; + + return 0.5 * (r_o * r_o - r_i * r_i) * (phi_o - phi_i) * (z_o - z_i); +} + //============================================================================== // SphericalMesh implementation //============================================================================== @@ -1523,6 +1560,21 @@ void SphericalMesh::to_hdf5(hid_t group) const close_group(mesh_group); } +double SphericalMesh::volume(const MeshIndex& ijk) const +{ + double r_i = grid_[0][ijk[0] - 1]; + double r_o = grid_[0][ijk[0]]; + + double theta_i = grid_[1][ijk[1] - 1]; + double theta_o = grid_[1][ijk[1]]; + + double phi_i = grid_[2][ijk[2] - 1]; + double phi_o = grid_[2][ijk[2]]; + + return (1.0 / 3.0) * (r_o * r_o * r_o - r_i * r_i * r_i) * + (std::cos(theta_i) - std::cos(theta_o)) * (phi_o - phi_i); +} + //============================================================================== // Helper functions for the C API //============================================================================== diff --git a/src/settings.cpp b/src/settings.cpp index 6d144412237..e16afbedc2a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -83,6 +83,7 @@ std::string path_particle_restart; std::string path_sourcepoint; std::string path_statepoint; const char* path_statepoint_c {path_statepoint.c_str()}; +std::string weight_windows_file; int32_t n_inactive {0}; int32_t max_lost_particles {10}; @@ -904,11 +905,19 @@ void read_settings_xml(pugi::xml_node root) for (pugi::xml_node node_ww : root.children("weight_windows")) { variance_reduction::weight_windows.emplace_back( std::make_unique(node_ww)); + } - // Enable weight windows by default if one or more are present + // Enable weight windows by default if one or more are present + if (variance_reduction::weight_windows.size() > 0) settings::weight_windows_on = true; + + // read weight windows from file + if (check_for_node(root, "weight_windows_file")) { + weight_windows_file = get_node_value(root, "weight_windows_file"); } + // read settings for weight windows value, this will override + // the automatic setting even if weight windows are present if (check_for_node(root, "weight_windows_on")) { weight_windows_on = get_node_value_bool(root, "weight_windows_on"); } @@ -920,6 +929,24 @@ void read_settings_xml(pugi::xml_node root) if (check_for_node(root, "max_tracks")) { settings::max_tracks = std::stoi(get_node_value(root, "max_tracks")); } + + // Create weight window generator objects + if (check_for_node(root, "weight_window_generators")) { + auto wwgs_node = root.child("weight_window_generators"); + for (pugi::xml_node node_wwg : + wwgs_node.children("weight_windows_generator")) { + variance_reduction::weight_windows_generators.emplace_back( + std::make_unique(node_wwg)); + } + // if any of the weight windows are intended to be generated otf, make sure + // they're applied + for (const auto& wwg : variance_reduction::weight_windows_generators) { + if (wwg->on_the_fly_) { + settings::weight_windows_on = true; + break; + } + } + } } void free_memory_settings() diff --git a/src/simulation.cpp b/src/simulation.cpp index d46787c2822..310629936bd 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -24,6 +24,7 @@ #include "openmc/tallies/trigger.h" #include "openmc/timer.h" #include "openmc/track_output.h" +#include "openmc/weight_windows.h" #ifdef _OPENMP #include @@ -137,6 +138,11 @@ int openmc_simulation_init() } } + // load weight windows from file + if (!settings::weight_windows_file.empty()) { + openmc_weight_windows_import(settings::weight_windows_file.c_str()); + } + // Set flag indicating initialization is done simulation::initialized = true; return 0; @@ -175,6 +181,12 @@ int openmc_simulation_finalize() if (settings::output_tallies && mpi::master) write_tallies(); + // If weight window generators are present in this simulation, + // write a weight windows file + if (variance_reduction::weight_windows_generators.size() > 0) { + openmc_weight_windows_export(); + } + // Deactivate all tallies for (auto& t : model::tallies) { t->active_ = false; @@ -356,6 +368,11 @@ void finalize_batch() accumulate_tallies(); simulation::time_tallies.stop(); + // update weight windows if needed + for (const auto& wwg : variance_reduction::weight_windows_generators) { + wwg->update(); + } + // Reset global tally results if (simulation::current_batch <= settings::n_inactive) { xt::view(simulation::global_tallies, xt::all()) = 0.0; diff --git a/src/tallies/filter.cpp b/src/tallies/filter.cpp index 5e8204b2adf..d8efd590f96 100644 --- a/src/tallies/filter.cpp +++ b/src/tallies/filter.cpp @@ -221,6 +221,15 @@ extern "C" int openmc_filter_get_type(int32_t index, char* type) return 0; } +extern "C" int openmc_filter_get_num_bins(int32_t index, int* n_bins) +{ + if (int err = verify_filter(index)) + return err; + + *n_bins = model::tally_filters[index]->n_bins(); + return 0; +} + extern "C" int openmc_get_filter_index(int32_t id, int32_t* index) { auto it = model::filter_map.find(id); diff --git a/src/tallies/filter_particle.cpp b/src/tallies/filter_particle.cpp index 3865824f670..56d93a47f40 100644 --- a/src/tallies/filter_particle.cpp +++ b/src/tallies/filter_particle.cpp @@ -58,4 +58,23 @@ std::string ParticleFilter::text_label(int bin) const return fmt::format("Particle: {}", particle_type_to_str(p)); } +extern "C" int openmc_particle_filter_get_bins(int32_t idx, int bins[]) +{ + if (int err = verify_filter(idx)) + return err; + + const auto& f = model::tally_filters[idx]; + auto pf = dynamic_cast(f.get()); + if (pf) { + const auto& particles = pf->particles(); + for (int i = 0; i < particles.size(); i++) { + bins[i] = static_cast(particles[i]); + } + } else { + set_errmsg("The filter at the specified index is not a ParticleFilter"); + return OPENMC_E_INVALID_ARGUMENT; + } + return 0; +} + } // namespace openmc diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 85d999fd4a6..9a7e52b9508 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -358,6 +358,34 @@ void Tally::set_id(int32_t id) model::tally_map[id] = index_; } +std::vector Tally::filter_types() const +{ + std::vector filter_types; + for (auto idx : this->filters()) + filter_types.push_back(model::tally_filters[idx]->type()); + return filter_types; +} + +std::unordered_map Tally::filter_indices() const +{ + std::unordered_map filter_indices; + for (int i = 0; i < this->filters().size(); i++) { + const auto& f = model::tally_filters[this->filters(i)]; + + filter_indices[f->type()] = i; + } + return filter_indices; +} + +bool Tally::has_filter(FilterType filter_type) const +{ + for (auto idx : this->filters()) { + if (model::tally_filters[idx]->type() == filter_type) + return true; + } + return false; +} + void Tally::set_filters(gsl::span filters) { // Clear old data. @@ -692,6 +720,31 @@ void Tally::accumulate() } } +int Tally::score_index(const std::string& score) const +{ + for (int i = 0; i < scores_.size(); i++) { + if (this->score_name(i) == score) + return i; + } + return -1; +} + +xt::xarray Tally::get_reshaped_data() const +{ + std::vector shape; + for (auto f : filters()) { + shape.push_back(model::tally_filters[f]->n_bins()); + } + + // add number of scores and nuclides to tally + shape.push_back(results_.shape()[1]); + shape.push_back(results_.shape()[2]); + + xt::xarray reshaped_results = results_; + reshaped_results.reshape(shape); + return reshaped_results; +} + std::string Tally::score_name(int score_idx) const { if (score_idx < 0 || score_idx >= scores_.size()) { @@ -700,6 +753,14 @@ std::string Tally::score_name(int score_idx) const return reaction_name(scores_[score_idx]); } +std::vector Tally::scores() const +{ + std::vector score_names; + for (int score : scores_) + score_names.push_back(reaction_name(score)); + return score_names; +} + std::string Tally::nuclide_name(int nuclide_idx) const { if (nuclide_idx < 0 || nuclide_idx >= nuclides_.size()) { diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index e8e8f4b0520..104c3881540 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -1,12 +1,33 @@ #include "openmc/weight_windows.h" +#include +#include +#include +#include + +#include "xtensor/xindex_view.hpp" +#include "xtensor/xio.hpp" +#include "xtensor/xmasked_view.hpp" +#include "xtensor/xnoalias.hpp" +#include "xtensor/xstrided_view.hpp" +#include "xtensor/xview.hpp" + #include "openmc/error.h" #include "openmc/file_utils.h" #include "openmc/hdf5_interface.h" +#include "openmc/mesh.h" +#include "openmc/message_passing.h" +#include "openmc/nuclide.h" +#include "openmc/output.h" #include "openmc/particle.h" #include "openmc/particle_data.h" #include "openmc/physics_common.h" #include "openmc/search.h" +#include "openmc/settings.h" +#include "openmc/tallies/filter_energy.h" +#include "openmc/tallies/filter_mesh.h" +#include "openmc/tallies/filter_particle.h" +#include "openmc/tallies/tally.h" #include "openmc/xml_interface.h" #include @@ -22,6 +43,7 @@ namespace variance_reduction { std::unordered_map ww_map; openmc::vector> weight_windows; +openmc::vector> weight_windows_generators; } // namespace variance_reduction @@ -108,6 +130,13 @@ void free_memory_weight_windows() // WeightWindowSettings implementation //============================================================================== +WeightWindows::WeightWindows(int32_t id) +{ + index_ = variance_reduction::weight_windows.size(); + set_id(id); + set_defaults(); +} + WeightWindows::WeightWindows(pugi::xml_node node) { // Make sure required elements are present @@ -132,11 +161,8 @@ WeightWindows::WeightWindows(pugi::xml_node node) mesh_idx_ = model::mesh_map.at(mesh_id); // energy bounds - energy_bounds_ = get_node_array(node, "energy_bounds"); - - // read the lower/upper weight bounds - lower_ww_ = get_node_array(node, "lower_ww_bounds"); - upper_ww_ = get_node_array(node, "upper_ww_bounds"); + if (check_for_node(node, "energy_bounds")) + energy_bounds_ = get_node_array(node, "energy_bounds"); // get the survival value - optional if (check_for_node(node, "survival_ratio")) { @@ -170,22 +196,81 @@ WeightWindows::WeightWindows(pugi::xml_node node) fatal_error("weight_cutoff must be less than 1"); } - // make sure that the upper and lower bounds have the same size - if (upper_ww_.size() != lower_ww_.size()) { - fatal_error("The upper and lower weight window lengths do not match."); + // read the lower/upper weight bounds + this->set_bounds(get_node_array(node, "lower_ww_bounds"), + get_node_array(node, "upper_ww_bounds")); + + set_defaults(); +} + +WeightWindows::~WeightWindows() +{ + variance_reduction::ww_map.erase(id()); +} + +WeightWindows* WeightWindows::create(int32_t id) +{ + variance_reduction::weight_windows.push_back(make_unique()); + auto wws = variance_reduction::weight_windows.back().get(); + variance_reduction::ww_map[wws->id()] = + variance_reduction::weight_windows.size() - 1; + return wws; +} + +WeightWindows* WeightWindows::from_hdf5( + hid_t wws_group, const std::string& group_name) +{ + // collect ID from the name of this group + hid_t ww_group = open_group(wws_group, group_name); + + auto wws = WeightWindows::create(); + + std::string particle_type; + read_dataset(ww_group, "particle_type", particle_type); + wws->particle_type_ = openmc::str_to_particle_type(particle_type); + + read_dataset(ww_group, "energy_bounds", wws->energy_bounds_); + + int32_t mesh_id; + read_dataset(ww_group, "mesh", mesh_id); + + if (model::mesh_map.count(mesh_id) == 0) { + fatal_error( + fmt::format("Mesh {} used in weight windows does not exist.", mesh_id)); } + wws->set_mesh(model::mesh_map[mesh_id]); - // num spatial*energy bins must match num weight bins - int num_spatial_bins = this->mesh().n_bins(); - int num_energy_bins = energy_bounds_.size() - 1; - int num_weight_bins = lower_ww_.size(); - if (num_weight_bins != num_spatial_bins * num_energy_bins) { - auto err_msg = - fmt::format("In weight window domain {} the number of " - "energy/spatial bins ({}) does not match the number " - "of weight bins provided ({})", - id_, num_energy_bins * num_spatial_bins, num_weight_bins); - fatal_error(err_msg); + wws->lower_ww_ = xt::empty(wws->bounds_size()); + wws->upper_ww_ = xt::empty(wws->bounds_size()); + + read_dataset(ww_group, "lower_ww_bounds", wws->lower_ww_); + read_dataset(ww_group, "upper_ww_bounds", wws->upper_ww_); + read_dataset(ww_group, "survival_ratio", wws->survival_ratio_); + read_dataset(ww_group, "max_lower_bound_ratio", wws->max_lb_ratio_); + read_dataset(ww_group, "max_split", wws->max_split_); + read_dataset(ww_group, "weight_cutoff", wws->weight_cutoff_); + + close_group(ww_group); + + return wws; +} + +void WeightWindows::set_defaults() +{ + // ensure default values are set + if (energy_bounds_.size() == 0) { + int p_type = static_cast(particle_type_); + energy_bounds_.push_back(data::energy_min[p_type]); + energy_bounds_.push_back(data::energy_max[p_type]); + } + + // some constructors won't allocate space for the bounds + // do that here so the object is valid + if (lower_ww_.size() == 0 || upper_ww_.size() == 0) { + lower_ww_ = xt::empty(bounds_size()); + lower_ww_.fill(-1); + upper_ww_ = xt::empty(bounds_size()); + upper_ww_.fill(-1); } } @@ -216,8 +301,40 @@ void WeightWindows::set_id(int32_t id) // Update ID and entry in the mesh map id_ = id; - variance_reduction::ww_map[id] = - variance_reduction::weight_windows.size() - 1; + variance_reduction::ww_map[id] = index_; +} + +void WeightWindows::set_energy_bounds(gsl::span bounds) +{ + energy_bounds_.clear(); + energy_bounds_.insert(energy_bounds_.begin(), bounds.begin(), bounds.end()); +} + +void WeightWindows::set_particle_type(ParticleType p_type) +{ + if (p_type != ParticleType::neutron && p_type != ParticleType::photon) + fatal_error( + fmt::format("Particle type '{}' cannot be applied to weight windows.", + particle_type_to_str(p_type))); + particle_type_ = p_type; +} + +void WeightWindows::set_mesh(int32_t mesh_idx) +{ + if (mesh_idx < 0 || mesh_idx >= model::meshes.size()) + fatal_error(fmt::format("Could not find a mesh for index {}", mesh_idx)); + + mesh_idx_ = mesh_idx; +} + +void WeightWindows::set_mesh(const std::unique_ptr& mesh) +{ + set_mesh(mesh.get()); +} + +void WeightWindows::set_mesh(const Mesh* mesh) +{ + set_mesh(model::mesh_map[mesh->id_]); } WeightWindow WeightWindows::get_weight_window(const Particle& p) const @@ -229,10 +346,10 @@ WeightWindow WeightWindows::get_weight_window(const Particle& p) const // Get mesh index for particle's position const auto& mesh = this->mesh(); - int ww_index = mesh.get_bin(p.r()); + int mesh_bin = mesh->get_bin(p.r()); // particle is outside the weight window mesh - if (ww_index < 0) + if (mesh_bin < 0) return {}; // particle energy @@ -246,13 +363,11 @@ WeightWindow WeightWindows::get_weight_window(const Particle& p) const int energy_bin = lower_bound_index(energy_bounds_.begin(), energy_bounds_.end(), E); - // indices now points to the correct weight for the given energy - ww_index += energy_bin * mesh.n_bins(); - + // mesh_bin += energy_bin * mesh->n_bins(); // Create individual weight window WeightWindow ww; - ww.lower_weight = lower_ww_[ww_index]; - ww.upper_weight = upper_ww_[ww_index]; + ww.lower_weight = lower_ww_(energy_bin, mesh_bin); + ww.upper_weight = upper_ww_(energy_bin, mesh_bin); ww.survival_weight = ww.lower_weight * survival_ratio_; ww.max_lb_ratio = max_lb_ratio_; ww.max_split = max_split_; @@ -260,22 +375,751 @@ WeightWindow WeightWindows::get_weight_window(const Particle& p) const return ww; } -void WeightWindows::to_hdf5(hid_t group) const +std::array WeightWindows::bounds_size() const +{ + int num_spatial_bins = this->mesh()->n_bins(); + int num_energy_bins = + energy_bounds_.size() > 0 ? energy_bounds_.size() - 1 : 1; + return {num_energy_bins, num_spatial_bins}; +} + +template +void WeightWindows::check_bounds(const T& lower, const T& upper) const { - hid_t ww_group = create_group(group, fmt::format("weight_windows {}", id_)); - - write_dataset( - ww_group, "particle_type", openmc::particle_type_to_str(particle_type_)); - write_dataset(ww_group, "energy_bounds", energy_bounds_); - write_dataset(ww_group, "lower_ww_bounds", lower_ww_); - write_dataset(ww_group, "upper_ww_bounds", upper_ww_); - write_dataset(ww_group, "survival_ratio", survival_ratio_); - write_dataset(ww_group, "max_lower_bound_ratio", max_lb_ratio_); - write_dataset(ww_group, "max_split", max_split_); - write_dataset(ww_group, "weight_cutoff", weight_cutoff_); - write_dataset(ww_group, "mesh", this->mesh().id_); + // make sure that the upper and lower bounds have the same size + if (lower.size() != upper.size()) { + auto msg = fmt::format("The upper and lower weight window lengths do not " + "match.\n Lower size: {}\n Upper size: {}", + lower.size(), upper.size()); + fatal_error(msg); + } + this->check_bounds(lower); +} - close_group(ww_group); +template +void WeightWindows::check_bounds(const T& bounds) const +{ + // check that the number of weight window entries is correct + auto dims = this->bounds_size(); + if (bounds.size() != dims[0] * dims[1]) { + auto err_msg = + fmt::format("In weight window domain {} the number of spatial " + "energy/spatial bins ({}) does not match the number " + "of weight bins ({})", + id_, dims, bounds.size()); + fatal_error(err_msg); + } +} + +void WeightWindows::set_bounds(const xt::xtensor& lower_bounds, + const xt::xtensor& upper_bounds) +{ + + this->check_bounds(lower_bounds, upper_bounds); + + // set new weight window values + lower_ww_ = lower_bounds; + upper_ww_ = upper_bounds; +} + +void WeightWindows::set_bounds( + const xt::xtensor& lower_bounds, double ratio) +{ + this->check_bounds(lower_bounds); + + // set new weight window values + lower_ww_ = lower_bounds; + upper_ww_ = lower_bounds; + upper_ww_ *= ratio; +} + +void WeightWindows::set_bounds( + gsl::span lower_bounds, gsl::span upper_bounds) +{ + check_bounds(lower_bounds, upper_bounds); + auto shape = this->bounds_size(); + lower_ww_ = xt::empty(shape); + upper_ww_ = xt::empty(shape); + + // set new weight window values + xt::view(lower_ww_, xt::all()) = + xt::adapt(lower_bounds.data(), lower_ww_.shape()); + xt::view(upper_ww_, xt::all()) = + xt::adapt(upper_bounds.data(), upper_ww_.shape()); +} + +void WeightWindows::set_bounds( + gsl::span lower_bounds, double ratio) +{ + this->check_bounds(lower_bounds); + + auto shape = this->bounds_size(); + lower_ww_ = xt::empty(shape); + upper_ww_ = xt::empty(shape); + + // set new weight window values + xt::view(lower_ww_, xt::all()) = + xt::adapt(lower_bounds.data(), lower_ww_.shape()); + xt::view(upper_ww_, xt::all()) = + xt::adapt(lower_bounds.data(), upper_ww_.shape()); + upper_ww_ *= ratio; +} + +void WeightWindows::update_magic( + const Tally* tally, const std::string& value, double threshold, double ratio) +{ + /////////////////////////// + // Setup and checks + /////////////////////////// + this->check_tally_update_compatibility(tally); + + lower_ww_.fill(-1); + upper_ww_.fill(-1); + + // determine which value to use + const std::set allowed_values = {"mean", "rel_err"}; + if (allowed_values.count(value) == 0) { + fatal_error(fmt::format("Invalid value '{}' specified for weight window " + "generation. Must be one of: 'mean' or 'rel_err'", + value)); + } + + // determine the index of the specified score + int score_index = tally->score_index("flux"); + if (score_index == C_NONE) { + fatal_error( + fmt::format("A 'flux' score required for weight window generation " + "is not present on tally {}.", + tally->id())); + } + + /////////////////////////// + // Extract tally data + // + // At the end of this section, the mean and rel_err array + // is a 2D view of tally data (n_e_groups, n_mesh_bins) + // + /////////////////////////// + + // build a shape for a view of the tally results, this will always be + // dimension 5 (3 filter dimensions, 1 score dimension, 1 results dimension) + std::array shape = { + 1, 1, 1, tally->n_scores(), static_cast(TallyResult::SIZE)}; + + // set the shape for the filters applied on the tally + for (int i = 0; i < tally->filters().size(); i++) { + const auto& filter = model::tally_filters[tally->filters(i)]; + shape[i] = filter->n_bins(); + } + + // build the transpose information to re-order data according to filter type + std::array transpose = {0, 1, 2, 3, 4}; + + // track our filter types and where we've added new ones + std::vector filter_types = tally->filter_types(); + + // assign other filter types to dummy positions if needed + if (!tally->has_filter(FilterType::PARTICLE)) + filter_types.push_back(FilterType::PARTICLE); + + if (!tally->has_filter(FilterType::ENERGY)) + filter_types.push_back(FilterType::ENERGY); + + // particle axis mapping + transpose[0] = + std::find(filter_types.begin(), filter_types.end(), FilterType::PARTICLE) - + filter_types.begin(); + + // energy axis mapping + transpose[1] = + std::find(filter_types.begin(), filter_types.end(), FilterType::ENERGY) - + filter_types.begin(); + + // mesh axis mapping + transpose[2] = + std::find(filter_types.begin(), filter_types.end(), FilterType::MESH) - + filter_types.begin(); + + // get a fully reshaped view of the tally according to tally ordering of + // filters + auto tally_values = xt::reshape_view(tally->results(), shape); + + // get a that is (particle, energy, mesh, scores, values) + auto transposed_view = xt::transpose(tally_values, transpose); + + // determine the dimension and index of the particle data + int particle_idx = 0; + if (tally->has_filter(FilterType::PARTICLE)) { + // get the particle filter + auto pf = tally->get_filter(); + const auto& particles = pf->particles(); + + // find the index of the particle that matches these weight windows + auto p_it = + std::find(particles.begin(), particles.end(), this->particle_type_); + // if the particle filter doesn't have particle data for the particle + // used on this weight windows instance, report an error + if (p_it == particles.end()) { + auto msg = fmt::format("Particle type '{}' not present on Filter {} for " + "Tally {} used to update WeightWindows {}", + particle_type_to_str(this->particle_type_), pf->id(), tally->id(), + this->id()); + fatal_error(msg); + } + + // use the index of the particle in the filter to down-select data later + particle_idx = p_it - particles.begin(); + } + + // down-select data based on particle and score + auto sum = xt::view(transposed_view, particle_idx, xt::all(), xt::all(), + score_index, static_cast(TallyResult::SUM)); + auto sum_sq = xt::view(transposed_view, particle_idx, xt::all(), xt::all(), + score_index, static_cast(TallyResult::SUM_SQ)); + int n = tally->n_realizations_; + + ////////////////////////////////////////////// + // + // Assign new weight windows + // + // Use references to the existing weight window data + // to store and update the values + // + ////////////////////////////////////////////// + + // up to this point the data arrays are views into the tally results (no + // computation has been performed) now we'll switch references to the tally's + // bounds to avoid allocating additional memory + auto& new_bounds = this->lower_ww_; + auto& rel_err = this->upper_ww_; + + // noalias avoids memory allocation here + xt::noalias(new_bounds) = sum / n; + + xt::noalias(rel_err) = + xt::sqrt(((sum_sq / n) - xt::square(new_bounds)) / (n - 1)) / new_bounds; + xt::filter(rel_err, sum <= 0.0).fill(INFTY); + + if (value == "rel_err") + xt::noalias(new_bounds) = 1 / rel_err; + + // get mesh volumes + auto mesh_vols = this->mesh()->volumes(); + + int e_bins = new_bounds.shape()[0]; + for (int e = 0; e < e_bins; e++) { + // select all + auto group_view = xt::view(new_bounds, e); + + double group_max = *std::max_element(group_view.begin(), group_view.end()); + // normalize values in this energy group by the maximum value for this + // group + if (group_max > 0.0) + group_view /= group_max; + + // divide by volume of mesh elements + for (int i = 0; i < group_view.size(); i++) { + group_view[i] /= mesh_vols[i]; + } + } + + // make sure that values where the mean is zero are set s.t. the weight window + // value will be ignored + xt::filter(new_bounds, sum <= 0.0).fill(-1.0); + + // make sure the weight windows are ignored for any locations where the + // relative error is higher than the specified relative error threshold + xt::filter(new_bounds, rel_err > threshold).fill(-1.0); + + // update the bounds of this weight window class + // noalias avoids additional memory allocation + xt::noalias(upper_ww_) = ratio * lower_ww_; } +void WeightWindows::check_tally_update_compatibility(const Tally* tally) +{ + // define the set of allowed filters for the tally + const std::set allowed_filters = { + FilterType::MESH, FilterType::ENERGY, FilterType::PARTICLE}; + + // retrieve a mapping of filter type to filter index for the tally + auto filter_indices = tally->filter_indices(); + + // a mesh filter is required for a tally used to update weight windows + if (!filter_indices.count(FilterType::MESH)) { + fatal_error( + "A mesh filter is required for a tally to update weight window bounds"); + } + + // ensure the mesh filter is using the same mesh as this weight window object + auto mesh_filter = tally->get_filter(); + + // make sure that all of the filters present on the tally are allowed + for (auto filter_pair : filter_indices) { + if (allowed_filters.find(filter_pair.first) == allowed_filters.end()) { + fatal_error(fmt::format("Invalid filter type '{}' found on tally " + "used for weight window generation.", + model::tally_filters[filter_pair.second]->type_str())); + } + } + + if (mesh_filter->mesh() != mesh_idx_) { + int32_t mesh_filter_id = model::meshes[mesh_filter->mesh()]->id(); + int32_t ww_mesh_id = model::meshes[this->mesh_idx_]->id(); + fatal_error(fmt::format("Mesh filter {} uses a different mesh ({}) than " + "weight window {} mesh ({})", + mesh_filter->id(), mesh_filter_id, id_, ww_mesh_id)); + } + + // if an energy filter exists, make sure the energy grid matches that of this + // weight window object + if (auto energy_filter = tally->get_filter()) { + std::vector filter_bins = energy_filter->bins(); + std::set filter_e_bounds( + energy_filter->bins().begin(), energy_filter->bins().end()); + if (filter_e_bounds.size() != energy_bounds().size()) { + fatal_error( + fmt::format("Energy filter {} does not have the same number of energy " + "bounds ({}) as weight window object {} ({})", + energy_filter->id(), filter_e_bounds.size(), id_, + energy_bounds().size())); + } + + for (auto e : energy_bounds()) { + if (filter_e_bounds.count(e) == 0) { + fatal_error(fmt::format( + "Energy bounds of filter {} and weight windows {} do not match", + energy_filter->id(), id_)); + } + } + } +} + + void WeightWindows::to_hdf5(hid_t group) const + { + hid_t ww_group = + create_group(group, fmt::format("weight_windows_{}", id())); + + write_dataset(ww_group, "mesh", this->mesh()->id()); + write_dataset( + ww_group, "particle_type", openmc::particle_type_to_str(particle_type_)); + write_dataset(ww_group, "energy_bounds", energy_bounds_); + write_dataset(ww_group, "lower_ww_bounds", lower_ww_); + write_dataset(ww_group, "upper_ww_bounds", upper_ww_); + write_dataset(ww_group, "survival_ratio", survival_ratio_); + write_dataset(ww_group, "max_lower_bound_ratio", max_lb_ratio_); + write_dataset(ww_group, "max_split", max_split_); + write_dataset(ww_group, "weight_cutoff", weight_cutoff_); + + close_group(ww_group); + } + + WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) + { + // read information from the XML node + int32_t mesh_id = std::stoi(get_node_value(node, "mesh")); + int32_t mesh_idx = model::mesh_map[mesh_id]; + max_realizations_ = std::stoi(get_node_value(node, "max_realizations")); + + int active_batches = settings::n_batches - settings::n_inactive; + if (max_realizations_ > active_batches) { + auto msg = fmt::format( + "The maximum number of specified tally realizations ({}) is " + "greater than the number of active batches ({}).", + max_realizations_, active_batches); + warning(msg); + } + auto tmp_str = get_node_value(node, "particle_type", true, true); + auto particle_type = str_to_particle_type(tmp_str); + + update_interval_ = std::stoi(get_node_value(node, "update_interval")); + on_the_fly_ = get_node_value_bool(node, "on_the_fly"); + + std::vector e_bounds; + if (check_for_node(node, "energy_bounds")) { + e_bounds = get_node_array(node, "energy_bounds"); + } else { + int p_type = static_cast(particle_type); + e_bounds.push_back(data::energy_min[p_type]); + e_bounds.push_back(data::energy_max[p_type]); + } + + // create a tally based on the WWG information + Tally* ww_tally = Tally::create(); + tally_idx_ = model::tally_map[ww_tally->id()]; + ww_tally->set_scores({"flux"}); + + // see if there's already a mesh filter using this mesh + bool found_mesh_filter = false; + for (const auto& f : model::tally_filters) { + if (f->type() == FilterType::MESH) { + const auto* mesh_filter = dynamic_cast(f.get()); + if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated()) { + ww_tally->add_filter(f.get()); + found_mesh_filter = true; + break; + } + } + } + + if (!found_mesh_filter) { + auto mesh_filter = Filter::create("mesh"); + openmc_mesh_filter_set_mesh( + mesh_filter->index(), model::mesh_map[mesh_id]); + ww_tally->add_filter(mesh_filter); + } + + if (e_bounds.size() > 0) { + auto energy_filter = Filter::create("energy"); + openmc_energy_filter_set_bins( + energy_filter->index(), e_bounds.size(), e_bounds.data()); + ww_tally->add_filter(energy_filter); + } + + // add a particle filter + auto particle_filter = Filter::create("particle"); + auto pf = dynamic_cast(particle_filter); + pf->set_particles({&particle_type, 1}); + ww_tally->add_filter(particle_filter); + + // set method and parameters for updates + method_ = get_node_value(node, "method"); + if (method_ == "magic") { + // parse non-default update parameters if specified + if (check_for_node(node, "update_parameters")) { + pugi::xml_node params_node = node.child("update_parameters"); + if (check_for_node(params_node, "value")) + tally_value_ = get_node_value(params_node, "value"); + if (check_for_node(params_node, "threshold")) + threshold_ = std::stod(get_node_value(params_node, "threshold")); + if (check_for_node(params_node, "ratio")) { + ratio_ = std::stod(get_node_value(params_node, "ratio")); + } + } + // check update parameter values + if (tally_value_ != "mean" && tally_value_ != "rel_err") { + fatal_error(fmt::format("Unsupported tally value '{}' specified for " + "weight window generation.", + tally_value_)); + } + if (threshold_ <= 0.0) + fatal_error( + fmt::format("Invalid relative error threshold '{}' (<= 0.0) " + "specified for weight window generation", + ratio_)); + if (ratio_ <= 1.0) + fatal_error(fmt::format("Invalid weight window ratio '{}' (<= 1.0) " + "specified for weight window generation")); + } else { + fatal_error(fmt::format( + "Unknown weight window update method '{}' specified", method_)); + } + + // create a matching weight windows object + auto wws = WeightWindows::create(); + ww_idx_ = wws->index(); + if (e_bounds.size() > 0) + wws->set_energy_bounds(e_bounds); + wws->set_mesh(model::mesh_map[mesh_id]); + wws->set_particle_type(particle_type); + wws->set_defaults(); + } + + void WeightWindowsGenerator::update() const + { + const auto& wws = variance_reduction::weight_windows[ww_idx_]; + + Tally* tally = model::tallies[tally_idx_].get(); + + // if we're beyond the number of max realizations or not at the corrrect + // update interval, skip the update + if (max_realizations_ < tally->n_realizations_ || + tally->n_realizations_ % update_interval_ != 0) + return; + + wws->update_magic(tally, tally_value_, threshold_, ratio_); + + // if we're not doing on the fly generation, reset the tally results once + // we're done with the update + if (!on_the_fly_) + tally->reset(); + + // TODO: deactivate or remove tally once weight window generation is + // complete + } + + //============================================================================== + // C API + //============================================================================== + + int verify_ww_index(int32_t index) + { + if (index < 0 || index >= variance_reduction::weight_windows.size()) { + set_errmsg( + fmt::format("Index '{}' for weight windows is invalid", index)); + return OPENMC_E_OUT_OF_BOUNDS; + } + return 0; + } + + extern "C" int openmc_get_weight_windows_index(int32_t id, int32_t * idx) + { + auto it = variance_reduction::ww_map.find(id); + if (it == variance_reduction::ww_map.end()) { + set_errmsg(fmt::format("No weight windows exist with ID={}", id)); + return OPENMC_E_INVALID_ID; + } + + *idx = it->second; + return 0; + } + + extern "C" int openmc_weight_windows_get_id(int32_t index, int32_t * id) + { + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + *id = wws->id(); + return 0; + } + + extern "C" int openmc_weight_windows_set_id(int32_t index, int32_t id) + { + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + wws->set_id(id); + return 0; + } + + extern "C" int openmc_weight_windows_update_magic(int32_t ww_idx, + int32_t tally_idx, const char* value, double threshold, double ratio) + { + if (int err = verify_ww_index(ww_idx)) + return err; + + if (tally_idx < 0 || tally_idx >= model::tallies.size()) { + set_errmsg(fmt::format("Index '{}' for tally is invalid", tally_idx)); + return OPENMC_E_OUT_OF_BOUNDS; + } + + // get the requested tally + const Tally* tally = model::tallies.at(tally_idx).get(); + + // get the WeightWindows object + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + + wws->update_magic(tally, value, threshold, ratio); + + return 0; + } + + extern "C" int openmc_weight_windows_set_mesh( + int32_t ww_idx, int32_t mesh_idx) + { + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + wws->set_mesh(mesh_idx); + return 0; + } + + extern "C" int openmc_weight_windows_get_mesh( + int32_t ww_idx, int32_t * mesh_idx) + { + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + *mesh_idx = model::mesh_map.at(wws->mesh()->id()); + return 0; + } + + extern "C" int openmc_weight_windows_set_energy_bounds( + int32_t ww_idx, double* e_bounds, size_t e_bounds_size) + { + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + wws->set_energy_bounds({e_bounds, e_bounds_size}); + return 0; + } + + extern "C" int openmc_weight_windows_get_energy_bounds( + int32_t ww_idx, const double** e_bounds, size_t* e_bounds_size) + { + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows[ww_idx].get(); + *e_bounds = wws->energy_bounds().data(); + *e_bounds_size = wws->energy_bounds().size(); + return 0; + } + + extern "C" int openmc_weight_windows_set_particle(int32_t index, int particle) + { + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + wws->set_particle_type(static_cast(particle)); + return 0; + } + + extern "C" int openmc_weight_windows_get_particle( + int32_t index, int* particle) + { + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows.at(index); + *particle = static_cast(wws->particle_type()); + return 0; + } + + extern "C" int openmc_weight_windows_get_bounds(int32_t index, + const double** lower_bounds, const double** upper_bounds, size_t* size) + { + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows[index]; + *size = wws->lower_ww_bounds().size(); + *lower_bounds = wws->lower_ww_bounds().data(); + *upper_bounds = wws->upper_ww_bounds().data(); + return 0; + } + + extern "C" int openmc_weight_windows_set_bounds(int32_t index, + const double* lower_bounds, const double* upper_bounds, size_t size) + { + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows[index]; + wws->set_bounds({lower_bounds, size}, {upper_bounds, size}); + return 0; + } + + extern "C" int openmc_extend_weight_windows( + int32_t n, int32_t * index_start, int32_t * index_end) + { + if (index_start) + *index_start = variance_reduction::weight_windows.size(); + if (index_end) + *index_end = variance_reduction::weight_windows.size() + n - 1; + for (int i = 0; i < n; ++i) + variance_reduction::weight_windows.push_back( + make_unique()); + return 0; + } + + extern "C" size_t openmc_weight_windows_size() + { + return variance_reduction::weight_windows.size(); + } + + extern "C" int openmc_weight_windows_export(const char* filename) + { + + if (!mpi::master) + return 0; + + std::string name = filename ? filename : "weight_windows.h5"; + + write_message(fmt::format("Exporting weight windows to {}...", name), 5); + + hid_t ww_file = file_open(name, 'w'); + + // Write file type + write_attribute(ww_file, "filetype", "weight_windows"); + + // Write revisiion number for state point file + write_attribute(ww_file, "version", VERSION_WEIGHT_WINDOWS); + + hid_t weight_windows_group = create_group(ww_file, "weight_windows"); + + hid_t mesh_group = create_group(ww_file, "meshes"); + + std::vector mesh_ids; + std::vector ww_ids; + for (const auto& ww : variance_reduction::weight_windows) { + + ww->to_hdf5(weight_windows_group); + ww_ids.push_back(ww->id()); + + // if the mesh has already been written, move on + int32_t mesh_id = ww->mesh()->id(); + if (std::find(mesh_ids.begin(), mesh_ids.end(), mesh_id) != + mesh_ids.end()) + continue; + + mesh_ids.push_back(mesh_id); + ww->mesh()->to_hdf5(mesh_group); + } + + write_attribute(mesh_group, "n_meshes", mesh_ids.size()); + write_attribute(mesh_group, "ids", mesh_ids); + close_group(mesh_group); + + write_attribute(weight_windows_group, "n_weight_windows", ww_ids.size()); + write_attribute(weight_windows_group, "ids", ww_ids); + close_group(weight_windows_group); + + file_close(ww_file); + + return 0; + } + + extern "C" int openmc_weight_windows_import(const char* filename) + { + std::string name = filename ? filename : "weight_windows.h5"; + + if (mpi::master) + write_message( + fmt::format("Importing weight windows from {}...", name), 5); + + if (!file_exists(name)) { + set_errmsg(fmt::format("File '{}' does not exist", name)); + } + + hid_t ww_file = file_open(name, 'r'); + + // Check that filetype is correct + std::string filetype; + read_attribute(ww_file, "filetype", filetype); + if (filetype != "weight_windows") { + file_close(ww_file); + set_errmsg(fmt::format("File '{}' is not a weight windows file.", name)); + return OPENMC_E_INVALID_ARGUMENT; + } + + // Check that the file version is compatible + std::array file_version; + read_attribute(ww_file, "version", file_version); + if (file_version[0] != VERSION_WEIGHT_WINDOWS[0]) { + std::string err_msg = + fmt::format("File '{}' has version {} which is incompatible with the " + "expected version ({}).", + name, file_version, VERSION_WEIGHT_WINDOWS); + set_errmsg(err_msg); + return OPENMC_E_INVALID_ARGUMENT; + } + + hid_t weight_windows_group = open_group(ww_file, "weight_windows"); + + std::vector names = group_names(weight_windows_group); + + for (const auto& name : names) { + WeightWindows::from_hdf5(weight_windows_group, name); + } + + close_group(weight_windows_group); + + file_close(ww_file); + + return 0; + } + } // namespace openmc diff --git a/tests/regression_tests/track_output/results_true.dat b/tests/regression_tests/track_output/results_true.dat index 37f4a0f9810..746f1448fd1 100644 --- a/tests/regression_tests/track_output/results_true.dat +++ b/tests/regression_tests/track_output/results_true.dat @@ -1,4 +1,4 @@ -ParticleType.NEUTRON [((-9.663085e-01, -6.616522e-01, -9.863690e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 0.000000e+00, 1.000000e+00, 23, 2403, 1) +neutron [((-9.663085e-01, -6.616522e-01, -9.863690e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 0.000000e+00, 1.000000e+00, 23, 2403, 1) ((-1.281491e+00, -4.879529e-01, -7.708709e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 1.323629e-10, 1.000000e+00, 22, 2403, 3) ((-1.368452e+00, -4.400285e-01, -7.114141e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 1.688824e-10, 1.000000e+00, 21, 2403, 2) ((-2.150539e+00, -9.015151e-03, -1.766823e-01), (-7.513921e-01, 4.140970e-01, 5.137447e-01), 5.293873e+06, 4.973246e-10, 1.000000e+00, 22, 2403, 3) @@ -117,7 +117,7 @@ ParticleType.NEUTRON [((-9.663085e-01, -6.616522e-01, -9.863690e-01), (-7.513921 ((-1.682182e+01, 1.413107e+00, -2.343954e+01), (6.002458e-01, 4.967948e-01, 6.268172e-01), 8.602342e-03, 2.164421e-05, 1.000000e+00, 21, 2129, 2) ((-1.636364e+01, 1.792326e+00, -2.296107e+01), (9.641593e-01, -1.162836e-01, 2.384846e-01), 7.837617e-03, 2.759442e-05, 1.000000e+00, 21, 2129, 2) ((-1.598564e+01, 1.746738e+00, -2.286758e+01), (9.641593e-01, -1.162836e-01, 2.384846e-01), 7.837617e-03, 3.079609e-05, 0.000000e+00, 21, 2129, 2)] -ParticleType.NEUTRON [((-9.469716e-01, -2.580266e-01, 1.414357e-01), (1.438873e-01, 2.365819e-01, 9.608983e-01), 9.724461e+05, 0.000000e+00, 1.000000e+00, 23, 2403, 1) +neutron [((-9.469716e-01, -2.580266e-01, 1.414357e-01), (1.438873e-01, 2.365819e-01, 9.608983e-01), 9.724461e+05, 0.000000e+00, 1.000000e+00, 23, 2403, 1) ((-9.064818e-01, -1.914524e-01, 4.118326e-01), (9.231638e-01, 3.100833e-01, 2.271937e-01), 1.746594e+05, 2.064696e-10, 1.000000e+00, 23, 2403, 1) ((-8.178800e-01, -1.616918e-01, 4.336377e-01), (9.231638e-01, 3.100833e-01, 2.271937e-01), 1.746594e+05, 3.725262e-10, 1.000000e+00, 11, 1756, 1) ((-3.834875e-01, -1.578285e-02, 5.405432e-01), (-5.547498e-01, -6.358598e-02, 8.295839e-01), 1.474011e+05, 1.186660e-09, 1.000000e+00, 11, 1756, 1) @@ -143,7 +143,7 @@ ParticleType.NEUTRON [((-9.469716e-01, -2.580266e-01, 1.414357e-01), (1.438873e- ((-3.920090e+00, -9.211794e-01, 2.908406e+00), (9.094673e-01, -3.659267e-01, -1.974002e-01), 9.547085e+00, 1.260840e-07, 1.000000e+00, 23, 2387, 1) ((-3.729948e+00, -9.976834e-01, 2.867135e+00), (-2.916959e-01, -6.494657e-01, -7.022164e-01), 8.590591e+00, 1.750036e-07, 1.000000e+00, 23, 2387, 1) ((-3.744933e+00, -1.031047e+00, 2.831062e+00), (-2.916959e-01, -6.494657e-01, -7.022164e-01), 8.590591e+00, 1.876753e-07, 0.000000e+00, 23, 2387, 1)] -ParticleType.NEUTRON [((6.474155e+00, -5.192870e+00, 5.413003e+00), (-9.112559e-01, 3.950037e-01, 1.165536e-01), 2.052226e+06, 4.450859e-05, 1.000000e+00, 21, 2367, 2) +neutron [((6.474155e+00, -5.192870e+00, 5.413003e+00), (-9.112559e-01, 3.950037e-01, 1.165536e-01), 2.052226e+06, 4.450859e-05, 1.000000e+00, 21, 2367, 2) ((6.037250e+00, -5.003484e+00, 5.468885e+00), (-9.112559e-01, 3.950037e-01, 1.165536e-01), 2.052226e+06, 4.450883e-05, 1.000000e+00, 22, 2367, 3) ((5.942573e+00, -4.962444e+00, 5.480995e+00), (-9.112559e-01, 3.950037e-01, 1.165536e-01), 2.052226e+06, 4.450888e-05, 1.000000e+00, 23, 2367, 1) ((5.861800e+00, -4.927431e+00, 5.491326e+00), (-9.518772e-01, -3.064714e-01, -2.259335e-03), 1.141417e+06, 4.450892e-05, 1.000000e+00, 23, 2367, 1) diff --git a/tests/regression_tests/weightwindows/generators/__init__.py b/tests/regression_tests/weightwindows/generators/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/weightwindows/generators/test.py b/tests/regression_tests/weightwindows/generators/test.py new file mode 100644 index 00000000000..f5bfc4dcd02 --- /dev/null +++ b/tests/regression_tests/weightwindows/generators/test.py @@ -0,0 +1,54 @@ +import os + +import numpy as np +import openmc +import pytest + + +def test_ww_generator(run_in_tmpdir): + # create a simple spherical shield model + model = openmc.Model() + + water = openmc.Material() + water.set_density('g/cc', 1.0) + water.add_nuclide('H1', 0.66) + water.add_nuclide('O16', 0.34) + + s = openmc.Sphere(r=50, boundary_type='vacuum') + c = openmc.Cell(fill=water, region=-s) + + model.geometry = openmc.Geometry([c]) + + model.settings.particles = 500 + model.settings.batches = 5 + model.settings.run_mode = 'fixed source' + model.settings.max_splits = 100 + + mesh = openmc.RegularMesh.from_domain(model.geometry.root_universe) + energy_bounds = np.linspace(0.0, 1e6, 70) + particle = 'neutron' + + wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle) + wwg.update_parameters = {'ratio' : 5.0, 'threshold': 0.8, 'value' : 'mean'} + + model.settings.weight_window_generators = wwg + model.export_to_xml() + + model.run() + # we test the effectiveness of the update method elsewhere, so + # just test that the generation happens successfully here + assert os.path.exists('weight_windows.h5') + + wws_mean = openmc.hdf5_to_wws() + assert len(wws_mean) == 1 + + # check that generation using the relative error works too + wwg.update_parameters['value'] = 'rel_err' + model.run() + + wws_rel_err = openmc.hdf5_to_wws() + assert len(wws_rel_err) == 1 + + # we should not get the same set of weight windows when switching to use of + # rel. err. + assert (wws_mean[0].lower_ww_bounds != wws_rel_err[0].lower_ww_bounds).any() diff --git a/tests/unit_tests/weightwindows/test.py b/tests/unit_tests/weightwindows/test.py index 1dfad56aaa9..dce75c74045 100644 --- a/tests/unit_tests/weightwindows/test.py +++ b/tests/unit_tests/weightwindows/test.py @@ -6,6 +6,7 @@ from uncertainties import ufloat import openmc +import openmc.lib from openmc.stats import Discrete, Point from tests import cdtemp @@ -15,8 +16,6 @@ def wws(): # weight windows - - ww_files = ('ww_n.txt', 'ww_p.txt') cwd = Path(__file__).parent.absolute() ww_n_file, ww_p_file = [cwd / Path(f) for f in ww_files] @@ -240,3 +239,47 @@ def test_roundtrip(run_in_tmpdir, model, wws): # ensure the lower bounds read in from the XML match those of the for ww_out, ww_in in zipped_wws: assert(ww_out == ww_in) + + +def test_ww_attrs(run_in_tmpdir, model): + model.export_to_xml() + + openmc.lib.init() + + tally = openmc.lib.tallies[model.tallies[0].id] + + wws = openmc.lib.WeightWindows.from_tally(tally) + + # this is the first weight window object created + assert wws.id == 1 + + with pytest.raises(ValueError): + tally.find_filter(openmc.lib.AzimuthalFilter) + + mesh_filter = tally.find_filter(openmc.lib.MeshFilter) + mesh = mesh_filter.mesh + + assert wws.mesh.id == mesh.id + + assert wws.particle == openmc.ParticleType.NEUTRON + + wws.particle = 1 + assert wws.particle == openmc.ParticleType.PHOTON + wws.particle = 'photon' + assert wws.particle == openmc.ParticleType.PHOTON + + with pytest.raises(ValueError): + wws.particle = '🌠' + + energy_filter = tally.find_filter(openmc.lib.EnergyFilter) + np.testing.assert_allclose(np.unique(energy_filter.bins), wws.energy_bounds) + + # at this point the weight window bounds are uninitialized + assert all(wws.bounds[0] == -1) + assert all(wws.bounds[1] == -1) + + wws = openmc.lib.WeightWindows.from_tally(tally, particle='photon') + assert wws.id == 2 + assert wws.particle == openmc.ParticleType.PHOTON + + openmc.lib.finalize() \ No newline at end of file diff --git a/tests/unit_tests/weightwindows/test_ww_gen.py b/tests/unit_tests/weightwindows/test_ww_gen.py new file mode 100644 index 00000000000..74bbcfadaee --- /dev/null +++ b/tests/unit_tests/weightwindows/test_ww_gen.py @@ -0,0 +1,316 @@ +from itertools import permutations +from pathlib import Path + +import numpy as np +import openmc +import openmc.lib +import pytest + + +@pytest.fixture +def model(): + openmc.reset_auto_ids() + + # create a simple spherical shell shielding model + + ### Materials ### + water = openmc.Material() + water.set_density('g/cc', 1.0) + water.add_nuclide("H1", 2) + water.add_nuclide("O16", 1) + + steel = openmc.Material() + steel.set_density('g/cc', 8.0) + steel.add_nuclide("Fe56", 1.0) + + air = openmc.Material() + air.set_density('g/cc', 0.001205) + air.add_nuclide("N14", 0.781557629247) + air.add_nuclide("O16", 0.210668126508) + + boron = openmc.Material() + boron.set_density('g/cc', 2.52) + boron.add_nuclide("B10", 0.15856) + boron.add_nuclide("B11", 0.64144) + boron.add_nuclide("C0", 0.2) + + ### Geometry ### + radii = [5.0, 10.0, 30.0, 31.0, 50.0] + + surfs = [openmc.Sphere(r=r) for r in radii] + + surfs[-1].boundary_type = 'vacuum' + + regions = openmc.model.subdivide(surfs) + + mats = [air, water, steel, boron, air] + + cells = [openmc.Cell(fill=m, region=r) for r, m in zip(regions, mats)] + + geometry = openmc.Geometry(cells) + + ### Settings ### + + settings = openmc.Settings( + run_mode='fixed source', + particles=100, + batches=10, + max_splits=10, + survival_biasing=False + ) + + # 10 keV neutron point source at the origin + space = openmc.stats.Point() + energy = openmc.stats.Discrete(x=[1e4], p=[1.0]) + settings.source = openmc.Source(space=space, energy=energy) + + return openmc.Model(geometry=geometry, settings=settings) + + +# create a tally used for weight window generation +mesh = openmc.RegularMesh() +mesh.lower_left = [-50.0] * 3 +mesh.upper_right = [50.0] * 3 +# use un-equal mesh widths in each dimension to more robustly check +# use of tally data +mesh.dimension = (19, 20, 21) + +mf = openmc.MeshFilter(mesh) + +ef = openmc.EnergyFilter([0.0, 1e7]) + +pf = openmc.ParticleFilter(['neutron', 'photon']) + +filters = [mf, ef, pf] + +test_cases = list(permutations(filters)) +test_cases += list(permutations(filters[:-1])) +test_cases += list(permutations(filters[::2])) + + +def labels(params): + out = [] + for p in params: + if isinstance(p, openmc.ParticleFilter): + out.append('particle') + elif isinstance(p, openmc.MeshFilter): + out.append('mesh') + elif isinstance(p, openmc.EnergyFilter): + out.append('energy') + return "filters:" + '-'.join(out) + + +@pytest.mark.parametrize("filters", test_cases, ids=labels) +def test_ww_gen(filters, model): + + tally = openmc.Tally() + tally.filters = list(filters) + tally.scores = ['flux'] + model.tallies = openmc.Tallies([tally]) + + model.export_to_model_xml() + + ref_lower = None + ref_upper = None + # test weight window generation capability + with openmc.lib.run_in_memory(): + + # retrieve the tally we created above in memory + lib_tally = openmc.lib.tallies[tally.id] + + # create a new weight windows object + ww = openmc.lib.WeightWindows.from_tally(lib_tally) + + # run particle transport + openmc.lib.run() + + # capture analog data + analog_mean = np.copy(lib_tally.mean) + + # update the weight window values using tally results + ww.update_magic(lib_tally) + + assert any(ww.bounds[0] != -1) + assert any(ww.bounds[1] != -1) + + # make sure that the weight window update doesn't change tally values + np.testing.assert_equal(lib_tally.mean, analog_mean) + + # check against weight windows from the previous iteration + # the order of filters should not change the weight window values + if ref_lower is None: + ref_lower = ww.bounds[0].copy() + else: + np.testing.assert_equal(ref_lower, ww.bounds[0]) + + if ref_upper is None: + ref_upper = ww.bounds[1].copy() + else: + np.testing.assert_equal(ref_upper, ww.bounds[1]) + + # turn on weight windows for the subsequent run + openmc.lib.settings.weight_windows_on = True + + openmc.lib.hard_reset() + + openmc.lib.run() + + ww_mean = np.copy(lib_tally.mean) + + # we expect that the application of weight windows will populate more tally + # bins than the analog run for the meshes in this test model + assert any(ww_mean != analog_mean) + assert np.count_nonzero(ww_mean) > np.count_nonzero(analog_mean) + + +def test_ww_import_export(run_in_tmpdir, model): + # create a tally for weight windows + mesh = openmc.RegularMesh() + mesh.lower_left = [-50.0] * 3 + mesh.upper_right = [50.0] * 3 + # use un-equal mesh widths in each dimension to more robustly check + # use of tally data + mesh.dimension = (3, 4, 5) + + mf = openmc.MeshFilter(mesh) + + e_groups = np.logspace(0, 7, 8) + ef = openmc.EnergyFilter(e_groups) + + pf = openmc.ParticleFilter(['neutron', 'photon']) + + tally = openmc.Tally() + tally.filters = [mf, ef, pf] + tally.scores = ['flux'] + + model.tallies = openmc.Tallies([tally]) + + # first, generate some weight windows + model.export_to_model_xml() + + openmc.lib.init() + + tally = openmc.lib.tallies[tally.id] + + ww = openmc.lib.WeightWindows.from_tally(tally) + + openmc.lib.run() + + mean_before = np.array(tally.mean) + + ww.update_magic(tally) + + mean_after = np.array(tally.mean) + + assert (mean_before == mean_after).all() + + lb_before, up_before = ww.bounds + + openmc.lib.export_weight_windows() + + assert Path('weight_windows.h5').exists() + + openmc.lib.import_weight_windows('weight_windows.h5') + + ww = openmc.lib.weight_windows[2] + + lb_after, up_after = ww.bounds + + assert np.allclose(lb_before, lb_after) + assert np.allclose(up_before, up_after) + + openmc.lib.finalize() + + +def test_ww_gen_roundtrip(run_in_tmpdir, model): + + mesh = openmc.RegularMesh.from_domain(model.geometry.root_universe) + energy_bounds = np.linspace(0.0, 1e8, 11) + particle_type = 'neutron' + + wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle_type) + wwg.update_params = {'ratio' : 5.0, + 'threshold': 0.8, + 'value' : 'mean'} + + model.settings.weight_window_generators = wwg + model.export_to_xml() + + model_in = openmc.Model.from_xml() + + assert len(model_in.settings.weight_window_generators) == 1 + + wwg_in = model.settings.weight_window_generators[0] + + # rountrip tests + model_in = openmc.Model.from_xml() + assert len(model_in.settings.weight_window_generators) == 1 + wwg_in = model_in.settings.weight_window_generators[0] + assert wwg_in.max_realizations == 1 + assert wwg_in.on_the_fly == True + assert wwg_in.update_interval == 1 + assert wwg_in.update_parameters == wwg.update_parameters + + with pytest.raises(ValueError): + wwg.method = '🦍🐒' + + with pytest.raises(TypeError): + wwg.update_parameters = {'ratio' : 'one-to-one'} + + with pytest.raises(ValueError): + wwg.max_realizations = -1 + + +def test_python_hdf5_roundtrip(run_in_tmpdir, model): + + # add a tally to the model + mesh = openmc.RegularMesh.from_domain(model.geometry) + + # some arbitrary energy groups + e_groups = np.logspace(0, 6, 4) + energy_filter = openmc.EnergyFilter(e_groups) + + bounds = np.arange(energy_filter.num_bins * np.prod(mesh.dimension)) + + wws = openmc.WeightWindows(mesh, bounds, bounds, energy_bounds=e_groups) + + model.settings.weight_windows = [wws] + + model.export_to_xml() + + # initialize and export wws to HDF5 + openmc.lib.init() + + openmc.lib.export_weight_windows() + + openmc.lib.finalize() + + wws_hdf5 = openmc.hdf5_to_wws()[0] + + # ensure + assert all(wws.energy_bounds == wws_hdf5.energy_bounds) + assert wws.id == wws_hdf5.id + assert wws.mesh.id == wws_hdf5.mesh.id + np.testing.assert_array_equal(wws.lower_ww_bounds, wws_hdf5.lower_ww_bounds) + np.testing.assert_array_equal(wws.upper_ww_bounds, wws_hdf5.upper_ww_bounds) + + +def test_ww_bounds_set_in_memory(run_in_tmpdir, model): + tally = openmc.Tally() + tally.filters = filters + tally.scores = ['flux'] + model.tallies = [tally] + + bounds = np.arange(ef.num_bins * np.prod(mf.mesh.dimension)) + + model.export_to_xml() + + openmc.lib.init() + + lib_tally = openmc.lib.tallies[tally.id] + + wws = openmc.lib.WeightWindows.from_tally(lib_tally) + + wws.bounds = (bounds, bounds) + + openmc.lib.finalize() From bc4e95127c4bbbe1b98557debfbc5e689aa6690a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 11 Jun 2023 15:05:16 -0500 Subject: [PATCH 23/45] Fix potential out-of-bounds access in TimeFilter (#2532) --- src/tallies/filter_time.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tallies/filter_time.cpp b/src/tallies/filter_time.cpp index 787acc49e11..0378aa28de3 100644 --- a/src/tallies/filter_time.cpp +++ b/src/tallies/filter_time.cpp @@ -80,10 +80,11 @@ void TimeFilter::get_all_bins( if (t_end < bins_[i_bin + 1]) break; } - } else { + } else if (t_end < bins_.back()) { // ------------------------------------------------------------------------- // For collision estimator or surface tallies, find a match based on the // exact time of the particle + const auto i_bin = lower_bound_index(bins_.begin(), bins_.end(), t_end); match.bins_.push_back(i_bin); match.weights_.push_back(1.0); From 6693ff3229a996ebe8de0a6b51950d74bf5f9135 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 12 Jun 2023 09:35:12 -0500 Subject: [PATCH 24/45] Add issue and pull request templates (#2560) --- .github/ISSUE_TEMPLATE/bug_report.md | 29 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 5 ++++ .github/ISSUE_TEMPLATE/documentation.md | 10 ++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 19 +++++++++++++++ .github/pull_request_template.md | 24 +++++++++++++++++++ 5 files changed, 87 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/documentation.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/pull_request_template.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000000..99ba77a6fee --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,29 @@ +--- +name: Bug report +about: Report a bug that is preventing proper operation +title: '' +labels: Bugs +assignees: '' + +--- + + + +## Bug Description + + + +## Steps to Reproduce + + + +## Environment + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..40e40338b92 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Troubleshooting and User Support + url: https://openmc.discourse.group/ + about: For user support and troubleshooting, please use our Discourse forum diff --git a/.github/ISSUE_TEMPLATE/documentation.md b/.github/ISSUE_TEMPLATE/documentation.md new file mode 100644 index 00000000000..04ecb8cf9c2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.md @@ -0,0 +1,10 @@ +--- +name: Documentation improvement +about: Found something incomplete or incorrect in our documentation? +title: '' +labels: Documentation +assignees: '' + +--- + + diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000000..ddf49b89417 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,19 @@ +--- +name: Feature request +about: Suggest a new feature or enhancement to existing capabilities +title: '' +labels: '' +assignees: '' + +--- + +## Description + + + +## Alternatives + + + +## Compatibility + diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 00000000000..03091481201 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,24 @@ + + +# Description + +Please include a summary of the change and which issue is fixed if applicable. Please also include relevant motivation and context. + +Fixes # (issue) + +# Checklist + +- [ ] I have performed a self-review of my own code +- [ ] I have run [clang-format](https://docs.openmc.org/en/latest/devguide/styleguide.html#automatic-formatting) on any C++ source files (if applicable) +- [ ] I have followed the [style guidelines](https://docs.openmc.org/en/latest/devguide/styleguide.html#python) for Python source files (if applicable) +- [ ] I have made corresponding changes to the documentation (if applicable) +- [ ] I have added tests that prove my fix is effective or that my feature works (if applicable) + From 98c4eb2a2cd7589a891cf1d19e937b0b72e6d39e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 13 Jun 2023 06:19:10 -0500 Subject: [PATCH 25/45] Several small documentation updates (#2558) --- docs/source/devguide/docbuild.rst | 17 +++++---------- docs/source/devguide/tests.rst | 18 +++++++--------- docs/source/devguide/workflow.rst | 2 +- docs/source/io_formats/particle_restart.rst | 2 ++ docs/source/io_formats/statepoint.rst | 2 +- docs/source/quickinstall.rst | 2 +- docs/source/usersguide/basics.rst | 23 ++++++--------------- docs/source/usersguide/install.rst | 20 +++++++++--------- 8 files changed, 33 insertions(+), 53 deletions(-) diff --git a/docs/source/devguide/docbuild.rst b/docs/source/devguide/docbuild.rst index 38ef628df56..389a423f3a2 100644 --- a/docs/source/devguide/docbuild.rst +++ b/docs/source/devguide/docbuild.rst @@ -5,21 +5,14 @@ Building Sphinx Documentation ============================= In order to build the documentation in the ``docs`` directory, you will need to -have the `Sphinx `_ third-party Python -package. The easiest way to install Sphinx is via pip: +have the several third-party Python packages installed, including `Sphinx +`_. To install the necessary +prerequisites, provide the optional "docs" dependencies when installing OpenMC's +Python API. That is, from the root directory of the OpenMC repository: .. code-block:: sh - pip install sphinx - -Additionally, you will need several Sphinx extensions that can be installed -directly with pip: - -.. code-block:: sh - - pip install sphinx-numfig - pip install sphinxcontrib-katex - pip install sphinxcontrib-svg2pdfconverter + python -m pip install .[docs] ----------------------------------- Building Documentation as a Webpage diff --git a/docs/source/devguide/tests.rst b/docs/source/devguide/tests.rst index d076511b1d9..582bb033d9e 100644 --- a/docs/source/devguide/tests.rst +++ b/docs/source/devguide/tests.rst @@ -23,11 +23,7 @@ Prerequisites OpenMC in development/editable mode. With setuptools, this is accomplished by running:: - python setup.py develop - - or using pip (recommended):: - - pip install -e .[test] + python -m pip install -e .[test] - The test suite requires a specific set of cross section data in order for tests to pass. A download URL for the data that OpenMC expects can be found @@ -83,13 +79,13 @@ does not exist run:: touch test_.cpp -The file must be added to the CMake build system in -``tests/cpp_unit_tests/CMakeLists.txt``. ``test_`` should -be added to ``TEST_NAMES``. +The file must be added to the CMake build system in +``tests/cpp_unit_tests/CMakeLists.txt``. ``test_`` should +be added to ``TEST_NAMES``. -To add a test case to ``test_.cpp`` ensure -``catch2/catch_test_macros.hpp`` is included. A unit test can then be added -using the ``TEST_CASE`` macro and the ``REQUIRE`` assertion from Catch2. +To add a test case to ``test_.cpp`` ensure +``catch2/catch_test_macros.hpp`` is included. A unit test can then be added +using the ``TEST_CASE`` macro and the ``REQUIRE`` assertion from Catch2. Adding Tests to the Regression Suite ------------------------------------ diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index 6b5ec63cb5f..d6a3c6ba4f4 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -116,7 +116,7 @@ pip_. From the root directory of the OpenMC repository, run: .. code-block:: sh - pip install -e .[test] + python -m pip install -e .[test] This installs the OpenMC Python package in `"editable" mode `_ so that 1) diff --git a/docs/source/io_formats/particle_restart.rst b/docs/source/io_formats/particle_restart.rst index 53f86735f31..2734f0470ef 100644 --- a/docs/source/io_formats/particle_restart.rst +++ b/docs/source/io_formats/particle_restart.rst @@ -26,6 +26,8 @@ The current version of the particle restart file format is 2.0. - **run_mode** (*char[]*) -- Run mode used, either 'fixed source', 'eigenvalue', or 'particle restart'. - **id** (*int8_t*) -- Unique identifier of the particle. + - **type** (*int*) -- Particle type (0=neutron, 1=photon, 2=electron, + 3=positron) - **weight** (*double*) -- Weight of the particle. - **energy** (*double*) -- Energy of the particle in eV for continuous-energy mode, or the energy group of the particle for diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 37a379b52cb..edff686b1bd 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -4,7 +4,7 @@ State Point File Format ======================= -The current version of the statepoint file format is 17.0. +The current version of the statepoint file format is 18.1. **/** diff --git a/docs/source/quickinstall.rst b/docs/source/quickinstall.rst index 480db5be68f..b25b02fb868 100644 --- a/docs/source/quickinstall.rst +++ b/docs/source/quickinstall.rst @@ -157,7 +157,7 @@ distribution/repository, run: .. code-block:: sh - pip install . + python -m pip install . If you want to build a parallel version of OpenMC (using OpenMP or MPI), directions can be found in the :ref:`detailed installation instructions diff --git a/docs/source/usersguide/basics.rst b/docs/source/usersguide/basics.rst index 3394c17a630..60b599588eb 100644 --- a/docs/source/usersguide/basics.rst +++ b/docs/source/usersguide/basics.rst @@ -83,12 +83,12 @@ Creating Input Files .. currentmodule:: openmc The most rudimentary option for creating input files is to simply write them -from scratch using the :ref:`XML format specifications -`. This approach will feel familiar to users of other -Monte Carlo codes such as MCNP and Serpent, with the added bonus that the XML -formats feel much more "readable". Alternatively, input files can be generated -using OpenMC's :ref:`Python API `, which is introduced in the -following section. +from scratch using the :ref:`XML format specifications `. +This approach will feel familiar to users of other Monte Carlo codes such as +MCNP and Serpent, with the added bonus that the XML formats feel much more +"readable". However, it is strongly recommended to generate input files using +OpenMC's :ref:`Python API `, which is introduced in the following +section. ---------- Python API @@ -178,14 +178,3 @@ energy electronvolt eV time second s ======= ============ ====== ------------------------------------- -ERSN-OpenMC Graphical User Interface ------------------------------------- - -A third-party Java-based user-friendly graphical user interface for creating XML -input files called ERSN-OpenMC_ is developed and maintained by members of the -Radiation and Nuclear Systems Group at the Faculty of Sciences Tetouan, Morocco. -The GUI also allows one to automatically download prerequisites for installing and -running OpenMC. - -.. _ERSN-OpenMC: https://github.com/EL-Bakkali-Jaafar/ERSN-OpenMC diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index ed02c5d9fab..ab2cbe64546 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -488,13 +488,13 @@ OpenMC locally by specifying an install prefix when running cmake: The ``CMAKE_INSTALL_PREFIX`` variable can be changed to any path for which you have write-access. -Compiling on Windows 10 ------------------------ +Compiling on Windows +-------------------- -Recent versions of Windows 10 include a subsystem for Linux that allows one to -run Bash within Ubuntu running in Windows. First, follow the installation guide -`here `_ to get Bash -on Ubuntu on Windows setup. Once you are within bash, obtain the necessary +Recent versions of Windows include a subsystem for Linux that allows one to run +Bash within Ubuntu running in Windows. First, follow the installation guide +`here `_ to get Bash on +Ubuntu on Windows set up. Once you are within bash, obtain the necessary :ref:`prerequisites ` via ``apt``. Finally, follow the :ref:`instructions for compiling on linux `. @@ -522,7 +522,7 @@ distribution/repository, run: .. code-block:: sh - pip install . + python -m pip install . pip will first check that all :ref:`required third-party packages ` have been installed, and if they are not present, @@ -608,15 +608,15 @@ for OpenMC. Thus, the install process would proceed as follows: make install cd .. - MPICC= pip install mpi4py - HDF5_DIR= pip install --no-binary=h5py h5py + MPICC= python -m pip install mpi4py + HDF5_DIR= python -m pip install --no-binary=h5py h5py If you are using parallel HDF5, you'll also need to make sure the right MPI wrapper is used when installing h5py: .. code-block:: sh - CC= HDF5_MPI=ON HDF5_DIR= pip install --no-binary=h5py h5py + CC= HDF5_MPI=ON HDF5_DIR= python -m pip install --no-binary=h5py h5py .. _Conda: https://conda.io/en/latest/ .. _pip: https://pip.pypa.io/en/stable/ From 787b3e0308e3470c86155f82ae048a533095470a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 15 Jun 2023 00:15:22 -0500 Subject: [PATCH 26/45] Use `multiply_density` in depletion reaction rate helper classes (#2559) Co-authored-by: Andrew Johnson --- openmc/deplete/abc.py | 3 +-- openmc/deplete/helpers.py | 35 +++++++++++--------------- openmc/deplete/independent_operator.py | 22 ++++++++++------ openmc/deplete/openmc_operator.py | 22 +++++++++------- 4 files changed, 43 insertions(+), 39 deletions(-) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index d4cc1ba4d7f..802b3833f16 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -274,8 +274,7 @@ def divide_by_atoms(self, number): Parameters ---------- number : iterable of float - Number density [atoms/b-cm] of each nuclide tracked in the - calculation. + Number of each nuclide in [atom] tracked in the calculation. Returns ------- diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index ec0f6565025..9a1fc6a3fa4 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -26,6 +26,7 @@ "ConstantFissionYieldHelper", "FissionYieldCutoffHelper", "AveragedFissionYieldHelper", "FluxCollapseHelper") + class TalliedFissionYieldHelper(FissionYieldHelper): """Abstract class for computing fission yields with tallies @@ -159,22 +160,23 @@ def nuclides(self, nuclides): def generate_tallies(self, materials, scores): """Produce one-group reaction rate tally - Uses the :mod:`openmc.lib` to generate a tally - of relevant reactions across all burnable materials. + Uses the :mod:`openmc.lib` to generate a tally of relevant reactions + across all burnable materials. Parameters ---------- - materials : iterable of :class:`openmc.Material` - Burnable materials in the problem. Used to - construct a :class:`openmc.MaterialFilter` + materials : iterable of :class:`openmc.lib.Material` + Burnable materials in the problem. Used to construct a + :class:`openmc.lib.MaterialFilter` scores : iterable of str - Reaction identifiers, e.g. ``"(n, fission)"``, - ``"(n, gamma)"``, needed for the reaction rate tally. + Reaction identifiers, e.g. ``"(n, fission)"``, ``"(n, gamma)"``, + needed for the reaction rate tally. """ self._rate_tally = Tally() self._rate_tally.writable = False self._rate_tally.scores = scores self._rate_tally.filters = [MaterialFilter(materials)] + self._rate_tally.multiply_density = False self._rate_tally_means_cache = None @property @@ -194,7 +196,7 @@ def reset_tally_means(self): """ self._rate_tally_means_cache = None - def get_material_rates(self, mat_id, nuc_index, react_index): + def get_material_rates(self, mat_id, nuc_index, rx_index): """Return an array of reaction rates for a material Parameters @@ -204,7 +206,7 @@ def get_material_rates(self, mat_id, nuc_index, react_index): nuc_index : iterable of int Index for each nuclide in :attr:`nuclides` in the desired reaction rate matrix - react_index : iterable of int + rx_index : iterable of int Index for each reaction scored in the tally Returns @@ -215,9 +217,8 @@ def get_material_rates(self, mat_id, nuc_index, react_index): """ self._results_cache.fill(0.0) full_tally_res = self.rate_tally_means[mat_id] - for i_tally, (i_nuc, i_react) in enumerate( - product(nuc_index, react_index)): - self._results_cache[i_nuc, i_react] = full_tally_res[i_tally] + for i_tally, (i_nuc, i_rx) in enumerate(product(nuc_index, rx_index)): + self._results_cache[i_nuc, i_rx] = full_tally_res[i_tally] return self._results_cache @@ -304,6 +305,7 @@ def generate_tallies(self, materials, scores): self._rate_tally.writable = False self._rate_tally.scores = self._reactions_direct self._rate_tally.filters = [MaterialFilter(materials)] + self._rate_tally.multiply_density = False self._rate_tally_means_cache = None if self._nuclides_direct is not None: # check if any direct tally nuclides are requested that are not @@ -375,13 +377,7 @@ def get_material_rates(self, mat_index, nuc_index, react_index): mat = self._materials[mat_index] - # Build nucname: density mapping to enable O(1) lookup in loop below - densities = dict(zip(mat.nuclides, mat.densities)) - for name, i_nuc in zip(self.nuclides, nuc_index): - # Determine density of nuclide - density = densities[name] - for mt, score, i_rx in zip(self._mts, self._scores, react_index): if score in self._reactions_direct and name in nuclides_direct: # Determine index in rx_rates @@ -396,8 +392,7 @@ def get_material_rates(self, mat_index, nuc_index, react_index): rate_per_nuc = nuc.collapse_rate( mt, mat.temperature, self._energies, flux) - # Multiply by density to get absolute reaction rate - self._results_cache[i_nuc, i_rx] = rate_per_nuc * density + self._results_cache[i_nuc, i_rx] = rate_per_nuc return self._results_cache diff --git a/openmc/deplete/independent_operator.py b/openmc/deplete/independent_operator.py index 0c950b31b6f..6caef263521 100644 --- a/openmc/deplete/independent_operator.py +++ b/openmc/deplete/independent_operator.py @@ -295,7 +295,7 @@ class _IndependentRateHelper(ReactionRateHelper): ---------- nuc_ind_map : dict of int to str Dictionary mapping the nuclide index to nuclide name - rxn_ind_map : dict of int to str + rx_ind_map : dict of int to str Dictionary mapping reaction index to reaction name """ @@ -305,7 +305,7 @@ def __init__(self, op): super().__init__(rates.n_nuc, rates.n_react) self.nuc_ind_map = {ind: nuc for nuc, ind in rates.index_nuc.items()} - self.rxn_ind_map = {ind: rxn for rxn, ind in rates.index_rx.items()} + self.rx_ind_map = {ind: rxn for rxn, ind in rates.index_rx.items()} self._op = op def generate_tallies(self, materials, scores): @@ -330,14 +330,20 @@ def get_material_rates(self, mat_id, nuc_index, react_index): """ self._results_cache.fill(0.0) + # Get volume in units of [b-cm] + volume_b_cm = 1e24 * self._op.number.get_mat_volume(mat_id) + for i_nuc, i_react in product(nuc_index, react_index): nuc = self.nuc_ind_map[i_nuc] - rxn = self.rxn_ind_map[i_react] - - # Sigma^j_i * V = sigma^j_i * n_i * V = sigma^j_i * N_i - self._results_cache[i_nuc,i_react] = \ - self._op.cross_sections[rxn][nuc] * \ - self._op.number[mat_id, nuc] + rx = self.rx_ind_map[i_react] + + # OK, this is kind of weird, but we multiply by volume in [b-cm] + # only because OpenMCOperator._calculate_reaction_rates has to + # divide it out later. It might make more sense to account for + # the source rate (flux) here rather than in the normalization + # helper. + self._results_cache[i_nuc, i_react] = \ + self._op.cross_sections[rx][nuc] * volume_b_cm return self._results_cache diff --git a/openmc/deplete/openmc_operator.py b/openmc/deplete/openmc_operator.py index 8a13bff7fa0..adf1c2eb7b3 100644 --- a/openmc/deplete/openmc_operator.py +++ b/openmc/deplete/openmc_operator.py @@ -371,8 +371,8 @@ def initial_condition(self, materials): Parameters ---------- - materials : list of str - list of material IDs + materials : list of openmc.lib.Material + list of materials Returns ------- @@ -503,7 +503,7 @@ def _calculate_reaction_rates(self, source_rate): # Form fast map nuc_ind = [rates.index_nuc[nuc] for nuc in rxn_nuclides] - react_ind = [rates.index_rx[react] for react in self.chain.reactions] + rx_ind = [rates.index_rx[react] for react in self.chain.reactions] # Keep track of energy produced from all reactions in eV per source # particle @@ -534,21 +534,25 @@ def _calculate_reaction_rates(self, source_rate): for nuc, i_nuc_results in zip(rxn_nuclides, nuc_ind): number[i_nuc_results] = self.number[mat, nuc] + # Get microscopic reaction rates in [(reactions/src)*b-cm/atom]. 2D + # array with shape (nuclides, reactions). tally_rates = self._rate_helper.get_material_rates( - mat_index, nuc_ind, react_ind) + mat_index, nuc_ind, rx_ind) # Compute fission yields for this material fission_yields.append(self._yield_helper.weighted_yields(i)) # Accumulate energy from fission + volume_b_cm = 1e24 * self.number.get_mat_volume(mat) if fission_ind is not None: - self._normalization_helper.update( - tally_rates[:, fission_ind]) + atom_per_bcm = number / volume_b_cm + fission_rates = tally_rates[:, fission_ind] * atom_per_bcm + self._normalization_helper.update(fission_rates) - # Divide by total number of atoms and store - rates[i] = self._rate_helper.divide_by_atoms(number) + # Divide by [b-cm] to get [(reactions/src)/atom] + rates[i] = tally_rates / volume_b_cm - # Scale reaction rates to obtain units of (reactions/sec)/atom + # Scale reaction rates to obtain units of [(reactions/sec)/atom] rates *= self._normalization_helper.factor(source_rate) # Store new fission yields on the chain From c5bc2302eb91745c810ddbaa97073ca8be0c3486 Mon Sep 17 00:00:00 2001 From: Lorenzo Chierici Date: Fri, 16 Jun 2023 06:00:20 +0200 Subject: [PATCH 27/45] Transfer rates mpi (#2551) Co-authored-by: Paul Romano --- openmc/deplete/coupled_operator.py | 3 +- openmc/deplete/independent_operator.py | 3 +- openmc/deplete/openmc_operator.py | 24 +----- openmc/deplete/pool.py | 108 +++++++++++++++++-------- openmc/deplete/transfer_rates.py | 3 + 5 files changed, 81 insertions(+), 60 deletions(-) diff --git a/openmc/deplete/coupled_operator.py b/openmc/deplete/coupled_operator.py index 669e98ddac3..d8d4838a4a7 100644 --- a/openmc/deplete/coupled_operator.py +++ b/openmc/deplete/coupled_operator.py @@ -21,7 +21,8 @@ import openmc.lib from openmc.mpi import comm from .abc import OperatorResult -from .openmc_operator import OpenMCOperator, _distribute +from .openmc_operator import OpenMCOperator +from .pool import _distribute from .results import Results from .helpers import ( DirectReactionRateHelper, ChainFissionHelper, ConstantFissionYieldHelper, diff --git a/openmc/deplete/independent_operator.py b/openmc/deplete/independent_operator.py index 6caef263521..8d7882ac9be 100644 --- a/openmc/deplete/independent_operator.py +++ b/openmc/deplete/independent_operator.py @@ -15,7 +15,8 @@ from openmc.checkvalue import check_type from openmc.mpi import comm from .abc import ReactionRateHelper, OperatorResult -from .openmc_operator import OpenMCOperator, _distribute +from .openmc_operator import OpenMCOperator +from .pool import _distribute from .microxs import MicroXS from .results import Results from .helpers import ChainFissionHelper, ConstantFissionYieldHelper, SourceRateHelper diff --git a/openmc/deplete/openmc_operator.py b/openmc/deplete/openmc_operator.py index adf1c2eb7b3..55a7d724692 100644 --- a/openmc/deplete/openmc_operator.py +++ b/openmc/deplete/openmc_operator.py @@ -16,33 +16,11 @@ from .abc import TransportOperator, OperatorResult from .atom_number import AtomNumber from .reaction_rates import ReactionRates +from .pool import _distribute __all__ = ["OpenMCOperator", "OperatorResult"] -def _distribute(items): - """Distribute items across MPI communicator - - Parameters - ---------- - items : list - List of items of distribute - - Returns - ------- - list - Items assigned to process that called - - """ - min_size, extra = divmod(len(items), comm.size) - j = 0 - for i in range(comm.size): - chunk_size = min_size + int(i < extra) - if comm.rank == i: - return items[j:j + chunk_size] - j += chunk_size - - class OpenMCOperator(TransportOperator): """Abstract class holding OpenMC-specific functions for running depletion calculations. diff --git a/openmc/deplete/pool.py b/openmc/deplete/pool.py index fc006a88426..1fa5e26ac87 100644 --- a/openmc/deplete/pool.py +++ b/openmc/deplete/pool.py @@ -6,7 +6,7 @@ from multiprocessing import Pool from scipy.sparse import bmat import numpy as np - +from openmc.mpi import comm # Configurable switch that enables / disables the use of # multiprocessing routines during depletion @@ -16,6 +16,27 @@ # calculations NUM_PROCESSES = None +def _distribute(items): + """Distribute items across MPI communicator + + Parameters + ---------- + items : list + List of items of distribute + + Returns + ------- + list + Items assigned to process that called + + """ + min_size, extra = divmod(len(items), comm.size) + j = 0 + for i in range(comm.size): + chunk_size = min_size + int(i < extra) + if comm.rank == i: + return items[j:j + chunk_size] + j += chunk_size def deplete(func, chain, x, rates, dt, matrix_func=None, transfer_rates=None, *matrix_args): @@ -72,45 +93,62 @@ def deplete(func, chain, x, rates, dt, matrix_func=None, transfer_rates=None, if transfer_rates is not None: # Calculate transfer rate terms as diagonal matrices transfers = map(chain.form_rr_term, repeat(transfer_rates), - transfer_rates.burnable_mats) + transfer_rates.local_mats) # Subtract transfer rate terms from Bateman matrices matrices = [matrix - transfer for (matrix, transfer) in zip(matrices, transfers)] if len(transfer_rates.index_transfer) > 0: - # Calculate transfer rate terms as diagonal matrices - transfer_pair = { - mat_pair: chain.form_rr_term(transfer_rates, mat_pair) - for mat_pair in transfer_rates.index_transfer - } - - # Combine all matrices together in a single matrix of matrices - # to be solved in one go - n_rows = n_cols = len(transfer_rates.burnable_mats) - rows = [] - for row in range(n_rows): - cols = [] - for col in range(n_cols): - mat_pair = (transfer_rates.burnable_mats[row], - transfer_rates.burnable_mats[col]) - if row == col: - # Fill the diagonals with the Bateman matrices - cols.append(matrices[row]) - elif mat_pair in transfer_rates.index_transfer: - # Fill the off-diagonals with the transfer pair matrices - cols.append(transfer_pair[mat_pair]) - else: - cols.append(None) - - rows.append(cols) - matrix = bmat(rows) - - # Concatenate vectors of nuclides in one - x_multi = np.concatenate([xx for xx in x]) - x_result = func(matrix, x_multi, dt) - - # Split back the nuclide vector result into the original form - x_result = np.split(x_result, np.cumsum([len(i) for i in x])[:-1]) + # Gather all on comm.rank 0 + matrices = comm.gather(matrices) + x = comm.gather(x) + + if comm.rank == 0: + # Expand lists + matrices = [elm for matrix in matrices for elm in matrix] + x = [x_elm for x_mat in x for x_elm in x_mat] + + # Calculate transfer rate terms as diagonal matrices + transfer_pair = { + mat_pair: chain.form_rr_term(transfer_rates, mat_pair) + for mat_pair in transfer_rates.index_transfer + } + + # Combine all matrices together in a single matrix of matrices + # to be solved in one go + n_rows = n_cols = len(transfer_rates.burnable_mats) + rows = [] + for row in range(n_rows): + cols = [] + for col in range(n_cols): + mat_pair = (transfer_rates.burnable_mats[row], + transfer_rates.burnable_mats[col]) + if row == col: + # Fill the diagonals with the Bateman matrices + cols.append(matrices[row]) + elif mat_pair in transfer_rates.index_transfer: + # Fill the off-diagonals with the transfer pair matrices + cols.append(transfer_pair[mat_pair]) + else: + cols.append(None) + + rows.append(cols) + matrix = bmat(rows) + + # Concatenate vectors of nuclides in one + x_multi = np.concatenate([xx for xx in x]) + x_result = func(matrix, x_multi, dt) + + # Split back the nuclide vector result into the original form + x_result = np.split(x_result, np.cumsum([len(i) for i in x])[:-1]) + + else: + x_result = None + + # Braodcast result to other ranks + x_result = comm.bcast(x_result) + # Distribute results across MPI + x_result = _distribute(x_result) return x_result diff --git a/openmc/deplete/transfer_rates.py b/openmc/deplete/transfer_rates.py index c6f0cd94dfb..fe21d7d6f41 100644 --- a/openmc/deplete/transfer_rates.py +++ b/openmc/deplete/transfer_rates.py @@ -30,6 +30,8 @@ class TransferRates: ---------- burnable_mats : list of str All burnable material IDs. + local_mats : list of str + All burnable material IDs being managed by a single process transfer_rates : dict of str to dict Container of transfer rates, elements and destination material index_transfer : Set of pair of str @@ -40,6 +42,7 @@ def __init__(self, operator, model): self.materials = model.materials self.burnable_mats = operator.burnable_mats + self.local_mats = operator.local_mats #initialize transfer rates container dict self.transfer_rates = {mat: {} for mat in self.burnable_mats} From 96d150a64e7636138bdc60042d97f3d33f5cce38 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 15 Jun 2023 23:03:46 -0500 Subject: [PATCH 28/45] Add C++ format check to GitHub Actions (#2554) --- .github/workflows/format-check.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .github/workflows/format-check.yml diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml new file mode 100644 index 00000000000..4914d5e5ea9 --- /dev/null +++ b/.github/workflows/format-check.yml @@ -0,0 +1,25 @@ +name: C++ Format Check + +on: pull_request + +jobs: + cpp-linter: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: cpp-linter/cpp-linter-action@v2 + id: linter + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + style: file + files-changed-only: true + tidy-checks: '-*' + version: '15' # clang-format version + file-annotations: true + step-summary: true + extensions: 'cpp,h' + + - name: Failure Check + if: steps.linter.outputs.checks-failed > 0 + run: echo "Some files failed the formatting check! See job summary and file annotations for more info" && exit 1 From 0fcb174b2af5c01d7b13aede766f8b7a53295394 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 16 Jun 2023 15:17:33 -0500 Subject: [PATCH 29/45] Add support for curvilinear elements when exporting cylindrical and spherical meshes to VTK (#2533) Co-authored-by: Paul Romano --- openmc/mesh.py | 486 ++-- .../mesh_to_vtk/cyl-data-actual.vtk | 41 + .../mesh_to_vtk/cyl-data-curvilinear.vtk | 329 +++ tests/unit_tests/mesh_to_vtk/cyl-data.vtk | 41 + .../mesh_to_vtk/cylindrical-curvilinear.vtk | 198 ++ .../mesh_to_vtk/cylindrical-linear.vtk | 33 + tests/unit_tests/mesh_to_vtk/rectilinear.vtk | 340 +++ tests/unit_tests/mesh_to_vtk/regular.vtk | 2394 +++++++++++++++++ .../mesh_to_vtk/spherical-curvilinear.vtk | 210 ++ .../mesh_to_vtk/spherical-linear.vtk | 39 + tests/unit_tests/mesh_to_vtk/test.py | 146 +- .../test_vtk_dims.py} | 2 +- 12 files changed, 4022 insertions(+), 237 deletions(-) create mode 100644 tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/cyl-data.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/rectilinear.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/regular.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk create mode 100644 tests/unit_tests/mesh_to_vtk/spherical-linear.vtk rename tests/unit_tests/{test_mesh_to_vtk.py => mesh_to_vtk/test_vtk_dims.py} (99%) diff --git a/openmc/mesh.py b/openmc/mesh.py index fde9f302dc9..0a5dff64336 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -177,7 +177,65 @@ def vertices(self): unpacked along the first dimension with xx, yy, zz = mesh.vertices. """ - return np.stack(np.meshgrid(*self._grids, indexing='ij'), axis=0) + return self._generate_vertices(*self._grids) + + @staticmethod + def _generate_vertices(i_grid, j_grid, k_grid): + """Returns an array with shape (3, i_grid.size+1, j_grid.size+1, k_grid.size+1) + containing the corner vertices of mesh elements. + """ + return np.stack(np.meshgrid(i_grid, j_grid, k_grid, indexing='ij'), axis=0) + + @staticmethod + def _generate_edge_midpoints(grids): + """Generates the midpoints of mesh element edges for each dimension of the mesh. + + Parameters + ---------- + grids : numpy.ndarray + The vertex grids along each dimension of the mesh. + + Returns + ------- + midpoint_grids : list of numpy.ndarray + The edge midpoints for the i, j, and k midpoints of each element in + i, j, k ordering. The shapes of the resulting grids are + [(3, ni-1, nj, nk), (3, ni, nj-1, nk), (3, ni, nj, nk-1)] + """ + # generate a set of edge midpoints for each dimension + midpoint_grids = [] + # generate the element edge midpoints in order s.t. + # the epxected element ordering is preserved with respect to the corner vertices + + # each grid is comprised of the mid points for one dimension and the + # corner vertices of the other two + for dims in ((0, 1, 2), (1, 0, 2), (2, 0, 1)): + # compute the midpoints along the first dimension + midpoints = grids[dims[0]][:-1] + 0.5 * np.diff(grids[dims[0]]) + + coords = (midpoints, grids[dims[1]], grids[dims[2]]) + + i_grid, j_grid, k_grid = [coords[dims.index(i)] for i in range(3)] + + # re-use the generate vertices method to create the full mesh grid + # transpose to get (i, j, k) ordering of the gridpoints + midpoint_grid = StructuredMesh._generate_vertices(i_grid, j_grid, k_grid) + midpoint_grids.append(midpoint_grid) + + return midpoint_grids + + @property + def midpoint_vertices(self): + """Create vertices that lie on the midpoint of element edges + """ + # generate edge midpoints needed for curvilinear element definition + midpoint_vertices = self._generate_edge_midpoints(self._grids) + + # convert each of the midpoint grids to cartesian coordinates + for vertices in midpoint_vertices: + self._convert_to_cartesian(vertices, self.origin) + + return midpoint_vertices @property def centroids(self): @@ -202,13 +260,15 @@ def centroids(self): def num_mesh_cells(self): return np.prod(self.dimension) - def write_data_to_vtk(self, points, filename, datasets, volume_normalization=True): + def write_data_to_vtk(self, + filename, + datasets=None, + volume_normalization=True, + curvilinear=False): """Creates a VTK object of the mesh Parameters ---------- - points : list or np.array - List of (X,Y,Z) tuples. filename : str Name of the VTK file to write. datasets : dict @@ -217,6 +277,9 @@ def write_data_to_vtk(self, points, filename, datasets, volume_normalization=Tru volume_normalization : bool, optional Whether or not to normalize the data by the volume of the mesh elements. + curvilinear : bool + Whether or not to write curvilinear elements. Only applies to + ``SphericalMesh`` and ``CylindricalMesh``. Raises ------ @@ -225,64 +288,193 @@ def write_data_to_vtk(self, points, filename, datasets, volume_normalization=Tru Returns ------- - vtk.vtkStructuredGrid - the VTK object + vtk.StructuredGrid or vtk.UnstructuredGrid + a VTK grid object representing the mesh """ - import vtk from vtk.util import numpy_support as nps # check that the data sets are appropriately sized - for label, dataset in datasets.items(): - errmsg = ( - f"The size of the dataset '{label}' ({dataset.size}) should be" - f" equal to the number of mesh cells ({self.num_mesh_cells})" - ) - if isinstance(dataset, np.ndarray): - if not dataset.size == self.num_mesh_cells: - raise ValueError(errmsg) - else: - if len(dataset) == self.num_mesh_cells: - raise ValueError(errmsg) - cv.check_type('label', label, str) + if datasets is not None: + self._check_vtk_datasets(datasets) - vtk_grid = vtk.vtkStructuredGrid() + # write linear elements using a structured grid + if not curvilinear or isinstance(self, (RegularMesh, RectilinearMesh)): + vtk_grid = self._create_vtk_structured_grid() + writer = vtk.vtkStructuredGridWriter() + # write curvilinear elements using an unstructured grid + else: + vtk_grid = self._create_vtk_unstructured_grid() + writer = vtk.vtkUnstructuredGridWriter() - vtk_grid.SetDimensions(*[dim + 1 for dim in self.dimension]) + if datasets is not None: + # maintain a list of the datasets as added + # to the VTK arrays to ensure they persist + # in memory until the file is written + datasets_out = [] + for label, dataset in datasets.items(): + dataset = np.asarray(dataset).flatten() + datasets_out.append(dataset) + + if volume_normalization: + dataset /= self.volumes.T.flatten() + + dataset_array = vtk.vtkDoubleArray() + dataset_array.SetName(label) + dataset_array.SetArray(nps.numpy_to_vtk(dataset), + dataset.size, + True) + vtk_grid.GetCellData().AddArray(dataset_array) + + writer.SetFileName(str(filename)) + writer.SetInputData(vtk_grid) + writer.Write() + + return vtk_grid + + def _create_vtk_structured_grid(self): + """Create a structured grid + + Returns + ------- + vtk.vtkStructuredGrid + a VTK structured grid object representing the mesh + """ + import vtk + from vtk.util import numpy_support as nps + + vertices = self.cartesian_vertices.T.reshape(-1, 3) vtkPts = vtk.vtkPoints() - vtkPts.SetData(nps.numpy_to_vtk(points, deep=True)) + vtkPts.SetData(nps.numpy_to_vtk(vertices, deep=True)) + vtk_grid = vtk.vtkStructuredGrid() vtk_grid.SetPoints(vtkPts) + vtk_grid.SetDimensions(*[dim + 1 for dim in self.dimension]) - # create VTK arrays for each of - # the data sets + return vtk_grid - # maintain a list of the datasets as added - # to the VTK arrays to ensure they persist - # in memory until the file is written - datasets_out = [] - for label, dataset in datasets.items(): - dataset = np.asarray(dataset).flatten() - datasets_out.append(dataset) + def _create_vtk_unstructured_grid(self): + """Create an unstructured grid of curvilinear elements + representing the mesh - if volume_normalization: - dataset /= self.volumes.T.flatten() + Returns + ------- + vtk.vtkUnstructuredGrid + a VTK unstructured grid object representing the mesh + """ + import vtk + from vtk.util import numpy_support as nps - dataset_array = vtk.vtkDoubleArray() - dataset_array.SetName(label) - dataset_array.SetArray(nps.numpy_to_vtk(dataset), - dataset.size, - True) - vtk_grid.GetCellData().AddArray(dataset_array) + corner_vertices = self.cartesian_vertices.T.reshape(-1, 3) - # write the .vtk file - writer = vtk.vtkStructuredGridWriter() - writer.SetFileName(str(filename)) - writer.SetInputData(vtk_grid) - writer.Write() + vtkPts = vtk.vtkPoints() + vtk_grid = vtk.vtkUnstructuredGrid() + vtk_grid.SetPoints(vtkPts) + # add corner vertices to the point set for the unstructured grid + # only insert unique points, we'll get their IDs in the point set to + # define element connectivity later + vtkPts.SetData(nps.numpy_to_vtk(np.unique(corner_vertices, axis=0), deep=True)) + + # create a locator to assist with duplicate points + locator = vtk.vtkPointLocator() + locator.SetDataSet(vtk_grid) + locator.AutomaticOn() # autmoatically adds points to locator + locator.InitPointInsertion(vtkPts, vtkPts.GetBounds()) + locator.BuildLocator() + + # this function is used to add new points to the unstructured + # grid. It will return an existing point ID if the point is alread present + def _insert_point(pnt): + result = locator.IsInsertedPoint(pnt) + if result == -1: + point_id = vtkPts.InsertNextPoint(pnt) + locator.InsertPoint(point_id, pnt) + return point_id + else: + return result + + ### Add all points to the unstructured grid, maintaining a flat list of IDs as we go ### + + # flat array storind point IDs for a given vertex + # in the grid + point_ids = [] + + # add element corner vertices to array + for pnt in corner_vertices: + point_ids.append(_insert_point(pnt)) + + # get edge midpoints and add them to the + # list of point IDs + midpoint_vertices = self.midpoint_vertices + for edge_grid in midpoint_vertices: + for pnt in edge_grid.T.reshape(-1, 3): + point_ids.append(_insert_point(pnt)) + + # determine how many elements in each dimension + # and how many points in each grid + n_elem = np.asarray(self.dimension) + n_pnts = n_elem + 1 + + # create hexes and set points for corner + # vertices + for i, j, k in self.indices: + # handle indices indexed from one + i -= 1 + j -= 1 + k -= 1 + + # create a new vtk hex + hex = vtk.vtkQuadraticHexahedron() + + # set connectivity the hex corners + for n, (di, dj, dk) in enumerate(_HEX_VERTEX_CONN): + # compute flat index into the point ID list based on i, j, k + # of the vertex + flat_idx = np.ravel_multi_index((i+di, j+dj, k+dk), n_pnts, order='F') + # set corner vertices + hex.GetPointIds().SetId(n, point_ids[flat_idx]) + + # set connectivity of the hex midpoints + n_midpoint_vertices = [v.size // 3 for v in midpoint_vertices] + for n, (dim, (di, dj, dk)) in enumerate(_HEX_MIDPOINT_CONN): + # initial offset for corner vertices and midpoint dimension + flat_idx = corner_vertices.shape[0] + sum(n_midpoint_vertices[:dim]) + # generate a flat index into the table of point IDs + midpoint_shape = midpoint_vertices[dim].shape[1:] + flat_idx += np.ravel_multi_index((i+di, j+dj, k+dk), + midpoint_shape, + order='F') + # set hex midpoint connectivity + hex.GetPointIds().SetId(_N_HEX_VERTICES + n, point_ids[flat_idx]) + + # add the hex to the grid + vtk_grid.InsertNextCell(hex.GetCellType(), hex.GetPointIds()) return vtk_grid + def _check_vtk_datasets(self, datasets): + """Perform some basic checks that the datasets are valid for this mesh + + Parameters + ---------- + datasets : dict + Dictionary whose keys are the data labels + and values are the data sets. + + """ + for label, dataset in datasets.items(): + errmsg = ( + f"The size of the dataset '{label}' ({dataset.size}) should be" + f" equal to the number of mesh cells ({self.num_mesh_cells})" + ) + if isinstance(dataset, np.ndarray): + if not dataset.size == self.num_mesh_cells: + raise ValueError(errmsg) + else: + if len(dataset) == self.num_mesh_cells: + raise ValueError(errmsg) + cv.check_type('data label', label, str) + class RegularMesh(StructuredMesh): """A regular Cartesian mesh in one, two, or three dimensions @@ -363,6 +555,12 @@ def width(self): dims = self._dimension return [(u - l) / d for u, l, d in zip(us, ls, dims)] + @property + def cartesian_vertices(self): + """Returns vertices in cartesian coordiantes. Identical to ``vertices`` for RegularMesh and RectilinearMesh + """ + return self.vertices + @property def volumes(self): """Return Volumes for every mesh cell @@ -763,42 +961,6 @@ def build_cells(self, bc=None): return root_cell, cells - def write_data_to_vtk(self, filename, datasets, volume_normalization=True): - """Creates a VTK object of the mesh - - Parameters - ---------- - filename : str or pathlib.Path - Name of the VTK file to write. - datasets : dict - Dictionary whose keys are the data labels - and values are the data sets. - volume_normalization : bool, optional - Whether or not to normalize the data by - the volume of the mesh elements. - Defaults to True. - - Returns - ------- - vtk.vtkStructuredGrid - the VTK object - """ - - ll, ur = self.lower_left, self.upper_right - x_vals = np.linspace(ll[0], ur[0], num=self.dimension[0] + 1) - y_vals = np.linspace(ll[1], ur[1], num=self.dimension[1] + 1) - z_vals = np.linspace(ll[2], ur[2], num=self.dimension[2] + 1) - - # create points - pts_cartesian = np.array([[x, y, z] for z in z_vals for y in y_vals for x in x_vals]) - - return super().write_data_to_vtk( - points=pts_cartesian, - filename=filename, - datasets=datasets, - volume_normalization=volume_normalization - ) - def Mesh(*args, **kwargs): warnings.warn("Mesh has been renamed RegularMesh. Future versions of " "OpenMC will not accept the name Mesh.") @@ -870,6 +1032,12 @@ def z_grid(self): def _grids(self): return (self.x_grid, self.y_grid, self.z_grid) + @property + def cartesian_vertices(self): + """Returns vertices in cartesian coordiantes. Identical to ``vertices`` for RegularMesh and RectilinearMesh + """ + return self.vertices + @property def volumes(self): """Return Volumes for every mesh cell @@ -997,36 +1165,6 @@ def to_xml_element(self): return element - def write_data_to_vtk(self, filename, datasets, volume_normalization=True): - """Creates a VTK object of the mesh - - Parameters - ---------- - filename : str or pathlib.Path - Name of the VTK file to write. - datasets : dict - Dictionary whose keys are the data labels - and values are the data sets. - volume_normalization : bool, optional - Whether or not to normalize the data by - the volume of the mesh elements. - Defaults to True. - - Returns - ------- - vtk.vtkStructuredGrid - the VTK object - """ - # create points - pts_cartesian = self.vertices.T.reshape(-1, 3) - - return super().write_data_to_vtk( - points=pts_cartesian, - filename=filename, - datasets=datasets, - volume_normalization=volume_normalization - ) - class CylindricalMesh(StructuredMesh): """A 3D cylindrical mesh @@ -1310,41 +1448,22 @@ def volumes(self): return np.multiply.outer(np.outer(V_r, V_p), V_z) - def write_data_to_vtk(self, filename, datasets, volume_normalization=True): - """Creates a VTK object of the mesh - - Parameters - ---------- - filename : str or pathlib.Path - Name of the VTK file to write. - datasets : dict - Dictionary whose keys are the data labels - and values are the data sets. - volume_normalization : bool, optional - Whether or not to normalize the data by - the volume of the mesh elements. - Defaults to True. + @property + def cartesian_vertices(self): + return self._convert_to_cartesian(self.vertices, self.origin) - Returns - ------- - vtk.vtkStructuredGrid - the VTK object + @staticmethod + def _convert_to_cartesian(arr, origin): + """Converts an array with xyz values in the first dimension (shape (3, ...)) + to Cartesian coordinates. """ - # create points - pts_cylindrical = self.vertices.T.reshape(-1, 3) - pts_cartesian = np.copy(pts_cylindrical) - - r, phi = pts_cylindrical[:, 0], pts_cylindrical[:, 1] - pts_cartesian[:, 0] = r * np.cos(phi) + self.origin[0] - pts_cartesian[:, 1] = r * np.sin(phi) + self.origin[1] - pts_cartesian[:, 2] += self.origin[2] - - return super().write_data_to_vtk( - points=pts_cartesian, - filename=filename, - datasets=datasets, - volume_normalization=volume_normalization - ) + x = arr[0, ...] * np.cos(arr[1, ...]) + origin[0] + y = arr[0, ...] * np.sin(arr[1, ...]) + origin[1] + arr[0, ...] = x + arr[1, ...] = y + arr[2, ...] += origin[2] + return arr + class SphericalMesh(StructuredMesh): """A 3D spherical mesh @@ -1532,7 +1651,6 @@ def from_xml_element(cls, elem): Spherical mesh object """ - mesh_id = int(get_text(elem, 'id')) mesh = cls(mesh_id) mesh.r_grid = [float(x) for x in get_text(elem, "r_grid").split()] @@ -1559,42 +1677,23 @@ def volumes(self): return np.multiply.outer(np.outer(V_r, V_t), V_p) - def write_data_to_vtk(self, filename, datasets, volume_normalization=True): - """Creates a VTK object of the mesh - - Parameters - ---------- - filename : str or pathlib.Path - Name of the VTK file to write. - datasets : dict - Dictionary whose keys are the data labels - and values are the data sets. - volume_normalization : bool, optional - Whether or not to normalize the data by - the volume of the mesh elements. - Defaults to True. + @property + def cartesian_vertices(self): + return self._convert_to_cartesian(self.vertices, self.origin) - Returns - ------- - vtk.vtkStructuredGrid - the VTK object + @staticmethod + def _convert_to_cartesian(arr, origin): + """Converts an array with xyz values in the first dimension (shape (3, ...)) + to Cartesian coordinates. """ - # create points - pts_spherical = self.vertices.T.reshape(-1, 3) - pts_cartesian = np.copy(pts_spherical) - - r, theta, phi = pts_spherical[:, 0], pts_spherical[:, 1], pts_spherical[:, 2] - - pts_cartesian[:, 0] = r * np.sin(theta) * np.cos(phi) + self.origin[0] - pts_cartesian[:, 1] = r * np.sin(theta) * np.sin(phi) + self.origin[1] - pts_cartesian[:, 2] = r * np.cos(theta) + self.origin[2] - - return super().write_data_to_vtk( - points=pts_cartesian, - filename=filename, - datasets=datasets, - volume_normalization=volume_normalization - ) + r_xy = arr[0, ...] * np.sin(arr[1, ...]) + x = r_xy * np.cos(arr[2, ...]) + y = r_xy * np.sin(arr[2, ...]) + z = arr[0, ...] * np.cos(arr[1, ...]) + arr[0, ...] = x + origin[0] + arr[1, ...] = y + origin[1] + arr[2, ...] = z + origin[2] + return arr class UnstructuredMesh(MeshBase): @@ -2005,3 +2104,34 @@ def _read_meshes(elem): out[mesh.id] = mesh return out + + +# hexahedron element connectivity +# lower-k connectivity offsets +_HEX_VERTEX_CONN = ((0, 0, 0), + (1, 0, 0), + (1, 1, 0), + (0, 1, 0)) +# upper-k connectivity offsets +_HEX_VERTEX_CONN += ((0, 0, 1), + (1, 0, 1), + (1, 1, 1), + (0, 1, 1)) + +_N_HEX_VERTICES = 8 + +# lower-k connectivity offsets +_HEX_MIDPOINT_CONN = ((0, (0, 0, 0)), + (1, (1, 0, 0)), + (0, (0, 1, 0)), + (1, (0, 0, 0))) +# upper-k connectivity offsets +_HEX_MIDPOINT_CONN += ((0, (0, 0, 1)), + (1, (1, 0, 1)), + (0, (0, 1, 1)), + (1, (0, 0, 1))) +# mid-plane k connectivity +_HEX_MIDPOINT_CONN += ((2, (0, 0, 0)), + (2, (1, 0, 0)), + (2, (1, 1, 0)), + (2, (0, 1, 0))) diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk new file mode 100644 index 00000000000..801a02b3ea4 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cyl-data-actual.vtk @@ -0,0 +1,41 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 4 4 +POINTS 80 double +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -10 +9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 +7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 +8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 +8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 +10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 +8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 +8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 +9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 +7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 10 10 -8 +9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 +7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 +8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 +CELL_DATA 36 +FIELD FieldData 1 +ascending_data 1 36 double +0 100 200 300 400 500 600 700 800 +900 1000 1100 1200 1300 1400 1500 1600 1700 +1800 1900 2000 2100 2200 2300 2400 2500 2600 +2700 2800 2900 3000 3100 3200 3300 3400 3500 + diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk new file mode 100644 index 00000000000..332d37db076 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cyl-data-curvilinear.vtk @@ -0,0 +1,329 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 323 double +-4.0450849719 -2.9389262615 0 -4.0450849719 -2.9389262615 0.66666666667 -4.0450849719 -2.9389262615 1.3333333333 +-4.0450849719 -2.9389262615 2 -4.0450849719 2.9389262615 0 -4.0450849719 2.9389262615 0.66666666667 +-4.0450849719 2.9389262615 1.3333333333 -4.0450849719 2.9389262615 2 -3.0338137289 -2.2041946961 0 +-3.0338137289 -2.2041946961 0.66666666667 -3.0338137289 -2.2041946961 1.3333333333 -3.0338137289 -2.2041946961 2 +-3.0338137289 2.2041946961 0 -3.0338137289 2.2041946961 0.66666666667 -3.0338137289 2.2041946961 1.3333333333 +-3.0338137289 2.2041946961 2 -2.0225424859 -1.4694631307 0 -2.0225424859 -1.4694631307 0.66666666667 +-2.0225424859 -1.4694631307 1.3333333333 -2.0225424859 -1.4694631307 2 -2.0225424859 1.4694631307 0 +-2.0225424859 1.4694631307 0.66666666667 -2.0225424859 1.4694631307 1.3333333333 -2.0225424859 1.4694631307 2 +-1.011271243 -0.73473156537 0 -1.011271243 -0.73473156537 0.66666666667 -1.011271243 -0.73473156537 1.3333333333 +-1.011271243 -0.73473156537 2 -1.011271243 0.73473156537 0 -1.011271243 0.73473156537 0.66666666667 +-1.011271243 0.73473156537 1.3333333333 -1.011271243 0.73473156537 2 0 0 0 +0 0 0.66666666667 0 0 1.3333333333 0 0 2 +0.38627124297 -1.1888206454 0 0.38627124297 -1.1888206454 0.66666666667 0.38627124297 -1.1888206454 1.3333333333 +0.38627124297 -1.1888206454 2 0.38627124297 1.1888206454 0 0.38627124297 1.1888206454 0.66666666667 +0.38627124297 1.1888206454 1.3333333333 0.38627124297 1.1888206454 2 0.77254248594 -2.3776412907 0 +0.77254248594 -2.3776412907 0.66666666667 0.77254248594 -2.3776412907 1.3333333333 0.77254248594 -2.3776412907 2 +0.77254248594 2.3776412907 0 0.77254248594 2.3776412907 0.66666666667 0.77254248594 2.3776412907 1.3333333333 +0.77254248594 2.3776412907 2 1.1588137289 -3.5664619361 0 1.1588137289 -3.5664619361 0.66666666667 +1.1588137289 -3.5664619361 1.3333333333 1.1588137289 -3.5664619361 2 1.1588137289 3.5664619361 0 +1.1588137289 3.5664619361 0.66666666667 1.1588137289 3.5664619361 1.3333333333 1.1588137289 3.5664619361 2 +1.25 -3.0616169979e-16 0 1.25 -3.0616169979e-16 0.66666666667 1.25 -3.0616169979e-16 1.3333333333 +1.25 -3.0616169979e-16 2 1.25 0 0 1.25 0 0.66666666667 +1.25 0 1.3333333333 1.25 0 2 1.5450849719 -4.7552825815 0 +1.5450849719 -4.7552825815 0.66666666667 1.5450849719 -4.7552825815 1.3333333333 1.5450849719 -4.7552825815 2 +1.5450849719 4.7552825815 0 1.5450849719 4.7552825815 0.66666666667 1.5450849719 4.7552825815 1.3333333333 +1.5450849719 4.7552825815 2 2.5 -6.1232339957e-16 0 2.5 -6.1232339957e-16 0.66666666667 +2.5 -6.1232339957e-16 1.3333333333 2.5 -6.1232339957e-16 2 2.5 0 0 +2.5 0 0.66666666667 2.5 0 1.3333333333 2.5 0 2 +3.75 -9.1848509936e-16 0 3.75 -9.1848509936e-16 0.66666666667 3.75 -9.1848509936e-16 1.3333333333 +3.75 -9.1848509936e-16 2 3.75 0 0 3.75 0 0.66666666667 +3.75 0 1.3333333333 3.75 0 2 5 -1.2246467991e-15 0 +5 -1.2246467991e-15 0.66666666667 5 -1.2246467991e-15 1.3333333333 5 -1.2246467991e-15 2 +5 0 0 5 0 0.66666666667 5 0 1.3333333333 +5 0 2 0.625 0 0 1.875 0 0 +3.125 0 0 4.375 0 0 0.19313562148 0.59441032268 0 +0.57940686445 1.7832309681 0 0.96567810742 2.9720516134 0 1.3519493504 4.1608722588 0 +-0.50563562148 0.36736578268 0 -1.5169068645 1.102097348 0 -2.5281781074 1.8368289134 0 +-3.5394493504 2.5715604788 0 -0.50563562148 -0.36736578268 0 -1.5169068645 -1.102097348 0 +-2.5281781074 -1.8368289134 0 -3.5394493504 -2.5715604788 0 0.19313562148 -0.59441032268 0 +0.57940686445 -1.7832309681 0 0.96567810742 -2.9720516134 0 1.3519493504 -4.1608722588 0 +0.625 0 0.66666666667 1.875 0 0.66666666667 3.125 0 0.66666666667 +4.375 0 0.66666666667 0.19313562148 0.59441032268 0.66666666667 0.57940686445 1.7832309681 0.66666666667 +0.96567810742 2.9720516134 0.66666666667 1.3519493504 4.1608722588 0.66666666667 -0.50563562148 0.36736578268 0.66666666667 +-1.5169068645 1.102097348 0.66666666667 -2.5281781074 1.8368289134 0.66666666667 -3.5394493504 2.5715604788 0.66666666667 +-0.50563562148 -0.36736578268 0.66666666667 -1.5169068645 -1.102097348 0.66666666667 -2.5281781074 -1.8368289134 0.66666666667 +-3.5394493504 -2.5715604788 0.66666666667 0.19313562148 -0.59441032268 0.66666666667 0.57940686445 -1.7832309681 0.66666666667 +0.96567810742 -2.9720516134 0.66666666667 1.3519493504 -4.1608722588 0.66666666667 0.625 0 1.3333333333 +1.875 0 1.3333333333 3.125 0 1.3333333333 4.375 0 1.3333333333 +0.19313562148 0.59441032268 1.3333333333 0.57940686445 1.7832309681 1.3333333333 0.96567810742 2.9720516134 1.3333333333 +1.3519493504 4.1608722588 1.3333333333 -0.50563562148 0.36736578268 1.3333333333 -1.5169068645 1.102097348 1.3333333333 +-2.5281781074 1.8368289134 1.3333333333 -3.5394493504 2.5715604788 1.3333333333 -0.50563562148 -0.36736578268 1.3333333333 +-1.5169068645 -1.102097348 1.3333333333 -2.5281781074 -1.8368289134 1.3333333333 -3.5394493504 -2.5715604788 1.3333333333 +0.19313562148 -0.59441032268 1.3333333333 0.57940686445 -1.7832309681 1.3333333333 0.96567810742 -2.9720516134 1.3333333333 +1.3519493504 -4.1608722588 1.3333333333 0.625 0 2 1.875 0 2 +3.125 0 2 4.375 0 2 0.19313562148 0.59441032268 2 +0.57940686445 1.7832309681 2 0.96567810742 2.9720516134 2 1.3519493504 4.1608722588 2 +-0.50563562148 0.36736578268 2 -1.5169068645 1.102097348 2 -2.5281781074 1.8368289134 2 +-3.5394493504 2.5715604788 2 -0.50563562148 -0.36736578268 2 -1.5169068645 -1.102097348 2 +-2.5281781074 -1.8368289134 2 -3.5394493504 -2.5715604788 2 0.19313562148 -0.59441032268 2 +0.57940686445 -1.7832309681 2 0.96567810742 -2.9720516134 2 1.3519493504 -4.1608722588 2 +1.011271243 0.73473156537 0 2.0225424859 1.4694631307 0 3.0338137289 2.2041946961 0 +4.0450849719 2.9389262615 0 -0.38627124297 1.1888206454 0 -0.77254248594 2.3776412907 0 +-1.1588137289 3.5664619361 0 -1.5450849719 4.7552825815 0 -1.25 1.5308084989e-16 0 +-2.5 3.0616169979e-16 0 -3.75 4.5924254968e-16 0 -5 6.1232339957e-16 0 +-0.38627124297 -1.1888206454 0 -0.77254248594 -2.3776412907 0 -1.1588137289 -3.5664619361 0 +-1.5450849719 -4.7552825815 0 1.011271243 -0.73473156537 0 2.0225424859 -1.4694631307 0 +3.0338137289 -2.2041946961 0 4.0450849719 -2.9389262615 0 1.011271243 0.73473156537 0.66666666667 +2.0225424859 1.4694631307 0.66666666667 3.0338137289 2.2041946961 0.66666666667 4.0450849719 2.9389262615 0.66666666667 +-0.38627124297 1.1888206454 0.66666666667 -0.77254248594 2.3776412907 0.66666666667 -1.1588137289 3.5664619361 0.66666666667 +-1.5450849719 4.7552825815 0.66666666667 -1.25 1.5308084989e-16 0.66666666667 -2.5 3.0616169979e-16 0.66666666667 +-3.75 4.5924254968e-16 0.66666666667 -5 6.1232339957e-16 0.66666666667 -0.38627124297 -1.1888206454 0.66666666667 +-0.77254248594 -2.3776412907 0.66666666667 -1.1588137289 -3.5664619361 0.66666666667 -1.5450849719 -4.7552825815 0.66666666667 +1.011271243 -0.73473156537 0.66666666667 2.0225424859 -1.4694631307 0.66666666667 3.0338137289 -2.2041946961 0.66666666667 +4.0450849719 -2.9389262615 0.66666666667 1.011271243 0.73473156537 1.3333333333 2.0225424859 1.4694631307 1.3333333333 +3.0338137289 2.2041946961 1.3333333333 4.0450849719 2.9389262615 1.3333333333 -0.38627124297 1.1888206454 1.3333333333 +-0.77254248594 2.3776412907 1.3333333333 -1.1588137289 3.5664619361 1.3333333333 -1.5450849719 4.7552825815 1.3333333333 +-1.25 1.5308084989e-16 1.3333333333 -2.5 3.0616169979e-16 1.3333333333 -3.75 4.5924254968e-16 1.3333333333 +-5 6.1232339957e-16 1.3333333333 -0.38627124297 -1.1888206454 1.3333333333 -0.77254248594 -2.3776412907 1.3333333333 +-1.1588137289 -3.5664619361 1.3333333333 -1.5450849719 -4.7552825815 1.3333333333 1.011271243 -0.73473156537 1.3333333333 +2.0225424859 -1.4694631307 1.3333333333 3.0338137289 -2.2041946961 1.3333333333 4.0450849719 -2.9389262615 1.3333333333 +1.011271243 0.73473156537 2 2.0225424859 1.4694631307 2 3.0338137289 2.2041946961 2 +4.0450849719 2.9389262615 2 -0.38627124297 1.1888206454 2 -0.77254248594 2.3776412907 2 +-1.1588137289 3.5664619361 2 -1.5450849719 4.7552825815 2 -1.25 1.5308084989e-16 2 +-2.5 3.0616169979e-16 2 -3.75 4.5924254968e-16 2 -5 6.1232339957e-16 2 +-0.38627124297 -1.1888206454 2 -0.77254248594 -2.3776412907 2 -1.1588137289 -3.5664619361 2 +-1.5450849719 -4.7552825815 2 1.011271243 -0.73473156537 2 2.0225424859 -1.4694631307 2 +3.0338137289 -2.2041946961 2 4.0450849719 -2.9389262615 2 0 0 0.33333333333 +1.25 0 0.33333333333 2.5 0 0.33333333333 3.75 0 0.33333333333 +5 0 0.33333333333 0.38627124297 1.1888206454 0.33333333333 0.77254248594 2.3776412907 0.33333333333 +1.1588137289 3.5664619361 0.33333333333 1.5450849719 4.7552825815 0.33333333333 -1.011271243 0.73473156537 0.33333333333 +-2.0225424859 1.4694631307 0.33333333333 -3.0338137289 2.2041946961 0.33333333333 -4.0450849719 2.9389262615 0.33333333333 +-1.011271243 -0.73473156537 0.33333333333 -2.0225424859 -1.4694631307 0.33333333333 -3.0338137289 -2.2041946961 0.33333333333 +-4.0450849719 -2.9389262615 0.33333333333 0.38627124297 -1.1888206454 0.33333333333 0.77254248594 -2.3776412907 0.33333333333 +1.1588137289 -3.5664619361 0.33333333333 1.5450849719 -4.7552825815 0.33333333333 0 0 1 +1.25 0 1 2.5 0 1 3.75 0 1 +5 0 1 0.38627124297 1.1888206454 1 0.77254248594 2.3776412907 1 +1.1588137289 3.5664619361 1 1.5450849719 4.7552825815 1 -1.011271243 0.73473156537 1 +-2.0225424859 1.4694631307 1 -3.0338137289 2.2041946961 1 -4.0450849719 2.9389262615 1 +-1.011271243 -0.73473156537 1 -2.0225424859 -1.4694631307 1 -3.0338137289 -2.2041946961 1 +-4.0450849719 -2.9389262615 1 0.38627124297 -1.1888206454 1 0.77254248594 -2.3776412907 1 +1.1588137289 -3.5664619361 1 1.5450849719 -4.7552825815 1 0 0 1.6666666667 +1.25 0 1.6666666667 2.5 0 1.6666666667 3.75 0 1.6666666667 +5 0 1.6666666667 0.38627124297 1.1888206454 1.6666666667 0.77254248594 2.3776412907 1.6666666667 +1.1588137289 3.5664619361 1.6666666667 1.5450849719 4.7552825815 1.6666666667 -1.011271243 0.73473156537 1.6666666667 +-2.0225424859 1.4694631307 1.6666666667 -3.0338137289 2.2041946961 1.6666666667 -4.0450849719 2.9389262615 1.6666666667 +-1.011271243 -0.73473156537 1.6666666667 -2.0225424859 -1.4694631307 1.6666666667 -3.0338137289 -2.2041946961 1.6666666667 +-4.0450849719 -2.9389262615 1.6666666667 0.38627124297 -1.1888206454 1.6666666667 0.77254248594 -2.3776412907 1.6666666667 +1.1588137289 -3.5664619361 1.6666666667 1.5450849719 -4.7552825815 1.6666666667 +CELLS 61 1200 +OFFSETS vtktypeint64 +0 20 40 60 80 100 120 140 160 +180 200 220 240 260 280 300 320 340 +360 380 400 420 440 460 480 500 520 +540 560 580 600 620 640 660 680 700 +720 740 760 780 800 820 840 860 880 +900 920 940 960 980 1000 1020 1040 1060 +1080 1100 1120 1140 1160 1180 1200 +CONNECTIVITY vtktypeint64 +32 60 40 32 33 61 41 33 100 +180 104 32 120 200 124 33 260 261 +265 260 60 76 48 40 61 77 49 +41 101 181 105 180 121 201 125 200 +261 262 266 265 76 84 56 48 77 +85 57 49 102 182 106 181 122 202 +126 201 262 263 267 266 84 92 72 +56 85 93 73 57 103 183 107 182 +123 203 127 202 263 264 268 267 32 +40 28 32 33 41 29 33 104 184 +108 32 124 204 128 33 260 265 269 +260 40 48 20 28 41 49 21 29 +105 185 109 184 125 205 129 204 265 +266 270 269 48 56 12 20 49 57 +13 21 106 186 110 185 126 206 130 +205 266 267 271 270 56 72 4 12 +57 73 5 13 107 187 111 186 127 +207 131 206 267 268 272 271 32 28 +24 32 33 29 25 33 108 188 112 +32 128 208 132 33 260 269 273 260 +28 20 16 24 29 21 17 25 109 +189 113 188 129 209 133 208 269 270 +274 273 20 12 8 16 21 13 9 +17 110 190 114 189 130 210 134 209 +270 271 275 274 12 4 0 8 13 +5 1 9 111 191 115 190 131 211 +135 210 271 272 276 275 32 24 36 +32 33 25 37 33 112 192 116 32 +132 212 136 33 260 273 277 260 24 +16 44 36 25 17 45 37 113 193 +117 192 133 213 137 212 273 274 278 +277 16 8 52 44 17 9 53 45 +114 194 118 193 134 214 138 213 274 +275 279 278 8 0 68 52 9 1 +69 53 115 195 119 194 135 215 139 +214 275 276 280 279 32 36 60 32 +33 37 61 33 116 196 100 32 136 +216 120 33 260 277 261 260 36 44 +76 60 37 45 77 61 117 197 101 +196 137 217 121 216 277 278 262 261 +44 52 84 76 45 53 85 77 118 +198 102 197 138 218 122 217 278 279 +263 262 52 68 92 84 53 69 93 +85 119 199 103 198 139 219 123 218 +279 280 264 263 33 61 41 33 34 +62 42 34 120 200 124 33 140 220 +144 34 281 282 286 281 61 77 49 +41 62 78 50 42 121 201 125 200 +141 221 145 220 282 283 287 286 77 +85 57 49 78 86 58 50 122 202 +126 201 142 222 146 221 283 284 288 +287 85 93 73 57 86 94 74 58 +123 203 127 202 143 223 147 222 284 +285 289 288 33 41 29 33 34 42 +30 34 124 204 128 33 144 224 148 +34 281 286 290 281 41 49 21 29 +42 50 22 30 125 205 129 204 145 +225 149 224 286 287 291 290 49 57 +13 21 50 58 14 22 126 206 130 +205 146 226 150 225 287 288 292 291 +57 73 5 13 58 74 6 14 127 +207 131 206 147 227 151 226 288 289 +293 292 33 29 25 33 34 30 26 +34 128 208 132 33 148 228 152 34 +281 290 294 281 29 21 17 25 30 +22 18 26 129 209 133 208 149 229 +153 228 290 291 295 294 21 13 9 +17 22 14 10 18 130 210 134 209 +150 230 154 229 291 292 296 295 13 +5 1 9 14 6 2 10 131 211 +135 210 151 231 155 230 292 293 297 +296 33 25 37 33 34 26 38 34 +132 212 136 33 152 232 156 34 281 +294 298 281 25 17 45 37 26 18 +46 38 133 213 137 212 153 233 157 +232 294 295 299 298 17 9 53 45 +18 10 54 46 134 214 138 213 154 +234 158 233 295 296 300 299 9 1 +69 53 10 2 70 54 135 215 139 +214 155 235 159 234 296 297 301 300 +33 37 61 33 34 38 62 34 136 +216 120 33 156 236 140 34 281 298 +282 281 37 45 77 61 38 46 78 +62 137 217 121 216 157 237 141 236 +298 299 283 282 45 53 85 77 46 +54 86 78 138 218 122 217 158 238 +142 237 299 300 284 283 53 69 93 +85 54 70 94 86 139 219 123 218 +159 239 143 238 300 301 285 284 34 +62 42 34 35 63 43 35 140 220 +144 34 160 240 164 35 302 303 307 +302 62 78 50 42 63 79 51 43 +141 221 145 220 161 241 165 240 303 +304 308 307 78 86 58 50 79 87 +59 51 142 222 146 221 162 242 166 +241 304 305 309 308 86 94 74 58 +87 95 75 59 143 223 147 222 163 +243 167 242 305 306 310 309 34 42 +30 34 35 43 31 35 144 224 148 +34 164 244 168 35 302 307 311 302 +42 50 22 30 43 51 23 31 145 +225 149 224 165 245 169 244 307 308 +312 311 50 58 14 22 51 59 15 +23 146 226 150 225 166 246 170 245 +308 309 313 312 58 74 6 14 59 +75 7 15 147 227 151 226 167 247 +171 246 309 310 314 313 34 30 26 +34 35 31 27 35 148 228 152 34 +168 248 172 35 302 311 315 302 30 +22 18 26 31 23 19 27 149 229 +153 228 169 249 173 248 311 312 316 +315 22 14 10 18 23 15 11 19 +150 230 154 229 170 250 174 249 312 +313 317 316 14 6 2 10 15 7 +3 11 151 231 155 230 171 251 175 +250 313 314 318 317 34 26 38 34 +35 27 39 35 152 232 156 34 172 +252 176 35 302 315 319 302 26 18 +46 38 27 19 47 39 153 233 157 +232 173 253 177 252 315 316 320 319 +18 10 54 46 19 11 55 47 154 +234 158 233 174 254 178 253 316 317 +321 320 10 2 70 54 11 3 71 +55 155 235 159 234 175 255 179 254 +317 318 322 321 34 38 62 34 35 +39 63 35 156 236 140 34 176 256 +160 35 302 319 303 302 38 46 78 +62 39 47 79 63 157 237 141 236 +177 257 161 256 319 320 304 303 46 +54 86 78 47 55 87 79 158 238 +142 237 178 258 162 257 320 321 305 +304 54 70 94 86 55 71 95 87 +159 239 143 238 179 259 163 258 321 +322 306 305 +CELL_TYPES 60 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 + +CELL_DATA 60 +FIELD FieldData 1 +ascending_data 1 60 double +0 100 200 300 400 500 600 700 800 +900 1000 1100 1200 1300 1400 1500 1600 1700 +1800 1900 2000 2100 2200 2300 2400 2500 2600 +2700 2800 2900 3000 3100 3200 3300 3400 3500 +3600 3700 3800 3900 4000 4100 4200 4300 4400 +4500 4600 4700 4800 4900 5000 5100 5200 5300 +5400 5500 5600 5700 5800 5900 diff --git a/tests/unit_tests/mesh_to_vtk/cyl-data.vtk b/tests/unit_tests/mesh_to_vtk/cyl-data.vtk new file mode 100644 index 00000000000..801a02b3ea4 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cyl-data.vtk @@ -0,0 +1,41 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 4 4 +POINTS 80 double +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -10 +9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 +7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 +8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 +8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 +10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 +8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 +8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 +9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 +7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 10 10 -8 +9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 +7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 +8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 +CELL_DATA 36 +FIELD FieldData 1 +ascending_data 1 36 double +0 100 200 300 400 500 600 700 800 +900 1000 1100 1200 1300 1400 1500 1600 1700 +1800 1900 2000 2100 2200 2300 2400 2500 2600 +2700 2800 2900 3000 3100 3200 3300 3400 3500 + diff --git a/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk new file mode 100644 index 00000000000..24bdd7f14ed --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cylindrical-curvilinear.vtk @@ -0,0 +1,198 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 195 double +7.5 5.6698729811 -10 7.5 5.6698729811 -9.3333333333 7.5 5.6698729811 -8.6666666667 +7.5 5.6698729811 -8 7.5 14.330127019 -10 7.5 14.330127019 -9.3333333333 +7.5 14.330127019 -8.6666666667 7.5 14.330127019 -8 8.125 6.7524047358 -10 +8.125 6.7524047358 -9.3333333333 8.125 6.7524047358 -8.6666666667 8.125 6.7524047358 -8 +8.125 13.247595264 -10 8.125 13.247595264 -9.3333333333 8.125 13.247595264 -8.6666666667 +8.125 13.247595264 -8 8.75 7.8349364905 -10 8.75 7.8349364905 -9.3333333333 +8.75 7.8349364905 -8.6666666667 8.75 7.8349364905 -8 8.75 12.165063509 -10 +8.75 12.165063509 -9.3333333333 8.75 12.165063509 -8.6666666667 8.75 12.165063509 -8 +9.375 8.9174682453 -10 9.375 8.9174682453 -9.3333333333 9.375 8.9174682453 -8.6666666667 +9.375 8.9174682453 -8 9.375 11.082531755 -10 9.375 11.082531755 -9.3333333333 +9.375 11.082531755 -8.6666666667 9.375 11.082531755 -8 10 10 -10 +10 10 -9.3333333333 10 10 -8.6666666667 10 10 -8 +11.25 10 -10 11.25 10 -9.3333333333 11.25 10 -8.6666666667 +11.25 10 -8 12.5 10 -10 12.5 10 -9.3333333333 +12.5 10 -8.6666666667 12.5 10 -8 13.75 10 -10 +13.75 10 -9.3333333333 13.75 10 -8.6666666667 13.75 10 -8 +13.75 10 -10 13.75 10 -9.3333333333 13.75 10 -8.6666666667 +13.75 10 -8 15 10 -10 15 10 -9.3333333333 +15 10 -8.6666666667 15 10 -8 15 10 -10 +15 10 -9.3333333333 15 10 -8.6666666667 15 10 -8 +10.625 10 -10 11.875 10 -10 13.125 10 -10 +14.375 10 -10 9.6875 10.541265877 -10 9.0625 11.623797632 -10 +8.4375 12.706329387 -10 7.8125 13.788861142 -10 9.6875 9.4587341226 -10 +9.0625 8.3762023679 -10 8.4375 7.2936706132 -10 7.8125 6.2111388584 -10 +10.625 10 -9.3333333333 11.875 10 -9.3333333333 13.125 10 -9.3333333333 +14.375 10 -9.3333333333 9.6875 10.541265877 -9.3333333333 9.0625 11.623797632 -9.3333333333 +8.4375 12.706329387 -9.3333333333 7.8125 13.788861142 -9.3333333333 9.6875 9.4587341226 -9.3333333333 +9.0625 8.3762023679 -9.3333333333 8.4375 7.2936706132 -9.3333333333 7.8125 6.2111388584 -9.3333333333 +10.625 10 -8.6666666667 11.875 10 -8.6666666667 13.125 10 -8.6666666667 +14.375 10 -8.6666666667 9.6875 10.541265877 -8.6666666667 9.0625 11.623797632 -8.6666666667 +8.4375 12.706329387 -8.6666666667 7.8125 13.788861142 -8.6666666667 9.6875 9.4587341226 -8.6666666667 +9.0625 8.3762023679 -8.6666666667 8.4375 7.2936706132 -8.6666666667 7.8125 6.2111388584 -8.6666666667 +10.625 10 -8 11.875 10 -8 13.125 10 -8 +14.375 10 -8 9.6875 10.541265877 -8 9.0625 11.623797632 -8 +8.4375 12.706329387 -8 7.8125 13.788861142 -8 9.6875 9.4587341226 -8 +9.0625 8.3762023679 -8 8.4375 7.2936706132 -8 7.8125 6.2111388584 -8 +10.625 11.082531755 -10 11.25 12.165063509 -10 11.875 13.247595264 -10 +12.5 14.330127019 -10 8.75 10 -10 7.5 10 -10 +6.25 10 -10 5 10 -10 10.625 8.9174682453 -10 +11.25 7.8349364905 -10 11.875 6.7524047358 -10 12.5 5.6698729811 -10 +10.625 11.082531755 -9.3333333333 11.25 12.165063509 -9.3333333333 11.875 13.247595264 -9.3333333333 +12.5 14.330127019 -9.3333333333 8.75 10 -9.3333333333 7.5 10 -9.3333333333 +6.25 10 -9.3333333333 5 10 -9.3333333333 10.625 8.9174682453 -9.3333333333 +11.25 7.8349364905 -9.3333333333 11.875 6.7524047358 -9.3333333333 12.5 5.6698729811 -9.3333333333 +10.625 11.082531755 -8.6666666667 11.25 12.165063509 -8.6666666667 11.875 13.247595264 -8.6666666667 +12.5 14.330127019 -8.6666666667 8.75 10 -8.6666666667 7.5 10 -8.6666666667 +6.25 10 -8.6666666667 5 10 -8.6666666667 10.625 8.9174682453 -8.6666666667 +11.25 7.8349364905 -8.6666666667 11.875 6.7524047358 -8.6666666667 12.5 5.6698729811 -8.6666666667 +10.625 11.082531755 -8 11.25 12.165063509 -8 11.875 13.247595264 -8 +12.5 14.330127019 -8 8.75 10 -8 7.5 10 -8 +6.25 10 -8 5 10 -8 10.625 8.9174682453 -8 +11.25 7.8349364905 -8 11.875 6.7524047358 -8 12.5 5.6698729811 -8 +10 10 -9.6666666667 11.25 10 -9.6666666667 12.5 10 -9.6666666667 +13.75 10 -9.6666666667 15 10 -9.6666666667 9.375 11.082531755 -9.6666666667 +8.75 12.165063509 -9.6666666667 8.125 13.247595264 -9.6666666667 7.5 14.330127019 -9.6666666667 +9.375 8.9174682453 -9.6666666667 8.75 7.8349364905 -9.6666666667 8.125 6.7524047358 -9.6666666667 +7.5 5.6698729811 -9.6666666667 10 10 -9 11.25 10 -9 +12.5 10 -9 13.75 10 -9 15 10 -9 +9.375 11.082531755 -9 8.75 12.165063509 -9 8.125 13.247595264 -9 +7.5 14.330127019 -9 9.375 8.9174682453 -9 8.75 7.8349364905 -9 +8.125 6.7524047358 -9 7.5 5.6698729811 -9 10 10 -8.3333333333 +11.25 10 -8.3333333333 12.5 10 -8.3333333333 13.75 10 -8.3333333333 +15 10 -8.3333333333 9.375 11.082531755 -8.3333333333 8.75 12.165063509 -8.3333333333 +8.125 13.247595264 -8.3333333333 7.5 14.330127019 -8.3333333333 9.375 8.9174682453 -8.3333333333 +8.75 7.8349364905 -8.3333333333 8.125 6.7524047358 -8.3333333333 7.5 5.6698729811 -8.3333333333 + +CELLS 37 720 +OFFSETS vtktypeint64 +0 20 40 60 80 100 120 140 160 +180 200 220 240 260 280 300 320 340 +360 380 400 420 440 460 480 500 520 +540 560 580 600 620 640 660 680 700 +720 +CONNECTIVITY vtktypeint64 +32 36 28 32 33 37 29 33 60 +108 64 32 72 120 76 33 156 157 +161 156 36 40 20 28 37 41 21 +29 61 109 65 108 73 121 77 120 +157 158 162 161 40 44 12 20 41 +45 13 21 62 110 66 109 74 122 +78 121 158 159 163 162 44 52 4 +12 45 53 5 13 63 111 67 110 +75 123 79 122 159 160 164 163 32 +28 24 32 33 29 25 33 64 112 +68 32 76 124 80 33 156 161 165 +156 28 20 16 24 29 21 17 25 +65 113 69 112 77 125 81 124 161 +162 166 165 20 12 8 16 21 13 +9 17 66 114 70 113 78 126 82 +125 162 163 167 166 12 4 0 8 +13 5 1 9 67 115 71 114 79 +127 83 126 163 164 168 167 32 24 +36 32 33 25 37 33 68 116 60 +32 80 128 72 33 156 165 157 156 +24 16 40 36 25 17 41 37 69 +117 61 116 81 129 73 128 165 166 +158 157 16 8 44 40 17 9 45 +41 70 118 62 117 82 130 74 129 +166 167 159 158 8 0 52 44 9 +1 53 45 71 119 63 118 83 131 +75 130 167 168 160 159 33 37 29 +33 34 38 30 34 72 120 76 33 +84 132 88 34 169 170 174 169 37 +41 21 29 38 42 22 30 73 121 +77 120 85 133 89 132 170 171 175 +174 41 45 13 21 42 46 14 22 +74 122 78 121 86 134 90 133 171 +172 176 175 45 53 5 13 46 54 +6 14 75 123 79 122 87 135 91 +134 172 173 177 176 33 29 25 33 +34 30 26 34 76 124 80 33 88 +136 92 34 169 174 178 169 29 21 +17 25 30 22 18 26 77 125 81 +124 89 137 93 136 174 175 179 178 +21 13 9 17 22 14 10 18 78 +126 82 125 90 138 94 137 175 176 +180 179 13 5 1 9 14 6 2 +10 79 127 83 126 91 139 95 138 +176 177 181 180 33 25 37 33 34 +26 38 34 80 128 72 33 92 140 +84 34 169 178 170 169 25 17 41 +37 26 18 42 38 81 129 73 128 +93 141 85 140 178 179 171 170 17 +9 45 41 18 10 46 42 82 130 +74 129 94 142 86 141 179 180 172 +171 9 1 53 45 10 2 54 46 +83 131 75 130 95 143 87 142 180 +181 173 172 34 38 30 34 35 39 +31 35 84 132 88 34 96 144 100 +35 182 183 187 182 38 42 22 30 +39 43 23 31 85 133 89 132 97 +145 101 144 183 184 188 187 42 46 +14 22 43 47 15 23 86 134 90 +133 98 146 102 145 184 185 189 188 +46 54 6 14 47 55 7 15 87 +135 91 134 99 147 103 146 185 186 +190 189 34 30 26 34 35 31 27 +35 88 136 92 34 100 148 104 35 +182 187 191 182 30 22 18 26 31 +23 19 27 89 137 93 136 101 149 +105 148 187 188 192 191 22 14 10 +18 23 15 11 19 90 138 94 137 +102 150 106 149 188 189 193 192 14 +6 2 10 15 7 3 11 91 139 +95 138 103 151 107 150 189 190 194 +193 34 26 38 34 35 27 39 35 +92 140 84 34 104 152 96 35 182 +191 183 182 26 18 42 38 27 19 +43 39 93 141 85 140 105 153 97 +152 191 192 184 183 18 10 46 42 +19 11 47 43 94 142 86 141 106 +154 98 153 192 193 185 184 10 2 +54 46 11 3 55 47 95 143 87 +142 107 155 99 154 193 194 186 185 + +CELL_TYPES 36 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 + diff --git a/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk b/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk new file mode 100644 index 00000000000..33d1ce497a1 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/cylindrical-linear.vtk @@ -0,0 +1,33 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 4 4 +POINTS 80 double +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -10 +9.375 11.082531755 -10 8.75 12.165063509 -10 8.125 13.247595264 -10 +7.5 14.330127019 -10 10 10 -10 9.375 8.9174682453 -10 +8.75 7.8349364905 -10 8.125 6.7524047358 -10 7.5 5.6698729811 -10 +10 10 -10 11.25 10 -10 12.5 10 -10 +13.75 10 -10 15 10 -10 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -9.3333333333 9.375 11.082531755 -9.3333333333 +8.75 12.165063509 -9.3333333333 8.125 13.247595264 -9.3333333333 7.5 14.330127019 -9.3333333333 +10 10 -9.3333333333 9.375 8.9174682453 -9.3333333333 8.75 7.8349364905 -9.3333333333 +8.125 6.7524047358 -9.3333333333 7.5 5.6698729811 -9.3333333333 10 10 -9.3333333333 +11.25 10 -9.3333333333 12.5 10 -9.3333333333 13.75 10 -9.3333333333 +15 10 -9.3333333333 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8.6666666667 9.375 11.082531755 -8.6666666667 8.75 12.165063509 -8.6666666667 +8.125 13.247595264 -8.6666666667 7.5 14.330127019 -8.6666666667 10 10 -8.6666666667 +9.375 8.9174682453 -8.6666666667 8.75 7.8349364905 -8.6666666667 8.125 6.7524047358 -8.6666666667 +7.5 5.6698729811 -8.6666666667 10 10 -8.6666666667 11.25 10 -8.6666666667 +12.5 10 -8.6666666667 13.75 10 -8.6666666667 15 10 -8.6666666667 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 10 10 -8 +9.375 11.082531755 -8 8.75 12.165063509 -8 8.125 13.247595264 -8 +7.5 14.330127019 -8 10 10 -8 9.375 8.9174682453 -8 +8.75 7.8349364905 -8 8.125 6.7524047358 -8 7.5 5.6698729811 -8 +10 10 -8 11.25 10 -8 12.5 10 -8 +13.75 10 -8 15 10 -8 diff --git a/tests/unit_tests/mesh_to_vtk/rectilinear.vtk b/tests/unit_tests/mesh_to_vtk/rectilinear.vtk new file mode 100644 index 00000000000..71826392e82 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/rectilinear.vtk @@ -0,0 +1,340 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 5 10 20 +POINTS 1000 double +0 5 1 2.5 5 1 5 5 1 +7.5 5 1 10 5 1 0 5.8326451979 1 +2.5 5.8326451979 1 5 5.8326451979 1 7.5 5.8326451979 1 +10 5.8326451979 1 0 6.8039500009 1 2.5 6.8039500009 1 +5 6.8039500009 1 7.5 6.8039500009 1 10 6.8039500009 1 +0 7.9370052598 1 2.5 7.9370052598 1 5 7.9370052598 1 +7.5 7.9370052598 1 10 7.9370052598 1 0 9.2587471229 1 +2.5 9.2587471229 1 5 9.2587471229 1 7.5 9.2587471229 1 +10 9.2587471229 1 0 10.800597389 1 2.5 10.800597389 1 +5 10.800597389 1 7.5 10.800597389 1 10 10.800597389 1 +0 12.599210499 1 2.5 12.599210499 1 5 12.599210499 1 +7.5 12.599210499 1 10 12.599210499 1 0 14.697344923 1 +2.5 14.697344923 1 5 14.697344923 1 7.5 14.697344923 1 +10 14.697344923 1 0 17.144879657 1 2.5 17.144879657 1 +5 17.144879657 1 7.5 17.144879657 1 10 17.144879657 1 +0 20 1 2.5 20 1 5 20 1 +7.5 20 1 10 20 1 0 5 6.2105263158 +2.5 5 6.2105263158 5 5 6.2105263158 7.5 5 6.2105263158 +10 5 6.2105263158 0 5.8326451979 6.2105263158 2.5 5.8326451979 6.2105263158 +5 5.8326451979 6.2105263158 7.5 5.8326451979 6.2105263158 10 5.8326451979 6.2105263158 +0 6.8039500009 6.2105263158 2.5 6.8039500009 6.2105263158 5 6.8039500009 6.2105263158 +7.5 6.8039500009 6.2105263158 10 6.8039500009 6.2105263158 0 7.9370052598 6.2105263158 +2.5 7.9370052598 6.2105263158 5 7.9370052598 6.2105263158 7.5 7.9370052598 6.2105263158 +10 7.9370052598 6.2105263158 0 9.2587471229 6.2105263158 2.5 9.2587471229 6.2105263158 +5 9.2587471229 6.2105263158 7.5 9.2587471229 6.2105263158 10 9.2587471229 6.2105263158 +0 10.800597389 6.2105263158 2.5 10.800597389 6.2105263158 5 10.800597389 6.2105263158 +7.5 10.800597389 6.2105263158 10 10.800597389 6.2105263158 0 12.599210499 6.2105263158 +2.5 12.599210499 6.2105263158 5 12.599210499 6.2105263158 7.5 12.599210499 6.2105263158 +10 12.599210499 6.2105263158 0 14.697344923 6.2105263158 2.5 14.697344923 6.2105263158 +5 14.697344923 6.2105263158 7.5 14.697344923 6.2105263158 10 14.697344923 6.2105263158 +0 17.144879657 6.2105263158 2.5 17.144879657 6.2105263158 5 17.144879657 6.2105263158 +7.5 17.144879657 6.2105263158 10 17.144879657 6.2105263158 0 20 6.2105263158 +2.5 20 6.2105263158 5 20 6.2105263158 7.5 20 6.2105263158 +10 20 6.2105263158 0 5 11.421052632 2.5 5 11.421052632 +5 5 11.421052632 7.5 5 11.421052632 10 5 11.421052632 +0 5.8326451979 11.421052632 2.5 5.8326451979 11.421052632 5 5.8326451979 11.421052632 +7.5 5.8326451979 11.421052632 10 5.8326451979 11.421052632 0 6.8039500009 11.421052632 +2.5 6.8039500009 11.421052632 5 6.8039500009 11.421052632 7.5 6.8039500009 11.421052632 +10 6.8039500009 11.421052632 0 7.9370052598 11.421052632 2.5 7.9370052598 11.421052632 +5 7.9370052598 11.421052632 7.5 7.9370052598 11.421052632 10 7.9370052598 11.421052632 +0 9.2587471229 11.421052632 2.5 9.2587471229 11.421052632 5 9.2587471229 11.421052632 +7.5 9.2587471229 11.421052632 10 9.2587471229 11.421052632 0 10.800597389 11.421052632 +2.5 10.800597389 11.421052632 5 10.800597389 11.421052632 7.5 10.800597389 11.421052632 +10 10.800597389 11.421052632 0 12.599210499 11.421052632 2.5 12.599210499 11.421052632 +5 12.599210499 11.421052632 7.5 12.599210499 11.421052632 10 12.599210499 11.421052632 +0 14.697344923 11.421052632 2.5 14.697344923 11.421052632 5 14.697344923 11.421052632 +7.5 14.697344923 11.421052632 10 14.697344923 11.421052632 0 17.144879657 11.421052632 +2.5 17.144879657 11.421052632 5 17.144879657 11.421052632 7.5 17.144879657 11.421052632 +10 17.144879657 11.421052632 0 20 11.421052632 2.5 20 11.421052632 +5 20 11.421052632 7.5 20 11.421052632 10 20 11.421052632 +0 5 16.631578947 2.5 5 16.631578947 5 5 16.631578947 +7.5 5 16.631578947 10 5 16.631578947 0 5.8326451979 16.631578947 +2.5 5.8326451979 16.631578947 5 5.8326451979 16.631578947 7.5 5.8326451979 16.631578947 +10 5.8326451979 16.631578947 0 6.8039500009 16.631578947 2.5 6.8039500009 16.631578947 +5 6.8039500009 16.631578947 7.5 6.8039500009 16.631578947 10 6.8039500009 16.631578947 +0 7.9370052598 16.631578947 2.5 7.9370052598 16.631578947 5 7.9370052598 16.631578947 +7.5 7.9370052598 16.631578947 10 7.9370052598 16.631578947 0 9.2587471229 16.631578947 +2.5 9.2587471229 16.631578947 5 9.2587471229 16.631578947 7.5 9.2587471229 16.631578947 +10 9.2587471229 16.631578947 0 10.800597389 16.631578947 2.5 10.800597389 16.631578947 +5 10.800597389 16.631578947 7.5 10.800597389 16.631578947 10 10.800597389 16.631578947 +0 12.599210499 16.631578947 2.5 12.599210499 16.631578947 5 12.599210499 16.631578947 +7.5 12.599210499 16.631578947 10 12.599210499 16.631578947 0 14.697344923 16.631578947 +2.5 14.697344923 16.631578947 5 14.697344923 16.631578947 7.5 14.697344923 16.631578947 +10 14.697344923 16.631578947 0 17.144879657 16.631578947 2.5 17.144879657 16.631578947 +5 17.144879657 16.631578947 7.5 17.144879657 16.631578947 10 17.144879657 16.631578947 +0 20 16.631578947 2.5 20 16.631578947 5 20 16.631578947 +7.5 20 16.631578947 10 20 16.631578947 0 5 21.842105263 +2.5 5 21.842105263 5 5 21.842105263 7.5 5 21.842105263 +10 5 21.842105263 0 5.8326451979 21.842105263 2.5 5.8326451979 21.842105263 +5 5.8326451979 21.842105263 7.5 5.8326451979 21.842105263 10 5.8326451979 21.842105263 +0 6.8039500009 21.842105263 2.5 6.8039500009 21.842105263 5 6.8039500009 21.842105263 +7.5 6.8039500009 21.842105263 10 6.8039500009 21.842105263 0 7.9370052598 21.842105263 +2.5 7.9370052598 21.842105263 5 7.9370052598 21.842105263 7.5 7.9370052598 21.842105263 +10 7.9370052598 21.842105263 0 9.2587471229 21.842105263 2.5 9.2587471229 21.842105263 +5 9.2587471229 21.842105263 7.5 9.2587471229 21.842105263 10 9.2587471229 21.842105263 +0 10.800597389 21.842105263 2.5 10.800597389 21.842105263 5 10.800597389 21.842105263 +7.5 10.800597389 21.842105263 10 10.800597389 21.842105263 0 12.599210499 21.842105263 +2.5 12.599210499 21.842105263 5 12.599210499 21.842105263 7.5 12.599210499 21.842105263 +10 12.599210499 21.842105263 0 14.697344923 21.842105263 2.5 14.697344923 21.842105263 +5 14.697344923 21.842105263 7.5 14.697344923 21.842105263 10 14.697344923 21.842105263 +0 17.144879657 21.842105263 2.5 17.144879657 21.842105263 5 17.144879657 21.842105263 +7.5 17.144879657 21.842105263 10 17.144879657 21.842105263 0 20 21.842105263 +2.5 20 21.842105263 5 20 21.842105263 7.5 20 21.842105263 +10 20 21.842105263 0 5 27.052631579 2.5 5 27.052631579 +5 5 27.052631579 7.5 5 27.052631579 10 5 27.052631579 +0 5.8326451979 27.052631579 2.5 5.8326451979 27.052631579 5 5.8326451979 27.052631579 +7.5 5.8326451979 27.052631579 10 5.8326451979 27.052631579 0 6.8039500009 27.052631579 +2.5 6.8039500009 27.052631579 5 6.8039500009 27.052631579 7.5 6.8039500009 27.052631579 +10 6.8039500009 27.052631579 0 7.9370052598 27.052631579 2.5 7.9370052598 27.052631579 +5 7.9370052598 27.052631579 7.5 7.9370052598 27.052631579 10 7.9370052598 27.052631579 +0 9.2587471229 27.052631579 2.5 9.2587471229 27.052631579 5 9.2587471229 27.052631579 +7.5 9.2587471229 27.052631579 10 9.2587471229 27.052631579 0 10.800597389 27.052631579 +2.5 10.800597389 27.052631579 5 10.800597389 27.052631579 7.5 10.800597389 27.052631579 +10 10.800597389 27.052631579 0 12.599210499 27.052631579 2.5 12.599210499 27.052631579 +5 12.599210499 27.052631579 7.5 12.599210499 27.052631579 10 12.599210499 27.052631579 +0 14.697344923 27.052631579 2.5 14.697344923 27.052631579 5 14.697344923 27.052631579 +7.5 14.697344923 27.052631579 10 14.697344923 27.052631579 0 17.144879657 27.052631579 +2.5 17.144879657 27.052631579 5 17.144879657 27.052631579 7.5 17.144879657 27.052631579 +10 17.144879657 27.052631579 0 20 27.052631579 2.5 20 27.052631579 +5 20 27.052631579 7.5 20 27.052631579 10 20 27.052631579 +0 5 32.263157895 2.5 5 32.263157895 5 5 32.263157895 +7.5 5 32.263157895 10 5 32.263157895 0 5.8326451979 32.263157895 +2.5 5.8326451979 32.263157895 5 5.8326451979 32.263157895 7.5 5.8326451979 32.263157895 +10 5.8326451979 32.263157895 0 6.8039500009 32.263157895 2.5 6.8039500009 32.263157895 +5 6.8039500009 32.263157895 7.5 6.8039500009 32.263157895 10 6.8039500009 32.263157895 +0 7.9370052598 32.263157895 2.5 7.9370052598 32.263157895 5 7.9370052598 32.263157895 +7.5 7.9370052598 32.263157895 10 7.9370052598 32.263157895 0 9.2587471229 32.263157895 +2.5 9.2587471229 32.263157895 5 9.2587471229 32.263157895 7.5 9.2587471229 32.263157895 +10 9.2587471229 32.263157895 0 10.800597389 32.263157895 2.5 10.800597389 32.263157895 +5 10.800597389 32.263157895 7.5 10.800597389 32.263157895 10 10.800597389 32.263157895 +0 12.599210499 32.263157895 2.5 12.599210499 32.263157895 5 12.599210499 32.263157895 +7.5 12.599210499 32.263157895 10 12.599210499 32.263157895 0 14.697344923 32.263157895 +2.5 14.697344923 32.263157895 5 14.697344923 32.263157895 7.5 14.697344923 32.263157895 +10 14.697344923 32.263157895 0 17.144879657 32.263157895 2.5 17.144879657 32.263157895 +5 17.144879657 32.263157895 7.5 17.144879657 32.263157895 10 17.144879657 32.263157895 +0 20 32.263157895 2.5 20 32.263157895 5 20 32.263157895 +7.5 20 32.263157895 10 20 32.263157895 0 5 37.473684211 +2.5 5 37.473684211 5 5 37.473684211 7.5 5 37.473684211 +10 5 37.473684211 0 5.8326451979 37.473684211 2.5 5.8326451979 37.473684211 +5 5.8326451979 37.473684211 7.5 5.8326451979 37.473684211 10 5.8326451979 37.473684211 +0 6.8039500009 37.473684211 2.5 6.8039500009 37.473684211 5 6.8039500009 37.473684211 +7.5 6.8039500009 37.473684211 10 6.8039500009 37.473684211 0 7.9370052598 37.473684211 +2.5 7.9370052598 37.473684211 5 7.9370052598 37.473684211 7.5 7.9370052598 37.473684211 +10 7.9370052598 37.473684211 0 9.2587471229 37.473684211 2.5 9.2587471229 37.473684211 +5 9.2587471229 37.473684211 7.5 9.2587471229 37.473684211 10 9.2587471229 37.473684211 +0 10.800597389 37.473684211 2.5 10.800597389 37.473684211 5 10.800597389 37.473684211 +7.5 10.800597389 37.473684211 10 10.800597389 37.473684211 0 12.599210499 37.473684211 +2.5 12.599210499 37.473684211 5 12.599210499 37.473684211 7.5 12.599210499 37.473684211 +10 12.599210499 37.473684211 0 14.697344923 37.473684211 2.5 14.697344923 37.473684211 +5 14.697344923 37.473684211 7.5 14.697344923 37.473684211 10 14.697344923 37.473684211 +0 17.144879657 37.473684211 2.5 17.144879657 37.473684211 5 17.144879657 37.473684211 +7.5 17.144879657 37.473684211 10 17.144879657 37.473684211 0 20 37.473684211 +2.5 20 37.473684211 5 20 37.473684211 7.5 20 37.473684211 +10 20 37.473684211 0 5 42.684210526 2.5 5 42.684210526 +5 5 42.684210526 7.5 5 42.684210526 10 5 42.684210526 +0 5.8326451979 42.684210526 2.5 5.8326451979 42.684210526 5 5.8326451979 42.684210526 +7.5 5.8326451979 42.684210526 10 5.8326451979 42.684210526 0 6.8039500009 42.684210526 +2.5 6.8039500009 42.684210526 5 6.8039500009 42.684210526 7.5 6.8039500009 42.684210526 +10 6.8039500009 42.684210526 0 7.9370052598 42.684210526 2.5 7.9370052598 42.684210526 +5 7.9370052598 42.684210526 7.5 7.9370052598 42.684210526 10 7.9370052598 42.684210526 +0 9.2587471229 42.684210526 2.5 9.2587471229 42.684210526 5 9.2587471229 42.684210526 +7.5 9.2587471229 42.684210526 10 9.2587471229 42.684210526 0 10.800597389 42.684210526 +2.5 10.800597389 42.684210526 5 10.800597389 42.684210526 7.5 10.800597389 42.684210526 +10 10.800597389 42.684210526 0 12.599210499 42.684210526 2.5 12.599210499 42.684210526 +5 12.599210499 42.684210526 7.5 12.599210499 42.684210526 10 12.599210499 42.684210526 +0 14.697344923 42.684210526 2.5 14.697344923 42.684210526 5 14.697344923 42.684210526 +7.5 14.697344923 42.684210526 10 14.697344923 42.684210526 0 17.144879657 42.684210526 +2.5 17.144879657 42.684210526 5 17.144879657 42.684210526 7.5 17.144879657 42.684210526 +10 17.144879657 42.684210526 0 20 42.684210526 2.5 20 42.684210526 +5 20 42.684210526 7.5 20 42.684210526 10 20 42.684210526 +0 5 47.894736842 2.5 5 47.894736842 5 5 47.894736842 +7.5 5 47.894736842 10 5 47.894736842 0 5.8326451979 47.894736842 +2.5 5.8326451979 47.894736842 5 5.8326451979 47.894736842 7.5 5.8326451979 47.894736842 +10 5.8326451979 47.894736842 0 6.8039500009 47.894736842 2.5 6.8039500009 47.894736842 +5 6.8039500009 47.894736842 7.5 6.8039500009 47.894736842 10 6.8039500009 47.894736842 +0 7.9370052598 47.894736842 2.5 7.9370052598 47.894736842 5 7.9370052598 47.894736842 +7.5 7.9370052598 47.894736842 10 7.9370052598 47.894736842 0 9.2587471229 47.894736842 +2.5 9.2587471229 47.894736842 5 9.2587471229 47.894736842 7.5 9.2587471229 47.894736842 +10 9.2587471229 47.894736842 0 10.800597389 47.894736842 2.5 10.800597389 47.894736842 +5 10.800597389 47.894736842 7.5 10.800597389 47.894736842 10 10.800597389 47.894736842 +0 12.599210499 47.894736842 2.5 12.599210499 47.894736842 5 12.599210499 47.894736842 +7.5 12.599210499 47.894736842 10 12.599210499 47.894736842 0 14.697344923 47.894736842 +2.5 14.697344923 47.894736842 5 14.697344923 47.894736842 7.5 14.697344923 47.894736842 +10 14.697344923 47.894736842 0 17.144879657 47.894736842 2.5 17.144879657 47.894736842 +5 17.144879657 47.894736842 7.5 17.144879657 47.894736842 10 17.144879657 47.894736842 +0 20 47.894736842 2.5 20 47.894736842 5 20 47.894736842 +7.5 20 47.894736842 10 20 47.894736842 0 5 53.105263158 +2.5 5 53.105263158 5 5 53.105263158 7.5 5 53.105263158 +10 5 53.105263158 0 5.8326451979 53.105263158 2.5 5.8326451979 53.105263158 +5 5.8326451979 53.105263158 7.5 5.8326451979 53.105263158 10 5.8326451979 53.105263158 +0 6.8039500009 53.105263158 2.5 6.8039500009 53.105263158 5 6.8039500009 53.105263158 +7.5 6.8039500009 53.105263158 10 6.8039500009 53.105263158 0 7.9370052598 53.105263158 +2.5 7.9370052598 53.105263158 5 7.9370052598 53.105263158 7.5 7.9370052598 53.105263158 +10 7.9370052598 53.105263158 0 9.2587471229 53.105263158 2.5 9.2587471229 53.105263158 +5 9.2587471229 53.105263158 7.5 9.2587471229 53.105263158 10 9.2587471229 53.105263158 +0 10.800597389 53.105263158 2.5 10.800597389 53.105263158 5 10.800597389 53.105263158 +7.5 10.800597389 53.105263158 10 10.800597389 53.105263158 0 12.599210499 53.105263158 +2.5 12.599210499 53.105263158 5 12.599210499 53.105263158 7.5 12.599210499 53.105263158 +10 12.599210499 53.105263158 0 14.697344923 53.105263158 2.5 14.697344923 53.105263158 +5 14.697344923 53.105263158 7.5 14.697344923 53.105263158 10 14.697344923 53.105263158 +0 17.144879657 53.105263158 2.5 17.144879657 53.105263158 5 17.144879657 53.105263158 +7.5 17.144879657 53.105263158 10 17.144879657 53.105263158 0 20 53.105263158 +2.5 20 53.105263158 5 20 53.105263158 7.5 20 53.105263158 +10 20 53.105263158 0 5 58.315789474 2.5 5 58.315789474 +5 5 58.315789474 7.5 5 58.315789474 10 5 58.315789474 +0 5.8326451979 58.315789474 2.5 5.8326451979 58.315789474 5 5.8326451979 58.315789474 +7.5 5.8326451979 58.315789474 10 5.8326451979 58.315789474 0 6.8039500009 58.315789474 +2.5 6.8039500009 58.315789474 5 6.8039500009 58.315789474 7.5 6.8039500009 58.315789474 +10 6.8039500009 58.315789474 0 7.9370052598 58.315789474 2.5 7.9370052598 58.315789474 +5 7.9370052598 58.315789474 7.5 7.9370052598 58.315789474 10 7.9370052598 58.315789474 +0 9.2587471229 58.315789474 2.5 9.2587471229 58.315789474 5 9.2587471229 58.315789474 +7.5 9.2587471229 58.315789474 10 9.2587471229 58.315789474 0 10.800597389 58.315789474 +2.5 10.800597389 58.315789474 5 10.800597389 58.315789474 7.5 10.800597389 58.315789474 +10 10.800597389 58.315789474 0 12.599210499 58.315789474 2.5 12.599210499 58.315789474 +5 12.599210499 58.315789474 7.5 12.599210499 58.315789474 10 12.599210499 58.315789474 +0 14.697344923 58.315789474 2.5 14.697344923 58.315789474 5 14.697344923 58.315789474 +7.5 14.697344923 58.315789474 10 14.697344923 58.315789474 0 17.144879657 58.315789474 +2.5 17.144879657 58.315789474 5 17.144879657 58.315789474 7.5 17.144879657 58.315789474 +10 17.144879657 58.315789474 0 20 58.315789474 2.5 20 58.315789474 +5 20 58.315789474 7.5 20 58.315789474 10 20 58.315789474 +0 5 63.526315789 2.5 5 63.526315789 5 5 63.526315789 +7.5 5 63.526315789 10 5 63.526315789 0 5.8326451979 63.526315789 +2.5 5.8326451979 63.526315789 5 5.8326451979 63.526315789 7.5 5.8326451979 63.526315789 +10 5.8326451979 63.526315789 0 6.8039500009 63.526315789 2.5 6.8039500009 63.526315789 +5 6.8039500009 63.526315789 7.5 6.8039500009 63.526315789 10 6.8039500009 63.526315789 +0 7.9370052598 63.526315789 2.5 7.9370052598 63.526315789 5 7.9370052598 63.526315789 +7.5 7.9370052598 63.526315789 10 7.9370052598 63.526315789 0 9.2587471229 63.526315789 +2.5 9.2587471229 63.526315789 5 9.2587471229 63.526315789 7.5 9.2587471229 63.526315789 +10 9.2587471229 63.526315789 0 10.800597389 63.526315789 2.5 10.800597389 63.526315789 +5 10.800597389 63.526315789 7.5 10.800597389 63.526315789 10 10.800597389 63.526315789 +0 12.599210499 63.526315789 2.5 12.599210499 63.526315789 5 12.599210499 63.526315789 +7.5 12.599210499 63.526315789 10 12.599210499 63.526315789 0 14.697344923 63.526315789 +2.5 14.697344923 63.526315789 5 14.697344923 63.526315789 7.5 14.697344923 63.526315789 +10 14.697344923 63.526315789 0 17.144879657 63.526315789 2.5 17.144879657 63.526315789 +5 17.144879657 63.526315789 7.5 17.144879657 63.526315789 10 17.144879657 63.526315789 +0 20 63.526315789 2.5 20 63.526315789 5 20 63.526315789 +7.5 20 63.526315789 10 20 63.526315789 0 5 68.736842105 +2.5 5 68.736842105 5 5 68.736842105 7.5 5 68.736842105 +10 5 68.736842105 0 5.8326451979 68.736842105 2.5 5.8326451979 68.736842105 +5 5.8326451979 68.736842105 7.5 5.8326451979 68.736842105 10 5.8326451979 68.736842105 +0 6.8039500009 68.736842105 2.5 6.8039500009 68.736842105 5 6.8039500009 68.736842105 +7.5 6.8039500009 68.736842105 10 6.8039500009 68.736842105 0 7.9370052598 68.736842105 +2.5 7.9370052598 68.736842105 5 7.9370052598 68.736842105 7.5 7.9370052598 68.736842105 +10 7.9370052598 68.736842105 0 9.2587471229 68.736842105 2.5 9.2587471229 68.736842105 +5 9.2587471229 68.736842105 7.5 9.2587471229 68.736842105 10 9.2587471229 68.736842105 +0 10.800597389 68.736842105 2.5 10.800597389 68.736842105 5 10.800597389 68.736842105 +7.5 10.800597389 68.736842105 10 10.800597389 68.736842105 0 12.599210499 68.736842105 +2.5 12.599210499 68.736842105 5 12.599210499 68.736842105 7.5 12.599210499 68.736842105 +10 12.599210499 68.736842105 0 14.697344923 68.736842105 2.5 14.697344923 68.736842105 +5 14.697344923 68.736842105 7.5 14.697344923 68.736842105 10 14.697344923 68.736842105 +0 17.144879657 68.736842105 2.5 17.144879657 68.736842105 5 17.144879657 68.736842105 +7.5 17.144879657 68.736842105 10 17.144879657 68.736842105 0 20 68.736842105 +2.5 20 68.736842105 5 20 68.736842105 7.5 20 68.736842105 +10 20 68.736842105 0 5 73.947368421 2.5 5 73.947368421 +5 5 73.947368421 7.5 5 73.947368421 10 5 73.947368421 +0 5.8326451979 73.947368421 2.5 5.8326451979 73.947368421 5 5.8326451979 73.947368421 +7.5 5.8326451979 73.947368421 10 5.8326451979 73.947368421 0 6.8039500009 73.947368421 +2.5 6.8039500009 73.947368421 5 6.8039500009 73.947368421 7.5 6.8039500009 73.947368421 +10 6.8039500009 73.947368421 0 7.9370052598 73.947368421 2.5 7.9370052598 73.947368421 +5 7.9370052598 73.947368421 7.5 7.9370052598 73.947368421 10 7.9370052598 73.947368421 +0 9.2587471229 73.947368421 2.5 9.2587471229 73.947368421 5 9.2587471229 73.947368421 +7.5 9.2587471229 73.947368421 10 9.2587471229 73.947368421 0 10.800597389 73.947368421 +2.5 10.800597389 73.947368421 5 10.800597389 73.947368421 7.5 10.800597389 73.947368421 +10 10.800597389 73.947368421 0 12.599210499 73.947368421 2.5 12.599210499 73.947368421 +5 12.599210499 73.947368421 7.5 12.599210499 73.947368421 10 12.599210499 73.947368421 +0 14.697344923 73.947368421 2.5 14.697344923 73.947368421 5 14.697344923 73.947368421 +7.5 14.697344923 73.947368421 10 14.697344923 73.947368421 0 17.144879657 73.947368421 +2.5 17.144879657 73.947368421 5 17.144879657 73.947368421 7.5 17.144879657 73.947368421 +10 17.144879657 73.947368421 0 20 73.947368421 2.5 20 73.947368421 +5 20 73.947368421 7.5 20 73.947368421 10 20 73.947368421 +0 5 79.157894737 2.5 5 79.157894737 5 5 79.157894737 +7.5 5 79.157894737 10 5 79.157894737 0 5.8326451979 79.157894737 +2.5 5.8326451979 79.157894737 5 5.8326451979 79.157894737 7.5 5.8326451979 79.157894737 +10 5.8326451979 79.157894737 0 6.8039500009 79.157894737 2.5 6.8039500009 79.157894737 +5 6.8039500009 79.157894737 7.5 6.8039500009 79.157894737 10 6.8039500009 79.157894737 +0 7.9370052598 79.157894737 2.5 7.9370052598 79.157894737 5 7.9370052598 79.157894737 +7.5 7.9370052598 79.157894737 10 7.9370052598 79.157894737 0 9.2587471229 79.157894737 +2.5 9.2587471229 79.157894737 5 9.2587471229 79.157894737 7.5 9.2587471229 79.157894737 +10 9.2587471229 79.157894737 0 10.800597389 79.157894737 2.5 10.800597389 79.157894737 +5 10.800597389 79.157894737 7.5 10.800597389 79.157894737 10 10.800597389 79.157894737 +0 12.599210499 79.157894737 2.5 12.599210499 79.157894737 5 12.599210499 79.157894737 +7.5 12.599210499 79.157894737 10 12.599210499 79.157894737 0 14.697344923 79.157894737 +2.5 14.697344923 79.157894737 5 14.697344923 79.157894737 7.5 14.697344923 79.157894737 +10 14.697344923 79.157894737 0 17.144879657 79.157894737 2.5 17.144879657 79.157894737 +5 17.144879657 79.157894737 7.5 17.144879657 79.157894737 10 17.144879657 79.157894737 +0 20 79.157894737 2.5 20 79.157894737 5 20 79.157894737 +7.5 20 79.157894737 10 20 79.157894737 0 5 84.368421053 +2.5 5 84.368421053 5 5 84.368421053 7.5 5 84.368421053 +10 5 84.368421053 0 5.8326451979 84.368421053 2.5 5.8326451979 84.368421053 +5 5.8326451979 84.368421053 7.5 5.8326451979 84.368421053 10 5.8326451979 84.368421053 +0 6.8039500009 84.368421053 2.5 6.8039500009 84.368421053 5 6.8039500009 84.368421053 +7.5 6.8039500009 84.368421053 10 6.8039500009 84.368421053 0 7.9370052598 84.368421053 +2.5 7.9370052598 84.368421053 5 7.9370052598 84.368421053 7.5 7.9370052598 84.368421053 +10 7.9370052598 84.368421053 0 9.2587471229 84.368421053 2.5 9.2587471229 84.368421053 +5 9.2587471229 84.368421053 7.5 9.2587471229 84.368421053 10 9.2587471229 84.368421053 +0 10.800597389 84.368421053 2.5 10.800597389 84.368421053 5 10.800597389 84.368421053 +7.5 10.800597389 84.368421053 10 10.800597389 84.368421053 0 12.599210499 84.368421053 +2.5 12.599210499 84.368421053 5 12.599210499 84.368421053 7.5 12.599210499 84.368421053 +10 12.599210499 84.368421053 0 14.697344923 84.368421053 2.5 14.697344923 84.368421053 +5 14.697344923 84.368421053 7.5 14.697344923 84.368421053 10 14.697344923 84.368421053 +0 17.144879657 84.368421053 2.5 17.144879657 84.368421053 5 17.144879657 84.368421053 +7.5 17.144879657 84.368421053 10 17.144879657 84.368421053 0 20 84.368421053 +2.5 20 84.368421053 5 20 84.368421053 7.5 20 84.368421053 +10 20 84.368421053 0 5 89.578947368 2.5 5 89.578947368 +5 5 89.578947368 7.5 5 89.578947368 10 5 89.578947368 +0 5.8326451979 89.578947368 2.5 5.8326451979 89.578947368 5 5.8326451979 89.578947368 +7.5 5.8326451979 89.578947368 10 5.8326451979 89.578947368 0 6.8039500009 89.578947368 +2.5 6.8039500009 89.578947368 5 6.8039500009 89.578947368 7.5 6.8039500009 89.578947368 +10 6.8039500009 89.578947368 0 7.9370052598 89.578947368 2.5 7.9370052598 89.578947368 +5 7.9370052598 89.578947368 7.5 7.9370052598 89.578947368 10 7.9370052598 89.578947368 +0 9.2587471229 89.578947368 2.5 9.2587471229 89.578947368 5 9.2587471229 89.578947368 +7.5 9.2587471229 89.578947368 10 9.2587471229 89.578947368 0 10.800597389 89.578947368 +2.5 10.800597389 89.578947368 5 10.800597389 89.578947368 7.5 10.800597389 89.578947368 +10 10.800597389 89.578947368 0 12.599210499 89.578947368 2.5 12.599210499 89.578947368 +5 12.599210499 89.578947368 7.5 12.599210499 89.578947368 10 12.599210499 89.578947368 +0 14.697344923 89.578947368 2.5 14.697344923 89.578947368 5 14.697344923 89.578947368 +7.5 14.697344923 89.578947368 10 14.697344923 89.578947368 0 17.144879657 89.578947368 +2.5 17.144879657 89.578947368 5 17.144879657 89.578947368 7.5 17.144879657 89.578947368 +10 17.144879657 89.578947368 0 20 89.578947368 2.5 20 89.578947368 +5 20 89.578947368 7.5 20 89.578947368 10 20 89.578947368 +0 5 94.789473684 2.5 5 94.789473684 5 5 94.789473684 +7.5 5 94.789473684 10 5 94.789473684 0 5.8326451979 94.789473684 +2.5 5.8326451979 94.789473684 5 5.8326451979 94.789473684 7.5 5.8326451979 94.789473684 +10 5.8326451979 94.789473684 0 6.8039500009 94.789473684 2.5 6.8039500009 94.789473684 +5 6.8039500009 94.789473684 7.5 6.8039500009 94.789473684 10 6.8039500009 94.789473684 +0 7.9370052598 94.789473684 2.5 7.9370052598 94.789473684 5 7.9370052598 94.789473684 +7.5 7.9370052598 94.789473684 10 7.9370052598 94.789473684 0 9.2587471229 94.789473684 +2.5 9.2587471229 94.789473684 5 9.2587471229 94.789473684 7.5 9.2587471229 94.789473684 +10 9.2587471229 94.789473684 0 10.800597389 94.789473684 2.5 10.800597389 94.789473684 +5 10.800597389 94.789473684 7.5 10.800597389 94.789473684 10 10.800597389 94.789473684 +0 12.599210499 94.789473684 2.5 12.599210499 94.789473684 5 12.599210499 94.789473684 +7.5 12.599210499 94.789473684 10 12.599210499 94.789473684 0 14.697344923 94.789473684 +2.5 14.697344923 94.789473684 5 14.697344923 94.789473684 7.5 14.697344923 94.789473684 +10 14.697344923 94.789473684 0 17.144879657 94.789473684 2.5 17.144879657 94.789473684 +5 17.144879657 94.789473684 7.5 17.144879657 94.789473684 10 17.144879657 94.789473684 +0 20 94.789473684 2.5 20 94.789473684 5 20 94.789473684 +7.5 20 94.789473684 10 20 94.789473684 0 5 100 +2.5 5 100 5 5 100 7.5 5 100 +10 5 100 0 5.8326451979 100 2.5 5.8326451979 100 +5 5.8326451979 100 7.5 5.8326451979 100 10 5.8326451979 100 +0 6.8039500009 100 2.5 6.8039500009 100 5 6.8039500009 100 +7.5 6.8039500009 100 10 6.8039500009 100 0 7.9370052598 100 +2.5 7.9370052598 100 5 7.9370052598 100 7.5 7.9370052598 100 +10 7.9370052598 100 0 9.2587471229 100 2.5 9.2587471229 100 +5 9.2587471229 100 7.5 9.2587471229 100 10 9.2587471229 100 +0 10.800597389 100 2.5 10.800597389 100 5 10.800597389 100 +7.5 10.800597389 100 10 10.800597389 100 0 12.599210499 100 +2.5 12.599210499 100 5 12.599210499 100 7.5 12.599210499 100 +10 12.599210499 100 0 14.697344923 100 2.5 14.697344923 100 +5 14.697344923 100 7.5 14.697344923 100 10 14.697344923 100 +0 17.144879657 100 2.5 17.144879657 100 5 17.144879657 100 +7.5 17.144879657 100 10 17.144879657 100 0 20 100 +2.5 20 100 5 20 100 7.5 20 100 +10 20 100 diff --git a/tests/unit_tests/mesh_to_vtk/regular.vtk b/tests/unit_tests/mesh_to_vtk/regular.vtk new file mode 100644 index 00000000000..8f8aca5a620 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/regular.vtk @@ -0,0 +1,2394 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 11 21 31 +POINTS 7161 double +0 0 0 2 0 0 4 0 0 +6 0 0 8 0 0 10 0 0 +12 0 0 14 0 0 16 0 0 +18 0 0 20 0 0 0 2.5 0 +2 2.5 0 4 2.5 0 6 2.5 0 +8 2.5 0 10 2.5 0 12 2.5 0 +14 2.5 0 16 2.5 0 18 2.5 0 +20 2.5 0 0 5 0 2 5 0 +4 5 0 6 5 0 8 5 0 +10 5 0 12 5 0 14 5 0 +16 5 0 18 5 0 20 5 0 +0 7.5 0 2 7.5 0 4 7.5 0 +6 7.5 0 8 7.5 0 10 7.5 0 +12 7.5 0 14 7.5 0 16 7.5 0 +18 7.5 0 20 7.5 0 0 10 0 +2 10 0 4 10 0 6 10 0 +8 10 0 10 10 0 12 10 0 +14 10 0 16 10 0 18 10 0 +20 10 0 0 12.5 0 2 12.5 0 +4 12.5 0 6 12.5 0 8 12.5 0 +10 12.5 0 12 12.5 0 14 12.5 0 +16 12.5 0 18 12.5 0 20 12.5 0 +0 15 0 2 15 0 4 15 0 +6 15 0 8 15 0 10 15 0 +12 15 0 14 15 0 16 15 0 +18 15 0 20 15 0 0 17.5 0 +2 17.5 0 4 17.5 0 6 17.5 0 +8 17.5 0 10 17.5 0 12 17.5 0 +14 17.5 0 16 17.5 0 18 17.5 0 +20 17.5 0 0 20 0 2 20 0 +4 20 0 6 20 0 8 20 0 +10 20 0 12 20 0 14 20 0 +16 20 0 18 20 0 20 20 0 +0 22.5 0 2 22.5 0 4 22.5 0 +6 22.5 0 8 22.5 0 10 22.5 0 +12 22.5 0 14 22.5 0 16 22.5 0 +18 22.5 0 20 22.5 0 0 25 0 +2 25 0 4 25 0 6 25 0 +8 25 0 10 25 0 12 25 0 +14 25 0 16 25 0 18 25 0 +20 25 0 0 27.5 0 2 27.5 0 +4 27.5 0 6 27.5 0 8 27.5 0 +10 27.5 0 12 27.5 0 14 27.5 0 +16 27.5 0 18 27.5 0 20 27.5 0 +0 30 0 2 30 0 4 30 0 +6 30 0 8 30 0 10 30 0 +12 30 0 14 30 0 16 30 0 +18 30 0 20 30 0 0 32.5 0 +2 32.5 0 4 32.5 0 6 32.5 0 +8 32.5 0 10 32.5 0 12 32.5 0 +14 32.5 0 16 32.5 0 18 32.5 0 +20 32.5 0 0 35 0 2 35 0 +4 35 0 6 35 0 8 35 0 +10 35 0 12 35 0 14 35 0 +16 35 0 18 35 0 20 35 0 +0 37.5 0 2 37.5 0 4 37.5 0 +6 37.5 0 8 37.5 0 10 37.5 0 +12 37.5 0 14 37.5 0 16 37.5 0 +18 37.5 0 20 37.5 0 0 40 0 +2 40 0 4 40 0 6 40 0 +8 40 0 10 40 0 12 40 0 +14 40 0 16 40 0 18 40 0 +20 40 0 0 42.5 0 2 42.5 0 +4 42.5 0 6 42.5 0 8 42.5 0 +10 42.5 0 12 42.5 0 14 42.5 0 +16 42.5 0 18 42.5 0 20 42.5 0 +0 45 0 2 45 0 4 45 0 +6 45 0 8 45 0 10 45 0 +12 45 0 14 45 0 16 45 0 +18 45 0 20 45 0 0 47.5 0 +2 47.5 0 4 47.5 0 6 47.5 0 +8 47.5 0 10 47.5 0 12 47.5 0 +14 47.5 0 16 47.5 0 18 47.5 0 +20 47.5 0 0 50 0 2 50 0 +4 50 0 6 50 0 8 50 0 +10 50 0 12 50 0 14 50 0 +16 50 0 18 50 0 20 50 0 +0 0 1.6666666667 2 0 1.6666666667 4 0 1.6666666667 +6 0 1.6666666667 8 0 1.6666666667 10 0 1.6666666667 +12 0 1.6666666667 14 0 1.6666666667 16 0 1.6666666667 +18 0 1.6666666667 20 0 1.6666666667 0 2.5 1.6666666667 +2 2.5 1.6666666667 4 2.5 1.6666666667 6 2.5 1.6666666667 +8 2.5 1.6666666667 10 2.5 1.6666666667 12 2.5 1.6666666667 +14 2.5 1.6666666667 16 2.5 1.6666666667 18 2.5 1.6666666667 +20 2.5 1.6666666667 0 5 1.6666666667 2 5 1.6666666667 +4 5 1.6666666667 6 5 1.6666666667 8 5 1.6666666667 +10 5 1.6666666667 12 5 1.6666666667 14 5 1.6666666667 +16 5 1.6666666667 18 5 1.6666666667 20 5 1.6666666667 +0 7.5 1.6666666667 2 7.5 1.6666666667 4 7.5 1.6666666667 +6 7.5 1.6666666667 8 7.5 1.6666666667 10 7.5 1.6666666667 +12 7.5 1.6666666667 14 7.5 1.6666666667 16 7.5 1.6666666667 +18 7.5 1.6666666667 20 7.5 1.6666666667 0 10 1.6666666667 +2 10 1.6666666667 4 10 1.6666666667 6 10 1.6666666667 +8 10 1.6666666667 10 10 1.6666666667 12 10 1.6666666667 +14 10 1.6666666667 16 10 1.6666666667 18 10 1.6666666667 +20 10 1.6666666667 0 12.5 1.6666666667 2 12.5 1.6666666667 +4 12.5 1.6666666667 6 12.5 1.6666666667 8 12.5 1.6666666667 +10 12.5 1.6666666667 12 12.5 1.6666666667 14 12.5 1.6666666667 +16 12.5 1.6666666667 18 12.5 1.6666666667 20 12.5 1.6666666667 +0 15 1.6666666667 2 15 1.6666666667 4 15 1.6666666667 +6 15 1.6666666667 8 15 1.6666666667 10 15 1.6666666667 +12 15 1.6666666667 14 15 1.6666666667 16 15 1.6666666667 +18 15 1.6666666667 20 15 1.6666666667 0 17.5 1.6666666667 +2 17.5 1.6666666667 4 17.5 1.6666666667 6 17.5 1.6666666667 +8 17.5 1.6666666667 10 17.5 1.6666666667 12 17.5 1.6666666667 +14 17.5 1.6666666667 16 17.5 1.6666666667 18 17.5 1.6666666667 +20 17.5 1.6666666667 0 20 1.6666666667 2 20 1.6666666667 +4 20 1.6666666667 6 20 1.6666666667 8 20 1.6666666667 +10 20 1.6666666667 12 20 1.6666666667 14 20 1.6666666667 +16 20 1.6666666667 18 20 1.6666666667 20 20 1.6666666667 +0 22.5 1.6666666667 2 22.5 1.6666666667 4 22.5 1.6666666667 +6 22.5 1.6666666667 8 22.5 1.6666666667 10 22.5 1.6666666667 +12 22.5 1.6666666667 14 22.5 1.6666666667 16 22.5 1.6666666667 +18 22.5 1.6666666667 20 22.5 1.6666666667 0 25 1.6666666667 +2 25 1.6666666667 4 25 1.6666666667 6 25 1.6666666667 +8 25 1.6666666667 10 25 1.6666666667 12 25 1.6666666667 +14 25 1.6666666667 16 25 1.6666666667 18 25 1.6666666667 +20 25 1.6666666667 0 27.5 1.6666666667 2 27.5 1.6666666667 +4 27.5 1.6666666667 6 27.5 1.6666666667 8 27.5 1.6666666667 +10 27.5 1.6666666667 12 27.5 1.6666666667 14 27.5 1.6666666667 +16 27.5 1.6666666667 18 27.5 1.6666666667 20 27.5 1.6666666667 +0 30 1.6666666667 2 30 1.6666666667 4 30 1.6666666667 +6 30 1.6666666667 8 30 1.6666666667 10 30 1.6666666667 +12 30 1.6666666667 14 30 1.6666666667 16 30 1.6666666667 +18 30 1.6666666667 20 30 1.6666666667 0 32.5 1.6666666667 +2 32.5 1.6666666667 4 32.5 1.6666666667 6 32.5 1.6666666667 +8 32.5 1.6666666667 10 32.5 1.6666666667 12 32.5 1.6666666667 +14 32.5 1.6666666667 16 32.5 1.6666666667 18 32.5 1.6666666667 +20 32.5 1.6666666667 0 35 1.6666666667 2 35 1.6666666667 +4 35 1.6666666667 6 35 1.6666666667 8 35 1.6666666667 +10 35 1.6666666667 12 35 1.6666666667 14 35 1.6666666667 +16 35 1.6666666667 18 35 1.6666666667 20 35 1.6666666667 +0 37.5 1.6666666667 2 37.5 1.6666666667 4 37.5 1.6666666667 +6 37.5 1.6666666667 8 37.5 1.6666666667 10 37.5 1.6666666667 +12 37.5 1.6666666667 14 37.5 1.6666666667 16 37.5 1.6666666667 +18 37.5 1.6666666667 20 37.5 1.6666666667 0 40 1.6666666667 +2 40 1.6666666667 4 40 1.6666666667 6 40 1.6666666667 +8 40 1.6666666667 10 40 1.6666666667 12 40 1.6666666667 +14 40 1.6666666667 16 40 1.6666666667 18 40 1.6666666667 +20 40 1.6666666667 0 42.5 1.6666666667 2 42.5 1.6666666667 +4 42.5 1.6666666667 6 42.5 1.6666666667 8 42.5 1.6666666667 +10 42.5 1.6666666667 12 42.5 1.6666666667 14 42.5 1.6666666667 +16 42.5 1.6666666667 18 42.5 1.6666666667 20 42.5 1.6666666667 +0 45 1.6666666667 2 45 1.6666666667 4 45 1.6666666667 +6 45 1.6666666667 8 45 1.6666666667 10 45 1.6666666667 +12 45 1.6666666667 14 45 1.6666666667 16 45 1.6666666667 +18 45 1.6666666667 20 45 1.6666666667 0 47.5 1.6666666667 +2 47.5 1.6666666667 4 47.5 1.6666666667 6 47.5 1.6666666667 +8 47.5 1.6666666667 10 47.5 1.6666666667 12 47.5 1.6666666667 +14 47.5 1.6666666667 16 47.5 1.6666666667 18 47.5 1.6666666667 +20 47.5 1.6666666667 0 50 1.6666666667 2 50 1.6666666667 +4 50 1.6666666667 6 50 1.6666666667 8 50 1.6666666667 +10 50 1.6666666667 12 50 1.6666666667 14 50 1.6666666667 +16 50 1.6666666667 18 50 1.6666666667 20 50 1.6666666667 +0 0 3.3333333333 2 0 3.3333333333 4 0 3.3333333333 +6 0 3.3333333333 8 0 3.3333333333 10 0 3.3333333333 +12 0 3.3333333333 14 0 3.3333333333 16 0 3.3333333333 +18 0 3.3333333333 20 0 3.3333333333 0 2.5 3.3333333333 +2 2.5 3.3333333333 4 2.5 3.3333333333 6 2.5 3.3333333333 +8 2.5 3.3333333333 10 2.5 3.3333333333 12 2.5 3.3333333333 +14 2.5 3.3333333333 16 2.5 3.3333333333 18 2.5 3.3333333333 +20 2.5 3.3333333333 0 5 3.3333333333 2 5 3.3333333333 +4 5 3.3333333333 6 5 3.3333333333 8 5 3.3333333333 +10 5 3.3333333333 12 5 3.3333333333 14 5 3.3333333333 +16 5 3.3333333333 18 5 3.3333333333 20 5 3.3333333333 +0 7.5 3.3333333333 2 7.5 3.3333333333 4 7.5 3.3333333333 +6 7.5 3.3333333333 8 7.5 3.3333333333 10 7.5 3.3333333333 +12 7.5 3.3333333333 14 7.5 3.3333333333 16 7.5 3.3333333333 +18 7.5 3.3333333333 20 7.5 3.3333333333 0 10 3.3333333333 +2 10 3.3333333333 4 10 3.3333333333 6 10 3.3333333333 +8 10 3.3333333333 10 10 3.3333333333 12 10 3.3333333333 +14 10 3.3333333333 16 10 3.3333333333 18 10 3.3333333333 +20 10 3.3333333333 0 12.5 3.3333333333 2 12.5 3.3333333333 +4 12.5 3.3333333333 6 12.5 3.3333333333 8 12.5 3.3333333333 +10 12.5 3.3333333333 12 12.5 3.3333333333 14 12.5 3.3333333333 +16 12.5 3.3333333333 18 12.5 3.3333333333 20 12.5 3.3333333333 +0 15 3.3333333333 2 15 3.3333333333 4 15 3.3333333333 +6 15 3.3333333333 8 15 3.3333333333 10 15 3.3333333333 +12 15 3.3333333333 14 15 3.3333333333 16 15 3.3333333333 +18 15 3.3333333333 20 15 3.3333333333 0 17.5 3.3333333333 +2 17.5 3.3333333333 4 17.5 3.3333333333 6 17.5 3.3333333333 +8 17.5 3.3333333333 10 17.5 3.3333333333 12 17.5 3.3333333333 +14 17.5 3.3333333333 16 17.5 3.3333333333 18 17.5 3.3333333333 +20 17.5 3.3333333333 0 20 3.3333333333 2 20 3.3333333333 +4 20 3.3333333333 6 20 3.3333333333 8 20 3.3333333333 +10 20 3.3333333333 12 20 3.3333333333 14 20 3.3333333333 +16 20 3.3333333333 18 20 3.3333333333 20 20 3.3333333333 +0 22.5 3.3333333333 2 22.5 3.3333333333 4 22.5 3.3333333333 +6 22.5 3.3333333333 8 22.5 3.3333333333 10 22.5 3.3333333333 +12 22.5 3.3333333333 14 22.5 3.3333333333 16 22.5 3.3333333333 +18 22.5 3.3333333333 20 22.5 3.3333333333 0 25 3.3333333333 +2 25 3.3333333333 4 25 3.3333333333 6 25 3.3333333333 +8 25 3.3333333333 10 25 3.3333333333 12 25 3.3333333333 +14 25 3.3333333333 16 25 3.3333333333 18 25 3.3333333333 +20 25 3.3333333333 0 27.5 3.3333333333 2 27.5 3.3333333333 +4 27.5 3.3333333333 6 27.5 3.3333333333 8 27.5 3.3333333333 +10 27.5 3.3333333333 12 27.5 3.3333333333 14 27.5 3.3333333333 +16 27.5 3.3333333333 18 27.5 3.3333333333 20 27.5 3.3333333333 +0 30 3.3333333333 2 30 3.3333333333 4 30 3.3333333333 +6 30 3.3333333333 8 30 3.3333333333 10 30 3.3333333333 +12 30 3.3333333333 14 30 3.3333333333 16 30 3.3333333333 +18 30 3.3333333333 20 30 3.3333333333 0 32.5 3.3333333333 +2 32.5 3.3333333333 4 32.5 3.3333333333 6 32.5 3.3333333333 +8 32.5 3.3333333333 10 32.5 3.3333333333 12 32.5 3.3333333333 +14 32.5 3.3333333333 16 32.5 3.3333333333 18 32.5 3.3333333333 +20 32.5 3.3333333333 0 35 3.3333333333 2 35 3.3333333333 +4 35 3.3333333333 6 35 3.3333333333 8 35 3.3333333333 +10 35 3.3333333333 12 35 3.3333333333 14 35 3.3333333333 +16 35 3.3333333333 18 35 3.3333333333 20 35 3.3333333333 +0 37.5 3.3333333333 2 37.5 3.3333333333 4 37.5 3.3333333333 +6 37.5 3.3333333333 8 37.5 3.3333333333 10 37.5 3.3333333333 +12 37.5 3.3333333333 14 37.5 3.3333333333 16 37.5 3.3333333333 +18 37.5 3.3333333333 20 37.5 3.3333333333 0 40 3.3333333333 +2 40 3.3333333333 4 40 3.3333333333 6 40 3.3333333333 +8 40 3.3333333333 10 40 3.3333333333 12 40 3.3333333333 +14 40 3.3333333333 16 40 3.3333333333 18 40 3.3333333333 +20 40 3.3333333333 0 42.5 3.3333333333 2 42.5 3.3333333333 +4 42.5 3.3333333333 6 42.5 3.3333333333 8 42.5 3.3333333333 +10 42.5 3.3333333333 12 42.5 3.3333333333 14 42.5 3.3333333333 +16 42.5 3.3333333333 18 42.5 3.3333333333 20 42.5 3.3333333333 +0 45 3.3333333333 2 45 3.3333333333 4 45 3.3333333333 +6 45 3.3333333333 8 45 3.3333333333 10 45 3.3333333333 +12 45 3.3333333333 14 45 3.3333333333 16 45 3.3333333333 +18 45 3.3333333333 20 45 3.3333333333 0 47.5 3.3333333333 +2 47.5 3.3333333333 4 47.5 3.3333333333 6 47.5 3.3333333333 +8 47.5 3.3333333333 10 47.5 3.3333333333 12 47.5 3.3333333333 +14 47.5 3.3333333333 16 47.5 3.3333333333 18 47.5 3.3333333333 +20 47.5 3.3333333333 0 50 3.3333333333 2 50 3.3333333333 +4 50 3.3333333333 6 50 3.3333333333 8 50 3.3333333333 +10 50 3.3333333333 12 50 3.3333333333 14 50 3.3333333333 +16 50 3.3333333333 18 50 3.3333333333 20 50 3.3333333333 +0 0 5 2 0 5 4 0 5 +6 0 5 8 0 5 10 0 5 +12 0 5 14 0 5 16 0 5 +18 0 5 20 0 5 0 2.5 5 +2 2.5 5 4 2.5 5 6 2.5 5 +8 2.5 5 10 2.5 5 12 2.5 5 +14 2.5 5 16 2.5 5 18 2.5 5 +20 2.5 5 0 5 5 2 5 5 +4 5 5 6 5 5 8 5 5 +10 5 5 12 5 5 14 5 5 +16 5 5 18 5 5 20 5 5 +0 7.5 5 2 7.5 5 4 7.5 5 +6 7.5 5 8 7.5 5 10 7.5 5 +12 7.5 5 14 7.5 5 16 7.5 5 +18 7.5 5 20 7.5 5 0 10 5 +2 10 5 4 10 5 6 10 5 +8 10 5 10 10 5 12 10 5 +14 10 5 16 10 5 18 10 5 +20 10 5 0 12.5 5 2 12.5 5 +4 12.5 5 6 12.5 5 8 12.5 5 +10 12.5 5 12 12.5 5 14 12.5 5 +16 12.5 5 18 12.5 5 20 12.5 5 +0 15 5 2 15 5 4 15 5 +6 15 5 8 15 5 10 15 5 +12 15 5 14 15 5 16 15 5 +18 15 5 20 15 5 0 17.5 5 +2 17.5 5 4 17.5 5 6 17.5 5 +8 17.5 5 10 17.5 5 12 17.5 5 +14 17.5 5 16 17.5 5 18 17.5 5 +20 17.5 5 0 20 5 2 20 5 +4 20 5 6 20 5 8 20 5 +10 20 5 12 20 5 14 20 5 +16 20 5 18 20 5 20 20 5 +0 22.5 5 2 22.5 5 4 22.5 5 +6 22.5 5 8 22.5 5 10 22.5 5 +12 22.5 5 14 22.5 5 16 22.5 5 +18 22.5 5 20 22.5 5 0 25 5 +2 25 5 4 25 5 6 25 5 +8 25 5 10 25 5 12 25 5 +14 25 5 16 25 5 18 25 5 +20 25 5 0 27.5 5 2 27.5 5 +4 27.5 5 6 27.5 5 8 27.5 5 +10 27.5 5 12 27.5 5 14 27.5 5 +16 27.5 5 18 27.5 5 20 27.5 5 +0 30 5 2 30 5 4 30 5 +6 30 5 8 30 5 10 30 5 +12 30 5 14 30 5 16 30 5 +18 30 5 20 30 5 0 32.5 5 +2 32.5 5 4 32.5 5 6 32.5 5 +8 32.5 5 10 32.5 5 12 32.5 5 +14 32.5 5 16 32.5 5 18 32.5 5 +20 32.5 5 0 35 5 2 35 5 +4 35 5 6 35 5 8 35 5 +10 35 5 12 35 5 14 35 5 +16 35 5 18 35 5 20 35 5 +0 37.5 5 2 37.5 5 4 37.5 5 +6 37.5 5 8 37.5 5 10 37.5 5 +12 37.5 5 14 37.5 5 16 37.5 5 +18 37.5 5 20 37.5 5 0 40 5 +2 40 5 4 40 5 6 40 5 +8 40 5 10 40 5 12 40 5 +14 40 5 16 40 5 18 40 5 +20 40 5 0 42.5 5 2 42.5 5 +4 42.5 5 6 42.5 5 8 42.5 5 +10 42.5 5 12 42.5 5 14 42.5 5 +16 42.5 5 18 42.5 5 20 42.5 5 +0 45 5 2 45 5 4 45 5 +6 45 5 8 45 5 10 45 5 +12 45 5 14 45 5 16 45 5 +18 45 5 20 45 5 0 47.5 5 +2 47.5 5 4 47.5 5 6 47.5 5 +8 47.5 5 10 47.5 5 12 47.5 5 +14 47.5 5 16 47.5 5 18 47.5 5 +20 47.5 5 0 50 5 2 50 5 +4 50 5 6 50 5 8 50 5 +10 50 5 12 50 5 14 50 5 +16 50 5 18 50 5 20 50 5 +0 0 6.6666666667 2 0 6.6666666667 4 0 6.6666666667 +6 0 6.6666666667 8 0 6.6666666667 10 0 6.6666666667 +12 0 6.6666666667 14 0 6.6666666667 16 0 6.6666666667 +18 0 6.6666666667 20 0 6.6666666667 0 2.5 6.6666666667 +2 2.5 6.6666666667 4 2.5 6.6666666667 6 2.5 6.6666666667 +8 2.5 6.6666666667 10 2.5 6.6666666667 12 2.5 6.6666666667 +14 2.5 6.6666666667 16 2.5 6.6666666667 18 2.5 6.6666666667 +20 2.5 6.6666666667 0 5 6.6666666667 2 5 6.6666666667 +4 5 6.6666666667 6 5 6.6666666667 8 5 6.6666666667 +10 5 6.6666666667 12 5 6.6666666667 14 5 6.6666666667 +16 5 6.6666666667 18 5 6.6666666667 20 5 6.6666666667 +0 7.5 6.6666666667 2 7.5 6.6666666667 4 7.5 6.6666666667 +6 7.5 6.6666666667 8 7.5 6.6666666667 10 7.5 6.6666666667 +12 7.5 6.6666666667 14 7.5 6.6666666667 16 7.5 6.6666666667 +18 7.5 6.6666666667 20 7.5 6.6666666667 0 10 6.6666666667 +2 10 6.6666666667 4 10 6.6666666667 6 10 6.6666666667 +8 10 6.6666666667 10 10 6.6666666667 12 10 6.6666666667 +14 10 6.6666666667 16 10 6.6666666667 18 10 6.6666666667 +20 10 6.6666666667 0 12.5 6.6666666667 2 12.5 6.6666666667 +4 12.5 6.6666666667 6 12.5 6.6666666667 8 12.5 6.6666666667 +10 12.5 6.6666666667 12 12.5 6.6666666667 14 12.5 6.6666666667 +16 12.5 6.6666666667 18 12.5 6.6666666667 20 12.5 6.6666666667 +0 15 6.6666666667 2 15 6.6666666667 4 15 6.6666666667 +6 15 6.6666666667 8 15 6.6666666667 10 15 6.6666666667 +12 15 6.6666666667 14 15 6.6666666667 16 15 6.6666666667 +18 15 6.6666666667 20 15 6.6666666667 0 17.5 6.6666666667 +2 17.5 6.6666666667 4 17.5 6.6666666667 6 17.5 6.6666666667 +8 17.5 6.6666666667 10 17.5 6.6666666667 12 17.5 6.6666666667 +14 17.5 6.6666666667 16 17.5 6.6666666667 18 17.5 6.6666666667 +20 17.5 6.6666666667 0 20 6.6666666667 2 20 6.6666666667 +4 20 6.6666666667 6 20 6.6666666667 8 20 6.6666666667 +10 20 6.6666666667 12 20 6.6666666667 14 20 6.6666666667 +16 20 6.6666666667 18 20 6.6666666667 20 20 6.6666666667 +0 22.5 6.6666666667 2 22.5 6.6666666667 4 22.5 6.6666666667 +6 22.5 6.6666666667 8 22.5 6.6666666667 10 22.5 6.6666666667 +12 22.5 6.6666666667 14 22.5 6.6666666667 16 22.5 6.6666666667 +18 22.5 6.6666666667 20 22.5 6.6666666667 0 25 6.6666666667 +2 25 6.6666666667 4 25 6.6666666667 6 25 6.6666666667 +8 25 6.6666666667 10 25 6.6666666667 12 25 6.6666666667 +14 25 6.6666666667 16 25 6.6666666667 18 25 6.6666666667 +20 25 6.6666666667 0 27.5 6.6666666667 2 27.5 6.6666666667 +4 27.5 6.6666666667 6 27.5 6.6666666667 8 27.5 6.6666666667 +10 27.5 6.6666666667 12 27.5 6.6666666667 14 27.5 6.6666666667 +16 27.5 6.6666666667 18 27.5 6.6666666667 20 27.5 6.6666666667 +0 30 6.6666666667 2 30 6.6666666667 4 30 6.6666666667 +6 30 6.6666666667 8 30 6.6666666667 10 30 6.6666666667 +12 30 6.6666666667 14 30 6.6666666667 16 30 6.6666666667 +18 30 6.6666666667 20 30 6.6666666667 0 32.5 6.6666666667 +2 32.5 6.6666666667 4 32.5 6.6666666667 6 32.5 6.6666666667 +8 32.5 6.6666666667 10 32.5 6.6666666667 12 32.5 6.6666666667 +14 32.5 6.6666666667 16 32.5 6.6666666667 18 32.5 6.6666666667 +20 32.5 6.6666666667 0 35 6.6666666667 2 35 6.6666666667 +4 35 6.6666666667 6 35 6.6666666667 8 35 6.6666666667 +10 35 6.6666666667 12 35 6.6666666667 14 35 6.6666666667 +16 35 6.6666666667 18 35 6.6666666667 20 35 6.6666666667 +0 37.5 6.6666666667 2 37.5 6.6666666667 4 37.5 6.6666666667 +6 37.5 6.6666666667 8 37.5 6.6666666667 10 37.5 6.6666666667 +12 37.5 6.6666666667 14 37.5 6.6666666667 16 37.5 6.6666666667 +18 37.5 6.6666666667 20 37.5 6.6666666667 0 40 6.6666666667 +2 40 6.6666666667 4 40 6.6666666667 6 40 6.6666666667 +8 40 6.6666666667 10 40 6.6666666667 12 40 6.6666666667 +14 40 6.6666666667 16 40 6.6666666667 18 40 6.6666666667 +20 40 6.6666666667 0 42.5 6.6666666667 2 42.5 6.6666666667 +4 42.5 6.6666666667 6 42.5 6.6666666667 8 42.5 6.6666666667 +10 42.5 6.6666666667 12 42.5 6.6666666667 14 42.5 6.6666666667 +16 42.5 6.6666666667 18 42.5 6.6666666667 20 42.5 6.6666666667 +0 45 6.6666666667 2 45 6.6666666667 4 45 6.6666666667 +6 45 6.6666666667 8 45 6.6666666667 10 45 6.6666666667 +12 45 6.6666666667 14 45 6.6666666667 16 45 6.6666666667 +18 45 6.6666666667 20 45 6.6666666667 0 47.5 6.6666666667 +2 47.5 6.6666666667 4 47.5 6.6666666667 6 47.5 6.6666666667 +8 47.5 6.6666666667 10 47.5 6.6666666667 12 47.5 6.6666666667 +14 47.5 6.6666666667 16 47.5 6.6666666667 18 47.5 6.6666666667 +20 47.5 6.6666666667 0 50 6.6666666667 2 50 6.6666666667 +4 50 6.6666666667 6 50 6.6666666667 8 50 6.6666666667 +10 50 6.6666666667 12 50 6.6666666667 14 50 6.6666666667 +16 50 6.6666666667 18 50 6.6666666667 20 50 6.6666666667 +0 0 8.3333333333 2 0 8.3333333333 4 0 8.3333333333 +6 0 8.3333333333 8 0 8.3333333333 10 0 8.3333333333 +12 0 8.3333333333 14 0 8.3333333333 16 0 8.3333333333 +18 0 8.3333333333 20 0 8.3333333333 0 2.5 8.3333333333 +2 2.5 8.3333333333 4 2.5 8.3333333333 6 2.5 8.3333333333 +8 2.5 8.3333333333 10 2.5 8.3333333333 12 2.5 8.3333333333 +14 2.5 8.3333333333 16 2.5 8.3333333333 18 2.5 8.3333333333 +20 2.5 8.3333333333 0 5 8.3333333333 2 5 8.3333333333 +4 5 8.3333333333 6 5 8.3333333333 8 5 8.3333333333 +10 5 8.3333333333 12 5 8.3333333333 14 5 8.3333333333 +16 5 8.3333333333 18 5 8.3333333333 20 5 8.3333333333 +0 7.5 8.3333333333 2 7.5 8.3333333333 4 7.5 8.3333333333 +6 7.5 8.3333333333 8 7.5 8.3333333333 10 7.5 8.3333333333 +12 7.5 8.3333333333 14 7.5 8.3333333333 16 7.5 8.3333333333 +18 7.5 8.3333333333 20 7.5 8.3333333333 0 10 8.3333333333 +2 10 8.3333333333 4 10 8.3333333333 6 10 8.3333333333 +8 10 8.3333333333 10 10 8.3333333333 12 10 8.3333333333 +14 10 8.3333333333 16 10 8.3333333333 18 10 8.3333333333 +20 10 8.3333333333 0 12.5 8.3333333333 2 12.5 8.3333333333 +4 12.5 8.3333333333 6 12.5 8.3333333333 8 12.5 8.3333333333 +10 12.5 8.3333333333 12 12.5 8.3333333333 14 12.5 8.3333333333 +16 12.5 8.3333333333 18 12.5 8.3333333333 20 12.5 8.3333333333 +0 15 8.3333333333 2 15 8.3333333333 4 15 8.3333333333 +6 15 8.3333333333 8 15 8.3333333333 10 15 8.3333333333 +12 15 8.3333333333 14 15 8.3333333333 16 15 8.3333333333 +18 15 8.3333333333 20 15 8.3333333333 0 17.5 8.3333333333 +2 17.5 8.3333333333 4 17.5 8.3333333333 6 17.5 8.3333333333 +8 17.5 8.3333333333 10 17.5 8.3333333333 12 17.5 8.3333333333 +14 17.5 8.3333333333 16 17.5 8.3333333333 18 17.5 8.3333333333 +20 17.5 8.3333333333 0 20 8.3333333333 2 20 8.3333333333 +4 20 8.3333333333 6 20 8.3333333333 8 20 8.3333333333 +10 20 8.3333333333 12 20 8.3333333333 14 20 8.3333333333 +16 20 8.3333333333 18 20 8.3333333333 20 20 8.3333333333 +0 22.5 8.3333333333 2 22.5 8.3333333333 4 22.5 8.3333333333 +6 22.5 8.3333333333 8 22.5 8.3333333333 10 22.5 8.3333333333 +12 22.5 8.3333333333 14 22.5 8.3333333333 16 22.5 8.3333333333 +18 22.5 8.3333333333 20 22.5 8.3333333333 0 25 8.3333333333 +2 25 8.3333333333 4 25 8.3333333333 6 25 8.3333333333 +8 25 8.3333333333 10 25 8.3333333333 12 25 8.3333333333 +14 25 8.3333333333 16 25 8.3333333333 18 25 8.3333333333 +20 25 8.3333333333 0 27.5 8.3333333333 2 27.5 8.3333333333 +4 27.5 8.3333333333 6 27.5 8.3333333333 8 27.5 8.3333333333 +10 27.5 8.3333333333 12 27.5 8.3333333333 14 27.5 8.3333333333 +16 27.5 8.3333333333 18 27.5 8.3333333333 20 27.5 8.3333333333 +0 30 8.3333333333 2 30 8.3333333333 4 30 8.3333333333 +6 30 8.3333333333 8 30 8.3333333333 10 30 8.3333333333 +12 30 8.3333333333 14 30 8.3333333333 16 30 8.3333333333 +18 30 8.3333333333 20 30 8.3333333333 0 32.5 8.3333333333 +2 32.5 8.3333333333 4 32.5 8.3333333333 6 32.5 8.3333333333 +8 32.5 8.3333333333 10 32.5 8.3333333333 12 32.5 8.3333333333 +14 32.5 8.3333333333 16 32.5 8.3333333333 18 32.5 8.3333333333 +20 32.5 8.3333333333 0 35 8.3333333333 2 35 8.3333333333 +4 35 8.3333333333 6 35 8.3333333333 8 35 8.3333333333 +10 35 8.3333333333 12 35 8.3333333333 14 35 8.3333333333 +16 35 8.3333333333 18 35 8.3333333333 20 35 8.3333333333 +0 37.5 8.3333333333 2 37.5 8.3333333333 4 37.5 8.3333333333 +6 37.5 8.3333333333 8 37.5 8.3333333333 10 37.5 8.3333333333 +12 37.5 8.3333333333 14 37.5 8.3333333333 16 37.5 8.3333333333 +18 37.5 8.3333333333 20 37.5 8.3333333333 0 40 8.3333333333 +2 40 8.3333333333 4 40 8.3333333333 6 40 8.3333333333 +8 40 8.3333333333 10 40 8.3333333333 12 40 8.3333333333 +14 40 8.3333333333 16 40 8.3333333333 18 40 8.3333333333 +20 40 8.3333333333 0 42.5 8.3333333333 2 42.5 8.3333333333 +4 42.5 8.3333333333 6 42.5 8.3333333333 8 42.5 8.3333333333 +10 42.5 8.3333333333 12 42.5 8.3333333333 14 42.5 8.3333333333 +16 42.5 8.3333333333 18 42.5 8.3333333333 20 42.5 8.3333333333 +0 45 8.3333333333 2 45 8.3333333333 4 45 8.3333333333 +6 45 8.3333333333 8 45 8.3333333333 10 45 8.3333333333 +12 45 8.3333333333 14 45 8.3333333333 16 45 8.3333333333 +18 45 8.3333333333 20 45 8.3333333333 0 47.5 8.3333333333 +2 47.5 8.3333333333 4 47.5 8.3333333333 6 47.5 8.3333333333 +8 47.5 8.3333333333 10 47.5 8.3333333333 12 47.5 8.3333333333 +14 47.5 8.3333333333 16 47.5 8.3333333333 18 47.5 8.3333333333 +20 47.5 8.3333333333 0 50 8.3333333333 2 50 8.3333333333 +4 50 8.3333333333 6 50 8.3333333333 8 50 8.3333333333 +10 50 8.3333333333 12 50 8.3333333333 14 50 8.3333333333 +16 50 8.3333333333 18 50 8.3333333333 20 50 8.3333333333 +0 0 10 2 0 10 4 0 10 +6 0 10 8 0 10 10 0 10 +12 0 10 14 0 10 16 0 10 +18 0 10 20 0 10 0 2.5 10 +2 2.5 10 4 2.5 10 6 2.5 10 +8 2.5 10 10 2.5 10 12 2.5 10 +14 2.5 10 16 2.5 10 18 2.5 10 +20 2.5 10 0 5 10 2 5 10 +4 5 10 6 5 10 8 5 10 +10 5 10 12 5 10 14 5 10 +16 5 10 18 5 10 20 5 10 +0 7.5 10 2 7.5 10 4 7.5 10 +6 7.5 10 8 7.5 10 10 7.5 10 +12 7.5 10 14 7.5 10 16 7.5 10 +18 7.5 10 20 7.5 10 0 10 10 +2 10 10 4 10 10 6 10 10 +8 10 10 10 10 10 12 10 10 +14 10 10 16 10 10 18 10 10 +20 10 10 0 12.5 10 2 12.5 10 +4 12.5 10 6 12.5 10 8 12.5 10 +10 12.5 10 12 12.5 10 14 12.5 10 +16 12.5 10 18 12.5 10 20 12.5 10 +0 15 10 2 15 10 4 15 10 +6 15 10 8 15 10 10 15 10 +12 15 10 14 15 10 16 15 10 +18 15 10 20 15 10 0 17.5 10 +2 17.5 10 4 17.5 10 6 17.5 10 +8 17.5 10 10 17.5 10 12 17.5 10 +14 17.5 10 16 17.5 10 18 17.5 10 +20 17.5 10 0 20 10 2 20 10 +4 20 10 6 20 10 8 20 10 +10 20 10 12 20 10 14 20 10 +16 20 10 18 20 10 20 20 10 +0 22.5 10 2 22.5 10 4 22.5 10 +6 22.5 10 8 22.5 10 10 22.5 10 +12 22.5 10 14 22.5 10 16 22.5 10 +18 22.5 10 20 22.5 10 0 25 10 +2 25 10 4 25 10 6 25 10 +8 25 10 10 25 10 12 25 10 +14 25 10 16 25 10 18 25 10 +20 25 10 0 27.5 10 2 27.5 10 +4 27.5 10 6 27.5 10 8 27.5 10 +10 27.5 10 12 27.5 10 14 27.5 10 +16 27.5 10 18 27.5 10 20 27.5 10 +0 30 10 2 30 10 4 30 10 +6 30 10 8 30 10 10 30 10 +12 30 10 14 30 10 16 30 10 +18 30 10 20 30 10 0 32.5 10 +2 32.5 10 4 32.5 10 6 32.5 10 +8 32.5 10 10 32.5 10 12 32.5 10 +14 32.5 10 16 32.5 10 18 32.5 10 +20 32.5 10 0 35 10 2 35 10 +4 35 10 6 35 10 8 35 10 +10 35 10 12 35 10 14 35 10 +16 35 10 18 35 10 20 35 10 +0 37.5 10 2 37.5 10 4 37.5 10 +6 37.5 10 8 37.5 10 10 37.5 10 +12 37.5 10 14 37.5 10 16 37.5 10 +18 37.5 10 20 37.5 10 0 40 10 +2 40 10 4 40 10 6 40 10 +8 40 10 10 40 10 12 40 10 +14 40 10 16 40 10 18 40 10 +20 40 10 0 42.5 10 2 42.5 10 +4 42.5 10 6 42.5 10 8 42.5 10 +10 42.5 10 12 42.5 10 14 42.5 10 +16 42.5 10 18 42.5 10 20 42.5 10 +0 45 10 2 45 10 4 45 10 +6 45 10 8 45 10 10 45 10 +12 45 10 14 45 10 16 45 10 +18 45 10 20 45 10 0 47.5 10 +2 47.5 10 4 47.5 10 6 47.5 10 +8 47.5 10 10 47.5 10 12 47.5 10 +14 47.5 10 16 47.5 10 18 47.5 10 +20 47.5 10 0 50 10 2 50 10 +4 50 10 6 50 10 8 50 10 +10 50 10 12 50 10 14 50 10 +16 50 10 18 50 10 20 50 10 +0 0 11.666666667 2 0 11.666666667 4 0 11.666666667 +6 0 11.666666667 8 0 11.666666667 10 0 11.666666667 +12 0 11.666666667 14 0 11.666666667 16 0 11.666666667 +18 0 11.666666667 20 0 11.666666667 0 2.5 11.666666667 +2 2.5 11.666666667 4 2.5 11.666666667 6 2.5 11.666666667 +8 2.5 11.666666667 10 2.5 11.666666667 12 2.5 11.666666667 +14 2.5 11.666666667 16 2.5 11.666666667 18 2.5 11.666666667 +20 2.5 11.666666667 0 5 11.666666667 2 5 11.666666667 +4 5 11.666666667 6 5 11.666666667 8 5 11.666666667 +10 5 11.666666667 12 5 11.666666667 14 5 11.666666667 +16 5 11.666666667 18 5 11.666666667 20 5 11.666666667 +0 7.5 11.666666667 2 7.5 11.666666667 4 7.5 11.666666667 +6 7.5 11.666666667 8 7.5 11.666666667 10 7.5 11.666666667 +12 7.5 11.666666667 14 7.5 11.666666667 16 7.5 11.666666667 +18 7.5 11.666666667 20 7.5 11.666666667 0 10 11.666666667 +2 10 11.666666667 4 10 11.666666667 6 10 11.666666667 +8 10 11.666666667 10 10 11.666666667 12 10 11.666666667 +14 10 11.666666667 16 10 11.666666667 18 10 11.666666667 +20 10 11.666666667 0 12.5 11.666666667 2 12.5 11.666666667 +4 12.5 11.666666667 6 12.5 11.666666667 8 12.5 11.666666667 +10 12.5 11.666666667 12 12.5 11.666666667 14 12.5 11.666666667 +16 12.5 11.666666667 18 12.5 11.666666667 20 12.5 11.666666667 +0 15 11.666666667 2 15 11.666666667 4 15 11.666666667 +6 15 11.666666667 8 15 11.666666667 10 15 11.666666667 +12 15 11.666666667 14 15 11.666666667 16 15 11.666666667 +18 15 11.666666667 20 15 11.666666667 0 17.5 11.666666667 +2 17.5 11.666666667 4 17.5 11.666666667 6 17.5 11.666666667 +8 17.5 11.666666667 10 17.5 11.666666667 12 17.5 11.666666667 +14 17.5 11.666666667 16 17.5 11.666666667 18 17.5 11.666666667 +20 17.5 11.666666667 0 20 11.666666667 2 20 11.666666667 +4 20 11.666666667 6 20 11.666666667 8 20 11.666666667 +10 20 11.666666667 12 20 11.666666667 14 20 11.666666667 +16 20 11.666666667 18 20 11.666666667 20 20 11.666666667 +0 22.5 11.666666667 2 22.5 11.666666667 4 22.5 11.666666667 +6 22.5 11.666666667 8 22.5 11.666666667 10 22.5 11.666666667 +12 22.5 11.666666667 14 22.5 11.666666667 16 22.5 11.666666667 +18 22.5 11.666666667 20 22.5 11.666666667 0 25 11.666666667 +2 25 11.666666667 4 25 11.666666667 6 25 11.666666667 +8 25 11.666666667 10 25 11.666666667 12 25 11.666666667 +14 25 11.666666667 16 25 11.666666667 18 25 11.666666667 +20 25 11.666666667 0 27.5 11.666666667 2 27.5 11.666666667 +4 27.5 11.666666667 6 27.5 11.666666667 8 27.5 11.666666667 +10 27.5 11.666666667 12 27.5 11.666666667 14 27.5 11.666666667 +16 27.5 11.666666667 18 27.5 11.666666667 20 27.5 11.666666667 +0 30 11.666666667 2 30 11.666666667 4 30 11.666666667 +6 30 11.666666667 8 30 11.666666667 10 30 11.666666667 +12 30 11.666666667 14 30 11.666666667 16 30 11.666666667 +18 30 11.666666667 20 30 11.666666667 0 32.5 11.666666667 +2 32.5 11.666666667 4 32.5 11.666666667 6 32.5 11.666666667 +8 32.5 11.666666667 10 32.5 11.666666667 12 32.5 11.666666667 +14 32.5 11.666666667 16 32.5 11.666666667 18 32.5 11.666666667 +20 32.5 11.666666667 0 35 11.666666667 2 35 11.666666667 +4 35 11.666666667 6 35 11.666666667 8 35 11.666666667 +10 35 11.666666667 12 35 11.666666667 14 35 11.666666667 +16 35 11.666666667 18 35 11.666666667 20 35 11.666666667 +0 37.5 11.666666667 2 37.5 11.666666667 4 37.5 11.666666667 +6 37.5 11.666666667 8 37.5 11.666666667 10 37.5 11.666666667 +12 37.5 11.666666667 14 37.5 11.666666667 16 37.5 11.666666667 +18 37.5 11.666666667 20 37.5 11.666666667 0 40 11.666666667 +2 40 11.666666667 4 40 11.666666667 6 40 11.666666667 +8 40 11.666666667 10 40 11.666666667 12 40 11.666666667 +14 40 11.666666667 16 40 11.666666667 18 40 11.666666667 +20 40 11.666666667 0 42.5 11.666666667 2 42.5 11.666666667 +4 42.5 11.666666667 6 42.5 11.666666667 8 42.5 11.666666667 +10 42.5 11.666666667 12 42.5 11.666666667 14 42.5 11.666666667 +16 42.5 11.666666667 18 42.5 11.666666667 20 42.5 11.666666667 +0 45 11.666666667 2 45 11.666666667 4 45 11.666666667 +6 45 11.666666667 8 45 11.666666667 10 45 11.666666667 +12 45 11.666666667 14 45 11.666666667 16 45 11.666666667 +18 45 11.666666667 20 45 11.666666667 0 47.5 11.666666667 +2 47.5 11.666666667 4 47.5 11.666666667 6 47.5 11.666666667 +8 47.5 11.666666667 10 47.5 11.666666667 12 47.5 11.666666667 +14 47.5 11.666666667 16 47.5 11.666666667 18 47.5 11.666666667 +20 47.5 11.666666667 0 50 11.666666667 2 50 11.666666667 +4 50 11.666666667 6 50 11.666666667 8 50 11.666666667 +10 50 11.666666667 12 50 11.666666667 14 50 11.666666667 +16 50 11.666666667 18 50 11.666666667 20 50 11.666666667 +0 0 13.333333333 2 0 13.333333333 4 0 13.333333333 +6 0 13.333333333 8 0 13.333333333 10 0 13.333333333 +12 0 13.333333333 14 0 13.333333333 16 0 13.333333333 +18 0 13.333333333 20 0 13.333333333 0 2.5 13.333333333 +2 2.5 13.333333333 4 2.5 13.333333333 6 2.5 13.333333333 +8 2.5 13.333333333 10 2.5 13.333333333 12 2.5 13.333333333 +14 2.5 13.333333333 16 2.5 13.333333333 18 2.5 13.333333333 +20 2.5 13.333333333 0 5 13.333333333 2 5 13.333333333 +4 5 13.333333333 6 5 13.333333333 8 5 13.333333333 +10 5 13.333333333 12 5 13.333333333 14 5 13.333333333 +16 5 13.333333333 18 5 13.333333333 20 5 13.333333333 +0 7.5 13.333333333 2 7.5 13.333333333 4 7.5 13.333333333 +6 7.5 13.333333333 8 7.5 13.333333333 10 7.5 13.333333333 +12 7.5 13.333333333 14 7.5 13.333333333 16 7.5 13.333333333 +18 7.5 13.333333333 20 7.5 13.333333333 0 10 13.333333333 +2 10 13.333333333 4 10 13.333333333 6 10 13.333333333 +8 10 13.333333333 10 10 13.333333333 12 10 13.333333333 +14 10 13.333333333 16 10 13.333333333 18 10 13.333333333 +20 10 13.333333333 0 12.5 13.333333333 2 12.5 13.333333333 +4 12.5 13.333333333 6 12.5 13.333333333 8 12.5 13.333333333 +10 12.5 13.333333333 12 12.5 13.333333333 14 12.5 13.333333333 +16 12.5 13.333333333 18 12.5 13.333333333 20 12.5 13.333333333 +0 15 13.333333333 2 15 13.333333333 4 15 13.333333333 +6 15 13.333333333 8 15 13.333333333 10 15 13.333333333 +12 15 13.333333333 14 15 13.333333333 16 15 13.333333333 +18 15 13.333333333 20 15 13.333333333 0 17.5 13.333333333 +2 17.5 13.333333333 4 17.5 13.333333333 6 17.5 13.333333333 +8 17.5 13.333333333 10 17.5 13.333333333 12 17.5 13.333333333 +14 17.5 13.333333333 16 17.5 13.333333333 18 17.5 13.333333333 +20 17.5 13.333333333 0 20 13.333333333 2 20 13.333333333 +4 20 13.333333333 6 20 13.333333333 8 20 13.333333333 +10 20 13.333333333 12 20 13.333333333 14 20 13.333333333 +16 20 13.333333333 18 20 13.333333333 20 20 13.333333333 +0 22.5 13.333333333 2 22.5 13.333333333 4 22.5 13.333333333 +6 22.5 13.333333333 8 22.5 13.333333333 10 22.5 13.333333333 +12 22.5 13.333333333 14 22.5 13.333333333 16 22.5 13.333333333 +18 22.5 13.333333333 20 22.5 13.333333333 0 25 13.333333333 +2 25 13.333333333 4 25 13.333333333 6 25 13.333333333 +8 25 13.333333333 10 25 13.333333333 12 25 13.333333333 +14 25 13.333333333 16 25 13.333333333 18 25 13.333333333 +20 25 13.333333333 0 27.5 13.333333333 2 27.5 13.333333333 +4 27.5 13.333333333 6 27.5 13.333333333 8 27.5 13.333333333 +10 27.5 13.333333333 12 27.5 13.333333333 14 27.5 13.333333333 +16 27.5 13.333333333 18 27.5 13.333333333 20 27.5 13.333333333 +0 30 13.333333333 2 30 13.333333333 4 30 13.333333333 +6 30 13.333333333 8 30 13.333333333 10 30 13.333333333 +12 30 13.333333333 14 30 13.333333333 16 30 13.333333333 +18 30 13.333333333 20 30 13.333333333 0 32.5 13.333333333 +2 32.5 13.333333333 4 32.5 13.333333333 6 32.5 13.333333333 +8 32.5 13.333333333 10 32.5 13.333333333 12 32.5 13.333333333 +14 32.5 13.333333333 16 32.5 13.333333333 18 32.5 13.333333333 +20 32.5 13.333333333 0 35 13.333333333 2 35 13.333333333 +4 35 13.333333333 6 35 13.333333333 8 35 13.333333333 +10 35 13.333333333 12 35 13.333333333 14 35 13.333333333 +16 35 13.333333333 18 35 13.333333333 20 35 13.333333333 +0 37.5 13.333333333 2 37.5 13.333333333 4 37.5 13.333333333 +6 37.5 13.333333333 8 37.5 13.333333333 10 37.5 13.333333333 +12 37.5 13.333333333 14 37.5 13.333333333 16 37.5 13.333333333 +18 37.5 13.333333333 20 37.5 13.333333333 0 40 13.333333333 +2 40 13.333333333 4 40 13.333333333 6 40 13.333333333 +8 40 13.333333333 10 40 13.333333333 12 40 13.333333333 +14 40 13.333333333 16 40 13.333333333 18 40 13.333333333 +20 40 13.333333333 0 42.5 13.333333333 2 42.5 13.333333333 +4 42.5 13.333333333 6 42.5 13.333333333 8 42.5 13.333333333 +10 42.5 13.333333333 12 42.5 13.333333333 14 42.5 13.333333333 +16 42.5 13.333333333 18 42.5 13.333333333 20 42.5 13.333333333 +0 45 13.333333333 2 45 13.333333333 4 45 13.333333333 +6 45 13.333333333 8 45 13.333333333 10 45 13.333333333 +12 45 13.333333333 14 45 13.333333333 16 45 13.333333333 +18 45 13.333333333 20 45 13.333333333 0 47.5 13.333333333 +2 47.5 13.333333333 4 47.5 13.333333333 6 47.5 13.333333333 +8 47.5 13.333333333 10 47.5 13.333333333 12 47.5 13.333333333 +14 47.5 13.333333333 16 47.5 13.333333333 18 47.5 13.333333333 +20 47.5 13.333333333 0 50 13.333333333 2 50 13.333333333 +4 50 13.333333333 6 50 13.333333333 8 50 13.333333333 +10 50 13.333333333 12 50 13.333333333 14 50 13.333333333 +16 50 13.333333333 18 50 13.333333333 20 50 13.333333333 +0 0 15 2 0 15 4 0 15 +6 0 15 8 0 15 10 0 15 +12 0 15 14 0 15 16 0 15 +18 0 15 20 0 15 0 2.5 15 +2 2.5 15 4 2.5 15 6 2.5 15 +8 2.5 15 10 2.5 15 12 2.5 15 +14 2.5 15 16 2.5 15 18 2.5 15 +20 2.5 15 0 5 15 2 5 15 +4 5 15 6 5 15 8 5 15 +10 5 15 12 5 15 14 5 15 +16 5 15 18 5 15 20 5 15 +0 7.5 15 2 7.5 15 4 7.5 15 +6 7.5 15 8 7.5 15 10 7.5 15 +12 7.5 15 14 7.5 15 16 7.5 15 +18 7.5 15 20 7.5 15 0 10 15 +2 10 15 4 10 15 6 10 15 +8 10 15 10 10 15 12 10 15 +14 10 15 16 10 15 18 10 15 +20 10 15 0 12.5 15 2 12.5 15 +4 12.5 15 6 12.5 15 8 12.5 15 +10 12.5 15 12 12.5 15 14 12.5 15 +16 12.5 15 18 12.5 15 20 12.5 15 +0 15 15 2 15 15 4 15 15 +6 15 15 8 15 15 10 15 15 +12 15 15 14 15 15 16 15 15 +18 15 15 20 15 15 0 17.5 15 +2 17.5 15 4 17.5 15 6 17.5 15 +8 17.5 15 10 17.5 15 12 17.5 15 +14 17.5 15 16 17.5 15 18 17.5 15 +20 17.5 15 0 20 15 2 20 15 +4 20 15 6 20 15 8 20 15 +10 20 15 12 20 15 14 20 15 +16 20 15 18 20 15 20 20 15 +0 22.5 15 2 22.5 15 4 22.5 15 +6 22.5 15 8 22.5 15 10 22.5 15 +12 22.5 15 14 22.5 15 16 22.5 15 +18 22.5 15 20 22.5 15 0 25 15 +2 25 15 4 25 15 6 25 15 +8 25 15 10 25 15 12 25 15 +14 25 15 16 25 15 18 25 15 +20 25 15 0 27.5 15 2 27.5 15 +4 27.5 15 6 27.5 15 8 27.5 15 +10 27.5 15 12 27.5 15 14 27.5 15 +16 27.5 15 18 27.5 15 20 27.5 15 +0 30 15 2 30 15 4 30 15 +6 30 15 8 30 15 10 30 15 +12 30 15 14 30 15 16 30 15 +18 30 15 20 30 15 0 32.5 15 +2 32.5 15 4 32.5 15 6 32.5 15 +8 32.5 15 10 32.5 15 12 32.5 15 +14 32.5 15 16 32.5 15 18 32.5 15 +20 32.5 15 0 35 15 2 35 15 +4 35 15 6 35 15 8 35 15 +10 35 15 12 35 15 14 35 15 +16 35 15 18 35 15 20 35 15 +0 37.5 15 2 37.5 15 4 37.5 15 +6 37.5 15 8 37.5 15 10 37.5 15 +12 37.5 15 14 37.5 15 16 37.5 15 +18 37.5 15 20 37.5 15 0 40 15 +2 40 15 4 40 15 6 40 15 +8 40 15 10 40 15 12 40 15 +14 40 15 16 40 15 18 40 15 +20 40 15 0 42.5 15 2 42.5 15 +4 42.5 15 6 42.5 15 8 42.5 15 +10 42.5 15 12 42.5 15 14 42.5 15 +16 42.5 15 18 42.5 15 20 42.5 15 +0 45 15 2 45 15 4 45 15 +6 45 15 8 45 15 10 45 15 +12 45 15 14 45 15 16 45 15 +18 45 15 20 45 15 0 47.5 15 +2 47.5 15 4 47.5 15 6 47.5 15 +8 47.5 15 10 47.5 15 12 47.5 15 +14 47.5 15 16 47.5 15 18 47.5 15 +20 47.5 15 0 50 15 2 50 15 +4 50 15 6 50 15 8 50 15 +10 50 15 12 50 15 14 50 15 +16 50 15 18 50 15 20 50 15 +0 0 16.666666667 2 0 16.666666667 4 0 16.666666667 +6 0 16.666666667 8 0 16.666666667 10 0 16.666666667 +12 0 16.666666667 14 0 16.666666667 16 0 16.666666667 +18 0 16.666666667 20 0 16.666666667 0 2.5 16.666666667 +2 2.5 16.666666667 4 2.5 16.666666667 6 2.5 16.666666667 +8 2.5 16.666666667 10 2.5 16.666666667 12 2.5 16.666666667 +14 2.5 16.666666667 16 2.5 16.666666667 18 2.5 16.666666667 +20 2.5 16.666666667 0 5 16.666666667 2 5 16.666666667 +4 5 16.666666667 6 5 16.666666667 8 5 16.666666667 +10 5 16.666666667 12 5 16.666666667 14 5 16.666666667 +16 5 16.666666667 18 5 16.666666667 20 5 16.666666667 +0 7.5 16.666666667 2 7.5 16.666666667 4 7.5 16.666666667 +6 7.5 16.666666667 8 7.5 16.666666667 10 7.5 16.666666667 +12 7.5 16.666666667 14 7.5 16.666666667 16 7.5 16.666666667 +18 7.5 16.666666667 20 7.5 16.666666667 0 10 16.666666667 +2 10 16.666666667 4 10 16.666666667 6 10 16.666666667 +8 10 16.666666667 10 10 16.666666667 12 10 16.666666667 +14 10 16.666666667 16 10 16.666666667 18 10 16.666666667 +20 10 16.666666667 0 12.5 16.666666667 2 12.5 16.666666667 +4 12.5 16.666666667 6 12.5 16.666666667 8 12.5 16.666666667 +10 12.5 16.666666667 12 12.5 16.666666667 14 12.5 16.666666667 +16 12.5 16.666666667 18 12.5 16.666666667 20 12.5 16.666666667 +0 15 16.666666667 2 15 16.666666667 4 15 16.666666667 +6 15 16.666666667 8 15 16.666666667 10 15 16.666666667 +12 15 16.666666667 14 15 16.666666667 16 15 16.666666667 +18 15 16.666666667 20 15 16.666666667 0 17.5 16.666666667 +2 17.5 16.666666667 4 17.5 16.666666667 6 17.5 16.666666667 +8 17.5 16.666666667 10 17.5 16.666666667 12 17.5 16.666666667 +14 17.5 16.666666667 16 17.5 16.666666667 18 17.5 16.666666667 +20 17.5 16.666666667 0 20 16.666666667 2 20 16.666666667 +4 20 16.666666667 6 20 16.666666667 8 20 16.666666667 +10 20 16.666666667 12 20 16.666666667 14 20 16.666666667 +16 20 16.666666667 18 20 16.666666667 20 20 16.666666667 +0 22.5 16.666666667 2 22.5 16.666666667 4 22.5 16.666666667 +6 22.5 16.666666667 8 22.5 16.666666667 10 22.5 16.666666667 +12 22.5 16.666666667 14 22.5 16.666666667 16 22.5 16.666666667 +18 22.5 16.666666667 20 22.5 16.666666667 0 25 16.666666667 +2 25 16.666666667 4 25 16.666666667 6 25 16.666666667 +8 25 16.666666667 10 25 16.666666667 12 25 16.666666667 +14 25 16.666666667 16 25 16.666666667 18 25 16.666666667 +20 25 16.666666667 0 27.5 16.666666667 2 27.5 16.666666667 +4 27.5 16.666666667 6 27.5 16.666666667 8 27.5 16.666666667 +10 27.5 16.666666667 12 27.5 16.666666667 14 27.5 16.666666667 +16 27.5 16.666666667 18 27.5 16.666666667 20 27.5 16.666666667 +0 30 16.666666667 2 30 16.666666667 4 30 16.666666667 +6 30 16.666666667 8 30 16.666666667 10 30 16.666666667 +12 30 16.666666667 14 30 16.666666667 16 30 16.666666667 +18 30 16.666666667 20 30 16.666666667 0 32.5 16.666666667 +2 32.5 16.666666667 4 32.5 16.666666667 6 32.5 16.666666667 +8 32.5 16.666666667 10 32.5 16.666666667 12 32.5 16.666666667 +14 32.5 16.666666667 16 32.5 16.666666667 18 32.5 16.666666667 +20 32.5 16.666666667 0 35 16.666666667 2 35 16.666666667 +4 35 16.666666667 6 35 16.666666667 8 35 16.666666667 +10 35 16.666666667 12 35 16.666666667 14 35 16.666666667 +16 35 16.666666667 18 35 16.666666667 20 35 16.666666667 +0 37.5 16.666666667 2 37.5 16.666666667 4 37.5 16.666666667 +6 37.5 16.666666667 8 37.5 16.666666667 10 37.5 16.666666667 +12 37.5 16.666666667 14 37.5 16.666666667 16 37.5 16.666666667 +18 37.5 16.666666667 20 37.5 16.666666667 0 40 16.666666667 +2 40 16.666666667 4 40 16.666666667 6 40 16.666666667 +8 40 16.666666667 10 40 16.666666667 12 40 16.666666667 +14 40 16.666666667 16 40 16.666666667 18 40 16.666666667 +20 40 16.666666667 0 42.5 16.666666667 2 42.5 16.666666667 +4 42.5 16.666666667 6 42.5 16.666666667 8 42.5 16.666666667 +10 42.5 16.666666667 12 42.5 16.666666667 14 42.5 16.666666667 +16 42.5 16.666666667 18 42.5 16.666666667 20 42.5 16.666666667 +0 45 16.666666667 2 45 16.666666667 4 45 16.666666667 +6 45 16.666666667 8 45 16.666666667 10 45 16.666666667 +12 45 16.666666667 14 45 16.666666667 16 45 16.666666667 +18 45 16.666666667 20 45 16.666666667 0 47.5 16.666666667 +2 47.5 16.666666667 4 47.5 16.666666667 6 47.5 16.666666667 +8 47.5 16.666666667 10 47.5 16.666666667 12 47.5 16.666666667 +14 47.5 16.666666667 16 47.5 16.666666667 18 47.5 16.666666667 +20 47.5 16.666666667 0 50 16.666666667 2 50 16.666666667 +4 50 16.666666667 6 50 16.666666667 8 50 16.666666667 +10 50 16.666666667 12 50 16.666666667 14 50 16.666666667 +16 50 16.666666667 18 50 16.666666667 20 50 16.666666667 +0 0 18.333333333 2 0 18.333333333 4 0 18.333333333 +6 0 18.333333333 8 0 18.333333333 10 0 18.333333333 +12 0 18.333333333 14 0 18.333333333 16 0 18.333333333 +18 0 18.333333333 20 0 18.333333333 0 2.5 18.333333333 +2 2.5 18.333333333 4 2.5 18.333333333 6 2.5 18.333333333 +8 2.5 18.333333333 10 2.5 18.333333333 12 2.5 18.333333333 +14 2.5 18.333333333 16 2.5 18.333333333 18 2.5 18.333333333 +20 2.5 18.333333333 0 5 18.333333333 2 5 18.333333333 +4 5 18.333333333 6 5 18.333333333 8 5 18.333333333 +10 5 18.333333333 12 5 18.333333333 14 5 18.333333333 +16 5 18.333333333 18 5 18.333333333 20 5 18.333333333 +0 7.5 18.333333333 2 7.5 18.333333333 4 7.5 18.333333333 +6 7.5 18.333333333 8 7.5 18.333333333 10 7.5 18.333333333 +12 7.5 18.333333333 14 7.5 18.333333333 16 7.5 18.333333333 +18 7.5 18.333333333 20 7.5 18.333333333 0 10 18.333333333 +2 10 18.333333333 4 10 18.333333333 6 10 18.333333333 +8 10 18.333333333 10 10 18.333333333 12 10 18.333333333 +14 10 18.333333333 16 10 18.333333333 18 10 18.333333333 +20 10 18.333333333 0 12.5 18.333333333 2 12.5 18.333333333 +4 12.5 18.333333333 6 12.5 18.333333333 8 12.5 18.333333333 +10 12.5 18.333333333 12 12.5 18.333333333 14 12.5 18.333333333 +16 12.5 18.333333333 18 12.5 18.333333333 20 12.5 18.333333333 +0 15 18.333333333 2 15 18.333333333 4 15 18.333333333 +6 15 18.333333333 8 15 18.333333333 10 15 18.333333333 +12 15 18.333333333 14 15 18.333333333 16 15 18.333333333 +18 15 18.333333333 20 15 18.333333333 0 17.5 18.333333333 +2 17.5 18.333333333 4 17.5 18.333333333 6 17.5 18.333333333 +8 17.5 18.333333333 10 17.5 18.333333333 12 17.5 18.333333333 +14 17.5 18.333333333 16 17.5 18.333333333 18 17.5 18.333333333 +20 17.5 18.333333333 0 20 18.333333333 2 20 18.333333333 +4 20 18.333333333 6 20 18.333333333 8 20 18.333333333 +10 20 18.333333333 12 20 18.333333333 14 20 18.333333333 +16 20 18.333333333 18 20 18.333333333 20 20 18.333333333 +0 22.5 18.333333333 2 22.5 18.333333333 4 22.5 18.333333333 +6 22.5 18.333333333 8 22.5 18.333333333 10 22.5 18.333333333 +12 22.5 18.333333333 14 22.5 18.333333333 16 22.5 18.333333333 +18 22.5 18.333333333 20 22.5 18.333333333 0 25 18.333333333 +2 25 18.333333333 4 25 18.333333333 6 25 18.333333333 +8 25 18.333333333 10 25 18.333333333 12 25 18.333333333 +14 25 18.333333333 16 25 18.333333333 18 25 18.333333333 +20 25 18.333333333 0 27.5 18.333333333 2 27.5 18.333333333 +4 27.5 18.333333333 6 27.5 18.333333333 8 27.5 18.333333333 +10 27.5 18.333333333 12 27.5 18.333333333 14 27.5 18.333333333 +16 27.5 18.333333333 18 27.5 18.333333333 20 27.5 18.333333333 +0 30 18.333333333 2 30 18.333333333 4 30 18.333333333 +6 30 18.333333333 8 30 18.333333333 10 30 18.333333333 +12 30 18.333333333 14 30 18.333333333 16 30 18.333333333 +18 30 18.333333333 20 30 18.333333333 0 32.5 18.333333333 +2 32.5 18.333333333 4 32.5 18.333333333 6 32.5 18.333333333 +8 32.5 18.333333333 10 32.5 18.333333333 12 32.5 18.333333333 +14 32.5 18.333333333 16 32.5 18.333333333 18 32.5 18.333333333 +20 32.5 18.333333333 0 35 18.333333333 2 35 18.333333333 +4 35 18.333333333 6 35 18.333333333 8 35 18.333333333 +10 35 18.333333333 12 35 18.333333333 14 35 18.333333333 +16 35 18.333333333 18 35 18.333333333 20 35 18.333333333 +0 37.5 18.333333333 2 37.5 18.333333333 4 37.5 18.333333333 +6 37.5 18.333333333 8 37.5 18.333333333 10 37.5 18.333333333 +12 37.5 18.333333333 14 37.5 18.333333333 16 37.5 18.333333333 +18 37.5 18.333333333 20 37.5 18.333333333 0 40 18.333333333 +2 40 18.333333333 4 40 18.333333333 6 40 18.333333333 +8 40 18.333333333 10 40 18.333333333 12 40 18.333333333 +14 40 18.333333333 16 40 18.333333333 18 40 18.333333333 +20 40 18.333333333 0 42.5 18.333333333 2 42.5 18.333333333 +4 42.5 18.333333333 6 42.5 18.333333333 8 42.5 18.333333333 +10 42.5 18.333333333 12 42.5 18.333333333 14 42.5 18.333333333 +16 42.5 18.333333333 18 42.5 18.333333333 20 42.5 18.333333333 +0 45 18.333333333 2 45 18.333333333 4 45 18.333333333 +6 45 18.333333333 8 45 18.333333333 10 45 18.333333333 +12 45 18.333333333 14 45 18.333333333 16 45 18.333333333 +18 45 18.333333333 20 45 18.333333333 0 47.5 18.333333333 +2 47.5 18.333333333 4 47.5 18.333333333 6 47.5 18.333333333 +8 47.5 18.333333333 10 47.5 18.333333333 12 47.5 18.333333333 +14 47.5 18.333333333 16 47.5 18.333333333 18 47.5 18.333333333 +20 47.5 18.333333333 0 50 18.333333333 2 50 18.333333333 +4 50 18.333333333 6 50 18.333333333 8 50 18.333333333 +10 50 18.333333333 12 50 18.333333333 14 50 18.333333333 +16 50 18.333333333 18 50 18.333333333 20 50 18.333333333 +0 0 20 2 0 20 4 0 20 +6 0 20 8 0 20 10 0 20 +12 0 20 14 0 20 16 0 20 +18 0 20 20 0 20 0 2.5 20 +2 2.5 20 4 2.5 20 6 2.5 20 +8 2.5 20 10 2.5 20 12 2.5 20 +14 2.5 20 16 2.5 20 18 2.5 20 +20 2.5 20 0 5 20 2 5 20 +4 5 20 6 5 20 8 5 20 +10 5 20 12 5 20 14 5 20 +16 5 20 18 5 20 20 5 20 +0 7.5 20 2 7.5 20 4 7.5 20 +6 7.5 20 8 7.5 20 10 7.5 20 +12 7.5 20 14 7.5 20 16 7.5 20 +18 7.5 20 20 7.5 20 0 10 20 +2 10 20 4 10 20 6 10 20 +8 10 20 10 10 20 12 10 20 +14 10 20 16 10 20 18 10 20 +20 10 20 0 12.5 20 2 12.5 20 +4 12.5 20 6 12.5 20 8 12.5 20 +10 12.5 20 12 12.5 20 14 12.5 20 +16 12.5 20 18 12.5 20 20 12.5 20 +0 15 20 2 15 20 4 15 20 +6 15 20 8 15 20 10 15 20 +12 15 20 14 15 20 16 15 20 +18 15 20 20 15 20 0 17.5 20 +2 17.5 20 4 17.5 20 6 17.5 20 +8 17.5 20 10 17.5 20 12 17.5 20 +14 17.5 20 16 17.5 20 18 17.5 20 +20 17.5 20 0 20 20 2 20 20 +4 20 20 6 20 20 8 20 20 +10 20 20 12 20 20 14 20 20 +16 20 20 18 20 20 20 20 20 +0 22.5 20 2 22.5 20 4 22.5 20 +6 22.5 20 8 22.5 20 10 22.5 20 +12 22.5 20 14 22.5 20 16 22.5 20 +18 22.5 20 20 22.5 20 0 25 20 +2 25 20 4 25 20 6 25 20 +8 25 20 10 25 20 12 25 20 +14 25 20 16 25 20 18 25 20 +20 25 20 0 27.5 20 2 27.5 20 +4 27.5 20 6 27.5 20 8 27.5 20 +10 27.5 20 12 27.5 20 14 27.5 20 +16 27.5 20 18 27.5 20 20 27.5 20 +0 30 20 2 30 20 4 30 20 +6 30 20 8 30 20 10 30 20 +12 30 20 14 30 20 16 30 20 +18 30 20 20 30 20 0 32.5 20 +2 32.5 20 4 32.5 20 6 32.5 20 +8 32.5 20 10 32.5 20 12 32.5 20 +14 32.5 20 16 32.5 20 18 32.5 20 +20 32.5 20 0 35 20 2 35 20 +4 35 20 6 35 20 8 35 20 +10 35 20 12 35 20 14 35 20 +16 35 20 18 35 20 20 35 20 +0 37.5 20 2 37.5 20 4 37.5 20 +6 37.5 20 8 37.5 20 10 37.5 20 +12 37.5 20 14 37.5 20 16 37.5 20 +18 37.5 20 20 37.5 20 0 40 20 +2 40 20 4 40 20 6 40 20 +8 40 20 10 40 20 12 40 20 +14 40 20 16 40 20 18 40 20 +20 40 20 0 42.5 20 2 42.5 20 +4 42.5 20 6 42.5 20 8 42.5 20 +10 42.5 20 12 42.5 20 14 42.5 20 +16 42.5 20 18 42.5 20 20 42.5 20 +0 45 20 2 45 20 4 45 20 +6 45 20 8 45 20 10 45 20 +12 45 20 14 45 20 16 45 20 +18 45 20 20 45 20 0 47.5 20 +2 47.5 20 4 47.5 20 6 47.5 20 +8 47.5 20 10 47.5 20 12 47.5 20 +14 47.5 20 16 47.5 20 18 47.5 20 +20 47.5 20 0 50 20 2 50 20 +4 50 20 6 50 20 8 50 20 +10 50 20 12 50 20 14 50 20 +16 50 20 18 50 20 20 50 20 +0 0 21.666666667 2 0 21.666666667 4 0 21.666666667 +6 0 21.666666667 8 0 21.666666667 10 0 21.666666667 +12 0 21.666666667 14 0 21.666666667 16 0 21.666666667 +18 0 21.666666667 20 0 21.666666667 0 2.5 21.666666667 +2 2.5 21.666666667 4 2.5 21.666666667 6 2.5 21.666666667 +8 2.5 21.666666667 10 2.5 21.666666667 12 2.5 21.666666667 +14 2.5 21.666666667 16 2.5 21.666666667 18 2.5 21.666666667 +20 2.5 21.666666667 0 5 21.666666667 2 5 21.666666667 +4 5 21.666666667 6 5 21.666666667 8 5 21.666666667 +10 5 21.666666667 12 5 21.666666667 14 5 21.666666667 +16 5 21.666666667 18 5 21.666666667 20 5 21.666666667 +0 7.5 21.666666667 2 7.5 21.666666667 4 7.5 21.666666667 +6 7.5 21.666666667 8 7.5 21.666666667 10 7.5 21.666666667 +12 7.5 21.666666667 14 7.5 21.666666667 16 7.5 21.666666667 +18 7.5 21.666666667 20 7.5 21.666666667 0 10 21.666666667 +2 10 21.666666667 4 10 21.666666667 6 10 21.666666667 +8 10 21.666666667 10 10 21.666666667 12 10 21.666666667 +14 10 21.666666667 16 10 21.666666667 18 10 21.666666667 +20 10 21.666666667 0 12.5 21.666666667 2 12.5 21.666666667 +4 12.5 21.666666667 6 12.5 21.666666667 8 12.5 21.666666667 +10 12.5 21.666666667 12 12.5 21.666666667 14 12.5 21.666666667 +16 12.5 21.666666667 18 12.5 21.666666667 20 12.5 21.666666667 +0 15 21.666666667 2 15 21.666666667 4 15 21.666666667 +6 15 21.666666667 8 15 21.666666667 10 15 21.666666667 +12 15 21.666666667 14 15 21.666666667 16 15 21.666666667 +18 15 21.666666667 20 15 21.666666667 0 17.5 21.666666667 +2 17.5 21.666666667 4 17.5 21.666666667 6 17.5 21.666666667 +8 17.5 21.666666667 10 17.5 21.666666667 12 17.5 21.666666667 +14 17.5 21.666666667 16 17.5 21.666666667 18 17.5 21.666666667 +20 17.5 21.666666667 0 20 21.666666667 2 20 21.666666667 +4 20 21.666666667 6 20 21.666666667 8 20 21.666666667 +10 20 21.666666667 12 20 21.666666667 14 20 21.666666667 +16 20 21.666666667 18 20 21.666666667 20 20 21.666666667 +0 22.5 21.666666667 2 22.5 21.666666667 4 22.5 21.666666667 +6 22.5 21.666666667 8 22.5 21.666666667 10 22.5 21.666666667 +12 22.5 21.666666667 14 22.5 21.666666667 16 22.5 21.666666667 +18 22.5 21.666666667 20 22.5 21.666666667 0 25 21.666666667 +2 25 21.666666667 4 25 21.666666667 6 25 21.666666667 +8 25 21.666666667 10 25 21.666666667 12 25 21.666666667 +14 25 21.666666667 16 25 21.666666667 18 25 21.666666667 +20 25 21.666666667 0 27.5 21.666666667 2 27.5 21.666666667 +4 27.5 21.666666667 6 27.5 21.666666667 8 27.5 21.666666667 +10 27.5 21.666666667 12 27.5 21.666666667 14 27.5 21.666666667 +16 27.5 21.666666667 18 27.5 21.666666667 20 27.5 21.666666667 +0 30 21.666666667 2 30 21.666666667 4 30 21.666666667 +6 30 21.666666667 8 30 21.666666667 10 30 21.666666667 +12 30 21.666666667 14 30 21.666666667 16 30 21.666666667 +18 30 21.666666667 20 30 21.666666667 0 32.5 21.666666667 +2 32.5 21.666666667 4 32.5 21.666666667 6 32.5 21.666666667 +8 32.5 21.666666667 10 32.5 21.666666667 12 32.5 21.666666667 +14 32.5 21.666666667 16 32.5 21.666666667 18 32.5 21.666666667 +20 32.5 21.666666667 0 35 21.666666667 2 35 21.666666667 +4 35 21.666666667 6 35 21.666666667 8 35 21.666666667 +10 35 21.666666667 12 35 21.666666667 14 35 21.666666667 +16 35 21.666666667 18 35 21.666666667 20 35 21.666666667 +0 37.5 21.666666667 2 37.5 21.666666667 4 37.5 21.666666667 +6 37.5 21.666666667 8 37.5 21.666666667 10 37.5 21.666666667 +12 37.5 21.666666667 14 37.5 21.666666667 16 37.5 21.666666667 +18 37.5 21.666666667 20 37.5 21.666666667 0 40 21.666666667 +2 40 21.666666667 4 40 21.666666667 6 40 21.666666667 +8 40 21.666666667 10 40 21.666666667 12 40 21.666666667 +14 40 21.666666667 16 40 21.666666667 18 40 21.666666667 +20 40 21.666666667 0 42.5 21.666666667 2 42.5 21.666666667 +4 42.5 21.666666667 6 42.5 21.666666667 8 42.5 21.666666667 +10 42.5 21.666666667 12 42.5 21.666666667 14 42.5 21.666666667 +16 42.5 21.666666667 18 42.5 21.666666667 20 42.5 21.666666667 +0 45 21.666666667 2 45 21.666666667 4 45 21.666666667 +6 45 21.666666667 8 45 21.666666667 10 45 21.666666667 +12 45 21.666666667 14 45 21.666666667 16 45 21.666666667 +18 45 21.666666667 20 45 21.666666667 0 47.5 21.666666667 +2 47.5 21.666666667 4 47.5 21.666666667 6 47.5 21.666666667 +8 47.5 21.666666667 10 47.5 21.666666667 12 47.5 21.666666667 +14 47.5 21.666666667 16 47.5 21.666666667 18 47.5 21.666666667 +20 47.5 21.666666667 0 50 21.666666667 2 50 21.666666667 +4 50 21.666666667 6 50 21.666666667 8 50 21.666666667 +10 50 21.666666667 12 50 21.666666667 14 50 21.666666667 +16 50 21.666666667 18 50 21.666666667 20 50 21.666666667 +0 0 23.333333333 2 0 23.333333333 4 0 23.333333333 +6 0 23.333333333 8 0 23.333333333 10 0 23.333333333 +12 0 23.333333333 14 0 23.333333333 16 0 23.333333333 +18 0 23.333333333 20 0 23.333333333 0 2.5 23.333333333 +2 2.5 23.333333333 4 2.5 23.333333333 6 2.5 23.333333333 +8 2.5 23.333333333 10 2.5 23.333333333 12 2.5 23.333333333 +14 2.5 23.333333333 16 2.5 23.333333333 18 2.5 23.333333333 +20 2.5 23.333333333 0 5 23.333333333 2 5 23.333333333 +4 5 23.333333333 6 5 23.333333333 8 5 23.333333333 +10 5 23.333333333 12 5 23.333333333 14 5 23.333333333 +16 5 23.333333333 18 5 23.333333333 20 5 23.333333333 +0 7.5 23.333333333 2 7.5 23.333333333 4 7.5 23.333333333 +6 7.5 23.333333333 8 7.5 23.333333333 10 7.5 23.333333333 +12 7.5 23.333333333 14 7.5 23.333333333 16 7.5 23.333333333 +18 7.5 23.333333333 20 7.5 23.333333333 0 10 23.333333333 +2 10 23.333333333 4 10 23.333333333 6 10 23.333333333 +8 10 23.333333333 10 10 23.333333333 12 10 23.333333333 +14 10 23.333333333 16 10 23.333333333 18 10 23.333333333 +20 10 23.333333333 0 12.5 23.333333333 2 12.5 23.333333333 +4 12.5 23.333333333 6 12.5 23.333333333 8 12.5 23.333333333 +10 12.5 23.333333333 12 12.5 23.333333333 14 12.5 23.333333333 +16 12.5 23.333333333 18 12.5 23.333333333 20 12.5 23.333333333 +0 15 23.333333333 2 15 23.333333333 4 15 23.333333333 +6 15 23.333333333 8 15 23.333333333 10 15 23.333333333 +12 15 23.333333333 14 15 23.333333333 16 15 23.333333333 +18 15 23.333333333 20 15 23.333333333 0 17.5 23.333333333 +2 17.5 23.333333333 4 17.5 23.333333333 6 17.5 23.333333333 +8 17.5 23.333333333 10 17.5 23.333333333 12 17.5 23.333333333 +14 17.5 23.333333333 16 17.5 23.333333333 18 17.5 23.333333333 +20 17.5 23.333333333 0 20 23.333333333 2 20 23.333333333 +4 20 23.333333333 6 20 23.333333333 8 20 23.333333333 +10 20 23.333333333 12 20 23.333333333 14 20 23.333333333 +16 20 23.333333333 18 20 23.333333333 20 20 23.333333333 +0 22.5 23.333333333 2 22.5 23.333333333 4 22.5 23.333333333 +6 22.5 23.333333333 8 22.5 23.333333333 10 22.5 23.333333333 +12 22.5 23.333333333 14 22.5 23.333333333 16 22.5 23.333333333 +18 22.5 23.333333333 20 22.5 23.333333333 0 25 23.333333333 +2 25 23.333333333 4 25 23.333333333 6 25 23.333333333 +8 25 23.333333333 10 25 23.333333333 12 25 23.333333333 +14 25 23.333333333 16 25 23.333333333 18 25 23.333333333 +20 25 23.333333333 0 27.5 23.333333333 2 27.5 23.333333333 +4 27.5 23.333333333 6 27.5 23.333333333 8 27.5 23.333333333 +10 27.5 23.333333333 12 27.5 23.333333333 14 27.5 23.333333333 +16 27.5 23.333333333 18 27.5 23.333333333 20 27.5 23.333333333 +0 30 23.333333333 2 30 23.333333333 4 30 23.333333333 +6 30 23.333333333 8 30 23.333333333 10 30 23.333333333 +12 30 23.333333333 14 30 23.333333333 16 30 23.333333333 +18 30 23.333333333 20 30 23.333333333 0 32.5 23.333333333 +2 32.5 23.333333333 4 32.5 23.333333333 6 32.5 23.333333333 +8 32.5 23.333333333 10 32.5 23.333333333 12 32.5 23.333333333 +14 32.5 23.333333333 16 32.5 23.333333333 18 32.5 23.333333333 +20 32.5 23.333333333 0 35 23.333333333 2 35 23.333333333 +4 35 23.333333333 6 35 23.333333333 8 35 23.333333333 +10 35 23.333333333 12 35 23.333333333 14 35 23.333333333 +16 35 23.333333333 18 35 23.333333333 20 35 23.333333333 +0 37.5 23.333333333 2 37.5 23.333333333 4 37.5 23.333333333 +6 37.5 23.333333333 8 37.5 23.333333333 10 37.5 23.333333333 +12 37.5 23.333333333 14 37.5 23.333333333 16 37.5 23.333333333 +18 37.5 23.333333333 20 37.5 23.333333333 0 40 23.333333333 +2 40 23.333333333 4 40 23.333333333 6 40 23.333333333 +8 40 23.333333333 10 40 23.333333333 12 40 23.333333333 +14 40 23.333333333 16 40 23.333333333 18 40 23.333333333 +20 40 23.333333333 0 42.5 23.333333333 2 42.5 23.333333333 +4 42.5 23.333333333 6 42.5 23.333333333 8 42.5 23.333333333 +10 42.5 23.333333333 12 42.5 23.333333333 14 42.5 23.333333333 +16 42.5 23.333333333 18 42.5 23.333333333 20 42.5 23.333333333 +0 45 23.333333333 2 45 23.333333333 4 45 23.333333333 +6 45 23.333333333 8 45 23.333333333 10 45 23.333333333 +12 45 23.333333333 14 45 23.333333333 16 45 23.333333333 +18 45 23.333333333 20 45 23.333333333 0 47.5 23.333333333 +2 47.5 23.333333333 4 47.5 23.333333333 6 47.5 23.333333333 +8 47.5 23.333333333 10 47.5 23.333333333 12 47.5 23.333333333 +14 47.5 23.333333333 16 47.5 23.333333333 18 47.5 23.333333333 +20 47.5 23.333333333 0 50 23.333333333 2 50 23.333333333 +4 50 23.333333333 6 50 23.333333333 8 50 23.333333333 +10 50 23.333333333 12 50 23.333333333 14 50 23.333333333 +16 50 23.333333333 18 50 23.333333333 20 50 23.333333333 +0 0 25 2 0 25 4 0 25 +6 0 25 8 0 25 10 0 25 +12 0 25 14 0 25 16 0 25 +18 0 25 20 0 25 0 2.5 25 +2 2.5 25 4 2.5 25 6 2.5 25 +8 2.5 25 10 2.5 25 12 2.5 25 +14 2.5 25 16 2.5 25 18 2.5 25 +20 2.5 25 0 5 25 2 5 25 +4 5 25 6 5 25 8 5 25 +10 5 25 12 5 25 14 5 25 +16 5 25 18 5 25 20 5 25 +0 7.5 25 2 7.5 25 4 7.5 25 +6 7.5 25 8 7.5 25 10 7.5 25 +12 7.5 25 14 7.5 25 16 7.5 25 +18 7.5 25 20 7.5 25 0 10 25 +2 10 25 4 10 25 6 10 25 +8 10 25 10 10 25 12 10 25 +14 10 25 16 10 25 18 10 25 +20 10 25 0 12.5 25 2 12.5 25 +4 12.5 25 6 12.5 25 8 12.5 25 +10 12.5 25 12 12.5 25 14 12.5 25 +16 12.5 25 18 12.5 25 20 12.5 25 +0 15 25 2 15 25 4 15 25 +6 15 25 8 15 25 10 15 25 +12 15 25 14 15 25 16 15 25 +18 15 25 20 15 25 0 17.5 25 +2 17.5 25 4 17.5 25 6 17.5 25 +8 17.5 25 10 17.5 25 12 17.5 25 +14 17.5 25 16 17.5 25 18 17.5 25 +20 17.5 25 0 20 25 2 20 25 +4 20 25 6 20 25 8 20 25 +10 20 25 12 20 25 14 20 25 +16 20 25 18 20 25 20 20 25 +0 22.5 25 2 22.5 25 4 22.5 25 +6 22.5 25 8 22.5 25 10 22.5 25 +12 22.5 25 14 22.5 25 16 22.5 25 +18 22.5 25 20 22.5 25 0 25 25 +2 25 25 4 25 25 6 25 25 +8 25 25 10 25 25 12 25 25 +14 25 25 16 25 25 18 25 25 +20 25 25 0 27.5 25 2 27.5 25 +4 27.5 25 6 27.5 25 8 27.5 25 +10 27.5 25 12 27.5 25 14 27.5 25 +16 27.5 25 18 27.5 25 20 27.5 25 +0 30 25 2 30 25 4 30 25 +6 30 25 8 30 25 10 30 25 +12 30 25 14 30 25 16 30 25 +18 30 25 20 30 25 0 32.5 25 +2 32.5 25 4 32.5 25 6 32.5 25 +8 32.5 25 10 32.5 25 12 32.5 25 +14 32.5 25 16 32.5 25 18 32.5 25 +20 32.5 25 0 35 25 2 35 25 +4 35 25 6 35 25 8 35 25 +10 35 25 12 35 25 14 35 25 +16 35 25 18 35 25 20 35 25 +0 37.5 25 2 37.5 25 4 37.5 25 +6 37.5 25 8 37.5 25 10 37.5 25 +12 37.5 25 14 37.5 25 16 37.5 25 +18 37.5 25 20 37.5 25 0 40 25 +2 40 25 4 40 25 6 40 25 +8 40 25 10 40 25 12 40 25 +14 40 25 16 40 25 18 40 25 +20 40 25 0 42.5 25 2 42.5 25 +4 42.5 25 6 42.5 25 8 42.5 25 +10 42.5 25 12 42.5 25 14 42.5 25 +16 42.5 25 18 42.5 25 20 42.5 25 +0 45 25 2 45 25 4 45 25 +6 45 25 8 45 25 10 45 25 +12 45 25 14 45 25 16 45 25 +18 45 25 20 45 25 0 47.5 25 +2 47.5 25 4 47.5 25 6 47.5 25 +8 47.5 25 10 47.5 25 12 47.5 25 +14 47.5 25 16 47.5 25 18 47.5 25 +20 47.5 25 0 50 25 2 50 25 +4 50 25 6 50 25 8 50 25 +10 50 25 12 50 25 14 50 25 +16 50 25 18 50 25 20 50 25 +0 0 26.666666667 2 0 26.666666667 4 0 26.666666667 +6 0 26.666666667 8 0 26.666666667 10 0 26.666666667 +12 0 26.666666667 14 0 26.666666667 16 0 26.666666667 +18 0 26.666666667 20 0 26.666666667 0 2.5 26.666666667 +2 2.5 26.666666667 4 2.5 26.666666667 6 2.5 26.666666667 +8 2.5 26.666666667 10 2.5 26.666666667 12 2.5 26.666666667 +14 2.5 26.666666667 16 2.5 26.666666667 18 2.5 26.666666667 +20 2.5 26.666666667 0 5 26.666666667 2 5 26.666666667 +4 5 26.666666667 6 5 26.666666667 8 5 26.666666667 +10 5 26.666666667 12 5 26.666666667 14 5 26.666666667 +16 5 26.666666667 18 5 26.666666667 20 5 26.666666667 +0 7.5 26.666666667 2 7.5 26.666666667 4 7.5 26.666666667 +6 7.5 26.666666667 8 7.5 26.666666667 10 7.5 26.666666667 +12 7.5 26.666666667 14 7.5 26.666666667 16 7.5 26.666666667 +18 7.5 26.666666667 20 7.5 26.666666667 0 10 26.666666667 +2 10 26.666666667 4 10 26.666666667 6 10 26.666666667 +8 10 26.666666667 10 10 26.666666667 12 10 26.666666667 +14 10 26.666666667 16 10 26.666666667 18 10 26.666666667 +20 10 26.666666667 0 12.5 26.666666667 2 12.5 26.666666667 +4 12.5 26.666666667 6 12.5 26.666666667 8 12.5 26.666666667 +10 12.5 26.666666667 12 12.5 26.666666667 14 12.5 26.666666667 +16 12.5 26.666666667 18 12.5 26.666666667 20 12.5 26.666666667 +0 15 26.666666667 2 15 26.666666667 4 15 26.666666667 +6 15 26.666666667 8 15 26.666666667 10 15 26.666666667 +12 15 26.666666667 14 15 26.666666667 16 15 26.666666667 +18 15 26.666666667 20 15 26.666666667 0 17.5 26.666666667 +2 17.5 26.666666667 4 17.5 26.666666667 6 17.5 26.666666667 +8 17.5 26.666666667 10 17.5 26.666666667 12 17.5 26.666666667 +14 17.5 26.666666667 16 17.5 26.666666667 18 17.5 26.666666667 +20 17.5 26.666666667 0 20 26.666666667 2 20 26.666666667 +4 20 26.666666667 6 20 26.666666667 8 20 26.666666667 +10 20 26.666666667 12 20 26.666666667 14 20 26.666666667 +16 20 26.666666667 18 20 26.666666667 20 20 26.666666667 +0 22.5 26.666666667 2 22.5 26.666666667 4 22.5 26.666666667 +6 22.5 26.666666667 8 22.5 26.666666667 10 22.5 26.666666667 +12 22.5 26.666666667 14 22.5 26.666666667 16 22.5 26.666666667 +18 22.5 26.666666667 20 22.5 26.666666667 0 25 26.666666667 +2 25 26.666666667 4 25 26.666666667 6 25 26.666666667 +8 25 26.666666667 10 25 26.666666667 12 25 26.666666667 +14 25 26.666666667 16 25 26.666666667 18 25 26.666666667 +20 25 26.666666667 0 27.5 26.666666667 2 27.5 26.666666667 +4 27.5 26.666666667 6 27.5 26.666666667 8 27.5 26.666666667 +10 27.5 26.666666667 12 27.5 26.666666667 14 27.5 26.666666667 +16 27.5 26.666666667 18 27.5 26.666666667 20 27.5 26.666666667 +0 30 26.666666667 2 30 26.666666667 4 30 26.666666667 +6 30 26.666666667 8 30 26.666666667 10 30 26.666666667 +12 30 26.666666667 14 30 26.666666667 16 30 26.666666667 +18 30 26.666666667 20 30 26.666666667 0 32.5 26.666666667 +2 32.5 26.666666667 4 32.5 26.666666667 6 32.5 26.666666667 +8 32.5 26.666666667 10 32.5 26.666666667 12 32.5 26.666666667 +14 32.5 26.666666667 16 32.5 26.666666667 18 32.5 26.666666667 +20 32.5 26.666666667 0 35 26.666666667 2 35 26.666666667 +4 35 26.666666667 6 35 26.666666667 8 35 26.666666667 +10 35 26.666666667 12 35 26.666666667 14 35 26.666666667 +16 35 26.666666667 18 35 26.666666667 20 35 26.666666667 +0 37.5 26.666666667 2 37.5 26.666666667 4 37.5 26.666666667 +6 37.5 26.666666667 8 37.5 26.666666667 10 37.5 26.666666667 +12 37.5 26.666666667 14 37.5 26.666666667 16 37.5 26.666666667 +18 37.5 26.666666667 20 37.5 26.666666667 0 40 26.666666667 +2 40 26.666666667 4 40 26.666666667 6 40 26.666666667 +8 40 26.666666667 10 40 26.666666667 12 40 26.666666667 +14 40 26.666666667 16 40 26.666666667 18 40 26.666666667 +20 40 26.666666667 0 42.5 26.666666667 2 42.5 26.666666667 +4 42.5 26.666666667 6 42.5 26.666666667 8 42.5 26.666666667 +10 42.5 26.666666667 12 42.5 26.666666667 14 42.5 26.666666667 +16 42.5 26.666666667 18 42.5 26.666666667 20 42.5 26.666666667 +0 45 26.666666667 2 45 26.666666667 4 45 26.666666667 +6 45 26.666666667 8 45 26.666666667 10 45 26.666666667 +12 45 26.666666667 14 45 26.666666667 16 45 26.666666667 +18 45 26.666666667 20 45 26.666666667 0 47.5 26.666666667 +2 47.5 26.666666667 4 47.5 26.666666667 6 47.5 26.666666667 +8 47.5 26.666666667 10 47.5 26.666666667 12 47.5 26.666666667 +14 47.5 26.666666667 16 47.5 26.666666667 18 47.5 26.666666667 +20 47.5 26.666666667 0 50 26.666666667 2 50 26.666666667 +4 50 26.666666667 6 50 26.666666667 8 50 26.666666667 +10 50 26.666666667 12 50 26.666666667 14 50 26.666666667 +16 50 26.666666667 18 50 26.666666667 20 50 26.666666667 +0 0 28.333333333 2 0 28.333333333 4 0 28.333333333 +6 0 28.333333333 8 0 28.333333333 10 0 28.333333333 +12 0 28.333333333 14 0 28.333333333 16 0 28.333333333 +18 0 28.333333333 20 0 28.333333333 0 2.5 28.333333333 +2 2.5 28.333333333 4 2.5 28.333333333 6 2.5 28.333333333 +8 2.5 28.333333333 10 2.5 28.333333333 12 2.5 28.333333333 +14 2.5 28.333333333 16 2.5 28.333333333 18 2.5 28.333333333 +20 2.5 28.333333333 0 5 28.333333333 2 5 28.333333333 +4 5 28.333333333 6 5 28.333333333 8 5 28.333333333 +10 5 28.333333333 12 5 28.333333333 14 5 28.333333333 +16 5 28.333333333 18 5 28.333333333 20 5 28.333333333 +0 7.5 28.333333333 2 7.5 28.333333333 4 7.5 28.333333333 +6 7.5 28.333333333 8 7.5 28.333333333 10 7.5 28.333333333 +12 7.5 28.333333333 14 7.5 28.333333333 16 7.5 28.333333333 +18 7.5 28.333333333 20 7.5 28.333333333 0 10 28.333333333 +2 10 28.333333333 4 10 28.333333333 6 10 28.333333333 +8 10 28.333333333 10 10 28.333333333 12 10 28.333333333 +14 10 28.333333333 16 10 28.333333333 18 10 28.333333333 +20 10 28.333333333 0 12.5 28.333333333 2 12.5 28.333333333 +4 12.5 28.333333333 6 12.5 28.333333333 8 12.5 28.333333333 +10 12.5 28.333333333 12 12.5 28.333333333 14 12.5 28.333333333 +16 12.5 28.333333333 18 12.5 28.333333333 20 12.5 28.333333333 +0 15 28.333333333 2 15 28.333333333 4 15 28.333333333 +6 15 28.333333333 8 15 28.333333333 10 15 28.333333333 +12 15 28.333333333 14 15 28.333333333 16 15 28.333333333 +18 15 28.333333333 20 15 28.333333333 0 17.5 28.333333333 +2 17.5 28.333333333 4 17.5 28.333333333 6 17.5 28.333333333 +8 17.5 28.333333333 10 17.5 28.333333333 12 17.5 28.333333333 +14 17.5 28.333333333 16 17.5 28.333333333 18 17.5 28.333333333 +20 17.5 28.333333333 0 20 28.333333333 2 20 28.333333333 +4 20 28.333333333 6 20 28.333333333 8 20 28.333333333 +10 20 28.333333333 12 20 28.333333333 14 20 28.333333333 +16 20 28.333333333 18 20 28.333333333 20 20 28.333333333 +0 22.5 28.333333333 2 22.5 28.333333333 4 22.5 28.333333333 +6 22.5 28.333333333 8 22.5 28.333333333 10 22.5 28.333333333 +12 22.5 28.333333333 14 22.5 28.333333333 16 22.5 28.333333333 +18 22.5 28.333333333 20 22.5 28.333333333 0 25 28.333333333 +2 25 28.333333333 4 25 28.333333333 6 25 28.333333333 +8 25 28.333333333 10 25 28.333333333 12 25 28.333333333 +14 25 28.333333333 16 25 28.333333333 18 25 28.333333333 +20 25 28.333333333 0 27.5 28.333333333 2 27.5 28.333333333 +4 27.5 28.333333333 6 27.5 28.333333333 8 27.5 28.333333333 +10 27.5 28.333333333 12 27.5 28.333333333 14 27.5 28.333333333 +16 27.5 28.333333333 18 27.5 28.333333333 20 27.5 28.333333333 +0 30 28.333333333 2 30 28.333333333 4 30 28.333333333 +6 30 28.333333333 8 30 28.333333333 10 30 28.333333333 +12 30 28.333333333 14 30 28.333333333 16 30 28.333333333 +18 30 28.333333333 20 30 28.333333333 0 32.5 28.333333333 +2 32.5 28.333333333 4 32.5 28.333333333 6 32.5 28.333333333 +8 32.5 28.333333333 10 32.5 28.333333333 12 32.5 28.333333333 +14 32.5 28.333333333 16 32.5 28.333333333 18 32.5 28.333333333 +20 32.5 28.333333333 0 35 28.333333333 2 35 28.333333333 +4 35 28.333333333 6 35 28.333333333 8 35 28.333333333 +10 35 28.333333333 12 35 28.333333333 14 35 28.333333333 +16 35 28.333333333 18 35 28.333333333 20 35 28.333333333 +0 37.5 28.333333333 2 37.5 28.333333333 4 37.5 28.333333333 +6 37.5 28.333333333 8 37.5 28.333333333 10 37.5 28.333333333 +12 37.5 28.333333333 14 37.5 28.333333333 16 37.5 28.333333333 +18 37.5 28.333333333 20 37.5 28.333333333 0 40 28.333333333 +2 40 28.333333333 4 40 28.333333333 6 40 28.333333333 +8 40 28.333333333 10 40 28.333333333 12 40 28.333333333 +14 40 28.333333333 16 40 28.333333333 18 40 28.333333333 +20 40 28.333333333 0 42.5 28.333333333 2 42.5 28.333333333 +4 42.5 28.333333333 6 42.5 28.333333333 8 42.5 28.333333333 +10 42.5 28.333333333 12 42.5 28.333333333 14 42.5 28.333333333 +16 42.5 28.333333333 18 42.5 28.333333333 20 42.5 28.333333333 +0 45 28.333333333 2 45 28.333333333 4 45 28.333333333 +6 45 28.333333333 8 45 28.333333333 10 45 28.333333333 +12 45 28.333333333 14 45 28.333333333 16 45 28.333333333 +18 45 28.333333333 20 45 28.333333333 0 47.5 28.333333333 +2 47.5 28.333333333 4 47.5 28.333333333 6 47.5 28.333333333 +8 47.5 28.333333333 10 47.5 28.333333333 12 47.5 28.333333333 +14 47.5 28.333333333 16 47.5 28.333333333 18 47.5 28.333333333 +20 47.5 28.333333333 0 50 28.333333333 2 50 28.333333333 +4 50 28.333333333 6 50 28.333333333 8 50 28.333333333 +10 50 28.333333333 12 50 28.333333333 14 50 28.333333333 +16 50 28.333333333 18 50 28.333333333 20 50 28.333333333 +0 0 30 2 0 30 4 0 30 +6 0 30 8 0 30 10 0 30 +12 0 30 14 0 30 16 0 30 +18 0 30 20 0 30 0 2.5 30 +2 2.5 30 4 2.5 30 6 2.5 30 +8 2.5 30 10 2.5 30 12 2.5 30 +14 2.5 30 16 2.5 30 18 2.5 30 +20 2.5 30 0 5 30 2 5 30 +4 5 30 6 5 30 8 5 30 +10 5 30 12 5 30 14 5 30 +16 5 30 18 5 30 20 5 30 +0 7.5 30 2 7.5 30 4 7.5 30 +6 7.5 30 8 7.5 30 10 7.5 30 +12 7.5 30 14 7.5 30 16 7.5 30 +18 7.5 30 20 7.5 30 0 10 30 +2 10 30 4 10 30 6 10 30 +8 10 30 10 10 30 12 10 30 +14 10 30 16 10 30 18 10 30 +20 10 30 0 12.5 30 2 12.5 30 +4 12.5 30 6 12.5 30 8 12.5 30 +10 12.5 30 12 12.5 30 14 12.5 30 +16 12.5 30 18 12.5 30 20 12.5 30 +0 15 30 2 15 30 4 15 30 +6 15 30 8 15 30 10 15 30 +12 15 30 14 15 30 16 15 30 +18 15 30 20 15 30 0 17.5 30 +2 17.5 30 4 17.5 30 6 17.5 30 +8 17.5 30 10 17.5 30 12 17.5 30 +14 17.5 30 16 17.5 30 18 17.5 30 +20 17.5 30 0 20 30 2 20 30 +4 20 30 6 20 30 8 20 30 +10 20 30 12 20 30 14 20 30 +16 20 30 18 20 30 20 20 30 +0 22.5 30 2 22.5 30 4 22.5 30 +6 22.5 30 8 22.5 30 10 22.5 30 +12 22.5 30 14 22.5 30 16 22.5 30 +18 22.5 30 20 22.5 30 0 25 30 +2 25 30 4 25 30 6 25 30 +8 25 30 10 25 30 12 25 30 +14 25 30 16 25 30 18 25 30 +20 25 30 0 27.5 30 2 27.5 30 +4 27.5 30 6 27.5 30 8 27.5 30 +10 27.5 30 12 27.5 30 14 27.5 30 +16 27.5 30 18 27.5 30 20 27.5 30 +0 30 30 2 30 30 4 30 30 +6 30 30 8 30 30 10 30 30 +12 30 30 14 30 30 16 30 30 +18 30 30 20 30 30 0 32.5 30 +2 32.5 30 4 32.5 30 6 32.5 30 +8 32.5 30 10 32.5 30 12 32.5 30 +14 32.5 30 16 32.5 30 18 32.5 30 +20 32.5 30 0 35 30 2 35 30 +4 35 30 6 35 30 8 35 30 +10 35 30 12 35 30 14 35 30 +16 35 30 18 35 30 20 35 30 +0 37.5 30 2 37.5 30 4 37.5 30 +6 37.5 30 8 37.5 30 10 37.5 30 +12 37.5 30 14 37.5 30 16 37.5 30 +18 37.5 30 20 37.5 30 0 40 30 +2 40 30 4 40 30 6 40 30 +8 40 30 10 40 30 12 40 30 +14 40 30 16 40 30 18 40 30 +20 40 30 0 42.5 30 2 42.5 30 +4 42.5 30 6 42.5 30 8 42.5 30 +10 42.5 30 12 42.5 30 14 42.5 30 +16 42.5 30 18 42.5 30 20 42.5 30 +0 45 30 2 45 30 4 45 30 +6 45 30 8 45 30 10 45 30 +12 45 30 14 45 30 16 45 30 +18 45 30 20 45 30 0 47.5 30 +2 47.5 30 4 47.5 30 6 47.5 30 +8 47.5 30 10 47.5 30 12 47.5 30 +14 47.5 30 16 47.5 30 18 47.5 30 +20 47.5 30 0 50 30 2 50 30 +4 50 30 6 50 30 8 50 30 +10 50 30 12 50 30 14 50 30 +16 50 30 18 50 30 20 50 30 +0 0 31.666666667 2 0 31.666666667 4 0 31.666666667 +6 0 31.666666667 8 0 31.666666667 10 0 31.666666667 +12 0 31.666666667 14 0 31.666666667 16 0 31.666666667 +18 0 31.666666667 20 0 31.666666667 0 2.5 31.666666667 +2 2.5 31.666666667 4 2.5 31.666666667 6 2.5 31.666666667 +8 2.5 31.666666667 10 2.5 31.666666667 12 2.5 31.666666667 +14 2.5 31.666666667 16 2.5 31.666666667 18 2.5 31.666666667 +20 2.5 31.666666667 0 5 31.666666667 2 5 31.666666667 +4 5 31.666666667 6 5 31.666666667 8 5 31.666666667 +10 5 31.666666667 12 5 31.666666667 14 5 31.666666667 +16 5 31.666666667 18 5 31.666666667 20 5 31.666666667 +0 7.5 31.666666667 2 7.5 31.666666667 4 7.5 31.666666667 +6 7.5 31.666666667 8 7.5 31.666666667 10 7.5 31.666666667 +12 7.5 31.666666667 14 7.5 31.666666667 16 7.5 31.666666667 +18 7.5 31.666666667 20 7.5 31.666666667 0 10 31.666666667 +2 10 31.666666667 4 10 31.666666667 6 10 31.666666667 +8 10 31.666666667 10 10 31.666666667 12 10 31.666666667 +14 10 31.666666667 16 10 31.666666667 18 10 31.666666667 +20 10 31.666666667 0 12.5 31.666666667 2 12.5 31.666666667 +4 12.5 31.666666667 6 12.5 31.666666667 8 12.5 31.666666667 +10 12.5 31.666666667 12 12.5 31.666666667 14 12.5 31.666666667 +16 12.5 31.666666667 18 12.5 31.666666667 20 12.5 31.666666667 +0 15 31.666666667 2 15 31.666666667 4 15 31.666666667 +6 15 31.666666667 8 15 31.666666667 10 15 31.666666667 +12 15 31.666666667 14 15 31.666666667 16 15 31.666666667 +18 15 31.666666667 20 15 31.666666667 0 17.5 31.666666667 +2 17.5 31.666666667 4 17.5 31.666666667 6 17.5 31.666666667 +8 17.5 31.666666667 10 17.5 31.666666667 12 17.5 31.666666667 +14 17.5 31.666666667 16 17.5 31.666666667 18 17.5 31.666666667 +20 17.5 31.666666667 0 20 31.666666667 2 20 31.666666667 +4 20 31.666666667 6 20 31.666666667 8 20 31.666666667 +10 20 31.666666667 12 20 31.666666667 14 20 31.666666667 +16 20 31.666666667 18 20 31.666666667 20 20 31.666666667 +0 22.5 31.666666667 2 22.5 31.666666667 4 22.5 31.666666667 +6 22.5 31.666666667 8 22.5 31.666666667 10 22.5 31.666666667 +12 22.5 31.666666667 14 22.5 31.666666667 16 22.5 31.666666667 +18 22.5 31.666666667 20 22.5 31.666666667 0 25 31.666666667 +2 25 31.666666667 4 25 31.666666667 6 25 31.666666667 +8 25 31.666666667 10 25 31.666666667 12 25 31.666666667 +14 25 31.666666667 16 25 31.666666667 18 25 31.666666667 +20 25 31.666666667 0 27.5 31.666666667 2 27.5 31.666666667 +4 27.5 31.666666667 6 27.5 31.666666667 8 27.5 31.666666667 +10 27.5 31.666666667 12 27.5 31.666666667 14 27.5 31.666666667 +16 27.5 31.666666667 18 27.5 31.666666667 20 27.5 31.666666667 +0 30 31.666666667 2 30 31.666666667 4 30 31.666666667 +6 30 31.666666667 8 30 31.666666667 10 30 31.666666667 +12 30 31.666666667 14 30 31.666666667 16 30 31.666666667 +18 30 31.666666667 20 30 31.666666667 0 32.5 31.666666667 +2 32.5 31.666666667 4 32.5 31.666666667 6 32.5 31.666666667 +8 32.5 31.666666667 10 32.5 31.666666667 12 32.5 31.666666667 +14 32.5 31.666666667 16 32.5 31.666666667 18 32.5 31.666666667 +20 32.5 31.666666667 0 35 31.666666667 2 35 31.666666667 +4 35 31.666666667 6 35 31.666666667 8 35 31.666666667 +10 35 31.666666667 12 35 31.666666667 14 35 31.666666667 +16 35 31.666666667 18 35 31.666666667 20 35 31.666666667 +0 37.5 31.666666667 2 37.5 31.666666667 4 37.5 31.666666667 +6 37.5 31.666666667 8 37.5 31.666666667 10 37.5 31.666666667 +12 37.5 31.666666667 14 37.5 31.666666667 16 37.5 31.666666667 +18 37.5 31.666666667 20 37.5 31.666666667 0 40 31.666666667 +2 40 31.666666667 4 40 31.666666667 6 40 31.666666667 +8 40 31.666666667 10 40 31.666666667 12 40 31.666666667 +14 40 31.666666667 16 40 31.666666667 18 40 31.666666667 +20 40 31.666666667 0 42.5 31.666666667 2 42.5 31.666666667 +4 42.5 31.666666667 6 42.5 31.666666667 8 42.5 31.666666667 +10 42.5 31.666666667 12 42.5 31.666666667 14 42.5 31.666666667 +16 42.5 31.666666667 18 42.5 31.666666667 20 42.5 31.666666667 +0 45 31.666666667 2 45 31.666666667 4 45 31.666666667 +6 45 31.666666667 8 45 31.666666667 10 45 31.666666667 +12 45 31.666666667 14 45 31.666666667 16 45 31.666666667 +18 45 31.666666667 20 45 31.666666667 0 47.5 31.666666667 +2 47.5 31.666666667 4 47.5 31.666666667 6 47.5 31.666666667 +8 47.5 31.666666667 10 47.5 31.666666667 12 47.5 31.666666667 +14 47.5 31.666666667 16 47.5 31.666666667 18 47.5 31.666666667 +20 47.5 31.666666667 0 50 31.666666667 2 50 31.666666667 +4 50 31.666666667 6 50 31.666666667 8 50 31.666666667 +10 50 31.666666667 12 50 31.666666667 14 50 31.666666667 +16 50 31.666666667 18 50 31.666666667 20 50 31.666666667 +0 0 33.333333333 2 0 33.333333333 4 0 33.333333333 +6 0 33.333333333 8 0 33.333333333 10 0 33.333333333 +12 0 33.333333333 14 0 33.333333333 16 0 33.333333333 +18 0 33.333333333 20 0 33.333333333 0 2.5 33.333333333 +2 2.5 33.333333333 4 2.5 33.333333333 6 2.5 33.333333333 +8 2.5 33.333333333 10 2.5 33.333333333 12 2.5 33.333333333 +14 2.5 33.333333333 16 2.5 33.333333333 18 2.5 33.333333333 +20 2.5 33.333333333 0 5 33.333333333 2 5 33.333333333 +4 5 33.333333333 6 5 33.333333333 8 5 33.333333333 +10 5 33.333333333 12 5 33.333333333 14 5 33.333333333 +16 5 33.333333333 18 5 33.333333333 20 5 33.333333333 +0 7.5 33.333333333 2 7.5 33.333333333 4 7.5 33.333333333 +6 7.5 33.333333333 8 7.5 33.333333333 10 7.5 33.333333333 +12 7.5 33.333333333 14 7.5 33.333333333 16 7.5 33.333333333 +18 7.5 33.333333333 20 7.5 33.333333333 0 10 33.333333333 +2 10 33.333333333 4 10 33.333333333 6 10 33.333333333 +8 10 33.333333333 10 10 33.333333333 12 10 33.333333333 +14 10 33.333333333 16 10 33.333333333 18 10 33.333333333 +20 10 33.333333333 0 12.5 33.333333333 2 12.5 33.333333333 +4 12.5 33.333333333 6 12.5 33.333333333 8 12.5 33.333333333 +10 12.5 33.333333333 12 12.5 33.333333333 14 12.5 33.333333333 +16 12.5 33.333333333 18 12.5 33.333333333 20 12.5 33.333333333 +0 15 33.333333333 2 15 33.333333333 4 15 33.333333333 +6 15 33.333333333 8 15 33.333333333 10 15 33.333333333 +12 15 33.333333333 14 15 33.333333333 16 15 33.333333333 +18 15 33.333333333 20 15 33.333333333 0 17.5 33.333333333 +2 17.5 33.333333333 4 17.5 33.333333333 6 17.5 33.333333333 +8 17.5 33.333333333 10 17.5 33.333333333 12 17.5 33.333333333 +14 17.5 33.333333333 16 17.5 33.333333333 18 17.5 33.333333333 +20 17.5 33.333333333 0 20 33.333333333 2 20 33.333333333 +4 20 33.333333333 6 20 33.333333333 8 20 33.333333333 +10 20 33.333333333 12 20 33.333333333 14 20 33.333333333 +16 20 33.333333333 18 20 33.333333333 20 20 33.333333333 +0 22.5 33.333333333 2 22.5 33.333333333 4 22.5 33.333333333 +6 22.5 33.333333333 8 22.5 33.333333333 10 22.5 33.333333333 +12 22.5 33.333333333 14 22.5 33.333333333 16 22.5 33.333333333 +18 22.5 33.333333333 20 22.5 33.333333333 0 25 33.333333333 +2 25 33.333333333 4 25 33.333333333 6 25 33.333333333 +8 25 33.333333333 10 25 33.333333333 12 25 33.333333333 +14 25 33.333333333 16 25 33.333333333 18 25 33.333333333 +20 25 33.333333333 0 27.5 33.333333333 2 27.5 33.333333333 +4 27.5 33.333333333 6 27.5 33.333333333 8 27.5 33.333333333 +10 27.5 33.333333333 12 27.5 33.333333333 14 27.5 33.333333333 +16 27.5 33.333333333 18 27.5 33.333333333 20 27.5 33.333333333 +0 30 33.333333333 2 30 33.333333333 4 30 33.333333333 +6 30 33.333333333 8 30 33.333333333 10 30 33.333333333 +12 30 33.333333333 14 30 33.333333333 16 30 33.333333333 +18 30 33.333333333 20 30 33.333333333 0 32.5 33.333333333 +2 32.5 33.333333333 4 32.5 33.333333333 6 32.5 33.333333333 +8 32.5 33.333333333 10 32.5 33.333333333 12 32.5 33.333333333 +14 32.5 33.333333333 16 32.5 33.333333333 18 32.5 33.333333333 +20 32.5 33.333333333 0 35 33.333333333 2 35 33.333333333 +4 35 33.333333333 6 35 33.333333333 8 35 33.333333333 +10 35 33.333333333 12 35 33.333333333 14 35 33.333333333 +16 35 33.333333333 18 35 33.333333333 20 35 33.333333333 +0 37.5 33.333333333 2 37.5 33.333333333 4 37.5 33.333333333 +6 37.5 33.333333333 8 37.5 33.333333333 10 37.5 33.333333333 +12 37.5 33.333333333 14 37.5 33.333333333 16 37.5 33.333333333 +18 37.5 33.333333333 20 37.5 33.333333333 0 40 33.333333333 +2 40 33.333333333 4 40 33.333333333 6 40 33.333333333 +8 40 33.333333333 10 40 33.333333333 12 40 33.333333333 +14 40 33.333333333 16 40 33.333333333 18 40 33.333333333 +20 40 33.333333333 0 42.5 33.333333333 2 42.5 33.333333333 +4 42.5 33.333333333 6 42.5 33.333333333 8 42.5 33.333333333 +10 42.5 33.333333333 12 42.5 33.333333333 14 42.5 33.333333333 +16 42.5 33.333333333 18 42.5 33.333333333 20 42.5 33.333333333 +0 45 33.333333333 2 45 33.333333333 4 45 33.333333333 +6 45 33.333333333 8 45 33.333333333 10 45 33.333333333 +12 45 33.333333333 14 45 33.333333333 16 45 33.333333333 +18 45 33.333333333 20 45 33.333333333 0 47.5 33.333333333 +2 47.5 33.333333333 4 47.5 33.333333333 6 47.5 33.333333333 +8 47.5 33.333333333 10 47.5 33.333333333 12 47.5 33.333333333 +14 47.5 33.333333333 16 47.5 33.333333333 18 47.5 33.333333333 +20 47.5 33.333333333 0 50 33.333333333 2 50 33.333333333 +4 50 33.333333333 6 50 33.333333333 8 50 33.333333333 +10 50 33.333333333 12 50 33.333333333 14 50 33.333333333 +16 50 33.333333333 18 50 33.333333333 20 50 33.333333333 +0 0 35 2 0 35 4 0 35 +6 0 35 8 0 35 10 0 35 +12 0 35 14 0 35 16 0 35 +18 0 35 20 0 35 0 2.5 35 +2 2.5 35 4 2.5 35 6 2.5 35 +8 2.5 35 10 2.5 35 12 2.5 35 +14 2.5 35 16 2.5 35 18 2.5 35 +20 2.5 35 0 5 35 2 5 35 +4 5 35 6 5 35 8 5 35 +10 5 35 12 5 35 14 5 35 +16 5 35 18 5 35 20 5 35 +0 7.5 35 2 7.5 35 4 7.5 35 +6 7.5 35 8 7.5 35 10 7.5 35 +12 7.5 35 14 7.5 35 16 7.5 35 +18 7.5 35 20 7.5 35 0 10 35 +2 10 35 4 10 35 6 10 35 +8 10 35 10 10 35 12 10 35 +14 10 35 16 10 35 18 10 35 +20 10 35 0 12.5 35 2 12.5 35 +4 12.5 35 6 12.5 35 8 12.5 35 +10 12.5 35 12 12.5 35 14 12.5 35 +16 12.5 35 18 12.5 35 20 12.5 35 +0 15 35 2 15 35 4 15 35 +6 15 35 8 15 35 10 15 35 +12 15 35 14 15 35 16 15 35 +18 15 35 20 15 35 0 17.5 35 +2 17.5 35 4 17.5 35 6 17.5 35 +8 17.5 35 10 17.5 35 12 17.5 35 +14 17.5 35 16 17.5 35 18 17.5 35 +20 17.5 35 0 20 35 2 20 35 +4 20 35 6 20 35 8 20 35 +10 20 35 12 20 35 14 20 35 +16 20 35 18 20 35 20 20 35 +0 22.5 35 2 22.5 35 4 22.5 35 +6 22.5 35 8 22.5 35 10 22.5 35 +12 22.5 35 14 22.5 35 16 22.5 35 +18 22.5 35 20 22.5 35 0 25 35 +2 25 35 4 25 35 6 25 35 +8 25 35 10 25 35 12 25 35 +14 25 35 16 25 35 18 25 35 +20 25 35 0 27.5 35 2 27.5 35 +4 27.5 35 6 27.5 35 8 27.5 35 +10 27.5 35 12 27.5 35 14 27.5 35 +16 27.5 35 18 27.5 35 20 27.5 35 +0 30 35 2 30 35 4 30 35 +6 30 35 8 30 35 10 30 35 +12 30 35 14 30 35 16 30 35 +18 30 35 20 30 35 0 32.5 35 +2 32.5 35 4 32.5 35 6 32.5 35 +8 32.5 35 10 32.5 35 12 32.5 35 +14 32.5 35 16 32.5 35 18 32.5 35 +20 32.5 35 0 35 35 2 35 35 +4 35 35 6 35 35 8 35 35 +10 35 35 12 35 35 14 35 35 +16 35 35 18 35 35 20 35 35 +0 37.5 35 2 37.5 35 4 37.5 35 +6 37.5 35 8 37.5 35 10 37.5 35 +12 37.5 35 14 37.5 35 16 37.5 35 +18 37.5 35 20 37.5 35 0 40 35 +2 40 35 4 40 35 6 40 35 +8 40 35 10 40 35 12 40 35 +14 40 35 16 40 35 18 40 35 +20 40 35 0 42.5 35 2 42.5 35 +4 42.5 35 6 42.5 35 8 42.5 35 +10 42.5 35 12 42.5 35 14 42.5 35 +16 42.5 35 18 42.5 35 20 42.5 35 +0 45 35 2 45 35 4 45 35 +6 45 35 8 45 35 10 45 35 +12 45 35 14 45 35 16 45 35 +18 45 35 20 45 35 0 47.5 35 +2 47.5 35 4 47.5 35 6 47.5 35 +8 47.5 35 10 47.5 35 12 47.5 35 +14 47.5 35 16 47.5 35 18 47.5 35 +20 47.5 35 0 50 35 2 50 35 +4 50 35 6 50 35 8 50 35 +10 50 35 12 50 35 14 50 35 +16 50 35 18 50 35 20 50 35 +0 0 36.666666667 2 0 36.666666667 4 0 36.666666667 +6 0 36.666666667 8 0 36.666666667 10 0 36.666666667 +12 0 36.666666667 14 0 36.666666667 16 0 36.666666667 +18 0 36.666666667 20 0 36.666666667 0 2.5 36.666666667 +2 2.5 36.666666667 4 2.5 36.666666667 6 2.5 36.666666667 +8 2.5 36.666666667 10 2.5 36.666666667 12 2.5 36.666666667 +14 2.5 36.666666667 16 2.5 36.666666667 18 2.5 36.666666667 +20 2.5 36.666666667 0 5 36.666666667 2 5 36.666666667 +4 5 36.666666667 6 5 36.666666667 8 5 36.666666667 +10 5 36.666666667 12 5 36.666666667 14 5 36.666666667 +16 5 36.666666667 18 5 36.666666667 20 5 36.666666667 +0 7.5 36.666666667 2 7.5 36.666666667 4 7.5 36.666666667 +6 7.5 36.666666667 8 7.5 36.666666667 10 7.5 36.666666667 +12 7.5 36.666666667 14 7.5 36.666666667 16 7.5 36.666666667 +18 7.5 36.666666667 20 7.5 36.666666667 0 10 36.666666667 +2 10 36.666666667 4 10 36.666666667 6 10 36.666666667 +8 10 36.666666667 10 10 36.666666667 12 10 36.666666667 +14 10 36.666666667 16 10 36.666666667 18 10 36.666666667 +20 10 36.666666667 0 12.5 36.666666667 2 12.5 36.666666667 +4 12.5 36.666666667 6 12.5 36.666666667 8 12.5 36.666666667 +10 12.5 36.666666667 12 12.5 36.666666667 14 12.5 36.666666667 +16 12.5 36.666666667 18 12.5 36.666666667 20 12.5 36.666666667 +0 15 36.666666667 2 15 36.666666667 4 15 36.666666667 +6 15 36.666666667 8 15 36.666666667 10 15 36.666666667 +12 15 36.666666667 14 15 36.666666667 16 15 36.666666667 +18 15 36.666666667 20 15 36.666666667 0 17.5 36.666666667 +2 17.5 36.666666667 4 17.5 36.666666667 6 17.5 36.666666667 +8 17.5 36.666666667 10 17.5 36.666666667 12 17.5 36.666666667 +14 17.5 36.666666667 16 17.5 36.666666667 18 17.5 36.666666667 +20 17.5 36.666666667 0 20 36.666666667 2 20 36.666666667 +4 20 36.666666667 6 20 36.666666667 8 20 36.666666667 +10 20 36.666666667 12 20 36.666666667 14 20 36.666666667 +16 20 36.666666667 18 20 36.666666667 20 20 36.666666667 +0 22.5 36.666666667 2 22.5 36.666666667 4 22.5 36.666666667 +6 22.5 36.666666667 8 22.5 36.666666667 10 22.5 36.666666667 +12 22.5 36.666666667 14 22.5 36.666666667 16 22.5 36.666666667 +18 22.5 36.666666667 20 22.5 36.666666667 0 25 36.666666667 +2 25 36.666666667 4 25 36.666666667 6 25 36.666666667 +8 25 36.666666667 10 25 36.666666667 12 25 36.666666667 +14 25 36.666666667 16 25 36.666666667 18 25 36.666666667 +20 25 36.666666667 0 27.5 36.666666667 2 27.5 36.666666667 +4 27.5 36.666666667 6 27.5 36.666666667 8 27.5 36.666666667 +10 27.5 36.666666667 12 27.5 36.666666667 14 27.5 36.666666667 +16 27.5 36.666666667 18 27.5 36.666666667 20 27.5 36.666666667 +0 30 36.666666667 2 30 36.666666667 4 30 36.666666667 +6 30 36.666666667 8 30 36.666666667 10 30 36.666666667 +12 30 36.666666667 14 30 36.666666667 16 30 36.666666667 +18 30 36.666666667 20 30 36.666666667 0 32.5 36.666666667 +2 32.5 36.666666667 4 32.5 36.666666667 6 32.5 36.666666667 +8 32.5 36.666666667 10 32.5 36.666666667 12 32.5 36.666666667 +14 32.5 36.666666667 16 32.5 36.666666667 18 32.5 36.666666667 +20 32.5 36.666666667 0 35 36.666666667 2 35 36.666666667 +4 35 36.666666667 6 35 36.666666667 8 35 36.666666667 +10 35 36.666666667 12 35 36.666666667 14 35 36.666666667 +16 35 36.666666667 18 35 36.666666667 20 35 36.666666667 +0 37.5 36.666666667 2 37.5 36.666666667 4 37.5 36.666666667 +6 37.5 36.666666667 8 37.5 36.666666667 10 37.5 36.666666667 +12 37.5 36.666666667 14 37.5 36.666666667 16 37.5 36.666666667 +18 37.5 36.666666667 20 37.5 36.666666667 0 40 36.666666667 +2 40 36.666666667 4 40 36.666666667 6 40 36.666666667 +8 40 36.666666667 10 40 36.666666667 12 40 36.666666667 +14 40 36.666666667 16 40 36.666666667 18 40 36.666666667 +20 40 36.666666667 0 42.5 36.666666667 2 42.5 36.666666667 +4 42.5 36.666666667 6 42.5 36.666666667 8 42.5 36.666666667 +10 42.5 36.666666667 12 42.5 36.666666667 14 42.5 36.666666667 +16 42.5 36.666666667 18 42.5 36.666666667 20 42.5 36.666666667 +0 45 36.666666667 2 45 36.666666667 4 45 36.666666667 +6 45 36.666666667 8 45 36.666666667 10 45 36.666666667 +12 45 36.666666667 14 45 36.666666667 16 45 36.666666667 +18 45 36.666666667 20 45 36.666666667 0 47.5 36.666666667 +2 47.5 36.666666667 4 47.5 36.666666667 6 47.5 36.666666667 +8 47.5 36.666666667 10 47.5 36.666666667 12 47.5 36.666666667 +14 47.5 36.666666667 16 47.5 36.666666667 18 47.5 36.666666667 +20 47.5 36.666666667 0 50 36.666666667 2 50 36.666666667 +4 50 36.666666667 6 50 36.666666667 8 50 36.666666667 +10 50 36.666666667 12 50 36.666666667 14 50 36.666666667 +16 50 36.666666667 18 50 36.666666667 20 50 36.666666667 +0 0 38.333333333 2 0 38.333333333 4 0 38.333333333 +6 0 38.333333333 8 0 38.333333333 10 0 38.333333333 +12 0 38.333333333 14 0 38.333333333 16 0 38.333333333 +18 0 38.333333333 20 0 38.333333333 0 2.5 38.333333333 +2 2.5 38.333333333 4 2.5 38.333333333 6 2.5 38.333333333 +8 2.5 38.333333333 10 2.5 38.333333333 12 2.5 38.333333333 +14 2.5 38.333333333 16 2.5 38.333333333 18 2.5 38.333333333 +20 2.5 38.333333333 0 5 38.333333333 2 5 38.333333333 +4 5 38.333333333 6 5 38.333333333 8 5 38.333333333 +10 5 38.333333333 12 5 38.333333333 14 5 38.333333333 +16 5 38.333333333 18 5 38.333333333 20 5 38.333333333 +0 7.5 38.333333333 2 7.5 38.333333333 4 7.5 38.333333333 +6 7.5 38.333333333 8 7.5 38.333333333 10 7.5 38.333333333 +12 7.5 38.333333333 14 7.5 38.333333333 16 7.5 38.333333333 +18 7.5 38.333333333 20 7.5 38.333333333 0 10 38.333333333 +2 10 38.333333333 4 10 38.333333333 6 10 38.333333333 +8 10 38.333333333 10 10 38.333333333 12 10 38.333333333 +14 10 38.333333333 16 10 38.333333333 18 10 38.333333333 +20 10 38.333333333 0 12.5 38.333333333 2 12.5 38.333333333 +4 12.5 38.333333333 6 12.5 38.333333333 8 12.5 38.333333333 +10 12.5 38.333333333 12 12.5 38.333333333 14 12.5 38.333333333 +16 12.5 38.333333333 18 12.5 38.333333333 20 12.5 38.333333333 +0 15 38.333333333 2 15 38.333333333 4 15 38.333333333 +6 15 38.333333333 8 15 38.333333333 10 15 38.333333333 +12 15 38.333333333 14 15 38.333333333 16 15 38.333333333 +18 15 38.333333333 20 15 38.333333333 0 17.5 38.333333333 +2 17.5 38.333333333 4 17.5 38.333333333 6 17.5 38.333333333 +8 17.5 38.333333333 10 17.5 38.333333333 12 17.5 38.333333333 +14 17.5 38.333333333 16 17.5 38.333333333 18 17.5 38.333333333 +20 17.5 38.333333333 0 20 38.333333333 2 20 38.333333333 +4 20 38.333333333 6 20 38.333333333 8 20 38.333333333 +10 20 38.333333333 12 20 38.333333333 14 20 38.333333333 +16 20 38.333333333 18 20 38.333333333 20 20 38.333333333 +0 22.5 38.333333333 2 22.5 38.333333333 4 22.5 38.333333333 +6 22.5 38.333333333 8 22.5 38.333333333 10 22.5 38.333333333 +12 22.5 38.333333333 14 22.5 38.333333333 16 22.5 38.333333333 +18 22.5 38.333333333 20 22.5 38.333333333 0 25 38.333333333 +2 25 38.333333333 4 25 38.333333333 6 25 38.333333333 +8 25 38.333333333 10 25 38.333333333 12 25 38.333333333 +14 25 38.333333333 16 25 38.333333333 18 25 38.333333333 +20 25 38.333333333 0 27.5 38.333333333 2 27.5 38.333333333 +4 27.5 38.333333333 6 27.5 38.333333333 8 27.5 38.333333333 +10 27.5 38.333333333 12 27.5 38.333333333 14 27.5 38.333333333 +16 27.5 38.333333333 18 27.5 38.333333333 20 27.5 38.333333333 +0 30 38.333333333 2 30 38.333333333 4 30 38.333333333 +6 30 38.333333333 8 30 38.333333333 10 30 38.333333333 +12 30 38.333333333 14 30 38.333333333 16 30 38.333333333 +18 30 38.333333333 20 30 38.333333333 0 32.5 38.333333333 +2 32.5 38.333333333 4 32.5 38.333333333 6 32.5 38.333333333 +8 32.5 38.333333333 10 32.5 38.333333333 12 32.5 38.333333333 +14 32.5 38.333333333 16 32.5 38.333333333 18 32.5 38.333333333 +20 32.5 38.333333333 0 35 38.333333333 2 35 38.333333333 +4 35 38.333333333 6 35 38.333333333 8 35 38.333333333 +10 35 38.333333333 12 35 38.333333333 14 35 38.333333333 +16 35 38.333333333 18 35 38.333333333 20 35 38.333333333 +0 37.5 38.333333333 2 37.5 38.333333333 4 37.5 38.333333333 +6 37.5 38.333333333 8 37.5 38.333333333 10 37.5 38.333333333 +12 37.5 38.333333333 14 37.5 38.333333333 16 37.5 38.333333333 +18 37.5 38.333333333 20 37.5 38.333333333 0 40 38.333333333 +2 40 38.333333333 4 40 38.333333333 6 40 38.333333333 +8 40 38.333333333 10 40 38.333333333 12 40 38.333333333 +14 40 38.333333333 16 40 38.333333333 18 40 38.333333333 +20 40 38.333333333 0 42.5 38.333333333 2 42.5 38.333333333 +4 42.5 38.333333333 6 42.5 38.333333333 8 42.5 38.333333333 +10 42.5 38.333333333 12 42.5 38.333333333 14 42.5 38.333333333 +16 42.5 38.333333333 18 42.5 38.333333333 20 42.5 38.333333333 +0 45 38.333333333 2 45 38.333333333 4 45 38.333333333 +6 45 38.333333333 8 45 38.333333333 10 45 38.333333333 +12 45 38.333333333 14 45 38.333333333 16 45 38.333333333 +18 45 38.333333333 20 45 38.333333333 0 47.5 38.333333333 +2 47.5 38.333333333 4 47.5 38.333333333 6 47.5 38.333333333 +8 47.5 38.333333333 10 47.5 38.333333333 12 47.5 38.333333333 +14 47.5 38.333333333 16 47.5 38.333333333 18 47.5 38.333333333 +20 47.5 38.333333333 0 50 38.333333333 2 50 38.333333333 +4 50 38.333333333 6 50 38.333333333 8 50 38.333333333 +10 50 38.333333333 12 50 38.333333333 14 50 38.333333333 +16 50 38.333333333 18 50 38.333333333 20 50 38.333333333 +0 0 40 2 0 40 4 0 40 +6 0 40 8 0 40 10 0 40 +12 0 40 14 0 40 16 0 40 +18 0 40 20 0 40 0 2.5 40 +2 2.5 40 4 2.5 40 6 2.5 40 +8 2.5 40 10 2.5 40 12 2.5 40 +14 2.5 40 16 2.5 40 18 2.5 40 +20 2.5 40 0 5 40 2 5 40 +4 5 40 6 5 40 8 5 40 +10 5 40 12 5 40 14 5 40 +16 5 40 18 5 40 20 5 40 +0 7.5 40 2 7.5 40 4 7.5 40 +6 7.5 40 8 7.5 40 10 7.5 40 +12 7.5 40 14 7.5 40 16 7.5 40 +18 7.5 40 20 7.5 40 0 10 40 +2 10 40 4 10 40 6 10 40 +8 10 40 10 10 40 12 10 40 +14 10 40 16 10 40 18 10 40 +20 10 40 0 12.5 40 2 12.5 40 +4 12.5 40 6 12.5 40 8 12.5 40 +10 12.5 40 12 12.5 40 14 12.5 40 +16 12.5 40 18 12.5 40 20 12.5 40 +0 15 40 2 15 40 4 15 40 +6 15 40 8 15 40 10 15 40 +12 15 40 14 15 40 16 15 40 +18 15 40 20 15 40 0 17.5 40 +2 17.5 40 4 17.5 40 6 17.5 40 +8 17.5 40 10 17.5 40 12 17.5 40 +14 17.5 40 16 17.5 40 18 17.5 40 +20 17.5 40 0 20 40 2 20 40 +4 20 40 6 20 40 8 20 40 +10 20 40 12 20 40 14 20 40 +16 20 40 18 20 40 20 20 40 +0 22.5 40 2 22.5 40 4 22.5 40 +6 22.5 40 8 22.5 40 10 22.5 40 +12 22.5 40 14 22.5 40 16 22.5 40 +18 22.5 40 20 22.5 40 0 25 40 +2 25 40 4 25 40 6 25 40 +8 25 40 10 25 40 12 25 40 +14 25 40 16 25 40 18 25 40 +20 25 40 0 27.5 40 2 27.5 40 +4 27.5 40 6 27.5 40 8 27.5 40 +10 27.5 40 12 27.5 40 14 27.5 40 +16 27.5 40 18 27.5 40 20 27.5 40 +0 30 40 2 30 40 4 30 40 +6 30 40 8 30 40 10 30 40 +12 30 40 14 30 40 16 30 40 +18 30 40 20 30 40 0 32.5 40 +2 32.5 40 4 32.5 40 6 32.5 40 +8 32.5 40 10 32.5 40 12 32.5 40 +14 32.5 40 16 32.5 40 18 32.5 40 +20 32.5 40 0 35 40 2 35 40 +4 35 40 6 35 40 8 35 40 +10 35 40 12 35 40 14 35 40 +16 35 40 18 35 40 20 35 40 +0 37.5 40 2 37.5 40 4 37.5 40 +6 37.5 40 8 37.5 40 10 37.5 40 +12 37.5 40 14 37.5 40 16 37.5 40 +18 37.5 40 20 37.5 40 0 40 40 +2 40 40 4 40 40 6 40 40 +8 40 40 10 40 40 12 40 40 +14 40 40 16 40 40 18 40 40 +20 40 40 0 42.5 40 2 42.5 40 +4 42.5 40 6 42.5 40 8 42.5 40 +10 42.5 40 12 42.5 40 14 42.5 40 +16 42.5 40 18 42.5 40 20 42.5 40 +0 45 40 2 45 40 4 45 40 +6 45 40 8 45 40 10 45 40 +12 45 40 14 45 40 16 45 40 +18 45 40 20 45 40 0 47.5 40 +2 47.5 40 4 47.5 40 6 47.5 40 +8 47.5 40 10 47.5 40 12 47.5 40 +14 47.5 40 16 47.5 40 18 47.5 40 +20 47.5 40 0 50 40 2 50 40 +4 50 40 6 50 40 8 50 40 +10 50 40 12 50 40 14 50 40 +16 50 40 18 50 40 20 50 40 +0 0 41.666666667 2 0 41.666666667 4 0 41.666666667 +6 0 41.666666667 8 0 41.666666667 10 0 41.666666667 +12 0 41.666666667 14 0 41.666666667 16 0 41.666666667 +18 0 41.666666667 20 0 41.666666667 0 2.5 41.666666667 +2 2.5 41.666666667 4 2.5 41.666666667 6 2.5 41.666666667 +8 2.5 41.666666667 10 2.5 41.666666667 12 2.5 41.666666667 +14 2.5 41.666666667 16 2.5 41.666666667 18 2.5 41.666666667 +20 2.5 41.666666667 0 5 41.666666667 2 5 41.666666667 +4 5 41.666666667 6 5 41.666666667 8 5 41.666666667 +10 5 41.666666667 12 5 41.666666667 14 5 41.666666667 +16 5 41.666666667 18 5 41.666666667 20 5 41.666666667 +0 7.5 41.666666667 2 7.5 41.666666667 4 7.5 41.666666667 +6 7.5 41.666666667 8 7.5 41.666666667 10 7.5 41.666666667 +12 7.5 41.666666667 14 7.5 41.666666667 16 7.5 41.666666667 +18 7.5 41.666666667 20 7.5 41.666666667 0 10 41.666666667 +2 10 41.666666667 4 10 41.666666667 6 10 41.666666667 +8 10 41.666666667 10 10 41.666666667 12 10 41.666666667 +14 10 41.666666667 16 10 41.666666667 18 10 41.666666667 +20 10 41.666666667 0 12.5 41.666666667 2 12.5 41.666666667 +4 12.5 41.666666667 6 12.5 41.666666667 8 12.5 41.666666667 +10 12.5 41.666666667 12 12.5 41.666666667 14 12.5 41.666666667 +16 12.5 41.666666667 18 12.5 41.666666667 20 12.5 41.666666667 +0 15 41.666666667 2 15 41.666666667 4 15 41.666666667 +6 15 41.666666667 8 15 41.666666667 10 15 41.666666667 +12 15 41.666666667 14 15 41.666666667 16 15 41.666666667 +18 15 41.666666667 20 15 41.666666667 0 17.5 41.666666667 +2 17.5 41.666666667 4 17.5 41.666666667 6 17.5 41.666666667 +8 17.5 41.666666667 10 17.5 41.666666667 12 17.5 41.666666667 +14 17.5 41.666666667 16 17.5 41.666666667 18 17.5 41.666666667 +20 17.5 41.666666667 0 20 41.666666667 2 20 41.666666667 +4 20 41.666666667 6 20 41.666666667 8 20 41.666666667 +10 20 41.666666667 12 20 41.666666667 14 20 41.666666667 +16 20 41.666666667 18 20 41.666666667 20 20 41.666666667 +0 22.5 41.666666667 2 22.5 41.666666667 4 22.5 41.666666667 +6 22.5 41.666666667 8 22.5 41.666666667 10 22.5 41.666666667 +12 22.5 41.666666667 14 22.5 41.666666667 16 22.5 41.666666667 +18 22.5 41.666666667 20 22.5 41.666666667 0 25 41.666666667 +2 25 41.666666667 4 25 41.666666667 6 25 41.666666667 +8 25 41.666666667 10 25 41.666666667 12 25 41.666666667 +14 25 41.666666667 16 25 41.666666667 18 25 41.666666667 +20 25 41.666666667 0 27.5 41.666666667 2 27.5 41.666666667 +4 27.5 41.666666667 6 27.5 41.666666667 8 27.5 41.666666667 +10 27.5 41.666666667 12 27.5 41.666666667 14 27.5 41.666666667 +16 27.5 41.666666667 18 27.5 41.666666667 20 27.5 41.666666667 +0 30 41.666666667 2 30 41.666666667 4 30 41.666666667 +6 30 41.666666667 8 30 41.666666667 10 30 41.666666667 +12 30 41.666666667 14 30 41.666666667 16 30 41.666666667 +18 30 41.666666667 20 30 41.666666667 0 32.5 41.666666667 +2 32.5 41.666666667 4 32.5 41.666666667 6 32.5 41.666666667 +8 32.5 41.666666667 10 32.5 41.666666667 12 32.5 41.666666667 +14 32.5 41.666666667 16 32.5 41.666666667 18 32.5 41.666666667 +20 32.5 41.666666667 0 35 41.666666667 2 35 41.666666667 +4 35 41.666666667 6 35 41.666666667 8 35 41.666666667 +10 35 41.666666667 12 35 41.666666667 14 35 41.666666667 +16 35 41.666666667 18 35 41.666666667 20 35 41.666666667 +0 37.5 41.666666667 2 37.5 41.666666667 4 37.5 41.666666667 +6 37.5 41.666666667 8 37.5 41.666666667 10 37.5 41.666666667 +12 37.5 41.666666667 14 37.5 41.666666667 16 37.5 41.666666667 +18 37.5 41.666666667 20 37.5 41.666666667 0 40 41.666666667 +2 40 41.666666667 4 40 41.666666667 6 40 41.666666667 +8 40 41.666666667 10 40 41.666666667 12 40 41.666666667 +14 40 41.666666667 16 40 41.666666667 18 40 41.666666667 +20 40 41.666666667 0 42.5 41.666666667 2 42.5 41.666666667 +4 42.5 41.666666667 6 42.5 41.666666667 8 42.5 41.666666667 +10 42.5 41.666666667 12 42.5 41.666666667 14 42.5 41.666666667 +16 42.5 41.666666667 18 42.5 41.666666667 20 42.5 41.666666667 +0 45 41.666666667 2 45 41.666666667 4 45 41.666666667 +6 45 41.666666667 8 45 41.666666667 10 45 41.666666667 +12 45 41.666666667 14 45 41.666666667 16 45 41.666666667 +18 45 41.666666667 20 45 41.666666667 0 47.5 41.666666667 +2 47.5 41.666666667 4 47.5 41.666666667 6 47.5 41.666666667 +8 47.5 41.666666667 10 47.5 41.666666667 12 47.5 41.666666667 +14 47.5 41.666666667 16 47.5 41.666666667 18 47.5 41.666666667 +20 47.5 41.666666667 0 50 41.666666667 2 50 41.666666667 +4 50 41.666666667 6 50 41.666666667 8 50 41.666666667 +10 50 41.666666667 12 50 41.666666667 14 50 41.666666667 +16 50 41.666666667 18 50 41.666666667 20 50 41.666666667 +0 0 43.333333333 2 0 43.333333333 4 0 43.333333333 +6 0 43.333333333 8 0 43.333333333 10 0 43.333333333 +12 0 43.333333333 14 0 43.333333333 16 0 43.333333333 +18 0 43.333333333 20 0 43.333333333 0 2.5 43.333333333 +2 2.5 43.333333333 4 2.5 43.333333333 6 2.5 43.333333333 +8 2.5 43.333333333 10 2.5 43.333333333 12 2.5 43.333333333 +14 2.5 43.333333333 16 2.5 43.333333333 18 2.5 43.333333333 +20 2.5 43.333333333 0 5 43.333333333 2 5 43.333333333 +4 5 43.333333333 6 5 43.333333333 8 5 43.333333333 +10 5 43.333333333 12 5 43.333333333 14 5 43.333333333 +16 5 43.333333333 18 5 43.333333333 20 5 43.333333333 +0 7.5 43.333333333 2 7.5 43.333333333 4 7.5 43.333333333 +6 7.5 43.333333333 8 7.5 43.333333333 10 7.5 43.333333333 +12 7.5 43.333333333 14 7.5 43.333333333 16 7.5 43.333333333 +18 7.5 43.333333333 20 7.5 43.333333333 0 10 43.333333333 +2 10 43.333333333 4 10 43.333333333 6 10 43.333333333 +8 10 43.333333333 10 10 43.333333333 12 10 43.333333333 +14 10 43.333333333 16 10 43.333333333 18 10 43.333333333 +20 10 43.333333333 0 12.5 43.333333333 2 12.5 43.333333333 +4 12.5 43.333333333 6 12.5 43.333333333 8 12.5 43.333333333 +10 12.5 43.333333333 12 12.5 43.333333333 14 12.5 43.333333333 +16 12.5 43.333333333 18 12.5 43.333333333 20 12.5 43.333333333 +0 15 43.333333333 2 15 43.333333333 4 15 43.333333333 +6 15 43.333333333 8 15 43.333333333 10 15 43.333333333 +12 15 43.333333333 14 15 43.333333333 16 15 43.333333333 +18 15 43.333333333 20 15 43.333333333 0 17.5 43.333333333 +2 17.5 43.333333333 4 17.5 43.333333333 6 17.5 43.333333333 +8 17.5 43.333333333 10 17.5 43.333333333 12 17.5 43.333333333 +14 17.5 43.333333333 16 17.5 43.333333333 18 17.5 43.333333333 +20 17.5 43.333333333 0 20 43.333333333 2 20 43.333333333 +4 20 43.333333333 6 20 43.333333333 8 20 43.333333333 +10 20 43.333333333 12 20 43.333333333 14 20 43.333333333 +16 20 43.333333333 18 20 43.333333333 20 20 43.333333333 +0 22.5 43.333333333 2 22.5 43.333333333 4 22.5 43.333333333 +6 22.5 43.333333333 8 22.5 43.333333333 10 22.5 43.333333333 +12 22.5 43.333333333 14 22.5 43.333333333 16 22.5 43.333333333 +18 22.5 43.333333333 20 22.5 43.333333333 0 25 43.333333333 +2 25 43.333333333 4 25 43.333333333 6 25 43.333333333 +8 25 43.333333333 10 25 43.333333333 12 25 43.333333333 +14 25 43.333333333 16 25 43.333333333 18 25 43.333333333 +20 25 43.333333333 0 27.5 43.333333333 2 27.5 43.333333333 +4 27.5 43.333333333 6 27.5 43.333333333 8 27.5 43.333333333 +10 27.5 43.333333333 12 27.5 43.333333333 14 27.5 43.333333333 +16 27.5 43.333333333 18 27.5 43.333333333 20 27.5 43.333333333 +0 30 43.333333333 2 30 43.333333333 4 30 43.333333333 +6 30 43.333333333 8 30 43.333333333 10 30 43.333333333 +12 30 43.333333333 14 30 43.333333333 16 30 43.333333333 +18 30 43.333333333 20 30 43.333333333 0 32.5 43.333333333 +2 32.5 43.333333333 4 32.5 43.333333333 6 32.5 43.333333333 +8 32.5 43.333333333 10 32.5 43.333333333 12 32.5 43.333333333 +14 32.5 43.333333333 16 32.5 43.333333333 18 32.5 43.333333333 +20 32.5 43.333333333 0 35 43.333333333 2 35 43.333333333 +4 35 43.333333333 6 35 43.333333333 8 35 43.333333333 +10 35 43.333333333 12 35 43.333333333 14 35 43.333333333 +16 35 43.333333333 18 35 43.333333333 20 35 43.333333333 +0 37.5 43.333333333 2 37.5 43.333333333 4 37.5 43.333333333 +6 37.5 43.333333333 8 37.5 43.333333333 10 37.5 43.333333333 +12 37.5 43.333333333 14 37.5 43.333333333 16 37.5 43.333333333 +18 37.5 43.333333333 20 37.5 43.333333333 0 40 43.333333333 +2 40 43.333333333 4 40 43.333333333 6 40 43.333333333 +8 40 43.333333333 10 40 43.333333333 12 40 43.333333333 +14 40 43.333333333 16 40 43.333333333 18 40 43.333333333 +20 40 43.333333333 0 42.5 43.333333333 2 42.5 43.333333333 +4 42.5 43.333333333 6 42.5 43.333333333 8 42.5 43.333333333 +10 42.5 43.333333333 12 42.5 43.333333333 14 42.5 43.333333333 +16 42.5 43.333333333 18 42.5 43.333333333 20 42.5 43.333333333 +0 45 43.333333333 2 45 43.333333333 4 45 43.333333333 +6 45 43.333333333 8 45 43.333333333 10 45 43.333333333 +12 45 43.333333333 14 45 43.333333333 16 45 43.333333333 +18 45 43.333333333 20 45 43.333333333 0 47.5 43.333333333 +2 47.5 43.333333333 4 47.5 43.333333333 6 47.5 43.333333333 +8 47.5 43.333333333 10 47.5 43.333333333 12 47.5 43.333333333 +14 47.5 43.333333333 16 47.5 43.333333333 18 47.5 43.333333333 +20 47.5 43.333333333 0 50 43.333333333 2 50 43.333333333 +4 50 43.333333333 6 50 43.333333333 8 50 43.333333333 +10 50 43.333333333 12 50 43.333333333 14 50 43.333333333 +16 50 43.333333333 18 50 43.333333333 20 50 43.333333333 +0 0 45 2 0 45 4 0 45 +6 0 45 8 0 45 10 0 45 +12 0 45 14 0 45 16 0 45 +18 0 45 20 0 45 0 2.5 45 +2 2.5 45 4 2.5 45 6 2.5 45 +8 2.5 45 10 2.5 45 12 2.5 45 +14 2.5 45 16 2.5 45 18 2.5 45 +20 2.5 45 0 5 45 2 5 45 +4 5 45 6 5 45 8 5 45 +10 5 45 12 5 45 14 5 45 +16 5 45 18 5 45 20 5 45 +0 7.5 45 2 7.5 45 4 7.5 45 +6 7.5 45 8 7.5 45 10 7.5 45 +12 7.5 45 14 7.5 45 16 7.5 45 +18 7.5 45 20 7.5 45 0 10 45 +2 10 45 4 10 45 6 10 45 +8 10 45 10 10 45 12 10 45 +14 10 45 16 10 45 18 10 45 +20 10 45 0 12.5 45 2 12.5 45 +4 12.5 45 6 12.5 45 8 12.5 45 +10 12.5 45 12 12.5 45 14 12.5 45 +16 12.5 45 18 12.5 45 20 12.5 45 +0 15 45 2 15 45 4 15 45 +6 15 45 8 15 45 10 15 45 +12 15 45 14 15 45 16 15 45 +18 15 45 20 15 45 0 17.5 45 +2 17.5 45 4 17.5 45 6 17.5 45 +8 17.5 45 10 17.5 45 12 17.5 45 +14 17.5 45 16 17.5 45 18 17.5 45 +20 17.5 45 0 20 45 2 20 45 +4 20 45 6 20 45 8 20 45 +10 20 45 12 20 45 14 20 45 +16 20 45 18 20 45 20 20 45 +0 22.5 45 2 22.5 45 4 22.5 45 +6 22.5 45 8 22.5 45 10 22.5 45 +12 22.5 45 14 22.5 45 16 22.5 45 +18 22.5 45 20 22.5 45 0 25 45 +2 25 45 4 25 45 6 25 45 +8 25 45 10 25 45 12 25 45 +14 25 45 16 25 45 18 25 45 +20 25 45 0 27.5 45 2 27.5 45 +4 27.5 45 6 27.5 45 8 27.5 45 +10 27.5 45 12 27.5 45 14 27.5 45 +16 27.5 45 18 27.5 45 20 27.5 45 +0 30 45 2 30 45 4 30 45 +6 30 45 8 30 45 10 30 45 +12 30 45 14 30 45 16 30 45 +18 30 45 20 30 45 0 32.5 45 +2 32.5 45 4 32.5 45 6 32.5 45 +8 32.5 45 10 32.5 45 12 32.5 45 +14 32.5 45 16 32.5 45 18 32.5 45 +20 32.5 45 0 35 45 2 35 45 +4 35 45 6 35 45 8 35 45 +10 35 45 12 35 45 14 35 45 +16 35 45 18 35 45 20 35 45 +0 37.5 45 2 37.5 45 4 37.5 45 +6 37.5 45 8 37.5 45 10 37.5 45 +12 37.5 45 14 37.5 45 16 37.5 45 +18 37.5 45 20 37.5 45 0 40 45 +2 40 45 4 40 45 6 40 45 +8 40 45 10 40 45 12 40 45 +14 40 45 16 40 45 18 40 45 +20 40 45 0 42.5 45 2 42.5 45 +4 42.5 45 6 42.5 45 8 42.5 45 +10 42.5 45 12 42.5 45 14 42.5 45 +16 42.5 45 18 42.5 45 20 42.5 45 +0 45 45 2 45 45 4 45 45 +6 45 45 8 45 45 10 45 45 +12 45 45 14 45 45 16 45 45 +18 45 45 20 45 45 0 47.5 45 +2 47.5 45 4 47.5 45 6 47.5 45 +8 47.5 45 10 47.5 45 12 47.5 45 +14 47.5 45 16 47.5 45 18 47.5 45 +20 47.5 45 0 50 45 2 50 45 +4 50 45 6 50 45 8 50 45 +10 50 45 12 50 45 14 50 45 +16 50 45 18 50 45 20 50 45 +0 0 46.666666667 2 0 46.666666667 4 0 46.666666667 +6 0 46.666666667 8 0 46.666666667 10 0 46.666666667 +12 0 46.666666667 14 0 46.666666667 16 0 46.666666667 +18 0 46.666666667 20 0 46.666666667 0 2.5 46.666666667 +2 2.5 46.666666667 4 2.5 46.666666667 6 2.5 46.666666667 +8 2.5 46.666666667 10 2.5 46.666666667 12 2.5 46.666666667 +14 2.5 46.666666667 16 2.5 46.666666667 18 2.5 46.666666667 +20 2.5 46.666666667 0 5 46.666666667 2 5 46.666666667 +4 5 46.666666667 6 5 46.666666667 8 5 46.666666667 +10 5 46.666666667 12 5 46.666666667 14 5 46.666666667 +16 5 46.666666667 18 5 46.666666667 20 5 46.666666667 +0 7.5 46.666666667 2 7.5 46.666666667 4 7.5 46.666666667 +6 7.5 46.666666667 8 7.5 46.666666667 10 7.5 46.666666667 +12 7.5 46.666666667 14 7.5 46.666666667 16 7.5 46.666666667 +18 7.5 46.666666667 20 7.5 46.666666667 0 10 46.666666667 +2 10 46.666666667 4 10 46.666666667 6 10 46.666666667 +8 10 46.666666667 10 10 46.666666667 12 10 46.666666667 +14 10 46.666666667 16 10 46.666666667 18 10 46.666666667 +20 10 46.666666667 0 12.5 46.666666667 2 12.5 46.666666667 +4 12.5 46.666666667 6 12.5 46.666666667 8 12.5 46.666666667 +10 12.5 46.666666667 12 12.5 46.666666667 14 12.5 46.666666667 +16 12.5 46.666666667 18 12.5 46.666666667 20 12.5 46.666666667 +0 15 46.666666667 2 15 46.666666667 4 15 46.666666667 +6 15 46.666666667 8 15 46.666666667 10 15 46.666666667 +12 15 46.666666667 14 15 46.666666667 16 15 46.666666667 +18 15 46.666666667 20 15 46.666666667 0 17.5 46.666666667 +2 17.5 46.666666667 4 17.5 46.666666667 6 17.5 46.666666667 +8 17.5 46.666666667 10 17.5 46.666666667 12 17.5 46.666666667 +14 17.5 46.666666667 16 17.5 46.666666667 18 17.5 46.666666667 +20 17.5 46.666666667 0 20 46.666666667 2 20 46.666666667 +4 20 46.666666667 6 20 46.666666667 8 20 46.666666667 +10 20 46.666666667 12 20 46.666666667 14 20 46.666666667 +16 20 46.666666667 18 20 46.666666667 20 20 46.666666667 +0 22.5 46.666666667 2 22.5 46.666666667 4 22.5 46.666666667 +6 22.5 46.666666667 8 22.5 46.666666667 10 22.5 46.666666667 +12 22.5 46.666666667 14 22.5 46.666666667 16 22.5 46.666666667 +18 22.5 46.666666667 20 22.5 46.666666667 0 25 46.666666667 +2 25 46.666666667 4 25 46.666666667 6 25 46.666666667 +8 25 46.666666667 10 25 46.666666667 12 25 46.666666667 +14 25 46.666666667 16 25 46.666666667 18 25 46.666666667 +20 25 46.666666667 0 27.5 46.666666667 2 27.5 46.666666667 +4 27.5 46.666666667 6 27.5 46.666666667 8 27.5 46.666666667 +10 27.5 46.666666667 12 27.5 46.666666667 14 27.5 46.666666667 +16 27.5 46.666666667 18 27.5 46.666666667 20 27.5 46.666666667 +0 30 46.666666667 2 30 46.666666667 4 30 46.666666667 +6 30 46.666666667 8 30 46.666666667 10 30 46.666666667 +12 30 46.666666667 14 30 46.666666667 16 30 46.666666667 +18 30 46.666666667 20 30 46.666666667 0 32.5 46.666666667 +2 32.5 46.666666667 4 32.5 46.666666667 6 32.5 46.666666667 +8 32.5 46.666666667 10 32.5 46.666666667 12 32.5 46.666666667 +14 32.5 46.666666667 16 32.5 46.666666667 18 32.5 46.666666667 +20 32.5 46.666666667 0 35 46.666666667 2 35 46.666666667 +4 35 46.666666667 6 35 46.666666667 8 35 46.666666667 +10 35 46.666666667 12 35 46.666666667 14 35 46.666666667 +16 35 46.666666667 18 35 46.666666667 20 35 46.666666667 +0 37.5 46.666666667 2 37.5 46.666666667 4 37.5 46.666666667 +6 37.5 46.666666667 8 37.5 46.666666667 10 37.5 46.666666667 +12 37.5 46.666666667 14 37.5 46.666666667 16 37.5 46.666666667 +18 37.5 46.666666667 20 37.5 46.666666667 0 40 46.666666667 +2 40 46.666666667 4 40 46.666666667 6 40 46.666666667 +8 40 46.666666667 10 40 46.666666667 12 40 46.666666667 +14 40 46.666666667 16 40 46.666666667 18 40 46.666666667 +20 40 46.666666667 0 42.5 46.666666667 2 42.5 46.666666667 +4 42.5 46.666666667 6 42.5 46.666666667 8 42.5 46.666666667 +10 42.5 46.666666667 12 42.5 46.666666667 14 42.5 46.666666667 +16 42.5 46.666666667 18 42.5 46.666666667 20 42.5 46.666666667 +0 45 46.666666667 2 45 46.666666667 4 45 46.666666667 +6 45 46.666666667 8 45 46.666666667 10 45 46.666666667 +12 45 46.666666667 14 45 46.666666667 16 45 46.666666667 +18 45 46.666666667 20 45 46.666666667 0 47.5 46.666666667 +2 47.5 46.666666667 4 47.5 46.666666667 6 47.5 46.666666667 +8 47.5 46.666666667 10 47.5 46.666666667 12 47.5 46.666666667 +14 47.5 46.666666667 16 47.5 46.666666667 18 47.5 46.666666667 +20 47.5 46.666666667 0 50 46.666666667 2 50 46.666666667 +4 50 46.666666667 6 50 46.666666667 8 50 46.666666667 +10 50 46.666666667 12 50 46.666666667 14 50 46.666666667 +16 50 46.666666667 18 50 46.666666667 20 50 46.666666667 +0 0 48.333333333 2 0 48.333333333 4 0 48.333333333 +6 0 48.333333333 8 0 48.333333333 10 0 48.333333333 +12 0 48.333333333 14 0 48.333333333 16 0 48.333333333 +18 0 48.333333333 20 0 48.333333333 0 2.5 48.333333333 +2 2.5 48.333333333 4 2.5 48.333333333 6 2.5 48.333333333 +8 2.5 48.333333333 10 2.5 48.333333333 12 2.5 48.333333333 +14 2.5 48.333333333 16 2.5 48.333333333 18 2.5 48.333333333 +20 2.5 48.333333333 0 5 48.333333333 2 5 48.333333333 +4 5 48.333333333 6 5 48.333333333 8 5 48.333333333 +10 5 48.333333333 12 5 48.333333333 14 5 48.333333333 +16 5 48.333333333 18 5 48.333333333 20 5 48.333333333 +0 7.5 48.333333333 2 7.5 48.333333333 4 7.5 48.333333333 +6 7.5 48.333333333 8 7.5 48.333333333 10 7.5 48.333333333 +12 7.5 48.333333333 14 7.5 48.333333333 16 7.5 48.333333333 +18 7.5 48.333333333 20 7.5 48.333333333 0 10 48.333333333 +2 10 48.333333333 4 10 48.333333333 6 10 48.333333333 +8 10 48.333333333 10 10 48.333333333 12 10 48.333333333 +14 10 48.333333333 16 10 48.333333333 18 10 48.333333333 +20 10 48.333333333 0 12.5 48.333333333 2 12.5 48.333333333 +4 12.5 48.333333333 6 12.5 48.333333333 8 12.5 48.333333333 +10 12.5 48.333333333 12 12.5 48.333333333 14 12.5 48.333333333 +16 12.5 48.333333333 18 12.5 48.333333333 20 12.5 48.333333333 +0 15 48.333333333 2 15 48.333333333 4 15 48.333333333 +6 15 48.333333333 8 15 48.333333333 10 15 48.333333333 +12 15 48.333333333 14 15 48.333333333 16 15 48.333333333 +18 15 48.333333333 20 15 48.333333333 0 17.5 48.333333333 +2 17.5 48.333333333 4 17.5 48.333333333 6 17.5 48.333333333 +8 17.5 48.333333333 10 17.5 48.333333333 12 17.5 48.333333333 +14 17.5 48.333333333 16 17.5 48.333333333 18 17.5 48.333333333 +20 17.5 48.333333333 0 20 48.333333333 2 20 48.333333333 +4 20 48.333333333 6 20 48.333333333 8 20 48.333333333 +10 20 48.333333333 12 20 48.333333333 14 20 48.333333333 +16 20 48.333333333 18 20 48.333333333 20 20 48.333333333 +0 22.5 48.333333333 2 22.5 48.333333333 4 22.5 48.333333333 +6 22.5 48.333333333 8 22.5 48.333333333 10 22.5 48.333333333 +12 22.5 48.333333333 14 22.5 48.333333333 16 22.5 48.333333333 +18 22.5 48.333333333 20 22.5 48.333333333 0 25 48.333333333 +2 25 48.333333333 4 25 48.333333333 6 25 48.333333333 +8 25 48.333333333 10 25 48.333333333 12 25 48.333333333 +14 25 48.333333333 16 25 48.333333333 18 25 48.333333333 +20 25 48.333333333 0 27.5 48.333333333 2 27.5 48.333333333 +4 27.5 48.333333333 6 27.5 48.333333333 8 27.5 48.333333333 +10 27.5 48.333333333 12 27.5 48.333333333 14 27.5 48.333333333 +16 27.5 48.333333333 18 27.5 48.333333333 20 27.5 48.333333333 +0 30 48.333333333 2 30 48.333333333 4 30 48.333333333 +6 30 48.333333333 8 30 48.333333333 10 30 48.333333333 +12 30 48.333333333 14 30 48.333333333 16 30 48.333333333 +18 30 48.333333333 20 30 48.333333333 0 32.5 48.333333333 +2 32.5 48.333333333 4 32.5 48.333333333 6 32.5 48.333333333 +8 32.5 48.333333333 10 32.5 48.333333333 12 32.5 48.333333333 +14 32.5 48.333333333 16 32.5 48.333333333 18 32.5 48.333333333 +20 32.5 48.333333333 0 35 48.333333333 2 35 48.333333333 +4 35 48.333333333 6 35 48.333333333 8 35 48.333333333 +10 35 48.333333333 12 35 48.333333333 14 35 48.333333333 +16 35 48.333333333 18 35 48.333333333 20 35 48.333333333 +0 37.5 48.333333333 2 37.5 48.333333333 4 37.5 48.333333333 +6 37.5 48.333333333 8 37.5 48.333333333 10 37.5 48.333333333 +12 37.5 48.333333333 14 37.5 48.333333333 16 37.5 48.333333333 +18 37.5 48.333333333 20 37.5 48.333333333 0 40 48.333333333 +2 40 48.333333333 4 40 48.333333333 6 40 48.333333333 +8 40 48.333333333 10 40 48.333333333 12 40 48.333333333 +14 40 48.333333333 16 40 48.333333333 18 40 48.333333333 +20 40 48.333333333 0 42.5 48.333333333 2 42.5 48.333333333 +4 42.5 48.333333333 6 42.5 48.333333333 8 42.5 48.333333333 +10 42.5 48.333333333 12 42.5 48.333333333 14 42.5 48.333333333 +16 42.5 48.333333333 18 42.5 48.333333333 20 42.5 48.333333333 +0 45 48.333333333 2 45 48.333333333 4 45 48.333333333 +6 45 48.333333333 8 45 48.333333333 10 45 48.333333333 +12 45 48.333333333 14 45 48.333333333 16 45 48.333333333 +18 45 48.333333333 20 45 48.333333333 0 47.5 48.333333333 +2 47.5 48.333333333 4 47.5 48.333333333 6 47.5 48.333333333 +8 47.5 48.333333333 10 47.5 48.333333333 12 47.5 48.333333333 +14 47.5 48.333333333 16 47.5 48.333333333 18 47.5 48.333333333 +20 47.5 48.333333333 0 50 48.333333333 2 50 48.333333333 +4 50 48.333333333 6 50 48.333333333 8 50 48.333333333 +10 50 48.333333333 12 50 48.333333333 14 50 48.333333333 +16 50 48.333333333 18 50 48.333333333 20 50 48.333333333 +0 0 50 2 0 50 4 0 50 +6 0 50 8 0 50 10 0 50 +12 0 50 14 0 50 16 0 50 +18 0 50 20 0 50 0 2.5 50 +2 2.5 50 4 2.5 50 6 2.5 50 +8 2.5 50 10 2.5 50 12 2.5 50 +14 2.5 50 16 2.5 50 18 2.5 50 +20 2.5 50 0 5 50 2 5 50 +4 5 50 6 5 50 8 5 50 +10 5 50 12 5 50 14 5 50 +16 5 50 18 5 50 20 5 50 +0 7.5 50 2 7.5 50 4 7.5 50 +6 7.5 50 8 7.5 50 10 7.5 50 +12 7.5 50 14 7.5 50 16 7.5 50 +18 7.5 50 20 7.5 50 0 10 50 +2 10 50 4 10 50 6 10 50 +8 10 50 10 10 50 12 10 50 +14 10 50 16 10 50 18 10 50 +20 10 50 0 12.5 50 2 12.5 50 +4 12.5 50 6 12.5 50 8 12.5 50 +10 12.5 50 12 12.5 50 14 12.5 50 +16 12.5 50 18 12.5 50 20 12.5 50 +0 15 50 2 15 50 4 15 50 +6 15 50 8 15 50 10 15 50 +12 15 50 14 15 50 16 15 50 +18 15 50 20 15 50 0 17.5 50 +2 17.5 50 4 17.5 50 6 17.5 50 +8 17.5 50 10 17.5 50 12 17.5 50 +14 17.5 50 16 17.5 50 18 17.5 50 +20 17.5 50 0 20 50 2 20 50 +4 20 50 6 20 50 8 20 50 +10 20 50 12 20 50 14 20 50 +16 20 50 18 20 50 20 20 50 +0 22.5 50 2 22.5 50 4 22.5 50 +6 22.5 50 8 22.5 50 10 22.5 50 +12 22.5 50 14 22.5 50 16 22.5 50 +18 22.5 50 20 22.5 50 0 25 50 +2 25 50 4 25 50 6 25 50 +8 25 50 10 25 50 12 25 50 +14 25 50 16 25 50 18 25 50 +20 25 50 0 27.5 50 2 27.5 50 +4 27.5 50 6 27.5 50 8 27.5 50 +10 27.5 50 12 27.5 50 14 27.5 50 +16 27.5 50 18 27.5 50 20 27.5 50 +0 30 50 2 30 50 4 30 50 +6 30 50 8 30 50 10 30 50 +12 30 50 14 30 50 16 30 50 +18 30 50 20 30 50 0 32.5 50 +2 32.5 50 4 32.5 50 6 32.5 50 +8 32.5 50 10 32.5 50 12 32.5 50 +14 32.5 50 16 32.5 50 18 32.5 50 +20 32.5 50 0 35 50 2 35 50 +4 35 50 6 35 50 8 35 50 +10 35 50 12 35 50 14 35 50 +16 35 50 18 35 50 20 35 50 +0 37.5 50 2 37.5 50 4 37.5 50 +6 37.5 50 8 37.5 50 10 37.5 50 +12 37.5 50 14 37.5 50 16 37.5 50 +18 37.5 50 20 37.5 50 0 40 50 +2 40 50 4 40 50 6 40 50 +8 40 50 10 40 50 12 40 50 +14 40 50 16 40 50 18 40 50 +20 40 50 0 42.5 50 2 42.5 50 +4 42.5 50 6 42.5 50 8 42.5 50 +10 42.5 50 12 42.5 50 14 42.5 50 +16 42.5 50 18 42.5 50 20 42.5 50 +0 45 50 2 45 50 4 45 50 +6 45 50 8 45 50 10 45 50 +12 45 50 14 45 50 16 45 50 +18 45 50 20 45 50 0 47.5 50 +2 47.5 50 4 47.5 50 6 47.5 50 +8 47.5 50 10 47.5 50 12 47.5 50 +14 47.5 50 16 47.5 50 18 47.5 50 +20 47.5 50 0 50 50 2 50 50 +4 50 50 6 50 50 8 50 50 +10 50 50 12 50 50 14 50 50 +16 50 50 18 50 50 20 50 50 + diff --git a/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk b/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk new file mode 100644 index 00000000000..2308432eec4 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/spherical-curvilinear.vtk @@ -0,0 +1,210 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 175 double +5.4951556605 7.8305813044 -10 5.4951556605 12.169418696 -10 6.0986903619 8.1212282982 -7.5 +6.0986903619 11.878771702 -7.5 7.7475778302 8.9152906522 -10 7.7475778302 8.9152906522 -5.6698729811 +7.7475778302 11.084709348 -10 7.7475778302 11.084709348 -5.6698729811 8.0493451809 9.0606141491 -8.75 +8.0493451809 10.939385851 -8.75 8.8737889151 9.4576453261 -7.8349364905 8.8737889151 10.542354674 -7.8349364905 +8.8873953302 5.1253604391 -10 8.8873953302 14.874639561 -10 9.0364560916 5.778438306 -7.5 +9.0364560916 14.221561694 -7.5 9.4436976651 7.5626802195 -10 9.4436976651 7.5626802195 -5.6698729811 +9.4436976651 12.43731978 -10 9.4436976651 12.43731978 -5.6698729811 9.5182280458 7.889219153 -8.75 +9.5182280458 12.110780847 -8.75 9.7218488326 8.7813401098 -7.8349364905 9.7218488326 11.21865989 -7.8349364905 +10 10 -10 10 10 -7.5 10 10 -5 +10.779362252 9.0227106469 -7.8349364905 10.779362252 10.977289353 -7.8349364905 11.25 10 -7.8349364905 +11.349895019 8.3072851868 -8.75 11.349895019 11.692714813 -8.75 11.558724505 8.0454212938 -10 +11.558724505 8.0454212938 -5.6698729811 11.558724505 11.954578706 -10 11.558724505 11.954578706 -5.6698729811 +12.165063509 10 -8.75 12.5 10 -10 12.5 10 -5.6698729811 +12.699790037 6.6145703735 -7.5 12.699790037 13.385429626 -7.5 13.117449009 6.0908425877 -10 +13.117449009 13.909157412 -10 14.330127019 10 -7.5 14.330127019 10 -7.5 +15 10 -10 15 10 -10 10 10 -8.75 +10 10 -6.25 10.625 10 -8.9174682453 11.875 10 -6.7524047358 +11.082531755 10 -9.375 13.247595264 10 -8.125 11.25 10 -10 +13.75 10 -10 10.389681126 10.488644677 -8.9174682453 11.169043378 11.46593403 -6.7524047358 +10.674947509 10.846357407 -9.375 12.024842528 12.53907222 -8.125 10.779362252 10.977289353 -10 +12.338086757 12.931868059 -10 9.8609244163 10.609329945 -8.9174682453 9.5827732488 11.827989835 -6.7524047358 +9.7591140229 11.055390424 -9.375 9.2773420687 13.166171271 -8.125 9.7218488326 11.21865989 -10 +9.1655464977 13.655979671 -10 9.4368944576 10.271177337 -8.9174682453 8.3106833727 10.813532011 -6.7524047358 +9.0246725905 10.469692925 -9.375 7.0740177714 11.409078776 -8.125 8.8737889151 10.542354674 -10 +6.6213667454 11.627064022 -10 9.4368944576 9.7288226631 -8.9174682453 8.3106833727 9.1864679892 -6.7524047358 +9.0246725905 9.5303070745 -9.375 7.0740177714 8.5909212236 -8.125 8.8737889151 9.4576453261 -10 +6.6213667454 8.3729359783 -10 9.8609244163 9.3906700549 -8.9174682453 9.5827732488 8.1720101647 -6.7524047358 +9.7591140229 8.9446095765 -9.375 9.2773420687 6.8338287295 -8.125 9.7218488326 8.7813401098 -10 +9.1655464977 6.3440203293 -10 10.389681126 9.5113553235 -8.9174682453 11.169043378 8.5340659704 -6.7524047358 +10.674947509 9.1536425934 -9.375 12.024842528 7.4609277801 -8.125 10.779362252 9.0227106469 -10 +12.338086757 7.0681319407 -10 10.647047613 10 -7.5851854343 11.294095226 10 -5.1703708686 +11.767766953 10 -8.232233047 13.535533906 10 -6.4644660941 12.414814566 10 -9.3529523872 +14.829629131 10 -8.7059047745 10.403427588 10.505882194 -7.5851854343 10.806855176 11.011764389 -5.1703708686 +11.102184667 11.382095857 -8.232233047 12.204369334 12.764191715 -6.4644660941 11.505612255 11.887978052 -9.3529523872 +13.01122451 13.775956104 -8.7059047745 9.8560183609 10.630824778 -7.5851854343 9.7120367218 11.261649556 -5.1703708686 +9.6066348466 11.723445345 -8.232233047 9.2132696932 13.446890689 -6.4644660941 9.4626532075 12.354270123 -9.3529523872 +8.925306415 14.708540246 -8.7059047745 9.4170302449 10.280743438 -7.5851854343 8.8340604897 10.561486875 -5.1703708686 +8.4072970097 10.767005335 -8.232233047 6.8145940193 11.534010671 -6.4644660941 7.8243272545 11.047748773 -9.3529523872 +5.6486545091 12.095497546 -8.7059047745 9.4170302449 9.7192565624 -7.5851854343 8.8340604897 9.4385131248 -5.1703708686 +8.4072970097 9.2329946646 -8.232233047 6.8145940193 8.4659893291 -6.4644660941 7.8243272545 8.9522512269 -9.3529523872 +5.6486545091 7.9045024539 -8.7059047745 9.8560183609 9.3691752218 -7.5851854343 9.7120367218 8.7383504436 -5.1703708686 +9.6066348466 8.2765546553 -8.232233047 9.2132696932 6.5531093106 -6.4644660941 9.4626532075 7.6457298771 -9.3529523872 +8.925306415 5.2914597543 -8.7059047745 10.403427588 9.4941178057 -7.5851854343 10.806855176 8.9882356114 -5.1703708686 +11.102184667 8.6179041425 -8.232233047 12.204369334 7.235808285 -6.4644660941 11.505612255 8.1120219482 -9.3529523872 +13.01122451 6.2240438964 -8.7059047745 11.126211085 10.542354674 -7.8349364905 12.25242217 11.084709348 -5.6698729811 +11.950654819 10.939385851 -8.75 13.901309638 11.878771702 -7.5 12.25242217 11.084709348 -10 +14.50484434 12.169418696 -10 10.278151167 11.21865989 -7.8349364905 10.556302335 12.43731978 -5.6698729811 +10.481771954 12.110780847 -8.75 10.963543908 14.221561694 -7.5 10.556302335 12.43731978 -10 +11.11260467 14.874639561 -10 9.2206377477 10.977289353 -7.8349364905 8.4412754954 11.954578706 -5.6698729811 +8.6501049815 11.692714813 -8.75 7.3002099629 13.385429626 -7.5 8.4412754954 11.954578706 -10 +6.8825509907 13.909157412 -10 8.75 10 -7.8349364905 7.5 10 -5.6698729811 +7.8349364905 10 -8.75 5.6698729811 10 -7.5 7.5 10 -10 +5 10 -10 9.2206377477 9.0227106469 -7.8349364905 8.4412754954 8.0454212938 -5.6698729811 +8.6501049815 8.3072851868 -8.75 7.3002099629 6.6145703735 -7.5 8.4412754954 8.0454212938 -10 +6.8825509907 6.0908425877 -10 10.278151167 8.7813401098 -7.8349364905 10.556302335 7.5626802195 -5.6698729811 +10.481771954 7.889219153 -8.75 10.963543908 5.778438306 -7.5 10.556302335 7.5626802195 -10 +11.11260467 5.1253604391 -10 11.126211085 9.4576453261 -7.8349364905 12.25242217 8.9152906522 -5.6698729811 +11.950654819 9.0606141491 -8.75 13.901309638 8.1212282982 -7.5 12.25242217 8.9152906522 -10 +14.50484434 7.8305813044 -10 +CELLS 43 840 +OFFSETS vtktypeint64 +0 20 40 60 80 100 120 140 160 +180 200 220 240 260 280 300 320 340 +360 380 400 420 440 460 480 500 520 +540 560 580 600 620 640 660 680 700 +720 740 760 780 800 820 840 +CONNECTIVITY vtktypeint64 +24 25 29 24 24 25 28 24 47 +91 49 24 47 97 55 24 24 25 +133 24 25 26 38 29 25 26 35 +28 48 92 50 91 48 98 56 97 +25 26 134 133 24 29 36 24 24 +28 31 24 49 93 51 24 55 99 +57 24 24 133 135 24 29 38 43 +36 28 35 40 31 50 94 52 93 +56 100 58 99 133 134 136 135 24 +36 37 24 24 31 34 24 51 95 +53 24 57 101 59 24 24 135 137 +24 36 43 45 37 31 40 42 34 +52 96 54 95 58 102 60 101 135 +136 138 137 24 25 28 24 24 25 +23 24 47 97 55 24 47 103 61 +24 24 25 139 24 25 26 35 28 +25 26 19 23 48 98 56 97 48 +104 62 103 25 26 140 139 24 28 +31 24 24 23 21 24 55 99 57 +24 61 105 63 24 24 139 141 24 +28 35 40 31 23 19 15 21 56 +100 58 99 62 106 64 105 139 140 +142 141 24 31 34 24 24 21 18 +24 57 101 59 24 63 107 65 24 +24 141 143 24 31 40 42 34 21 +15 13 18 58 102 60 101 64 108 +66 107 141 142 144 143 24 25 23 +24 24 25 11 24 47 103 61 24 +47 109 67 24 24 25 145 24 25 +26 19 23 25 26 7 11 48 104 +62 103 48 110 68 109 25 26 146 +145 24 23 21 24 24 11 9 24 +61 105 63 24 67 111 69 24 24 +145 147 24 23 19 15 21 11 7 +3 9 62 106 64 105 68 112 70 +111 145 146 148 147 24 21 18 24 +24 9 6 24 63 107 65 24 69 +113 71 24 24 147 149 24 21 15 +13 18 9 3 1 6 64 108 66 +107 70 114 72 113 147 148 150 149 +24 25 11 24 24 25 10 24 47 +109 67 24 47 115 73 24 24 25 +151 24 25 26 7 11 25 26 5 +10 48 110 68 109 48 116 74 115 +25 26 152 151 24 11 9 24 24 +10 8 24 67 111 69 24 73 117 +75 24 24 151 153 24 11 7 3 +9 10 5 2 8 68 112 70 111 +74 118 76 117 151 152 154 153 24 +9 6 24 24 8 4 24 69 113 +71 24 75 119 77 24 24 153 155 +24 9 3 1 6 8 2 0 4 +70 114 72 113 76 120 78 119 153 +154 156 155 24 25 10 24 24 25 +22 24 47 115 73 24 47 121 79 +24 24 25 157 24 25 26 5 10 +25 26 17 22 48 116 74 115 48 +122 80 121 25 26 158 157 24 10 +8 24 24 22 20 24 73 117 75 +24 79 123 81 24 24 157 159 24 +10 5 2 8 22 17 14 20 74 +118 76 117 80 124 82 123 157 158 +160 159 24 8 4 24 24 20 16 +24 75 119 77 24 81 125 83 24 +24 159 161 24 8 2 0 4 20 +14 12 16 76 120 78 119 82 126 +84 125 159 160 162 161 24 25 22 +24 24 25 27 24 47 121 79 24 +47 127 85 24 24 25 163 24 25 +26 17 22 25 26 33 27 48 122 +80 121 48 128 86 127 25 26 164 +163 24 22 20 24 24 27 30 24 +79 123 81 24 85 129 87 24 24 +163 165 24 22 17 14 20 27 33 +39 30 80 124 82 123 86 130 88 +129 163 164 166 165 24 20 16 24 +24 30 32 24 81 125 83 24 87 +131 89 24 24 165 167 24 20 14 +12 16 30 39 41 32 82 126 84 +125 88 132 90 131 165 166 168 167 +24 25 27 24 24 25 29 24 47 +127 85 24 47 91 49 24 24 25 +169 24 25 26 33 27 25 26 38 +29 48 128 86 127 48 92 50 91 +25 26 170 169 24 27 30 24 24 +29 36 24 85 129 87 24 49 93 +51 24 24 169 171 24 27 33 39 +30 29 38 43 36 86 130 88 129 +50 94 52 93 169 170 172 171 24 +30 32 24 24 36 37 24 87 131 +89 24 51 95 53 24 24 171 173 +24 30 39 41 32 36 43 45 37 +88 132 90 131 52 96 54 95 171 +172 174 173 +CELL_TYPES 42 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 +25 + diff --git a/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk b/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk new file mode 100644 index 00000000000..3dff18a0839 --- /dev/null +++ b/tests/unit_tests/mesh_to_vtk/spherical-linear.vtk @@ -0,0 +1,39 @@ +# vtk DataFile Version 5.1 +vtk output +ASCII +DATASET STRUCTURED_GRID +DIMENSIONS 3 4 8 +POINTS 96 double +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 11.25 10 -7.8349364905 12.5 10 -5.6698729811 +10 10 -10 12.165063509 10 -8.75 14.330127019 10 -7.5 +10 10 -10 12.5 10 -10 15 10 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 10.779362252 10.977289353 -7.8349364905 11.558724505 11.954578706 -5.6698729811 +10 10 -10 11.349895019 11.692714813 -8.75 12.699790037 13.385429626 -7.5 +10 10 -10 11.558724505 11.954578706 -10 13.117449009 13.909157412 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 9.7218488326 11.21865989 -7.8349364905 9.4436976651 12.43731978 -5.6698729811 +10 10 -10 9.5182280458 12.110780847 -8.75 9.0364560916 14.221561694 -7.5 +10 10 -10 9.4436976651 12.43731978 -10 8.8873953302 14.874639561 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 8.8737889151 10.542354674 -7.8349364905 7.7475778302 11.084709348 -5.6698729811 +10 10 -10 8.0493451809 10.939385851 -8.75 6.0986903619 11.878771702 -7.5 +10 10 -10 7.7475778302 11.084709348 -10 5.4951556605 12.169418696 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 8.8737889151 9.4576453261 -7.8349364905 7.7475778302 8.9152906522 -5.6698729811 +10 10 -10 8.0493451809 9.0606141491 -8.75 6.0986903619 8.1212282982 -7.5 +10 10 -10 7.7475778302 8.9152906522 -10 5.4951556605 7.8305813044 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 9.7218488326 8.7813401098 -7.8349364905 9.4436976651 7.5626802195 -5.6698729811 +10 10 -10 9.5182280458 7.889219153 -8.75 9.0364560916 5.778438306 -7.5 +10 10 -10 9.4436976651 7.5626802195 -10 8.8873953302 5.1253604391 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 10.779362252 9.0227106469 -7.8349364905 11.558724505 8.0454212938 -5.6698729811 +10 10 -10 11.349895019 8.3072851868 -8.75 12.699790037 6.6145703735 -7.5 +10 10 -10 11.558724505 8.0454212938 -10 13.117449009 6.0908425877 -10 +10 10 -10 10 10 -7.5 10 10 -5 +10 10 -10 11.25 10 -7.8349364905 12.5 10 -5.6698729811 +10 10 -10 12.165063509 10 -8.75 14.330127019 10 -7.5 +10 10 -10 12.5 10 -10 15 10 -10 + diff --git a/tests/unit_tests/mesh_to_vtk/test.py b/tests/unit_tests/mesh_to_vtk/test.py index 5f6cd6a41f2..36928676cff 100644 --- a/tests/unit_tests/mesh_to_vtk/test.py +++ b/tests/unit_tests/mesh_to_vtk/test.py @@ -1,69 +1,99 @@ +import difflib import filecmp -from itertools import product -from pathlib import Path - import numpy as np +from pathlib import Path import openmc -import openmc.lib import pytest -pytest.importorskip('vtk') - - -def ids_func(param): - return f"{param['library']}_{param['elem_type']}" - -test_params = (['libmesh', 'moab'], - ['tets', 'hexes']) +from tests.regression_tests import config -test_cases = [ - {'library' : library, 'elem_type' : elem_type} - for library, elem_type in product(*test_params) -] - -@pytest.mark.parametrize("test_opts", test_cases, ids=ids_func) -def test_unstructured_mesh_to_vtk(run_in_tmpdir, request, test_opts): - - if test_opts['library'] == 'moab' and test_opts['elem_type'] == 'hexes': - pytest.skip('Hexes are not supported with MOAB') - - if test_opts['library'] == 'libmesh' and not openmc.lib._libmesh_enabled(): - pytest.skip('LibMesh is not enabled in this build.') - - if test_opts['library'] == 'moab' and not openmc.lib._dagmc_enabled(): - pytest.skip('DAGMC (and MOAB) mesh not enabled in this build.') - - # pull in a simple model -- just need to create the statepoint file - openmc.reset_auto_ids() - model = openmc.examples.pwr_pin_cell() - - if test_opts['elem_type'] == 'tets': - filename = Path('tets.exo') - else: - filename = Path('hexes.exo') +pytest.importorskip('vtk') - # create a basic tally using the unstructured mesh - umesh = openmc.UnstructuredMesh(request.node.path.parent / filename, - test_opts['library']) - umesh.output = False - mesh_filter = openmc.MeshFilter(umesh) - tally = openmc.Tally() - tally.filters = [mesh_filter] - tally.scores = ['flux'] - tally.estimator = 'collision' - model.tallies = openmc.Tallies([tally]) - sp_file = model.run() +def full_path(f): + return Path(__file__).parent.absolute() / f + +def diff_file(file1, file2): + with open(file1) as fh: + f1_text = fh.readlines() + with open(file2) as fh: + f2_text = fh.readlines() + diff_lines = difflib.unified_diff(f1_text, f2_text) + return ''.join(diff_lines) + +# test meshes +reg_mesh = openmc.RegularMesh() +reg_mesh.lower_left = (0, 0, 0) +reg_mesh.upper_right = (20, 50, 50) +reg_mesh.dimension = (10, 20, 30) + +rect_mesh = openmc.RectilinearMesh() +rect_mesh.x_grid = np.linspace(0, 10, 5) +rect_mesh.y_grid = np.geomspace(5., 20., 10) +rect_mesh.z_grid = np.linspace(1, 100, 20) + +cyl_mesh = openmc.CylindricalMesh() +cyl_mesh.origin = (10, 10, -10) +cyl_mesh.r_grid = np.linspace(0, 5, 5) +cyl_mesh.phi_grid = np.linspace(0, 2 * np.pi, 4) +cyl_mesh.z_grid = np.linspace(0, 2, 4) + +sphere_mesh = openmc.SphericalMesh() +sphere_mesh.origin = (10, 10, -10) +sphere_mesh.r_grid = np.linspace(0, 5, 3) +sphere_mesh.theta_grid = np.linspace(0, 0.5 * np.pi, 4) +sphere_mesh.phi_grid = np.linspace(0, 2*np.pi, 8) + + +def mesh_data(mesh_dims): + data = 100 * np.arange(np.prod(mesh_dims), dtype=float) + return data.reshape(*mesh_dims) + +test_data = ((reg_mesh, False, 'regular'), + (rect_mesh, False, 'rectilinear'), + (cyl_mesh, False, 'cylindrical-linear'), + (cyl_mesh, True, 'cylindrical-curvilinear'), + (sphere_mesh, False, 'spherical-linear'), + (sphere_mesh, True, 'spherical-curvilinear')) + +@pytest.mark.parametrize('mesh_params', + test_data, + ids=lambda params: params[2]) +def test_mesh_write_vtk(mesh_params, run_in_tmpdir): + mesh, curvilinear, filename = mesh_params + + test_data = full_path(filename + ".vtk") + kwargs = {} + if curvilinear: + kwargs['curvilinear'] = curvilinear + + # set output filename based on test configuration + filename = test_data if config['update'] else filename + "-actual.vtk" + + # write the mesh file and compare to the expected version + mesh.write_data_to_vtk(filename, **kwargs) + + try: + assert filecmp.cmp(test_data, filename) + except AssertionError as e: + diff = diff_file(test_data, filename) + raise AssertionError(diff) from e + +# check data writing +def test_mesh_write_vtk_data(run_in_tmpdir): + + data = {'ascending_data': mesh_data(cyl_mesh.dimension)} + filename_expected = full_path('cyl-data.vtk') + filename_actual = full_path('cyl-data-actual.vtk') + # update the test file if requested + filename = filename_expected if config['update'] else filename_actual + cyl_mesh.write_data_to_vtk(filename, datasets=data, volume_normalization=False) + + try: + assert filecmp.cmp(filename, filename_expected) + except AssertionError as e: + diff = diff_file(filename_expected, filename) + raise AssertionError(diff) from e - # check VTK output after reading mesh from statepoint file - with openmc.StatePoint(sp_file) as sp: - umesh = sp.meshes[umesh.id] - test_data = {'ids': np.arange(umesh.n_elements)} - umesh.write_data_to_vtk('umesh.vtk', - datasets=test_data, - volume_normalization=False) - # compare file content with reference file - ref_file = Path(f"{test_opts['library']}_{test_opts['elem_type']}_ref.vtk") - assert filecmp.cmp('umesh.vtk', request.node.path.parent / ref_file) diff --git a/tests/unit_tests/test_mesh_to_vtk.py b/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py similarity index 99% rename from tests/unit_tests/test_mesh_to_vtk.py rename to tests/unit_tests/mesh_to_vtk/test_vtk_dims.py index 2e2790e0a5f..f7f5af8d054 100644 --- a/tests/unit_tests/test_mesh_to_vtk.py +++ b/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py @@ -212,7 +212,7 @@ def mesh_surf_id(param): @pytest.mark.parametrize("mesh,surface", product(MESHES, SURFS), ids=mesh_surf_id) -def test_vtk_write_ordering(model, mesh, surface): +def test_vtk_write_ordering(run_in_tmpdir, model, mesh, surface): tally = openmc.Tally() tally.scores = ['flux'] From 3eeb13171351fc25a72a1ab54e97f7d729e21fac Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 16 Jun 2023 15:18:12 -0500 Subject: [PATCH 30/45] Add support for import of wwinp files using cylindrical and spherical meshes. (#2556) Co-authored-by: Paul Romano --- openmc/weight_windows.py | 52 ++++++----- tests/regression_tests/weightwindows/test.py | 62 +++++++++++++ .../weightwindows/ww_n_cyl.txt | 88 ++++++++++++++++++ .../weightwindows/ww_n_sph.txt | 89 +++++++++++++++++++ 4 files changed, 270 insertions(+), 21 deletions(-) create mode 100644 tests/regression_tests/weightwindows/ww_n_cyl.txt create mode 100644 tests/regression_tests/weightwindows/ww_n_sph.txt diff --git a/openmc/weight_windows.py b/openmc/weight_windows.py index 2411b83f805..bbc5c2f1836 100644 --- a/openmc/weight_windows.py +++ b/openmc/weight_windows.py @@ -11,7 +11,7 @@ import openmc from openmc.filter import _PARTICLES -from openmc.mesh import MeshBase, RectilinearMesh, UnstructuredMesh +from openmc.mesh import MeshBase, RectilinearMesh, CylindricalMesh, SphericalMesh, UnstructuredMesh import openmc.checkvalue as cv from openmc.checkvalue import PathLike @@ -494,10 +494,6 @@ def wwinp_to_wws(path: PathLike) -> List[WeightWindows]: else: nt = ni * [1] - if nr == 16: - raise NotImplementedError('Cylindrical and spherical mesh ' - 'types are not yet supported') - # read number of energy bins for each particle, 'ne(1...ni)' ne = np.fromstring(wwinp.readline(), sep=' ', dtype=int) @@ -512,14 +508,18 @@ def wwinp_to_wws(path: PathLike) -> List[WeightWindows]: line_arr = np.fromstring(wwinp.readline(), sep=' ') ncx, ncy, ncz = line_arr[:3].astype(int) # read polar vector (x1, y1, z1) - xyz1 = line_arr[3:] - xyz0 - polar_vec = xyz1 / np.linalg.norm(xyz1) + xyz1 = line_arr[3:] # read azimuthal vector (x2, y2, z2) line_arr = np.fromstring(wwinp.readline(), sep=' ') - xyz2 = line_arr[:3] - xyz0 - azimuthal_vec = xyz2 / np.linalg.norm(xyz2) + xyz2 = line_arr[:3] + + # oriented polar and azimuthal vectors aren't yet supported + if np.count_nonzero(xyz1) or np.count_nonzero(xyz2): + raise NotImplementedError('Custom sphere/cylinder orientations are not supported') + # read geometry type nwg = int(line_arr[-1]) + elif nr == 10: # read rectilinear data: # number of coarse mesh bins and mesh type @@ -537,39 +537,40 @@ def wwinp_to_wws(path: PathLike) -> List[WeightWindows]: # first values in the mesh definition arrays are the first # coordinate of the grid end_idx = start_idx + 1 + 3 * ncx - x0, x_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + i0, i_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] start_idx = end_idx end_idx = start_idx + 1 + 3 * ncy - y0, y_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + j0, j_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] start_idx = end_idx end_idx = start_idx + 1 + 3 * ncz - z0, z_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] + k0, k_vals = ww_data[start_idx], ww_data[start_idx+1:end_idx] start_idx = end_idx # mesh consistency checks - if nr == 16 and nwg == 1: + if nr == 16 and nwg == 1 or nr == 10 and nwg != 1: raise ValueError(f'Mesh description in header ({nr}) ' f'does not match the mesh type ({nwg})') - if (xyz0 != (x0, y0, z0)).any(): + if nr == 10 and (xyz0 != (i0, j0, k0)).any(): raise ValueError(f'Mesh origin in the header ({xyz0}) ' f' does not match the origin in the mesh ' - f' description ({x0, y0, z0})') + f' description ({i0, j0, k0})') # create openmc mesh object grids = [] - mesh_definition = [(x0, x_vals, nfx), (y0, y_vals, nfy), (z0, z_vals, nfz)] + mesh_definition = [(i0, i_vals, nfx), (j0, j_vals, nfy), (k0, k_vals, nfz)] for grid0, grid_vals, n_pnts in mesh_definition: # file spec checks for the mesh definition if (grid_vals[2::3] != 1.0).any(): raise ValueError('One or more mesh ratio value, qx, ' 'is not equal to one') - if grid_vals[::3].sum() != n_pnts: - raise ValueError('Sum of the fine bin entries, s, does ' - 'not match the number of fine bins') + s = int(grid_vals[::3].sum()) + if s != n_pnts: + raise ValueError(f'Sum of the fine bin entries, {s}, does ' + f'not match the number of fine bins, {n_pnts}') # extend the grid based on the next coarse bin endpoint, px # and the number of fine bins in the coarse bin, sx @@ -580,8 +581,17 @@ def wwinp_to_wws(path: PathLike) -> List[WeightWindows]: grids.append(np.array(coords)) - mesh = RectilinearMesh() - mesh.x_grid, mesh.y_grid, mesh.z_grid = grids + if nwg == 1: + mesh = RectilinearMesh() + mesh.x_grid, mesh.y_grid, mesh.z_grid = grids + elif nwg == 2: + mesh = CylindricalMesh() + mesh.r_grid, mesh.z_grid, mesh.phi_grid = grids + mesh.origin = xyz0 + elif nwg == 3: + mesh = SphericalMesh() + mesh.r_grid, mesh.theta_grid, mesh.phi_grid = grids + mesh.origin = xyz0 # extract weight window values from array wws = [] diff --git a/tests/regression_tests/weightwindows/test.py b/tests/regression_tests/weightwindows/test.py index 3d3cf9d7ae2..b7a0e4fe1d4 100644 --- a/tests/regression_tests/weightwindows/test.py +++ b/tests/regression_tests/weightwindows/test.py @@ -110,3 +110,65 @@ def model(): def test_weightwindows(model): test = HashedPyAPITestHarness('statepoint.2.h5', model) test.main() + + +def test_wwinp_cylindrical(): + + ww = openmc.wwinp_to_wws('ww_n_cyl.txt')[0] + + mesh = ww.mesh + + assert mesh.dimension == (8, 8, 7) + + # make sure that the mesh grids are correct + exp_r_grid = np.hstack((np.linspace(0.0, 3.02, 3, endpoint=False), + np.linspace(3.02, 6.0001, 6))).flatten() + + exp_phi_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), + np.linspace(0.25, 1.5707, 1, endpoint=False), + np.linspace(1.5707, 3.1415, 2, endpoint=False), + np.linspace(3.1415, 4.7124, 4))).flatten() + + exp_z_grid = np.hstack((np.linspace(0.0, 8.008, 4, endpoint=False), + np.linspace(8.008, 14.002, 4))).flatten() + + assert isinstance(mesh, openmc.CylindricalMesh) + + np.testing.assert_equal(mesh.r_grid, exp_r_grid) + np.testing.assert_equal(mesh.phi_grid, exp_phi_grid) + np.testing.assert_equal(mesh.z_grid, exp_z_grid) + np.testing.assert_equal(mesh.origin, (0, 0, -9.0001)) + assert ww.lower_ww_bounds.flat[0] == 0.0 + assert ww.lower_ww_bounds.flat[-1] == np.prod(mesh.dimension) - 1 + + +def test_wwinp_spherical(): + + ww = openmc.wwinp_to_wws('ww_n_sph.txt')[0] + + mesh = ww.mesh + + assert mesh.dimension == (8, 7, 8) + + # make sure that the mesh grids are correct + exp_r_grid = np.hstack((np.linspace(0.0, 3.02, 3, endpoint=False), + np.linspace(3.02, 6.0001, 6))).flatten() + + exp_theta_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), + np.linspace(0.25, 0.5, 1, endpoint=False), + np.linspace(0.5, 0.75, 2, endpoint=False), + np.linspace(0.75, 1.5707, 3))).flatten() + + exp_phi_grid = np.hstack((np.linspace(0.0, 0.25, 2, endpoint=False), + np.linspace(0.25, 0.5, 1, endpoint=False), + np.linspace(0.5, 1.5707, 2, endpoint=False), + np.linspace(1.5707, 3.1415, 4))).flatten() + + assert isinstance(mesh, openmc.SphericalMesh) + + np.testing.assert_equal(mesh.r_grid, exp_r_grid) + np.testing.assert_equal(mesh.theta_grid, exp_theta_grid) + np.testing.assert_equal(mesh.phi_grid, exp_phi_grid) + np.testing.assert_equal(mesh.origin, (0, 0, -9.0001)) + assert ww.lower_ww_bounds.flat[0] == 0.0 + assert ww.lower_ww_bounds.flat[-1] == np.prod(mesh.dimension) - 1 diff --git a/tests/regression_tests/weightwindows/ww_n_cyl.txt b/tests/regression_tests/weightwindows/ww_n_cyl.txt new file mode 100644 index 00000000000..89232628fa1 --- /dev/null +++ b/tests/regression_tests/weightwindows/ww_n_cyl.txt @@ -0,0 +1,88 @@ +1 1 1 16 +1 +8.0000 7.0000 8.0000 0.0000 0.0000 -9.0001 +2.0000 2.0000 4.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 2.0000 +0.0000 3.0000 3.0200 1.0000 5.0000 6.0001 +1.0000 +0.0000 4.0000 8.0080 1.0000 3.0000 14.002 +1.0000 +0.0000 2.0000 0.25000 1.0000 1.0000 1.57070 +1.0000 2.0000 3.1415 1.0000 3.0000 4.7124 +1.0000 +100.00 +0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 +6.000000 7.000000 8.000000 9.000000 10.000000 11.000000 +12.000000 13.000000 14.000000 15.000000 16.000000 17.000000 +18.000000 19.000000 20.000000 21.000000 22.000000 23.000000 +24.000000 25.000000 26.000000 27.000000 28.000000 29.000000 +30.000000 31.000000 32.000000 33.000000 34.000000 35.000000 +36.000000 37.000000 38.000000 39.000000 40.000000 41.000000 +42.000000 43.000000 44.000000 45.000000 46.000000 47.000000 +48.000000 49.000000 50.000000 51.000000 52.000000 53.000000 +54.000000 55.000000 56.000000 57.000000 58.000000 59.000000 +60.000000 61.000000 62.000000 63.000000 64.000000 65.000000 +66.000000 67.000000 68.000000 69.000000 70.000000 71.000000 +72.000000 73.000000 74.000000 75.000000 76.000000 77.000000 +78.000000 79.000000 80.000000 81.000000 82.000000 83.000000 +84.000000 85.000000 86.000000 87.000000 88.000000 89.000000 +90.000000 91.000000 92.000000 93.000000 94.000000 95.000000 +96.000000 97.000000 98.000000 99.000000 100.000000 101.000000 +102.000000 103.000000 104.000000 105.000000 106.000000 107.000000 +108.000000 109.000000 110.000000 111.000000 112.000000 113.000000 +114.000000 115.000000 116.000000 117.000000 118.000000 119.000000 +120.000000 121.000000 122.000000 123.000000 124.000000 125.000000 +126.000000 127.000000 128.000000 129.000000 130.000000 131.000000 +132.000000 133.000000 134.000000 135.000000 136.000000 137.000000 +138.000000 139.000000 140.000000 141.000000 142.000000 143.000000 +144.000000 145.000000 146.000000 147.000000 148.000000 149.000000 +150.000000 151.000000 152.000000 153.000000 154.000000 155.000000 +156.000000 157.000000 158.000000 159.000000 160.000000 161.000000 +162.000000 163.000000 164.000000 165.000000 166.000000 167.000000 +168.000000 169.000000 170.000000 171.000000 172.000000 173.000000 +174.000000 175.000000 176.000000 177.000000 178.000000 179.000000 +180.000000 181.000000 182.000000 183.000000 184.000000 185.000000 +186.000000 187.000000 188.000000 189.000000 190.000000 191.000000 +192.000000 193.000000 194.000000 195.000000 196.000000 197.000000 +198.000000 199.000000 200.000000 201.000000 202.000000 203.000000 +204.000000 205.000000 206.000000 207.000000 208.000000 209.000000 +210.000000 211.000000 212.000000 213.000000 214.000000 215.000000 +216.000000 217.000000 218.000000 219.000000 220.000000 221.000000 +222.000000 223.000000 224.000000 225.000000 226.000000 227.000000 +228.000000 229.000000 230.000000 231.000000 232.000000 233.000000 +234.000000 235.000000 236.000000 237.000000 238.000000 239.000000 +240.000000 241.000000 242.000000 243.000000 244.000000 245.000000 +246.000000 247.000000 248.000000 249.000000 250.000000 251.000000 +252.000000 253.000000 254.000000 255.000000 256.000000 257.000000 +258.000000 259.000000 260.000000 261.000000 262.000000 263.000000 +264.000000 265.000000 266.000000 267.000000 268.000000 269.000000 +270.000000 271.000000 272.000000 273.000000 274.000000 275.000000 +276.000000 277.000000 278.000000 279.000000 280.000000 281.000000 +282.000000 283.000000 284.000000 285.000000 286.000000 287.000000 +288.000000 289.000000 290.000000 291.000000 292.000000 293.000000 +294.000000 295.000000 296.000000 297.000000 298.000000 299.000000 +300.000000 301.000000 302.000000 303.000000 304.000000 305.000000 +306.000000 307.000000 308.000000 309.000000 310.000000 311.000000 +312.000000 313.000000 314.000000 315.000000 316.000000 317.000000 +318.000000 319.000000 320.000000 321.000000 322.000000 323.000000 +324.000000 325.000000 326.000000 327.000000 328.000000 329.000000 +330.000000 331.000000 332.000000 333.000000 334.000000 335.000000 +336.000000 337.000000 338.000000 339.000000 340.000000 341.000000 +342.000000 343.000000 344.000000 345.000000 346.000000 347.000000 +348.000000 349.000000 350.000000 351.000000 352.000000 353.000000 +354.000000 355.000000 356.000000 357.000000 358.000000 359.000000 +360.000000 361.000000 362.000000 363.000000 364.000000 365.000000 +366.000000 367.000000 368.000000 369.000000 370.000000 371.000000 +372.000000 373.000000 374.000000 375.000000 376.000000 377.000000 +378.000000 379.000000 380.000000 381.000000 382.000000 383.000000 +384.000000 385.000000 386.000000 387.000000 388.000000 389.000000 +390.000000 391.000000 392.000000 393.000000 394.000000 395.000000 +396.000000 397.000000 398.000000 399.000000 400.000000 401.000000 +402.000000 403.000000 404.000000 405.000000 406.000000 407.000000 +408.000000 409.000000 410.000000 411.000000 412.000000 413.000000 +414.000000 415.000000 416.000000 417.000000 418.000000 419.000000 +420.000000 421.000000 422.000000 423.000000 424.000000 425.000000 +426.000000 427.000000 428.000000 429.000000 430.000000 431.000000 +432.000000 433.000000 434.000000 435.000000 436.000000 437.000000 +438.000000 439.000000 440.000000 441.000000 442.000000 443.000000 +444.000000 445.000000 446.000000 447.000000 diff --git a/tests/regression_tests/weightwindows/ww_n_sph.txt b/tests/regression_tests/weightwindows/ww_n_sph.txt new file mode 100644 index 00000000000..3f9b8dab6d2 --- /dev/null +++ b/tests/regression_tests/weightwindows/ww_n_sph.txt @@ -0,0 +1,89 @@ +1 1 1 16 +1 +8.0000 7.0000 8.0000 0.0000 0.0000 -9.0001 +2.0000 4.0000 4.0000 0.0000 0.0000 0.0000 +0.0000 0.0000 0.0000 3.0000 +0.0000 3.0000 3.0200 1.0000 5.0000 6.0001 +1.0000 +0.0000 2.0000 0.25000 1.0000 1.0000 0.50000 +1.0000 2.0000 0.75000 1.0000 2.0000 1.5707 +1.0000 +0.0000 2.0000 0.25000 1.0000 1.0000 0.50000 +1.0000 2.0000 1.5707 1.0000 3.0000 3.1415 +1.0000 +100.00 +0.000000 1.000000 2.000000 3.000000 4.000000 5.000000 +6.000000 7.000000 8.000000 9.000000 10.000000 11.000000 +12.000000 13.000000 14.000000 15.000000 16.000000 17.000000 +18.000000 19.000000 20.000000 21.000000 22.000000 23.000000 +24.000000 25.000000 26.000000 27.000000 28.000000 29.000000 +30.000000 31.000000 32.000000 33.000000 34.000000 35.000000 +36.000000 37.000000 38.000000 39.000000 40.000000 41.000000 +42.000000 43.000000 44.000000 45.000000 46.000000 47.000000 +48.000000 49.000000 50.000000 51.000000 52.000000 53.000000 +54.000000 55.000000 56.000000 57.000000 58.000000 59.000000 +60.000000 61.000000 62.000000 63.000000 64.000000 65.000000 +66.000000 67.000000 68.000000 69.000000 70.000000 71.000000 +72.000000 73.000000 74.000000 75.000000 76.000000 77.000000 +78.000000 79.000000 80.000000 81.000000 82.000000 83.000000 +84.000000 85.000000 86.000000 87.000000 88.000000 89.000000 +90.000000 91.000000 92.000000 93.000000 94.000000 95.000000 +96.000000 97.000000 98.000000 99.000000 100.000000 101.000000 +102.000000 103.000000 104.000000 105.000000 106.000000 107.000000 +108.000000 109.000000 110.000000 111.000000 112.000000 113.000000 +114.000000 115.000000 116.000000 117.000000 118.000000 119.000000 +120.000000 121.000000 122.000000 123.000000 124.000000 125.000000 +126.000000 127.000000 128.000000 129.000000 130.000000 131.000000 +132.000000 133.000000 134.000000 135.000000 136.000000 137.000000 +138.000000 139.000000 140.000000 141.000000 142.000000 143.000000 +144.000000 145.000000 146.000000 147.000000 148.000000 149.000000 +150.000000 151.000000 152.000000 153.000000 154.000000 155.000000 +156.000000 157.000000 158.000000 159.000000 160.000000 161.000000 +162.000000 163.000000 164.000000 165.000000 166.000000 167.000000 +168.000000 169.000000 170.000000 171.000000 172.000000 173.000000 +174.000000 175.000000 176.000000 177.000000 178.000000 179.000000 +180.000000 181.000000 182.000000 183.000000 184.000000 185.000000 +186.000000 187.000000 188.000000 189.000000 190.000000 191.000000 +192.000000 193.000000 194.000000 195.000000 196.000000 197.000000 +198.000000 199.000000 200.000000 201.000000 202.000000 203.000000 +204.000000 205.000000 206.000000 207.000000 208.000000 209.000000 +210.000000 211.000000 212.000000 213.000000 214.000000 215.000000 +216.000000 217.000000 218.000000 219.000000 220.000000 221.000000 +222.000000 223.000000 224.000000 225.000000 226.000000 227.000000 +228.000000 229.000000 230.000000 231.000000 232.000000 233.000000 +234.000000 235.000000 236.000000 237.000000 238.000000 239.000000 +240.000000 241.000000 242.000000 243.000000 244.000000 245.000000 +246.000000 247.000000 248.000000 249.000000 250.000000 251.000000 +252.000000 253.000000 254.000000 255.000000 256.000000 257.000000 +258.000000 259.000000 260.000000 261.000000 262.000000 263.000000 +264.000000 265.000000 266.000000 267.000000 268.000000 269.000000 +270.000000 271.000000 272.000000 273.000000 274.000000 275.000000 +276.000000 277.000000 278.000000 279.000000 280.000000 281.000000 +282.000000 283.000000 284.000000 285.000000 286.000000 287.000000 +288.000000 289.000000 290.000000 291.000000 292.000000 293.000000 +294.000000 295.000000 296.000000 297.000000 298.000000 299.000000 +300.000000 301.000000 302.000000 303.000000 304.000000 305.000000 +306.000000 307.000000 308.000000 309.000000 310.000000 311.000000 +312.000000 313.000000 314.000000 315.000000 316.000000 317.000000 +318.000000 319.000000 320.000000 321.000000 322.000000 323.000000 +324.000000 325.000000 326.000000 327.000000 328.000000 329.000000 +330.000000 331.000000 332.000000 333.000000 334.000000 335.000000 +336.000000 337.000000 338.000000 339.000000 340.000000 341.000000 +342.000000 343.000000 344.000000 345.000000 346.000000 347.000000 +348.000000 349.000000 350.000000 351.000000 352.000000 353.000000 +354.000000 355.000000 356.000000 357.000000 358.000000 359.000000 +360.000000 361.000000 362.000000 363.000000 364.000000 365.000000 +366.000000 367.000000 368.000000 369.000000 370.000000 371.000000 +372.000000 373.000000 374.000000 375.000000 376.000000 377.000000 +378.000000 379.000000 380.000000 381.000000 382.000000 383.000000 +384.000000 385.000000 386.000000 387.000000 388.000000 389.000000 +390.000000 391.000000 392.000000 393.000000 394.000000 395.000000 +396.000000 397.000000 398.000000 399.000000 400.000000 401.000000 +402.000000 403.000000 404.000000 405.000000 406.000000 407.000000 +408.000000 409.000000 410.000000 411.000000 412.000000 413.000000 +414.000000 415.000000 416.000000 417.000000 418.000000 419.000000 +420.000000 421.000000 422.000000 423.000000 424.000000 425.000000 +426.000000 427.000000 428.000000 429.000000 430.000000 431.000000 +432.000000 433.000000 434.000000 435.000000 436.000000 437.000000 +438.000000 439.000000 440.000000 441.000000 442.000000 443.000000 +444.000000 445.000000 446.000000 447.000000 From ee7b95245a981d59f9e3bc2a6ba5da1adba0c60b Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sat, 17 Jun 2023 04:34:02 +0100 Subject: [PATCH 31/45] Static errors continuation (#2557) Co-authored-by: Christina Cai Co-authored-by: christinacai123 <63215816+christinacai123@users.noreply.github.com> --- openmc/arithmetic.py | 176 ++++----- openmc/cell.py | 184 ++++----- openmc/data/angle_distribution.py | 8 +- openmc/data/correlated.py | 32 +- openmc/data/data.py | 5 +- openmc/data/decay.py | 48 +-- openmc/data/energy_distribution.py | 97 +++-- openmc/data/fission_energy.py | 70 ++-- openmc/data/function.py | 64 +-- openmc/data/kalbach_mann.py | 40 +- openmc/data/laboratory.py | 31 +- openmc/data/multipole.py | 66 ++-- openmc/data/nbody.py | 24 +- openmc/data/neutron.py | 84 ++-- openmc/data/photon.py | 64 +-- openmc/data/product.py | 40 +- openmc/data/reaction.py | 40 +- openmc/data/resonance.py | 12 +- openmc/data/thermal.py | 8 +- openmc/data/uncorrelated.py | 8 +- openmc/data/urr.py | 40 +- openmc/filter.py | 48 +-- openmc/geometry.py | 18 +- openmc/lattice.py | 58 +-- openmc/lib/plot.py | 52 +-- openmc/lib/tally.py | 8 +- openmc/material.py | 60 +-- openmc/mesh.py | 190 ++++----- openmc/mgxs/groups.py | 8 +- openmc/mgxs/library.py | 206 +++++----- openmc/mgxs/mdgxs.py | 14 +- openmc/mgxs/mgxs.py | 392 +++++++++---------- openmc/mgxs_library.py | 170 ++++---- openmc/model/model.py | 80 ++-- openmc/model/triso.py | 136 +++---- openmc/plots.py | 192 ++++----- openmc/settings.py | 598 ++++++++++++++--------------- openmc/source.py | 100 ++--- openmc/statepoint.py | 40 +- openmc/stats/multivariate.py | 88 ++--- openmc/stats/univariate.py | 72 ++-- openmc/surface.py | 24 +- openmc/tallies.py | 220 +++++------ openmc/tally_derivative.py | 16 +- openmc/trigger.py | 16 +- openmc/universe.py | 18 +- openmc/volume.py | 100 ++--- 47 files changed, 2034 insertions(+), 2031 deletions(-) diff --git a/openmc/arithmetic.py b/openmc/arithmetic.py index 3655ef2a3d6..5ca7cc66682 100644 --- a/openmc/arithmetic.py +++ b/openmc/arithmetic.py @@ -61,26 +61,26 @@ def __repr__(self): def left_score(self): return self._left_score - @property - def right_score(self): - return self._right_score - - @property - def binary_op(self): - return self._binary_op - @left_score.setter def left_score(self, left_score): cv.check_type('left_score', left_score, (str, CrossScore, AggregateScore)) self._left_score = left_score + @property + def right_score(self): + return self._right_score + @right_score.setter def right_score(self, right_score): cv.check_type('right_score', right_score, (str, CrossScore, AggregateScore)) self._right_score = right_score + @property + def binary_op(self): + return self._binary_op + @binary_op.setter def binary_op(self, binary_op): cv.check_type('binary_op', binary_op, str) @@ -132,14 +132,32 @@ def __repr__(self): def left_nuclide(self): return self._left_nuclide + @left_nuclide.setter + def left_nuclide(self, left_nuclide): + cv.check_type('left_nuclide', left_nuclide, + (openmc.Nuclide, CrossNuclide, AggregateNuclide)) + self._left_nuclide = left_nuclide + @property def right_nuclide(self): return self._right_nuclide + @right_nuclide.setter + def right_nuclide(self, right_nuclide): + cv.check_type('right_nuclide', right_nuclide, + (openmc.Nuclide, CrossNuclide, AggregateNuclide)) + self._right_nuclide = right_nuclide + @property def binary_op(self): return self._binary_op + @binary_op.setter + def binary_op(self, binary_op): + cv.check_type('binary_op', binary_op, str) + cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) + self._binary_op = binary_op + @property def name(self): @@ -163,24 +181,6 @@ def name(self): return string - @left_nuclide.setter - def left_nuclide(self, left_nuclide): - cv.check_type('left_nuclide', left_nuclide, - (openmc.Nuclide, CrossNuclide, AggregateNuclide)) - self._left_nuclide = left_nuclide - - @right_nuclide.setter - def right_nuclide(self, right_nuclide): - cv.check_type('right_nuclide', right_nuclide, - (openmc.Nuclide, CrossNuclide, AggregateNuclide)) - self._right_nuclide = right_nuclide - - @binary_op.setter - def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, str) - cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) - self._binary_op = binary_op - class CrossFilter: """A special-purpose filter used to encapsulate all combinations of two @@ -241,14 +241,32 @@ def __repr__(self): def left_filter(self): return self._left_filter + @left_filter.setter + def left_filter(self, left_filter): + cv.check_type('left_filter', left_filter, + (openmc.Filter, CrossFilter, AggregateFilter)) + self._left_filter = left_filter + @property def right_filter(self): return self._right_filter + @right_filter.setter + def right_filter(self, right_filter): + cv.check_type('right_filter', right_filter, + (openmc.Filter, CrossFilter, AggregateFilter)) + self._right_filter = right_filter + @property def binary_op(self): return self._binary_op + @binary_op.setter + def binary_op(self, binary_op): + cv.check_type('binary_op', binary_op, str) + cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) + self._binary_op = binary_op + @property def type(self): left_type = self.left_filter.type @@ -266,24 +284,6 @@ def num_bins(self): else: return 0 - @left_filter.setter - def left_filter(self, left_filter): - cv.check_type('left_filter', left_filter, - (openmc.Filter, CrossFilter, AggregateFilter)) - self._left_filter = left_filter - - @right_filter.setter - def right_filter(self, right_filter): - cv.check_type('right_filter', right_filter, - (openmc.Filter, CrossFilter, AggregateFilter)) - self._right_filter = right_filter - - @binary_op.setter - def binary_op(self, binary_op): - cv.check_type('binary_op', binary_op, str) - cv.check_value('binary_op', binary_op, _TALLY_ARITHMETIC_OPS) - self._binary_op = binary_op - def get_bin_index(self, filter_bin): """Returns the index in the CrossFilter for some bin. @@ -412,28 +412,28 @@ def __repr__(self): def scores(self): return self._scores - @property - def aggregate_op(self): - return self._aggregate_op - - @property - def name(self): - - # Append each score in the aggregate to the string - string = '(' + ', '.join(self.scores) + ')' - return string - @scores.setter def scores(self, scores): cv.check_iterable_type('scores', scores, str) self._scores = scores + @property + def aggregate_op(self): + return self._aggregate_op + @aggregate_op.setter def aggregate_op(self, aggregate_op): cv.check_type('aggregate_op', aggregate_op, (str, CrossScore)) cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) self._aggregate_op = aggregate_op + @property + def name(self): + + # Append each score in the aggregate to the string + string = '(' + ', '.join(self.scores) + ')' + return string + class AggregateNuclide: """A special-purpose tally nuclide used to encapsulate an aggregate of a @@ -486,10 +486,21 @@ def __repr__(self): def nuclides(self): return self._nuclides + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, (str, CrossNuclide)) + self._nuclides = nuclides + @property def aggregate_op(self): return self._aggregate_op + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, str) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + @property def name(self): @@ -499,17 +510,6 @@ def name(self): string = '(' + ', '.join(map(str, names)) + ')' return string - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, (str, CrossNuclide)) - self._nuclides = nuclides - - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, str) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op - class AggregateFilter: """A special-purpose tally filter used to encapsulate an aggregate of a @@ -588,26 +588,26 @@ def __repr__(self): def aggregate_filter(self): return self._aggregate_filter + @aggregate_filter.setter + def aggregate_filter(self, aggregate_filter): + cv.check_type('aggregate_filter', aggregate_filter, + (openmc.Filter, CrossFilter)) + self._aggregate_filter = aggregate_filter + @property def aggregate_op(self): return self._aggregate_op + @aggregate_op.setter + def aggregate_op(self, aggregate_op): + cv.check_type('aggregate_op', aggregate_op, str) + cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) + self._aggregate_op = aggregate_op + @property def type(self): return self._type - @property - def bins(self): - return self._bins - - @property - def num_bins(self): - return len(self.bins) if self.aggregate_filter else 0 - - @property - def shape(self): - return (self.num_bins,) - @type.setter def type(self, filter_type): if filter_type not in _FILTER_TYPES: @@ -617,22 +617,22 @@ def type(self, filter_type): self._type = filter_type - @aggregate_filter.setter - def aggregate_filter(self, aggregate_filter): - cv.check_type('aggregate_filter', aggregate_filter, - (openmc.Filter, CrossFilter)) - self._aggregate_filter = aggregate_filter + @property + def bins(self): + return self._bins @bins.setter def bins(self, bins): cv.check_iterable_type('bins', bins, Iterable) self._bins = list(map(tuple, bins)) - @aggregate_op.setter - def aggregate_op(self, aggregate_op): - cv.check_type('aggregate_op', aggregate_op, str) - cv.check_value('aggregate_op', aggregate_op, _TALLY_AGGREGATE_OPS) - self._aggregate_op = aggregate_op + @property + def num_bins(self): + return len(self.bins) if self.aggregate_filter else 0 + + @property + def shape(self): + return (self.num_bins,) def get_bin_index(self, filter_bin): """Returns the index in the AggregateFilter for some bin. diff --git a/openmc/cell.py b/openmc/cell.py index 5797bc0f622..b0be1ea79ae 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -150,10 +150,37 @@ def __repr__(self): def name(self): return self._name + @name.setter + def name(self, name): + if name is not None: + cv.check_type('cell name', name, str) + self._name = name + else: + self._name = '' + @property def fill(self): return self._fill + @fill.setter + def fill(self, fill): + if fill is not None: + if isinstance(fill, Iterable): + for i, f in enumerate(fill): + if f is not None: + cv.check_type('cell.fill[i]', f, openmc.Material) + + elif not isinstance(fill, (openmc.Material, openmc.Lattice, + openmc.UniverseBase)): + msg = (f'Unable to set Cell ID="{self._id}" to use a ' + f'non-Material or Universe fill "{fill}"') + raise ValueError(msg) + self._fill = fill + + # Info about atom content can now be invalid + # (since fill has just changed) + self._atoms = None + @property def fill_type(self): if isinstance(self.fill, openmc.Material): @@ -171,10 +198,37 @@ def fill_type(self): def region(self): return self._region + @region.setter + def region(self, region): + if region is not None: + cv.check_type('cell region', region, Region) + self._region = region + @property def rotation(self): return self._rotation + @rotation.setter + def rotation(self, rotation): + cv.check_length('cell rotation', rotation, 3) + self._rotation = np.asarray(rotation) + + # Save rotation matrix -- the reason we do this instead of having it be + # automatically calculated when the rotation_matrix property is accessed + # is so that plotting on a rotated geometry can be done faster. + if self._rotation.ndim == 2: + # User specified rotation matrix directly + self._rotation_matrix = self._rotation + else: + phi, theta, psi = self.rotation*(-pi/180.) + c3, s3 = cos(phi), sin(phi) + c2, s2 = cos(theta), sin(theta) + c1, s1 = cos(psi), sin(psi) + self._rotation_matrix = np.array([ + [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], + [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], + [-s2, c2*s3, c2*c3]]) + @property def rotation_matrix(self): return self._rotation_matrix @@ -183,14 +237,52 @@ def rotation_matrix(self): def temperature(self): return self._temperature + @temperature.setter + def temperature(self, temperature): + # Make sure temperatures are positive + cv.check_type('cell temperature', temperature, (Iterable, Real), none_ok=True) + if isinstance(temperature, Iterable): + cv.check_type('cell temperature', temperature, Iterable, Real) + for T in temperature: + cv.check_greater_than('cell temperature', T, 0.0, True) + elif isinstance(temperature, Real): + cv.check_greater_than('cell temperature', temperature, 0.0, True) + + # If this cell is filled with a universe or lattice, propagate + # temperatures to all cells contained. Otherwise, simply assign it. + if self.fill_type in ('universe', 'lattice'): + for c in self.get_all_cells().values(): + if c.fill_type == 'material': + c._temperature = temperature + else: + self._temperature = temperature + @property def translation(self): return self._translation + @translation.setter + def translation(self, translation): + cv.check_type('cell translation', translation, Iterable, Real) + cv.check_length('cell translation', translation, 3) + self._translation = np.asarray(translation) + @property def volume(self): return self._volume + @volume.setter + def volume(self, volume): + if volume is not None: + cv.check_type('cell volume', volume, (Real, UFloat)) + cv.check_greater_than('cell volume', volume, 0.0, equality=True) + + self._volume = volume + + # Info about atom content can now be invalid + # (since volume has just changed) + self._atoms = None + @property def atoms(self): if self._atoms is None: @@ -263,98 +355,6 @@ def num_instances(self): 'Geometry.determine_paths() method.') return self._num_instances - @name.setter - def name(self, name): - if name is not None: - cv.check_type('cell name', name, str) - self._name = name - else: - self._name = '' - - @fill.setter - def fill(self, fill): - if fill is not None: - if isinstance(fill, Iterable): - for i, f in enumerate(fill): - if f is not None: - cv.check_type('cell.fill[i]', f, openmc.Material) - - elif not isinstance(fill, (openmc.Material, openmc.Lattice, - openmc.UniverseBase)): - msg = (f'Unable to set Cell ID="{self._id}" to use a ' - f'non-Material or Universe fill "{fill}"') - raise ValueError(msg) - self._fill = fill - - # Info about atom content can now be invalid - # (since fill has just changed) - self._atoms = None - - @rotation.setter - def rotation(self, rotation): - cv.check_length('cell rotation', rotation, 3) - self._rotation = np.asarray(rotation) - - # Save rotation matrix -- the reason we do this instead of having it be - # automatically calculated when the rotation_matrix property is accessed - # is so that plotting on a rotated geometry can be done faster. - if self._rotation.ndim == 2: - # User specified rotation matrix directly - self._rotation_matrix = self._rotation - else: - phi, theta, psi = self.rotation*(-pi/180.) - c3, s3 = cos(phi), sin(phi) - c2, s2 = cos(theta), sin(theta) - c1, s1 = cos(psi), sin(psi) - self._rotation_matrix = np.array([ - [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], - [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], - [-s2, c2*s3, c2*c3]]) - - @translation.setter - def translation(self, translation): - cv.check_type('cell translation', translation, Iterable, Real) - cv.check_length('cell translation', translation, 3) - self._translation = np.asarray(translation) - - @temperature.setter - def temperature(self, temperature): - # Make sure temperatures are positive - cv.check_type('cell temperature', temperature, (Iterable, Real), none_ok=True) - if isinstance(temperature, Iterable): - cv.check_type('cell temperature', temperature, Iterable, Real) - for T in temperature: - cv.check_greater_than('cell temperature', T, 0.0, True) - elif isinstance(temperature, Real): - cv.check_greater_than('cell temperature', temperature, 0.0, True) - - # If this cell is filled with a universe or lattice, propagate - # temperatures to all cells contained. Otherwise, simply assign it. - if self.fill_type in ('universe', 'lattice'): - for c in self.get_all_cells().values(): - if c.fill_type == 'material': - c._temperature = temperature - else: - self._temperature = temperature - - @region.setter - def region(self, region): - if region is not None: - cv.check_type('cell region', region, Region) - self._region = region - - @volume.setter - def volume(self, volume): - if volume is not None: - cv.check_type('cell volume', volume, (Real, UFloat)) - cv.check_greater_than('cell volume', volume, 0.0, equality=True) - - self._volume = volume - - # Info about atom content can now be invalid - # (since volume has just changed) - self._atoms = None - def add_volume_information(self, volume_calc): """Add volume information to a cell. diff --git a/openmc/data/angle_distribution.py b/openmc/data/angle_distribution.py index 4d058bcb7cb..bb0eafe5a0c 100644 --- a/openmc/data/angle_distribution.py +++ b/openmc/data/angle_distribution.py @@ -42,16 +42,16 @@ def __init__(self, energy, mu): def energy(self): return self._energy - @property - def mu(self): - return self._mu - @energy.setter def energy(self, energy): cv.check_type('angle distribution incoming energy', energy, Iterable, Real) self._energy = energy + @property + def mu(self): + return self._mu + @mu.setter def mu(self, mu): cv.check_type('angle distribution scattering cosines', mu, diff --git a/openmc/data/correlated.py b/openmc/data/correlated.py index 1aa4c20c8c5..f131ce30d56 100644 --- a/openmc/data/correlated.py +++ b/openmc/data/correlated.py @@ -58,46 +58,46 @@ def __init__(self, breakpoints, interpolation, energy, energy_out, mu): def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - - @property - def energy(self): - return self._energy - - @property - def energy_out(self): - return self._energy_out - - @property - def mu(self): - return self._mu - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('correlated angle-energy breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('correlated angle-energy interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('correlated angle-energy incoming energy', energy, Iterable, Real) self._energy = energy + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_type('correlated angle-energy outgoing energy', energy_out, Iterable, Univariate) self._energy_out = energy_out + @property + def mu(self): + return self._mu + @mu.setter def mu(self, mu): cv.check_iterable_type('correlated angle-energy outgoing cosine', diff --git a/openmc/data/data.py b/openmc/data/data.py index 16c7ecf54ce..609a901d9b4 100644 --- a/openmc/data/data.py +++ b/openmc/data/data.py @@ -5,6 +5,7 @@ from pathlib import Path from math import sqrt, log from warnings import warn +from typing import Dict # Isotopic abundances from Meija J, Coplen T B, et al, "Isotopic compositions # of the elements 2013 (IUPAC Technical Report)", Pure. Appl. Chem. 88 (3), @@ -195,13 +196,13 @@ NEUTRON_MASS = 1.00866491595 # Used in atomic_mass function as a cache -_ATOMIC_MASS = {} +_ATOMIC_MASS: Dict[str, float] = {} # Regex for GNDS nuclide names (used in zam function) _GNDS_NAME_RE = re.compile(r'([A-Zn][a-z]*)(\d+)((?:_[em]\d+)?)') # Used in half_life function as a cache -_HALF_LIFE = {} +_HALF_LIFE: Dict[str, float] = {} _LOG_TWO = log(2.0) def atomic_mass(isotope): diff --git a/openmc/data/decay.py b/openmc/data/decay.py index 57327c07f3b..4f9d6f46030 100644 --- a/openmc/data/decay.py +++ b/openmc/data/decay.py @@ -228,6 +228,18 @@ def __repr__(self): def branching_ratio(self): return self._branching_ratio + @branching_ratio.setter + def branching_ratio(self, branching_ratio): + cv.check_type('branching ratio', branching_ratio, UFloat) + cv.check_greater_than('branching ratio', + branching_ratio.nominal_value, 0.0, True) + if branching_ratio.nominal_value == 0.0: + warn('Decay mode {} of parent {} has a zero branching ratio.' + .format(self.modes, self.parent)) + cv.check_greater_than('branching ratio uncertainty', + branching_ratio.std_dev, 0.0, True) + self._branching_ratio = branching_ratio + @property def daughter(self): # Determine atomic number and mass number of parent @@ -249,29 +261,18 @@ def daughter(self): else: return '{}{}'.format(ATOMIC_SYMBOL[Z], A) - @property - def energy(self): - return self._energy - - @property - def modes(self): - return self._modes - @property def parent(self): return self._parent - @branching_ratio.setter - def branching_ratio(self, branching_ratio): - cv.check_type('branching ratio', branching_ratio, UFloat) - cv.check_greater_than('branching ratio', - branching_ratio.nominal_value, 0.0, True) - if branching_ratio.nominal_value == 0.0: - warn('Decay mode {} of parent {} has a zero branching ratio.' - .format(self.modes, self.parent)) - cv.check_greater_than('branching ratio uncertainty', - branching_ratio.std_dev, 0.0, True) - self._branching_ratio = branching_ratio + @parent.setter + def parent(self, parent): + cv.check_type('parent nuclide', parent, str) + self._parent = parent + + @property + def energy(self): + return self._energy @energy.setter def energy(self, energy): @@ -281,16 +282,15 @@ def energy(self, energy): energy.std_dev, 0.0, True) self._energy = energy + @property + def modes(self): + return self._modes + @modes.setter def modes(self, modes): cv.check_type('decay modes', modes, Iterable, str) self._modes = modes - @parent.setter - def parent(self, parent): - cv.check_type('parent nuclide', parent, str) - self._parent = parent - class Decay(EqualityMixin): """Radioactive decay data. diff --git a/openmc/data/energy_distribution.py b/openmc/data/energy_distribution.py index 3b6d325effe..a13893a68f1 100644 --- a/openmc/data/energy_distribution.py +++ b/openmc/data/energy_distribution.py @@ -253,15 +253,15 @@ def __init__(self, theta, u): def theta(self): return self._theta - @property - def u(self): - return self._u - @theta.setter def theta(self, theta): cv.check_type('Maxwell theta', theta, Tabulated1D) self._theta = theta + @property + def u(self): + return self._u + @u.setter def u(self, u): cv.check_type('Maxwell restriction energy', u, Real) @@ -386,15 +386,15 @@ def __init__(self, theta, u): def theta(self): return self._theta - @property - def u(self): - return self._u - @theta.setter def theta(self, theta): cv.check_type('Evaporation theta', theta, Tabulated1D) self._theta = theta + @property + def u(self): + return self._u + @u.setter def u(self, u): cv.check_type('Evaporation restriction energy', u, Real) @@ -523,24 +523,24 @@ def __init__(self, a, b, u): def a(self): return self._a - @property - def b(self): - return self._b - - @property - def u(self): - return self._u - @a.setter def a(self, a): cv.check_type('Watt a', a, Tabulated1D) self._a = a + @property + def b(self): + return self._b + @b.setter def b(self, b): cv.check_type('Watt b', b, Tabulated1D) self._b = b + @property + def u(self): + return self._u + @u.setter def u(self, u): cv.check_type('Watt restriction energy', u, Real) @@ -691,14 +691,6 @@ def __init__(self, efl, efh, tm): def efl(self): return self._efl - @property - def efh(self): - return self._efh - - @property - def tm(self): - return self._tm - @efl.setter def efl(self, efl): name = 'Madland-Nix light fragment energy' @@ -706,6 +698,10 @@ def efl(self, efl): cv.check_greater_than(name, efl, 0.) self._efl = efl + @property + def efh(self): + return self._efh + @efh.setter def efh(self, efh): name = 'Madland-Nix heavy fragment energy' @@ -713,6 +709,10 @@ def efh(self, efh): cv.check_greater_than(name, efh, 0.) self._efh = efh + @property + def tm(self): + return self._tm + @tm.setter def tm(self, tm): cv.check_type('Madland-Nix maximum temperature', tm, Tabulated1D) @@ -778,7 +778,6 @@ def from_endf(cls, file_obj, params): return cls(efl, efh, tm) - class DiscretePhoton(EnergyDistribution): """Discrete photon energy distribution @@ -814,24 +813,24 @@ def __init__(self, primary_flag, energy, atomic_weight_ratio): def primary_flag(self): return self._primary_flag - @property - def energy(self): - return self._energy - - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - @primary_flag.setter def primary_flag(self, primary_flag): cv.check_type('discrete photon primary_flag', primary_flag, Integral) self._primary_flag = primary_flag + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('discrete photon energy', energy, Real) self._energy = energy + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_type('atomic weight ratio', atomic_weight_ratio, Real) @@ -922,15 +921,15 @@ def __init__(self, threshold, mass_ratio): def threshold(self): return self._threshold - @property - def mass_ratio(self): - return self._mass_ratio - @threshold.setter def threshold(self, threshold): cv.check_type('level inelastic threhsold', threshold, Real) self._threshold = threshold + @property + def mass_ratio(self): + return self._mass_ratio + @mass_ratio.setter def mass_ratio(self, mass_ratio): cv.check_type('level inelastic mass ratio', mass_ratio, Real) @@ -1029,36 +1028,36 @@ def __init__(self, breakpoints, interpolation, energy, energy_out): def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - - @property - def energy(self): - return self._energy - - @property - def energy_out(self): - return self._energy_out - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('continuous tabular breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('continuous tabular interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('continuous tabular incoming energy', energy, Iterable, Real) self._energy = energy + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_type('continuous tabular outgoing energy', energy_out, diff --git a/openmc/data/fission_energy.py b/openmc/data/fission_energy.py index bdce84ff79f..870881dbaf7 100644 --- a/openmc/data/fission_energy.py +++ b/openmc/data/fission_energy.py @@ -100,30 +100,65 @@ def __init__(self, fragments, prompt_neutrons, delayed_neutrons, def fragments(self): return self._fragments + @fragments.setter + def fragments(self, energy_release): + cv.check_type('fragments', energy_release, Callable) + self._fragments = energy_release + @property def prompt_neutrons(self): return self._prompt_neutrons + @prompt_neutrons.setter + def prompt_neutrons(self, energy_release): + cv.check_type('prompt_neutrons', energy_release, Callable) + self._prompt_neutrons = energy_release + @property def delayed_neutrons(self): return self._delayed_neutrons + @delayed_neutrons.setter + def delayed_neutrons(self, energy_release): + cv.check_type('delayed_neutrons', energy_release, Callable) + self._delayed_neutrons = energy_release + @property def prompt_photons(self): return self._prompt_photons + @prompt_photons.setter + def prompt_photons(self, energy_release): + cv.check_type('prompt_photons', energy_release, Callable) + self._prompt_photons = energy_release + @property def delayed_photons(self): return self._delayed_photons + @delayed_photons.setter + def delayed_photons(self, energy_release): + cv.check_type('delayed_photons', energy_release, Callable) + self._delayed_photons = energy_release + @property def betas(self): return self._betas + @betas.setter + def betas(self, energy_release): + cv.check_type('betas', energy_release, Callable) + self._betas = energy_release + @property def neutrinos(self): return self._neutrinos + @neutrinos.setter + def neutrinos(self, energy_release): + cv.check_type('neutrinos', energy_release, Callable) + self._neutrinos = energy_release + @property def recoverable(self): components = ['fragments', 'prompt_neutrons', 'delayed_neutrons', @@ -154,41 +189,6 @@ def q_total(self): # Use a polynomial to subtract incident energy. return sum_functions([self.total, Polynomial((0.0, -1.0))]) - @fragments.setter - def fragments(self, energy_release): - cv.check_type('fragments', energy_release, Callable) - self._fragments = energy_release - - @prompt_neutrons.setter - def prompt_neutrons(self, energy_release): - cv.check_type('prompt_neutrons', energy_release, Callable) - self._prompt_neutrons = energy_release - - @delayed_neutrons.setter - def delayed_neutrons(self, energy_release): - cv.check_type('delayed_neutrons', energy_release, Callable) - self._delayed_neutrons = energy_release - - @prompt_photons.setter - def prompt_photons(self, energy_release): - cv.check_type('prompt_photons', energy_release, Callable) - self._prompt_photons = energy_release - - @delayed_photons.setter - def delayed_photons(self, energy_release): - cv.check_type('delayed_photons', energy_release, Callable) - self._delayed_photons = energy_release - - @betas.setter - def betas(self, energy_release): - cv.check_type('betas', energy_release, Callable) - self._betas = energy_release - - @neutrinos.setter - def neutrinos(self, energy_release): - cv.check_type('neutrinos', energy_release, Callable) - self._neutrinos = energy_release - @classmethod def from_endf(cls, ev, incident_neutron): """Generate fission energy release data from an ENDF file. diff --git a/openmc/data/function.py b/openmc/data/function.py index b0390d19cde..299924b37cc 100644 --- a/openmc/data/function.py +++ b/openmc/data/function.py @@ -255,46 +255,46 @@ def __len__(self): def x(self): return self._x - @property - def y(self): - return self._y - - @property - def breakpoints(self): - return self._breakpoints - - @property - def interpolation(self): - return self._interpolation - - @property - def n_pairs(self): - return len(self.x) - - @property - def n_regions(self): - return len(self.breakpoints) - @x.setter def x(self, x): cv.check_type('x values', x, Iterable, Real) self._x = x + @property + def y(self): + return self._y + @y.setter def y(self, y): cv.check_type('y values', y, Iterable, Real) self._y = y + @property + def breakpoints(self): + return self._breakpoints + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def n_pairs(self): + return len(self.x) + + @property + def n_regions(self): + return len(self.breakpoints) + def integral(self): """Integral of the tabulated function over its tabulated range. @@ -664,15 +664,15 @@ def __call__(self, x): def functions(self): return self._functions - @property - def breakpoints(self): - return self._breakpoints - @functions.setter def functions(self, functions): cv.check_type('functions', functions, Iterable, Callable) self._functions = functions + @property + def breakpoints(self): + return self._breakpoints + @breakpoints.setter def breakpoints(self, breakpoints): cv.check_iterable_type('breakpoints', breakpoints, Real) @@ -734,24 +734,24 @@ def __call__(self, x): def background(self): return self._background - @property - def mt(self): - return self._mt - - @property - def resonances(self): - return self._resonances - @background.setter def background(self, background): cv.check_type('background cross section', background, Callable) self._background = background + @property + def mt(self): + return self._mt + @mt.setter def mt(self, mt): cv.check_type('MT value', mt, Integral) self._mt = mt + @property + def resonances(self): + return self._resonances + @resonances.setter def resonances(self, resonances): cv.check_type('resolved resonance parameters', resonances, diff --git a/openmc/data/kalbach_mann.py b/openmc/data/kalbach_mann.py index f98bb418692..b49399139d5 100644 --- a/openmc/data/kalbach_mann.py +++ b/openmc/data/kalbach_mann.py @@ -302,56 +302,56 @@ def __init__(self, breakpoints, interpolation, energy, energy_out, def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - - @property - def energy(self): - return self._energy - - @property - def energy_out(self): - return self._energy_out - - @property - def precompound(self): - return self._precompound - - @property - def slope(self): - return self._slope - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('Kalbach-Mann breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('Kalbach-Mann interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('Kalbach-Mann incoming energy', energy, Iterable, Real) self._energy = energy + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_type('Kalbach-Mann distributions', energy_out, Iterable, Univariate) self._energy_out = energy_out + @property + def precompound(self): + return self._precompound + @precompound.setter def precompound(self, precompound): cv.check_type('Kalbach-Mann precompound factor', precompound, Iterable, Tabulated1D) self._precompound = precompound + @property + def slope(self): + return self._slope + @slope.setter def slope(self, slope): cv.check_type('Kalbach-Mann slope', slope, Iterable, Tabulated1D) diff --git a/openmc/data/laboratory.py b/openmc/data/laboratory.py index 87d9d296183..c20b4596846 100644 --- a/openmc/data/laboratory.py +++ b/openmc/data/laboratory.py @@ -54,45 +54,46 @@ def __init__(self, breakpoints, interpolation, energy, mu, energy_out): def breakpoints(self): return self._breakpoints - @property - def interpolation(self): - return self._interpolation - @property - def energy(self): - return self._energy - - @property - def mu(self): - return self._mu - - @property - def energy_out(self): - return self._energy_out - @breakpoints.setter def breakpoints(self, breakpoints): cv.check_type('laboratory angle-energy breakpoints', breakpoints, Iterable, Integral) self._breakpoints = breakpoints + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_type('laboratory angle-energy interpolation', interpolation, Iterable, Integral) self._interpolation = interpolation + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('laboratory angle-energy incoming energy', energy, Iterable, Real) self._energy = energy + @property + def mu(self): + return self._mu + @mu.setter def mu(self, mu): cv.check_type('laboratory angle-energy outgoing cosine', mu, Iterable, Univariate) self._mu = mu + @property + def energy_out(self): + return self._energy_out + @energy_out.setter def energy_out(self, energy_out): cv.check_iterable_type('laboratory angle-energy outgoing energy', diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index 5e227990238..9fd6c9a9bea 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -799,6 +799,11 @@ def __init__(self, name): def name(self): return self._name + @name.setter + def name(self, name): + cv.check_type('name', name, str) + self._name = name + @property def fit_order(self): return self.curvefit.shape[1] - 1 @@ -823,39 +828,6 @@ def poles_per_window(self): def spacing(self): return self._spacing - @property - def sqrtAWR(self): - return self._sqrtAWR - - @property - def E_min(self): - return self._E_min - - @property - def E_max(self): - return self._E_max - - @property - def data(self): - return self._data - - @property - def windows(self): - return self._windows - - @property - def broaden_poly(self): - return self._broaden_poly - - @property - def curvefit(self): - return self._curvefit - - @name.setter - def name(self, name): - cv.check_type('name', name, str) - self._name = name - @spacing.setter def spacing(self, spacing): if spacing is not None: @@ -863,6 +835,10 @@ def spacing(self, spacing): cv.check_greater_than('spacing', spacing, 0.0, equality=False) self._spacing = spacing + @property + def sqrtAWR(self): + return self._sqrtAWR + @sqrtAWR.setter def sqrtAWR(self, sqrtAWR): if sqrtAWR is not None: @@ -870,6 +846,10 @@ def sqrtAWR(self, sqrtAWR): cv.check_greater_than('sqrtAWR', sqrtAWR, 0.0, equality=False) self._sqrtAWR = sqrtAWR + @property + def E_min(self): + return self._E_min + @E_min.setter def E_min(self, E_min): if E_min is not None: @@ -877,6 +857,10 @@ def E_min(self, E_min): cv.check_greater_than('E_min', E_min, 0.0, equality=True) self._E_min = E_min + @property + def E_max(self): + return self._E_max + @E_max.setter def E_max(self, E_max): if E_max is not None: @@ -884,6 +868,10 @@ def E_max(self, E_max): cv.check_greater_than('E_max', E_max, 0.0, equality=False) self._E_max = E_max + @property + def data(self): + return self._data + @data.setter def data(self, data): if data is not None: @@ -899,6 +887,10 @@ def data(self, data): raise TypeError('Multipole data arrays must be complex dtype') self._data = data + @property + def windows(self): + return self._windows + @windows.setter def windows(self, windows): if windows is not None: @@ -910,6 +902,10 @@ def windows(self, windows): ' dtype') self._windows = windows + @property + def broaden_poly(self): + return self._broaden_poly + @broaden_poly.setter def broaden_poly(self, broaden_poly): if broaden_poly is not None: @@ -921,6 +917,10 @@ def broaden_poly(self, broaden_poly): ' dtype') self._broaden_poly = broaden_poly + @property + def curvefit(self): + return self._curvefit + @curvefit.setter def curvefit(self, curvefit): if curvefit is not None: diff --git a/openmc/data/nbody.py b/openmc/data/nbody.py index 4db9934b953..1f2ff5b4d1c 100644 --- a/openmc/data/nbody.py +++ b/openmc/data/nbody.py @@ -43,18 +43,6 @@ def __init__(self, total_mass, n_particles, atomic_weight_ratio, q_value): def total_mass(self): return self._total_mass - @property - def n_particles(self): - return self._n_particles - - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - - @property - def q_value(self): - return self._q_value - @total_mass.setter def total_mass(self, total_mass): name = 'N-body phase space total mass' @@ -62,6 +50,10 @@ def total_mass(self, total_mass): cv.check_greater_than(name, total_mass, 0.) self._total_mass = total_mass + @property + def n_particles(self): + return self._n_particles + @n_particles.setter def n_particles(self, n_particles): name = 'N-body phase space number of particles' @@ -69,6 +61,10 @@ def n_particles(self, n_particles): cv.check_greater_than(name, n_particles, 0) self._n_particles = n_particles + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): name = 'N-body phase space atomic weight ratio' @@ -76,6 +72,10 @@ def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_greater_than(name, atomic_weight_ratio, 0.0) self._atomic_weight_ratio = atomic_weight_ratio + @property + def q_value(self): + return self._q_value + @q_value.setter def q_value(self, q_value): name = 'N-body phase space Q value' diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 2d4c139635d..11d1456f853 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -135,54 +135,14 @@ def __iter__(self): def name(self): return self._name - @property - def atomic_number(self): - return self._atomic_number - - @property - def mass_number(self): - return self._mass_number - - @property - def metastable(self): - return self._metastable - - @property - def atomic_weight_ratio(self): - return self._atomic_weight_ratio - - @property - def fission_energy(self): - return self._fission_energy - - @property - def reactions(self): - return self._reactions - - @property - def resonances(self): - return self._resonances - - @property - def resonance_covariance(self): - return self._resonance_covariance - - @property - def urr(self): - return self._urr - - @property - def temperatures(self): - return ["{}K".format(int(round(kT / K_BOLTZMANN))) for kT in self.kTs] - @name.setter def name(self, name): cv.check_type('name', name, str) self._name = name @property - def atomic_symbol(self): - return ATOMIC_SYMBOL[self.atomic_number] + def atomic_number(self): + return self._atomic_number @atomic_number.setter def atomic_number(self, atomic_number): @@ -190,46 +150,78 @@ def atomic_number(self, atomic_number): cv.check_greater_than('atomic number', atomic_number, 0, True) self._atomic_number = atomic_number + @property + def mass_number(self): + return self._mass_number + @mass_number.setter def mass_number(self, mass_number): cv.check_type('mass number', mass_number, Integral) cv.check_greater_than('mass number', mass_number, 0, True) self._mass_number = mass_number + @property + def metastable(self): + return self._metastable + @metastable.setter def metastable(self, metastable): cv.check_type('metastable', metastable, Integral) cv.check_greater_than('metastable', metastable, 0, True) self._metastable = metastable + @property + def atomic_weight_ratio(self): + return self._atomic_weight_ratio + @atomic_weight_ratio.setter def atomic_weight_ratio(self, atomic_weight_ratio): cv.check_type('atomic weight ratio', atomic_weight_ratio, Real) cv.check_greater_than('atomic weight ratio', atomic_weight_ratio, 0.0) self._atomic_weight_ratio = atomic_weight_ratio + @property + def fission_energy(self): + return self._fission_energy + @fission_energy.setter def fission_energy(self, fission_energy): cv.check_type('fission energy release', fission_energy, FissionEnergyRelease) self._fission_energy = fission_energy + @property + def reactions(self): + return self._reactions + @reactions.setter def reactions(self, reactions): cv.check_type('reactions', reactions, Mapping) self._reactions = reactions + @property + def resonances(self): + return self._resonances + @resonances.setter def resonances(self, resonances): cv.check_type('resonances', resonances, res.Resonances) self._resonances = resonances + @property + def resonance_covariance(self): + return self._resonance_covariance + @resonance_covariance.setter def resonance_covariance(self, resonance_covariance): cv.check_type('resonance covariance', resonance_covariance, res_cov.ResonanceCovariances) self._resonance_covariance = resonance_covariance + @property + def urr(self): + return self._urr + @urr.setter def urr(self, urr): cv.check_type('probability table dictionary', urr, MutableMapping) @@ -238,6 +230,14 @@ def urr(self, urr): cv.check_type('probability tables', value, ProbabilityTables) self._urr = urr + @property + def temperatures(self): + return ["{}K".format(int(round(kT / K_BOLTZMANN))) for kT in self.kTs] + + @property + def atomic_symbol(self): + return ATOMIC_SYMBOL[self.atomic_number] + def add_temperature_from_ace(self, ace_or_filename, metastable_scheme='nndc'): """Append data from an ACE file at a different temperature. diff --git a/openmc/data/photon.py b/openmc/data/photon.py index e83ff844d16..1d2546f0e55 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -168,18 +168,6 @@ def __init__(self, binding_energy, num_electrons, transitions): def binding_energy(self): return self._binding_energy - @property - def num_electrons(self): - return self._num_electrons - - @property - def subshells(self): - return list(sorted(self.binding_energy.keys())) - - @property - def transitions(self): - return self._transitions - @binding_energy.setter def binding_energy(self, binding_energy): cv.check_type('binding energies', binding_energy, Mapping) @@ -189,6 +177,10 @@ def binding_energy(self, binding_energy): cv.check_greater_than('binding energy', energy, 0.0, True) self._binding_energy = binding_energy + @property + def num_electrons(self): + return self._num_electrons + @num_electrons.setter def num_electrons(self, num_electrons): cv.check_type('number of electrons', num_electrons, Mapping) @@ -198,6 +190,14 @@ def num_electrons(self, num_electrons): cv.check_greater_than('number of electrons', num, 0.0, True) self._num_electrons = num_electrons + @property + def subshells(self): + return list(sorted(self.binding_energy.keys())) + + @property + def transitions(self): + return self._transitions + @transitions.setter def transitions(self, transitions): cv.check_type('transitions', transitions, Mapping) @@ -464,26 +464,26 @@ def __iter__(self): def atomic_number(self): return self._atomic_number - @property - def atomic_relaxation(self): - return self._atomic_relaxation - - @property - def name(self): - return ATOMIC_SYMBOL[self.atomic_number] - @atomic_number.setter def atomic_number(self, atomic_number): cv.check_type('atomic number', atomic_number, Integral) cv.check_greater_than('atomic number', atomic_number, 0, True) self._atomic_number = atomic_number + @property + def atomic_relaxation(self): + return self._atomic_relaxation + @atomic_relaxation.setter def atomic_relaxation(self, atomic_relaxation): cv.check_type('atomic relaxation data', atomic_relaxation, AtomicRelaxation) self._atomic_relaxation = atomic_relaxation + @property + def name(self): + return ATOMIC_SYMBOL[self.atomic_number] + @classmethod def from_ace(cls, ace_or_filename): """Generate incident photon data from an ACE table @@ -934,35 +934,35 @@ def __repr__(self): def anomalous_real(self): return self._anomalous_real - @property - def anomalous_imag(self): - return self._anomalous_imag - - @property - def scattering_factor(self): - return self._scattering_factor - - @property - def xs(self): - return self._xs - @anomalous_real.setter def anomalous_real(self, anomalous_real): cv.check_type('real part of anomalous scattering factor', anomalous_real, Callable) self._anomalous_real = anomalous_real + @property + def anomalous_imag(self): + return self._anomalous_imag + @anomalous_imag.setter def anomalous_imag(self, anomalous_imag): cv.check_type('imaginary part of anomalous scattering factor', anomalous_imag, Callable) self._anomalous_imag = anomalous_imag + @property + def scattering_factor(self): + return self._scattering_factor + @scattering_factor.setter def scattering_factor(self, scattering_factor): cv.check_type('scattering factor', scattering_factor, Callable) self._scattering_factor = scattering_factor + @property + def xs(self): + return self._xs + @xs.setter def xs(self, xs): cv.check_type('reaction cross section', xs, Callable) diff --git a/openmc/data/product.py b/openmc/data/product.py index a6b2fd89e5c..93697a9e7b7 100644 --- a/openmc/data/product.py +++ b/openmc/data/product.py @@ -61,55 +61,55 @@ def __repr__(self): def applicability(self): return self._applicability - @property - def decay_rate(self): - return self._decay_rate - - @property - def distribution(self): - return self._distribution - - @property - def emission_mode(self): - return self._emission_mode - - @property - def particle(self): - return self._particle - - @property - def yield_(self): - return self._yield - @applicability.setter def applicability(self, applicability): cv.check_type('product distribution applicability', applicability, Iterable, Tabulated1D) self._applicability = applicability + @property + def decay_rate(self): + return self._decay_rate + @decay_rate.setter def decay_rate(self, decay_rate): cv.check_type('product decay rate', decay_rate, Real) cv.check_greater_than('product decay rate', decay_rate, 0.0, True) self._decay_rate = decay_rate + @property + def distribution(self): + return self._distribution + @distribution.setter def distribution(self, distribution): cv.check_type('product angle-energy distribution', distribution, Iterable, AngleEnergy) self._distribution = distribution + @property + def emission_mode(self): + return self._emission_mode + @emission_mode.setter def emission_mode(self, emission_mode): cv.check_value('product emission mode', emission_mode, ('prompt', 'delayed', 'total')) self._emission_mode = emission_mode + @property + def particle(self): + return self._particle + @particle.setter def particle(self, particle): cv.check_type('product particle type', particle, str) self._particle = particle + @property + def yield_(self): + return self._yield + @yield_.setter def yield_(self, yield_): cv.check_type('product yield', yield_, Function1D) diff --git a/openmc/data/reaction.py b/openmc/data/reaction.py index ac9d7f14e92..650e8663ef5 100644 --- a/openmc/data/reaction.py +++ b/openmc/data/reaction.py @@ -855,52 +855,52 @@ def __repr__(self): def center_of_mass(self): return self._center_of_mass - @property - def redundant(self): - return self._redundant - - @property - def q_value(self): - return self._q_value - - @property - def products(self): - return self._products - - @property - def derived_products(self): - return self._derived_products - - @property - def xs(self): - return self._xs - @center_of_mass.setter def center_of_mass(self, center_of_mass): cv.check_type('center of mass', center_of_mass, (bool, np.bool_)) self._center_of_mass = center_of_mass + @property + def redundant(self): + return self._redundant + @redundant.setter def redundant(self, redundant): cv.check_type('redundant', redundant, (bool, np.bool_)) self._redundant = redundant + @property + def q_value(self): + return self._q_value + @q_value.setter def q_value(self, q_value): cv.check_type('Q value', q_value, Real) self._q_value = q_value + @property + def products(self): + return self._products + @products.setter def products(self, products): cv.check_type('reaction products', products, Iterable, Product) self._products = products + @property + def derived_products(self): + return self._derived_products + @derived_products.setter def derived_products(self, derived_products): cv.check_type('reaction derived products', derived_products, Iterable, Product) self._derived_products = derived_products + @property + def xs(self): + return self._xs + @xs.setter def xs(self, xs): cv.check_type('reaction cross section dictionary', xs, MutableMapping) diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 7d27ea7cc3c..7b9cd268f5a 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -46,6 +46,12 @@ def __iter__(self): def ranges(self): return self._ranges + @ranges.setter + def ranges(self, ranges): + cv.check_type('resonance ranges', ranges, MutableSequence) + self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', + ranges) + @property def resolved(self): resolved_ranges = [r for r in self.ranges @@ -65,12 +71,6 @@ def unresolved(self): else: return None - @ranges.setter - def ranges(self, ranges): - cv.check_type('resonance ranges', ranges, MutableSequence) - self._ranges = cv.CheckedList(ResonanceRange, 'resonance ranges', - ranges) - @classmethod def from_endf(cls, ev): """Generate resonance data from an ENDF evaluation. diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 48f6bfc9b3d..b6e700a0cbd 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -193,15 +193,15 @@ def __len__(self): def bragg_edges(self): return self._bragg_edges - @property - def factors(self): - return self._factors - @bragg_edges.setter def bragg_edges(self, bragg_edges): cv.check_type('Bragg edges', bragg_edges, Iterable, Real) self._bragg_edges = np.asarray(bragg_edges) + @property + def factors(self): + return self._factors + @factors.setter def factors(self, factors): cv.check_type('structure factor cumulative sums', factors, diff --git a/openmc/data/uncorrelated.py b/openmc/data/uncorrelated.py index 0361c9b37a3..9dcb18bf616 100644 --- a/openmc/data/uncorrelated.py +++ b/openmc/data/uncorrelated.py @@ -38,16 +38,16 @@ def __init__(self, angle=None, energy=None): def angle(self): return self._angle - @property - def energy(self): - return self._energy - @angle.setter def angle(self, angle): cv.check_type('uncorrelated angle distribution', angle, AngleDistribution) self._angle = angle + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('uncorrelated energy distribution', energy, diff --git a/openmc/data/urr.py b/openmc/data/urr.py index 53961a50acb..f129c98f811 100644 --- a/openmc/data/urr.py +++ b/openmc/data/urr.py @@ -79,51 +79,51 @@ def __init__(self, energy, table, interpolation, inelastic_flag=-1, def absorption_flag(self): return self._absorption_flag - @property - def energy(self): - return self._energy - - @property - def inelastic_flag(self): - return self._inelastic_flag - - @property - def interpolation(self): - return self._interpolation - - @property - def multiply_smooth(self): - return self._multiply_smooth - - @property - def table(self): - return self._table - @absorption_flag.setter def absorption_flag(self, absorption_flag): cv.check_type('absorption flag', absorption_flag, Integral) self._absorption_flag = absorption_flag + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('probability table energies', energy, Iterable, Real) self._energy = energy + @property + def inelastic_flag(self): + return self._inelastic_flag + @inelastic_flag.setter def inelastic_flag(self, inelastic_flag): cv.check_type('inelastic flag', inelastic_flag, Integral) self._inelastic_flag = inelastic_flag + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_value('interpolation', interpolation, [2, 5]) self._interpolation = interpolation + @property + def multiply_smooth(self): + return self._multiply_smooth + @multiply_smooth.setter def multiply_smooth(self, multiply_smooth): cv.check_type('multiply by smooth', multiply_smooth, bool) self._multiply_smooth = multiply_smooth + @property + def table(self): + return self._table + @table.setter def table(self, table): cv.check_type('probability tables', table, np.ndarray) diff --git a/openmc/filter.py b/openmc/filter.py index 1ad2892783a..9b3dd516291 100644 --- a/openmc/filter.py +++ b/openmc/filter.py @@ -1575,6 +1575,11 @@ def num_bins(self): def paths(self): return self._paths + @paths.setter + def paths(self, paths): + cv.check_iterable_type('paths', paths, str) + self._paths = paths + @Filter.bins.setter def bins(self, bins): # Format the bins as a 1D numpy array. @@ -1593,11 +1598,6 @@ def bins(self, bins): self._bins = bins - @paths.setter - def paths(self, paths): - cv.check_iterable_type('paths', paths, str) - self._paths = paths - def can_merge(self, other): # Distribcell filters cannot have more than one bin return False @@ -2060,22 +2060,6 @@ def from_tabulated1d(cls, tab1d): def energy(self): return self._energy - @property - def y(self): - return self._y - - @property - def interpolation(self): - return self._interpolation - - @property - def bins(self): - raise AttributeError('EnergyFunctionFilters have no bins.') - - @property - def num_bins(self): - return 1 - @energy.setter def energy(self, energy): # Format the bins as a 1D numpy array. @@ -2088,6 +2072,10 @@ def energy(self, energy): self._energy = energy + @property + def y(self): + return self._y + @y.setter def y(self, y): # Format the bins as a 1D numpy array. @@ -2098,9 +2086,9 @@ def y(self, y): self._y = y - @bins.setter - def bins(self, bins): - raise RuntimeError('EnergyFunctionFilters have no bins.') + @property + def interpolation(self): + return self._interpolation @interpolation.setter def interpolation(self, val): @@ -2115,6 +2103,18 @@ def interpolation(self, val): self._interpolation = val + @property + def bins(self): + raise AttributeError('EnergyFunctionFilters have no bins.') + + @bins.setter + def bins(self, bins): + raise RuntimeError('EnergyFunctionFilters have no bins.') + + @property + def num_bins(self): + return 1 + def to_xml_element(self): """Return XML Element representing the Filter. diff --git a/openmc/geometry.py b/openmc/geometry.py index 9038895b84b..d4e7aa201d0 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -57,6 +57,11 @@ def __init__(self, root=None): def root_universe(self) -> openmc.UniverseBase: return self._root_universe + @root_universe.setter + def root_universe(self, root_universe): + check_type('root universe', root_universe, openmc.UniverseBase) + self._root_universe = root_universe + @property def bounding_box(self) -> np.ndarray: return self.root_universe.bounding_box @@ -65,20 +70,15 @@ def bounding_box(self) -> np.ndarray: def merge_surfaces(self) -> bool: return self._merge_surfaces - @property - def surface_precision(self) -> int: - return self._surface_precision - - @root_universe.setter - def root_universe(self, root_universe): - check_type('root universe', root_universe, openmc.UniverseBase) - self._root_universe = root_universe - @merge_surfaces.setter def merge_surfaces(self, merge_surfaces): check_type('merge surfaces', merge_surfaces, bool) self._merge_surfaces = merge_surfaces + @property + def surface_precision(self) -> int: + return self._surface_precision + @surface_precision.setter def surface_precision(self, surface_precision): check_type('surface precision', surface_precision, int) diff --git a/openmc/lattice.py b/openmc/lattice.py index 37faaf00fc2..0983f6d0c7a 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -57,18 +57,6 @@ def __init__(self, lattice_id=None, name=''): def name(self): return self._name - @property - def pitch(self): - return self._pitch - - @property - def outer(self): - return self._outer - - @property - def universes(self): - return self._universes - @name.setter def name(self, name): if name is not None: @@ -77,11 +65,23 @@ def name(self, name): else: self._name = '' + @property + def pitch(self): + return self._pitch + + @property + def outer(self): + return self._outer + @outer.setter def outer(self, outer): cv.check_type('outer universe', outer, openmc.UniverseBase) self._outer = outer + @property + def universes(self): + return self._universes + @staticmethod def from_hdf5(group, universes): """Create lattice from HDF5 group @@ -460,6 +460,12 @@ def _natural_indices(self): def lower_left(self): return self._lower_left + @lower_left.setter + def lower_left(self, lower_left): + cv.check_type('lattice lower left corner', lower_left, Iterable, Real) + cv.check_length('lattice lower left corner', lower_left, 2, 3) + self._lower_left = lower_left + @property def ndim(self): if self.pitch is not None: @@ -472,12 +478,6 @@ def ndim(self): def shape(self): return self._universes.shape[::-1] - @lower_left.setter - def lower_left(self, lower_left): - cv.check_type('lattice lower left corner', lower_left, Iterable, Real) - cv.check_length('lattice lower left corner', lower_left, 2, 3) - self._lower_left = lower_left - @Lattice.pitch.setter def pitch(self, pitch): cv.check_type('lattice pitch', pitch, Iterable, Real) @@ -1127,6 +1127,11 @@ def num_rings(self): @property def orientation(self): return self._orientation + + @orientation.setter + def orientation(self, orientation): + cv.check_value('orientation', orientation.lower(), ('x', 'y')) + self._orientation = orientation.lower() @property def num_axial(self): @@ -1136,6 +1141,12 @@ def num_axial(self): def center(self): return self._center + @center.setter + def center(self, center): + cv.check_type('lattice center', center, Iterable, Real) + cv.check_length('lattice center', center, 2, 3) + self._center = center + @property def indices(self): if self.num_axial is None: @@ -1175,17 +1186,6 @@ def _natural_indices(self): def ndim(self): return 2 if isinstance(self.universes[0][0], openmc.UniverseBase) else 3 - @center.setter - def center(self, center): - cv.check_type('lattice center', center, Iterable, Real) - cv.check_length('lattice center', center, 2, 3) - self._center = center - - @orientation.setter - def orientation(self, orientation): - cv.check_value('orientation', orientation.lower(), ('x', 'y')) - self._orientation = orientation.lower() - @Lattice.pitch.setter def pitch(self, pitch): cv.check_type('lattice pitch', pitch, Iterable, Real) diff --git a/openmc/lib/plot.py b/openmc/lib/plot.py index da42ea49e0d..d142d6cd208 100644 --- a/openmc/lib/plot.py +++ b/openmc/lib/plot.py @@ -96,14 +96,28 @@ def __init__(self): def origin(self): return self.origin_ + @origin.setter + def origin(self, origin): + self.origin_.x = origin[0] + self.origin_.y = origin[1] + self.origin_.z = origin[2] + @property def width(self): return self.width_.x + @width.setter + def width(self, width): + self.width_.x = width + @property def height(self): return self.width_.y + @height.setter + def height(self, height): + self.width_.y = height + @property def basis(self): if self.basis_ == 1: @@ -145,14 +159,26 @@ def basis(self, basis): def h_res(self): return self.pixels_[0] + @h_res.setter + def h_res(self, h_res): + self.pixels_[0] = h_res + @property def v_res(self): return self.pixels_[1] + @v_res.setter + def v_res(self, v_res): + self.pixels_[1] = v_res + @property def level(self): return int(self.level_) + @level.setter + def level(self, level): + self.level_ = level + @property def color_overlaps(self): return self.color_overlaps_ @@ -161,32 +187,6 @@ def color_overlaps(self): def color_overlaps(self, color_overlaps): self.color_overlaps_ = color_overlaps - @origin.setter - def origin(self, origin): - self.origin_.x = origin[0] - self.origin_.y = origin[1] - self.origin_.z = origin[2] - - @width.setter - def width(self, width): - self.width_.x = width - - @height.setter - def height(self, height): - self.width_.y = height - - @h_res.setter - def h_res(self, h_res): - self.pixels_[0] = h_res - - @v_res.setter - def v_res(self, v_res): - self.pixels_[1] = v_res - - @level.setter - def level(self, level): - self.level_ = level - @property def color_overlaps(self): return self.color_overlaps_ diff --git a/openmc/lib/tally.py b/openmc/lib/tally.py index b8e048974de..f327692e73c 100644 --- a/openmc/lib/tally.py +++ b/openmc/lib/tally.py @@ -231,6 +231,10 @@ def active(self): _dll.openmc_tally_get_active(self._index, active) return active.value + @active.setter + def active(self, active): + _dll.openmc_tally_set_active(self._index, active) + @property def type(self): type = c_int32() @@ -251,10 +255,6 @@ def estimator(self): def estimator(self, estimator): _dll.openmc_tally_set_estimator(self._index, estimator.encode()) - @active.setter - def active(self, active): - _dll.openmc_tally_set_active(self._index, active) - @property def id(self): tally_id = c_int32() diff --git a/openmc/material.py b/openmc/material.py index 20041aa53c7..5f28535dba7 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -170,10 +170,25 @@ def __repr__(self) -> str: def name(self) -> Optional[str]: return self._name + @name.setter + def name(self, name: Optional[str]): + if name is not None: + cv.check_type(f'name for Material ID="{self._id}"', + name, str) + self._name = name + else: + self._name = '' + @property def temperature(self) -> Optional[float]: return self._temperature + @temperature.setter + def temperature(self, temperature: Optional[Real]): + cv.check_type(f'Temperature for Material ID="{self._id}"', + temperature, (Real, type(None))) + self._temperature = temperature + @property def density(self) -> Optional[float]: return self._density @@ -186,6 +201,12 @@ def density_units(self) -> str: def depletable(self) -> bool: return self._depletable + @depletable.setter + def depletable(self, depletable: bool): + cv.check_type(f'Depletable flag for Material ID="{self._id}"', + depletable, bool) + self._depletable = depletable + @property def paths(self) -> List[str]: if self._paths is None: @@ -209,6 +230,12 @@ def nuclides(self) -> List[namedtuple]: def isotropic(self) -> List[str]: return self._isotropic + @isotropic.setter + def isotropic(self, isotropic: typing.Iterable[str]): + cv.check_iterable_type('Isotropic scattering nuclides', isotropic, + str) + self._isotropic = list(isotropic) + @property def average_molar_mass(self) -> float: # Using the sum of specified atomic or weight amounts as a basis, sum @@ -230,42 +257,15 @@ def average_molar_mass(self) -> float: def volume(self) -> Optional[float]: return self._volume - @property - def ncrystal_cfg(self) -> Optional[str]: - return self._ncrystal_cfg - - @name.setter - def name(self, name: Optional[str]): - if name is not None: - cv.check_type(f'name for Material ID="{self._id}"', - name, str) - self._name = name - else: - self._name = '' - - @temperature.setter - def temperature(self, temperature: Optional[Real]): - cv.check_type(f'Temperature for Material ID="{self._id}"', - temperature, (Real, type(None))) - self._temperature = temperature - - @depletable.setter - def depletable(self, depletable: bool): - cv.check_type(f'Depletable flag for Material ID="{self._id}"', - depletable, bool) - self._depletable = depletable - @volume.setter def volume(self, volume: Real): if volume is not None: cv.check_type('material volume', volume, Real) self._volume = volume - @isotropic.setter - def isotropic(self, isotropic: typing.Iterable[str]): - cv.check_iterable_type('Isotropic scattering nuclides', isotropic, - str) - self._isotropic = list(isotropic) + @property + def ncrystal_cfg(self) -> Optional[str]: + return self._ncrystal_cfg @property def fissionable_mass(self) -> float: diff --git a/openmc/mesh.py b/openmc/mesh.py index 0a5dff64336..f9eaff6d5f8 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -522,6 +522,12 @@ def __init__(self, mesh_id=None, name=''): def dimension(self): return tuple(self._dimension) + @dimension.setter + def dimension(self, dimension): + cv.check_type('mesh dimension', dimension, Iterable, Integral) + cv.check_length('mesh dimension', dimension, 1, 3) + self._dimension = dimension + @property def n_dimension(self): if self._dimension is not None: @@ -533,6 +539,15 @@ def n_dimension(self): def lower_left(self): return self._lower_left + @lower_left.setter + def lower_left(self, lower_left): + cv.check_type('mesh lower_left', lower_left, Iterable, Real) + cv.check_length('mesh lower_left', lower_left, 1, 3) + self._lower_left = lower_left + + if self.upper_right is not None and any(np.isclose(self.upper_right, lower_left)): + raise ValueError("Mesh cannot have zero thickness in any dimension") + @property def upper_right(self): if self._upper_right is not None: @@ -544,6 +559,19 @@ def upper_right(self): dims = self._dimension return [l + w * d for l, w, d in zip(ls, ws, dims)] + @upper_right.setter + def upper_right(self, upper_right): + cv.check_type('mesh upper_right', upper_right, Iterable, Real) + cv.check_length('mesh upper_right', upper_right, 1, 3) + self._upper_right = upper_right + + if self._width is not None: + self._width = None + warnings.warn("Unsetting width attribute.") + + if self.lower_left is not None and any(np.isclose(self.lower_left, upper_right)): + raise ValueError("Mesh cannot have zero thickness in any dimension") + @property def width(self): if self._width is not None: @@ -555,6 +583,16 @@ def width(self): dims = self._dimension return [(u - l) / d for u, l, d in zip(us, ls, dims)] + @width.setter + def width(self, width): + cv.check_type('mesh width', width, Iterable, Real) + cv.check_length('mesh width', width, 1, 3) + self._width = width + + if self._upper_right is not None: + self._upper_right = None + warnings.warn("Unsetting upper_right attribute.") + @property def cartesian_vertices(self): """Returns vertices in cartesian coordiantes. Identical to ``vertices`` for RegularMesh and RectilinearMesh @@ -626,44 +664,6 @@ def bounding_box(self): np.array(self.lower_left), np.array(self.upper_right) ) - @dimension.setter - def dimension(self, dimension): - cv.check_type('mesh dimension', dimension, Iterable, Integral) - cv.check_length('mesh dimension', dimension, 1, 3) - self._dimension = dimension - - @lower_left.setter - def lower_left(self, lower_left): - cv.check_type('mesh lower_left', lower_left, Iterable, Real) - cv.check_length('mesh lower_left', lower_left, 1, 3) - self._lower_left = lower_left - - if self.upper_right is not None and any(np.isclose(self.upper_right, lower_left)): - raise ValueError("Mesh cannot have zero thickness in any dimension") - - @upper_right.setter - def upper_right(self, upper_right): - cv.check_type('mesh upper_right', upper_right, Iterable, Real) - cv.check_length('mesh upper_right', upper_right, 1, 3) - self._upper_right = upper_right - - if self._width is not None: - self._width = None - warnings.warn("Unsetting width attribute.") - - if self.lower_left is not None and any(np.isclose(self.lower_left, upper_right)): - raise ValueError("Mesh cannot have zero thickness in any dimension") - - @width.setter - def width(self, width): - cv.check_type('mesh width', width, Iterable, Real) - cv.check_length('mesh width', width, 1, 3) - self._width = width - - if self._upper_right is not None: - self._upper_right = None - warnings.warn("Unsetting upper_right attribute.") - def __repr__(self): string = super().__repr__() string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) @@ -1020,14 +1020,29 @@ def n_dimension(self): def x_grid(self): return self._x_grid + @x_grid.setter + def x_grid(self, grid): + cv.check_type('mesh x_grid', grid, Iterable, Real) + self._x_grid = np.asarray(grid) + @property def y_grid(self): return self._y_grid + @y_grid.setter + def y_grid(self, grid): + cv.check_type('mesh y_grid', grid, Iterable, Real) + self._y_grid = np.asarray(grid) + @property def z_grid(self): return self._z_grid + @z_grid.setter + def z_grid(self, grid): + cv.check_type('mesh z_grid', grid, Iterable, Real) + self._z_grid = np.asarray(grid) + @property def _grids(self): return (self.x_grid, self.y_grid, self.z_grid) @@ -1069,21 +1084,6 @@ def indices(self): for y in range(1, ny + 1) for x in range(1, nx + 1)) - @x_grid.setter - def x_grid(self, grid): - cv.check_type('mesh x_grid', grid, Iterable, Real) - self._x_grid = np.asarray(grid) - - @y_grid.setter - def y_grid(self, grid): - cv.check_type('mesh y_grid', grid, Iterable, Real) - self._y_grid = np.asarray(grid) - - @z_grid.setter - def z_grid(self, grid): - cv.check_type('mesh z_grid', grid, Iterable, Real) - self._z_grid = np.asarray(grid) - def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() @@ -1225,17 +1225,38 @@ def n_dimension(self): def origin(self): return self._origin + @origin.setter + def origin(self, coords): + cv.check_type('mesh origin', coords, Iterable, Real) + cv.check_length("mesh origin", coords, 3) + self._origin = np.asarray(coords) + @property def r_grid(self): return self._r_grid + @r_grid.setter + def r_grid(self, grid): + cv.check_type('mesh r_grid', grid, Iterable, Real) + self._r_grid = np.asarray(grid) + @property def phi_grid(self): return self._phi_grid + @phi_grid.setter + def phi_grid(self, grid): + cv.check_type('mesh phi_grid', grid, Iterable, Real) + self._phi_grid = np.asarray(grid) + @property def z_grid(self): return self._z_grid + + @z_grid.setter + def z_grid(self, grid): + cv.check_type('mesh z_grid', grid, Iterable, Real) + self._z_grid = np.asarray(grid) @property def _grids(self): @@ -1251,27 +1272,6 @@ def indices(self): for p in range(1, np + 1) for r in range(1, nr + 1)) - @origin.setter - def origin(self, coords): - cv.check_type('mesh origin', coords, Iterable, Real) - cv.check_length("mesh origin", coords, 3) - self._origin = np.asarray(coords) - - @r_grid.setter - def r_grid(self, grid): - cv.check_type('mesh r_grid', grid, Iterable, Real) - self._r_grid = np.asarray(grid) - - @phi_grid.setter - def phi_grid(self, grid): - cv.check_type('mesh phi_grid', grid, Iterable, Real) - self._phi_grid = np.asarray(grid) - - @z_grid.setter - def z_grid(self, grid): - cv.check_type('mesh z_grid', grid, Iterable, Real) - self._z_grid = np.asarray(grid) - def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() @@ -1525,18 +1525,39 @@ def n_dimension(self): def origin(self): return self._origin + @origin.setter + def origin(self, coords): + cv.check_type('mesh origin', coords, Iterable, Real) + cv.check_length("mesh origin", coords, 3) + self._origin = np.asarray(coords) + @property def r_grid(self): return self._r_grid + @r_grid.setter + def r_grid(self, grid): + cv.check_type('mesh r_grid', grid, Iterable, Real) + self._r_grid = np.asarray(grid) + @property def theta_grid(self): return self._theta_grid + @theta_grid.setter + def theta_grid(self, grid): + cv.check_type('mesh theta_grid', grid, Iterable, Real) + self._theta_grid = np.asarray(grid) + @property def phi_grid(self): return self._phi_grid + @phi_grid.setter + def phi_grid(self, grid): + cv.check_type('mesh phi_grid', grid, Iterable, Real) + self._phi_grid = np.asarray(grid) + @property def _grids(self): return (self.r_grid, self.theta_grid, self.phi_grid) @@ -1551,27 +1572,6 @@ def indices(self): for t in range(1, nt + 1) for r in range(1, nr + 1)) - @origin.setter - def origin(self, coords): - cv.check_type('mesh origin', coords, Iterable, Real) - cv.check_length("mesh origin", coords, 3) - self._origin = np.asarray(coords) - - @r_grid.setter - def r_grid(self, grid): - cv.check_type('mesh r_grid', grid, Iterable, Real) - self._r_grid = np.asarray(grid) - - @theta_grid.setter - def theta_grid(self, grid): - cv.check_type('mesh theta_grid', grid, Iterable, Real) - self._theta_grid = np.asarray(grid) - - @phi_grid.setter - def phi_grid(self, grid): - cv.check_type('mesh phi_grid', grid, Iterable, Real) - self._phi_grid = np.asarray(grid) - def __repr__(self): fmt = '{0: <16}{1}{2}\n' string = super().__repr__() diff --git a/openmc/mgxs/groups.py b/openmc/mgxs/groups.py index eaef519da18..ef4b78f7ed5 100644 --- a/openmc/mgxs/groups.py +++ b/openmc/mgxs/groups.py @@ -75,16 +75,16 @@ def __repr__(self): def group_edges(self): return self._group_edges - @property - def num_groups(self): - return len(self.group_edges) - 1 - @group_edges.setter def group_edges(self, edges): cv.check_type('group edges', edges, Iterable, Real) cv.check_greater_than('number of group edges', len(edges), 1) self._group_edges = np.array(edges) + @property + def num_groups(self): + return len(self.group_edges) - 1 + def get_group(self, energy): """Returns the energy group in which the given energy resides. diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index 8ab052b0d4f..988b7cc7566 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -178,118 +178,23 @@ def __deepcopy__(self, memo): def geometry(self): return self._geometry - @property - def name(self): - return self._name - - @property - def mgxs_types(self): - return self._mgxs_types - - @property - def by_nuclide(self): - return self._by_nuclide - - @property - def domain_type(self): - return self._domain_type - - @property - def domains(self): - if self._domains == 'all': - if self.domain_type == 'material': - return list(self.geometry.get_all_materials().values()) - elif self.domain_type == 'cell': - return list(self.geometry.get_all_cells().values()) - elif self.domain_type in 'distribcell': - return list(self.geometry.get_all_material_cells().values()) - elif self.domain_type == 'universe': - return list(self.geometry.get_all_universes().values()) - elif self.domain_type == 'mesh': - raise ValueError('Unable to get domains for Mesh domain type') - else: - raise ValueError('Unable to get domains without a domain type') - else: - return self._domains - - @property - def nuclides(self): - return self._nuclides - - @property - def energy_groups(self): - return self._energy_groups - - @property - def num_delayed_groups(self): - return self._num_delayed_groups - - @property - def num_polar(self): - return self._num_polar - - @property - def num_azimuthal(self): - return self._num_azimuthal - - @property - def correction(self): - return self._correction - - @property - def scatter_format(self): - return self._scatter_format - - @property - def legendre_order(self): - return self._legendre_order - - @property - def histogram_bins(self): - return self._histogram_bins - - @property - def tally_trigger(self): - return self._tally_trigger - - @property - def estimator(self): - return self._estimator - - @property - def num_groups(self): - return self.energy_groups.num_groups - - @property - def all_mgxs(self): - return self._all_mgxs - - @property - def sp_filename(self): - return self._sp_filename - - @property - def keff(self): - return self._keff - - @property - def sparse(self): - return self._sparse - @geometry.setter def geometry(self, geometry): cv.check_type('geometry', geometry, openmc.Geometry) self._geometry = geometry + @property + def name(self): + return self._name + @name.setter def name(self, name): cv.check_type('name', name, str) self._name = name - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, str) - self._nuclides = nuclides + + @property + def mgxs_types(self): + return self._mgxs_types @mgxs_types.setter def mgxs_types(self, mgxs_types): @@ -304,6 +209,10 @@ def mgxs_types(self, mgxs_types): cv.check_value('mgxs_type', mgxs_type, all_mgxs_types) self._mgxs_types = mgxs_types + @property + def by_nuclide(self): + return self._by_nuclide + @by_nuclide.setter def by_nuclide(self, by_nuclide): cv.check_type('by_nuclide', by_nuclide, bool) @@ -314,6 +223,10 @@ def by_nuclide(self, by_nuclide): self._by_nuclide = by_nuclide + @property + def domain_type(self): + return self._domain_type + @domain_type.setter def domain_type(self, domain_type): cv.check_value('domain type', domain_type, openmc.mgxs.DOMAIN_TYPES) @@ -324,6 +237,24 @@ def domain_type(self, domain_type): self._domain_type = domain_type + @property + def domains(self): + if self._domains == 'all': + if self.domain_type == 'material': + return list(self.geometry.get_all_materials().values()) + elif self.domain_type == 'cell': + return list(self.geometry.get_all_cells().values()) + elif self.domain_type in 'distribcell': + return list(self.geometry.get_all_material_cells().values()) + elif self.domain_type == 'universe': + return list(self.geometry.get_all_universes().values()) + elif self.domain_type == 'mesh': + raise ValueError('Unable to get domains for Mesh domain type') + else: + raise ValueError('Unable to get domains without a domain type') + else: + return self._domains + @domains.setter def domains(self, domains): @@ -363,11 +294,28 @@ def domains(self, domains): self._domains = list(domains) + @property + def nuclides(self): + return self._nuclides + + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, str) + self._nuclides = nuclides + + @property + def energy_groups(self): + return self._energy_groups + @energy_groups.setter def energy_groups(self, energy_groups): cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) self._energy_groups = energy_groups + @property + def num_delayed_groups(self): + return self._num_delayed_groups + @num_delayed_groups.setter def num_delayed_groups(self, num_delayed_groups): @@ -376,6 +324,10 @@ def num_delayed_groups(self, num_delayed_groups): cv.check_greater_than('num delayed groups', num_delayed_groups, 0, equality=True) self._num_delayed_groups = num_delayed_groups + + @property + def num_polar(self): + return self._num_polar @num_polar.setter def num_polar(self, num_polar): @@ -383,12 +335,20 @@ def num_polar(self, num_polar): cv.check_greater_than('num_polar', num_polar, 0) self._num_polar = num_polar + @property + def num_azimuthal(self): + return self._num_azimuthal + @num_azimuthal.setter def num_azimuthal(self, num_azimuthal): cv.check_type('num_azimuthal', num_azimuthal, Integral) cv.check_greater_than('num_azimuthal', num_azimuthal, 0) self._num_azimuthal = num_azimuthal + @property + def correction(self): + return self._correction + @correction.setter def correction(self, correction): cv.check_value('correction', correction, ('P0', None)) @@ -406,6 +366,10 @@ def correction(self, correction): self._correction = correction + @property + def scatter_format(self): + return self._scatter_format + @scatter_format.setter def scatter_format(self, scatter_format): cv.check_value('scatter_format', scatter_format, @@ -418,6 +382,10 @@ def scatter_format(self, scatter_format): self.correction = None self._scatter_format = scatter_format + + @property + def legendre_order(self): + return self._legendre_order @legendre_order.setter def legendre_order(self, legendre_order): @@ -440,6 +408,10 @@ def legendre_order(self, legendre_order): self._legendre_order = legendre_order + @property + def histogram_bins(self): + return self._histogram_bins + @histogram_bins.setter def histogram_bins(self, histogram_bins): cv.check_type('histogram_bins', histogram_bins, Integral) @@ -459,16 +431,44 @@ def histogram_bins(self, histogram_bins): self._histogram_bins = histogram_bins + @property + def tally_trigger(self): + return self._tally_trigger + @tally_trigger.setter def tally_trigger(self, tally_trigger): cv.check_type('tally trigger', tally_trigger, openmc.Trigger) self._tally_trigger = tally_trigger + @property + def estimator(self): + return self._estimator + @estimator.setter def estimator(self, estimator): cv.check_value('estimator', estimator, ESTIMATOR_TYPES) self._estimator = estimator + @property + def num_groups(self): + return self.energy_groups.num_groups + + @property + def all_mgxs(self): + return self._all_mgxs + + @property + def sp_filename(self): + return self._sp_filename + + @property + def keff(self): + return self._keff + + @property + def sparse(self): + return self._sparse + @sparse.setter def sparse(self, sparse): """Convert tally data from NumPy arrays to SciPy list of lists (LIL) diff --git a/openmc/mgxs/mdgxs.py b/openmc/mgxs/mdgxs.py index 96192323e0f..7643757d469 100644 --- a/openmc/mgxs/mdgxs.py +++ b/openmc/mgxs/mdgxs.py @@ -187,13 +187,6 @@ def _dont_squeeze(self): def delayed_groups(self): return self._delayed_groups - @property - def num_delayed_groups(self): - if self.delayed_groups is None: - return 1 - else: - return len(self.delayed_groups) - @delayed_groups.setter def delayed_groups(self, delayed_groups): @@ -210,6 +203,13 @@ def delayed_groups(self, delayed_groups): self._delayed_groups = delayed_groups + @property + def num_delayed_groups(self): + if self.delayed_groups is None: + return 1 + else: + return len(self.delayed_groups) + @property def filters(self): diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 1077896ccc6..264cbc8924c 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -453,6 +453,11 @@ def _dont_squeeze(self): def name(self): return self._name + @name.setter + def name(self, name): + cv.check_type('name', name, str) + self._name = name + @property def rxn_type(self): return self._rxn_type @@ -461,30 +466,78 @@ def rxn_type(self): def by_nuclide(self): return self._by_nuclide + @by_nuclide.setter + def by_nuclide(self, by_nuclide): + cv.check_type('by_nuclide', by_nuclide, bool) + self._by_nuclide = by_nuclide + @property def domain(self): return self._domain + @domain.setter + def domain(self, domain): + cv.check_type('domain', domain, _DOMAINS) + self._domain = domain + + # Assign a domain type + if self.domain_type is None: + if isinstance(domain, openmc.Material): + self._domain_type = 'material' + elif isinstance(domain, openmc.Cell): + self._domain_type = 'cell' + elif isinstance(domain, openmc.Universe): + self._domain_type = 'universe' + elif isinstance(domain, openmc.RegularMesh): + self._domain_type = 'mesh' + @property def domain_type(self): return self._domain_type + @domain_type.setter + def domain_type(self, domain_type): + cv.check_value('domain type', domain_type, DOMAIN_TYPES) + self._domain_type = domain_type + @property def energy_groups(self): return self._energy_groups + @energy_groups.setter + def energy_groups(self, energy_groups): + cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) + self._energy_groups = energy_groups + @property def num_polar(self): return self._num_polar + @num_polar.setter + def num_polar(self, num_polar): + cv.check_type('num_polar', num_polar, Integral) + cv.check_greater_than('num_polar', num_polar, 0) + self._num_polar = num_polar + @property def num_azimuthal(self): return self._num_azimuthal + @num_azimuthal.setter + def num_azimuthal(self, num_azimuthal): + cv.check_type('num_azimuthal', num_azimuthal, Integral) + cv.check_greater_than('num_azimuthal', num_azimuthal, 0) + self._num_azimuthal = num_azimuthal + @property def tally_trigger(self): return self._tally_trigger + @tally_trigger.setter + def tally_trigger(self, tally_trigger): + cv.check_type('tally trigger', tally_trigger, openmc.Trigger) + self._tally_trigger = tally_trigger + @property def num_groups(self): return self.energy_groups.num_groups @@ -511,6 +564,11 @@ def tally_keys(self): def estimator(self): return self._estimator + @estimator.setter + def estimator(self, estimator): + cv.check_value('estimator', estimator, self._valid_estimators) + self._estimator = estimator + @property def tallies(self): @@ -585,6 +643,31 @@ def xs_tally(self): def sparse(self): return self._sparse + @sparse.setter + def sparse(self, sparse): + """Convert tally data from NumPy arrays to SciPy list of lists (LIL) + sparse matrices, and vice versa. + + This property may be used to reduce the amount of data in memory during + tally data processing. The tally data will be stored as SciPy LIL + matrices internally within the Tally object. All tally data access + properties and methods will return data as a dense NumPy array. + + """ + + cv.check_type('sparse', sparse, bool) + + # Sparsify or densify the derived MGXS tallies and the base tallies + if self._xs_tally: + self.xs_tally.sparse = sparse + if self._rxn_rate_tally: + self.rxn_rate_tally.sparse = sparse + + for tally_name in self.tallies: + self.tallies[tally_name].sparse = sparse + + self._sparse = sparse + @property def num_subdomains(self): if self.domain_type.startswith('sum('): @@ -612,6 +695,11 @@ def nuclides(self): else: return ['sum'] + @nuclides.setter + def nuclides(self, nuclides): + cv.check_iterable_type('nuclides', nuclides, str) + self._nuclides = nuclides + @property def loaded_sp(self): return self._loaded_sp @@ -627,94 +715,6 @@ def mgxs_type(self): else: return self._rxn_type - @name.setter - def name(self, name): - cv.check_type('name', name, str) - self._name = name - - @by_nuclide.setter - def by_nuclide(self, by_nuclide): - cv.check_type('by_nuclide', by_nuclide, bool) - self._by_nuclide = by_nuclide - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_iterable_type('nuclides', nuclides, str) - self._nuclides = nuclides - - @estimator.setter - def estimator(self, estimator): - cv.check_value('estimator', estimator, self._valid_estimators) - self._estimator = estimator - - @domain.setter - def domain(self, domain): - cv.check_type('domain', domain, _DOMAINS) - self._domain = domain - - # Assign a domain type - if self.domain_type is None: - if isinstance(domain, openmc.Material): - self._domain_type = 'material' - elif isinstance(domain, openmc.Cell): - self._domain_type = 'cell' - elif isinstance(domain, openmc.Universe): - self._domain_type = 'universe' - elif isinstance(domain, openmc.RegularMesh): - self._domain_type = 'mesh' - - @domain_type.setter - def domain_type(self, domain_type): - cv.check_value('domain type', domain_type, DOMAIN_TYPES) - self._domain_type = domain_type - - @energy_groups.setter - def energy_groups(self, energy_groups): - cv.check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) - self._energy_groups = energy_groups - - @num_polar.setter - def num_polar(self, num_polar): - cv.check_type('num_polar', num_polar, Integral) - cv.check_greater_than('num_polar', num_polar, 0) - self._num_polar = num_polar - - @num_azimuthal.setter - def num_azimuthal(self, num_azimuthal): - cv.check_type('num_azimuthal', num_azimuthal, Integral) - cv.check_greater_than('num_azimuthal', num_azimuthal, 0) - self._num_azimuthal = num_azimuthal - - @tally_trigger.setter - def tally_trigger(self, tally_trigger): - cv.check_type('tally trigger', tally_trigger, openmc.Trigger) - self._tally_trigger = tally_trigger - - @sparse.setter - def sparse(self, sparse): - """Convert tally data from NumPy arrays to SciPy list of lists (LIL) - sparse matrices, and vice versa. - - This property may be used to reduce the amount of data in memory during - tally data processing. The tally data will be stored as SciPy LIL - matrices internally within the Tally object. All tally data access - properties and methods will return data as a dense NumPy array. - - """ - - cv.check_type('sparse', sparse, bool) - - # Sparsify or densify the derived MGXS tallies and the base tallies - if self._xs_tally: - self.xs_tally.sparse = sparse - if self._rxn_rate_tally: - self.rxn_rate_tally.sparse = sparse - - for tally_name in self.tallies: - self.tallies[tally_name].sparse = sparse - - self._sparse = sparse - @staticmethod def get_mgxs(mgxs_type, domain=None, domain_type=None, energy_groups=None, by_nuclide=False, name='', num_polar=1, @@ -3453,10 +3453,6 @@ def __deepcopy__(self, memo): def nu(self): return self._nu - @property - def prompt(self): - return self._prompt - @nu.setter def nu(self, nu): cv.check_type('nu', nu, bool) @@ -3469,6 +3465,10 @@ def nu(self, nu): else: self._rxn_type = 'prompt-nu-fission' + @property + def prompt(self): + return self._prompt + @prompt.setter def prompt(self, prompt): cv.check_type('prompt', prompt, bool) @@ -4006,26 +4006,115 @@ def _dont_squeeze(self): def formulation(self): return self._formulation + @formulation.setter + def formulation(self, formulation): + cv.check_value('formulation', formulation, ('simple', 'consistent')) + self._formulation = formulation + + if self.formulation == 'simple': + self._valid_estimators = ['analog'] + if not self.nu: + self._mgxs_type = 'scatter matrix' + else: + self._mgxs_type = 'nu-scatter matrix' + else: + self._valid_estimators = ['tracklength'] + if not self.nu: + self._mgxs_type = 'consistent scatter matrix' + else: + self._mgxs_type = 'consistent nu-scatter matrix' + @property def correction(self): return self._correction + @correction.setter + def correction(self, correction): + cv.check_value('correction', correction, ('P0', None)) + + if self.scatter_format == SCATTER_LEGENDRE: + if correction == 'P0' and self.legendre_order > 0: + msg = 'The P0 correction will be ignored since the ' \ + 'scattering order {} is greater than '\ + 'zero'.format(self.legendre_order) + warnings.warn(msg) + elif self.scatter_format == SCATTER_HISTOGRAM: + msg = 'The P0 correction will be ignored since the ' \ + 'scatter format is set to histogram' + warnings.warn(msg) + + self._correction = correction + @property def scatter_format(self): return self._scatter_format + @scatter_format.setter + def scatter_format(self, scatter_format): + cv.check_value('scatter_format', scatter_format, MU_TREATMENTS) + self._scatter_format = scatter_format + @property def legendre_order(self): return self._legendre_order + @legendre_order.setter + def legendre_order(self, legendre_order): + cv.check_type('legendre_order', legendre_order, Integral) + cv.check_greater_than('legendre_order', legendre_order, 0, + equality=True) + cv.check_less_than('legendre_order', legendre_order, _MAX_LEGENDRE, + equality=True) + + if self.scatter_format == SCATTER_LEGENDRE: + if self.correction == 'P0' and legendre_order > 0: + msg = 'The P0 correction will be ignored since the ' \ + 'scattering order {} is greater than '\ + 'zero'.format(legendre_order) + warnings.warn(msg, RuntimeWarning) + self.correction = None + elif self.scatter_format == SCATTER_HISTOGRAM: + msg = 'The legendre order will be ignored since the ' \ + 'scatter format is set to histogram' + warnings.warn(msg) + + self._legendre_order = legendre_order + @property def histogram_bins(self): return self._histogram_bins + @histogram_bins.setter + def histogram_bins(self, histogram_bins): + cv.check_type('histogram_bins', histogram_bins, Integral) + cv.check_greater_than('histogram_bins', histogram_bins, 0) + + self._histogram_bins = histogram_bins + @property def nu(self): return self._nu + @nu.setter + def nu(self, nu): + cv.check_type('nu', nu, bool) + self._nu = nu + + if self.formulation == 'simple': + if not nu: + self._rxn_type = 'scatter' + self._mgxs_type = 'scatter matrix' + else: + self._rxn_type = 'nu-scatter' + self._mgxs_type = 'nu-scatter matrix' + else: + if not nu: + self._rxn_type = 'scatter' + self._mgxs_type = 'consistent scatter matrix' + else: + self._rxn_type = 'nu-scatter' + self._mgxs_type = 'consistent nu-scatter matrix' + @property def scores(self): @@ -4307,95 +4396,6 @@ def xs_tally(self): return self._xs_tally - @nu.setter - def nu(self, nu): - cv.check_type('nu', nu, bool) - self._nu = nu - - if self.formulation == 'simple': - if not nu: - self._rxn_type = 'scatter' - self._mgxs_type = 'scatter matrix' - else: - self._rxn_type = 'nu-scatter' - self._mgxs_type = 'nu-scatter matrix' - else: - if not nu: - self._rxn_type = 'scatter' - self._mgxs_type = 'consistent scatter matrix' - else: - self._rxn_type = 'nu-scatter' - self._mgxs_type = 'consistent nu-scatter matrix' - - @formulation.setter - def formulation(self, formulation): - cv.check_value('formulation', formulation, ('simple', 'consistent')) - self._formulation = formulation - - if self.formulation == 'simple': - self._valid_estimators = ['analog'] - if not self.nu: - self._mgxs_type = 'scatter matrix' - else: - self._mgxs_type = 'nu-scatter matrix' - else: - self._valid_estimators = ['tracklength'] - if not self.nu: - self._mgxs_type = 'consistent scatter matrix' - else: - self._mgxs_type = 'consistent nu-scatter matrix' - - @correction.setter - def correction(self, correction): - cv.check_value('correction', correction, ('P0', None)) - - if self.scatter_format == SCATTER_LEGENDRE: - if correction == 'P0' and self.legendre_order > 0: - msg = 'The P0 correction will be ignored since the ' \ - 'scattering order {} is greater than '\ - 'zero'.format(self.legendre_order) - warnings.warn(msg) - elif self.scatter_format == SCATTER_HISTOGRAM: - msg = 'The P0 correction will be ignored since the ' \ - 'scatter format is set to histogram' - warnings.warn(msg) - - self._correction = correction - - @scatter_format.setter - def scatter_format(self, scatter_format): - cv.check_value('scatter_format', scatter_format, MU_TREATMENTS) - self._scatter_format = scatter_format - - @legendre_order.setter - def legendre_order(self, legendre_order): - cv.check_type('legendre_order', legendre_order, Integral) - cv.check_greater_than('legendre_order', legendre_order, 0, - equality=True) - cv.check_less_than('legendre_order', legendre_order, _MAX_LEGENDRE, - equality=True) - - if self.scatter_format == SCATTER_LEGENDRE: - if self.correction == 'P0' and legendre_order > 0: - msg = 'The P0 correction will be ignored since the ' \ - 'scattering order {} is greater than '\ - 'zero'.format(legendre_order) - warnings.warn(msg, RuntimeWarning) - self.correction = None - elif self.scatter_format == SCATTER_HISTOGRAM: - msg = 'The legendre order will be ignored since the ' \ - 'scatter format is set to histogram' - warnings.warn(msg) - - self._legendre_order = legendre_order - - @histogram_bins.setter - def histogram_bins(self, histogram_bins): - cv.check_type('histogram_bins', histogram_bins, Integral) - cv.check_greater_than('histogram_bins', histogram_bins, 0) - - self._histogram_bins = histogram_bins - def load_from_statepoint(self, statepoint): """Extracts tallies in an OpenMC StatePoint with the data needed to compute multi-group cross sections. @@ -5416,6 +5416,17 @@ def __deepcopy__(self, memo): def prompt(self): return self._prompt + @prompt.setter + def prompt(self, prompt): + cv.check_type('prompt', prompt, bool) + self._prompt = prompt + if not self.prompt: + self._rxn_type = 'chi' + self._mgxs_type = 'chi' + else: + self._rxn_type = 'chi-prompt' + self._mgxs_type = 'chi-prompt' + @property def _dont_squeeze(self): """Create a tuple of axes which should not be removed during the get_xs @@ -5472,17 +5483,6 @@ def xs_tally(self): return self._xs_tally - @prompt.setter - def prompt(self, prompt): - cv.check_type('prompt', prompt, bool) - self._prompt = prompt - if not self.prompt: - self._rxn_type = 'chi' - self._mgxs_type = 'chi' - else: - self._rxn_type = 'chi-prompt' - self._mgxs_type = 'chi-prompt' - def get_homogenized_mgxs(self, other_mgxs): """Construct a homogenized mgxs with other MGXS objects. @@ -5968,10 +5968,6 @@ def scores(self): def domain(self): return self._domain - @property - def domain_type(self): - return self._domain_type - @domain.setter def domain(self, domain): cv.check_type('domain', domain, openmc.RegularMesh) @@ -5981,6 +5977,10 @@ def domain(self, domain): if self.domain_type is None: self._domain_type = 'mesh' + @property + def domain_type(self): + return self._domain_type + @domain_type.setter def domain_type(self, domain_type): cv.check_value('domain type', domain_type, 'mesh') diff --git a/openmc/mgxs_library.py b/openmc/mgxs_library.py index 98a99196e5a..85e15f8ebca 100644 --- a/openmc/mgxs_library.py +++ b/openmc/mgxs_library.py @@ -260,22 +260,62 @@ def __deepcopy__(self, memo): def name(self): return self._name + @name.setter + def name(self, name): + + check_type('name for XSdata', name, str) + self._name = name + @property def energy_groups(self): return self._energy_groups + @energy_groups.setter + def energy_groups(self, energy_groups): + + check_type('energy_groups', energy_groups, openmc.mgxs.EnergyGroups) + if energy_groups.group_edges is None: + msg = 'Unable to assign an EnergyGroups object ' \ + 'with uninitialized group edges' + raise ValueError(msg) + + self._energy_groups = energy_groups + @property def num_delayed_groups(self): return self._num_delayed_groups + @num_delayed_groups.setter + def num_delayed_groups(self, num_delayed_groups): + + check_type('num_delayed_groups', num_delayed_groups, Integral) + check_less_than('num_delayed_groups', num_delayed_groups, + openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) + check_greater_than('num_delayed_groups', num_delayed_groups, 0, + equality=True) + self._num_delayed_groups = num_delayed_groups + @property def representation(self): return self._representation + @representation.setter + def representation(self, representation): + + check_value('representation', representation, _REPRESENTATIONS) + self._representation = representation + @property def atomic_weight_ratio(self): return self._atomic_weight_ratio + @atomic_weight_ratio.setter + def atomic_weight_ratio(self, atomic_weight_ratio): + + check_type('atomic_weight_ratio', atomic_weight_ratio, Real) + check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) + self._atomic_weight_ratio = atomic_weight_ratio + @property def fissionable(self): return self._fissionable @@ -284,22 +324,55 @@ def fissionable(self): def temperatures(self): return self._temperatures + @temperatures.setter + def temperatures(self, temperatures): + + check_iterable_type('temperatures', temperatures, Real) + self._temperatures = np.array(temperatures) + @property def scatter_format(self): return self._scatter_format + @scatter_format.setter + def scatter_format(self, scatter_format): + + check_value('scatter_format', scatter_format, _SCATTER_TYPES) + self._scatter_format = scatter_format + @property def order(self): return self._order + @order.setter + def order(self, order): + + check_type('order', order, Integral) + check_greater_than('order', order, 0, equality=True) + self._order = order + @property def num_polar(self): return self._num_polar + @num_polar.setter + def num_polar(self, num_polar): + + check_type('num_polar', num_polar, Integral) + check_greater_than('num_polar', num_polar, 0) + self._num_polar = num_polar + @property def num_azimuthal(self): return self._num_azimuthal + @num_azimuthal.setter + def num_azimuthal(self, num_azimuthal): + + check_type('num_azimuthal', num_azimuthal, Integral) + check_greater_than('num_azimuthal', num_azimuthal, 0) + self._num_azimuthal = num_azimuthal + @property def total(self): return self._total @@ -401,79 +474,6 @@ def xs_shapes(self): return self._xs_shapes - @name.setter - def name(self, name): - - check_type('name for XSdata', name, str) - self._name = name - - @energy_groups.setter - def energy_groups(self, energy_groups): - - check_type('energy_groups', energy_groups, openmc.mgxs.EnergyGroups) - if energy_groups.group_edges is None: - msg = 'Unable to assign an EnergyGroups object ' \ - 'with uninitialized group edges' - raise ValueError(msg) - - self._energy_groups = energy_groups - - @num_delayed_groups.setter - def num_delayed_groups(self, num_delayed_groups): - - check_type('num_delayed_groups', num_delayed_groups, Integral) - check_less_than('num_delayed_groups', num_delayed_groups, - openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) - check_greater_than('num_delayed_groups', num_delayed_groups, 0, - equality=True) - self._num_delayed_groups = num_delayed_groups - - @representation.setter - def representation(self, representation): - - check_value('representation', representation, _REPRESENTATIONS) - self._representation = representation - - @atomic_weight_ratio.setter - def atomic_weight_ratio(self, atomic_weight_ratio): - - check_type('atomic_weight_ratio', atomic_weight_ratio, Real) - check_greater_than('atomic_weight_ratio', atomic_weight_ratio, 0.0) - self._atomic_weight_ratio = atomic_weight_ratio - - @temperatures.setter - def temperatures(self, temperatures): - - check_iterable_type('temperatures', temperatures, Real) - self._temperatures = np.array(temperatures) - - @scatter_format.setter - def scatter_format(self, scatter_format): - - check_value('scatter_format', scatter_format, _SCATTER_TYPES) - self._scatter_format = scatter_format - - @order.setter - def order(self, order): - - check_type('order', order, Integral) - check_greater_than('order', order, 0, equality=True) - self._order = order - - @num_polar.setter - def num_polar(self, num_polar): - - check_type('num_polar', num_polar, Integral) - check_greater_than('num_polar', num_polar, 0) - self._num_polar = num_polar - - @num_azimuthal.setter - def num_azimuthal(self, num_azimuthal): - - check_type('num_azimuthal', num_azimuthal, Integral) - check_greater_than('num_azimuthal', num_azimuthal, 0) - self._num_azimuthal = num_azimuthal - def add_temperature(self, temperature): """This method re-sizes the attributes of this XSdata object so that it can accommodate an additional temperature. Note that the set_* methods @@ -2330,23 +2330,15 @@ def __deepcopy__(self, memo): def energy_groups(self): return self._energy_groups - @property - def num_delayed_groups(self): - return self._num_delayed_groups - - @property - def xsdatas(self): - return self._xsdatas - - @property - def names(self): - return [xsdata.name for xsdata in self.xsdatas] - @energy_groups.setter def energy_groups(self, energy_groups): check_type('energy groups', energy_groups, openmc.mgxs.EnergyGroups) self._energy_groups = energy_groups + @property + def num_delayed_groups(self): + return self._num_delayed_groups + @num_delayed_groups.setter def num_delayed_groups(self, num_delayed_groups): check_type('num_delayed_groups', num_delayed_groups, Integral) @@ -2356,6 +2348,14 @@ def num_delayed_groups(self, num_delayed_groups): openmc.mgxs.MAX_DELAYED_GROUPS, equality=True) self._num_delayed_groups = num_delayed_groups + @property + def xsdatas(self): + return self._xsdatas + + @property + def names(self): + return [xsdata.name for xsdata in self.xsdatas] + def add_xsdata(self, xsdata): """Add an XSdata entry to the file. diff --git a/openmc/model/model.py b/openmc/model/model.py index ee7f3647fd5..db0b05e15d9 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -98,22 +98,62 @@ def __init__(self, geometry=None, materials=None, settings=None, def geometry(self) -> Optional[openmc.Geometry]: return self._geometry + @geometry.setter + def geometry(self, geometry): + check_type('geometry', geometry, openmc.Geometry) + self._geometry = geometry + @property def materials(self) -> Optional[openmc.Materials]: return self._materials + @materials.setter + def materials(self, materials): + check_type('materials', materials, Iterable, openmc.Material) + if isinstance(materials, openmc.Materials): + self._materials = materials + else: + del self._materials[:] + for mat in materials: + self._materials.append(mat) + @property def settings(self) -> Optional[openmc.Settings]: return self._settings + @settings.setter + def settings(self, settings): + check_type('settings', settings, openmc.Settings) + self._settings = settings + @property def tallies(self) -> Optional[openmc.Tallies]: return self._tallies + @tallies.setter + def tallies(self, tallies): + check_type('tallies', tallies, Iterable, openmc.Tally) + if isinstance(tallies, openmc.Tallies): + self._tallies = tallies + else: + del self._tallies[:] + for tally in tallies: + self._tallies.append(tally) + @property def plots(self) -> Optional[openmc.Plots]: return self._plots + @plots.setter + def plots(self, plots): + check_type('plots', plots, Iterable, openmc.Plot) + if isinstance(plots, openmc.Plots): + self._plots = plots + else: + del self._plots[:] + for plot in plots: + self._plots.append(plot) + @property def is_initialized(self) -> bool: try: @@ -166,46 +206,6 @@ def _materials_by_name(self) -> Dict[int, openmc.Material]: result[mat.name].add(mat) return result - @geometry.setter - def geometry(self, geometry): - check_type('geometry', geometry, openmc.Geometry) - self._geometry = geometry - - @materials.setter - def materials(self, materials): - check_type('materials', materials, Iterable, openmc.Material) - if isinstance(materials, openmc.Materials): - self._materials = materials - else: - del self._materials[:] - for mat in materials: - self._materials.append(mat) - - @settings.setter - def settings(self, settings): - check_type('settings', settings, openmc.Settings) - self._settings = settings - - @tallies.setter - def tallies(self, tallies): - check_type('tallies', tallies, Iterable, openmc.Tally) - if isinstance(tallies, openmc.Tallies): - self._tallies = tallies - else: - del self._tallies[:] - for tally in tallies: - self._tallies.append(tally) - - @plots.setter - def plots(self, plots): - check_type('plots', plots, Iterable, openmc.Plot) - if isinstance(plots, openmc.Plots): - self._plots = plots - else: - del self._plots[:] - for plot in plots: - self._plots.append(plot) - @classmethod def from_xml(cls, geometry='geometry.xml', materials='materials.xml', settings='settings.xml', tallies='tallies.xml', diff --git a/openmc/model/triso.py b/openmc/model/triso.py index b41ae7fa61b..f344b8edd42 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -138,10 +138,20 @@ def __init__(self, sphere_radius, center=(0., 0., 0.)): def sphere_radius(self): return self._sphere_radius + @sphere_radius.setter + def sphere_radius(self, sphere_radius): + self._sphere_radius = float(sphere_radius) + self._limits = None + self._cell_length = None + @property def center(self): return self._center + @center.setter + def center(self, center): + self._center = center + @abstractproperty def limits(self): pass @@ -154,15 +164,6 @@ def cell_length(self): def volume(self): pass - @sphere_radius.setter - def sphere_radius(self, sphere_radius): - self._sphere_radius = float(sphere_radius) - self._limits = None - self._cell_length = None - - @center.setter - def center(self, center): - self._center = center def mesh_cell(self, p): """Calculate the index of the cell in a mesh overlaid on the domain in @@ -300,14 +301,32 @@ def __init__(self, width, depth, height, sphere_radius, center=(0., 0., 0.)): def width(self): return self._width + @width.setter + def width(self, width): + self._width = float(width) + self._limits = None + self._cell_length = None + @property def depth(self): return self._depth + @depth.setter + def depth(self, depth): + self._depth = float(depth) + self._limits = None + self._cell_length = None + @property def height(self): return self._height + @height.setter + def height(self, height): + self._height = float(height) + self._limits = None + self._cell_length = None + @property def limits(self): if self._limits is None: @@ -316,8 +335,13 @@ def limits(self): x, y, z = self.width/2, self.depth/2, self.height/2 self._limits = [[c[0] - x + r, c[1] - y + r, c[2] - z + r], [c[0] + x - r, c[1] + y - r, c[2] + z - r]] + return self._limits + @limits.setter + def limits(self, limits): + self._limits = limits + @property def cell_length(self): if self._cell_length is None: @@ -330,28 +354,6 @@ def cell_length(self): def volume(self): return self.width*self.depth*self.height - @width.setter - def width(self, width): - self._width = float(width) - self._limits = None - self._cell_length = None - - @depth.setter - def depth(self, depth): - self._depth = float(depth) - self._limits = None - self._cell_length = None - - @height.setter - def height(self, height): - self._height = float(height) - self._limits = None - self._cell_length = None - - @limits.setter - def limits(self, limits): - self._limits = limits - @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -470,14 +472,31 @@ def __init__(self, length, radius, axis, sphere_radius, center=(0., 0., 0.)): def length(self): return self._length + @length.setter + def length(self, length): + self._length = float(length) + self._limits = None + self._cell_length = None + @property def radius(self): return self._radius + @radius.setter + def radius(self, radius): + self._radius = float(radius) + self._limits = None + self._cell_length = None + @property def axis(self): return self._axis + @axis.setter + def axis(self, axis): + self._axis = axis + self._shift = None + @property def shift(self): if self._shift is None: @@ -498,6 +517,10 @@ def limits(self): self._limits = [[z0 - z + r], [z0 + z - r, self.radius - r]] return self._limits + @limits.setter + def limits(self, limits): + self._limits = limits + @property def cell_length(self): if self._cell_length is None: @@ -513,27 +536,6 @@ def cell_length(self): def volume(self): return self.length*pi*self.radius**2 - @length.setter - def length(self, length): - self._length = float(length) - self._limits = None - self._cell_length = None - - @radius.setter - def radius(self, radius): - self._radius = float(radius) - self._limits = None - self._cell_length = None - - @axis.setter - def axis(self, axis): - self._axis = axis - self._shift = None - - @limits.setter - def limits(self, limits): - self._limits = limits - @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) @@ -676,10 +678,21 @@ def __init__(self, radius, inner_radius, sphere_radius, def radius(self): return self._radius + @radius.setter + def radius(self, radius): + self._radius = float(radius) + self._limits = None + self._cell_length = None + @property def inner_radius(self): return self._inner_radius + @inner_radius.setter + def inner_radius(self, inner_radius): + self._inner_radius = float(inner_radius) + self._limits = None + @property def limits(self): if self._limits is None: @@ -691,6 +704,10 @@ def limits(self): self._limits = [[r_min], [r_max]] return self._limits + @limits.setter + def limits(self, limits): + self._limits = limits + @property def cell_length(self): if self._cell_length is None: @@ -703,21 +720,6 @@ def cell_length(self): def volume(self): return _volume_sphere(self.radius) - _volume_sphere(self.inner_radius) - @radius.setter - def radius(self, radius): - self._radius = float(radius) - self._limits = None - self._cell_length = None - - @inner_radius.setter - def inner_radius(self, inner_radius): - self._inner_radius = float(inner_radius) - self._limits = None - - @limits.setter - def limits(self, limits): - self._limits = limits - @classmethod def from_region(self, region, sphere_radius): check_type('region', region, openmc.Region) diff --git a/openmc/plots.py b/openmc/plots.py index 5d8cf9ba40e..5bc8a2e6e8a 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -315,51 +315,15 @@ def __init__(self, plot_id=None, name=''): def name(self): return self._name - @property - def pixels(self): - return self._pixels - - @property - def filename(self): - return self._filename - - @property - def color_by(self): - return self._color_by - - @property - def background(self): - return self._background - - @property - def mask_components(self): - return self._mask_components - - @property - def mask_background(self): - return self._mask_background - - @property - def show_overlaps(self): - return self._show_overlaps - - @property - def overlap_color(self): - return self._overlap_color - - @property - def colors(self): - return self._colors - - @property - def level(self): - return self._level - @name.setter def name(self, name): cv.check_type('plot name', name, str) self._name = name + @property + def pixels(self): + return self._pixels + @pixels.setter def pixels(self, pixels): cv.check_type('plot pixels', pixels, Iterable, Integral) @@ -368,29 +332,36 @@ def pixels(self, pixels): cv.check_greater_than('plot pixels', dim, 0) self._pixels = pixels + @property + def filename(self): + return self._filename + @filename.setter def filename(self, filename): cv.check_type('filename', filename, str) self._filename = filename + @property + def color_by(self): + return self._color_by + @color_by.setter def color_by(self, color_by): cv.check_value('plot color_by', color_by, ['cell', 'material']) self._color_by = color_by + @property + def background(self): + return self._background + @background.setter def background(self, background): self._check_color('plot background', background) self._background = background - @colors.setter - def colors(self, colors): - cv.check_type('plot colors', colors, Mapping) - for key, value in colors.items(): - cv.check_type('plot color key', key, - (openmc.Cell, openmc.Material, Integral)) - self._check_color('plot color value', value) - self._colors = colors + @property + def mask_components(self): + return self._mask_components @mask_components.setter def mask_components(self, mask_components): @@ -398,22 +369,51 @@ def mask_components(self, mask_components): (openmc.Cell, openmc.Material, Integral)) self._mask_components = mask_components + @property + def mask_background(self): + return self._mask_background + @mask_background.setter def mask_background(self, mask_background): self._check_color('plot mask background', mask_background) self._mask_background = mask_background + @property + def show_overlaps(self): + return self._show_overlaps + @show_overlaps.setter def show_overlaps(self, show_overlaps): cv.check_type(f'Show overlaps flag for Plot ID="{self.id}"', show_overlaps, bool) self._show_overlaps = show_overlaps + @property + def overlap_color(self): + return self._overlap_color + @overlap_color.setter def overlap_color(self, overlap_color): self._check_color('plot overlap color', overlap_color) self._overlap_color = overlap_color + @property + def colors(self): + return self._colors + + @colors.setter + def colors(self, colors): + cv.check_type('plot colors', colors, Mapping) + for key, value in colors.items(): + cv.check_type('plot color key', key, + (openmc.Cell, openmc.Material, Integral)) + self._check_color('plot color value', value) + self._colors = colors + + @property + def level(self): + return self._level + @level.setter def level(self, plot_level): cv.check_type('plot level', plot_level, Integral) @@ -584,44 +584,44 @@ def __init__(self, plot_id=None, name=''): def width(self): return self._width - @property - def origin(self): - return self._origin - - @property - def type(self): - return self._type - - @property - def basis(self): - return self._basis - - @property - def meshlines(self): - return self._meshlines - @width.setter def width(self, width): cv.check_type('plot width', width, Iterable, Real) cv.check_length('plot width', width, 2, 3) self._width = width + @property + def origin(self): + return self._origin + @origin.setter def origin(self, origin): cv.check_type('plot origin', origin, Iterable, Real) cv.check_length('plot origin', origin, 3) self._origin = origin + @property + def type(self): + return self._type + @type.setter def type(self, plottype): cv.check_value('plot type', plottype, ['slice', 'voxel']) self._type = plottype + @property + def basis(self): + return self._basis + @basis.setter def basis(self, basis): cv.check_value('plot basis', basis, _BASES) self._basis = basis + @property + def meshlines(self): + return self._meshlines + @meshlines.setter def meshlines(self, meshlines): cv.check_type('plot meshlines', meshlines, dict) @@ -1046,38 +1046,6 @@ def __init__(self, plot_id=None, name=''): def horizontal_field_of_view(self): return self._horizontal_field_of_view - @property - def camera_position(self): - return self._camera_position - - @property - def look_at(self): - return self._look_at - - @property - def up(self): - return self._up - - @property - def orthographic_width(self): - return self._orthographic_width - - @property - def wireframe_thickness(self): - return self._wireframe_thickness - - @property - def wireframe_color(self): - return self._wireframe_color - - @property - def wireframe_domains(self): - return self._wireframe_domains - - @property - def xs(self): - return self._xs - @horizontal_field_of_view.setter def horizontal_field_of_view(self, horizontal_field_of_view): cv.check_type('plot horizontal field of view', horizontal_field_of_view, @@ -1086,30 +1054,50 @@ def horizontal_field_of_view(self, horizontal_field_of_view): assert horizontal_field_of_view < 180.0 self._horizontal_field_of_view = horizontal_field_of_view + @property + def camera_position(self): + return self._camera_position + @camera_position.setter def camera_position(self, camera_position): cv.check_type('plot camera position', camera_position, Iterable, Real) cv.check_length('plot camera position', camera_position, 3) self._camera_position = camera_position + @property + def look_at(self): + return self._look_at + @look_at.setter def look_at(self, look_at): cv.check_type('plot look at', look_at, Iterable, Real) cv.check_length('plot look at', look_at, 3) self._look_at = look_at + @property + def up(self): + return self._up + @up.setter def up(self, up): cv.check_type('plot up', up, Iterable, Real) cv.check_length('plot up', up, 3) self._up = up + @property + def orthographic_width(self): + return self._orthographic_width + @orthographic_width.setter def orthographic_width(self, orthographic_width): cv.check_type('plot orthographic width', orthographic_width, Real) assert orthographic_width >= 0.0 self._orthographic_width = orthographic_width + @property + def wireframe_thickness(self): + return self._wireframe_thickness + @wireframe_thickness.setter def wireframe_thickness(self, wireframe_thickness): cv.check_type('plot wireframe thickness', @@ -1117,11 +1105,19 @@ def wireframe_thickness(self, wireframe_thickness): assert wireframe_thickness >= 0 self._wireframe_thickness = wireframe_thickness + @property + def wireframe_color(self): + return self._wireframe_color + @wireframe_color.setter def wireframe_color(self, wireframe_color): self._check_color('plot wireframe color', wireframe_color) self._wireframe_color = wireframe_color + @property + def wireframe_domains(self): + return self._wireframe_domains + @wireframe_domains.setter def wireframe_domains(self, wireframe_domains): for region in wireframe_domains: @@ -1135,6 +1131,10 @@ def wireframe_domains(self, wireframe_domains): wireframe_region if color_by=cell') self._wireframe_domains = wireframe_domains + @property + def xs(self): + return self._xs + @xs.setter def xs(self, xs): cv.check_type('plot xs', xs, Mapping) diff --git a/openmc/settings.py b/openmc/settings.py index 8b6d5f0fe5d..fbbb0c71993 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -335,213 +335,6 @@ def __init__(self, **kwargs): def run_mode(self) -> str: return self._run_mode.value - @property - def batches(self) -> int: - return self._batches - - @property - def generations_per_batch(self) -> int: - return self._generations_per_batch - - @property - def inactive(self) -> int: - return self._inactive - - @property - def max_lost_particles(self) -> int: - return self._max_lost_particles - - @property - def rel_max_lost_particles(self) -> float: - return self._rel_max_lost_particles - - @property - def particles(self) -> int: - return self._particles - - @property - def keff_trigger(self) -> dict: - return self._keff_trigger - - @property - def energy_mode(self) -> str: - return self._energy_mode - - @property - def max_order(self) -> int: - return self._max_order - - @property - def source(self) -> typing.List[Source]: - return self._source - - @property - def confidence_intervals(self) -> bool: - return self._confidence_intervals - - @property - def electron_treatment(self) -> str: - return self._electron_treatment - - @property - def ptables(self) -> bool: - return self._ptables - - @property - def photon_transport(self) -> bool: - return self._photon_transport - - @property - def seed(self) -> int: - return self._seed - - @property - def survival_biasing(self) -> bool: - return self._survival_biasing - - @property - def entropy_mesh(self) -> RegularMesh: - return self._entropy_mesh - - @property - def trigger_active(self) -> bool: - return self._trigger_active - - @property - def trigger_max_batches(self) -> int: - return self._trigger_max_batches - - @property - def trigger_batch_interval(self) -> int: - return self._trigger_batch_interval - - @property - def output(self) -> dict: - return self._output - - @property - def sourcepoint(self) -> dict: - return self._sourcepoint - - @property - def statepoint(self) -> dict: - return self._statepoint - - @property - def surf_source_read(self) -> dict: - return self._surf_source_read - - @property - def surf_source_write(self) -> dict: - return self._surf_source_write - - @property - def no_reduce(self) -> bool: - return self._no_reduce - - @property - def verbosity(self) -> int: - return self._verbosity - - @property - def tabular_legendre(self) -> dict: - return self._tabular_legendre - - @property - def temperature(self) -> dict: - return self._temperature - - @property - def trace(self) -> typing.Iterable: - return self._trace - - @property - def track(self) -> typing.Iterable[typing.Iterable[int]]: - return self._track - - @property - def cutoff(self) -> dict: - return self._cutoff - - @property - def ufs_mesh(self) -> RegularMesh: - return self._ufs_mesh - - @property - def resonance_scattering(self) -> dict: - return self._resonance_scattering - - @property - def volume_calculations(self) -> typing.List[VolumeCalculation]: - return self._volume_calculations - - @property - def create_fission_neutrons(self) -> bool: - return self._create_fission_neutrons - - @property - def create_delayed_neutrons(self) -> bool: - return self._create_delayed_neutrons - - @property - def delayed_photon_scaling(self) -> bool: - return self._delayed_photon_scaling - - @property - def material_cell_offsets(self) -> bool: - return self._material_cell_offsets - - @property - def log_grid_bins(self) -> int: - return self._log_grid_bins - - @property - def event_based(self) -> bool: - return self._event_based - - @property - def max_particles_in_flight(self) -> int: - return self._max_particles_in_flight - - @property - def write_initial_source(self) -> bool: - return self._write_initial_source - - @property - def weight_windows(self) -> typing.List[WeightWindows]: - return self._weight_windows - - @property - def weight_windows_on(self) -> bool: - return self._weight_windows_on - - @property - def weight_windows_file(self) -> Optional[PathLike]: - return self._weight_windows_file - - @weight_windows_file.setter - def weight_windows_file(self, value: PathLike): - cv.check_type('weight windows file', value, (str, Path)) - self._weight_windows_file = value - - @property - def weight_window_generators(self) -> typing.List[WeightWindowGenerator]: - return self._weight_window_generators - - @weight_window_generators.setter - def weight_window_generators(self, wwgs): - if not isinstance(wwgs, MutableSequence): - wwgs = [wwgs] - self._weight_window_generators = cv.CheckedList(WeightWindowGenerator, 'weight window generators', wwgs) - - @property - def max_splits(self) -> int: - return self._max_splits - - @property - def max_tracks(self) -> int: - return self._max_tracks - @run_mode.setter def run_mode(self, run_mode: str): cv.check_value('run mode', run_mode, {x.value for x in RunMode}) @@ -549,30 +342,50 @@ def run_mode(self, run_mode: str): if mode.value == run_mode: self._run_mode = mode + @property + def batches(self) -> int: + return self._batches + @batches.setter def batches(self, batches: int): cv.check_type('batches', batches, Integral) cv.check_greater_than('batches', batches, 0) self._batches = batches + @property + def generations_per_batch(self) -> int: + return self._generations_per_batch + @generations_per_batch.setter def generations_per_batch(self, generations_per_batch: int): cv.check_type('generations per patch', generations_per_batch, Integral) cv.check_greater_than('generations per batch', generations_per_batch, 0) self._generations_per_batch = generations_per_batch + @property + def inactive(self) -> int: + return self._inactive + @inactive.setter def inactive(self, inactive: int): cv.check_type('inactive batches', inactive, Integral) cv.check_greater_than('inactive batches', inactive, 0, True) self._inactive = inactive + @property + def max_lost_particles(self) -> int: + return self._max_lost_particles + @max_lost_particles.setter def max_lost_particles(self, max_lost_particles: int): cv.check_type('max_lost_particles', max_lost_particles, Integral) cv.check_greater_than('max_lost_particles', max_lost_particles, 0) self._max_lost_particles = max_lost_particles + @property + def rel_max_lost_particles(self) -> float: + return self._rel_max_lost_particles + @rel_max_lost_particles.setter def rel_max_lost_particles(self, rel_max_lost_particles: float): cv.check_type('rel_max_lost_particles', rel_max_lost_particles, Real) @@ -580,12 +393,20 @@ def rel_max_lost_particles(self, rel_max_lost_particles: float): cv.check_less_than('rel_max_lost_particles', rel_max_lost_particles, 1) self._rel_max_lost_particles = rel_max_lost_particles + @property + def particles(self) -> int: + return self._particles + @particles.setter def particles(self, particles: int): cv.check_type('particles', particles, Integral) cv.check_greater_than('particles', particles, 0) self._particles = particles + @property + def keff_trigger(self) -> dict: + return self._keff_trigger + @keff_trigger.setter def keff_trigger(self, keff_trigger: dict): if not isinstance(keff_trigger, dict): @@ -615,12 +436,20 @@ def keff_trigger(self, keff_trigger: dict): self._keff_trigger = keff_trigger + @property + def energy_mode(self) -> str: + return self._energy_mode + @energy_mode.setter def energy_mode(self, energy_mode: str): cv.check_value('energy mode', energy_mode, ['continuous-energy', 'multi-group']) self._energy_mode = energy_mode + @property + def max_order(self) -> int: + return self._max_order + @max_order.setter def max_order(self, max_order: Optional[int]): if max_order is not None: @@ -629,12 +458,113 @@ def max_order(self, max_order: Optional[int]): True) self._max_order = max_order + @property + def source(self) -> typing.List[Source]: + return self._source + @source.setter def source(self, source: typing.Union[Source, typing.Iterable[Source]]): if not isinstance(source, MutableSequence): source = [source] self._source = cv.CheckedList(Source, 'source distributions', source) + @property + def confidence_intervals(self) -> bool: + return self._confidence_intervals + + @confidence_intervals.setter + def confidence_intervals(self, confidence_intervals: bool): + cv.check_type('confidence interval', confidence_intervals, bool) + self._confidence_intervals = confidence_intervals + + @property + def electron_treatment(self) -> str: + return self._electron_treatment + + @electron_treatment.setter + def electron_treatment(self, electron_treatment: str): + cv.check_value('electron treatment', electron_treatment, ['led', 'ttb']) + self._electron_treatment = electron_treatment + + @property + def ptables(self) -> bool: + return self._ptables + + @ptables.setter + def ptables(self, ptables: bool): + cv.check_type('probability tables', ptables, bool) + self._ptables = ptables + + @property + def photon_transport(self) -> bool: + return self._photon_transport + + @photon_transport.setter + def photon_transport(self, photon_transport: bool): + cv.check_type('photon transport', photon_transport, bool) + self._photon_transport = photon_transport + + @property + def seed(self) -> int: + return self._seed + + @seed.setter + def seed(self, seed: int): + cv.check_type('random number generator seed', seed, Integral) + cv.check_greater_than('random number generator seed', seed, 0) + self._seed = seed + + @property + def survival_biasing(self) -> bool: + return self._survival_biasing + + @survival_biasing.setter + def survival_biasing(self, survival_biasing: bool): + cv.check_type('survival biasing', survival_biasing, bool) + self._survival_biasing = survival_biasing + + @property + def entropy_mesh(self) -> RegularMesh: + return self._entropy_mesh + + @entropy_mesh.setter + def entropy_mesh(self, entropy: RegularMesh): + cv.check_type('entropy mesh', entropy, RegularMesh) + self._entropy_mesh = entropy + + @property + def trigger_active(self) -> bool: + return self._trigger_active + + @trigger_active.setter + def trigger_active(self, trigger_active: bool): + cv.check_type('trigger active', trigger_active, bool) + self._trigger_active = trigger_active + + @property + def trigger_max_batches(self) -> int: + return self._trigger_max_batches + + @trigger_max_batches.setter + def trigger_max_batches(self, trigger_max_batches: int): + cv.check_type('trigger maximum batches', trigger_max_batches, Integral) + cv.check_greater_than('trigger maximum batches', trigger_max_batches, 0) + self._trigger_max_batches = trigger_max_batches + + @property + def trigger_batch_interval(self) -> int: + return self._trigger_batch_interval + + @trigger_batch_interval.setter + def trigger_batch_interval(self, trigger_batch_interval: int): + cv.check_type('trigger batch interval', trigger_batch_interval, Integral) + cv.check_greater_than('trigger batch interval', trigger_batch_interval, 0) + self._trigger_batch_interval = trigger_batch_interval + + @property + def output(self) -> dict: + return self._output + @output.setter def output(self, output: dict): cv.check_type('output', output, Mapping) @@ -646,12 +576,9 @@ def output(self, output: dict): cv.check_type("output['path']", value, str) self._output = output - @verbosity.setter - def verbosity(self, verbosity: int): - cv.check_type('verbosity', verbosity, Integral) - cv.check_greater_than('verbosity', verbosity, 1, True) - cv.check_less_than('verbosity', verbosity, 10, True) - self._verbosity = verbosity + @property + def sourcepoint(self) -> dict: + return self._sourcepoint @sourcepoint.setter def sourcepoint(self, sourcepoint: dict): @@ -674,6 +601,10 @@ def sourcepoint(self, sourcepoint: dict): "setting sourcepoint options.") self._sourcepoint = sourcepoint + @property + def statepoint(self) -> dict: + return self._statepoint + @statepoint.setter def statepoint(self, statepoint: dict): cv.check_type('statepoint options', statepoint, Mapping) @@ -687,6 +618,10 @@ def statepoint(self, statepoint: dict): "setting statepoint options.") self._statepoint = statepoint + @property + def surf_source_read(self) -> dict: + return self._surf_source_read + @surf_source_read.setter def surf_source_read(self, surf_source_read: dict): cv.check_type('surface source reading options', surf_source_read, Mapping) @@ -697,6 +632,10 @@ def surf_source_read(self, surf_source_read: dict): cv.check_type('path to surface source file', value, str) self._surf_source_read = surf_source_read + @property + def surf_source_write(self) -> dict: + return self._surf_source_write + @surf_source_write.setter def surf_source_write(self, surf_source_write: dict): cv.check_type('surface source writing options', surf_source_write, Mapping) @@ -719,88 +658,30 @@ def surf_source_write(self, surf_source_write: dict): self._surf_source_write = surf_source_write - @confidence_intervals.setter - def confidence_intervals(self, confidence_intervals: bool): - cv.check_type('confidence interval', confidence_intervals, bool) - self._confidence_intervals = confidence_intervals - - @electron_treatment.setter - def electron_treatment(self, electron_treatment: str): - cv.check_value('electron treatment', electron_treatment, ['led', 'ttb']) - self._electron_treatment = electron_treatment - - @photon_transport.setter - def photon_transport(self, photon_transport: bool): - cv.check_type('photon transport', photon_transport, bool) - self._photon_transport = photon_transport - - @ptables.setter - def ptables(self, ptables: bool): - cv.check_type('probability tables', ptables, bool) - self._ptables = ptables - - @seed.setter - def seed(self, seed: int): - cv.check_type('random number generator seed', seed, Integral) - cv.check_greater_than('random number generator seed', seed, 0) - self._seed = seed - - @survival_biasing.setter - def survival_biasing(self, survival_biasing: bool): - cv.check_type('survival biasing', survival_biasing, bool) - self._survival_biasing = survival_biasing - - @cutoff.setter - def cutoff(self, cutoff: dict): - if not isinstance(cutoff, Mapping): - msg = f'Unable to set cutoff from "{cutoff}" which is not a '\ - 'Python dictionary' - raise ValueError(msg) - for key in cutoff: - if key == 'weight': - cv.check_type('weight cutoff', cutoff[key], Real) - cv.check_greater_than('weight cutoff', cutoff[key], 0.0) - elif key == 'weight_avg': - cv.check_type('average survival weight', cutoff[key], Real) - cv.check_greater_than('average survival weight', - cutoff[key], 0.0) - elif key in ['energy_neutron', 'energy_photon', 'energy_electron', - 'energy_positron']: - cv.check_type('energy cutoff', cutoff[key], Real) - cv.check_greater_than('energy cutoff', cutoff[key], 0.0) - else: - msg = f'Unable to set cutoff to "{key}" which is unsupported ' \ - 'by OpenMC' - - self._cutoff = cutoff - - @entropy_mesh.setter - def entropy_mesh(self, entropy: RegularMesh): - cv.check_type('entropy mesh', entropy, RegularMesh) - self._entropy_mesh = entropy - - @trigger_active.setter - def trigger_active(self, trigger_active: bool): - cv.check_type('trigger active', trigger_active, bool) - self._trigger_active = trigger_active - - @trigger_max_batches.setter - def trigger_max_batches(self, trigger_max_batches: int): - cv.check_type('trigger maximum batches', trigger_max_batches, Integral) - cv.check_greater_than('trigger maximum batches', trigger_max_batches, 0) - self._trigger_max_batches = trigger_max_batches - - @trigger_batch_interval.setter - def trigger_batch_interval(self, trigger_batch_interval: int): - cv.check_type('trigger batch interval', trigger_batch_interval, Integral) - cv.check_greater_than('trigger batch interval', trigger_batch_interval, 0) - self._trigger_batch_interval = trigger_batch_interval + @property + def no_reduce(self) -> bool: + return self._no_reduce @no_reduce.setter def no_reduce(self, no_reduce: bool): cv.check_type('no reduction option', no_reduce, bool) self._no_reduce = no_reduce + @property + def verbosity(self) -> int: + return self._verbosity + + @verbosity.setter + def verbosity(self, verbosity: int): + cv.check_type('verbosity', verbosity, Integral) + cv.check_greater_than('verbosity', verbosity, 1, True) + cv.check_less_than('verbosity', verbosity, 10, True) + self._verbosity = verbosity + + @property + def tabular_legendre(self) -> dict: + return self._tabular_legendre + @tabular_legendre.setter def tabular_legendre(self, tabular_legendre: dict): cv.check_type('tabular_legendre settings', tabular_legendre, Mapping) @@ -814,6 +695,10 @@ def tabular_legendre(self, tabular_legendre: dict): cv.check_greater_than('num_points tabular_legendre', value, 0) self._tabular_legendre = tabular_legendre + @property + def temperature(self) -> dict: + return self._temperature + @temperature.setter def temperature(self, temperature: dict): @@ -838,6 +723,10 @@ def temperature(self, temperature: dict): self._temperature = temperature + @property + def trace(self) -> typing.Iterable: + return self._trace + @trace.setter def trace(self, trace: Iterable): cv.check_type('trace', trace, Iterable, Integral) @@ -847,6 +736,10 @@ def trace(self, trace: Iterable): cv.check_greater_than('trace particle', trace[2], 0) self._trace = trace + @property + def track(self) -> typing.Iterable[typing.Iterable[int]]: + return self._track + @track.setter def track(self, track: typing.Iterable[typing.Iterable[int]]): cv.check_type('track', track, Iterable) @@ -862,6 +755,38 @@ def track(self, track: typing.Iterable[typing.Iterable[int]]): cv.check_type('track particle', t[2], Integral) self._track = track + @property + def cutoff(self) -> dict: + return self._cutoff + + @cutoff.setter + def cutoff(self, cutoff: dict): + if not isinstance(cutoff, Mapping): + msg = f'Unable to set cutoff from "{cutoff}" which is not a '\ + 'Python dictionary' + raise ValueError(msg) + for key in cutoff: + if key == 'weight': + cv.check_type('weight cutoff', cutoff[key], Real) + cv.check_greater_than('weight cutoff', cutoff[key], 0.0) + elif key == 'weight_avg': + cv.check_type('average survival weight', cutoff[key], Real) + cv.check_greater_than('average survival weight', + cutoff[key], 0.0) + elif key in ['energy_neutron', 'energy_photon', 'energy_electron', + 'energy_positron']: + cv.check_type('energy cutoff', cutoff[key], Real) + cv.check_greater_than('energy cutoff', cutoff[key], 0.0) + else: + msg = f'Unable to set cutoff to "{key}" which is unsupported ' \ + 'by OpenMC' + + self._cutoff = cutoff + + @property + def ufs_mesh(self) -> RegularMesh: + return self._ufs_mesh + @ufs_mesh.setter def ufs_mesh(self, ufs_mesh: RegularMesh): cv.check_type('UFS mesh', ufs_mesh, RegularMesh) @@ -870,6 +795,10 @@ def ufs_mesh(self, ufs_mesh: RegularMesh): cv.check_length('UFS mesh upper-right corner', ufs_mesh.upper_right, 3) self._ufs_mesh = ufs_mesh + @property + def resonance_scattering(self) -> dict: + return self._resonance_scattering + @resonance_scattering.setter def resonance_scattering(self, res: dict): cv.check_type('resonance scattering settings', res, Mapping) @@ -894,6 +823,10 @@ def resonance_scattering(self, res: dict): Iterable, str) self._resonance_scattering = res + @property + def volume_calculations(self) -> typing.List[VolumeCalculation]: + return self._volume_calculations + @volume_calculations.setter def volume_calculations( self, vol_calcs: typing.Union[VolumeCalculation, typing.Iterable[VolumeCalculation]] @@ -903,73 +836,140 @@ def volume_calculations( self._volume_calculations = cv.CheckedList( VolumeCalculation, 'stochastic volume calculations', vol_calcs) + @property + def create_fission_neutrons(self) -> bool: + return self._create_fission_neutrons + @create_fission_neutrons.setter def create_fission_neutrons(self, create_fission_neutrons: bool): cv.check_type('Whether create fission neutrons', create_fission_neutrons, bool) self._create_fission_neutrons = create_fission_neutrons + @property + def create_delayed_neutrons(self) -> bool: + return self._create_delayed_neutrons + @create_delayed_neutrons.setter def create_delayed_neutrons(self, create_delayed_neutrons: bool): cv.check_type('Whether create only prompt neutrons', create_delayed_neutrons, bool) self._create_delayed_neutrons = create_delayed_neutrons + @property + def delayed_photon_scaling(self) -> bool: + return self._delayed_photon_scaling + @delayed_photon_scaling.setter def delayed_photon_scaling(self, value: bool): cv.check_type('delayed photon scaling', value, bool) self._delayed_photon_scaling = value - @event_based.setter - def event_based(self, value: bool): - cv.check_type('event based', value, bool) - self._event_based = value - - @max_particles_in_flight.setter - def max_particles_in_flight(self, value: int): - cv.check_type('max particles in flight', value, Integral) - cv.check_greater_than('max particles in flight', value, 0) - self._max_particles_in_flight = value + @property + def material_cell_offsets(self) -> bool: + return self._material_cell_offsets @material_cell_offsets.setter def material_cell_offsets(self, value: bool): cv.check_type('material cell offsets', value, bool) self._material_cell_offsets = value + @property + def log_grid_bins(self) -> int: + return self._log_grid_bins + @log_grid_bins.setter def log_grid_bins(self, log_grid_bins: int): cv.check_type('log grid bins', log_grid_bins, Real) cv.check_greater_than('log grid bins', log_grid_bins, 0) self._log_grid_bins = log_grid_bins + @property + def event_based(self) -> bool: + return self._event_based + + @event_based.setter + def event_based(self, value: bool): + cv.check_type('event based', value, bool) + self._event_based = value + + @property + def max_particles_in_flight(self) -> int: + return self._max_particles_in_flight + + @max_particles_in_flight.setter + def max_particles_in_flight(self, value: int): + cv.check_type('max particles in flight', value, Integral) + cv.check_greater_than('max particles in flight', value, 0) + self._max_particles_in_flight = value + + @property + def write_initial_source(self) -> bool: + return self._write_initial_source + @write_initial_source.setter def write_initial_source(self, value: bool): cv.check_type('write initial source', value, bool) self._write_initial_source = value + @property + def weight_windows(self) -> typing.List[WeightWindows]: + return self._weight_windows + @weight_windows.setter def weight_windows(self, value: typing.Union[WeightWindows, typing.Iterable[WeightWindows]]): if not isinstance(value, MutableSequence): value = [value] self._weight_windows = cv.CheckedList(WeightWindows, 'weight windows', value) + @property + def weight_windows_on(self) -> bool: + return self._weight_windows_on + @weight_windows_on.setter def weight_windows_on(self, value: bool): cv.check_type('weight windows on', value, bool) self._weight_windows_on = value + @property + def max_splits(self) -> int: + return self._max_splits + @max_splits.setter def max_splits(self, value: int): cv.check_type('maximum particle splits', value, Integral) cv.check_greater_than('max particle splits', value, 0) self._max_splits = value + @property + def max_tracks(self) -> int: + return self._max_tracks + @max_tracks.setter def max_tracks(self, value: int): cv.check_type('maximum particle tracks', value, Integral) cv.check_greater_than('maximum particle tracks', value, 0, True) self._max_tracks = value + @property + def weight_windows_file(self) -> Optional[PathLike]: + return self._weight_windows_file + + @weight_windows_file.setter + def weight_windows_file(self, value: PathLike): + cv.check_type('weight windows file', value, (str, Path)) + self._weight_windows_file = value + + @property + def weight_window_generators(self) -> typing.List[WeightWindowGenerator]: + return self._weight_window_generators + + @weight_window_generators.setter + def weight_window_generators(self, wwgs): + if not isinstance(wwgs, MutableSequence): + wwgs = [wwgs] + self._weight_window_generators = cv.CheckedList(WeightWindowGenerator, 'weight window generators', wwgs) + def _create_run_mode_subelement(self, root): elem = ET.SubElement(root, "run_mode") elem.text = self._run_mode.value diff --git a/openmc/source.py b/openmc/source.py index cc68c9535b1..150830cc829 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -127,102 +127,102 @@ def __init__( def file(self): return self._file - @property - def library(self): - return self._library - - @property - def parameters(self): - return self._parameters - - @property - def space(self): - return self._space - - @property - def angle(self): - return self._angle - - @property - def energy(self): - return self._energy - - @property - def time(self): - return self._time - - @property - def strength(self): - return self._strength - - @property - def particle(self): - return self._particle - - @property - def domain_ids(self): - return self._domain_ids - - @property - def domain_type(self): - return self._domain_type - - @domain_ids.setter - def domain_ids(self, ids): - cv.check_type('domain IDs', ids, Iterable, Real) - self._domain_ids = ids - - @domain_type.setter - def domain_type(self, domain_type): - cv.check_value('domain type', domain_type, ('cell', 'material', 'universe')) - self._domain_type = domain_type - @file.setter def file(self, filename): cv.check_type('source file', filename, str) self._file = filename + @property + def library(self): + return self._library + @library.setter def library(self, library_name): cv.check_type('library', library_name, str) self._library = library_name + @property + def parameters(self): + return self._parameters + @parameters.setter def parameters(self, parameters_path): cv.check_type('parameters', parameters_path, str) self._parameters = parameters_path + @property + def space(self): + return self._space + @space.setter def space(self, space): cv.check_type('spatial distribution', space, Spatial) self._space = space + @property + def angle(self): + return self._angle + @angle.setter def angle(self, angle): cv.check_type('angular distribution', angle, UnitSphere) self._angle = angle + @property + def energy(self): + return self._energy + @energy.setter def energy(self, energy): cv.check_type('energy distribution', energy, Univariate) self._energy = energy + @property + def time(self): + return self._time + @time.setter def time(self, time): cv.check_type('time distribution', time, Univariate) self._time = time + @property + def strength(self): + return self._strength + @strength.setter def strength(self, strength): cv.check_type('source strength', strength, Real) cv.check_greater_than('source strength', strength, 0.0, True) self._strength = strength + @property + def particle(self): + return self._particle + @particle.setter def particle(self, particle): cv.check_value('source particle', particle, ['neutron', 'photon']) self._particle = particle + @property + def domain_ids(self): + return self._domain_ids + + @domain_ids.setter + def domain_ids(self, ids): + cv.check_type('domain IDs', ids, Iterable, Real) + self._domain_ids = ids + + @property + def domain_type(self): + return self._domain_type + + @domain_type.setter + def domain_type(self, domain_type): + cv.check_value('domain type', domain_type, ('cell', 'material', 'universe')) + self._domain_type = domain_type + def to_xml_element(self) -> ET.Element: """Return XML representation of the source diff --git a/openmc/statepoint.py b/openmc/statepoint.py index 7c1ecd13773..f6df01bd4f1 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -367,6 +367,26 @@ def source_present(self): def sparse(self): return self._sparse + @sparse.setter + def sparse(self, sparse): + """Convert tally data from NumPy arrays to SciPy list of lists (LIL) + sparse matrices, and vice versa. + + This property may be used to reduce the amount of data in memory during + tally data processing. The tally data will be stored as SciPy LIL + matrices internally within each Tally object. All tally data access + properties and methods will return data as a dense NumPy array. + + """ + + cv.check_type('sparse', sparse, bool) + self._sparse = sparse + + # Update tally sparsities + if self._tallies_read: + for tally_id in self.tallies: + self.tallies[tally_id].sparse = self.sparse + @property def tallies(self): if self.tallies_present and not self._tallies_read: @@ -484,26 +504,6 @@ def version(self): def summary(self): return self._summary - @sparse.setter - def sparse(self, sparse): - """Convert tally data from NumPy arrays to SciPy list of lists (LIL) - sparse matrices, and vice versa. - - This property may be used to reduce the amount of data in memory during - tally data processing. The tally data will be stored as SciPy LIL - matrices internally within each Tally object. All tally data access - properties and methods will return data as a dense NumPy array. - - """ - - cv.check_type('sparse', sparse, bool) - self._sparse = sparse - - # Update tally sparsities - if self._tallies_read: - for tally_id in self.tallies: - self.tallies[tally_id].sparse = self.sparse - def close(self): """Close the statepoint HDF5 file and the corresponding summary HDF5 file if present. diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index 190dfd64d00..058bee7da69 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -102,15 +102,15 @@ def __init__(self, mu=None, phi=None, reference_uvw=(0., 0., 1.)): def mu(self): return self._mu - @property - def phi(self): - return self._phi - @mu.setter def mu(self, mu): cv.check_type('cosine of polar angle', mu, Univariate) self._mu = mu + @property + def phi(self): + return self._phi + @phi.setter def phi(self, phi): cv.check_type('azimuthal angle', phi, Univariate) @@ -313,24 +313,24 @@ def __init__(self, x, y, z): def x(self): return self._x - @property - def y(self): - return self._y - - @property - def z(self): - return self._z - @x.setter def x(self, x): cv.check_type('x coordinate', x, Univariate) self._x = x + @property + def y(self): + return self._y + @y.setter def y(self, y): cv.check_type('y coordinate', y, Univariate) self._y = y + @property + def z(self): + return self._z + @z.setter def z(self, z): cv.check_type('z coordinate', z, Univariate) @@ -426,33 +426,33 @@ def __init__(self, r, cos_theta, phi, origin=(0.0, 0.0, 0.0)): def r(self): return self._r - @property - def cos_theta(self): - return self._cos_theta - - @property - def phi(self): - return self._phi - - @property - def origin(self): - return self._origin - @r.setter def r(self, r): cv.check_type('r coordinate', r, Univariate) self._r = r + @property + def cos_theta(self): + return self._cos_theta + @cos_theta.setter def cos_theta(self, cos_theta): cv.check_type('cos_theta coordinate', cos_theta, Univariate) self._cos_theta = cos_theta + @property + def phi(self): + return self._phi + @phi.setter def phi(self, phi): cv.check_type('phi coordinate', phi, Univariate) self._phi = phi + @property + def origin(self): + return self._origin + @origin.setter def origin(self, origin): cv.check_type('origin coordinates', origin, Iterable, Real) @@ -548,33 +548,33 @@ def __init__(self, r, phi, z, origin=(0.0, 0.0, 0.0)): def r(self): return self._r - @property - def phi(self): - return self._phi - - @property - def z(self): - return self._z - - @property - def origin(self): - return self._origin - @r.setter def r(self, r): cv.check_type('r coordinate', r, Univariate) self._r = r + @property + def phi(self): + return self._phi + @phi.setter def phi(self, phi): cv.check_type('phi coordinate', phi, Univariate) self._phi = phi + @property + def z(self): + return self._z + @z.setter def z(self, z): cv.check_type('z coordinate', z, Univariate) self._z = z + @property + def origin(self): + return self._origin + @origin.setter def origin(self, origin): cv.check_type('origin coordinates', origin, Iterable, Real) @@ -781,26 +781,26 @@ def __init__(self, lower_left, upper_right, only_fissionable=False): def lower_left(self): return self._lower_left - @property - def upper_right(self): - return self._upper_right - - @property - def only_fissionable(self): - return self._only_fissionable - @lower_left.setter def lower_left(self, lower_left): cv.check_type('lower left coordinate', lower_left, Iterable, Real) cv.check_length('lower left coordinate', lower_left, 3) self._lower_left = lower_left + @property + def upper_right(self): + return self._upper_right + @upper_right.setter def upper_right(self, upper_right): cv.check_type('upper right coordinate', upper_right, Iterable, Real) cv.check_length('upper right coordinate', upper_right, 3) self._upper_right = upper_right + @property + def only_fissionable(self): + return self._only_fissionable + @only_fissionable.setter def only_fissionable(self, only_fissionable): cv.check_type('only fissionable', only_fissionable, bool) diff --git a/openmc/stats/univariate.py b/openmc/stats/univariate.py index b98b87d6f42..5625d26acb9 100644 --- a/openmc/stats/univariate.py +++ b/openmc/stats/univariate.py @@ -130,10 +130,6 @@ def __len__(self): def x(self): return self._x - @property - def p(self): - return self._p - @x.setter def x(self, x): if isinstance(x, Real): @@ -141,6 +137,10 @@ def x(self, x): cv.check_type('discrete values', x, Iterable, Real) self._x = np.array(x, dtype=float) + @property + def p(self): + return self._p + @p.setter def p(self, p): if isinstance(p, Real): @@ -282,15 +282,15 @@ def __len__(self): def a(self): return self._a - @property - def b(self): - return self._b - @a.setter def a(self, a): cv.check_type('Uniform a', a, Real) self._a = a + @property + def b(self): + return self._b + @b.setter def b(self, b): cv.check_type('Uniform b', b, Real) @@ -384,24 +384,24 @@ def __len__(self): def a(self): return self._a - @property - def b(self): - return self._b - - @property - def n(self): - return self._n - @a.setter def a(self, a): cv.check_type('interval lower bound', a, Real) self._a = a + @property + def b(self): + return self._b + @b.setter def b(self, b): cv.check_type('interval upper bound', b, Real) self._b = b + @property + def n(self): + return self._n + @n.setter def n(self, n): cv.check_type('power law exponent', n, Real) @@ -570,16 +570,16 @@ def __len__(self): def a(self): return self._a - @property - def b(self): - return self._b - @a.setter def a(self, a): cv.check_type('Watt a', a, Real) cv.check_greater_than('Watt a', a, 0.0) self._a = a + @property + def b(self): + return self._b + @b.setter def b(self, b): cv.check_type('Watt b', b, Real) @@ -664,15 +664,15 @@ def __len__(self): def mean_value(self): return self._mean_value - @property - def std_dev(self): - return self._std_dev - @mean_value.setter def mean_value(self, mean_value): cv.check_type('Normal mean_value', mean_value, Real) self._mean_value = mean_value + @property + def std_dev(self): + return self._std_dev + @std_dev.setter def std_dev(self, std_dev): cv.check_type('Normal std_dev', std_dev, Real) @@ -807,19 +807,15 @@ def __len__(self): def x(self): return self._x - @property - def p(self): - return self._p - - @property - def interpolation(self): - return self._interpolation - @x.setter def x(self, x): cv.check_type('tabulated values', x, Iterable, Real) self._x = np.array(x, dtype=float) + @property + def p(self): + return self._p + @p.setter def p(self, p): cv.check_type('tabulated probabilities', p, Iterable, Real) @@ -828,6 +824,10 @@ def p(self, p): cv.check_greater_than('tabulated probability', pk, 0.0, True) self._p = np.array(p, dtype=float) + @property + def interpolation(self): + return self._interpolation + @interpolation.setter def interpolation(self, interpolation): cv.check_value('interpolation', interpolation, _INTERPOLATION_SCHEMES) @@ -1093,10 +1093,6 @@ def __len__(self): def probability(self): return self._probability - @property - def distribution(self): - return self._distribution - @probability.setter def probability(self, probability): cv.check_type('mixture distribution probabilities', probability, @@ -1106,6 +1102,10 @@ def probability(self, probability): p, 0.0, True) self._probability = probability + @property + def distribution(self): + return self._distribution + @distribution.setter def distribution(self, distribution): cv.check_type('mixture distribution components', distribution, diff --git a/openmc/surface.py b/openmc/surface.py index b195c0af2b8..1f35e7bff49 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -185,18 +185,6 @@ def __repr__(self): def name(self): return self._name - @property - def type(self): - return self._type - - @property - def boundary_type(self): - return self._boundary_type - - @property - def coefficients(self): - return self._coefficients - @name.setter def name(self, name): if name is not None: @@ -205,12 +193,24 @@ def name(self, name): else: self._name = '' + @property + def type(self): + return self._type + + @property + def boundary_type(self): + return self._boundary_type + @boundary_type.setter def boundary_type(self, boundary_type): check_type('boundary type', boundary_type, str) check_value('boundary type', boundary_type, _BOUNDARY_TYPES) self._boundary_type = boundary_type + @property + def coefficients(self): + return self._coefficients + def bounding_box(self, side): """Determine an axis-aligned bounding box. diff --git a/openmc/tallies.py b/openmc/tallies.py index 6f56fbb64dd..5de00f43c3b 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -150,18 +150,61 @@ def __repr__(self): def name(self): return self._name + @name.setter + def name(self, name): + cv.check_type('tally name', name, str, none_ok=True) + self._name = name + @property def multiply_density(self): return self._multiply_density + @multiply_density.setter + def multiply_density(self, value): + cv.check_type('multiply density', value, bool) + self._multiply_density = value + @property def filters(self): return self._filters + @filters.setter + def filters(self, filters): + cv.check_type('tally filters', filters, MutableSequence) + + # If the filter is already in the Tally, raise an error + visited_filters = set() + for f in filters: + if f in visited_filters: + msg = (f'Unable to add a duplicate filter "{f}" to Tally ' + f'ID="{self.id}" since duplicate filters are not ' + 'supported in the OpenMC Python API') + raise ValueError(msg) + visited_filters.add(f) + + self._filters = cv.CheckedList(_FILTER_CLASSES, 'tally filters', filters) + @property def nuclides(self): return self._nuclides + @nuclides.setter + def nuclides(self, nuclides): + cv.check_type('tally nuclides', nuclides, MutableSequence) + + # If the nuclide is already in the Tally, raise an error + visited_nuclides = set() + for nuc in nuclides: + if nuc in visited_nuclides: + msg = (f'Unable to add a duplicate nuclide "{nuc}" to Tally ID=' + f'"{self.id}" since duplicate nuclides are not supported ' + 'in the OpenMC Python API') + raise ValueError(msg) + visited_nuclides.add(nuc) + + self._nuclides = cv.CheckedList(_NUCLIDE_CLASSES, 'tally nuclides', + nuclides) + @property def num_nuclides(self): return len(self._nuclides) @@ -170,6 +213,33 @@ def num_nuclides(self): def scores(self): return self._scores + @scores.setter + def scores(self, scores): + cv.check_type('tally scores', scores, MutableSequence) + + visited_scores = set() + for i, score in enumerate(scores): + # If the score is already in the Tally, raise an error + if score in visited_scores: + msg = (f'Unable to add a duplicate score "{score}" to Tally ' + f'ID="{self.id}" since duplicate scores are not ' + 'supported in the OpenMC Python API') + raise ValueError(msg) + visited_scores.add(score) + + # If score is a string, strip whitespace + if isinstance(score, str): + # Check to see if scores are deprecated before storing + for deprecated in ['scatter-', 'nu-scatter-', 'scatter-p', + 'nu-scatter-p', 'scatter-y', 'nu-scatter-y', + 'flux-y', 'total-y']: + if score.strip().startswith(deprecated): + msg = score.strip() + ' is no longer supported.' + raise ValueError(msg) + scores[i] = score.strip() + + self._scores = cv.CheckedList(_SCORE_CLASSES, 'tally scores', scores) + @property def num_scores(self): return len(self._scores) @@ -194,18 +264,40 @@ def shape(self): def estimator(self): return self._estimator + @estimator.setter + def estimator(self, estimator): + cv.check_value('estimator', estimator, ESTIMATOR_TYPES) + self._estimator = estimator + @property def triggers(self): return self._triggers + @triggers.setter + def triggers(self, triggers): + cv.check_type('tally triggers', triggers, MutableSequence) + self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers', + triggers) + @property def num_realizations(self): return self._num_realizations + @num_realizations.setter + def num_realizations(self, num_realizations): + cv.check_type('number of realizations', num_realizations, Integral) + cv.check_greater_than('number of realizations', num_realizations, 0, True) + self._num_realizations = num_realizations + @property def with_summary(self): return self._with_summary + @with_summary.setter + def with_summary(self, with_summary): + cv.check_type('with_summary', with_summary, bool) + self._with_summary = with_summary + def _read_results(self): if self._results_read: return @@ -246,6 +338,11 @@ def sum(self): else: return self._sum + @sum.setter + def sum(self, sum): + cv.check_type('sum', sum, Iterable) + self._sum = sum + @property def sum_sq(self): if not self._sp_filename or self.derived: @@ -259,6 +356,11 @@ def sum_sq(self): else: return self._sum_sq + @sum_sq.setter + def sum_sq(self, sum_sq): + cv.check_type('sum_sq', sum_sq, Iterable) + self._sum_sq = sum_sq + @property def mean(self): if self._mean is None: @@ -305,6 +407,11 @@ def std_dev(self): def with_batch_statistics(self): return self._with_batch_statistics + @with_batch_statistics.setter + def with_batch_statistics(self, with_batch_statistics): + cv.check_type('with_batch_statistics', with_batch_statistics, bool) + self._with_batch_statistics = with_batch_statistics + @property def derived(self): return self._derived @@ -313,122 +420,15 @@ def derived(self): def derivative(self): return self._derivative - @property - def sparse(self): - return self._sparse - - @estimator.setter - def estimator(self, estimator): - cv.check_value('estimator', estimator, ESTIMATOR_TYPES) - self._estimator = estimator - - @triggers.setter - def triggers(self, triggers): - cv.check_type('tally triggers', triggers, MutableSequence) - self._triggers = cv.CheckedList(openmc.Trigger, 'tally triggers', - triggers) - - @name.setter - def name(self, name): - cv.check_type('tally name', name, str, none_ok=True) - self._name = name - - @multiply_density.setter - def multiply_density(self, value): - cv.check_type('multiply density', value, bool) - self._multiply_density = value - @derivative.setter def derivative(self, deriv): cv.check_type('tally derivative', deriv, openmc.TallyDerivative, none_ok=True) self._derivative = deriv - @filters.setter - def filters(self, filters): - cv.check_type('tally filters', filters, MutableSequence) - - # If the filter is already in the Tally, raise an error - visited_filters = set() - for f in filters: - if f in visited_filters: - msg = (f'Unable to add a duplicate filter "{f}" to Tally ' - f'ID="{self.id}" since duplicate filters are not ' - 'supported in the OpenMC Python API') - raise ValueError(msg) - visited_filters.add(f) - - self._filters = cv.CheckedList(_FILTER_CLASSES, 'tally filters', filters) - - @nuclides.setter - def nuclides(self, nuclides): - cv.check_type('tally nuclides', nuclides, MutableSequence) - - # If the nuclide is already in the Tally, raise an error - visited_nuclides = set() - for nuc in nuclides: - if nuc in visited_nuclides: - msg = (f'Unable to add a duplicate nuclide "{nuc}" to Tally ID=' - f'"{self.id}" since duplicate nuclides are not supported ' - 'in the OpenMC Python API') - raise ValueError(msg) - visited_nuclides.add(nuc) - - self._nuclides = cv.CheckedList(_NUCLIDE_CLASSES, 'tally nuclides', - nuclides) - - @scores.setter - def scores(self, scores): - cv.check_type('tally scores', scores, MutableSequence) - - visited_scores = set() - for i, score in enumerate(scores): - # If the score is already in the Tally, raise an error - if score in visited_scores: - msg = (f'Unable to add a duplicate score "{score}" to Tally ' - f'ID="{self.id}" since duplicate scores are not ' - 'supported in the OpenMC Python API') - raise ValueError(msg) - visited_scores.add(score) - - # If score is a string, strip whitespace - if isinstance(score, str): - # Check to see if scores are deprecated before storing - for deprecated in ['scatter-', 'nu-scatter-', 'scatter-p', - 'nu-scatter-p', 'scatter-y', 'nu-scatter-y', - 'flux-y', 'total-y']: - if score.strip().startswith(deprecated): - msg = score.strip() + ' is no longer supported.' - raise ValueError(msg) - scores[i] = score.strip() - - self._scores = cv.CheckedList(_SCORE_CLASSES, 'tally scores', scores) - - @num_realizations.setter - def num_realizations(self, num_realizations): - cv.check_type('number of realizations', num_realizations, Integral) - cv.check_greater_than('number of realizations', num_realizations, 0, True) - self._num_realizations = num_realizations - - @with_summary.setter - def with_summary(self, with_summary): - cv.check_type('with_summary', with_summary, bool) - self._with_summary = with_summary - - @with_batch_statistics.setter - def with_batch_statistics(self, with_batch_statistics): - cv.check_type('with_batch_statistics', with_batch_statistics, bool) - self._with_batch_statistics = with_batch_statistics - - @sum.setter - def sum(self, sum): - cv.check_type('sum', sum, Iterable) - self._sum = sum - - @sum_sq.setter - def sum_sq(self, sum_sq): - cv.check_type('sum_sq', sum_sq, Iterable) - self._sum_sq = sum_sq + @property + def sparse(self): + return self._sparse @sparse.setter def sparse(self, sparse): diff --git a/openmc/tally_derivative.py b/openmc/tally_derivative.py index d8e165e8bea..779ca619f2a 100644 --- a/openmc/tally_derivative.py +++ b/openmc/tally_derivative.py @@ -60,14 +60,6 @@ def __repr__(self): def variable(self): return self._variable - @property - def material(self): - return self._material - - @property - def nuclide(self): - return self._nuclide - @variable.setter def variable(self, var): if var is not None: @@ -76,12 +68,20 @@ def variable(self, var): ('density', 'nuclide_density', 'temperature')) self._variable = var + @property + def material(self): + return self._material + @material.setter def material(self, mat): if mat is not None: cv.check_type('derivative material', mat, Integral) self._material = mat + @property + def nuclide(self): + return self._nuclide + @nuclide.setter def nuclide(self, nuc): if nuc is not None: diff --git a/openmc/trigger.py b/openmc/trigger.py index 3f7d8d7d075..86d17dfefd0 100644 --- a/openmc/trigger.py +++ b/openmc/trigger.py @@ -45,25 +45,25 @@ def __repr__(self): def trigger_type(self): return self._trigger_type - @property - def threshold(self): - return self._threshold - - @property - def scores(self): - return self._scores - @trigger_type.setter def trigger_type(self, trigger_type): cv.check_value('tally trigger type', trigger_type, ['variance', 'std_dev', 'rel_err']) self._trigger_type = trigger_type + @property + def threshold(self): + return self._threshold + @threshold.setter def threshold(self, threshold): cv.check_type('tally trigger threshold', threshold, Real) self._threshold = threshold + @property + def scores(self): + return self._scores + @scores.setter def scores(self, scores): cv.check_type('trigger scores', scores, Iterable, str) diff --git a/openmc/universe.py b/openmc/universe.py index 458729d5cf1..6acecf8006a 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -58,10 +58,6 @@ def __repr__(self): def name(self): return self._name - @property - def volume(self): - return self._volume - @name.setter def name(self, name): if name is not None: @@ -70,6 +66,10 @@ def name(self, name): else: self._name = '' + @property + def volume(self): + return self._volume + @volume.setter def volume(self, volume): if volume is not None: @@ -854,6 +854,11 @@ def auto_geom_ids(self, val): def auto_mat_ids(self): return self._auto_mat_ids + @auto_mat_ids.setter + def auto_mat_ids(self, val): + cv.check_type('DAGMC automatic material ids', val, bool) + self._auto_mat_ids = val + @property def material_names(self): dagmc_file_contents = h5py.File(self.filename) @@ -870,11 +875,6 @@ def material_names(self): return sorted(set(material_tags_ascii)) - @auto_mat_ids.setter - def auto_mat_ids(self, val): - cv.check_type('DAGMC automatic material ids', val, bool) - self._auto_mat_ids = val - def get_all_cells(self, memo=None): return OrderedDict() diff --git a/openmc/volume.py b/openmc/volume.py index 363b108c9f2..72fe89fbc4a 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -126,63 +126,25 @@ def __init__(self, domains, samples, lower_left=None, upper_right=None): def ids(self): return self._ids - @property - def samples(self): - return self._samples - - @property - def lower_left(self): - return self._lower_left - - @property - def upper_right(self): - return self._upper_right - - @property - def threshold(self): - return self._threshold - - @property - def trigger_type(self): - return self._trigger_type - - @property - def iterations(self): - return self._iterations - - @property - def domain_type(self): - return self._domain_type - - @property - def atoms(self): - return self._atoms - - @property - def volumes(self): - return self._volumes - - @property - def atoms_dataframe(self): - items = [] - columns = [self.domain_type.capitalize(), 'Nuclide', 'Atoms'] - for uid, atoms_dict in self.atoms.items(): - for name, atoms in atoms_dict.items(): - items.append((uid, name, atoms)) - - return pd.DataFrame.from_records(items, columns=columns) - @ids.setter def ids(self, ids): cv.check_type('domain IDs', ids, Iterable, Real) self._ids = ids + @property + def samples(self): + return self._samples + @samples.setter def samples(self, samples): cv.check_type('number of samples', samples, Integral) cv.check_greater_than('number of samples', samples, 0) self._samples = samples + @property + def lower_left(self): + return self._lower_left + @lower_left.setter def lower_left(self, lower_left): name = 'lower-left bounding box coordinates', @@ -190,6 +152,10 @@ def lower_left(self, lower_left): cv.check_length(name, lower_left, 3) self._lower_left = lower_left + @property + def upper_right(self): + return self._upper_right + @upper_right.setter def upper_right(self, upper_right): name = 'upper-right bounding box coordinates' @@ -197,6 +163,10 @@ def upper_right(self, upper_right): cv.check_length(name, upper_right, 3) self._upper_right = upper_right + @property + def threshold(self): + return self._threshold + @threshold.setter def threshold(self, threshold): name = 'volume std. dev. threshold' @@ -204,12 +174,20 @@ def threshold(self, threshold): cv.check_greater_than(name, threshold, 0.0) self._threshold = threshold + @property + def trigger_type(self): + return self._trigger_type + @trigger_type.setter def trigger_type(self, trigger_type): cv.check_value('tally trigger type', trigger_type, ('variance', 'std_dev', 'rel_err')) self._trigger_type = trigger_type + @property + def iterations(self): + return self._iterations + @iterations.setter def iterations(self, iterations): name = 'volume calculation iterations' @@ -217,16 +195,38 @@ def iterations(self, iterations): cv.check_greater_than(name, iterations, 0) self._iterations = iterations - @volumes.setter - def volumes(self, volumes): - cv.check_type('volumes', volumes, Mapping) - self._volumes = volumes + @property + def domain_type(self): + return self._domain_type + + @property + def atoms(self): + return self._atoms @atoms.setter def atoms(self, atoms): cv.check_type('atoms', atoms, Mapping) self._atoms = atoms + @property + def volumes(self): + return self._volumes + + @volumes.setter + def volumes(self, volumes): + cv.check_type('volumes', volumes, Mapping) + self._volumes = volumes + + @property + def atoms_dataframe(self): + items = [] + columns = [self.domain_type.capitalize(), 'Nuclide', 'Atoms'] + for uid, atoms_dict in self.atoms.items(): + for name, atoms in atoms_dict.items(): + items.append((uid, name, atoms)) + + return pd.DataFrame.from_records(items, columns=columns) + def set_trigger(self, threshold, trigger_type): """Set a trigger on the volume calculation From eda39ad9cae067f735e27a8918cffbeb299f7884 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 20 Jun 2023 21:27:55 -0500 Subject: [PATCH 32/45] Python source class refactor (#2524) Co-authored-by: Paul Romano --- docs/source/io_formats/settings.rst | 31 +- examples/assembly/assembly.py | 2 +- examples/custom_source/build_xml.py | 2 +- .../parameterized_custom_source/build_xml.py | 2 +- include/openmc/source.h | 14 +- openmc/examples.py | 8 +- openmc/settings.py | 20 +- openmc/source.py | 419 +- src/settings.cpp | 2 +- src/source.cpp | 14 +- .../adj_cell_rotation/inputs_true.dat | 2 +- .../adj_cell_rotation/test.py | 2 +- .../asymmetric_lattice/inputs_true.dat | 2 +- .../asymmetric_lattice/test.py | 2 +- .../create_fission_neutrons/inputs_true.dat | 2 +- .../create_fission_neutrons/test.py | 4 +- .../dagmc/external/inputs_true.dat | 2 +- tests/regression_tests/dagmc/external/test.py | 2 +- .../dagmc/legacy/inputs_true.dat | 2 +- tests/regression_tests/dagmc/legacy/test.py | 2 +- .../dagmc/refl/inputs_true.dat | 2 +- tests/regression_tests/dagmc/refl/test.py | 4 +- .../dagmc/uwuw/inputs_true.dat | 2 +- tests/regression_tests/dagmc/uwuw/test.py | 4 +- .../deplete_with_transport/test.py | 2 +- .../diff_tally/inputs_true.dat | 2 +- tests/regression_tests/diff_tally/test.py | 2 +- .../distribmat/inputs_true.dat | 2 +- tests/regression_tests/distribmat/test.py | 2 +- .../eigenvalue_genperbatch/inputs_true.dat | 2 +- .../eigenvalue_genperbatch/test.py | 2 +- .../energy_cutoff/inputs_true.dat | 2 +- tests/regression_tests/energy_cutoff/test.py | 4 +- .../external_moab/inputs_true.dat | 2 +- tests/regression_tests/external_moab/test.py | 2 +- .../filter_cellinstance/inputs_true.dat | 2 +- .../filter_cellinstance/test.py | 2 +- .../fixed_source/inputs_true.dat | 2 +- tests/regression_tests/fixed_source/test.py | 4 +- .../iso_in_lab/inputs_true.dat | 2 +- .../lattice_hex_coincident/inputs_true.dat | 2 +- .../lattice_hex_coincident/test.py | 2 +- .../lattice_hex_x/inputs_true.dat | 2 +- tests/regression_tests/lattice_hex_x/test.py | 2 +- .../lattice_rotated/inputs_true.dat | 2 +- .../regression_tests/lattice_rotated/test.py | 2 +- .../regression_tests/mg_basic/inputs_true.dat | 2 +- .../mg_basic_delayed/inputs_true.dat | 2 +- .../mg_convert/inputs_true.dat | 2 +- tests/regression_tests/mg_convert/test.py | 2 +- .../mg_legendre/inputs_true.dat | 2 +- .../mg_max_order/inputs_true.dat | 2 +- .../mg_survival_biasing/inputs_true.dat | 2 +- .../mg_tallies/inputs_true.dat | 2 +- .../mg_temperature/build_2g.py | 2 +- .../mgxs_library_ce_to_mg/inputs_true.dat | 2 +- .../inputs_true.dat | 2 +- .../mgxs_library_condense/inputs_true.dat | 2 +- .../mgxs_library_correction/inputs_true.dat | 2 +- .../mgxs_library_distribcell/inputs_true.dat | 2 +- .../mgxs_library_hdf5/inputs_true.dat | 2 +- .../mgxs_library_histogram/inputs_true.dat | 2 +- .../mgxs_library_no_nuclides/inputs_true.dat | 2 +- .../mgxs_library_nuclides/inputs_true.dat | 2 +- .../inputs_true.dat | 2 +- .../adj_cell_rotation_inputs_true.dat | 2 +- .../photon_production_inputs_true.dat | 2 +- .../multipole/inputs_true.dat | 2 +- tests/regression_tests/multipole/test.py | 2 +- .../regression_tests/ncrystal/inputs_true.dat | 2 +- tests/regression_tests/ncrystal/test.py | 2 +- .../regression_tests/periodic/inputs_true.dat | 2 +- tests/regression_tests/periodic/test.py | 2 +- .../periodic_6fold/inputs_true.dat | 2 +- tests/regression_tests/periodic_6fold/test.py | 2 +- .../photon_production/inputs_true.dat | 2 +- .../photon_production/test.py | 2 +- .../photon_production_fission/inputs_true.dat | 2 +- .../photon_production_fission/test.py | 2 +- .../photon_source/inputs_true.dat | 2 +- tests/regression_tests/photon_source/test.py | 2 +- .../resonance_scattering/inputs_true.dat | 2 +- .../resonance_scattering/test.py | 2 +- .../salphabeta/inputs_true.dat | 2 +- tests/regression_tests/salphabeta/test.py | 2 +- tests/regression_tests/source/inputs_true.dat | 16 +- tests/regression_tests/source/test.py | 16 +- .../source_dlopen/inputs_true.dat | 16 +- .../source_dlopen/results_true.dat | 5 + .../source_dlopen/source_sampling.cpp | 14 +- tests/regression_tests/source_dlopen/test.py | 12 +- .../inputs_true.dat | 16 +- .../results_true.dat | 5 + .../source_parameterized_dlopen/test.py | 11 +- .../surface_source/inputs_true_write.dat | 2 +- tests/regression_tests/surface_source/test.py | 2 +- .../surface_tally/inputs_true.dat | 2 +- tests/regression_tests/surface_tally/test.py | 2 +- .../regression_tests/tallies/inputs_true.dat | 2 +- tests/regression_tests/tallies/test.py | 2 +- .../tally_slice_merge/inputs_true.dat | 2 +- .../torus/large_major/inputs_true.dat | 2 +- .../torus/large_major/test.py | 2 +- tests/regression_tests/triso/inputs_true.dat | 2 +- tests/regression_tests/triso/test.py | 2 +- .../unstructured_mesh/inputs_true.dat | 2 +- .../unstructured_mesh/inputs_true0.dat | 2 +- .../unstructured_mesh/inputs_true1.dat | 2 +- .../unstructured_mesh/inputs_true10.dat | 2 +- .../unstructured_mesh/inputs_true11.dat | 2 +- .../unstructured_mesh/inputs_true12.dat | 2 +- .../unstructured_mesh/inputs_true13.dat | 2 +- .../unstructured_mesh/inputs_true14.dat | 2 +- .../unstructured_mesh/inputs_true15.dat | 2 +- .../unstructured_mesh/inputs_true2.dat | 2 +- .../unstructured_mesh/inputs_true3.dat | 2 +- .../unstructured_mesh/inputs_true8.dat | 2 +- .../unstructured_mesh/inputs_true9.dat | 2 +- .../unstructured_mesh/results_true.dat | 4002 ----------------- .../unstructured_mesh/test.py | 14 +- tests/regression_tests/void/inputs_true.dat | 2 +- tests/regression_tests/void/test.py | 2 +- .../weightwindows/inputs_true.dat | 2 +- tests/regression_tests/weightwindows/test.py | 2 +- tests/unit_tests/conftest.py | 2 +- tests/unit_tests/dagmc/test.py | 2 +- tests/unit_tests/mesh_to_vtk/test_vtk_dims.py | 2 +- tests/unit_tests/test_complex_cell_bb.py | 2 +- tests/unit_tests/test_cylindrical_mesh.py | 6 +- tests/unit_tests/test_data_thermal.py | 2 +- tests/unit_tests/test_deplete_activation.py | 2 +- tests/unit_tests/test_energy_cutoff.py | 2 +- tests/unit_tests/test_filters.py | 2 +- tests/unit_tests/test_geometry.py | 2 +- tests/unit_tests/test_lib.py | 4 +- tests/unit_tests/test_model.py | 2 +- tests/unit_tests/test_settings.py | 4 +- tests/unit_tests/test_source.py | 39 +- tests/unit_tests/test_source_file.py | 4 +- tests/unit_tests/test_source_mesh.py | 6 +- tests/unit_tests/test_spherical_mesh.py | 6 +- tests/unit_tests/test_time_filter.py | 6 +- tests/unit_tests/test_torus.py | 2 +- tests/unit_tests/test_tracks.py | 2 +- tests/unit_tests/test_urr_capture.py | 2 +- tests/unit_tests/weightwindows/test.py | 2 +- 146 files changed, 649 insertions(+), 4311 deletions(-) delete mode 100644 tests/regression_tests/unstructured_mesh/results_true.dat diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index 2a85ebc8ac8..1016fbaa3d7 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -449,24 +449,27 @@ attributes/sub-elements: *Default*: 1.0 + :type: + Indicator of source type. One of ``independent``, ``file``, or ``compiled``. + :particle: The source particle type, either ``neutron`` or ``photon``. *Default*: neutron :file: - If this attribute is given, it indicates that the source is to be read from - a binary source file whose path is given by the value of this element. Note, - the number of source sites needs to be the same as the number of particles - simulated in a fission source generation. + If this attribute is given, it indicates that the source type is ``file``, + meaning particles are to be read from a binary source file whose path is + given by the value of this element. *Default*: None :library: - If this attribute is given, it indicates that the source is to be - instantiated from an externally compiled source function. This source can be - as complex as is required to define the source for your problem. The library - has a few basic requirements: + If this attribute is given, it indicates that the source type is + ``compiled``, meaning that particles are instantiated from an externally + compiled source function. This source can be completely customized as needed + to define the source for your problem. The library has a few basic + requirements: * It must contain a class that inherits from ``openmc::Source``; * The class must implement a function called ``sample()``; @@ -476,14 +479,12 @@ attributes/sub-elements: More documentation on how to build sources can be found in :ref:`custom_source`. - *Default*: None - :parameters: - If this attribute is given, it provides the parameters to pass through to the - class generated using the ``library`` parameter . More documentation on how to - build parametrized sources can be found in :ref:`parameterized_custom_source`. - - *Default*: None + If this attribute is given, it indicated that the source type is + ``compiled``. Its value provides the parameters to pass through to the class + generated using the ``library`` parameter. More documentation on how to + build parametrized sources can be found in + :ref:`parameterized_custom_source`. :space: An element specifying the spatial distribution of source sites. This element diff --git a/examples/assembly/assembly.py b/examples/assembly/assembly.py index ec1bb7e9f79..1355374f128 100644 --- a/examples/assembly/assembly.py +++ b/examples/assembly/assembly.py @@ -112,7 +112,7 @@ def assembly_model(): model.settings.batches = 150 model.settings.inactive = 50 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( (-pitch/2, -pitch/2, -1), (pitch/2, pitch/2, 1), only_fissionable=True diff --git a/examples/custom_source/build_xml.py b/examples/custom_source/build_xml.py index a0817d4223f..e9a9a065687 100644 --- a/examples/custom_source/build_xml.py +++ b/examples/custom_source/build_xml.py @@ -18,7 +18,7 @@ settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.Source() +source = openmc.IndependentSource() source.library = 'build/libsource.so' settings.source = source settings.export_to_xml() diff --git a/examples/parameterized_custom_source/build_xml.py b/examples/parameterized_custom_source/build_xml.py index 5edb204df21..3c67e244dc4 100644 --- a/examples/parameterized_custom_source/build_xml.py +++ b/examples/parameterized_custom_source/build_xml.py @@ -18,7 +18,7 @@ settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.Source() +source = openmc.IndependentSource() source.library = 'build/libparameterized_source.so' source.parameters = 'radius=3.0, energy=14.08e6' settings.source = source diff --git a/include/openmc/source.h b/include/openmc/source.h index 96d659dcb35..ad2aae562bb 100644 --- a/include/openmc/source.h +++ b/include/openmc/source.h @@ -115,26 +115,26 @@ class FileSource : public Source { //! Wrapper for custom sources that manages opening/closing shared library //============================================================================== -class CustomSourceWrapper : public Source { +class CompiledSourceWrapper : public Source { public: // Constructors, destructors - CustomSourceWrapper(std::string path, std::string parameters); - ~CustomSourceWrapper(); + CompiledSourceWrapper(std::string path, std::string parameters); + ~CompiledSourceWrapper(); // Defer implementation to custom source library SourceSite sample(uint64_t* seed) const override { - return custom_source_->sample(seed); + return compiled_source_->sample(seed); } - double strength() const override { return custom_source_->strength(); } + double strength() const override { return compiled_source_->strength(); } private: void* shared_library_; //!< library from dlopen - unique_ptr custom_source_; + unique_ptr compiled_source_; }; -typedef unique_ptr create_custom_source_t(std::string parameters); +typedef unique_ptr create_compiled_source_t(std::string parameters); //============================================================================== // Functions diff --git a/openmc/examples.py b/openmc/examples.py index 3b73d043ffc..cef86a47a87 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -76,7 +76,7 @@ def pwr_pin_cell(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1], only_fissionable=True)) plot = openmc.Plot.from_geometry(model.geometry) @@ -415,7 +415,7 @@ def pwr_core(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) plot = openmc.Plot() @@ -527,7 +527,7 @@ def pwr_assembly(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-pitch/2, -pitch/2, -1], [pitch/2, pitch/2, 1], only_fissionable=True)) plot = openmc.Plot() @@ -629,7 +629,7 @@ def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5'): 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.source = openmc.IndependentSource(space=uniform_dist) settings_file.output = {'summary': False} diff --git a/openmc/settings.py b/openmc/settings.py index fbbb0c71993..7937cd2e7a3 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -13,8 +13,8 @@ import openmc.checkvalue as cv from openmc.stats.multivariate import MeshSpatial -from . import (RegularMesh, Source, VolumeCalculation, WeightWindows, - WeightWindowGenerator) +from . import (RegularMesh, SourceBase, IndependentSource, + VolumeCalculation, WeightWindows, WeightWindowGenerator) from ._xml import clean_indentation, get_text, reorder_attributes from openmc.checkvalue import PathLike from .mesh import _read_meshes @@ -150,7 +150,7 @@ class Settings: The type of calculation to perform (default is 'eigenvalue') seed : int Seed for the linear congruential pseudorandom number generator - source : Iterable of openmc.Source + source : Iterable of openmc.SourceBase Distribution of source sites in space, angle, and energy sourcepoint : dict Options for writing source points. Acceptable keys are: @@ -265,7 +265,7 @@ def __init__(self, **kwargs): self._max_order = None # Source subelement - self._source = cv.CheckedList(Source, 'source distributions') + self._source = cv.CheckedList(SourceBase, 'source distributions') self._confidence_intervals = None self._electron_treatment = None @@ -459,14 +459,14 @@ def max_order(self, max_order: Optional[int]): self._max_order = max_order @property - def source(self) -> typing.List[Source]: + def source(self) -> typing.List[SourceBase]: return self._source @source.setter - def source(self, source: typing.Union[Source, typing.Iterable[Source]]): + def source(self, source: typing.Union[SourceBase, typing.Iterable[SourceBase]]): if not isinstance(source, MutableSequence): source = [source] - self._source = cv.CheckedList(Source, 'source distributions', source) + self._source = cv.CheckedList(SourceBase, 'source distributions', source) @property def confidence_intervals(self) -> bool: @@ -969,7 +969,7 @@ def weight_window_generators(self, wwgs): if not isinstance(wwgs, MutableSequence): wwgs = [wwgs] self._weight_window_generators = cv.CheckedList(WeightWindowGenerator, 'weight window generators', wwgs) - + def _create_run_mode_subelement(self, root): elem = ET.SubElement(root, "run_mode") elem.text = self._run_mode.value @@ -1024,7 +1024,7 @@ def _create_max_order_subelement(self, root): def _create_source_subelement(self, root): for source in self.source: root.append(source.to_xml_element()) - if isinstance(source.space, MeshSpatial): + if isinstance(source, IndependentSource) and isinstance(source.space, MeshSpatial): path = f"./mesh[@id='{source.space.mesh.id}']" if root.find(path) is None: root.append(source.space.mesh.to_xml_element()) @@ -1402,7 +1402,7 @@ def _keff_trigger_from_xml_element(self, root): def _source_from_xml_element(self, root, meshes=None): for elem in root.findall('source'): - src = Source.from_xml_element(elem, meshes) + src = SourceBase.from_xml_element(elem, meshes) # add newly constructed source object to the list self.source.append(src) diff --git a/openmc/source.py b/openmc/source.py index 150830cc829..0e17938a81d 100644 --- a/openmc/source.py +++ b/openmc/source.py @@ -1,3 +1,5 @@ +from __future__ import annotations +from abc import ABC, abstractmethod from collections.abc import Iterable from enum import IntEnum from numbers import Real @@ -16,9 +18,107 @@ from openmc.stats.multivariate import UnitSphere, Spatial from openmc.stats.univariate import Univariate from ._xml import get_text +from .mesh import MeshBase -class Source: +class SourceBase(ABC): + """Base class for external sources + + Parameters + ---------- + strength : float + Strength of the source + + Attributes + ---------- + type : {'independent', 'file', 'compiled'} + Indicator of source type. + strength : float + Strength of the source + + """ + + def __init__(self, strength=1.0): + self.strength = strength + + @property + def strength(self): + return self._strength + + @strength.setter + def strength(self, strength): + cv.check_type('source strength', strength, Real) + cv.check_greater_than('source strength', strength, 0.0, True) + self._strength = strength + + @abstractmethod + def populate_xml_element(self, element): + """Add necessary source information to an XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing source data + + """ + pass + + def to_xml_element(self) -> ET.Element: + """Return XML representation of the source + + Returns + ------- + element : xml.etree.ElementTree.Element + XML element containing source data + + """ + element = ET.Element("source") + element.set("type", self.type) + element.set("strength", str(self.strength)) + self.populate_xml_element(element) + return element + + @classmethod + def from_xml_element(cls, elem: ET.Element, meshes=None) -> openmc.SourceBase: + """Generate source from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + Dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.SourceBase + Source generated from XML element + + """ + source_type = get_text(elem, 'type') + + if source_type is None: + # attempt to determine source type based on attributes + # for backward compatibility + if get_text(elem, 'file') is not None: + return FileSource.from_xml_element(elem) + elif get_text(elem, 'library') is not None: + return CompiledSource.from_xml_element(elem) + else: + return IndependentSource.from_xml_element(elem) + else: + if source_type == 'independent': + return IndependentSource.from_xml_element(elem, meshes) + elif source_type == 'compiled': + return CompiledSource.from_xml_element(elem) + elif source_type == 'file': + return FileSource.from_xml_element(elem) + else: + raise ValueError(f'Source type {source_type} is not recognized') + + +class IndependentSource(SourceBase): """Distribution of phase space coordinates for source sites. Parameters @@ -31,14 +131,6 @@ class Source: Energy distribution of source sites time : openmc.stats.Univariate time distribution of source sites - filename : str - Source file from which sites should be sampled - library : str - Path to a custom source library - parameters : str - Parameters to be provided to the custom source library - - .. versionadded:: 0.12 strength : float Strength of the source particle : {'neutron', 'photon'} @@ -57,14 +149,13 @@ class Source: Energy distribution of source sites time : openmc.stats.Univariate or None time distribution of source sites - file : str or None - Source file from which sites should be sampled - library : str or None - Path to a custom source library - parameters : str - Parameters to be provided to the custom source library strength : float Strength of the source + type : str + Indicator of source type: 'independent' + + .. versionadded:: 0.13.4 + particle : {'neutron', 'photon'} Source particle type ids : Iterable of int @@ -80,20 +171,16 @@ def __init__( angle: Optional[openmc.stats.UnitSphere] = None, energy: Optional[openmc.stats.Univariate] = None, time: Optional[openmc.stats.Univariate] = None, - filename: Optional[str] = None, - library: Optional[str] = None, - parameters: Optional[str] = None, strength: float = 1.0, particle: str = 'neutron', domains: Optional[Sequence[typing.Union[openmc.Cell, openmc.Material, openmc.Universe]]] = None ): + super().__init__(strength) + self._space = None self._angle = None self._energy = None self._time = None - self._file = None - self._library = None - self._parameters = None if space is not None: self.space = space @@ -103,12 +190,6 @@ def __init__( self.energy = energy if time is not None: self.time = time - if filename is not None: - self.file = filename - if library is not None: - self.library = library - if parameters is not None: - self.parameters = parameters self.strength = strength self.particle = particle @@ -124,31 +205,25 @@ def __init__( self.domain_ids = [d.id for d in domains] @property - def file(self): - return self._file - - @file.setter - def file(self, filename): - cv.check_type('source file', filename, str) - self._file = filename - - @property - def library(self): - return self._library - - @library.setter - def library(self, library_name): - cv.check_type('library', library_name, str) - self._library = library_name - - @property - def parameters(self): - return self._parameters + def type(self) -> str: + return 'independent' + + def __getattr__(self, name): + cls_names = {'file': 'FileSource', 'library': 'CompiledSource', + 'parameters': 'CompiledSource'} + if name in cls_names: + raise AttributeError( + f'The "{name}" attribute has been deprecated on the ' + f'IndependentSource class. Please use the {cls_names[name]} class.') + else: + super().__getattribute__(name) - @parameters.setter - def parameters(self, parameters_path): - cv.check_type('parameters', parameters_path, str) - self._parameters = parameters_path + def __setattr__(self, name, value): + if name in ('file', 'library', 'parameters'): + # Ensure proper AttributeError is thrown + getattr(self, name) + else: + super().__setattr__(name, value) @property def space(self): @@ -186,16 +261,6 @@ def time(self, time): cv.check_type('time distribution', time, Univariate) self._time = time - @property - def strength(self): - return self._strength - - @strength.setter - def strength(self, strength): - cv.check_type('source strength', strength, Real) - cv.check_greater_than('source strength', strength, 0.0, True) - self._strength = strength - @property def particle(self): return self._particle @@ -223,25 +288,16 @@ def domain_type(self, domain_type): cv.check_value('domain type', domain_type, ('cell', 'material', 'universe')) self._domain_type = domain_type - def to_xml_element(self) -> ET.Element: - """Return XML representation of the source - + def populate_xml_element(self, element): + """Add necessary source information to an XML element Returns ------- element : lxml.etree._Element XML element containing source data """ - element = ET.Element("source") - element.set("strength", str(self.strength)) - if self.particle != 'neutron': - element.set("particle", self.particle) - if self.file is not None: - element.set("file", self.file) - if self.library is not None: - element.set("library", self.library) - if self.parameters is not None: - element.set("parameters", self.parameters) + super().populate_xml_element(element) + element.set("particle", self.particle) if self.space is not None: element.append(self.space.to_xml_element()) if self.angle is not None: @@ -255,10 +311,9 @@ def to_xml_element(self) -> ET.Element: dt_elem.text = self.domain_type id_elem = ET.SubElement(element, "domain_ids") id_elem.text = ' '.join(str(uid) for uid in self.domain_ids) - return element @classmethod - def from_xml_element(cls, elem: ET.Element, meshes=None) -> 'openmc.Source': + def from_xml_element(cls, elem: ET.Element, meshes=None) -> 'openmc.SourceBase': """Generate source from an XML element Parameters @@ -306,14 +361,6 @@ def from_xml_element(cls, elem: ET.Element, meshes=None) -> 'openmc.Source': if filename is not None: source.file = filename - library = get_text(elem, 'library') - if library is not None: - source.library = library - - parameters = get_text(elem, 'parameters') - if parameters is not None: - source.parameters = parameters - space = elem.find('space') if space is not None: source.space = Spatial.from_xml_element(space, meshes) @@ -333,6 +380,210 @@ def from_xml_element(cls, elem: ET.Element, meshes=None) -> 'openmc.Source': return source +def Source(*args, **kwargs): + """ + A function for backward compatibility of sources. Will be removed in the + future. Please update to IndependentSource. + """ + warnings.warn("This class is deprecated in favor of 'IndependentSource'", FutureWarning) + return openmc.IndependentSource(*args, **kwargs) + + +class CompiledSource(SourceBase): + """A source based on a compiled shared library + + .. versionadded:: 0.13.4 + + Parameters + ---------- + library : str or None + Path to a compiled shared library + parameters : str + Parameters to be provided to the compiled shared library function + strength : float + Strength of the source + + Attributes + ---------- + library : str or None + Path to a compiled shared library + parameters : str + Parameters to be provided to the compiled shared library function + strength : float + Strength of the source + type : str + Indicator of source type: 'compiled' + + """ + def __init__(self, library: Optional[str] = None, parameters: Optional[str] = None, strength=1.0) -> None: + super().__init__(strength=strength) + + self._library = None + if library is not None: + self.library = library + + self._parameters = None + if parameters is not None: + self.parameters = parameters + + @property + def type(self) -> str: + return "compiled" + + @property + def library(self) -> str: + return self._library + + @library.setter + def library(self, library_name): + cv.check_type('library', library_name, str) + self._library = library_name + + @property + def parameters(self) -> str: + return self._parameters + + @parameters.setter + def parameters(self, parameters_path): + cv.check_type('parameters', parameters_path, str) + self._parameters = parameters_path + + def populate_xml_element(self, element): + """Add necessary compiled source information to an XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing source data + + """ + super().populate_xml_element(element) + + element.set("library", self.library) + + if self.parameters is not None: + element.set("parameters", self.parameters) + + @classmethod + def from_xml_element(cls, elem: ET.Element, meshes=None) -> openmc.CompiledSource: + """Generate a compiled source from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + Dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.CompiledSource + Source generated from XML element + + """ + library = get_text(elem, 'library') + + source = cls(library) + + strength = get_text(elem, 'strength') + if strength is not None: + source.strength = float(strength) + + parameters = get_text(elem, 'parameters') + if parameters is not None: + source.parameters = parameters + + return source + + +class FileSource(SourceBase): + """A source based on particles stored in a file + + .. versionadded:: 0.13.4 + + Parameters + ---------- + path : str or pathlib.Path + Path to the source file from which sites should be sampled + strength : float + Strength of the source (default is 1.0) + + Attributes + ---------- + path : Pathlike + Source file from which sites should be sampled + strength : float + Strength of the source + type : str + Indicator of source type: 'file' + + """ + def __init__(self, path: Optional[PathLike] = None, strength=1.0) -> None: + super().__init__(strength=strength) + + self._path = None + + if path is not None: + self.path = path + + @property + def type(self) -> str: + return "file" + + @property + def path(self) -> PathLike: + return self._path + + @path.setter + def path(self, p: PathLike): + cv.check_type('source file', p, str) + self._path = p + + def populate_xml_element(self, element): + """Add necessary file source information to an XML element + + Returns + ------- + element : lxml.etree._Element + XML element containing source data + + """ + super().populate_xml_element(element) + + if self.path is not None: + element.set("file", self.path) + + @classmethod + def from_xml_element(cls, elem: ET.Element) -> openmc.FileSource: + """Generate file source from an XML element + + Parameters + ---------- + elem : lxml.etree._Element + XML element + meshes : dict + Dictionary with mesh IDs as keys and openmc.MeshBase instances as + values + + Returns + ------- + openmc.FileSource + Source generated from XML element + + """ + + filename = get_text(elem, 'file') + + source = cls(filename) + + strength = get_text(elem, 'strength') + if strength is not None: + source.strength = float(strength) + + return source + + class ParticleType(IntEnum): """ IntEnum class representing a particle type. Type diff --git a/src/settings.cpp b/src/settings.cpp index e16afbedc2a..1c039e9ba90 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -458,7 +458,7 @@ void read_settings_xml(pugi::xml_node root) // Create custom source model::external_sources.push_back( - make_unique(path, parameters)); + make_unique(path, parameters)); } else { model::external_sources.push_back(make_unique(node)); } diff --git a/src/source.cpp b/src/source.cpp index 163c8567666..817847b7618 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -326,10 +326,10 @@ SourceSite FileSource::sample(uint64_t* seed) const } //============================================================================== -// CustomSourceWrapper implementation +// CompiledSourceWrapper implementation //============================================================================== -CustomSourceWrapper::CustomSourceWrapper( +CompiledSourceWrapper::CompiledSourceWrapper( std::string path, std::string parameters) { #ifdef HAS_DYNAMIC_LINKING @@ -343,7 +343,7 @@ CustomSourceWrapper::CustomSourceWrapper( dlerror(); // get the function to create the custom source from the library - auto create_custom_source = reinterpret_cast( + auto create_compiled_source = reinterpret_cast( dlsym(shared_library_, "openmc_create_source")); // check for any dlsym errors @@ -356,7 +356,7 @@ CustomSourceWrapper::CustomSourceWrapper( } // create a pointer to an instance of the custom source - custom_source_ = create_custom_source(parameters); + compiled_source_ = create_compiled_source(parameters); #else fatal_error("Custom source libraries have not yet been implemented for " @@ -364,11 +364,11 @@ CustomSourceWrapper::CustomSourceWrapper( #endif } -CustomSourceWrapper::~CustomSourceWrapper() +CompiledSourceWrapper::~CompiledSourceWrapper() { // Make sure custom source is cleared before closing shared library - if (custom_source_.get()) - custom_source_.reset(); + if (compiled_source_.get()) + compiled_source_.reset(); #ifdef HAS_DYNAMIC_LINKING dlclose(shared_library_); diff --git a/tests/regression_tests/adj_cell_rotation/inputs_true.dat b/tests/regression_tests/adj_cell_rotation/inputs_true.dat index 48774bb020f..7e2a0cf628f 100644 --- a/tests/regression_tests/adj_cell_rotation/inputs_true.dat +++ b/tests/regression_tests/adj_cell_rotation/inputs_true.dat @@ -29,7 +29,7 @@ 10000 10 5 - + -4.0 -4.0 -4.0 4.0 4.0 4.0 diff --git a/tests/regression_tests/adj_cell_rotation/test.py b/tests/regression_tests/adj_cell_rotation/test.py index 25aada5aada..9b867c18e1d 100644 --- a/tests/regression_tests/adj_cell_rotation/test.py +++ b/tests/regression_tests/adj_cell_rotation/test.py @@ -40,7 +40,7 @@ def model(): model.settings.inactive = 5 model.settings.batches = 10 source_box = openmc.stats.Box((-4., -4., -4.), (4., 4., 4.)) - model.settings.source = openmc.Source(space=source_box) + model.settings.source = openmc.IndependentSource(space=source_box) return model diff --git a/tests/regression_tests/asymmetric_lattice/inputs_true.dat b/tests/regression_tests/asymmetric_lattice/inputs_true.dat index 6a09b10a321..3977220da61 100644 --- a/tests/regression_tests/asymmetric_lattice/inputs_true.dat +++ b/tests/regression_tests/asymmetric_lattice/inputs_true.dat @@ -208,7 +208,7 @@ 100 10 5 - + -32 -32 0 32 32 32 diff --git a/tests/regression_tests/asymmetric_lattice/test.py b/tests/regression_tests/asymmetric_lattice/test.py index 2197a1e7e2c..0d17a6c98eb 100644 --- a/tests/regression_tests/asymmetric_lattice/test.py +++ b/tests/regression_tests/asymmetric_lattice/test.py @@ -54,7 +54,7 @@ def __init__(self, *args, **kwargs): self._model.tallies.append(tally) # Specify summary output and correct source sampling box - self._model.settings.source = openmc.Source(space=openmc.stats.Box( + self._model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-32, -32, 0], [32, 32, 32], only_fissionable = True)) def _get_results(self, hash_output=True): diff --git a/tests/regression_tests/create_fission_neutrons/inputs_true.dat b/tests/regression_tests/create_fission_neutrons/inputs_true.dat index 8ee6f8b64f7..9e44a022497 100644 --- a/tests/regression_tests/create_fission_neutrons/inputs_true.dat +++ b/tests/regression_tests/create_fission_neutrons/inputs_true.dat @@ -20,7 +20,7 @@ fixed source 100 10 - + -1 -1 -1 1 1 1 diff --git a/tests/regression_tests/create_fission_neutrons/test.py b/tests/regression_tests/create_fission_neutrons/test.py index 82bfaafa64a..0ca4a48b292 100755 --- a/tests/regression_tests/create_fission_neutrons/test.py +++ b/tests/regression_tests/create_fission_neutrons/test.py @@ -38,8 +38,8 @@ def __init__(self, *args, **kwargs): bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) watt_dist = openmc.stats.Watt() - settings_file.source = openmc.source.Source(space=uniform_dist, - energy=watt_dist) + settings_file.source = openmc.IndependentSource(space=uniform_dist, + energy=watt_dist) self._model.settings = settings_file # Create tallies diff --git a/tests/regression_tests/dagmc/external/inputs_true.dat b/tests/regression_tests/dagmc/external/inputs_true.dat index 7237f4d4632..31f4c1f886d 100644 --- a/tests/regression_tests/dagmc/external/inputs_true.dat +++ b/tests/regression_tests/dagmc/external/inputs_true.dat @@ -20,7 +20,7 @@ 100 5 0 - + -4 -4 -4 4 4 4 diff --git a/tests/regression_tests/dagmc/external/test.py b/tests/regression_tests/dagmc/external/test.py index 93123ae1ed6..7993772e8b6 100644 --- a/tests/regression_tests/dagmc/external/test.py +++ b/tests/regression_tests/dagmc/external/test.py @@ -65,7 +65,7 @@ def model(): model.settings.particles = 100 source_box = openmc.stats.Box([-4, -4, -4], [ 4, 4, 4]) - source = openmc.Source(space=source_box) + source = openmc.IndependentSource(space=source_box) model.settings.source = source model.settings.temperature['default'] = 293 diff --git a/tests/regression_tests/dagmc/legacy/inputs_true.dat b/tests/regression_tests/dagmc/legacy/inputs_true.dat index b6e5133a4f6..b06516cb1eb 100644 --- a/tests/regression_tests/dagmc/legacy/inputs_true.dat +++ b/tests/regression_tests/dagmc/legacy/inputs_true.dat @@ -20,7 +20,7 @@ 100 5 0 - + -4 -4 -4 4 4 4 diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index 36da44808b1..7e4e6e1340b 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -22,7 +22,7 @@ def model(): source_box = openmc.stats.Box([-4, -4, -4], [ 4, 4, 4]) - source = openmc.Source(space=source_box) + source = openmc.IndependentSource(space=source_box) model.settings.source = source diff --git a/tests/regression_tests/dagmc/refl/inputs_true.dat b/tests/regression_tests/dagmc/refl/inputs_true.dat index 126702e3886..979eeb49206 100644 --- a/tests/regression_tests/dagmc/refl/inputs_true.dat +++ b/tests/regression_tests/dagmc/refl/inputs_true.dat @@ -10,7 +10,7 @@ 100 5 0 - + -4 -4 -4 4 4 4 diff --git a/tests/regression_tests/dagmc/refl/test.py b/tests/regression_tests/dagmc/refl/test.py index 5b08f0c4a41..03c1c407bbb 100644 --- a/tests/regression_tests/dagmc/refl/test.py +++ b/tests/regression_tests/dagmc/refl/test.py @@ -18,8 +18,8 @@ def __init__(self, *args, **kwargs): self._model.settings.inactive = 0 self._model.settings.particles = 100 - source = openmc.Source(space=Box([-4, -4, -4], - [ 4, 4, 4])) + source = openmc.IndependentSource(space=Box([-4, -4, -4], + [ 4, 4, 4])) self._model.settings.source = source # geometry diff --git a/tests/regression_tests/dagmc/uwuw/inputs_true.dat b/tests/regression_tests/dagmc/uwuw/inputs_true.dat index e6537a30e03..d7e4a12aa78 100644 --- a/tests/regression_tests/dagmc/uwuw/inputs_true.dat +++ b/tests/regression_tests/dagmc/uwuw/inputs_true.dat @@ -10,7 +10,7 @@ 100 5 0 - + -4 -4 -4 4 4 4 diff --git a/tests/regression_tests/dagmc/uwuw/test.py b/tests/regression_tests/dagmc/uwuw/test.py index 19986e58950..38c335a5ed4 100644 --- a/tests/regression_tests/dagmc/uwuw/test.py +++ b/tests/regression_tests/dagmc/uwuw/test.py @@ -18,8 +18,8 @@ def __init__(self, *args, **kwargs): self._model.settings.inactive = 0 self._model.settings.particles = 100 - source = openmc.Source(space=Box([-4, -4, -4], - [ 4, 4, 4])) + source = openmc.IndependentSource(space=Box([-4, -4, -4], + [ 4, 4, 4])) self._model.settings.source = source # geometry diff --git a/tests/regression_tests/deplete_with_transport/test.py b/tests/regression_tests/deplete_with_transport/test.py index 477959d1cb1..49e0203671e 100644 --- a/tests/regression_tests/deplete_with_transport/test.py +++ b/tests/regression_tests/deplete_with_transport/test.py @@ -46,7 +46,7 @@ def test_full(run_in_tmpdir, problem, multiproc): settings.batches = 10 settings.inactive = 0 space = openmc.stats.Box(lower_left, upper_right) - settings.source = openmc.Source(space=space) + settings.source = openmc.IndependentSource(space=space) settings.seed = 1 settings.verbosity = 1 diff --git a/tests/regression_tests/diff_tally/inputs_true.dat b/tests/regression_tests/diff_tally/inputs_true.dat index 5fad7175d82..3ec4154e82e 100644 --- a/tests/regression_tests/diff_tally/inputs_true.dat +++ b/tests/regression_tests/diff_tally/inputs_true.dat @@ -300,7 +300,7 @@ 100 3 0 - + -160 -160 -183 160 160 183 diff --git a/tests/regression_tests/diff_tally/test.py b/tests/regression_tests/diff_tally/test.py index 18c50137221..89460df9152 100644 --- a/tests/regression_tests/diff_tally/test.py +++ b/tests/regression_tests/diff_tally/test.py @@ -16,7 +16,7 @@ def __init__(self, *args, **kwargs): self._model.settings.batches = 3 self._model.settings.inactive = 0 self._model.settings.particles = 100 - self._model.settings.source = openmc.Source(space=openmc.stats.Box( + self._model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) self._model.settings.temperature['multipole'] = True diff --git a/tests/regression_tests/distribmat/inputs_true.dat b/tests/regression_tests/distribmat/inputs_true.dat index d002f0beb50..ade86999d0a 100644 --- a/tests/regression_tests/distribmat/inputs_true.dat +++ b/tests/regression_tests/distribmat/inputs_true.dat @@ -40,7 +40,7 @@ 1000 5 0 - + -1 -1 -1 1 1 1 diff --git a/tests/regression_tests/distribmat/test.py b/tests/regression_tests/distribmat/test.py index ab789731319..02f7e773e58 100644 --- a/tests/regression_tests/distribmat/test.py +++ b/tests/regression_tests/distribmat/test.py @@ -65,7 +65,7 @@ def __init__(self, *args, **kwargs): sets_file.batches = 5 sets_file.inactive = 0 sets_file.particles = 1000 - sets_file.source = openmc.Source(space=openmc.stats.Box( + sets_file.source = openmc.IndependentSource(space=openmc.stats.Box( [-1, -1, -1], [1, 1, 1])) self._model.settings = sets_file diff --git a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat index 690cd14e356..a3e67d62f69 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat +++ b/tests/regression_tests/eigenvalue_genperbatch/inputs_true.dat @@ -16,7 +16,7 @@ 7 3 3 - + -4.0 -4.0 -4.0 4.0 4.0 4.0 diff --git a/tests/regression_tests/eigenvalue_genperbatch/test.py b/tests/regression_tests/eigenvalue_genperbatch/test.py index 7e21c8d3674..17c6dff7f97 100644 --- a/tests/regression_tests/eigenvalue_genperbatch/test.py +++ b/tests/regression_tests/eigenvalue_genperbatch/test.py @@ -22,7 +22,7 @@ def model(): model.settings.batches = 7 model.settings.generations_per_batch = 3 space = openmc.stats.Box((-4.0, -4.0, -4.0), (4.0, 4.0, 4.)) - model.settings.source = openmc.Source(space=space) + model.settings.source = openmc.IndependentSource(space=space) t = openmc.Tally() t.scores = ['flux'] diff --git a/tests/regression_tests/energy_cutoff/inputs_true.dat b/tests/regression_tests/energy_cutoff/inputs_true.dat index c24164dd8bd..af8f86b6762 100644 --- a/tests/regression_tests/energy_cutoff/inputs_true.dat +++ b/tests/regression_tests/energy_cutoff/inputs_true.dat @@ -19,7 +19,7 @@ fixed source 100 10 - + -1 -1 -1 1 1 1 diff --git a/tests/regression_tests/energy_cutoff/test.py b/tests/regression_tests/energy_cutoff/test.py index e05d17f5f28..9aca802fa35 100755 --- a/tests/regression_tests/energy_cutoff/test.py +++ b/tests/regression_tests/energy_cutoff/test.py @@ -40,8 +40,8 @@ def __init__(self, *args, **kwargs): bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) watt_dist = openmc.stats.Watt() - settings_file.source = openmc.source.Source(space=uniform_dist, - energy=watt_dist) + settings_file.source = openmc.IndependentSource(space=uniform_dist, + energy=watt_dist) self._model.settings = settings_file # Tally flux under energy cutoff diff --git a/tests/regression_tests/external_moab/inputs_true.dat b/tests/regression_tests/external_moab/inputs_true.dat index d54f5db0ef2..23b656bceeb 100644 --- a/tests/regression_tests/external_moab/inputs_true.dat +++ b/tests/regression_tests/external_moab/inputs_true.dat @@ -46,7 +46,7 @@ fixed source 100 10 - + 0.0 0.0 0.0 diff --git a/tests/regression_tests/external_moab/test.py b/tests/regression_tests/external_moab/test.py index 12e0e5425d5..90bff69ed00 100644 --- a/tests/regression_tests/external_moab/test.py +++ b/tests/regression_tests/external_moab/test.py @@ -258,7 +258,7 @@ def test_external_mesh(cpp_driver): space = openmc.stats.Point() angle = openmc.stats.Monodirectional((-1.0, 0.0, 0.0)) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.Source(space=space, energy=energy, angle=angle) + source = openmc.IndependentSource(space=space, energy=energy, angle=angle) settings.source = source model = openmc.model.Model(geometry=geometry, diff --git a/tests/regression_tests/filter_cellinstance/inputs_true.dat b/tests/regression_tests/filter_cellinstance/inputs_true.dat index d3e0937ec05..b17cc0eb59f 100644 --- a/tests/regression_tests/filter_cellinstance/inputs_true.dat +++ b/tests/regression_tests/filter_cellinstance/inputs_true.dat @@ -39,7 +39,7 @@ 1000 5 0 - + 0.0 0.0 0.0 diff --git a/tests/regression_tests/filter_cellinstance/test.py b/tests/regression_tests/filter_cellinstance/test.py index 3f5fa54b267..0d6ad93669e 100644 --- a/tests/regression_tests/filter_cellinstance/test.py +++ b/tests/regression_tests/filter_cellinstance/test.py @@ -69,7 +69,7 @@ def model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) instances = ([(c4, i) for i in range(c4.num_instances)] + [(c2, i) for i in range(c2.num_instances)] + diff --git a/tests/regression_tests/fixed_source/inputs_true.dat b/tests/regression_tests/fixed_source/inputs_true.dat index 60043f20c95..0fdb1466ec5 100644 --- a/tests/regression_tests/fixed_source/inputs_true.dat +++ b/tests/regression_tests/fixed_source/inputs_true.dat @@ -15,7 +15,7 @@ fixed source 100 10 - + 0.0 0.0 0.0 diff --git a/tests/regression_tests/fixed_source/test.py b/tests/regression_tests/fixed_source/test.py index 74908f87cda..b9ee2512536 100644 --- a/tests/regression_tests/fixed_source/test.py +++ b/tests/regression_tests/fixed_source/test.py @@ -48,8 +48,8 @@ def test_fixed_source(): model.settings.batches = 10 model.settings.particles = 100 model.settings.temperature = {'default': 294} - model.settings.source = openmc.Source(space=openmc.stats.Point(), - strength=10.0) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point(), + strength=10.0) tally = openmc.Tally() tally.scores = ['flux'] diff --git a/tests/regression_tests/iso_in_lab/inputs_true.dat b/tests/regression_tests/iso_in_lab/inputs_true.dat index 2bb81da6dc6..bb6494adafb 100644 --- a/tests/regression_tests/iso_in_lab/inputs_true.dat +++ b/tests/regression_tests/iso_in_lab/inputs_true.dat @@ -312,7 +312,7 @@ 100 10 5 - + -160 -160 -183 160 160 183 diff --git a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat index c51a38c8938..7a83fb471f6 100644 --- a/tests/regression_tests/lattice_hex_coincident/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_coincident/inputs_true.dat @@ -68,7 +68,7 @@ 1000 5 2 - + -0.9899494936611666 -0.9899494936611666 0.0 0.9899494936611666 0.9899494936611666 10.0 diff --git a/tests/regression_tests/lattice_hex_coincident/test.py b/tests/regression_tests/lattice_hex_coincident/test.py index fae7f939b84..5a4760cd7c0 100644 --- a/tests/regression_tests/lattice_hex_coincident/test.py +++ b/tests/regression_tests/lattice_hex_coincident/test.py @@ -132,7 +132,7 @@ def __init__(self, *args, **kwargs): settings = openmc.Settings() settings.run_mode = 'eigenvalue' - source = openmc.Source() + source = openmc.IndependentSource() corner_dist = sqrt(2) * pin_rad ll = [-corner_dist, -corner_dist, 0.0] ur = [corner_dist, corner_dist, 10.0] diff --git a/tests/regression_tests/lattice_hex_x/inputs_true.dat b/tests/regression_tests/lattice_hex_x/inputs_true.dat index c510120291b..2946258e8b1 100644 --- a/tests/regression_tests/lattice_hex_x/inputs_true.dat +++ b/tests/regression_tests/lattice_hex_x/inputs_true.dat @@ -113,7 +113,7 @@ 1000 10 5 - + -13.62546635287517 -13.62546635287517 0.0 13.62546635287517 13.62546635287517 10.0 diff --git a/tests/regression_tests/lattice_hex_x/test.py b/tests/regression_tests/lattice_hex_x/test.py index e582c68aeb7..23aec77d3b3 100644 --- a/tests/regression_tests/lattice_hex_x/test.py +++ b/tests/regression_tests/lattice_hex_x/test.py @@ -187,7 +187,7 @@ def __init__(self, *args, **kwargs): settings = openmc.Settings() settings.run_mode = 'eigenvalue' - source = openmc.Source() + source = openmc.IndependentSource() ll = [-edge_length, -edge_length, 0.0] ur = [edge_length, edge_length, 10.0] source.space = openmc.stats.Box(ll, ur) diff --git a/tests/regression_tests/lattice_rotated/inputs_true.dat b/tests/regression_tests/lattice_rotated/inputs_true.dat index 3a8a0784e09..1b7c74870ad 100644 --- a/tests/regression_tests/lattice_rotated/inputs_true.dat +++ b/tests/regression_tests/lattice_rotated/inputs_true.dat @@ -62,7 +62,7 @@ 1000 5 0 - + 0.0 0.0 0.0 diff --git a/tests/regression_tests/lattice_rotated/test.py b/tests/regression_tests/lattice_rotated/test.py index 9cab92e1e65..63641fb84a7 100644 --- a/tests/regression_tests/lattice_rotated/test.py +++ b/tests/regression_tests/lattice_rotated/test.py @@ -73,7 +73,7 @@ def rotated_lattice_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) model.settings.export_to_xml() return model diff --git a/tests/regression_tests/mg_basic/inputs_true.dat b/tests/regression_tests/mg_basic/inputs_true.dat index 5ec5ade759d..8c6faaf070d 100644 --- a/tests/regression_tests/mg_basic/inputs_true.dat +++ b/tests/regression_tests/mg_basic/inputs_true.dat @@ -48,7 +48,7 @@ 1000 10 5 - + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 diff --git a/tests/regression_tests/mg_basic_delayed/inputs_true.dat b/tests/regression_tests/mg_basic_delayed/inputs_true.dat index b3f1993d91f..e0bcad15cef 100644 --- a/tests/regression_tests/mg_basic_delayed/inputs_true.dat +++ b/tests/regression_tests/mg_basic_delayed/inputs_true.dat @@ -47,7 +47,7 @@ 1000 10 5 - + 0.0 -1000.0 -1000.0 154.90833333333333 1000.0 1000.0 diff --git a/tests/regression_tests/mg_convert/inputs_true.dat b/tests/regression_tests/mg_convert/inputs_true.dat index 8277ca483aa..4e51ec80c52 100644 --- a/tests/regression_tests/mg_convert/inputs_true.dat +++ b/tests/regression_tests/mg_convert/inputs_true.dat @@ -19,7 +19,7 @@ 100 10 5 - + -5 -5 -5 5 5 5 diff --git a/tests/regression_tests/mg_convert/test.py b/tests/regression_tests/mg_convert/test.py index d9c4a57bd2f..8099c89a29c 100755 --- a/tests/regression_tests/mg_convert/test.py +++ b/tests/regression_tests/mg_convert/test.py @@ -114,7 +114,7 @@ def __init__(self, *args, **kwargs): # Create an initial uniform spatial source distribution bounds = [-5, -5, -5, 5, 5, 5] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:]) - settings_file.source = openmc.source.Source(space=uniform_dist) + settings_file.source = openmc.IndependentSource(space=uniform_dist) self._model.settings = settings_file diff --git a/tests/regression_tests/mg_legendre/inputs_true.dat b/tests/regression_tests/mg_legendre/inputs_true.dat index 4b7293d81af..34ff7b6300d 100644 --- a/tests/regression_tests/mg_legendre/inputs_true.dat +++ b/tests/regression_tests/mg_legendre/inputs_true.dat @@ -17,7 +17,7 @@ 1000 10 5 - + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 diff --git a/tests/regression_tests/mg_max_order/inputs_true.dat b/tests/regression_tests/mg_max_order/inputs_true.dat index 82699d00ec2..b6d70dc4c01 100644 --- a/tests/regression_tests/mg_max_order/inputs_true.dat +++ b/tests/regression_tests/mg_max_order/inputs_true.dat @@ -17,7 +17,7 @@ 1000 10 5 - + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 diff --git a/tests/regression_tests/mg_survival_biasing/inputs_true.dat b/tests/regression_tests/mg_survival_biasing/inputs_true.dat index 2b5801e120c..6529c60d83e 100644 --- a/tests/regression_tests/mg_survival_biasing/inputs_true.dat +++ b/tests/regression_tests/mg_survival_biasing/inputs_true.dat @@ -17,7 +17,7 @@ 1000 10 5 - + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 diff --git a/tests/regression_tests/mg_tallies/inputs_true.dat b/tests/regression_tests/mg_tallies/inputs_true.dat index b7d362b17eb..c526b65a205 100644 --- a/tests/regression_tests/mg_tallies/inputs_true.dat +++ b/tests/regression_tests/mg_tallies/inputs_true.dat @@ -17,7 +17,7 @@ 1000 10 5 - + 0.0 -1000.0 -1000.0 929.45 1000.0 1000.0 diff --git a/tests/regression_tests/mg_temperature/build_2g.py b/tests/regression_tests/mg_temperature/build_2g.py index 42f948be1e9..f236031a727 100644 --- a/tests/regression_tests/mg_temperature/build_2g.py +++ b/tests/regression_tests/mg_temperature/build_2g.py @@ -291,6 +291,6 @@ def build_inf_model(xsnames, xslibname, temperature, tempmethod='nearest'): bounds = [-INF, -INF, -INF, INF, INF, INF] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) settings_file.temperature = {'method': tempmethod} - settings_file.source = openmc.Source(space=uniform_dist) + settings_file.source = openmc.IndependentSource(space=uniform_dist) model.settings = settings_file model.export_to_model_xml() diff --git a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat index 74067874adf..d9a3c52c840 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat index 13a6ea6d413..f84adc32967 100644 --- a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_condense/inputs_true.dat b/tests/regression_tests/mgxs_library_condense/inputs_true.dat index ce709576596..93519cd2a2a 100644 --- a/tests/regression_tests/mgxs_library_condense/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_condense/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_correction/inputs_true.dat b/tests/regression_tests/mgxs_library_correction/inputs_true.dat index 4d9dbecd620..80cbc4bb56a 100644 --- a/tests/regression_tests/mgxs_library_correction/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_correction/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat index 893e0b3bf22..fc2c06d1cfa 100644 --- a/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_distribcell/inputs_true.dat @@ -68,7 +68,7 @@ 100 10 5 - + -10.71 -10.71 -1 10.71 10.71 1 diff --git a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat index ce709576596..93519cd2a2a 100644 --- a/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_hdf5/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat index f45b7dbf3ee..178a44464e9 100644 --- a/tests/regression_tests/mgxs_library_histogram/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_histogram/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat index 0608d6f966e..0003413acb1 100644 --- a/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_no_nuclides/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat index 215bb7c9fd5..97e227177e0 100644 --- a/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_nuclides/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat index 907bf43ccc4..b73ed179e5e 100644 --- a/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat +++ b/tests/regression_tests/mgxs_library_specific_nuclides/inputs_true.dat @@ -41,7 +41,7 @@ 100 10 5 - + -0.63 -0.63 -1 0.63 0.63 1 diff --git a/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat b/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat index 48774bb020f..7e2a0cf628f 100644 --- a/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat +++ b/tests/regression_tests/model_xml/adj_cell_rotation_inputs_true.dat @@ -29,7 +29,7 @@ 10000 10 5 - + -4.0 -4.0 -4.0 4.0 4.0 4.0 diff --git a/tests/regression_tests/model_xml/photon_production_inputs_true.dat b/tests/regression_tests/model_xml/photon_production_inputs_true.dat index 109b54c6755..ee6cb88622b 100644 --- a/tests/regression_tests/model_xml/photon_production_inputs_true.dat +++ b/tests/regression_tests/model_xml/photon_production_inputs_true.dat @@ -19,7 +19,7 @@ fixed source 10000 1 - + 0 0 0 diff --git a/tests/regression_tests/multipole/inputs_true.dat b/tests/regression_tests/multipole/inputs_true.dat index 5c905afb9cb..7bea669307c 100644 --- a/tests/regression_tests/multipole/inputs_true.dat +++ b/tests/regression_tests/multipole/inputs_true.dat @@ -37,7 +37,7 @@ 1000 5 0 - + -1 -1 -1 1 1 1 diff --git a/tests/regression_tests/multipole/test.py b/tests/regression_tests/multipole/test.py index 4c4353c8412..2f7369a9db5 100644 --- a/tests/regression_tests/multipole/test.py +++ b/tests/regression_tests/multipole/test.py @@ -53,7 +53,7 @@ def make_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-1, -1, -1], [1, 1, 1])) model.settings.temperature = {'tolerance': 1000, 'multipole': True} diff --git a/tests/regression_tests/ncrystal/inputs_true.dat b/tests/regression_tests/ncrystal/inputs_true.dat index be2336cf08d..ecbc3c54f40 100644 --- a/tests/regression_tests/ncrystal/inputs_true.dat +++ b/tests/regression_tests/ncrystal/inputs_true.dat @@ -16,7 +16,7 @@ fixed source 100000 10 - + 0 0 -20 diff --git a/tests/regression_tests/ncrystal/test.py b/tests/regression_tests/ncrystal/test.py index cb6421b0340..03994e0d384 100644 --- a/tests/regression_tests/ncrystal/test.py +++ b/tests/regression_tests/ncrystal/test.py @@ -33,7 +33,7 @@ def pencil_beam_model(cfg, E0, N): # Source definition - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Point((0, 0, -20)) source.angle = openmc.stats.Monodirectional(reference_uvw=(0, 0, 1)) source.energy = openmc.stats.Discrete([E0], [1.0]) diff --git a/tests/regression_tests/periodic/inputs_true.dat b/tests/regression_tests/periodic/inputs_true.dat index 9d50c2b7287..65e1b5ce309 100644 --- a/tests/regression_tests/periodic/inputs_true.dat +++ b/tests/regression_tests/periodic/inputs_true.dat @@ -28,7 +28,7 @@ 1000 4 0 - + 0 0 0 5 5 0 diff --git a/tests/regression_tests/periodic/test.py b/tests/regression_tests/periodic/test.py index 51a70a6aa7e..73fe8a83e44 100644 --- a/tests/regression_tests/periodic/test.py +++ b/tests/regression_tests/periodic/test.py @@ -42,7 +42,7 @@ def box_model(): model.settings.particles = 1000 model.settings.batches = 4 model.settings.inactive = 0 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( (0, 0, 0), (5, 5, 0)) ) return model diff --git a/tests/regression_tests/periodic_6fold/inputs_true.dat b/tests/regression_tests/periodic_6fold/inputs_true.dat index 795ce818faa..f7f413d092b 100644 --- a/tests/regression_tests/periodic_6fold/inputs_true.dat +++ b/tests/regression_tests/periodic_6fold/inputs_true.dat @@ -25,7 +25,7 @@ 1000 4 0 - + 0 0 0 5 5 0 diff --git a/tests/regression_tests/periodic_6fold/test.py b/tests/regression_tests/periodic_6fold/test.py index 69712eb5a95..272c65df57f 100644 --- a/tests/regression_tests/periodic_6fold/test.py +++ b/tests/regression_tests/periodic_6fold/test.py @@ -46,7 +46,7 @@ def model(): model.settings.particles = 1000 model.settings.batches = 4 model.settings.inactive = 0 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( (0, 0, 0), (5, 5, 0)) ) return model diff --git a/tests/regression_tests/photon_production/inputs_true.dat b/tests/regression_tests/photon_production/inputs_true.dat index 109b54c6755..ee6cb88622b 100644 --- a/tests/regression_tests/photon_production/inputs_true.dat +++ b/tests/regression_tests/photon_production/inputs_true.dat @@ -19,7 +19,7 @@ fixed source 10000 1 - + 0 0 0 diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index 107b53bbb60..150448a12f4 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -27,7 +27,7 @@ def model(): inner_cyl_right.fill = mat model.geometry = openmc.Geometry([inner_cyl_left, inner_cyl_right, outer_cyl]) - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Monodirectional() source.energy = openmc.stats.Discrete([14.0e6], [1.0]) diff --git a/tests/regression_tests/photon_production_fission/inputs_true.dat b/tests/regression_tests/photon_production_fission/inputs_true.dat index 6a102cfdcea..fa379b39e10 100644 --- a/tests/regression_tests/photon_production_fission/inputs_true.dat +++ b/tests/regression_tests/photon_production_fission/inputs_true.dat @@ -15,7 +15,7 @@ 1000 5 2 - + 0 0 0 diff --git a/tests/regression_tests/photon_production_fission/test.py b/tests/regression_tests/photon_production_fission/test.py index 595d3c2d6c2..96665b30867 100644 --- a/tests/regression_tests/photon_production_fission/test.py +++ b/tests/regression_tests/photon_production_fission/test.py @@ -20,7 +20,7 @@ def model(): model.settings.batches = 5 model.settings.inactive = 2 model.settings.photon_transport = True - model.settings.source = openmc.Source(space=openmc.stats.Point((0, 0, 0))) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point((0, 0, 0))) particle_filter = openmc.ParticleFilter(['neutron', 'photon']) tally_tracklength = openmc.Tally() diff --git a/tests/regression_tests/photon_source/inputs_true.dat b/tests/regression_tests/photon_source/inputs_true.dat index 33ace2c700c..3d2e0524350 100644 --- a/tests/regression_tests/photon_source/inputs_true.dat +++ b/tests/regression_tests/photon_source/inputs_true.dat @@ -17,7 +17,7 @@ fixed source 10000 1 - + 0 0 0 diff --git a/tests/regression_tests/photon_source/test.py b/tests/regression_tests/photon_source/test.py index d4b4a69fd94..c2eb1476de2 100644 --- a/tests/regression_tests/photon_source/test.py +++ b/tests/regression_tests/photon_source/test.py @@ -21,7 +21,7 @@ def __init__(self, *args, **kwargs): inside_sphere.fill = mat self._model.geometry = openmc.Geometry([inside_sphere]) - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Isotropic() source.energy = openmc.stats.Discrete([10.0e6], [1.0]) diff --git a/tests/regression_tests/resonance_scattering/inputs_true.dat b/tests/regression_tests/resonance_scattering/inputs_true.dat index 6ab82ba245f..dba4535c2b4 100644 --- a/tests/regression_tests/resonance_scattering/inputs_true.dat +++ b/tests/regression_tests/resonance_scattering/inputs_true.dat @@ -18,7 +18,7 @@ 1000 10 5 - + -4 -4 -4 4 4 4 diff --git a/tests/regression_tests/resonance_scattering/test.py b/tests/regression_tests/resonance_scattering/test.py index d9f76fac59a..24629b12b72 100644 --- a/tests/regression_tests/resonance_scattering/test.py +++ b/tests/regression_tests/resonance_scattering/test.py @@ -35,7 +35,7 @@ def __init__(self, *args, **kwargs): settings.batches = 10 settings.inactive = 5 settings.particles = 1000 - settings.source = openmc.source.Source( + settings.source = openmc.IndependentSource( space=openmc.stats.Box([-4, -4, -4], [4, 4, 4])) settings.resonance_scattering = res_scat_settings self._model.settings = settings diff --git a/tests/regression_tests/salphabeta/inputs_true.dat b/tests/regression_tests/salphabeta/inputs_true.dat index 508624b75a7..ef0e843c2f9 100644 --- a/tests/regression_tests/salphabeta/inputs_true.dat +++ b/tests/regression_tests/salphabeta/inputs_true.dat @@ -51,7 +51,7 @@ 400 5 0 - + -4 -4 -4 4 4 4 diff --git a/tests/regression_tests/salphabeta/test.py b/tests/regression_tests/salphabeta/test.py index fd0486118fa..11bf3bc842a 100644 --- a/tests/regression_tests/salphabeta/test.py +++ b/tests/regression_tests/salphabeta/test.py @@ -67,7 +67,7 @@ def make_model(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 400 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-4, -4, -4], [4, 4, 4])) return model diff --git a/tests/regression_tests/source/inputs_true.dat b/tests/regression_tests/source/inputs_true.dat index 460be7077da..c1a616dd109 100644 --- a/tests/regression_tests/source/inputs_true.dat +++ b/tests/regression_tests/source/inputs_true.dat @@ -15,7 +15,7 @@ 1000 10 5 - + @@ -33,14 +33,14 @@ - + -4.0 -4.0 -4.0 4.0 4.0 4.0 - + 1.2 -2.3 0.781 @@ -49,7 +49,7 @@ 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - + @@ -62,7 +62,7 @@ 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - + @@ -75,7 +75,7 @@ 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 - + @@ -98,7 +98,7 @@ - + @@ -122,7 +122,7 @@ - + + + 1 + + + 0.0 2000.0 1000000.0 + + + 1 2 + flux + + + diff --git a/tests/regression_tests/source_dlopen/results_true.dat b/tests/regression_tests/source_dlopen/results_true.dat index e69de29bb2d..1cddaf802ca 100644 --- a/tests/regression_tests/source_dlopen/results_true.dat +++ b/tests/regression_tests/source_dlopen/results_true.dat @@ -0,0 +1,5 @@ +tally 1: +1.445856E+04 +2.090732E+07 +0.000000E+00 +0.000000E+00 diff --git a/tests/regression_tests/source_dlopen/source_sampling.cpp b/tests/regression_tests/source_dlopen/source_sampling.cpp index 2c6de6d85e0..fc61ef1fdd8 100644 --- a/tests/regression_tests/source_dlopen/source_sampling.cpp +++ b/tests/regression_tests/source_dlopen/source_sampling.cpp @@ -5,8 +5,7 @@ #include "openmc/random_lcg.h" #include "openmc/source.h" -class CustomSource : public openmc::Source -{ +class CustomSource : public openmc::Source { openmc::SourceSite sample(uint64_t* seed) const { openmc::SourceSite particle; @@ -20,16 +19,17 @@ class CustomSource : public openmc::Source particle.r.z = 0.; // angle particle.u = {1.0, 0.0, 0.0}; - particle.E = 14.08e6; + particle.E = 1.00e3; particle.delayed_group = 0; return particle; } }; -// A function to create a unique pointer to an instance of this class when generated -// via a plugin call using dlopen/dlsym. -// You must have external C linkage here otherwise dlopen will not find the file -extern "C" std::unique_ptr openmc_create_source(std::string parameters) +// A function to create a unique pointer to an instance of this class when +// generated via a plugin call using dlopen/dlsym. You must have external C +// linkage here otherwise dlopen will not find the file +extern "C" std::unique_ptr openmc_create_source( + std::string parameters) { return std::make_unique(); } diff --git a/tests/regression_tests/source_dlopen/test.py b/tests/regression_tests/source_dlopen/test.py index 41690224dfb..efe942933dd 100644 --- a/tests/regression_tests/source_dlopen/test.py +++ b/tests/regression_tests/source_dlopen/test.py @@ -61,8 +61,18 @@ def model(): model.settings.particles = 1000 model.settings.run_mode = 'fixed source' + tally = openmc.Tally() + mat_filter = openmc.MaterialFilter([natural_lead]) + # energy filter with two bins 0 eV - 1 keV and 1 keV - 1 MeV the second bin + # of the energy filter (last two entries in the tally results) should be + # zero + energy_filter = openmc.EnergyFilter([0.0, 2e3, 1e6]) + tally.filters = [mat_filter, energy_filter] + tally.scores = ['flux'] + model.tallies = openmc.Tallies([tally]) + # custom source from shared library - source = openmc.Source() + source = openmc.CompiledSource() source.library = 'build/libsource.so' model.settings.source = source diff --git a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat index 68946359351..6cf3473f9f7 100644 --- a/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat +++ b/tests/regression_tests/source_parameterized_dlopen/inputs_true.dat @@ -18,6 +18,18 @@ 1000 10 0 - + - + + + 1 + + + 0.0 2000.0 1000000.0 + + + 1 2 + flux + + + diff --git a/tests/regression_tests/source_parameterized_dlopen/results_true.dat b/tests/regression_tests/source_parameterized_dlopen/results_true.dat index e69de29bb2d..1cddaf802ca 100644 --- a/tests/regression_tests/source_parameterized_dlopen/results_true.dat +++ b/tests/regression_tests/source_parameterized_dlopen/results_true.dat @@ -0,0 +1,5 @@ +tally 1: +1.445856E+04 +2.090732E+07 +0.000000E+00 +0.000000E+00 diff --git a/tests/regression_tests/source_parameterized_dlopen/test.py b/tests/regression_tests/source_parameterized_dlopen/test.py index c613cde4b3b..c7c5d06b1f9 100644 --- a/tests/regression_tests/source_parameterized_dlopen/test.py +++ b/tests/regression_tests/source_parameterized_dlopen/test.py @@ -61,8 +61,17 @@ def model(): model.settings.particles = 1000 model.settings.run_mode = 'fixed source' + tally = openmc.Tally() + mat_filter = openmc.MaterialFilter([natural_lead]) + # energy filter with two bins 0 eV - 1 keV and 1 keV - 1 MeV + # the second bin shouldn't have any results + energy_filter = openmc.EnergyFilter([0.0, 2e3, 1e6]) + tally.filters = [mat_filter, energy_filter] + tally.scores = ['flux'] + model.tallies = openmc.Tallies([tally]) + # custom source from shared library - source = openmc.Source() + source = openmc.CompiledSource() source.library = 'build/libsource.so' source.parameters = '1e3' model.settings.source = source diff --git a/tests/regression_tests/surface_source/inputs_true_write.dat b/tests/regression_tests/surface_source/inputs_true_write.dat index 4747fcaf42b..5c85de6318b 100644 --- a/tests/regression_tests/surface_source/inputs_true_write.dat +++ b/tests/regression_tests/surface_source/inputs_true_write.dat @@ -16,7 +16,7 @@ fixed source 1000 10 - + 0 0 0 diff --git a/tests/regression_tests/surface_source/test.py b/tests/regression_tests/surface_source/test.py index dc60cfd3c72..1647266f6cb 100644 --- a/tests/regression_tests/surface_source/test.py +++ b/tests/regression_tests/surface_source/test.py @@ -44,7 +44,7 @@ def model(request): if surf_source_op == 'write': point = openmc.stats.Point((0, 0, 0)) - pt_src = openmc.Source(space=point) + pt_src = openmc.IndependentSource(space=point) openmc_model.settings.source = pt_src openmc_model.settings.surf_source_write = {'surface_ids': [1], diff --git a/tests/regression_tests/surface_tally/inputs_true.dat b/tests/regression_tests/surface_tally/inputs_true.dat index 4be5d4e77a7..dc65e2a15da 100644 --- a/tests/regression_tests/surface_tally/inputs_true.dat +++ b/tests/regression_tests/surface_tally/inputs_true.dat @@ -29,7 +29,7 @@ 1000 10 0 - + -0.62992 -0.62992 -1 0.62992 0.62992 1 diff --git a/tests/regression_tests/surface_tally/test.py b/tests/regression_tests/surface_tally/test.py index 001fe6448e0..1224ebbb972 100644 --- a/tests/regression_tests/surface_tally/test.py +++ b/tests/regression_tests/surface_tally/test.py @@ -74,7 +74,7 @@ def __init__(self, *args, **kwargs): bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:],\ only_fissionable=True) - settings_file.source = openmc.source.Source(space=uniform_dist) + settings_file.source = openmc.IndependentSource(space=uniform_dist) self._model.settings = settings_file # Tallies file diff --git a/tests/regression_tests/tallies/inputs_true.dat b/tests/regression_tests/tallies/inputs_true.dat index 8d2e50af8cc..2ce36c5dfcd 100644 --- a/tests/regression_tests/tallies/inputs_true.dat +++ b/tests/regression_tests/tallies/inputs_true.dat @@ -300,7 +300,7 @@ 400 5 0 - + -160 -160 -183 160 160 183 diff --git a/tests/regression_tests/tallies/test.py b/tests/regression_tests/tallies/test.py index 6b4baabceb2..d20067ed33f 100644 --- a/tests/regression_tests/tallies/test.py +++ b/tests/regression_tests/tallies/test.py @@ -13,7 +13,7 @@ def test_tallies(): model.settings.batches = 5 model.settings.inactive = 0 model.settings.particles = 400 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-160, -160, -183], [160, 160, 183])) azimuthal_bins = (-3.14159, -1.8850, -0.6283, 0.6283, 1.8850, 3.14159) diff --git a/tests/regression_tests/tally_slice_merge/inputs_true.dat b/tests/regression_tests/tally_slice_merge/inputs_true.dat index 5dff76a6848..356962f8e4f 100644 --- a/tests/regression_tests/tally_slice_merge/inputs_true.dat +++ b/tests/regression_tests/tally_slice_merge/inputs_true.dat @@ -300,7 +300,7 @@ 100 10 5 - + -160 -160 -183 160 160 183 diff --git a/tests/regression_tests/torus/large_major/inputs_true.dat b/tests/regression_tests/torus/large_major/inputs_true.dat index 44a67b8aa06..fa7deb29a87 100644 --- a/tests/regression_tests/torus/large_major/inputs_true.dat +++ b/tests/regression_tests/torus/large_major/inputs_true.dat @@ -22,7 +22,7 @@ fixed source 1000 10 - + -1000.0 0 0 diff --git a/tests/regression_tests/torus/large_major/test.py b/tests/regression_tests/torus/large_major/test.py index 256716f4e10..1ce1ab2cac8 100644 --- a/tests/regression_tests/torus/large_major/test.py +++ b/tests/regression_tests/torus/large_major/test.py @@ -28,7 +28,7 @@ def model(): model.settings.run_mode ='fixed source' model.settings.particles = 1000 model.settings.batches = 10 - model.settings.source = openmc.Source(space=openmc.stats.Point((-R, 0, 0,))) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point((-R, 0, 0,))) tally = openmc.Tally() tally.scores = ['flux'] diff --git a/tests/regression_tests/triso/inputs_true.dat b/tests/regression_tests/triso/inputs_true.dat index 606f05f14d1..37f37af7871 100644 --- a/tests/regression_tests/triso/inputs_true.dat +++ b/tests/regression_tests/triso/inputs_true.dat @@ -433,7 +433,7 @@ 100 4 0 - + 0.0 0.0 0.0 diff --git a/tests/regression_tests/triso/test.py b/tests/regression_tests/triso/test.py index 06ae04492fb..3fa5e3c60d2 100644 --- a/tests/regression_tests/triso/test.py +++ b/tests/regression_tests/triso/test.py @@ -81,7 +81,7 @@ def __init__(self, *args, **kwargs): settings.batches = 4 settings.inactive = 0 settings.particles = 100 - settings.source = openmc.Source(space=openmc.stats.Point()) + settings.source = openmc.IndependentSource(space=openmc.stats.Point()) self._model.settings = settings self._model.materials = openmc.Materials([fuel, porous_carbon, ipyc, diff --git a/tests/regression_tests/unstructured_mesh/inputs_true.dat b/tests/regression_tests/unstructured_mesh/inputs_true.dat index 55fdf825bc9..07486d3e0ee 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true0.dat b/tests/regression_tests/unstructured_mesh/inputs_true0.dat index 45e15c59715..c6b28d890ed 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true0.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true0.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true1.dat b/tests/regression_tests/unstructured_mesh/inputs_true1.dat index d47985ceb2d..40183c89bc8 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true1.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true1.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true10.dat b/tests/regression_tests/unstructured_mesh/inputs_true10.dat index 943ef2dc8e1..ebc5548f54e 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true10.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true10.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true11.dat b/tests/regression_tests/unstructured_mesh/inputs_true11.dat index d0888b4b8b8..e30a5ccfc1e 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true11.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true11.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true12.dat b/tests/regression_tests/unstructured_mesh/inputs_true12.dat index b431b412e66..a60b70eab22 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true12.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true12.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true13.dat b/tests/regression_tests/unstructured_mesh/inputs_true13.dat index f53e733a88c..1b1aa19c312 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true13.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true13.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true14.dat b/tests/regression_tests/unstructured_mesh/inputs_true14.dat index 05bdf3ae9d3..d07504b9d28 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true14.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true14.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true15.dat b/tests/regression_tests/unstructured_mesh/inputs_true15.dat index 67c8af42768..8cabbb38d0b 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true15.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true15.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true2.dat b/tests/regression_tests/unstructured_mesh/inputs_true2.dat index 78ff40199a7..3521ac7b81e 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true2.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true2.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true3.dat b/tests/regression_tests/unstructured_mesh/inputs_true3.dat index fe551549340..a376b401d6c 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true3.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true3.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true8.dat b/tests/regression_tests/unstructured_mesh/inputs_true8.dat index 1e3b6cb83ea..5f14aa691bc 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true8.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true8.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/inputs_true9.dat b/tests/regression_tests/unstructured_mesh/inputs_true9.dat index cb35eb1867d..92354c75cf0 100644 --- a/tests/regression_tests/unstructured_mesh/inputs_true9.dat +++ b/tests/regression_tests/unstructured_mesh/inputs_true9.dat @@ -46,7 +46,7 @@ fixed source 1000 10 - + diff --git a/tests/regression_tests/unstructured_mesh/results_true.dat b/tests/regression_tests/unstructured_mesh/results_true.dat deleted file mode 100644 index a6cad647c67..00000000000 --- a/tests/regression_tests/unstructured_mesh/results_true.dat +++ /dev/null @@ -1,4002 +0,0 @@ -tally 1: -2.084815E-02 -1.082750E-04 -6.381818E-02 -9.439513E-04 -1.155641E-01 -2.178751E-03 -6.865908E-02 -7.355866E-04 -6.720820E-02 -7.310529E-04 -9.537792E-02 -1.957273E-03 -1.007744E-01 -1.573169E-03 -9.409645E-02 -1.796197E-03 -7.113698E-02 -8.980335E-04 -2.405019E-02 -9.740436E-05 -6.040159E-02 -7.575405E-04 -1.050048E-01 -2.108780E-03 -1.307457E-01 -2.170448E-03 -9.988454E-02 -1.092936E-03 -1.547083E-01 -3.688477E-03 -8.157999E-02 -1.133034E-03 -1.368232E-01 -2.667957E-03 -1.444186E-01 -3.197937E-03 -1.049316E-01 -1.560309E-03 -7.358073E-02 -1.128410E-03 -4.923095E-02 -6.563588E-04 -9.650255E-02 -1.789194E-03 -1.467738E-01 -3.481509E-03 -1.687123E-01 -5.414669E-03 -1.873036E-01 -4.734353E-03 -1.130087E-01 -1.673004E-03 -1.695614E-01 -3.526426E-03 -2.591168E-01 -8.231726E-03 -1.260152E-01 -2.175978E-03 -6.288783E-02 -9.200482E-04 -8.362502E-02 -1.022521E-03 -1.456806E-01 -3.692821E-03 -1.468696E-01 -3.582954E-03 -1.848215E-01 -5.256814E-03 -2.212472E-01 -5.760540E-03 -2.169211E-01 -5.946348E-03 -1.919182E-01 -7.063068E-03 -1.588234E-01 -3.825511E-03 -1.149909E-01 -1.553531E-03 -8.539019E-02 -1.065672E-03 -1.458566E-01 -4.113559E-03 -2.049774E-01 -6.265197E-03 -2.166930E-01 -7.983860E-03 -1.757110E-01 -5.024516E-03 -2.353728E-01 -7.533032E-03 -1.280409E-01 -2.167446E-03 -1.648011E-01 -3.936025E-03 -1.599354E-01 -3.980976E-03 -1.679361E-01 -3.415565E-03 -6.849881E-02 -7.535621E-04 -8.785791E-02 -1.103156E-03 -1.709025E-01 -4.264016E-03 -1.929437E-01 -4.281538E-03 -1.711011E-01 -3.912611E-03 -1.562002E-01 -3.325900E-03 -2.153821E-01 -5.848786E-03 -1.610373E-01 -3.861192E-03 -2.389629E-01 -8.850896E-03 -1.539258E-01 -3.811869E-03 -7.844092E-02 -1.163579E-03 -2.298462E-02 -1.395953E-04 -1.570027E-01 -4.835079E-03 -1.123717E-01 -1.760314E-03 -1.821249E-01 -6.802302E-03 -2.461041E-01 -7.613043E-03 -1.904001E-01 -4.047242E-03 -2.024477E-01 -5.524067E-03 -1.167011E-01 -2.057180E-03 -8.780067E-02 -1.080238E-03 -5.397296E-02 -5.850746E-04 -5.037871E-02 -5.560040E-04 -8.289459E-02 -1.268000E-03 -1.469691E-01 -4.146173E-03 -1.075211E-01 -1.625602E-03 -2.187908E-01 -6.919967E-03 -1.278025E-01 -2.170886E-03 -9.950167E-02 -1.901085E-03 -1.104557E-01 -2.248074E-03 -1.262151E-01 -2.266348E-03 -5.580544E-02 -9.620095E-04 -5.104294E-02 -5.268938E-04 -9.139465E-02 -1.164619E-03 -7.378130E-02 -1.282188E-03 -8.021098E-02 -7.940912E-04 -1.290978E-01 -2.526036E-03 -9.365705E-02 -1.199392E-03 -6.078377E-02 -5.442247E-04 -7.556566E-02 -8.976997E-04 -6.453527E-02 -1.173497E-03 -4.302808E-02 -5.599709E-04 -3.878239E-02 -5.236943E-04 -6.099196E-02 -1.095513E-03 -9.150086E-02 -1.624380E-03 -5.728387E-02 -5.659010E-04 -9.405318E-02 -1.606034E-03 -8.619696E-02 -1.337493E-03 -1.055978E-01 -2.086153E-03 -8.890472E-02 -1.315673E-03 -6.441028E-02 -7.477974E-04 -6.069918E-02 -6.588335E-04 -1.095224E-01 -2.675022E-03 -1.096306E-01 -2.122353E-03 -1.342330E-01 -3.619967E-03 -1.114064E-01 -1.730639E-03 -1.074251E-01 -1.586218E-03 -1.408447E-01 -2.389426E-03 -1.301662E-01 -3.969782E-03 -7.949674E-02 -1.090923E-03 -1.074998E-01 -3.217694E-03 -3.528248E-02 -2.289672E-04 -9.882155E-02 -1.696404E-03 -1.354820E-01 -2.909227E-03 -1.599751E-01 -2.957031E-03 -2.280781E-01 -6.081628E-03 -2.100930E-01 -5.450110E-03 -2.732779E-01 -8.620164E-03 -1.993743E-01 -5.362856E-03 -2.198036E-01 -5.376103E-03 -1.502824E-01 -2.786908E-03 -4.996523E-02 -5.024077E-04 -1.680575E-01 -3.208887E-03 -1.422788E-01 -4.002215E-03 -1.762382E-01 -4.255455E-03 -2.502725E-01 -7.152209E-03 -3.414429E-01 -1.411003E-02 -2.636737E-01 -9.397976E-03 -2.247647E-01 -7.123896E-03 -3.224482E-01 -1.294508E-02 -1.622669E-01 -3.583977E-03 -1.248655E-01 -2.516158E-03 -6.877708E-02 -1.029829E-03 -1.976808E-01 -6.130857E-03 -3.144113E-01 -1.232063E-02 -3.018257E-01 -1.124658E-02 -2.619717E-01 -8.351589E-03 -3.672028E-01 -1.638863E-02 -3.059552E-01 -1.103037E-02 -2.486122E-01 -8.141595E-03 -1.750139E-01 -3.956566E-03 -1.436264E-01 -3.567607E-03 -1.239696E-01 -2.379611E-03 -2.163287E-01 -5.949023E-03 -2.072743E-01 -5.179000E-03 -3.646146E-01 -1.695667E-02 -3.486264E-01 -1.301568E-02 -3.563685E-01 -1.447225E-02 -2.970379E-01 -1.009480E-02 -2.762591E-01 -9.482575E-03 -2.499264E-01 -7.462884E-03 -6.344775E-02 -6.567949E-04 -1.086029E-01 -1.976496E-03 -2.603220E-01 -8.391117E-03 -2.841149E-01 -1.105366E-02 -3.965469E-01 -1.974149E-02 -3.901607E-01 -1.960621E-02 -3.509285E-01 -1.478774E-02 -2.714593E-01 -8.321432E-03 -2.293816E-01 -7.685918E-03 -1.265740E-01 -2.312172E-03 -1.103539E-01 -2.077575E-03 -1.262352E-01 -2.754572E-03 -2.213458E-01 -6.719185E-03 -3.023706E-01 -1.146381E-02 -3.282506E-01 -1.233694E-02 -2.853774E-01 -1.070129E-02 -2.848374E-01 -9.701790E-03 -3.176142E-01 -1.194832E-02 -2.880766E-01 -1.175767E-02 -1.572435E-01 -3.553858E-03 -1.501104E-01 -2.820093E-03 -1.273408E-01 -2.552547E-03 -1.499070E-01 -3.571856E-03 -2.199953E-01 -7.783541E-03 -2.453178E-01 -7.052370E-03 -2.643229E-01 -9.900690E-03 -2.574947E-01 -8.333501E-03 -2.455689E-01 -8.366273E-03 -1.782866E-01 -3.900659E-03 -1.384975E-01 -2.258716E-03 -8.944673E-02 -1.404954E-03 -5.659795E-02 -4.694852E-04 -9.581840E-02 -1.386427E-03 -2.009835E-01 -6.159157E-03 -1.897439E-01 -7.235399E-03 -1.830639E-01 -5.540521E-03 -1.520639E-01 -2.752778E-03 -2.084599E-01 -5.955188E-03 -1.319666E-01 -2.817088E-03 -1.693010E-01 -3.303866E-03 -7.800745E-02 -8.928402E-04 -4.749930E-02 -5.129237E-04 -6.919528E-02 -9.104379E-04 -1.119151E-01 -2.477462E-03 -1.102521E-01 -1.584592E-03 -1.564084E-01 -3.266574E-03 -1.198104E-01 -2.580046E-03 -1.828790E-01 -4.860390E-03 -7.542042E-02 -1.053718E-03 -1.099096E-01 -1.964225E-03 -6.193848E-02 -6.865448E-04 -5.105046E-02 -5.591936E-04 -5.609383E-02 -5.921134E-04 -9.705482E-02 -1.351531E-03 -1.601898E-01 -3.408525E-03 -1.711068E-01 -3.795257E-03 -2.205615E-01 -7.391402E-03 -1.668188E-01 -3.216331E-03 -1.359445E-01 -2.208925E-03 -9.194982E-02 -1.221828E-03 -3.090110E-02 -1.871704E-04 -1.137084E-01 -1.891251E-03 -1.350332E-01 -3.254232E-03 -1.906275E-01 -4.961645E-03 -2.657405E-01 -8.636878E-03 -3.845292E-01 -1.700936E-02 -2.839796E-01 -9.879629E-03 -2.593192E-01 -7.387676E-03 -1.606576E-01 -4.742954E-03 -1.870343E-01 -4.582302E-03 -8.524427E-02 -1.055424E-03 -1.918440E-01 -4.887813E-03 -2.109751E-01 -5.543123E-03 -2.472924E-01 -8.124732E-03 -4.210681E-01 -1.934743E-02 -3.735043E-01 -1.670088E-02 -4.705633E-01 -2.767424E-02 -4.105274E-01 -2.102523E-02 -4.139000E-01 -1.844845E-02 -2.302657E-01 -6.040845E-03 -1.013844E-01 -1.496233E-03 -1.060074E-01 -1.569679E-03 -3.421581E-01 -1.371034E-02 -4.542071E-01 -2.517473E-02 -5.784381E-01 -3.768770E-02 -4.172596E-01 -1.856012E-02 -5.299200E-01 -3.825470E-02 -5.178634E-01 -3.589903E-02 -4.185970E-01 -1.861497E-02 -2.546343E-01 -8.375242E-03 -1.304944E-01 -1.999316E-03 -1.290019E-01 -2.856345E-03 -2.844146E-01 -9.114045E-03 -4.560916E-01 -2.713184E-02 -7.260552E-01 -5.922762E-02 -7.310584E-01 -6.237152E-02 -6.478348E-01 -5.416126E-02 -4.846913E-01 -3.277993E-02 -4.849197E-01 -2.856176E-02 -2.465437E-01 -7.303148E-03 -1.744812E-01 -4.301498E-03 -1.796564E-01 -4.684076E-03 -2.812314E-01 -1.216852E-02 -4.240103E-01 -2.176819E-02 -5.209518E-01 -3.000472E-02 -6.504938E-01 -4.819256E-02 -5.990305E-01 -4.159076E-02 -5.121545E-01 -3.102991E-02 -3.470484E-01 -1.737934E-02 -2.216267E-01 -5.579967E-03 -1.708599E-01 -4.101306E-03 -1.374646E-01 -2.373831E-03 -2.399512E-01 -9.436021E-03 -4.641786E-01 -2.746647E-02 -4.258629E-01 -2.112979E-02 -6.864289E-01 -5.425243E-02 -6.579119E-01 -5.051533E-02 -4.223368E-01 -2.321407E-02 -4.058385E-01 -2.310793E-02 -2.072746E-01 -5.809548E-03 -2.339589E-01 -7.282388E-03 -9.714578E-02 -1.698684E-03 -1.688968E-01 -3.770170E-03 -2.795405E-01 -9.154147E-03 -3.109678E-01 -1.173563E-02 -3.911757E-01 -1.773775E-02 -4.374549E-01 -2.366240E-02 -4.611865E-01 -2.432741E-02 -2.516503E-01 -7.415388E-03 -1.292894E-01 -2.441647E-03 -2.226852E-01 -6.770128E-03 -8.639730E-02 -1.201841E-03 -1.449879E-01 -2.972972E-03 -1.801392E-01 -3.863618E-03 -1.936577E-01 -4.483865E-03 -2.453357E-01 -9.056291E-03 -2.480125E-01 -8.275523E-03 -2.448524E-01 -6.977697E-03 -2.436311E-01 -7.489666E-03 -2.248261E-01 -6.983599E-03 -6.717077E-02 -9.275956E-04 -4.731066E-02 -3.124630E-04 -8.581231E-02 -1.170765E-03 -2.015455E-01 -5.727404E-03 -1.747214E-01 -3.928453E-03 -1.459763E-01 -2.610376E-03 -1.928041E-01 -5.431526E-03 -1.326436E-01 -2.700926E-03 -1.950403E-01 -6.678626E-03 -1.195635E-01 -1.740482E-03 -8.319821E-02 -2.457105E-03 -5.199084E-02 -8.828006E-04 -9.589097E-02 -1.548067E-03 -1.287095E-01 -3.340920E-03 -2.500082E-01 -7.508730E-03 -1.935346E-01 -5.219674E-03 -1.617078E-01 -3.813457E-03 -1.854527E-01 -4.327935E-03 -1.469009E-01 -2.610026E-03 -1.461825E-01 -3.217211E-03 -6.828427E-02 -8.825134E-04 -1.130324E-01 -1.720356E-03 -2.114890E-01 -6.553709E-03 -1.990033E-01 -5.173772E-03 -3.695621E-01 -1.648852E-02 -3.985679E-01 -1.776400E-02 -4.317996E-01 -1.968661E-02 -4.168039E-01 -1.881861E-02 -3.168143E-01 -1.633856E-02 -1.765576E-01 -5.283407E-03 -1.593152E-01 -4.604144E-03 -1.293622E-01 -1.916729E-03 -2.979566E-01 -1.047393E-02 -3.451328E-01 -1.555073E-02 -4.833176E-01 -2.633603E-02 -5.627698E-01 -3.356380E-02 -6.205981E-01 -4.614253E-02 -5.667030E-01 -4.186377E-02 -3.633926E-01 -1.532926E-02 -1.863158E-01 -4.282436E-03 -1.141892E-01 -2.085004E-03 -1.558106E-01 -2.875549E-03 -2.977518E-01 -1.072036E-02 -6.281147E-01 -4.728417E-02 -6.712593E-01 -4.960413E-02 -1.056883E+00 -1.367649E-01 -9.587365E-01 -1.078758E-01 -7.458883E-01 -6.448193E-02 -5.376124E-01 -3.468394E-02 -3.326626E-01 -1.382728E-02 -1.715305E-01 -3.663437E-03 -1.682990E-01 -3.326460E-03 -2.809424E-01 -1.063357E-02 -3.850550E-01 -2.020363E-02 -8.686055E-01 -8.923119E-02 -1.305252E+00 -2.173314E-01 -1.246711E+00 -1.850981E-01 -8.484663E-01 -8.472718E-02 -6.548499E-01 -4.947625E-02 -2.303342E-01 -5.911752E-03 -2.386545E-01 -6.839411E-03 -1.627119E-01 -2.886284E-03 -3.438278E-01 -1.334226E-02 -4.891845E-01 -3.041285E-02 -8.909073E-01 -9.620969E-02 -1.255312E+00 -1.734311E-01 -1.169852E+00 -1.621969E-01 -9.218086E-01 -9.573599E-02 -5.068244E-01 -3.491193E-02 -3.003659E-01 -9.829990E-03 -1.957695E-01 -5.152593E-03 -1.886300E-01 -4.844638E-03 -2.305332E-01 -6.488165E-03 -4.823482E-01 -2.794296E-02 -7.462144E-01 -6.544856E-02 -9.896232E-01 -1.097631E-01 -9.014297E-01 -9.720847E-02 -6.453827E-01 -4.960136E-02 -4.680612E-01 -2.551940E-02 -2.958141E-01 -1.060228E-02 -1.573863E-01 -3.574829E-03 -1.346274E-01 -2.606991E-03 -2.151576E-01 -5.865290E-03 -3.725391E-01 -1.667519E-02 -4.869630E-01 -2.818017E-02 -6.480100E-01 -5.048920E-02 -6.074075E-01 -5.206769E-02 -4.501793E-01 -2.531848E-02 -3.790470E-01 -1.851680E-02 -2.452106E-01 -7.276116E-03 -1.402939E-01 -2.997945E-03 -1.577787E-01 -2.960256E-03 -1.659923E-01 -3.686020E-03 -2.064830E-01 -6.139283E-03 -3.154830E-01 -1.105998E-02 -4.082087E-01 -1.828447E-02 -3.712626E-01 -1.597510E-02 -3.971745E-01 -1.721238E-02 -3.019064E-01 -1.052699E-02 -1.828928E-01 -4.248902E-03 -1.233601E-01 -2.166273E-03 -8.357176E-02 -1.039130E-03 -1.492118E-01 -3.605953E-03 -1.685975E-01 -3.436440E-03 -1.741635E-01 -4.786790E-03 -1.890091E-01 -4.516094E-03 -2.283632E-01 -6.314480E-03 -2.656566E-01 -8.538973E-03 -1.402148E-01 -3.495565E-03 -8.649749E-02 -1.100158E-03 -8.813243E-02 -1.064695E-03 -4.555958E-02 -6.107386E-04 -1.309527E-01 -2.731943E-03 -1.264672E-01 -2.142006E-03 -3.000507E-01 -1.065688E-02 -3.237002E-01 -1.209173E-02 -2.307443E-01 -7.102755E-03 -1.661595E-01 -4.258378E-03 -1.386893E-01 -3.229314E-03 -8.165890E-02 -9.243538E-04 -9.523925E-02 -1.956679E-03 -1.141044E-01 -2.428038E-03 -1.740908E-01 -3.775648E-03 -1.944806E-01 -4.977204E-03 -2.742895E-01 -8.190026E-03 -4.026905E-01 -1.975388E-02 -4.110115E-01 -1.874949E-02 -2.531408E-01 -7.828810E-03 -2.295291E-01 -6.890997E-03 -2.221209E-01 -6.094039E-03 -1.321954E-01 -2.553334E-03 -1.666256E-01 -4.426400E-03 -2.171404E-01 -6.076897E-03 -3.633640E-01 -1.502241E-02 -5.792842E-01 -3.974284E-02 -6.573016E-01 -5.041895E-02 -5.370335E-01 -3.858979E-02 -6.553493E-01 -5.021005E-02 -4.574564E-01 -2.381874E-02 -3.948129E-01 -1.754777E-02 -1.514078E-01 -3.617861E-03 -1.672928E-01 -3.337911E-03 -2.716967E-01 -8.803461E-03 -5.682403E-01 -3.764689E-02 -8.144576E-01 -8.737915E-02 -1.222427E+00 -1.615304E-01 -1.406450E+00 -2.161620E-01 -9.190365E-01 -9.711802E-02 -5.724671E-01 -3.647197E-02 -3.613345E-01 -1.386290E-02 -1.868095E-01 -3.836399E-03 -2.244663E-01 -5.650733E-03 -3.340151E-01 -1.419108E-02 -5.201277E-01 -3.061828E-02 -1.212509E+00 -1.609699E-01 -4.267920E+00 -1.910806E+00 -4.227114E+00 -1.859722E+00 -1.233210E+00 -1.636276E-01 -6.793213E-01 -5.401213E-02 -3.156364E-01 -1.221711E-02 -1.862610E-01 -4.406388E-03 -2.147662E-01 -5.433421E-03 -3.138361E-01 -1.254893E-02 -6.467791E-01 -4.949991E-02 -1.292908E+00 -1.841406E-01 -4.571133E+00 -2.199170E+00 -4.304366E+00 -1.934972E+00 -1.361497E+00 -2.027947E-01 -6.505924E-01 -4.666856E-02 -3.615811E-01 -1.447718E-02 -2.447963E-01 -7.854969E-03 -1.654784E-01 -4.247475E-03 -2.649194E-01 -1.051513E-02 -6.278811E-01 -4.683999E-02 -8.592361E-01 -8.990276E-02 -1.382839E+00 -2.107838E-01 -1.135130E+00 -1.382627E-01 -9.661898E-01 -1.164265E-01 -5.142024E-01 -3.024987E-02 -2.975162E-01 -9.543763E-03 -1.876877E-01 -4.835176E-03 -1.730644E-01 -3.300158E-03 -2.265572E-01 -7.086879E-03 -4.539714E-01 -2.260730E-02 -4.526763E-01 -2.455356E-02 -8.380497E-01 -7.969257E-02 -6.097070E-01 -3.995479E-02 -6.978494E-01 -5.538934E-02 -4.583192E-01 -2.651122E-02 -2.487859E-01 -6.745574E-03 -2.135994E-01 -7.272300E-03 -2.313010E-01 -7.739556E-03 -2.374439E-01 -8.831961E-03 -2.928583E-01 -1.186840E-02 -2.940020E-01 -9.794156E-03 -4.513060E-01 -2.594396E-02 -3.408815E-01 -1.439810E-02 -3.106891E-01 -1.144803E-02 -3.403069E-01 -1.268580E-02 -1.465408E-01 -2.813252E-03 -1.367546E-01 -2.740789E-03 -1.174094E-01 -2.667947E-03 -1.443079E-01 -2.844402E-03 -9.912399E-02 -1.868517E-03 -2.216936E-01 -5.865658E-03 -2.574848E-01 -7.753799E-03 -2.423469E-01 -6.852465E-03 -2.550700E-01 -1.011995E-02 -1.640218E-01 -3.672006E-03 -1.871862E-01 -4.742433E-03 -1.058744E-01 -2.396856E-03 -7.436797E-02 -1.038777E-03 -1.410499E-01 -3.203643E-03 -9.735284E-02 -1.185189E-03 -1.816982E-01 -4.474357E-03 -2.007849E-01 -5.112077E-03 -1.416364E-01 -2.343860E-03 -2.097978E-01 -8.245740E-03 -2.159614E-01 -6.154601E-03 -2.038247E-01 -5.452430E-03 -9.120379E-02 -1.840216E-03 -1.349742E-01 -2.504188E-03 -1.795569E-01 -4.117727E-03 -2.675136E-01 -8.973198E-03 -3.044579E-01 -1.168982E-02 -3.003136E-01 -1.182153E-02 -4.441106E-01 -2.285936E-02 -3.907089E-01 -1.770627E-02 -3.345364E-01 -1.299223E-02 -1.614780E-01 -3.943314E-03 -1.518321E-01 -3.298050E-03 -1.476469E-01 -3.292917E-03 -2.898729E-01 -1.012881E-02 -3.831674E-01 -1.706626E-02 -5.444391E-01 -3.551092E-02 -5.883316E-01 -3.857351E-02 -8.055244E-01 -7.407530E-02 -5.029322E-01 -3.156083E-02 -4.112561E-01 -2.349214E-02 -2.865882E-01 -9.222808E-03 -1.315274E-01 -2.025984E-03 -1.692347E-01 -5.943449E-03 -2.561683E-01 -9.086015E-03 -6.853967E-01 -5.662300E-02 -7.696698E-01 -7.205977E-02 -1.205382E+00 -1.530951E-01 -1.516911E+00 -2.710712E-01 -6.441196E-01 -4.644860E-02 -5.631822E-01 -4.613548E-02 -4.366129E-01 -2.169977E-02 -1.360192E-01 -2.392896E-03 -2.663718E-01 -9.395499E-03 -3.537282E-01 -1.600143E-02 -7.998053E-01 -7.670496E-02 -1.124722E+00 -1.372134E-01 -4.114708E+00 -1.791984E+00 -3.713956E+00 -1.432033E+00 -1.553058E+00 -2.512378E-01 -6.135941E-01 -4.664131E-02 -2.960858E-01 -1.062685E-02 -2.126076E-01 -6.791986E-03 -1.776585E-01 -4.588826E-03 -4.009987E-01 -1.935283E-02 -6.974237E-01 -5.462807E-02 -1.172320E+00 -1.490257E-01 -4.632606E+00 -2.269726E+00 -4.302933E+00 -1.909275E+00 -1.441901E+00 -2.253633E-01 -6.946025E-01 -5.477741E-02 -3.028572E-01 -9.995543E-03 -2.664800E-01 -8.114532E-03 -1.790515E-01 -4.363179E-03 -3.219591E-01 -1.154933E-02 -4.766048E-01 -2.623379E-02 -6.590219E-01 -5.182644E-02 -1.344103E+00 -1.870469E-01 -1.520658E+00 -2.437423E-01 -8.249516E-01 -8.014323E-02 -4.799528E-01 -2.728872E-02 -3.338091E-01 -1.258397E-02 -1.726451E-01 -3.517931E-03 -1.903056E-01 -5.121011E-03 -2.235869E-01 -6.195184E-03 -4.092350E-01 -1.860896E-02 -6.443407E-01 -4.753054E-02 -7.434275E-01 -6.152443E-02 -6.963186E-01 -5.524192E-02 -7.270762E-01 -6.487099E-02 -4.104319E-01 -2.113108E-02 -2.610332E-01 -8.341277E-03 -2.276467E-01 -7.079821E-03 -1.199303E-01 -2.107276E-03 -2.344765E-01 -7.515146E-03 -2.451220E-01 -8.310971E-03 -3.329565E-01 -1.431369E-02 -4.870420E-01 -2.883252E-02 -4.388732E-01 -2.334318E-02 -2.729832E-01 -1.331202E-02 -2.744247E-01 -9.030846E-03 -1.839791E-01 -4.150617E-03 -1.213890E-01 -3.277981E-03 -1.343672E-01 -2.619580E-03 -1.130422E-01 -2.462443E-03 -1.459336E-01 -2.484655E-03 -2.470614E-01 -7.228380E-03 -3.720114E-01 -1.471500E-02 -1.858744E-01 -4.441917E-03 -1.994268E-01 -4.419502E-03 -1.569202E-01 -3.503970E-03 -1.060675E-01 -1.816154E-03 -7.163514E-02 -8.735272E-04 -1.348760E-01 -3.157312E-03 -1.387692E-01 -2.620702E-03 -1.253738E-01 -2.347752E-03 -1.537875E-01 -3.483744E-03 -2.131755E-01 -5.511261E-03 -1.743480E-01 -3.911447E-03 -2.494725E-01 -7.777487E-03 -2.239382E-01 -7.615366E-03 -1.303960E-01 -2.333665E-03 -5.381387E-02 -3.817146E-04 -1.241519E-01 -2.433480E-03 -2.044311E-01 -4.786937E-03 -2.139543E-01 -6.602658E-03 -1.648073E-01 -3.517309E-03 -2.594795E-01 -9.019644E-03 -3.528032E-01 -1.338298E-02 -3.380248E-01 -1.227721E-02 -2.624372E-01 -8.835121E-03 -1.442538E-01 -3.516238E-03 -8.640530E-02 -1.102412E-03 -2.318335E-01 -6.603252E-03 -3.742742E-01 -1.745484E-02 -5.122567E-01 -3.062512E-02 -4.337463E-01 -2.546284E-02 -5.554541E-01 -3.321204E-02 -5.067434E-01 -2.756649E-02 -4.865666E-01 -2.851594E-02 -3.170831E-01 -1.371214E-02 -2.129101E-01 -6.053342E-03 -2.128070E-01 -7.648402E-03 -1.255629E-01 -1.948581E-03 -3.102388E-01 -1.048609E-02 -5.023490E-01 -3.068085E-02 -7.297304E-01 -6.002099E-02 -7.643998E-01 -7.101610E-02 -8.513612E-01 -8.749837E-02 -6.346410E-01 -4.868689E-02 -3.918803E-01 -2.306037E-02 -3.228690E-01 -1.113733E-02 -1.888798E-01 -5.346454E-03 -2.238570E-01 -5.467591E-03 -2.966176E-01 -1.248345E-02 -5.167505E-01 -3.402812E-02 -8.408580E-01 -7.498379E-02 -1.177612E+00 -1.493796E-01 -1.213429E+00 -1.710532E-01 -7.914586E-01 -8.003283E-02 -6.569462E-01 -4.890438E-02 -4.014122E-01 -1.892526E-02 -1.741005E-01 -3.674254E-03 -1.958982E-01 -5.115746E-03 -3.647228E-01 -1.505221E-02 -5.296653E-01 -2.974185E-02 -8.741589E-01 -8.241692E-02 -1.160357E+00 -1.460044E-01 -1.242926E+00 -1.872176E-01 -7.404224E-01 -7.498948E-02 -4.157637E-01 -2.024853E-02 -3.331424E-01 -1.418197E-02 -1.662525E-01 -3.292552E-03 -1.756303E-01 -4.247818E-03 -3.095415E-01 -1.142281E-02 -4.457274E-01 -2.647548E-02 -8.198863E-01 -7.837270E-02 -8.282276E-01 -7.382650E-02 -9.034572E-01 -9.315387E-02 -6.713558E-01 -6.787067E-02 -4.095750E-01 -1.979096E-02 -4.342550E-01 -2.175150E-02 -1.322553E-01 -2.335662E-03 -7.877879E-02 -1.036092E-03 -2.712902E-01 -1.019092E-02 -3.167190E-01 -1.335793E-02 -5.158618E-01 -3.370797E-02 -5.676681E-01 -3.856145E-02 -4.544440E-01 -2.549015E-02 -4.432888E-01 -2.126301E-02 -3.161041E-01 -1.234645E-02 -2.562026E-01 -7.985736E-03 -1.563374E-01 -3.245008E-03 -8.863898E-02 -1.306731E-03 -1.548733E-01 -3.412279E-03 -3.079218E-01 -1.069274E-02 -3.174567E-01 -1.269551E-02 -3.884142E-01 -1.709017E-02 -3.349271E-01 -1.222785E-02 -3.044983E-01 -1.423699E-02 -2.903925E-01 -9.489097E-03 -1.487595E-01 -2.773453E-03 -1.494058E-01 -2.846313E-03 -4.625762E-02 -6.009114E-04 -8.974298E-02 -9.375211E-04 -1.601786E-01 -4.585595E-03 -1.785646E-01 -4.336702E-03 -2.477972E-01 -7.750073E-03 -2.297032E-01 -6.245973E-03 -1.883691E-01 -4.541820E-03 -1.590142E-01 -3.260631E-03 -1.554108E-01 -4.270743E-03 -7.224886E-02 -8.834373E-04 -9.019638E-02 -1.611295E-03 -1.303901E-01 -2.764679E-03 -1.222936E-01 -2.240408E-03 -1.581304E-01 -3.695801E-03 -1.808779E-01 -3.998170E-03 -1.889571E-01 -4.444562E-03 -1.943967E-01 -4.459891E-03 -1.426015E-01 -2.562593E-03 -9.883790E-02 -1.983226E-03 -7.007983E-02 -7.319313E-04 -1.280076E-01 -2.520103E-03 -2.289759E-01 -6.569922E-03 -2.383089E-01 -6.703841E-03 -2.643140E-01 -9.790031E-03 -2.811310E-01 -8.775540E-03 -2.387165E-01 -7.680438E-03 -2.082093E-01 -4.991376E-03 -1.666022E-01 -5.373828E-03 -1.149541E-01 -1.639607E-03 -1.220668E-01 -2.216590E-03 -1.340186E-01 -2.951310E-03 -2.402611E-01 -6.073468E-03 -2.713634E-01 -8.566663E-03 -3.660427E-01 -1.616450E-02 -3.595602E-01 -1.586479E-02 -4.709360E-01 -2.736173E-02 -3.929542E-01 -1.710164E-02 -2.484219E-01 -8.065603E-03 -1.636269E-01 -3.625941E-03 -1.083314E-01 -1.503478E-03 -1.510553E-01 -3.275953E-03 -2.604648E-01 -7.914689E-03 -4.659340E-01 -2.706966E-02 -4.604958E-01 -2.466857E-02 -6.423896E-01 -5.370929E-02 -4.993435E-01 -3.139490E-02 -4.512831E-01 -2.316067E-02 -3.742188E-01 -1.866260E-02 -2.498718E-01 -9.012857E-03 -1.514092E-01 -3.487353E-03 -1.216650E-01 -2.493133E-03 -3.141187E-01 -1.212145E-02 -3.573130E-01 -1.672769E-02 -4.548534E-01 -2.472124E-02 -6.482388E-01 -4.852353E-02 -7.058570E-01 -5.448241E-02 -6.148571E-01 -4.270398E-02 -4.455893E-01 -2.579049E-02 -3.074559E-01 -1.128795E-02 -1.589893E-01 -3.478790E-03 -1.619699E-01 -3.585731E-03 -3.432049E-01 -1.277974E-02 -3.770375E-01 -1.987838E-02 -4.941913E-01 -2.727393E-02 -7.067789E-01 -5.775428E-02 -6.507162E-01 -4.675889E-02 -4.514535E-01 -2.501083E-02 -4.060220E-01 -1.794153E-02 -2.870835E-01 -9.368435E-03 -2.032184E-01 -5.194567E-03 -1.500232E-01 -3.209360E-03 -2.247567E-01 -6.429339E-03 -4.176628E-01 -2.402640E-02 -4.329508E-01 -2.267303E-02 -6.043048E-01 -3.982372E-02 -5.849860E-01 -3.657295E-02 -3.903656E-01 -2.120434E-02 -3.543847E-01 -1.568913E-02 -2.824890E-01 -9.829374E-03 -1.446874E-01 -3.872867E-03 -9.609740E-02 -1.572744E-03 -3.043448E-01 -1.189455E-02 -3.284045E-01 -1.210523E-02 -3.703590E-01 -1.909858E-02 -3.991370E-01 -1.981940E-02 -3.532581E-01 -1.465522E-02 -3.160296E-01 -1.372436E-02 -3.333697E-01 -1.223435E-02 -2.249296E-01 -6.801086E-03 -1.628327E-01 -3.377881E-03 -7.079336E-02 -8.561171E-04 -1.105650E-01 -1.955407E-03 -1.589050E-01 -3.902915E-03 -2.414331E-01 -7.590068E-03 -2.176293E-01 -5.727003E-03 -2.726467E-01 -9.337718E-03 -1.818539E-01 -3.576974E-03 -2.180168E-01 -6.336070E-03 -1.903736E-01 -5.558784E-03 -1.433931E-01 -2.788824E-03 -8.437203E-02 -1.544760E-03 -1.159951E-01 -1.971890E-03 -1.542921E-01 -2.942637E-03 -1.798106E-01 -4.414091E-03 -2.351155E-01 -6.895402E-03 -1.878790E-01 -5.021441E-03 -1.615985E-01 -3.901096E-03 -1.133366E-01 -1.754982E-03 -8.959341E-02 -1.548148E-03 -4.455245E-02 -4.150367E-04 -9.594518E-02 -1.952932E-03 -6.555887E-02 -7.561836E-04 -1.323975E-01 -2.792090E-03 -1.823800E-01 -6.046172E-03 -1.840112E-01 -5.611376E-03 -1.405650E-01 -4.207768E-03 -9.692459E-02 -1.219361E-03 -6.977514E-02 -7.637517E-04 -5.313139E-02 -5.751260E-04 -4.631552E-02 -5.181770E-04 -9.495661E-02 -1.419966E-03 -1.200447E-01 -2.077537E-03 -1.952442E-01 -4.590395E-03 -1.471117E-01 -3.028305E-03 -1.514228E-01 -2.942798E-03 -3.062551E-01 -1.122418E-02 -1.534497E-01 -2.980148E-03 -1.773128E-01 -4.163631E-03 -1.581280E-01 -3.230054E-03 -1.026207E-01 -1.722791E-03 -9.727136E-02 -1.353541E-03 -1.833104E-01 -4.064796E-03 -1.726271E-01 -3.698889E-03 -2.777797E-01 -1.009800E-02 -2.297180E-01 -6.584276E-03 -3.227158E-01 -1.178834E-02 -2.630960E-01 -9.478703E-03 -2.057216E-01 -5.184325E-03 -1.381855E-01 -3.483987E-03 -1.207644E-01 -2.491839E-03 -1.020355E-01 -1.285191E-03 -2.413347E-01 -7.206284E-03 -1.830190E-01 -4.936379E-03 -2.466750E-01 -7.737265E-03 -3.667100E-01 -1.823639E-02 -3.886601E-01 -1.908900E-02 -3.063991E-01 -1.145076E-02 -3.179609E-01 -1.267020E-02 -2.640979E-01 -8.849372E-03 -1.324137E-01 -3.423783E-03 -1.674432E-01 -3.867189E-03 -2.387486E-01 -7.617983E-03 -2.702949E-01 -9.072068E-03 -3.509396E-01 -1.367373E-02 -4.669900E-01 -2.481995E-02 -4.539417E-01 -2.445131E-02 -2.804180E-01 -9.256761E-03 -2.204163E-01 -5.757785E-03 -1.688854E-01 -3.626841E-03 -1.799124E-01 -4.569449E-03 -1.357315E-01 -3.117868E-03 -1.939662E-01 -4.609676E-03 -1.811233E-01 -4.001677E-03 -3.023547E-01 -1.006813E-02 -3.852946E-01 -1.646521E-02 -3.947190E-01 -1.652818E-02 -3.308085E-01 -1.319117E-02 -2.203472E-01 -7.096957E-03 -2.084519E-01 -6.333576E-03 -1.446787E-01 -3.971664E-03 -8.614610E-02 -1.069819E-03 -2.193677E-01 -8.326726E-03 -2.076369E-01 -4.682464E-03 -1.696243E-01 -3.956462E-03 -3.992762E-01 -1.931929E-02 -3.307711E-01 -1.232965E-02 -2.639926E-01 -8.553712E-03 -2.907994E-01 -1.195800E-02 -2.069794E-01 -4.706478E-03 -9.533912E-02 -1.278173E-03 -1.053247E-01 -1.903155E-03 -1.837208E-01 -5.173191E-03 -1.636891E-01 -4.284691E-03 -2.284680E-01 -8.035892E-03 -2.300168E-01 -5.784482E-03 -2.519821E-01 -8.684849E-03 -2.271669E-01 -6.331342E-03 -2.491848E-01 -7.449392E-03 -2.027002E-01 -4.880471E-03 -9.012995E-02 -1.564717E-03 -9.958124E-02 -1.614296E-03 -1.735102E-01 -5.642665E-03 -1.785074E-01 -4.132173E-03 -1.933132E-01 -5.239277E-03 -2.139676E-01 -6.356521E-03 -2.015977E-01 -5.099277E-03 -2.039189E-01 -7.545412E-03 -2.075736E-01 -7.064068E-03 -1.061529E-01 -1.352122E-03 -3.214966E-02 -1.717861E-04 -3.339740E-02 -2.480850E-04 -1.110320E-01 -2.164188E-03 -9.636462E-02 -1.094431E-03 -1.497850E-01 -5.420438E-03 -1.496108E-01 -2.948765E-03 -1.408888E-01 -2.897433E-03 -1.338729E-01 -2.922319E-03 -5.711633E-02 -4.306501E-04 -7.981911E-02 -8.325283E-04 -5.180954E-02 -5.871992E-04 -3.142337E-02 -2.743459E-04 -7.558078E-02 -1.440107E-03 -6.749596E-02 -7.121686E-04 -4.742528E-02 -3.421264E-04 -1.152645E-01 -2.543824E-03 -1.034826E-01 -1.553063E-03 -7.780836E-02 -1.674226E-03 -2.486040E-02 -1.152553E-04 -5.118031E-02 -4.782731E-04 -6.164448E-02 -1.090465E-03 -5.579780E-02 -5.469202E-04 -9.835519E-02 -1.561650E-03 -1.590188E-01 -3.559315E-03 -9.123141E-02 -1.186111E-03 -9.257051E-02 -1.160366E-03 -1.595071E-01 -3.372622E-03 -8.648914E-02 -1.391423E-03 -9.915992E-02 -1.496092E-03 -6.159336E-02 -7.871872E-04 -7.703115E-02 -8.995936E-04 -8.644781E-02 -1.794389E-03 -8.281040E-02 -1.022772E-03 -1.198087E-01 -2.578187E-03 -1.046543E-01 -2.073804E-03 -1.485974E-01 -3.372341E-03 -1.899240E-01 -5.053348E-03 -1.495518E-01 -3.346868E-03 -1.523611E-01 -2.626194E-03 -1.483976E-01 -3.461823E-03 -1.189640E-01 -2.194057E-03 -7.910820E-02 -1.021972E-03 -1.408445E-01 -2.513931E-03 -1.785598E-01 -6.539443E-03 -1.627058E-01 -4.133768E-03 -1.417975E-01 -2.575062E-03 -1.453104E-01 -3.242010E-03 -1.545322E-01 -2.888223E-03 -2.238452E-01 -8.182427E-03 -1.208627E-01 -2.044210E-03 -8.317750E-02 -1.508722E-03 -9.945978E-02 -1.606528E-03 -1.100115E-01 -1.679926E-03 -1.682495E-01 -3.387004E-03 -2.038347E-01 -5.001616E-03 -1.661126E-01 -3.716273E-03 -1.719126E-01 -4.353756E-03 -2.127676E-01 -7.068298E-03 -1.596044E-01 -3.435511E-03 -9.171613E-02 -1.258097E-03 -7.909923E-02 -1.167334E-03 -8.070294E-02 -1.198068E-03 -9.480490E-02 -1.184376E-03 -1.091868E-01 -1.673174E-03 -1.686522E-01 -3.814685E-03 -2.045902E-01 -4.997184E-03 -2.218509E-01 -5.932778E-03 -2.568657E-01 -9.334526E-03 -1.632220E-01 -4.266101E-03 -8.403406E-02 -1.398023E-03 -8.197852E-02 -9.887532E-04 -7.879086E-02 -1.433937E-03 -1.228523E-01 -2.416939E-03 -1.862098E-01 -4.308366E-03 -2.142186E-01 -8.247066E-03 -2.268010E-01 -6.502538E-03 -1.402457E-01 -2.618558E-03 -1.260213E-01 -2.059778E-03 -1.505995E-01 -2.876582E-03 -5.116714E-02 -3.766772E-04 -1.268702E-01 -2.695645E-03 -5.638152E-02 -5.767254E-04 -1.619056E-01 -3.154405E-03 -2.354666E-01 -1.065017E-02 -1.278153E-01 -2.300850E-03 -1.582320E-01 -3.193514E-03 -1.851274E-01 -5.144918E-03 -1.462501E-01 -3.549186E-03 -1.385494E-01 -3.784085E-03 -6.277077E-02 -8.146319E-04 -7.619565E-02 -1.435724E-03 -1.261746E-01 -3.287745E-03 -5.858084E-02 -5.268907E-04 -1.326578E-01 -2.611109E-03 -1.378942E-01 -2.421025E-03 -1.281363E-01 -1.960588E-03 -1.071155E-01 -1.748974E-03 -1.014830E-01 -1.540688E-03 -1.167308E-01 -3.039772E-03 -8.499870E-02 -1.048605E-03 -5.967367E-02 -1.011919E-03 -6.384520E-02 -1.050476E-03 -5.379547E-02 -4.842685E-04 -9.714870E-02 -1.167567E-03 -1.193232E-01 -2.711280E-03 -6.956983E-02 -7.545215E-04 -1.085462E-01 -2.036623E-03 -6.352672E-02 -7.273361E-04 -3.554724E-02 -4.034308E-04 -1.147332E-01 -3.617311E-03 -8.657826E-02 -1.515787E-03 -tally 2: -3.142337E-02 -2.743459E-04 -9.594518E-02 -1.952932E-03 -9.019638E-02 -1.611295E-03 -1.348760E-01 -3.157312E-03 -7.436797E-02 -1.038777E-03 -4.555958E-02 -6.107386E-04 -5.199084E-02 -8.828006E-04 -5.105046E-02 -5.591936E-04 -1.095224E-01 -2.675022E-03 -2.084815E-02 -1.082750E-04 -5.579780E-02 -5.469202E-04 -9.495661E-02 -1.419966E-03 -1.280076E-01 -2.520103E-03 -1.241519E-01 -2.433480E-03 -1.349742E-01 -2.504188E-03 -1.141044E-01 -2.428038E-03 -1.130324E-01 -1.720356E-03 -1.137084E-01 -1.891251E-03 -9.882155E-02 -1.696404E-03 -6.040159E-02 -7.575405E-04 -8.644781E-02 -1.794389E-03 -9.727136E-02 -1.353541E-03 -1.340186E-01 -2.951310E-03 -2.318335E-01 -6.603252E-03 -1.476469E-01 -3.292917E-03 -1.666256E-01 -4.426400E-03 -1.293622E-01 -1.916729E-03 -1.918440E-01 -4.887813E-03 -1.680575E-01 -3.208887E-03 -4.923095E-02 -6.563588E-04 -7.910820E-02 -1.021972E-03 -1.020355E-01 -1.285191E-03 -1.510553E-01 -3.275953E-03 -1.255629E-01 -1.948581E-03 -1.692347E-01 -5.943449E-03 -1.672928E-01 -3.337911E-03 -1.558106E-01 -2.875549E-03 -1.060074E-01 -1.569679E-03 -6.877708E-02 -1.029829E-03 -8.362502E-02 -1.022521E-03 -9.945978E-02 -1.606528E-03 -1.674432E-01 -3.867189E-03 -1.216650E-01 -2.493133E-03 -2.238570E-01 -5.467591E-03 -2.663718E-01 -9.395499E-03 -2.244663E-01 -5.650733E-03 -1.682990E-01 -3.326460E-03 -1.290019E-01 -2.856345E-03 -1.239696E-01 -2.379611E-03 -1.458566E-01 -4.113559E-03 -8.070294E-02 -1.198068E-03 -1.357315E-01 -3.117868E-03 -1.619699E-01 -3.585731E-03 -1.958982E-01 -5.115746E-03 -1.776585E-01 -4.588826E-03 -2.147662E-01 -5.433421E-03 -1.627119E-01 -2.886284E-03 -1.796564E-01 -4.684076E-03 -1.086029E-01 -1.976496E-03 -8.785791E-02 -1.103156E-03 -7.879086E-02 -1.433937E-03 -8.614610E-02 -1.069819E-03 -1.500232E-01 -3.209360E-03 -1.756303E-01 -4.247818E-03 -1.790515E-01 -4.363179E-03 -1.654784E-01 -4.247475E-03 -1.886300E-01 -4.844638E-03 -1.374646E-01 -2.373831E-03 -1.262352E-01 -2.754572E-03 -2.298462E-02 -1.395953E-04 -5.638152E-02 -5.767254E-04 -1.053247E-01 -1.903155E-03 -9.609740E-02 -1.572744E-03 -7.877879E-02 -1.036092E-03 -1.903056E-01 -5.121011E-03 -1.730644E-01 -3.300158E-03 -1.346274E-01 -2.606991E-03 -9.714578E-02 -1.698684E-03 -1.273408E-01 -2.552547E-03 -5.037871E-02 -5.560040E-04 -1.261746E-01 -3.287745E-03 -9.958124E-02 -1.614296E-03 -7.079336E-02 -8.561171E-04 -8.863898E-02 -1.306731E-03 -1.199303E-01 -2.107276E-03 -2.313010E-01 -7.739556E-03 -1.577787E-01 -2.960256E-03 -8.639730E-02 -1.201841E-03 -5.659795E-02 -4.694852E-04 -5.104294E-02 -5.268938E-04 -6.384520E-02 -1.050476E-03 -3.339740E-02 -2.480850E-04 -8.437203E-02 -1.544760E-03 -4.625762E-02 -6.009114E-04 -1.343672E-01 -2.619580E-03 -1.174094E-01 -2.667947E-03 -8.357176E-02 -1.039130E-03 -4.731066E-02 -3.124630E-04 -4.749930E-02 -5.129237E-04 -3.878239E-02 -5.236943E-04 -7.558078E-02 -1.440107E-03 -6.555887E-02 -7.561836E-04 -1.303901E-01 -2.764679E-03 -1.387692E-01 -2.620702E-03 -1.410499E-01 -3.203643E-03 -1.309527E-01 -2.731943E-03 -9.589097E-02 -1.548067E-03 -5.609383E-02 -5.921134E-04 -1.096306E-01 -2.122353E-03 -6.381818E-02 -9.439513E-04 -9.835519E-02 -1.561650E-03 -1.200447E-01 -2.077537E-03 -2.289759E-01 -6.569922E-03 -2.044311E-01 -4.786937E-03 -1.795569E-01 -4.117727E-03 -1.740908E-01 -3.775648E-03 -2.114890E-01 -6.553709E-03 -1.350332E-01 -3.254232E-03 -1.354820E-01 -2.909227E-03 -1.050048E-01 -2.108780E-03 -8.281040E-02 -1.022772E-03 -1.833104E-01 -4.064796E-03 -2.402611E-01 -6.073468E-03 -3.742742E-01 -1.745484E-02 -2.898729E-01 -1.012881E-02 -2.171404E-01 -6.076897E-03 -2.979566E-01 -1.047393E-02 -2.109751E-01 -5.543123E-03 -1.422788E-01 -4.002215E-03 -9.650255E-02 -1.789194E-03 -1.408445E-01 -2.513931E-03 -2.413347E-01 -7.206284E-03 -2.604648E-01 -7.914689E-03 -3.102388E-01 -1.048609E-02 -2.561683E-01 -9.086015E-03 -2.716967E-01 -8.803461E-03 -2.977518E-01 -1.072036E-02 -3.421581E-01 -1.371034E-02 -1.976808E-01 -6.130857E-03 -1.456806E-01 -3.692821E-03 -1.100115E-01 -1.679926E-03 -2.387486E-01 -7.617983E-03 -3.141187E-01 -1.212145E-02 -2.966176E-01 -1.248345E-02 -3.537282E-01 -1.600143E-02 -3.340151E-01 -1.419108E-02 -2.809424E-01 -1.063357E-02 -2.844146E-01 -9.114045E-03 -2.163287E-01 -5.949023E-03 -2.049774E-01 -6.265197E-03 -9.480490E-02 -1.184376E-03 -1.939662E-01 -4.609676E-03 -3.432049E-01 -1.277974E-02 -3.647228E-01 -1.505221E-02 -4.009987E-01 -1.935283E-02 -3.138361E-01 -1.254893E-02 -3.438278E-01 -1.334226E-02 -2.812314E-01 -1.216852E-02 -2.603220E-01 -8.391117E-03 -1.709025E-01 -4.264016E-03 -1.228523E-01 -2.416939E-03 -2.193677E-01 -8.326726E-03 -2.247567E-01 -6.429339E-03 -3.095415E-01 -1.142281E-02 -3.219591E-01 -1.154933E-02 -2.649194E-01 -1.051513E-02 -2.305332E-01 -6.488165E-03 -2.399512E-01 -9.436021E-03 -2.213458E-01 -6.719185E-03 -1.570027E-01 -4.835079E-03 -1.619056E-01 -3.154405E-03 -1.837208E-01 -5.173191E-03 -3.043448E-01 -1.189455E-02 -2.712902E-01 -1.019092E-02 -2.235869E-01 -6.195184E-03 -2.265572E-01 -7.086879E-03 -2.151576E-01 -5.865290E-03 -1.688968E-01 -3.770170E-03 -1.499070E-01 -3.571856E-03 -8.289459E-02 -1.268000E-03 -5.858084E-02 -5.268907E-04 -1.735102E-01 -5.642665E-03 -1.105650E-01 -1.955407E-03 -1.548733E-01 -3.412279E-03 -2.344765E-01 -7.515146E-03 -2.374439E-01 -8.831961E-03 -1.659923E-01 -3.686020E-03 -1.449879E-01 -2.972972E-03 -9.581840E-02 -1.386427E-03 -9.139465E-02 -1.164619E-03 -5.379547E-02 -4.842685E-04 -1.110320E-01 -2.164188E-03 -1.159951E-01 -1.971890E-03 -8.974298E-02 -9.375211E-04 -1.130422E-01 -2.462443E-03 -1.443079E-01 -2.844402E-03 -1.492118E-01 -3.605953E-03 -8.581231E-02 -1.170765E-03 -6.919528E-02 -9.104379E-04 -6.099196E-02 -1.095513E-03 -6.749596E-02 -7.121686E-04 -1.323975E-01 -2.792090E-03 -1.222936E-01 -2.240408E-03 -1.253738E-01 -2.347752E-03 -9.735284E-02 -1.185189E-03 -1.264672E-01 -2.142006E-03 -1.287095E-01 -3.340920E-03 -9.705482E-02 -1.351531E-03 -1.342330E-01 -3.619967E-03 -1.155641E-01 -2.178751E-03 -1.590188E-01 -3.559315E-03 -1.952442E-01 -4.590395E-03 -2.383089E-01 -6.703841E-03 -2.139543E-01 -6.602658E-03 -2.675136E-01 -8.973198E-03 -1.944806E-01 -4.977204E-03 -1.990033E-01 -5.173772E-03 -1.906275E-01 -4.961645E-03 -1.599751E-01 -2.957031E-03 -1.307457E-01 -2.170448E-03 -1.198087E-01 -2.578187E-03 -1.726271E-01 -3.698889E-03 -2.713634E-01 -8.566663E-03 -5.122567E-01 -3.062512E-02 -3.831674E-01 -1.706626E-02 -3.633640E-01 -1.502241E-02 -3.451328E-01 -1.555073E-02 -2.472924E-01 -8.124732E-03 -1.762382E-01 -4.255455E-03 -1.467738E-01 -3.481509E-03 -1.785598E-01 -6.539443E-03 -1.830190E-01 -4.936379E-03 -4.659340E-01 -2.706966E-02 -5.023490E-01 -3.068085E-02 -6.853967E-01 -5.662300E-02 -5.682403E-01 -3.764689E-02 -6.281147E-01 -4.728417E-02 -4.542071E-01 -2.517473E-02 -3.144113E-01 -1.232063E-02 -1.468696E-01 -3.582954E-03 -1.682495E-01 -3.387004E-03 -2.702949E-01 -9.072068E-03 -3.573130E-01 -1.672769E-02 -5.167505E-01 -3.402812E-02 -7.998053E-01 -7.670496E-02 -5.201277E-01 -3.061828E-02 -3.850550E-01 -2.020363E-02 -4.560916E-01 -2.713184E-02 -2.072743E-01 -5.179000E-03 -2.166930E-01 -7.983860E-03 -1.091868E-01 -1.673174E-03 -1.811233E-01 -4.001677E-03 -3.770375E-01 -1.987838E-02 -5.296653E-01 -2.974185E-02 -6.974237E-01 -5.462807E-02 -6.467791E-01 -4.949991E-02 -4.891845E-01 -3.041285E-02 -4.240103E-01 -2.176819E-02 -2.841149E-01 -1.105366E-02 -1.929437E-01 -4.281538E-03 -1.862098E-01 -4.308366E-03 -2.076369E-01 -4.682464E-03 -4.176628E-01 -2.402640E-02 -4.457274E-01 -2.647548E-02 -4.766048E-01 -2.623379E-02 -6.278811E-01 -4.683999E-02 -4.823482E-01 -2.794296E-02 -4.641786E-01 -2.746647E-02 -3.023706E-01 -1.146381E-02 -1.123717E-01 -1.760314E-03 -2.354666E-01 -1.065017E-02 -1.636891E-01 -4.284691E-03 -3.284045E-01 -1.210523E-02 -3.167190E-01 -1.335793E-02 -4.092350E-01 -1.860896E-02 -4.539714E-01 -2.260730E-02 -3.725391E-01 -1.667519E-02 -2.795405E-01 -9.154147E-03 -2.199953E-01 -7.783541E-03 -1.469691E-01 -4.146173E-03 -1.326578E-01 -2.611109E-03 -1.785074E-01 -4.132173E-03 -1.589050E-01 -3.902915E-03 -3.079218E-01 -1.069274E-02 -2.451220E-01 -8.310971E-03 -2.928583E-01 -1.186840E-02 -2.064830E-01 -6.139283E-03 -1.801392E-01 -3.863618E-03 -2.009835E-01 -6.159157E-03 -7.378130E-02 -1.282188E-03 -9.714870E-02 -1.167567E-03 -9.636462E-02 -1.094431E-03 -1.542921E-01 -2.942637E-03 -1.601786E-01 -4.585595E-03 -1.459336E-01 -2.484655E-03 -9.912399E-02 -1.868517E-03 -1.685975E-01 -3.436440E-03 -2.015455E-01 -5.727404E-03 -1.119151E-01 -2.477462E-03 -9.150086E-02 -1.624380E-03 -4.742528E-02 -3.421264E-04 -1.823800E-01 -6.046172E-03 -1.581304E-01 -3.695801E-03 -1.537875E-01 -3.483744E-03 -1.816982E-01 -4.474357E-03 -3.000507E-01 -1.065688E-02 -2.500082E-01 -7.508730E-03 -1.601898E-01 -3.408525E-03 -1.114064E-01 -1.730639E-03 -6.865908E-02 -7.355866E-04 -9.123141E-02 -1.186111E-03 -1.471117E-01 -3.028305E-03 -2.643140E-01 -9.790031E-03 -1.648073E-01 -3.517309E-03 -3.044579E-01 -1.168982E-02 -2.742895E-01 -8.190026E-03 -3.695621E-01 -1.648852E-02 -2.657405E-01 -8.636878E-03 -2.280781E-01 -6.081628E-03 -9.988454E-02 -1.092936E-03 -1.046543E-01 -2.073804E-03 -2.777797E-01 -1.009800E-02 -3.660427E-01 -1.616450E-02 -4.337463E-01 -2.546284E-02 -5.444391E-01 -3.551092E-02 -5.792842E-01 -3.974284E-02 -4.833176E-01 -2.633603E-02 -4.210681E-01 -1.934743E-02 -2.502725E-01 -7.152209E-03 -1.687123E-01 -5.414669E-03 -1.627058E-01 -4.133768E-03 -2.466750E-01 -7.737265E-03 -4.604958E-01 -2.466857E-02 -7.297304E-01 -6.002099E-02 -7.696698E-01 -7.205977E-02 -8.144576E-01 -8.737915E-02 -6.712593E-01 -4.960413E-02 -5.784381E-01 -3.768770E-02 -3.018257E-01 -1.124658E-02 -1.848215E-01 -5.256814E-03 -2.038347E-01 -5.001616E-03 -3.509396E-01 -1.367373E-02 -4.548534E-01 -2.472124E-02 -8.408580E-01 -7.498379E-02 -1.124722E+00 -1.372134E-01 -1.212509E+00 -1.609699E-01 -8.686055E-01 -8.923119E-02 -7.260552E-01 -5.922762E-02 -3.646146E-01 -1.695667E-02 -1.757110E-01 -5.024516E-03 -1.686522E-01 -3.814685E-03 -3.023547E-01 -1.006813E-02 -4.941913E-01 -2.727393E-02 -8.741589E-01 -8.241692E-02 -1.172320E+00 -1.490257E-01 -1.292908E+00 -1.841406E-01 -8.909073E-01 -9.620969E-02 -5.209518E-01 -3.000472E-02 -3.965469E-01 -1.974149E-02 -1.711011E-01 -3.912611E-03 -2.142186E-01 -8.247066E-03 -1.696243E-01 -3.956462E-03 -4.329508E-01 -2.267303E-02 -8.198863E-01 -7.837270E-02 -6.590219E-01 -5.182644E-02 -8.592361E-01 -8.990276E-02 -7.462144E-01 -6.544856E-02 -4.258629E-01 -2.112979E-02 -3.282506E-01 -1.233694E-02 -1.821249E-01 -6.802302E-03 -1.278153E-01 -2.300850E-03 -2.284680E-01 -8.035892E-03 -3.703590E-01 -1.909858E-02 -5.158618E-01 -3.370797E-02 -6.443407E-01 -4.753054E-02 -4.526763E-01 -2.455356E-02 -4.869630E-01 -2.818017E-02 -3.109678E-01 -1.173563E-02 -2.453178E-01 -7.052370E-03 -1.075211E-01 -1.625602E-03 -1.378942E-01 -2.421025E-03 -1.933132E-01 -5.239277E-03 -2.414331E-01 -7.590068E-03 -3.174567E-01 -1.269551E-02 -3.329565E-01 -1.431369E-02 -2.940020E-01 -9.794156E-03 -3.154830E-01 -1.105998E-02 -1.936577E-01 -4.483865E-03 -1.897439E-01 -7.235399E-03 -8.021098E-02 -7.940912E-04 -1.193232E-01 -2.711280E-03 -1.497850E-01 -5.420438E-03 -1.798106E-01 -4.414091E-03 -1.785646E-01 -4.336702E-03 -2.470614E-01 -7.228380E-03 -2.216936E-01 -5.865658E-03 -1.741635E-01 -4.786790E-03 -1.747214E-01 -3.928453E-03 -1.102521E-01 -1.584592E-03 -5.728387E-02 -5.659010E-04 -1.152645E-01 -2.543824E-03 -1.840112E-01 -5.611376E-03 -1.808779E-01 -3.998170E-03 -2.131755E-01 -5.511261E-03 -2.007849E-01 -5.112077E-03 -3.237002E-01 -1.209173E-02 -1.935346E-01 -5.219674E-03 -1.711068E-01 -3.795257E-03 -1.074251E-01 -1.586218E-03 -6.720820E-02 -7.310529E-04 -9.257051E-02 -1.160366E-03 -1.514228E-01 -2.942798E-03 -2.811310E-01 -8.775540E-03 -2.594795E-01 -9.019644E-03 -3.003136E-01 -1.182153E-02 -4.026905E-01 -1.975388E-02 -3.985679E-01 -1.776400E-02 -3.845292E-01 -1.700936E-02 -2.100930E-01 -5.450110E-03 -1.547083E-01 -3.688477E-03 -1.485974E-01 -3.372341E-03 -2.297180E-01 -6.584276E-03 -3.595602E-01 -1.586479E-02 -5.554541E-01 -3.321204E-02 -5.883316E-01 -3.857351E-02 -6.573016E-01 -5.041895E-02 -5.627698E-01 -3.356380E-02 -3.735043E-01 -1.670088E-02 -3.414429E-01 -1.411003E-02 -1.873036E-01 -4.734353E-03 -1.417975E-01 -2.575062E-03 -3.667100E-01 -1.823639E-02 -6.423896E-01 -5.370929E-02 -7.643998E-01 -7.101610E-02 -1.205382E+00 -1.530951E-01 -1.222427E+00 -1.615304E-01 -1.056883E+00 -1.367649E-01 -4.172596E-01 -1.856012E-02 -2.619717E-01 -8.351589E-03 -2.212472E-01 -5.760540E-03 -1.661126E-01 -3.716273E-03 -4.669900E-01 -2.481995E-02 -6.482388E-01 -4.852353E-02 -1.177612E+00 -1.493796E-01 -4.114708E+00 -1.791984E+00 -4.267920E+00 -1.910806E+00 -1.305252E+00 -2.173314E-01 -7.310584E-01 -6.237152E-02 -3.486264E-01 -1.301568E-02 -2.353728E-01 -7.533032E-03 -2.045902E-01 -4.997184E-03 -3.852946E-01 -1.646521E-02 -7.067789E-01 -5.775428E-02 -1.160357E+00 -1.460044E-01 -4.632606E+00 -2.269726E+00 -4.571133E+00 -2.199170E+00 -1.255312E+00 -1.734311E-01 -6.504938E-01 -4.819256E-02 -3.901607E-01 -1.960621E-02 -1.562002E-01 -3.325900E-03 -2.268010E-01 -6.502538E-03 -3.992762E-01 -1.931929E-02 -6.043048E-01 -3.982372E-02 -8.282276E-01 -7.382650E-02 -1.344103E+00 -1.870469E-01 -1.382839E+00 -2.107838E-01 -9.896232E-01 -1.097631E-01 -6.864289E-01 -5.425243E-02 -2.853774E-01 -1.070129E-02 -2.461041E-01 -7.613043E-03 -1.582320E-01 -3.193514E-03 -2.300168E-01 -5.784482E-03 -3.991370E-01 -1.981940E-02 -5.676681E-01 -3.856145E-02 -7.434275E-01 -6.152443E-02 -8.380497E-01 -7.969257E-02 -6.480100E-01 -5.048920E-02 -3.911757E-01 -1.773775E-02 -2.643229E-01 -9.900690E-03 -2.187908E-01 -6.919967E-03 -1.281363E-01 -1.960588E-03 -2.139676E-01 -6.356521E-03 -2.176293E-01 -5.727003E-03 -3.884142E-01 -1.709017E-02 -4.870420E-01 -2.883252E-02 -4.513060E-01 -2.594396E-02 -4.082087E-01 -1.828447E-02 -2.453357E-01 -9.056291E-03 -1.830639E-01 -5.540521E-03 -1.290978E-01 -2.526036E-03 -6.956983E-02 -7.545215E-04 -1.496108E-01 -2.948765E-03 -2.351155E-01 -6.895402E-03 -2.477972E-01 -7.750073E-03 -3.720114E-01 -1.471500E-02 -2.574848E-01 -7.753799E-03 -1.890091E-01 -4.516094E-03 -1.459763E-01 -2.610376E-03 -1.564084E-01 -3.266574E-03 -9.405318E-02 -1.606034E-03 -1.034826E-01 -1.553063E-03 -1.405650E-01 -4.207768E-03 -1.889571E-01 -4.444562E-03 -1.743480E-01 -3.911447E-03 -1.416364E-01 -2.343860E-03 -2.307443E-01 -7.102755E-03 -1.617078E-01 -3.813457E-03 -2.205615E-01 -7.391402E-03 -1.408447E-01 -2.389426E-03 -9.537792E-02 -1.957273E-03 -1.595071E-01 -3.372622E-03 -3.062551E-01 -1.122418E-02 -2.387165E-01 -7.680438E-03 -3.528032E-01 -1.338298E-02 -4.441106E-01 -2.285936E-02 -4.110115E-01 -1.874949E-02 -4.317996E-01 -1.968661E-02 -2.839796E-01 -9.879629E-03 -2.732779E-01 -8.620164E-03 -8.157999E-02 -1.133034E-03 -1.899240E-01 -5.053348E-03 -3.227158E-01 -1.178834E-02 -4.709360E-01 -2.736173E-02 -5.067434E-01 -2.756649E-02 -8.055244E-01 -7.407530E-02 -5.370335E-01 -3.858979E-02 -6.205981E-01 -4.614253E-02 -4.705633E-01 -2.767424E-02 -2.636737E-01 -9.397976E-03 -1.130087E-01 -1.673004E-03 -1.453104E-01 -3.242010E-03 -3.886601E-01 -1.908900E-02 -4.993435E-01 -3.139490E-02 -8.513612E-01 -8.749837E-02 -1.516911E+00 -2.710712E-01 -1.406450E+00 -2.161620E-01 -9.587365E-01 -1.078758E-01 -5.299200E-01 -3.825470E-02 -3.672028E-01 -1.638863E-02 -2.169211E-01 -5.946348E-03 -1.719126E-01 -4.353756E-03 -4.539417E-01 -2.445131E-02 -7.058570E-01 -5.448241E-02 -1.213429E+00 -1.710532E-01 -3.713956E+00 -1.432033E+00 -4.227114E+00 -1.859722E+00 -1.246711E+00 -1.850981E-01 -6.478348E-01 -5.416126E-02 -3.563685E-01 -1.447225E-02 -1.280409E-01 -2.167446E-03 -2.218509E-01 -5.932778E-03 -3.947190E-01 -1.652818E-02 -6.507162E-01 -4.675889E-02 -1.242926E+00 -1.872176E-01 -4.302933E+00 -1.909275E+00 -4.304366E+00 -1.934972E+00 -1.169852E+00 -1.621969E-01 -5.990305E-01 -4.159076E-02 -3.509285E-01 -1.478774E-02 -2.153821E-01 -5.848786E-03 -1.402457E-01 -2.618558E-03 -3.307711E-01 -1.232965E-02 -5.849860E-01 -3.657295E-02 -9.034572E-01 -9.315387E-02 -1.520658E+00 -2.437423E-01 -1.135130E+00 -1.382627E-01 -9.014297E-01 -9.720847E-02 -6.579119E-01 -5.051533E-02 -2.848374E-01 -9.701790E-03 -1.904001E-01 -4.047242E-03 -1.851274E-01 -5.144918E-03 -2.519821E-01 -8.684849E-03 -3.532581E-01 -1.465522E-02 -4.544440E-01 -2.549015E-02 -6.963186E-01 -5.524192E-02 -6.097070E-01 -3.995479E-02 -6.074075E-01 -5.206769E-02 -4.374549E-01 -2.366240E-02 -2.574947E-01 -8.333501E-03 -1.278025E-01 -2.170886E-03 -1.071155E-01 -1.748974E-03 -2.015977E-01 -5.099277E-03 -2.726467E-01 -9.337718E-03 -3.349271E-01 -1.222785E-02 -4.388732E-01 -2.334318E-02 -3.408815E-01 -1.439810E-02 -3.712626E-01 -1.597510E-02 -2.480125E-01 -8.275523E-03 -1.520639E-01 -2.752778E-03 -9.365705E-02 -1.199392E-03 -1.085462E-01 -2.036623E-03 -1.408888E-01 -2.897433E-03 -1.878790E-01 -5.021441E-03 -2.297032E-01 -6.245973E-03 -1.858744E-01 -4.441917E-03 -2.423469E-01 -6.852465E-03 -2.283632E-01 -6.314480E-03 -1.928041E-01 -5.431526E-03 -1.198104E-01 -2.580046E-03 -8.619696E-02 -1.337493E-03 -7.780836E-02 -1.674226E-03 -9.692459E-02 -1.219361E-03 -1.943967E-01 -4.459891E-03 -2.494725E-01 -7.777487E-03 -2.097978E-01 -8.245740E-03 -1.661595E-01 -4.258378E-03 -1.854527E-01 -4.327935E-03 -1.668188E-01 -3.216331E-03 -1.301662E-01 -3.969782E-03 -1.007744E-01 -1.573169E-03 -8.648914E-02 -1.391423E-03 -1.534497E-01 -2.980148E-03 -2.082093E-01 -4.991376E-03 -3.380248E-01 -1.227721E-02 -3.907089E-01 -1.770627E-02 -2.531408E-01 -7.828810E-03 -4.168039E-01 -1.881861E-02 -2.593192E-01 -7.387676E-03 -1.993743E-01 -5.362856E-03 -1.368232E-01 -2.667957E-03 -1.495518E-01 -3.346868E-03 -2.630960E-01 -9.478703E-03 -3.929542E-01 -1.710164E-02 -4.865666E-01 -2.851594E-02 -5.029322E-01 -3.156083E-02 -6.553493E-01 -5.021005E-02 -5.667030E-01 -4.186377E-02 -4.105274E-01 -2.102523E-02 -2.247647E-01 -7.123896E-03 -1.695614E-01 -3.526426E-03 -1.545322E-01 -2.888223E-03 -3.063991E-01 -1.145076E-02 -4.512831E-01 -2.316067E-02 -6.346410E-01 -4.868689E-02 -6.441196E-01 -4.644860E-02 -9.190365E-01 -9.711802E-02 -7.458883E-01 -6.448193E-02 -5.178634E-01 -3.589903E-02 -3.059552E-01 -1.103037E-02 -1.919182E-01 -7.063068E-03 -2.127676E-01 -7.068298E-03 -2.804180E-01 -9.256761E-03 -6.148571E-01 -4.270398E-02 -7.914586E-01 -8.003283E-02 -1.553058E+00 -2.512378E-01 -1.233210E+00 -1.636276E-01 -8.484663E-01 -8.472718E-02 -4.846913E-01 -3.277993E-02 -2.970379E-01 -1.009480E-02 -1.648011E-01 -3.936025E-03 -2.568657E-01 -9.334526E-03 -3.308085E-01 -1.319117E-02 -4.514535E-01 -2.501083E-02 -7.404224E-01 -7.498948E-02 -1.441901E+00 -2.253633E-01 -1.361497E+00 -2.027947E-01 -9.218086E-01 -9.573599E-02 -5.121545E-01 -3.102991E-02 -2.714593E-01 -8.321432E-03 -1.610373E-01 -3.861192E-03 -1.260213E-01 -2.059778E-03 -2.639926E-01 -8.553712E-03 -3.903656E-01 -2.120434E-02 -6.713558E-01 -6.787067E-02 -8.249516E-01 -8.014323E-02 -9.661898E-01 -1.164265E-01 -6.453827E-01 -4.960136E-02 -4.223368E-01 -2.321407E-02 -3.176142E-01 -1.194832E-02 -2.024477E-01 -5.524067E-03 -1.462501E-01 -3.549186E-03 -2.271669E-01 -6.331342E-03 -3.160296E-01 -1.372436E-02 -4.432888E-01 -2.126301E-02 -7.270762E-01 -6.487099E-02 -6.978494E-01 -5.538934E-02 -4.501793E-01 -2.531848E-02 -4.611865E-01 -2.432741E-02 -2.455689E-01 -8.366273E-03 -9.950167E-02 -1.901085E-03 -1.014830E-01 -1.540688E-03 -2.039189E-01 -7.545412E-03 -1.818539E-01 -3.576974E-03 -3.044983E-01 -1.423699E-02 -2.729832E-01 -1.331202E-02 -3.106891E-01 -1.144803E-02 -3.971745E-01 -1.721238E-02 -2.448524E-01 -6.977697E-03 -2.084599E-01 -5.955188E-03 -6.078377E-02 -5.442247E-04 -6.352672E-02 -7.273361E-04 -1.338729E-01 -2.922319E-03 -1.615985E-01 -3.901096E-03 -1.883691E-01 -4.541820E-03 -1.994268E-01 -4.419502E-03 -2.550700E-01 -1.011995E-02 -2.656566E-01 -8.538973E-03 -1.326436E-01 -2.700926E-03 -1.828790E-01 -4.860390E-03 -1.055978E-01 -2.086153E-03 -2.486040E-02 -1.152553E-04 -6.977514E-02 -7.637517E-04 -1.426015E-01 -2.562593E-03 -2.239382E-01 -7.615366E-03 -2.159614E-01 -6.154601E-03 -1.386893E-01 -3.229314E-03 -1.469009E-01 -2.610026E-03 -1.359445E-01 -2.208925E-03 -7.949674E-02 -1.090923E-03 -9.409645E-02 -1.796197E-03 -9.915992E-02 -1.496092E-03 -1.773128E-01 -4.163631E-03 -1.666022E-01 -5.373828E-03 -2.624372E-01 -8.835121E-03 -3.345364E-01 -1.299223E-02 -2.295291E-01 -6.890997E-03 -3.168143E-01 -1.633856E-02 -1.606576E-01 -4.742954E-03 -2.198036E-01 -5.376103E-03 -1.444186E-01 -3.197937E-03 -1.523611E-01 -2.626194E-03 -2.057216E-01 -5.184325E-03 -2.484219E-01 -8.065603E-03 -3.170831E-01 -1.371214E-02 -4.112561E-01 -2.349214E-02 -4.574564E-01 -2.381874E-02 -3.633926E-01 -1.532926E-02 -4.139000E-01 -1.844845E-02 -3.224482E-01 -1.294508E-02 -2.591168E-01 -8.231726E-03 -2.238452E-01 -8.182427E-03 -3.179609E-01 -1.267020E-02 -3.742188E-01 -1.866260E-02 -3.918803E-01 -2.306037E-02 -5.631822E-01 -4.613548E-02 -5.724671E-01 -3.647197E-02 -5.376124E-01 -3.468394E-02 -4.185970E-01 -1.861497E-02 -2.486122E-01 -8.141595E-03 -1.588234E-01 -3.825511E-03 -1.596044E-01 -3.435511E-03 -2.204163E-01 -5.757785E-03 -4.455893E-01 -2.579049E-02 -6.569462E-01 -4.890438E-02 -6.135941E-01 -4.664131E-02 -6.793213E-01 -5.401213E-02 -6.548499E-01 -4.947625E-02 -4.849197E-01 -2.856176E-02 -2.762591E-01 -9.482575E-03 -1.599354E-01 -3.980976E-03 -1.632220E-01 -4.266101E-03 -2.203472E-01 -7.096957E-03 -4.060220E-01 -1.794153E-02 -4.157637E-01 -2.024853E-02 -6.946025E-01 -5.477741E-02 -6.505924E-01 -4.666856E-02 -5.068244E-01 -3.491193E-02 -3.470484E-01 -1.737934E-02 -2.293816E-01 -7.685918E-03 -2.389629E-01 -8.850896E-03 -1.505995E-01 -2.876582E-03 -2.907994E-01 -1.195800E-02 -3.543847E-01 -1.568913E-02 -4.095750E-01 -1.979096E-02 -4.799528E-01 -2.728872E-02 -5.142024E-01 -3.024987E-02 -4.680612E-01 -2.551940E-02 -4.058385E-01 -2.310793E-02 -2.880766E-01 -1.175767E-02 -1.167011E-01 -2.057180E-03 -1.385494E-01 -3.784085E-03 -2.491848E-01 -7.449392E-03 -3.333697E-01 -1.223435E-02 -3.161041E-01 -1.234645E-02 -4.104319E-01 -2.113108E-02 -4.583192E-01 -2.651122E-02 -3.790470E-01 -1.851680E-02 -2.516503E-01 -7.415388E-03 -1.782866E-01 -3.900659E-03 -1.104557E-01 -2.248074E-03 -1.167308E-01 -3.039772E-03 -2.075736E-01 -7.064068E-03 -2.180168E-01 -6.336070E-03 -2.903925E-01 -9.489097E-03 -2.744247E-01 -9.030846E-03 -3.403069E-01 -1.268580E-02 -3.019064E-01 -1.052699E-02 -2.436311E-01 -7.489666E-03 -1.319666E-01 -2.817088E-03 -7.556566E-02 -8.976997E-04 -3.554724E-02 -4.034308E-04 -5.711633E-02 -4.306501E-04 -1.133366E-01 -1.754982E-03 -1.590142E-01 -3.260631E-03 -1.569202E-01 -3.503970E-03 -1.640218E-01 -3.672006E-03 -1.402148E-01 -3.495565E-03 -1.950403E-01 -6.678626E-03 -7.542042E-02 -1.053718E-03 -8.890472E-02 -1.315673E-03 -5.118031E-02 -4.782731E-04 -5.313139E-02 -5.751260E-04 -9.883790E-02 -1.983226E-03 -1.303960E-01 -2.333665E-03 -2.038247E-01 -5.452430E-03 -8.165890E-02 -9.243538E-04 -1.461825E-01 -3.217211E-03 -9.194982E-02 -1.221828E-03 -1.074998E-01 -3.217694E-03 -7.113698E-02 -8.980335E-04 -6.159336E-02 -7.871872E-04 -1.581280E-01 -3.230054E-03 -1.149541E-01 -1.639607E-03 -1.442538E-01 -3.516238E-03 -1.614780E-01 -3.943314E-03 -2.221209E-01 -6.094039E-03 -1.765576E-01 -5.283407E-03 -1.870343E-01 -4.582302E-03 -1.502824E-01 -2.786908E-03 -1.049316E-01 -1.560309E-03 -1.483976E-01 -3.461823E-03 -1.381855E-01 -3.483987E-03 -1.636269E-01 -3.625941E-03 -2.129101E-01 -6.053342E-03 -2.865882E-01 -9.222808E-03 -3.948129E-01 -1.754777E-02 -1.863158E-01 -4.282436E-03 -2.302657E-01 -6.040845E-03 -1.622669E-01 -3.583977E-03 -1.260152E-01 -2.175978E-03 -1.208627E-01 -2.044210E-03 -2.640979E-01 -8.849372E-03 -2.498718E-01 -9.012857E-03 -3.228690E-01 -1.113733E-02 -4.366129E-01 -2.169977E-02 -3.613345E-01 -1.386290E-02 -3.326626E-01 -1.382728E-02 -2.546343E-01 -8.375242E-03 -1.750139E-01 -3.956566E-03 -1.149909E-01 -1.553531E-03 -9.171613E-02 -1.258097E-03 -1.688854E-01 -3.626841E-03 -3.074559E-01 -1.128795E-02 -4.014122E-01 -1.892526E-02 -2.960858E-01 -1.062685E-02 -3.156364E-01 -1.221711E-02 -2.303342E-01 -5.911752E-03 -2.465437E-01 -7.303148E-03 -2.499264E-01 -7.462884E-03 -1.679361E-01 -3.415565E-03 -8.403406E-02 -1.398023E-03 -2.084519E-01 -6.333576E-03 -2.870835E-01 -9.368435E-03 -3.331424E-01 -1.418197E-02 -3.028572E-01 -9.995543E-03 -3.615811E-01 -1.447718E-02 -3.003659E-01 -9.829990E-03 -2.216267E-01 -5.579967E-03 -1.265740E-01 -2.312172E-03 -1.539258E-01 -3.811869E-03 -5.116714E-02 -3.766772E-04 -2.069794E-01 -4.706478E-03 -2.824890E-01 -9.829374E-03 -4.342550E-01 -2.175150E-02 -3.338091E-01 -1.258397E-02 -2.975162E-01 -9.543763E-03 -2.958141E-01 -1.060228E-02 -2.072746E-01 -5.809548E-03 -1.572435E-01 -3.553858E-03 -8.780067E-02 -1.080238E-03 -6.277077E-02 -8.146319E-04 -2.027002E-01 -4.880471E-03 -2.249296E-01 -6.801086E-03 -2.562026E-01 -7.985736E-03 -2.610332E-01 -8.341277E-03 -2.487859E-01 -6.745574E-03 -2.452106E-01 -7.276116E-03 -1.292894E-01 -2.441647E-03 -1.384975E-01 -2.258716E-03 -1.262151E-01 -2.266348E-03 -8.499870E-02 -1.048605E-03 -1.061529E-01 -1.352122E-03 -1.903736E-01 -5.558784E-03 -1.487595E-01 -2.773453E-03 -1.839791E-01 -4.150617E-03 -1.465408E-01 -2.813252E-03 -1.828928E-01 -4.248902E-03 -2.248261E-01 -6.983599E-03 -1.693010E-01 -3.303866E-03 -6.453527E-02 -1.173497E-03 -1.147332E-01 -3.617311E-03 -7.981911E-02 -8.325283E-04 -8.959341E-02 -1.548148E-03 -1.554108E-01 -4.270743E-03 -1.060675E-01 -1.816154E-03 -1.871862E-01 -4.742433E-03 -8.649749E-02 -1.100158E-03 -1.195635E-01 -1.740482E-03 -1.099096E-01 -1.964225E-03 -6.441028E-02 -7.477974E-04 -6.164448E-02 -1.090465E-03 -4.631552E-02 -5.181770E-04 -7.007983E-02 -7.319313E-04 -5.381387E-02 -3.817146E-04 -9.120379E-02 -1.840216E-03 -9.523925E-02 -1.956679E-03 -6.828427E-02 -8.825134E-04 -3.090110E-02 -1.871704E-04 -3.528248E-02 -2.289672E-04 -2.405019E-02 -9.740436E-05 -7.703115E-02 -8.995936E-04 -1.026207E-01 -1.722791E-03 -1.220668E-01 -2.216590E-03 -8.640530E-02 -1.102412E-03 -1.518321E-01 -3.298050E-03 -1.321954E-01 -2.553334E-03 -1.593152E-01 -4.604144E-03 -8.524427E-02 -1.055424E-03 -4.996523E-02 -5.024077E-04 -7.358073E-02 -1.128410E-03 -1.189640E-01 -2.194057E-03 -1.207644E-01 -2.491839E-03 -1.083314E-01 -1.503478E-03 -2.128070E-01 -7.648402E-03 -1.315274E-01 -2.025984E-03 -1.514078E-01 -3.617861E-03 -1.141892E-01 -2.085004E-03 -1.013844E-01 -1.496233E-03 -1.248655E-01 -2.516158E-03 -6.288783E-02 -9.200482E-04 -8.317750E-02 -1.508722E-03 -1.324137E-01 -3.423783E-03 -1.514092E-01 -3.487353E-03 -1.888798E-01 -5.346454E-03 -1.360192E-01 -2.392896E-03 -1.868095E-01 -3.836399E-03 -1.715305E-01 -3.663437E-03 -1.304944E-01 -1.999316E-03 -1.436264E-01 -3.567607E-03 -8.539019E-02 -1.065672E-03 -7.909923E-02 -1.167334E-03 -1.799124E-01 -4.569449E-03 -1.589893E-01 -3.478790E-03 -1.741005E-01 -3.674254E-03 -2.126076E-01 -6.791986E-03 -1.862610E-01 -4.406388E-03 -2.386545E-01 -6.839411E-03 -1.744812E-01 -4.301498E-03 -6.344775E-02 -6.567949E-04 -6.849881E-02 -7.535621E-04 -8.197852E-02 -9.887532E-04 -1.446787E-01 -3.971664E-03 -2.032184E-01 -5.194567E-03 -1.662525E-01 -3.292552E-03 -2.664800E-01 -8.114532E-03 -2.447963E-01 -7.854969E-03 -1.957695E-01 -5.152593E-03 -1.708599E-01 -4.101306E-03 -1.103539E-01 -2.077575E-03 -7.844092E-02 -1.163579E-03 -1.268702E-01 -2.695645E-03 -9.533912E-02 -1.278173E-03 -1.446874E-01 -3.872867E-03 -1.322553E-01 -2.335662E-03 -1.726451E-01 -3.517931E-03 -1.876877E-01 -4.835176E-03 -1.573863E-01 -3.574829E-03 -2.339589E-01 -7.282388E-03 -1.501104E-01 -2.820093E-03 -5.397296E-02 -5.850746E-04 -7.619565E-02 -1.435724E-03 -9.012995E-02 -1.564717E-03 -1.628327E-01 -3.377881E-03 -1.563374E-01 -3.245008E-03 -2.276467E-01 -7.079821E-03 -2.135994E-01 -7.272300E-03 -1.402939E-01 -2.997945E-03 -2.226852E-01 -6.770128E-03 -8.944673E-02 -1.404954E-03 -5.580544E-02 -9.620095E-04 -5.967367E-02 -1.011919E-03 -3.214966E-02 -1.717861E-04 -1.433931E-01 -2.788824E-03 -1.494058E-01 -2.846313E-03 -1.213890E-01 -3.277981E-03 -1.367546E-01 -2.740789E-03 -1.233601E-01 -2.166273E-03 -6.717077E-02 -9.275956E-04 -7.800745E-02 -8.928402E-04 -4.302808E-02 -5.599709E-04 -8.657826E-02 -1.515787E-03 -5.180954E-02 -5.871992E-04 -4.455245E-02 -4.150367E-04 -7.224886E-02 -8.834373E-04 -7.163514E-02 -8.735272E-04 -1.058744E-01 -2.396856E-03 -8.813243E-02 -1.064695E-03 -8.319821E-02 -2.457105E-03 -6.193848E-02 -6.865448E-04 -6.069918E-02 -6.588335E-04 diff --git a/tests/regression_tests/unstructured_mesh/test.py b/tests/regression_tests/unstructured_mesh/test.py index 9ed36c69c0a..3c41ce78caa 100644 --- a/tests/regression_tests/unstructured_mesh/test.py +++ b/tests/regression_tests/unstructured_mesh/test.py @@ -86,6 +86,18 @@ def get_mesh_tally_data(self, tally, structured=False): data.shape = (data.size, 1) return np.sum(data, axis=1) + def update_results(self): + """Update results_true.dat and inputs_true.dat""" + try: + self._build_inputs() + inputs = self._get_inputs() + self._write_inputs(inputs) + self._overwrite_inputs() + self._run_openmc() + self._test_output_created() + finally: + self._cleanup() + def _cleanup(self): super()._cleanup() output = glob.glob('tally*.vtk') @@ -219,7 +231,7 @@ def model(): space = openmc.stats.SphericalIndependent(r, cos_theta, phi) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.Source(space=space, energy=energy) + source = openmc.IndependentSource(space=space, energy=energy) settings.source = source model.settings = settings diff --git a/tests/regression_tests/void/inputs_true.dat b/tests/regression_tests/void/inputs_true.dat index 4e996c71d01..7fee0779e06 100644 --- a/tests/regression_tests/void/inputs_true.dat +++ b/tests/regression_tests/void/inputs_true.dat @@ -113,7 +113,7 @@ fixed source 1000 3 - + 0.0 0.0 0.0 diff --git a/tests/regression_tests/void/test.py b/tests/regression_tests/void/test.py index af1e3887b82..76c15eb39f6 100644 --- a/tests/regression_tests/void/test.py +++ b/tests/regression_tests/void/test.py @@ -23,7 +23,7 @@ def model(): model.settings.run_mode = 'fixed source' model.settings.batches = 3 model.settings.particles = 1000 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) cell_filter = openmc.CellFilter(cells) tally = openmc.Tally() diff --git a/tests/regression_tests/weightwindows/inputs_true.dat b/tests/regression_tests/weightwindows/inputs_true.dat index 16966ccafeb..c40f4b7615e 100644 --- a/tests/regression_tests/weightwindows/inputs_true.dat +++ b/tests/regression_tests/weightwindows/inputs_true.dat @@ -34,7 +34,7 @@ fixed source 200 2 - + 0.001 0.001 0.001 diff --git a/tests/regression_tests/weightwindows/test.py b/tests/regression_tests/weightwindows/test.py index b7a0e4fe1d4..9ed8559760f 100644 --- a/tests/regression_tests/weightwindows/test.py +++ b/tests/regression_tests/weightwindows/test.py @@ -53,7 +53,7 @@ def model(): space = Point((0.001, 0.001, 0.001)) energy = Discrete([14E6], [1.0]) - settings.source = openmc.Source(space=space, energy=energy) + settings.source = openmc.IndependentSource(space=space, energy=energy) # tally mesh = openmc.RegularMesh() diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 51d1b19a335..6041d898201 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -48,7 +48,7 @@ def sphere_model(): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) return model diff --git a/tests/unit_tests/dagmc/test.py b/tests/unit_tests/dagmc/test.py index 072167e793d..e84b5317ede 100644 --- a/tests/unit_tests/dagmc/test.py +++ b/tests/unit_tests/dagmc/test.py @@ -27,7 +27,7 @@ def dagmc_model(request): model.settings.verbosity = 1 source_box = openmc.stats.Box([ -4, -4, -4 ], [ 4, 4, 4 ]) - source = openmc.Source(space=source_box) + source = openmc.IndependentSource(space=source_box) model.settings.source = source # geometry diff --git a/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py b/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py index f7f5af8d054..4f23ef8591f 100644 --- a/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py +++ b/tests/unit_tests/mesh_to_vtk/test_vtk_dims.py @@ -25,7 +25,7 @@ def model(): settings.particles = 100 settings.run_mode = 'fixed source' - source = openmc.Source() + source = openmc.IndependentSource() source.angle = openmc.stats.Isotropic() source.energy = openmc.stats.Discrete([1.0e6], [1.0]) source.space = openmc.stats.Point((-0.01, -0.01, -0.01)) diff --git a/tests/unit_tests/test_complex_cell_bb.py b/tests/unit_tests/test_complex_cell_bb.py index ad6491cca92..8a94d9ddcfd 100644 --- a/tests/unit_tests/test_complex_cell_bb.py +++ b/tests/unit_tests/test_complex_cell_bb.py @@ -66,7 +66,7 @@ def complex_cell(run_in_tmpdir, mpi_intracomm): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-10., -10., -1.], [10., 10., 1.])) model.settings.verbosity = 1 diff --git a/tests/unit_tests/test_cylindrical_mesh.py b/tests/unit_tests/test_cylindrical_mesh.py index 4382b49ba57..22b6ed8169e 100644 --- a/tests/unit_tests/test_cylindrical_mesh.py +++ b/tests/unit_tests/test_cylindrical_mesh.py @@ -23,7 +23,7 @@ def model(): geom = openmc.Geometry([cell]) - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Point() source.energy = openmc.stats.Discrete([10000], [1.0]) @@ -155,7 +155,7 @@ def _check_void_cylindrical_tally(statepoint_filename): assert neutron_flux == pytest.approx(d_r) def test_void_geom_pnt_src(run_in_tmpdir, void_coincident_geom_model): - src = openmc.Source() + src = openmc.IndependentSource() src.space = openmc.stats.Point() src.angle = openmc.stats.PolarAzimuthal(mu=openmc.stats.Discrete([0.0], [1.0])) src.energy = openmc.stats.Discrete([14.06e6], [1]) @@ -180,7 +180,7 @@ def test_void_geom_boundary_src(run_in_tmpdir, void_coincident_geom_model): energy = openmc.stats.Discrete([14.06e6], [1]) for val in radial_vals: - src = openmc.Source() + src = openmc.IndependentSource() src.energy = energy pnt = np.array([np.cos(val), np.sin(val), 0.0]) diff --git a/tests/unit_tests/test_data_thermal.py b/tests/unit_tests/test_data_thermal.py index 61ae61b24f3..9f5a8cb4046 100644 --- a/tests/unit_tests/test_data_thermal.py +++ b/tests/unit_tests/test_data_thermal.py @@ -363,7 +363,7 @@ def test_mixed_elastic(fake_mixed_elastic, run_in_tmpdir): model.settings.particles = 1000 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( energy=openmc.stats.Discrete([3.0], [1.0]) # 3 eV source ) model.run() diff --git a/tests/unit_tests/test_deplete_activation.py b/tests/unit_tests/test_deplete_activation.py index 539f4d6bd59..357e303cdba 100644 --- a/tests/unit_tests/test_deplete_activation.py +++ b/tests/unit_tests/test_deplete_activation.py @@ -27,7 +27,7 @@ def model(): model.settings.batches = 10 model.settings.particles = 1000 - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( space=openmc.stats.Point(), energy=openmc.stats.Discrete([1.0e6], [1.0]) ) diff --git a/tests/unit_tests/test_energy_cutoff.py b/tests/unit_tests/test_energy_cutoff.py index fb82c579a15..45333f2e1dc 100644 --- a/tests/unit_tests/test_energy_cutoff.py +++ b/tests/unit_tests/test_energy_cutoff.py @@ -17,7 +17,7 @@ def inf_medium_model(cutoff_energy, source_energy): model.geometry = openmc.Geometry([cell]) model.settings.run_mode = 'fixed source' - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( particle='photon', energy=openmc.stats.Discrete([source_energy], [1.0]), ) diff --git a/tests/unit_tests/test_filters.py b/tests/unit_tests/test_filters.py index 0d34bfee3a2..ff064d5c251 100644 --- a/tests/unit_tests/test_filters.py +++ b/tests/unit_tests/test_filters.py @@ -17,7 +17,7 @@ def box_model(): model.settings.particles = 100 model.settings.batches = 10 model.settings.inactive = 0 - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) return model diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index 3b2deee285a..6fa34d26d01 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -20,7 +20,7 @@ def test_volume(run_in_tmpdir, uo2): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.Source(space=openmc.stats.Point()) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point()) ll, ur = model.geometry.bounding_box assert ll == pytest.approx((-outer.r, -outer.r, -outer.r)) diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index b4dd9197b18..5f74c7c235d 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -66,7 +66,7 @@ def uo2_trigger_model(): model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 100 - model.settings.source = openmc.Source(space=openmc.stats.Box( + model.settings.source = openmc.IndependentSource(space=openmc.stats.Box( [-0.5, -0.5, -1], [0.5, 0.5, 1], only_fissionable=True)) model.settings.verbosity = 1 model.settings.keff_trigger = {'type': 'std_dev', 'threshold': 0.001} @@ -849,7 +849,7 @@ def test_sample_external_source(run_in_tmpdir, mpi_intracomm): cell = openmc.Cell(fill=mat, region=-sph) model = openmc.Model() model.geometry = openmc.Geometry([cell]) - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( space=openmc.stats.Box([-5., -5., -5.], [5., 5., 5.]), angle=openmc.stats.Monodirectional((0., 0., 1.)), energy=openmc.stats.Discrete([1.0e5], [1.0]) diff --git a/tests/unit_tests/test_model.py b/tests/unit_tests/test_model.py index 6c483aeb94b..f78f9563737 100644 --- a/tests/unit_tests/test_model.py +++ b/tests/unit_tests/test_model.py @@ -59,7 +59,7 @@ def pin_model_attributes(): bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] uniform_dist = openmc.stats.Box( bounds[:3], bounds[3:], only_fissionable=True) - settings.source = openmc.source.Source(space=uniform_dist) + settings.source = openmc.IndependentSource(space=uniform_dist) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] diff --git a/tests/unit_tests/test_settings.py b/tests/unit_tests/test_settings.py index 15e86ca619b..d75a50477a3 100644 --- a/tests/unit_tests/test_settings.py +++ b/tests/unit_tests/test_settings.py @@ -13,7 +13,7 @@ def test_export_to_xml(run_in_tmpdir): s.energy_mode = 'continuous-energy' s.max_order = 5 s.max_tracks = 1234 - s.source = openmc.Source(space=openmc.stats.Point()) + s.source = openmc.IndependentSource(space=openmc.stats.Point()) s.output = {'summary': True, 'tallies': False, 'path': 'here'} s.verbosity = 7 s.sourcepoint = {'batches': [50, 150, 500, 1000], 'separate': True, @@ -71,7 +71,7 @@ def test_export_to_xml(run_in_tmpdir): assert s.energy_mode == 'continuous-energy' assert s.max_order == 5 assert s.max_tracks == 1234 - assert isinstance(s.source[0], openmc.Source) + assert isinstance(s.source[0], openmc.IndependentSource) assert isinstance(s.source[0].space, openmc.stats.Point) assert s.output == {'summary': True, 'tallies': False, 'path': 'here'} assert s.verbosity == 7 diff --git a/tests/unit_tests/test_source.py b/tests/unit_tests/test_source.py index 1e4766b4560..4783ff8f11d 100644 --- a/tests/unit_tests/test_source.py +++ b/tests/unit_tests/test_source.py @@ -4,6 +4,7 @@ import openmc.lib import openmc.stats import numpy as np +import pytest from pytest import approx @@ -12,7 +13,7 @@ def test_source(): energy = openmc.stats.Discrete([1.0e6], [1.0]) angle = openmc.stats.Isotropic() - src = openmc.Source(space=space, angle=angle, energy=energy) + src = openmc.IndependentSource(space=space, angle=angle, energy=energy) assert src.space == space assert src.angle == angle assert src.energy == energy @@ -23,7 +24,7 @@ def test_source(): assert elem.find('angle') is not None assert elem.find('energy') is not None - src = openmc.Source.from_xml_element(elem) + src = openmc.IndependentSource.from_xml_element(elem) assert isinstance(src.angle, openmc.stats.Isotropic) assert src.space.xyz == [0.0, 0.0, 0.0] assert src.energy.x == [1.0e6] @@ -49,8 +50,8 @@ def test_spherical_uniform(): def test_source_file(): filename = 'source.h5' - src = openmc.Source(filename=filename) - assert src.file == filename + src = openmc.FileSource(path=filename) + assert src.path == filename elem = src.to_xml_element() assert 'strength' in elem.attrib @@ -59,7 +60,7 @@ def test_source_file(): def test_source_dlopen(): library = './libsource.so' - src = openmc.Source(library=library) + src = openmc.CompiledSource(library=library) assert src.library == library elem = src.to_xml_element() @@ -75,14 +76,14 @@ def test_source_xml_roundtrip(): phi=openmc.stats.Uniform(0., 2*pi), reference_uvw=(0., 1., 0.) ) - src = openmc.Source( + src = openmc.IndependentSource( space=space, angle=angle, energy=energy, particle='photon', strength=100.0 ) elem = src.to_xml_element() # Read from XML element and make sure data is preserved - new_src = openmc.Source.from_xml_element(elem) + new_src = openmc.IndependentSource.from_xml_element(elem) assert isinstance(new_src.space, openmc.stats.Box) np.testing.assert_allclose(new_src.space.lower_left, src.space.lower_left) np.testing.assert_allclose(new_src.space.upper_right, src.space.upper_right) @@ -120,7 +121,7 @@ def test_rejection(run_in_tmpdir): # Set up a box source with rejection on the spherical cell space = openmc.stats.Box(*cell3.bounding_box) - model.settings.source = openmc.Source(space=space, domains=[cell1, cell2]) + model.settings.source = openmc.IndependentSource(space=space, domains=[cell1, cell2]) # Load up model via openmc.lib and sample source model.export_to_xml() @@ -134,3 +135,25 @@ def test_rejection(run_in_tmpdir): assert p.r not in non_source_region openmc.lib.finalize() + + +def test_exceptions(): + + with pytest.raises(AttributeError, match=r'Please use the FileSource class'): + s = openmc.IndependentSource() + s.file = 'my_file' + + with pytest.raises(AttributeError, match=r'Please use the CompiledSource class'): + s = openmc.IndependentSource() + s.library = 'my_library' + + with pytest.raises(AttributeError, match=r'Please use the CompiledSource class'): + s = openmc.IndependentSource() + s.parameters = 'my_params' + + with pytest.warns(FutureWarning, match=r'in favor of \'IndependentSource\''): + s = openmc.Source() + + with pytest.raises(AttributeError, match=r'has no attribute \'frisbee\''): + s = openmc.IndependentSource() + s.frisbee \ No newline at end of file diff --git a/tests/unit_tests/test_source_file.py b/tests/unit_tests/test_source_file.py index 78115a1f617..ec10260bafe 100644 --- a/tests/unit_tests/test_source_file.py +++ b/tests/unit_tests/test_source_file.py @@ -67,7 +67,7 @@ def test_wrong_source_attributes(run_in_tmpdir): settings = openmc.Settings() settings.particles = 100 settings.batches = 10 - settings.source = openmc.Source(filename='animal_source.h5') + settings.source = openmc.FileSource(path='animal_source.h5') settings.export_to_xml() # When we run the model, it should error out with a message that includes @@ -90,7 +90,7 @@ def test_source_file_transport(run_in_tmpdir): sph = openmc.Sphere(r=10.0, boundary_type='vacuum') cell = openmc.Cell(fill=al, region=-sph) model.geometry = openmc.Geometry([cell]) - model.settings.source = openmc.Source(filename='source.h5') + model.settings.source = openmc.FileSource(path='source.h5') model.settings.particles = 10 model.settings.batches = 3 model.settings.run_mode = 'fixed source' diff --git a/tests/unit_tests/test_source_mesh.py b/tests/unit_tests/test_source_mesh.py index 596b22f9a17..fd8b04148e7 100644 --- a/tests/unit_tests/test_source_mesh.py +++ b/tests/unit_tests/test_source_mesh.py @@ -94,7 +94,7 @@ def test_unstructured_mesh_sampling(model, request, test_cases): space = openmc.stats.MeshSpatial(uscd_mesh, strengths, vol_norm) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.Source(space=space, energy=energy) + source = openmc.IndependentSource(space=space, energy=energy) model.settings.source = source with cdtemp([mesh_filename]): @@ -155,7 +155,7 @@ def test_strengths_size_failure(request, model): space = openmc.stats.MeshSpatial(uscd_mesh, strengths) energy = openmc.stats.Discrete(x=[15.e+06], p=[1.0]) - source = openmc.Source(space=space, energy=energy) + source = openmc.IndependentSource(space=space, energy=energy) model.settings.source = source # skip the test if unstructured mesh is not available @@ -188,7 +188,7 @@ def test_roundtrip(run_in_tmpdir, model, request): space_out = openmc.MeshSpatial(ucd_mesh) space_out.strengths = np.random.rand(n_cells*TETS_PER_VOXEL) - model.settings.source = openmc.Source(space=space_out) + model.settings.source = openmc.IndependentSource(space=space_out) # write out the model model.export_to_xml() diff --git a/tests/unit_tests/test_spherical_mesh.py b/tests/unit_tests/test_spherical_mesh.py index ac2781378a3..80f65bb420e 100644 --- a/tests/unit_tests/test_spherical_mesh.py +++ b/tests/unit_tests/test_spherical_mesh.py @@ -23,7 +23,7 @@ def model(): geom = openmc.Geometry([cell]) - source = openmc.Source() + source = openmc.IndependentSource() source.space = openmc.stats.Point() source.energy = openmc.stats.Discrete([10000], [1.0]) @@ -163,7 +163,7 @@ def _check_void_spherical_tally(statepoint_filename): def test_void_geom_pnt_src(run_in_tmpdir, void_coincident_geom_model): # add isotropic point source - src = openmc.Source() + src = openmc.IndependentSource() src.space = openmc.stats.Point() src.energy = openmc.stats.Discrete([14.06e6], [1]) void_coincident_geom_model.settings.source = src @@ -190,7 +190,7 @@ def test_void_geom_boundary_src(run_in_tmpdir, void_coincident_geom_model): for phi, theta in zip(phi_vals, theta_vals): - src = openmc.Source() + src = openmc.IndependentSource() src.energy = energy pnt = np.array([np.sin(phi)*np.cos(theta), np.sin(phi)*np.sin(theta), np.cos(phi)]) diff --git a/tests/unit_tests/test_time_filter.py b/tests/unit_tests/test_time_filter.py index 45fabc5449a..b57c80a9758 100644 --- a/tests/unit_tests/test_time_filter.py +++ b/tests/unit_tests/test_time_filter.py @@ -59,7 +59,7 @@ def model(request): model.settings.particles = 1000 model.settings.batches = 20 particle = request.param - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( space=openmc.stats.Point((x, 0., 0.)), angle=openmc.stats.Monodirectional([-1., 0., 0.]), energy=openmc.stats.Discrete([E], [1.0]), @@ -100,7 +100,7 @@ def model_surf(request): model.settings.particles = 1000 model.settings.batches = 20 particle = request.param - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( space=openmc.stats.Point((0., 0., 0.)), angle=openmc.stats.Monodirectional([1., 0., 0.]), energy=openmc.stats.Discrete([E], [1.0]), @@ -165,7 +165,7 @@ def test_small_time_interval(run_in_tmpdir): model.settings.particles = 100 model.settings.batches = 10 model.settings.run_mode = 'fixed source' - model.settings.source = openmc.Source( + model.settings.source = openmc.IndependentSource( time=openmc.stats.Discrete([1.0e8], [1.0]), particle='photon' ) diff --git a/tests/unit_tests/test_torus.py b/tests/unit_tests/test_torus.py index ba92860e74f..8c413ffe06d 100644 --- a/tests/unit_tests/test_torus.py +++ b/tests/unit_tests/test_torus.py @@ -17,7 +17,7 @@ def get_torus_keff(cls, R, r, center=(0, 0, 0)): outer_cell = openmc.Cell(region=+torus & -sphere) model.geometry = openmc.Geometry([torus_cell, outer_cell]) - model.settings.source = openmc.Source(space=openmc.stats.Point(center)) + model.settings.source = openmc.IndependentSource(space=openmc.stats.Point(center)) model.settings.batches = 10 model.settings.inactive = 5 model.settings.particles = 1000 diff --git a/tests/unit_tests/test_tracks.py b/tests/unit_tests/test_tracks.py index be75c6f8813..3a017015564 100644 --- a/tests/unit_tests/test_tracks.py +++ b/tests/unit_tests/test_tracks.py @@ -48,7 +48,7 @@ def test_tracks(sphere_model, particle, run_in_tmpdir): sphere_model.settings.track = [(1, 1, 1), (1, 1, 10), (2, 1, 15)] # Set source particle - sphere_model.settings.source = openmc.Source(particle=particle) + sphere_model.settings.source = openmc.IndependentSource(particle=particle) # Run OpenMC to generate tracks.h5 file generate_track_file(sphere_model) diff --git a/tests/unit_tests/test_urr_capture.py b/tests/unit_tests/test_urr_capture.py index 745d62cef0f..34b518e9de8 100644 --- a/tests/unit_tests/test_urr_capture.py +++ b/tests/unit_tests/test_urr_capture.py @@ -19,7 +19,7 @@ def th232_model(): model.settings.batches = 10 model.settings.run_mode = 'fixed source' energies = openmc.stats.Uniform(e_min, e_max) - model.settings.source = openmc.Source(energy=energies) + model.settings.source = openmc.IndependentSource(energy=energies) tally = openmc.Tally(name='rates') tally.filters = [openmc.EnergyFilter([e_min, e_max])] diff --git a/tests/unit_tests/weightwindows/test.py b/tests/unit_tests/weightwindows/test.py index dce75c74045..f8db66820dd 100644 --- a/tests/unit_tests/weightwindows/test.py +++ b/tests/unit_tests/weightwindows/test.py @@ -99,7 +99,7 @@ def model(): space = Point((0.001, 0.001, 0.001)) energy = Discrete([14E6], [1.0]) - settings.source = openmc.Source(space=space, energy=energy) + settings.source = openmc.IndependentSource(space=space, energy=energy) # tally mesh = openmc.RegularMesh() From 2536cae11bb8fd1e15a990990deb095d4356e0f1 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Wed, 21 Jun 2023 13:07:15 +0100 Subject: [PATCH 33/45] allowing stepresult to save to a path (#2567) Co-authored-by: Paul Romano --- openmc/deplete/stepresult.py | 15 ++++++++++++--- tests/unit_tests/test_deplete_integrator.py | 6 ++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/openmc/deplete/stepresult.py b/openmc/deplete/stepresult.py index 042fa46a1e9..689627bbfdf 100644 --- a/openmc/deplete/stepresult.py +++ b/openmc/deplete/stepresult.py @@ -4,15 +4,17 @@ timestep. """ -from collections import OrderedDict import copy import warnings +from collections import OrderedDict +from pathlib import Path import h5py import numpy as np import openmc from openmc.mpi import comm, MPI +from openmc.checkvalue import PathLike from .reaction_rates import ReactionRates VERSION_RESULTS = (1, 1) @@ -495,7 +497,8 @@ def from_hdf5(cls, handle, step): return results @staticmethod - def save(op, x, op_results, t, source_rate, step_ind, proc_time=None): + def save(op, x, op_results, t, source_rate, step_ind, proc_time=None, + path: PathLike = "depletion_results.h5"): """Creates and writes depletion results to disk Parameters @@ -517,6 +520,10 @@ def save(op, x, op_results, t, source_rate, step_ind, proc_time=None): be process-dependent and will be reduced across MPI processes. + path : PathLike + Path to file to write. Defaults to 'depletion_results.h5'. + + .. versionadded:: 0.13.4 """ # Get indexing terms vol_dict, nuc_list, burn_list, full_burn_list = op.get_results_info() @@ -547,7 +554,9 @@ def save(op, x, op_results, t, source_rate, step_ind, proc_time=None): if results.proc_time is not None: results.proc_time = comm.reduce(proc_time, op=MPI.SUM) - results.export_to_hdf5("depletion_results.h5", step_ind) + if not Path(path).is_file(): + Path(path).parent.mkdir(parents=True, exist_ok=True) + results.export_to_hdf5(path, step_ind) def transfer_volumes(self, model): """Transfers volumes from depletion results to geometry diff --git a/tests/unit_tests/test_deplete_integrator.py b/tests/unit_tests/test_deplete_integrator.py index cb6374152c4..ba625a99981 100644 --- a/tests/unit_tests/test_deplete_integrator.py +++ b/tests/unit_tests/test_deplete_integrator.py @@ -99,6 +99,12 @@ def test_results_save(run_in_tmpdir): for k, rates in zip(eigvl1, rate1)] op_result2 = [OperatorResult(ufloat(*k), rates) for k, rates in zip(eigvl2, rate2)] + + # saves within a subdirectory + StepResult.save(op, x1, op_result1, t1, 0, 0, path='out/put/depletion.h5') + res = Results('out/put/depletion.h5') + + # saves with default filename StepResult.save(op, x1, op_result1, t1, 0, 0) StepResult.save(op, x2, op_result2, t2, 0, 1) From 8ce5c7366c5024c56c7d47e6ca8450357fca0eb0 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 21 Jun 2023 07:45:59 -0500 Subject: [PATCH 34/45] Remove initial dilute nuclides in depletion (#2568) --- docs/source/io_formats/depletion_results.rst | 7 - openmc/deplete/abc.py | 24 +- openmc/deplete/coupled_operator.py | 11 +- openmc/deplete/independent_operator.py | 16 - openmc/deplete/openmc_operator.py | 19 +- openmc/deplete/results.py | 15 - src/tallies/tally.cpp | 9 +- tests/regression_tests/__init__.py | 24 + .../deplete_no_transport/test.py | 64 +- .../test_reference_coupled_days.h5 | Bin 36312 -> 36048 bytes .../test_reference_coupled_hours.h5 | Bin 36312 -> 36048 bytes .../test_reference_coupled_minutes.h5 | Bin 36312 -> 36048 bytes .../test_reference_coupled_months.h5 | Bin 36312 -> 36048 bytes .../test_reference_fission_q.h5 | Bin 36312 -> 36048 bytes .../test_reference_source_rate.h5 | Bin 36312 -> 36048 bytes .../ref_depletion_with_feed.h5 | Bin 37328 -> 37328 bytes .../ref_depletion_with_removal.h5 | Bin 37328 -> 37328 bytes .../ref_depletion_with_transfer.h5 | Bin 37328 -> 37328 bytes .../ref_no_depletion_only_feed.h5 | Bin 37328 -> 37328 bytes .../ref_no_depletion_only_removal.h5 | Bin 37328 -> 37328 bytes .../ref_no_depletion_with_transfer.h5 | Bin 37328 -> 37328 bytes .../deplete_with_transfer_rates/test.py | 24 +- .../last_step_reference_materials.xml | 1288 ++++++++--------- .../deplete_with_transport/test.py | 20 +- .../deplete_with_transport/test_reference.h5 | Bin 163736 -> 163736 bytes 25 files changed, 708 insertions(+), 813 deletions(-) diff --git a/docs/source/io_formats/depletion_results.rst b/docs/source/io_formats/depletion_results.rst index 172c17ae636..7035fc9c9ee 100644 --- a/docs/source/io_formats/depletion_results.rst +++ b/docs/source/io_formats/depletion_results.rst @@ -47,10 +47,3 @@ The current version of the depletion results file format is 1.1. **/reactions//** :Attributes: - **index** (*int*) -- Index user in results for this reaction - -.. note:: - - The reaction rates for some isotopes not originally present may - be non-zero, but should be negligible compared to other atoms. - This can be controlled by changing the - :class:`openmc.deplete.Operator` ``dilute_initial`` attribute. diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 802b3833f16..e62cc2b5ecd 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -93,20 +93,11 @@ class TransportOperator(ABC): fission_q : dict, optional Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. - dilute_initial : float, optional - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. - Defaults to 1.0e3. prev_results : Results, optional Results from a previous depletion calculation. Attributes ---------- - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. prev_res : Results or None @@ -116,9 +107,7 @@ class TransportOperator(ABC): The depletion chain information necessary to form matrices and tallies. """ - def __init__(self, chain_file, fission_q=None, dilute_initial=1.0e3, - prev_results=None): - self.dilute_initial = dilute_initial + def __init__(self, chain_file, fission_q=None, prev_results=None): self.output_dir = '.' # Read depletion chain @@ -129,17 +118,6 @@ def __init__(self, chain_file, fission_q=None, dilute_initial=1.0e3, check_type("previous results", prev_results, Results) self.prev_res = prev_results - @property - def dilute_initial(self): - """Initial atom density for nuclides with zero initial concentration""" - return self._dilute_initial - - @dilute_initial.setter - def dilute_initial(self, value): - check_type("dilute_initial", value, Real) - check_greater_than("dilute_initial", value, 0.0, equality=True) - self._dilute_initial = value - @abstractmethod def __call__(self, vec, source_rate): """Runs a simulation. diff --git a/openmc/deplete/coupled_operator.py b/openmc/deplete/coupled_operator.py index d8d4838a4a7..ab7314ac786 100644 --- a/openmc/deplete/coupled_operator.py +++ b/openmc/deplete/coupled_operator.py @@ -122,10 +122,6 @@ class CoupledOperator(OpenMCOperator): Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. Only applicable if ``"normalization_mode" == "fission-q"`` - dilute_initial : float, optional - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. fission_yield_mode : {"constant", "cutoff", "average"} Key indicating what fission product yield scheme to use. The key determines what fission energy helper is used: @@ -177,10 +173,6 @@ class CoupledOperator(OpenMCOperator): OpenMC geometry object settings : openmc.Settings OpenMC settings object - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that - are zero in initial condition to ensure they exist in the decay - chain. Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. round_number : bool @@ -215,7 +207,7 @@ class CoupledOperator(OpenMCOperator): def __init__(self, model, chain_file=None, prev_results=None, diff_burnable_mats=False, normalization_mode="fission-q", - fission_q=None, dilute_initial=1.0e3, + fission_q=None, fission_yield_mode="constant", fission_yield_opts=None, reaction_rate_mode="direct", reaction_rate_opts=None, reduce_chain=False, reduce_chain_level=None): @@ -271,7 +263,6 @@ def __init__(self, model, chain_file=None, prev_results=None, prev_results, diff_burnable_mats, fission_q, - dilute_initial, helper_kwargs, reduce_chain, reduce_chain_level) diff --git a/openmc/deplete/independent_operator.py b/openmc/deplete/independent_operator.py index 8d7882ac9be..75727840669 100644 --- a/openmc/deplete/independent_operator.py +++ b/openmc/deplete/independent_operator.py @@ -63,10 +63,6 @@ class IndependentOperator(OpenMCOperator): Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. Only applicable if ``"normalization_mode" == "fission-q"``. - dilute_initial : float, optional - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. reduce_chain : bool, optional If True, use :meth:`openmc.deplete.Chain.reduce` to reduce the depletion chain up to ``reduce_chain_level``. @@ -86,10 +82,6 @@ class IndependentOperator(OpenMCOperator): All materials present in the model cross_sections : MicroXS Object containing one-group cross-sections in [cm^2]. - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that - are zero in initial condition to ensure they exist in the decay - chain. Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. round_number : bool @@ -122,7 +114,6 @@ def __init__(self, keff=None, normalization_mode='fission-q', fission_q=None, - dilute_initial=1.0e3, prev_results=None, reduce_chain=False, reduce_chain_level=None, @@ -148,7 +139,6 @@ def __init__(self, chain_file, prev_results, fission_q=fission_q, - dilute_initial=dilute_initial, helper_kwargs=helper_kwargs, reduce_chain=reduce_chain, reduce_chain_level=reduce_chain_level) @@ -161,7 +151,6 @@ def from_nuclides(cls, volume, nuclides, keff=None, normalization_mode='fission-q', fission_q=None, - dilute_initial=1.0e3, prev_results=None, reduce_chain=False, reduce_chain_level=None, @@ -196,10 +185,6 @@ def from_nuclides(cls, volume, nuclides, Dictionary of nuclides and their fission Q values [eV]. If not given, values will be pulled from the ``chain_file``. Only applicable if ``"normalization_mode" == "fission-q"``. - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that - are zero in initial condition to ensure they exist in the decay - chain. Only done for nuclides with reaction rates. prev_results : Results, optional Results from a previous depletion calculation. reduce_chain : bool, optional @@ -224,7 +209,6 @@ def from_nuclides(cls, volume, nuclides, keff=keff, normalization_mode=normalization_mode, fission_q=fission_q, - dilute_initial=dilute_initial, prev_results=prev_results, reduce_chain=reduce_chain, reduce_chain_level=reduce_chain_level, diff --git a/openmc/deplete/openmc_operator.py b/openmc/deplete/openmc_operator.py index 55a7d724692..f63828133d7 100644 --- a/openmc/deplete/openmc_operator.py +++ b/openmc/deplete/openmc_operator.py @@ -47,10 +47,6 @@ class OpenMCOperator(TransportOperator): Volumes are divided equally from the original material volume. fission_q : dict, optional Dictionary of nuclides and their fission Q values [eV]. - dilute_initial : float, optional - Initial atom density [atoms/cm^3] to add for nuclides that are zero - in initial condition to ensure they exist in the decay chain. - Only done for nuclides with reaction rates. helper_kwargs : dict Keyword arguments for helper classes reduce_chain : bool, optional @@ -68,10 +64,6 @@ class OpenMCOperator(TransportOperator): cross_sections : str or MicroXS Path to continuous energy cross section library, or object containing one-group cross-sections. - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that - are zero in initial condition to ensure they exist in the decay - chain. Only done for nuclides with reaction rates. output_dir : pathlib.Path Path to output directory to save results. round_number : bool @@ -105,7 +97,6 @@ def __init__( prev_results=None, diff_burnable_mats=False, fission_q=None, - dilute_initial=0.0, helper_kwargs=None, reduce_chain=False, reduce_chain_level=None): @@ -119,7 +110,7 @@ def __init__( "chain in openmc.config['chain_file']" ) - super().__init__(chain_file, fission_q, dilute_initial, prev_results) + super().__init__(chain_file, fission_q, prev_results) self.round_number = False self.materials = materials self.cross_sections = cross_sections @@ -265,11 +256,6 @@ def _extract_number(self, local_mats, volume, all_nuclides, prev_res=None): """ self.number = AtomNumber(local_mats, all_nuclides, volume, len(self.chain)) - if self.dilute_initial != 0.0: - for nuc in self._burnable_nucs: - self.number.set_atom_density( - np.s_[:], nuc, self.dilute_initial) - # Now extract and store the number densities # From the geometry if no previous depletion results if prev_res is None: @@ -433,8 +419,7 @@ def _get_reaction_nuclides(self): # for burning in which the number density is greater than zero. for nuc in self.number.nuclides: if nuc in self.nuclides_with_data: - if np.sum(self.number[:, nuc]) > 0.0: - nuc_set.add(nuc) + nuc_set.add(nuc) # Communicate which nuclides have nonzeros to rank 0 if comm.rank == 0: diff --git a/openmc/deplete/results.py b/openmc/deplete/results.py index 555a7ce3733..9cc3b439a60 100644 --- a/openmc/deplete/results.py +++ b/openmc/deplete/results.py @@ -103,13 +103,6 @@ def get_atoms( ) -> Tuple[np.ndarray, np.ndarray]: """Get number of nuclides over time from a single material - .. note:: - Initial values for some isotopes that do not appear in - initial concentrations may be non-zero, depending on the - value of the :attr:`openmc.deplete.CoupledOperator.dilute_initial` - attribute. The :class:`openmc.deplete.CoupledOperator` class adds - isotopes according to this setting, which can be set to zero. - Parameters ---------- mat : openmc.Material, str @@ -172,14 +165,6 @@ def get_reaction_rate( ) -> Tuple[np.ndarray, np.ndarray]: """Get reaction rate in a single material/nuclide over time - .. note:: - - Initial values for some isotopes that do not appear in - initial concentrations may be non-zero, depending on the - value of :class:`openmc.deplete.CoupledOperator` ``dilute_initial`` - The :class:`openmc.deplete.CoupledOperator` adds isotopes according - to this setting, which can be set to zero. - Parameters ---------- mat : openmc.Material, str diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 9a7e52b9508..c9c977ea961 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -1258,10 +1258,13 @@ extern "C" int openmc_tally_set_nuclides( } else { auto search = data::nuclide_map.find(word); if (search == data::nuclide_map.end()) { - set_errmsg("Nuclide \"" + word + "\" has not been loaded yet"); - return OPENMC_E_DATA; + int err = openmc_load_nuclide(word.c_str(), nullptr, 0); + if (err < 0) { + set_errmsg(openmc_err_msg); + return OPENMC_E_DATA; + } } - nucs.push_back(search->second); + nucs.push_back(data::nuclide_map.at(word)); } } diff --git a/tests/regression_tests/__init__.py b/tests/regression_tests/__init__.py index a887448c111..ba48fc01e9e 100644 --- a/tests/regression_tests/__init__.py +++ b/tests/regression_tests/__init__.py @@ -1,3 +1,5 @@ +import pytest + # Test configuration options for regression tests config = { 'event' : False, @@ -8,3 +10,25 @@ 'update': False, 'build_inputs': False } + + +def assert_atoms_equal(res_ref, res_test, tol=1e-5): + for mat in res_test[0].index_mat: + for nuc in res_test[0].index_nuc: + _, y_test = res_test.get_atoms(mat, nuc) + _, y_ref = res_ref.get_atoms(mat, nuc) + assert y_test == pytest.approx(y_ref, rel=tol), \ + f'Atoms not equal for material {mat}, nuclide {nuc}\n' \ + f'y_ref={y_ref}\ny_test={y_test}' + + +def assert_reaction_rates_equal(res_ref, res_test, tol=1e-5): + for reactions in res_test[0].rates: + for mat in reactions.index_mat: + for nuc in reactions.index_nuc: + for rx in reactions.index_rx: + y_test = res_test.get_reaction_rate(mat, nuc, rx)[1] + y_ref = res_ref.get_reaction_rate(mat, nuc, rx)[1] + assert y_test == pytest.approx(y_ref, rel=tol), \ + f'Reaction rate not equal for material {mat}, nuclide '\ + f'{nuc}, {rx}\ny_ref={y_ref}\ny_test={y_test}' diff --git a/tests/regression_tests/deplete_no_transport/test.py b/tests/regression_tests/deplete_no_transport/test.py index a3654174850..64769c0b0e8 100644 --- a/tests/regression_tests/deplete_no_transport/test.py +++ b/tests/regression_tests/deplete_no_transport/test.py @@ -1,6 +1,7 @@ """ Transport-free depletion test suite """ from pathlib import Path +import shutil import numpy as np import pytest @@ -8,6 +9,9 @@ import openmc.deplete from openmc.deplete import IndependentOperator, MicroXS +from tests.regression_tests import config, assert_atoms_equal, \ + assert_reaction_rates_equal + @pytest.fixture(scope="module") def fuel(): @@ -82,6 +86,11 @@ def test_against_self(run_in_tmpdir, ref_path = 'test_reference_fission_q.h5' path_reference = Path(__file__).with_name(ref_path) + # If updating results, do so and return + if config['update']: + shutil.copyfile(str(path_test), str(path_reference)) + return + # Load the reference/test results res_test = openmc.deplete.Results(path_test) res_ref = openmc.deplete.Results(path_reference) @@ -90,8 +99,8 @@ def test_against_self(run_in_tmpdir, _assert_same_mats(res_test, res_ref) tol = 1.0e-14 - _assert_atoms_equal(res_test, res_ref, tol) - _assert_reaction_rates_equal(res_test, res_ref, tol) + assert_atoms_equal(res_test, res_ref, tol) + assert_reaction_rates_equal(res_test, res_ref, tol) @pytest.mark.parametrize("multiproc, dt, time_units, time_type, atom_tol, rx_tol ", [ @@ -130,6 +139,11 @@ def test_against_coupled(run_in_tmpdir, ref_path = f'test_reference_coupled_{time_type}.h5' path_reference = Path(__file__).with_name(ref_path) + # If updating results, do so and return + if config['update']: + shutil.copyfile(str(path_test), str(path_reference)) + return + # Load the reference/test results res_test = openmc.deplete.Results(path_test) res_ref = openmc.deplete.Results(path_reference) @@ -137,8 +151,8 @@ def test_against_coupled(run_in_tmpdir, # Assert same mats _assert_same_mats(res_test, res_ref) - _assert_atoms_equal(res_test, res_ref, atom_tol) - _assert_reaction_rates_equal(res_test, res_ref, rx_tol) + assert_atoms_equal(res_test, res_ref, atom_tol) + assert_reaction_rates_equal(res_test, res_ref, rx_tol) def _create_operator(from_nuclides, @@ -181,45 +195,3 @@ def _assert_same_mats(res_ref, res_test): assert nuc in res_ref[0].index_nuc, \ f"Nuclide {nuc} not in old results." - -def _assert_atoms_equal(res_ref, res_test, tol): - for mat in res_test[0].index_mat: - for nuc in res_test[0].index_nuc: - _, y_test = res_test.get_atoms(mat, nuc) - _, y_old = res_ref.get_atoms(mat, nuc) - - # Test each point - correct = True - for i, ref in enumerate(y_old): - if ref != y_test[i]: - if ref != 0.0: - correct = np.abs(y_test[i] - ref) / ref <= tol - else: - correct = False - - assert correct, "Discrepancy in mat {} and nuc {}\n{}\n{}".format( - mat, nuc, y_old, y_test) - - -def _assert_reaction_rates_equal(res_ref, res_test, tol): - for reactions in res_test[0].rates: - for mat in reactions.index_mat: - for nuc in reactions.index_nuc: - for rx in reactions.index_rx: - y_test = res_test.get_reaction_rate(mat, nuc, rx)[1] / \ - res_test.get_atoms(mat, nuc)[1] - y_old = res_ref.get_reaction_rate(mat, nuc, rx)[1] / \ - res_ref.get_atoms(mat, nuc)[1] - - # Test each point - correct = True - for i, ref in enumerate(y_old): - if ref != y_test[i]: - if ref != 0.0: - correct = np.abs(y_test[i] - ref) / ref <= tol - else: - if y_test[i] != 0.0: - correct = False - - assert correct, "Discrepancy in mat {}, nuc {}, and rx {}\n{}\n{}".format( - mat, nuc, rx, y_old, y_test) diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_days.h5 index d97acffec6923460cacfe609b1122c57e5181ce9..5fdc656d97018b596147839415fa967031dc18e5 100644 GIT binary patch delta 2299 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 pJbfr!@}fKV%LL{|8&T`&R$} diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_hours.h5 index 6d9bcc91ff7eff734feb83cf96e56f2b2d3e8819..65bfc19a91cc73512791a1adb2d1dfef8131c8a3 100644 GIT binary patch delta 2299 zcmZ`(e{2&~9Dnz^u)A5d)~)nbx9$owZ6?f>4OTaB&|gttkEWXmMUy7a{&=A&x68r|ZMbUxKYNRG;zQdOgGsmEt&u4Hz-We~RV4rN2oW0GYCI z{6l$axvgk{Tb$ZJ@uSkzjN;TvXn9wnqy?hOhxRP#Fy!{9fE$q8sFe$NWH3!=F&K`N zqP7B6Fq89I)eHq!L?|S+_!BE?Q&y@X)+vTU9L2@+yel9+;v0t5a!D8k%gl~vr;fcd{7mRzak%2 zHG(1P0D2wL00tZ$q|4(N-x{1}1qXeH8mwhuYmH#49fB~u8cpc8J^_`>0)U)XbA-I@ ziPfY8X)ZYc2pipn6l@KkZR_S?s1I#x5+GPB-qsFsYCw`) zxr&6`3+{PEDhhiln0DeNP#iuRPP8Mx*9T*J(P8fzIKB^6wp4xm$n;`J??W>iT$Bz? zdLKePJT0`hj2AJHeHg7n$GkQwDkdw0Xm^Ye+;o}}E3t!HIA(akq6*aBO{1h&Coan{ z%qU6GBEEu($@tXHX@-d{NEoScF<}%^J2UygvXg=1AK4~7pVV%3)y?tVxsI*pqd)e0 z=bFEtI`p#9Mbv=TP20arT*_}${LB}dhiW$+;1xe@G5IqW=d%8;u3@WT$N4P&^7`xV zzSx?d^{wd$d#AYOVb{eMxW1tK8b5e67-MHGF3o#qKlgm?b)9Xy9bGkfi~s7gZ}{2y zGo)}PhzT=6G_t=e*xMXvJh8Xmx^&Fs(GUI6GOYir$$8{TS>)GJPvNCMR}2Iuno{Sy zy$7}oHC-<&IW#tNyy=&>QQ=8ZF>~$8F6%7so#`>RNs5o%%-j&l&F{&Ae` z$Pu6>B}j?r4@<46snif8M4UoM09A2Q6{SIeOInbls;X&KIS8d(|3HdRCEPYN%)p-KFE3oMY=KaR-!IBUz`DfgJRRdd(m6=u zevB?WBzKV<@#+hYC>QEp4dn;Oe$b~gQk4Jo^-WDecm?c3(rqy^PhZtjhQCo?#3;?; z(ng@U>FyTQ!$Z_f%(I$sY5TpH<}2#Mysi|@k}E>aZNI3LvwLei+1J_IBLaR&BdbXf z>+JDpW)L0Z4A%$v0$C{{WN*GK?-vhscE$U*CE}zmu9Aw2Wdiz};t8oBYYZmieFI(n zeNZ&`i)@c9smg+f=vP2>LLPO*FU>=bBM%R0PeFauW%+#hAOIe=QI`=dT4??NiB)ug z`Pz&dF6Dz?yFaR8$sm=VygR=k%UMX3R002>xhh1O;t|?w@&ddWsnqpCZ;aAsuhjYV z)U3(7=wglur+7Shg>ESPtM&uJ(GSeAZgF#F83EG|fJbc`{5SEc6m_%?nJ3pZe$m;pDXx6(1?w6Em`YJkXRPyYe|$7hqr8Mhk$10i#pgOlZ>}_=*I-@{qZbIh3w!d2HIPq>Wm|Lb)yc@k%*E3G_*?e&q@9^`QZO0w&V5eB#rLNcgVBY1<8%|vu z0Vm!iXdad*eRBGky_mk<{f4X%X|np@h*KsZmCl7 zZe*pdCq?y5mv?xsZQF4d?_j4`-i_X*`@y`+oj07iI08<*i_ttnsZ#MSc%!Z%LiO2v zaTo8ysM?(SDAO1F)Z^T;KaM}FXooQJe;ZD5n#QsZ`JDCWa2BER^4_x z$vdQ6r?W-tt*fm!1*BAJDqXK+TU;wBsmh^!F?F*92i}{c<)j#*eJScS_o;Q%20yK% zp=YkEto0<4WqYCh+@_*&f?Zy7RYQ z>Va*?oxg=0)87_)pF5x?tvqV9;PYjMfaynr)c+v8=L9%vdv1QXy}P@emK*Z>gg)zg z2k;dB0Q!X_zvom4q09TeIWMt~8&yFw>%jb*sratrr8o1QQ@!z?(;)F;nA!oqnIZz9 zJ!dH$n4{kTWI=*`~T(A!>apU zpKgI)1TD)xZ+T19y0Y?>iuzM#DFnGL0}PFDU?NUDxMs`Pyi*v%L%7m-Y;FbaifuBPsBH zDKhjct0I#hOiBatX1w#^c+b}Mt^q3A->JS15u&emAlVWBuF|sFXn)tLHGsG7y>mA% z96#NEkMH8+hjB2+3;9zYpPYL@xbMGr z_zAoJS^jBP{sEiiyZF8#LiPGX`5U0wB;Ut3_6O#7LYv7<8ipOr#wdSWehK&ge5m!c z=OX{dqj`#*Nxo)9Rq>b>;*0Q%VXI~5-(@VtPZ4>%#m`HTP~zz8q`i~u9R2rvSS zz-Nzu+x^3#BKHlW4*Lb(Cw%r}&n;jC7y(9r5nu!u0Y+dd2so`93%wV1l-7;Vb9&yK za#%M)ALXagX4Yi{7y(9r5nu!u0Y-okn0*AMx^7GrSTBw_tP^>CIQwJEH8KK>03*N% zFak4$z_wd{)xPC{9g$+?yIVT;zkI`~#=~zkgzxwy6n*Kzmg9T>yfb>@$niy$$t7X5 z>+j!wCI0$b6`B7^)cT#9mL@j;Ec4%y4o)om!+pc&GU@%lyz|(-PaV&cU-w$op2sID zGU>qi^6KR$R)>?HYr3{I`nOQ}q1uCQpI;vCue|Q$M{h*KyT5rjbYkBJq37=N+k*q3);G{{F^^uP*r4{oA9eC$}T0lMHPQ;_~~;02=$cf(ubC#cQHfnGjAXKobB+rD)@IKCS3L%3_vDv!m+@ zV@a}v6u}0VII2(%;cx>gDAt-;GY(r?u%&?PKX)R~hVx$Zxy8s>O0hSKyAPr3B|d*s zu~Y)v9^wy^2Jn^wkRV`bSaca)Zz{)D8mdQqf4w2%2P$w}hYbj8#6P8C-@@NG4uDiu zF#5hYwcJ(|z`;*#yz~iSYHEIJWwf{}Go%Hg%Y%-W52|welfWIwp;m|mTq2kzv=|J- z73f6yfGW3ZjDA%^s3$5h^H8-Y0uV4;ErK&ja5h8Tq!p;GT1*|+WuvJPbXPa1a%gd| zmn1RxfL;=v)MIMLLlXF$!2zjSk$F~+gA29TW|(ybf%#DbW}Y=lVDTJ#(a**~mC}HN zO(coI&zU6Vgb6b%ACbT>xAM$&BJ;2b2Sat(W|)=r0&{geW**`XzVMK}(s3&dHI$zv zqNT%?I|Kp(BSfFHE?2Mg#;%g#Nb7Q?Im8|S@ZzpJ(uXithKDSiBbudx3F3o>VDvTd zux26{k{Q5=Ss1{$*@cvOI>xgV=UL87-=ij4S=iIUX<8>COm0DoC4Emp>9PPI=hY08 zw>`FnlpxI|$XhNoN0Tv__IqUO&AzO{Z0;oPX4wwlT!oY z5^$oowCxwpH?zdW|=AVi~FZrkN&*Jhemez9Kp;v4Jw z=BK1^%8v@|0|C!dYMGE4;JoigU3I$;tY0a0roX3A}o)#3Bl{XGF@rn(z^Yen@AA>jln95STG}?dnR+i%C@Mn43 zvJ}5{w8X!(nI-wmwc6#1EXm7z@-O+aB>z^ew*OVyVl!97eaCpkhn}hYu!>h)`90_K j@QRuBeamgU;yaB;Y}DWXRxBzXIpoM#v^ZXnC(Pg}lhi}5A;s+ltU8}&tk(k#ww z1lrrK?@&EFNZrIdtB+Q;-^*yeqCU*)fM}Oo5pr((ML^E((PVnKZ)i{i{gOsjlVaA{ z;HW5AX#tAYx>1sVwgoJNx>RBYRRwQWwjm;xd_leorzb6=aQ}baFV;KQatO zgTKi3$daloc!+)lRVU=pNc_?~^f>bHp!O8hM_rcBXAc74VJCGN(V~Oq50F?(7nrZ@ zxZzT6`Qc4*6-#zg`I+mB8?u~*RLPd`51Ok&OjA5Udre+|H{$_aFZ3oUec~HBznPjf zb1hvgGT{`DXU^3Pg@4t4Ksfq=Mb<5D&H^J~`T_8$li~xK1D=47$agEXA5c+OA17+G zL_PI%quFSO+xpJba)|#XUIEca>yRaKUE>#hgFQ**b5B{<7{CNXGnK0mb+X*(P=97X zu3nafT4=0dV%@o7-ATjGcHg;U)0>AsYOz-)hG9xNtzS(4TWTK>uGI!ZWcS0X^hG*7`ad1*?4)YGgL(K2ITdpp3+^x#R-QM%H8Pv0%(g&#>L8>KOSE$!P>C}Zf zAN)CRQK4Rz($g2~{E!x+{*pqy7^M^6B!xvT5O+=dg zer3M=7kFp-ADb`kcvnpgw(Yp%9qg3LyTl4zG4l>HhGj7XoOtJ_d4#f+;++}KZN9kU z9X+<5bG(C{a(OpJ>kQ@{W(><>2srU>ud!aO6z|OS@mzU_zS?%&#XHz3mva+RcF5cniHQSCm-oZ|}yvwfC{b1e|&Kpjh9swub zrDz_ZRHb;=_$^&S2i0fu#U1bH=cPHXGhwG(-o?VYAIv+<7?#BlaN^zc6@{fL#k=uu z>w2^{eqUwYVaBj5hJX|AroLNP3iEKjen)`yjl*l3*2~0=J!{urLvn+Z zn{>9=dUccarht@6O{JTa>`ZC}B~>}JFQIN$;J|y6w44i zYO6C+cQ3_#=$Y$)7}=Yl20+jBTkWKmTCFdjH%93RV_Zpn!32IkGTUSONq7F%OFgjd zxbwHLWBS`t?{f#$q?Jd#7JNR-5HS5{i25I*_nZJncyRTuu7QCrT5ibi6Natt9l%rg z1L&8M{GL-OgwF2!=Dfr{ZbAjkyaV%ZzT&%%m)_iaPR+)9PP>U0W7H1#%`6cB?Kwf| z;3EAFAP>TdTq0hYc)5MQxKxC4dLMHi;h&;jvfru5aGxC_igAe?w7&^ zdb7tTY&F2=T{3oy-IRQMlxc)Xc}W3C>$*M<$k#^GeO>+dzH~6t-QU-fL{i}WQe@~? zRz)s9l$HkM&1B!MNy*lQF`~G{!?za1% z=b!c!AFu_!i|-p^RIfi$yaAd`@_l?`e_(zm)JtZjVc5ZJg7T;2mvH~jhgx5IPV;{} z+Gp9R?0vcb%7KTa%uL>2sDW~(MBMfls&k4FU<4QeMt~7u1Q-EEfDvE>7y(9Lfe~=p zNA7pojv(y|Q6Brja?RD#|G$Jj%9|4VN<2s7{Us1%$p|n4i~u9R2rvSS03*N%FanGK zBftn$9s#H43BfX}K0wb8ppSjOQ}OW<&kOkZfD>|@&j>IAi~u9R2rvSS03*N%eEkTx z-9H>GbKfxGuwUSP!q-3c+yX{`5nu!u0Y-okU<77^fYZ9M)O%qs(z+3PPS2aO4(mqf zqx@{z%({#KBftnS0*nA7zz8q`3y;8T*Nxc{>%~cjbt1117k+HHMn-@UU<4QeMqs`W z*t6!3U3c94^H{m^y*s)efAWeqHy%3D65a5hNc>M*I*uNA`xo)-vq#Slq%Vr1UGLrY zm*fkt*5v*x(U#j+U7YIub?(0-J^8_TuWugvDwlrzq3^x?gZqx=%HQ~O?ZZF)peC0N zoUE>Ec&#a#x}fc{t?~CG(>ud|e&b|AbR=;3v40+kNB3D0W6QsO)!MS{ z@Dsi*M_Qlx`(3|Z`tKF3k9w{<`dqxV^}x!>+WU{(+8T{s`iR0|wdeTGMv23*2ghGl zINbB2?DN;9Y#eU*?QeEH@mCv%OSZkU{iZe>hkM`p{*TvW{+q+0`k|hlJMXe_7`(Rc zi>uyQlEdNf@$VeJ_rj*=1)Z1wqoMcx$Wu#?uTOu~5dFi|n>TEIDIOhq_HXHM=CjD? jGougg8axzv_2CDmK2Lnv()*L`8|oe*9MFHrJRJT9)R*{% diff --git a/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 b/tests/regression_tests/deplete_no_transport/test_reference_coupled_months.h5 index 43b45cb370c43d2d05000e6cb2dfa1b764d0d5b7..ed62e461049f610d488e7af40ebf18866ec600b5 100644 GIT binary patch delta 2299 zcmZ`(e{2&~9Dnz^u)A5d&aLY)w)VrHZ{P;ACf_k z4l)xMENS;-DUfVMqfCN0I5d+fX*H8UBzF8*K*W*l}V5Koi>1 zxaCZIABB?ny1e})tm8wm4T#f}Q2_Cp)zWXDMnKaVmPwInEMju3R9Lj<7$D_D&&=t7 zNp~n_%=3{FQK^KnKbKw`CkVMW`AJtGt*HHWYH?m&7bgB_K8~v`Cs%}G18Bm@GKt4< zCMXutjgWGqHF+JSQ@M|p0W|ixyfZN)C26AdnGjBCK{WtKudS1GuF}>cT>;Ca+0iAf zwJ=#oieLk5A~iP`!mcWmS75ZWb{uxrU`qkbf9^!E4(EO7Q>T@27GZA~cOOQV3OfST z1!@UwTZ!LA8o*l$K!SkPVbR5Sy{!aWb*Ns$qxCw8ADoBd95!I2RQXe+^ez9L!U2#f z3&q}7rk34`7PzIU^%XrWPt71rt(aDJB|=&ty1eK>NxMF~KNVb$+y<>uKv2Lmp~YZ0 zG7t5ZwCS_E#^^Uo33dN`%-mV7hyVo4mMh?l5}eIYR~uz&-iWEExQEeHH@eHU>)l2i z^phk8Z#Ao;lV(iqenJHwx40oyp)e1dad4sn+YB>jk(n1;F!Qig1uN&+hwfP0^*Rd< zR+A(KzhqOH6E@7Odr}2&cSy{Y3UikY2g8-vW|(!0Wajckn7LCr`0_*ciW4WROjLj+ zqSeEdJp=**-9(?dE?ckq#!i#rsOz$&xs@IO@ZqlO(}yryhLE61hG?$H3@1Gj;|J@vs6}Y%hxhtS|g|f?;$~cSbyjNd? zQuW86R}c?37%3QBBYw;eQZTU*t#6!#+%|E&JD-BBU1;;lSs2`hHaCe7G)T9#otzpl zMXp>`LiPpsswx$Q1QX*YUL3{X%b~a*`8-}2?L|jDwQ%Afs$5rf_NnQ)kUofhUF)KB zXwtI;b@H_6UpG;}gb!l04juPcsfd&`iII*dBf9A%B~@bkU*VYHhZdQTzk^0o9-Xu- z#W15JMN4=S6;<$wozn~xeJEj|CZvQxOzceM2FgC{`rx#6QaI<>}8n-Xt{+90_3`E%nW|!uj^PdY}d0gjTycbzI`7{6J*hT)q z>?fpfDu4-70W@-`EYLl+qwz}Ay8POYcA@8a?$imhS-2|njB(Xt!s+Ic#lO3c2n%a( z&wR7{hbHT(q0dkYFZ@w=m-($?Qkeekg(X9W>peGb%r7{3y~ne(0t@xI%;>5YR18Idjz??u^n+2o+j*mPu#g2<<|G?hymf2<|?Z0v7-9Hx$J6w_L zgQlB%Z}YtiR_&j^v%>Y9?d)3ro@Uqfqw%8gOTX|J{%&Yl_|xdW6wAt^yZkFN7G3Vk I%aLdB4@P3gTL1t6 literal 36312 zcmeHP4{TdU89&=eQ zMxecIV?y=t2z3+ltRYg_elMr_iuy3GYel={ijZ^LFKXrN-kHh{rU&{(z%OZJH7RPH zJs!;rqJx~_`T$=bYekgoT_?-?#Utt7)X?rsiqyr8QgOLVK))xIkqWZLU^X>4+&eS~ zMT5V{_Q;Z|EO>~11ym>G(M0^xJoGs7@QC&l)JI*G&({tD;9)0q8POs^^9M+*r3=j0 zcHD3&ANbUkxQZpasQlE%nGIRaLaO9S_y^5ZAtosvp}i(Az?;!pT`%;;DShF6I=_XQ zHFXbNEHdE~kEfRDhQhyUKOh|az#{7wH)nwnF#P~{)JgFH%>hrqN94Pe+7GCxtB(sc zTB4o?y3t~^!)<+6YdOS!6R%p)MC*_xa$VyW>HeOS^0}9-YYbp&MGKXy5i4Z5oddnY zeRB1(JlINO6&352iFMP4pY48pTgT~F|JrJ=Obo-6bXvcd{bP5#kGtD%&}LB20ZJdCb_A%F(28Qc1f?_Y z*ZJVjq55LI9Hl2$>inPVU6<8`|2Tw5or<4Dhq;X{b1*BNcgn*O(IzaOX zW#L!m%YT7)rvI_|;*NLK)L`3=JKn)gxx7o>tSe^TVaBkW2>~bG`Dq@ZY^8W-#&er5 z?s!L!t>+x?V5eN(P0%`nd50OpawY_vc(=z`uU3k8=K6T9yhC4YJMQ8g?3By9M58Xj zyt9$xD`y0pcsCU+E>kJqjoqT_nV|Y?zPO8b_<7B?@&r2E0V!;E1$69P`Wn_OL7s#3fg z{jjblNA=B>cX+OC+i@4~V5eN(jjhrBVBQta8%|vr0Vm!iX&#|erFa*-UDpt$`fR?q zi+5NWSNP1FWIt)ro5 zuB)xiNZmaY_n~L51EOSaiW&et({HttUgi#c0lg7Qj~U}i>I)|D`;plm+fTalw_fUj zZO5Izg&ou1mU^E%peC(68noc^HHLucM}yS=Aid`VI70n*JlfUQ*G0<>`F+Bm^}Pdl z3V#6oQj*_uDuvLseczmy*vE~jpjmKW{>@i>*YVPuf6uAKc+Y7U@nVG90l%3e0-!w? zC>>a&-vJarSdmM_OA{}*?-!SfP)_e-?j!s&)Jyg|6&dcU#;B9uX)<^Wp3j%x0bfkN zF21amVMspMBKWv@|BAEQ)Vdy%opOi5}fgVqi&6=w9~rfsaDmiFO&75Q}(_M{l)!K zxIl0A_=Kzm_`FL-?zfv#h>tRjFexu70BK#<=RWz`Xg1x|i|7y(9r5nu!u0Y-ok zU<4QeMxgQtI6Y4Ylv(v5dVT7y(9r5nu!u0Y>1x zN5Jj=;YgYLhB1fz0`C*v`?2R1FanGKBftnS0*nA7FdGD%){Uj!3p+;ZM(8;`Z_YWa z8=;T#vuQKyG6IYMBftnS0*nA7zz8fn0<&E==1Qy=#~s#*ygpp`vE>>W0Y-okU<4R} z`9fg#o!{%)@#!a{<;p+q=zi(t)u&@ekGDoPTnfj(|3Kozq2KR~zy8w`H`He9BWTxe zANpbHwKr<=|CMOV=hv*vZ2x-xzax#Fx&Gwlk^kn?FMjLpUwm@^iG2CkkLtet#F?6W z+CN>rqVdh<$c~%ZZrK`tEBy8&p;vx0-543H{m`#29*;+!`s~s0n}^Sbzq#3S*Q#cD z-SPIFV*~HD-skz{$RFx5`F5!G9s6Q(qt(u1si=~B|MKJ3m)F;HOrKjDi+^p)#h-no zF&18V@H^+$yc&D*wbyTtw0|RZ_gBQ`;r_pUB2+c`kI-kru`fKh`>A(sI~`l~r;C@) zK7UVq)3K+|9RA(j_!D~?UfMCdGT-ivfBwnSr|OsH>wjnUW2c_^=kxh~|LgI;xAp9r z&ZiG|eAV~Z$v5)l&o9evYQD+F;gv(r)qnS7bENe@ThARl|5o_j^p{@jOWYQ@wCwnX x@%{Hk>JmNm=^spn(+@R<1HV2RKK#PL&mBDV@7B!bpFh0+K8*wV4=D<8_#el*|FQr8 diff --git a/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 b/tests/regression_tests/deplete_no_transport/test_reference_fission_q.h5 index 4ae9d3660534b651edb9ee20529ff90a02888d20..9d32d89fe233fd05e736519766eb54fb9c5486d1 100644 GIT binary patch delta 2235 zcmZ`(eN0aVB9uM~lvZq75gDayRG=SgYpjW8Wg82B=*BWW{Mc6fLuF=K zBrb7d%(hnvYzZGG8Z^_ey%}*))3R(~B!sfLSYx6!`$J+()@j0O9K`qDy|3*WeNB6M z&bhzyJHK=9yNPo!J_$o+7(X4Zx7Er41pr|Aukfh&kMQVaq5<>acT5k53b13t1^_oY z>^yuSK0={Xv8wPr5?0y6vHeIdtEK?5%XaadW{E~21!#|c8{O?WaDNGnpmgG!v2)=dz9p%}-dmQ!uv*f?6Uu}tzI zoC$HIv=dS;)L9tNCKL~r0W|jYg%@Hviq}M|vmu;Pf+hfvTG`6$d`{VpR3$8vVMo`M zrqWa?DS{0!b5xN6!l6b~SfaDA796%&v890QKX)S3it~Q-wavuX%CI+wyPrVUO9R2C z5~&2X-NYXv4d5*WAW6W|u;_BU-dusLG*qAF!Fq$l4^`s09vd*P75|ipeG7jRH~`Ys z;n*kQ)bd+V0vA8Ev9hOyscHDBmDA#`%#ap{E+0BsF`&-xPXf0imqsZT@Q7fV&|)y0 zuSBOR`qlYeWAs~ELLI5X%!4(e2tdGWjR?*v!PzWzlTM(v>o9dfpNpo3(Ovz3+NHz6 z9+Jf1BL+!y%7Cd|k4oTKqYF}XBJ-R92bb!w%`)qa0`n6_%sgk3z~VXfqhCz}YLyWO zn@AFaUocC|Ni$|vJuZP?ZQ+^gMdl$h4o=i#n`Krt2+TDNn0b&t_`*Z>O3$q|)>1*1 zh?Wjl{tyTV3=@6Qx_rIT8@o=1BdyDq<`R1Vz>m9b&m6*h89uUbfoPTrCW#Lk!?Cx; z!`d{lpxI|$y+WpN0Tv_`Fm?aY%U)u-9J{t|J@ujZMe8!yepuuP2A;dWt_!zK5n<7 zbo)8z^Kc(_=qMQKs2;u9J!c`U66R)0S9=@+Io&!v`LN9(5DyE)K%b>`N) z-p$UHA104$97GK`q3vIc-&8myKmFao@s|A`*d;$@(E8IiHZ%U4N9K&`qgONd?|1z& z{c^V=;~P^G?7cGUBaRy{=|_UDpX`yTV3fUYaL7Ko{H^Dj*KzszjhW`P-|Sb=t?eb;!YXQ|6*+#_OP!%Y;v-gU7xfLnSr?qayE6nZ3I^1qW!NqCqH+$VD z|7@NXq?K1}>u=(v8Rr%k1!+HrZ~irvBW-1*@9wP}Y0dLr$)C)T_WtqGeJfiz+Rk39 zTdmB|wtAr8QXog$A2k~1KV?>jr7{sX!ApC6U)5*TytJwxIk%6O#@s)&+R972gJ#F9 HazWa^!kDwD literal 36312 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 delta 2155 zcma)6O=ufO6y6!R@=8|X^^dHTQ%S4hBBgHZHFjdx>%{VIOMIxQ?2|FL$fh(Q5LtyD zoJ(b=|BVG&KX6=1OL8eDG{t2vs!5=N928%o_9S|#p^&PjP@6)kOG9^eW@LL?L{~^} z-_LyWy-zc*{3)({hVyY;$>}eQM4sUg$8nOZ7F-Xl?0g> zdFpSskvREFIWFFLye>)oOc#kWjcx^w*OjPW4U)J-3@4tlUpnj)WW6RxfJ=q+;+N*h z;QdZ2J}zNOcE3x3e234J?eh)|o@hc8asPb|tCSk;HxCnCm;6rN4D_N6s6ZmXHv~;} zlLiPV=DXoe@J+w7ONOdIs@tM^wYxFZO6VvmT7kCECI6u!BuPMXAx2dQH>R459tFiU z$);KelW0XcifXAUM=h%7qm8MSdXAxHdTdnrITB6MEa5ue!?^DCH0GL!Gt}GB1V%9% zbnAH%EX9betGXVyn4X9?W?JZFnASDLsa_jYI!&SpnkArTdKuI0-o{Mh^v2OsRWX8n z5tPkSRoOLisw|UDIiBjo>YTc<*|S1hXLU{~5)`jSbQ`T-BWHV)v@r7`d0~K?)Gxq6 z|A+p%*GH=8QInY{!hkIbhyxN9hKAp*5|j#xGz zO0-2rWS{ziIc=YS(Cg`REM${%kj+TBRrGwM5Y&u4%do82|Lq|bYr`6{_ea^%^|5xq z%EvhQvXN852yf09cgMa!xVi{a7oOtyk})-Y65-S}m`^;#oA1K>gn@V{;t0qpe_C*~ zcsP8?c9)6as&LyKffbcU6qo!3)fHcFS zJc)}~%)zeKXC!CJt&m*gA(fUOnfCBGx(B@F3K*HiY74BS?X0K3QpUpKBM;=S%dovH znDot^a4Bc(EW5q1cb&H*fwnR$r+~;f&>l6**UsEoxH7$(_`eqRKbb{0VS4QixO+n! z`zt%%^6kCHub@9w^}z?b2RC=r;QK#qd^PpEI(O<1PtUZbW`F+W*UtB@s6Rd&oP03+ bj@tdh#?`N5-)nCJTFauxu)6lD%Y^v{OZI@OM`~u;qjR)hG!ue`Bi}jCm zE5Z5yg-)8tdO6xXYmBfE+xO4*)u-kZPhJhXXssg$4&QgIw>zZVAln=9&vwIE2Zm0r zYqsYb@}$2XP=p&GUCX{5#z99p{1%ae(8?3D03S|GS`j97N0_XQz@3^BM^3i^J_4*AV z7YZkz@0ayg2%oqb<=lS7l8){{HG%#!eYU|T0_i$$% zW$L-Kv3nxi-`+ZV*lUa>;qtH3zjPL#Tmk1-KIEJp7NrX3pY>JM{PD!r?qeXM(7Nh> zwrOH_Pl=vUv)dS#upsdhFe2_M@iT>lGuUl(6Rs-Va@AH*sdJkhhces%=XHgj0-v$N zBSL1<$J~ItC2$8V;1Cu3P=bg!zunJoP4+kf*Z*SD;qy0&jp2M_U#6mYlY*dpU_`um s;4?FW!2+(};s+HUx9JEUh;44ntv>wGzIR>m+wS)I$?GS|vVbB209Tslz5oCK delta 928 zcmcbxnCZe|rVRpp^_9A-60-su9f+mbid~$0)h{~xoa?>)=Z~$+r9eN^imNRya~ahWiP`fGcA`_{<1ZC7k(T@LK)OUmY+^EtJcLJJn|9ioy@ZEuS9bY{sWq2~$742HAbdAr_uJKd; zhl^stc9KHjFNBU7+sPcAQrYBl-B#w9{OyGWAMM@4W>jTNYn^<)U$%a)-D&%UZ_obR zu-L#^OD*lOile^sS4Wi=b*=#C?F}1~?4op>MUPsmH1(WxQoG^YcckF9)3Oyx9m&9` zoMIgwn)=<=W$(Y$f%(9w+?*xtz$q-{(CGg9Q6jUX1M5!L-_;Ik6})2h(maqsw zyn%-VQ^3SS@slUOLoTf2;o6Ol#NqOi9L@_vWtYMErmK!Ex7JjH^DEBAJ20=YwG&!j zUpL9q`LAuvguN<9y*2C-#Z$j*&~~zm$c?Lsxbe?+-b-%3O~qGi*S9QYYp6v;rNc(! z{c}$Q$MW^mn6FUYsXks`Zx9{h6 zjzBxUx~sP)B{JGg2>Oua`rgv6YWkZYJ zBF;|Yw_|{UWvR-$PUXLX^9zGnel6jhU<;Ff|GeYr)fpmid12wGjR)hG!ucvWi}jCm zE5Z3P!Y55+y&UcSHAYy7?fYjt?Nf7#C$ENGqSlcEhwnSq+eIih$o5A3v+X?Vz|hHc z&Gt+~p7i$vif{v>YS}kzYGtv9IiRb0l|V$vLb!vTCj{@k(yj?t|8(2BWqwr$;QSLm zznq!8+7Qmq_wg^Af5sQeH)LSY6-e5)!O9A*ApYN~4|zf+aDJcljyw7xAMNLJtltoF zp>Xo~ep&AuvlrW6Sf79FX}f{5=9Ej5&xEKtdmkunRFtrCwtAL&%*tBTId{LAu6zC| zCtZWLpMI&`aXNfX%(NL85j^%?shhsrx(GZt;6EJ^5xf6eYc5w7fLlBHQf)k!$p<+9 z`9UA~OP>)DvFYifjuZz$xcsa)YqMUquZHu}Wjg9a&gsDUekr$>o}KDs=liEcmu31N z+j&1$ewGVUxAPa^Q|gj(s<&GuSZjG^!5>?;H7@_%FJG~>;qUvFHAw+(02_l_`SH8V z@Q4WC=@xv7djUKm9L;Qk^^;`b>g~U2|JO3u59dF)nsEO76+}ejD#dIucpL_m2S&u= tle|U8o6X=Fa`+sbTjjOje51*`+u6>2vd>H37`3Q8Wb*onvMiv8004H%=u`jz delta 928 zcmcbxnCZe|rVRpp^_9A-60-su9f+mbid~$0)h{~xoa?>)=Z~$+r9eN^imNRya~at6C<+l32wwLD|Fjq6uu&bZD`%k8flbzyH zJ^t)Ze{Jt>-x^uB?TYQi%fVkS`zXQ<2$aZ(O-yF7hdH2+)nUg^pM`J-)i-PT^+v0} z)jKVHd#26)Ae{eV&Cm83KaC-LC!i^(zZaYe-yLXo{Hy1r3{OV8;9ZNAuJKvgC4b8Q za8WGS?u%gf3!$UNcFsqqR5tlsx8*q|e|urUNBfr68C4n6S|^|Hm#wdxeae2p+p|A6 zEH-eSJ>zJ1+)fqenUhT7fBv>|-gPJ}c<~t(XUU`1Dos5noiuJZ_Z=y??X+x#Qb#f{ zDyLY7ho*kFb=muGbznX)DmQ0IJ8%k1Im~u{{V0)H(t%;8>+efVX%5;>JJ%>aNpP5J zD#h5S9q15g(Z?{SHpC%9YiIqx8erW2X=5&0SsvnGAQj%b7RXoW|GAOR1re2;zrC~H zE<{A-!6o0O=}(vd54qV}!VRNp#o!@jujIwPpkz6mZ#SuW0wdR+|-}z(fU@iUa-!u)oq`r%7?zT>LnUkZNdsF|}Uh+8n;<>;TTjPZ`>H0qv;0Db3 z94PLViipapzfChQY*-9;P`vLyne<|1xcWo!_633e_QUxOvR>;8&zjgVxIq&`-Sg$0 z`Ii26kBUvNowH}OOA$F}xG&Yx?sg;3{E`DfcBbd&t(W4|w~LBZExT~@nr&3@oxq5s VkM2X_>r!qAUw2Dgg)gPhtQ7 diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 index d428cdd7cc9a856b83f4b8517e1192c1336fcd06..11092aca6e1068573910661177b9f1aedd6aaf25 100644 GIT binary patch delta 780 zcmcbxnCZe|rVRpp6E7Hu%dD+fxla9}^A?j7JM+J`E`QTgjxM;`GI=4J{KN}d^*ben zBF;|Yw_|{Ud8x{~PUXLX^H&A4{93|0!4@VT@S@}C)fpmic~{}6jR)hG!ugUpi}jCm zE5Z3%!Y55+y&UbLn<6a4_WiT{@~Jt+lUKtoP3y>k!}lHQ?d~Wy$o5A3vrRkez|hHc z&GvIcp7i$vif{v@YuPt!YGtv9IpAaUDuIZSg>VP`O9Xo~e%YJ_y@mEy*5@C4+HT;iH|5ggGa;(Zeg}#h6(y{k?VhC`v$9ro4%=_0>z;qg zNy^~ur(bG!oDQE8Gi?S&gn)fl>Zb3uE`kpZ_)ovu;sW!SY9!+e-HabjCpUktYwpx> zp2qcX!Ruw8ohBaCsOMj1$p8I3AKXoEkBby~biRZ0w3 z@*|gj!3sG4+{P=5cT6;Z^OY1{2yGE{wR)=Z~$+r9eN^imNRya~a?40@D!0}DwOumjfVrBHhTX)uyZ>a$IN2#I z)#K0p^w&0T`_{<1ZC7j?F9(0U?4t-bV6sF;Y+^EtJ&hPb5fPO~R)-2T`Y(rvTnmrU!gE{I;CzXGY4;X)N4spb zde4QKx_@n*rq3L8NeB52%zyF_Ys$N80W!)9qS%073zpSVPH=v|F zDO<{y4IY(z|8F&&IK2q&pyuCaUBuoX)X&&`;i29eL{#21E-9ZWZDPmZ22Bi^w{QCF zmkzSySYvttMyg)iM9mWO?Fw7=k?XlZhF!Cw~RBc**f<0J)0i& V(LSM}OF*Wiee(K=vMive1OSs0NSu&86$Agq}Ox`<@p9QGJ9su9PFO>iQ delta 334 zcmcbxnCZe|rVRpp^_9A-60-su9f+mbid~$0)h{~xoa?>)=Z~$+r9eN^imNRya~a)=Z~$+r9eN^imNRya~ai+pkR_iE!6!mnicB4Ks5I;&RZ9IQb@|7Ozgn!tTj#!v!U*N*3K^T$T<_vhlvAe Z5wM4l1VDU<`>q4s$1!>DM1B^K8v(_^mD&IR diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 index 407c2114e8ecd797d646dd5e57ff51e5e9c3b2c6..73f290aab629676059dc610bd7fa0045932cf656 100644 GIT binary patch delta 104 zcmcbxnCZe|rVRpp6E7Hu%dD+fxla9}^A?j7JM+J`E`QTgjxM;`GI=4J{KgCEjFa#7 p^D{Hd$(WqzDnIdpkhmgL`39(RmJB52@gU_KllM;KX8~%l2LP+eEz1A^ delta 334 zcmcbxnCZe|rVRpp^_9A-60-su9f+mbid~$0)h{~xoa?>)=Z~$+r9eN^imNRya~a3w1w?W`(*h5Y2sz^VY?l6q0i2bk1V=-kao5E}3#{p=PB+O7*^-T22)X fv!U)sqD8 - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/tests/regression_tests/deplete_with_transport/test.py b/tests/regression_tests/deplete_with_transport/test.py index 49e0203671e..0f7ebf00f31 100644 --- a/tests/regression_tests/deplete_with_transport/test.py +++ b/tests/regression_tests/deplete_with_transport/test.py @@ -12,7 +12,7 @@ from openmc.data import JOULE_PER_EV import openmc.deplete -from tests.regression_tests import config +from tests.regression_tests import config, assert_atoms_equal from .example_geometry import generate_problem @@ -96,23 +96,7 @@ def test_full(run_in_tmpdir, problem, multiproc): assert nuc in res_ref[0].index_nuc, \ "Nuclide {} not in old results.".format(nuc) - tol = 1.0e-6 - for mat in res_test[0].index_mat: - for nuc in res_test[0].index_nuc: - _, y_test = res_test.get_atoms(mat, nuc) - _, y_old = res_ref.get_atoms(mat, nuc) - - # Test each point - correct = True - for i, ref in enumerate(y_old): - if ref != y_test[i]: - if ref != 0.0: - correct = np.abs(y_test[i] - ref) / ref <= tol - else: - correct = False - - assert correct, "Discrepancy in mat {} and nuc {}\n{}\n{}".format( - mat, nuc, y_old, y_test) + assert_atoms_equal(res_ref, res_test, tol=1e-6) # Compare statepoint files with depletion results diff --git a/tests/regression_tests/deplete_with_transport/test_reference.h5 b/tests/regression_tests/deplete_with_transport/test_reference.h5 index af0e3ff46f630056ab9141b30ddc2e0433473cc7..e8478250be6497c4d6ada14ca8fd20ae217b4fc6 100644 GIT binary patch literal 163736 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%0D>17(icZ91W!%}Q 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 Date: Thu, 22 Jun 2023 13:26:22 -0500 Subject: [PATCH 35/45] Fix test error and deprecation warnings from numpy 1.25 (#2573) --- openmc/cmfd.py | 7 +++---- openmc/model/model.py | 13 +++++++++---- .../ref_depletion_with_feed.h5 | Bin 37328 -> 37328 bytes .../ref_depletion_with_removal.h5 | Bin 37328 -> 37328 bytes .../ref_depletion_with_transfer.h5 | Bin 37328 -> 37328 bytes .../ref_no_depletion_only_feed.h5 | Bin 37328 -> 37328 bytes .../ref_no_depletion_only_removal.h5 | Bin 37328 -> 37328 bytes .../ref_no_depletion_with_transfer.h5 | Bin 37328 -> 37328 bytes .../deplete_with_transfer_rates/test.py | 2 ++ tests/testing_harness.py | 2 +- 10 files changed, 15 insertions(+), 9 deletions(-) diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 85550c49517..d45396f1416 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -1074,13 +1074,12 @@ def _initialize_cmfd(self): # Get acceleration map, otherwise set all regions to be accelerated if self._mesh.map is not None: check_length('CMFD coremap', self._mesh.map, - np.product(self._indices[0:3])) + np.prod(self._indices[:3])) if openmc.lib.master(): self._coremap = np.array(self._mesh.map) else: if openmc.lib.master(): - self._coremap = np.ones((np.product(self._indices[0:3])), - dtype=int) + self._coremap = np.ones(np.prod(self._indices[:3]), dtype=int) # Check CMFD tallies accummulated before feedback turned on if self._feedback and self._solver_begin < self._tally_begin: @@ -1434,7 +1433,7 @@ def _calc_fission_source(self): # nfissxs # Calculate volume - vol = np.product(self._hxyz, axis=3) + vol = np.prod(self._hxyz, axis=3) # Reshape phi by number of groups phi = self._phi.reshape((n, ng)) diff --git a/openmc/model/model.py b/openmc/model/model.py index db0b05e15d9..2b5681d8111 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -263,10 +263,10 @@ def from_model_xml(cls, path='model.xml'): model.materials = openmc.Materials.from_xml_element(root.find('materials')) model.geometry = openmc.Geometry.from_xml_element(root.find('geometry'), model.materials) - if root.find('tallies'): + if root.find('tallies') is not None: model.tallies = openmc.Tallies.from_xml_element(root.find('tallies'), meshes) - if root.find('plots'): + if root.find('plots') is not None: model.plots = openmc.Plots.from_xml_element(root.find('plots')) return model @@ -575,10 +575,15 @@ def import_properties(self, filename): cell_id = int(name.split()[1]) cell = cells[cell_id] if cell.fill_type in ('material', 'distribmat'): - cell.temperature = group['temperature'][()] + temperature = group['temperature'][()] + cell.temperature = temperature if self.is_initialized: lib_cell = openmc.lib.cells[cell_id] - lib_cell.set_temperature(group['temperature'][()]) + if temperature.size > 1: + for i, T in enumerate(temperature): + lib_cell.set_temperature(T, i) + else: + lib_cell.set_temperature(temperature[0]) # Make sure number of materials matches mats_group = fh['materials'] diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_feed.h5 index ae1c7e42301e81c0fdff0778b280309960aca009..4f270afab00ddb5651aeb22aed0ca9b32c173d06 100644 GIT binary patch delta 702 zcmcbxnCZe|rVR`F>Qg0!BF;|Yw_|{U+EnFTr}AIH`6q%|el6jhU<;FvebMps>I@OM z{70dvjR)hG!uf7Fi}jCmE5Z5d!Y55+y&UZlnj$R3_WiS6`KdX@lUKtoRqM!s!}lHQ z?Pe%9$o5A3vn@F5z|hHc&DO3lPx|`-MYsW5YuGnzYGtv9IpA#dDuIZSg>VO5P6*z6 zrCk%Qe(|<-%lxVi!1--Iznq!8+7Qm4?c-lI|BNq`ufxFbSRiTJ1}iJLf+c@eeaI6s zf%Chqcihnr`Dj0%WAdqfCD(?sIrbOV=O268Zs5GnS}!r!!@&82e_~5Am%p=rV4R|; zrml1JeluP7{8LWy25&$8QoG}H=$x2ov-(A6Ui+@pP2X)@cqbc92&m5~+HA8B5%O;9 zQavHy;$*?rj%x^ewmN4xqNGudR<2Qk>y3++v~ciMOFBF;|Yw_|{U52?z#PUXLX^DhUp{93|0!4@X(_@d+K)fpmi z`31sJ8xO`Wh4a;N7V97BR)X{Y3!OBP^>Va())-+Sw(pZ zZ+A$!LAE#IpY4XT4h)@K*KE%>U*}WTjp1F0M1|a^UImZs}13N3m^Zo`Dc8gd>sac3j#^oHdtA~70CWu^&wBl z1kUfb-f>4idB}2m0Vq77TTX%pMUIWyMgl(YrVu^4+G~f{)sKgT>j4LfpLnW zn!3)l`^|LS^G`Xs8NB`UOYM%+;d5f9&FUAOdF;DVH+{Et5twW^A)tQ2x5El+5FyXM z=I=j8-uG~Ok23XK+Sol2?on@@J?u5cl5qLg>0dgFPp*LTD<5)B4~tTT^UwOKYW{d) zYxgmbQD|NDKif31yQf6YsM&3dOIVQj$Nbt z4RBsp_$lxiJ3QoNCVk8e$Xfz;&;kxo!4D;fnDX2G{MKZTBXIpMCLKP1qu3bEH}+*J znl~v3#y4Pi^T20j27?7mfZ^f?6(6_h2p@=TZp^Jd{L#L5UGdxQ_WH@|C(5#bf*$~| C+t1Sg diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_removal.h5 index 8b60044ad4970e7308d0c470c53382b9786ba745..5ee1d696d3ea0313cecd6169f335bf1b680e2041 100644 GIT binary patch delta 678 zcmcbxnCZe|rVR`F>JLi^MVy_)Z^r-yx@pS0PUXLX^IrtB{93|0!4@VT|DxmR)fpmi z`Psrz8xO`Wh4ZK8EY?5Ltpw-C37<5P^>Vb6Y>u!H+xO3w_j7ZKC$ENGkk*j{hwnSq z+uc@fknN55XM69g14Ad*HQTVpJn8QT6yXNg*RpTe)XHKHbAUVPGNC@70 zrCk%Q-h11+Wqwr$;C$_0U(QTkZ3yQt_3pMI&` zaXNHP%(PkkqBF03SL&wkwl2Jr4JY{5yIxISsmvw-H@{jaXSRgK2RMJLql=o;6GRC2 zUxWlwb1-Jo6UAEl4lYe+!4(MZ k_h>e4*MjqBY&-s9(ezLDYv(RBdcVA5^7@IgETHfQ0NjtqbN~PV delta 678 zcmcbxnCZe|rVR`F>gPxbMVy_)Z^r-y%Tkqhoyva&=NAUE{93|0!4@X}{&~mKt20F4 z^1{MV8xO`Wh4WQ%7V97BR)X_ogio5tdO6ztYmBfE+xO3Q+Nb6ePhJhXM6DwS4&QgI zw~J72knN55XWMz!fuWP@n(di}Jn8QT6yXL$)v|Bc)XHKHb3j-1DuIZSg>VNwPYB+7 zrCk%Q{^_=L%lxVi!1*VBemOIFwIQ6J@8e%K|BNq`FU-K8E0DBpgOwFrLHy*6{noBG zW-qqCus;9T({=-A%_)~Ap9xWQ_C8SDs3>9OZ1pVln3c7vbMAgKUHAM`PPztfKmAg> z<8=6(m}#^6MQ0xSuGCH6ZCwN=8&2@A-~HcObGfnr-2BOxYU8;~KEV0U5BkVo`iuzS zO-~{KT^-#;z7EYttk&ik?Qvs{?E zoxcE|QkRrdz1=FoTFWyF{@Ajuary6l`HHO#f8V#PNeXZS*cjZ(kKbj6hj92#x8PIU z3*aH_Xl4_vpCk)cZ~smEzm~y%IRC-bg!AXGAVN4-DQ1ho<1nbaAp^tWle|U8o6X=F la`+sbTjjOje51*`+u6>2vd>H37`3Q8Wb*onvMiwR2LPh1$VUJG diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_depletion_with_transfer.h5 index 11092aca6e1068573910661177b9f1aedd6aaf25..791447253c5a3d6626037f202ab67dab218303a7 100644 GIT binary patch delta 696 zcmcbxnCZe|rVR`F>K{uAMVy_)Z^r-yQ&N?8oyva&=Wh>Y`L%?1f-Ouw?M27at20F4 z@>#-B8xO`Wh4YJY7V97BR)X_&gio5tdO6x9H$_;8?fYjd^|?94lUKtoUhBw#!}lHQ z?M^5+$o5A3vz>X?fuWP@nypJ?p7i$vif{ui*RXHc)XHKHbHJzSRRR$u3*ippP7L0A zrCk%Q{`9tW%lxVi!1;Q=zMPr7+7Qk^1J!N5qy7rGfgoOW#fT-V&GY4MJU25`ReohL$DL|yH! zq<;C~wePR3`R_#Q(>3aLtkWKc9N=@Rw_ExrUf6xvKif>kfCd%OtF~t9?_xigBf>pq z&cZL-7+B%qu3)%jPHpJ|c(^-$n|QP0o-Eu#v-)VipK=G`{8uvfB!1p7g7cR=Y&vp4 xD;&z#Wneg=p{96sx;b3I9>2$J{%`f*e7l;P@$deBv=9D1ee&vwiY%ZQ003l3&+z~N delta 696 zcmcbxnCZe|rVR`F>UT;CMVy_)Z^r-y^HP;}oyva&=dTK8`L%?1f-Ouw;6=yNt20F4 z@~*;B8xO`Wh4UqI7V97BR)X`jgio5tdO6xfH$_;8?fYl@mk_-7 zO1mapeb=^i%lxVi!1*VCemOIFwIQ5u}k7!v)+_Tlh1^xI{O_cZd8=8a<+Sxdd$jN)j4dxnXY^O zDJLm|x1WBg-ElfRS#g5AplT%J3*C$#PA4~iu50epah^6gaDsk4|1v}V@8|j8w!A$q zQs~k74$j}AxI}bC4kFyA-FZ9B{f;nPepAbjT>b?s;QVtNuPoj%(E!d@Qg|V>Mby>q zx!lhmUi<#qswgL0pRQ52yZrxA$N@g5db^Fnal-D){@M2U1UIONUbUUO`giOHb40k$ z>)Z8Z8v`pm+(Vx4n^Rl503Pmv3pd=XxF-v@u;Nvn-%q)NaK6l^ClWtz7{U2+Z`+O> y&?f3)ve@_zE_iHa)`fAi;e^?YEI<|Z E06AC|82|tP delta 48 zcmcbxnCZe|rVVfUnKvw$IXTf)e&PioLB+KdE7z%CblzZ+VrTx>)`exW;e^?YEI<|Z E04A&zF#rGn diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_only_removal.h5 index 535f5d14387d0231f68133c19a6488c287d084ac..7a3b95c812c47c5bdf5f485f679015ea38c691e3 100644 GIT binary patch delta 48 zcmcbxnCZe|rVVfUnKxw2oSf(?Kk%zF%aKdax7N81y E03Fs8zW@LL delta 48 zcmcbxnCZe|rVVfUnI~A!nw;n=Kk%y|xaKdax7N81y E01?U*DF6Tf diff --git a/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 b/tests/regression_tests/deplete_with_transfer_rates/ref_no_depletion_with_transfer.h5 index 73f290aab629676059dc610bd7fa0045932cf656..7d68d1d5f8576fde9a5e227efe3d18136a6c629e 100644 GIT binary patch delta 48 zcmcbxnCZe|rVVfUnGd|kot)?@Kk%zF%aKdax7N81y E04?qnhX4Qo delta 48 zcmcbxnCZe|rVVfUnHlC}Oipx_pLjt?P;qU=%5~}&oi~`I*qQ&ebz#|TIAJy;3s8kU E00HI`X8-^I diff --git a/tests/regression_tests/deplete_with_transfer_rates/test.py b/tests/regression_tests/deplete_with_transfer_rates/test.py index 99f35a95bdf..d6d58bbc037 100644 --- a/tests/regression_tests/deplete_with_transfer_rates/test.py +++ b/tests/regression_tests/deplete_with_transfer_rates/test.py @@ -2,6 +2,7 @@ from pathlib import Path import shutil +import sys import numpy as np import pytest @@ -45,6 +46,7 @@ def model(): return openmc.Model(geometry, materials, settings) +@pytest.mark.skipif(sys.version_info < (3, 9), reason="Requires Python 3.9+") @pytest.mark.parametrize("rate, dest_mat, power, ref_result", [ (1e-5, None, 0.0, 'no_depletion_only_removal'), (-1e-5, None, 0.0, 'no_depletion_only_feed'), diff --git a/tests/testing_harness.py b/tests/testing_harness.py index f0edf4ea44e..40c9d37d806 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -181,7 +181,7 @@ def _create_cmfd_result_str(self, cmfd_run): outstr += '\ncmfd openmc source comparison\n' outstr += '\n'.join(['{:.6E}'.format(x) for x in cmfd_run.src_cmp]) outstr += '\ncmfd source\n' - cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.product(cmfd_run.indices), + cmfdsrc = np.reshape(cmfd_run.cmfd_src, np.prod(cmfd_run.indices), order='F') outstr += '\n'.join(['{:.6E}'.format(x) for x in cmfdsrc]) outstr += '\n' From 8cc1c33463888fe277d0bddb9d4abdf8d3bc6e8e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 22 Jun 2023 21:36:33 -0500 Subject: [PATCH 36/45] Updating source definitions in examples (#2571) --- examples/custom_source/build_xml.py | 2 +- examples/lattice/hexagonal/build_xml.py | 2 +- examples/lattice/nested/build_xml.py | 2 +- examples/lattice/simple/build_xml.py | 2 +- examples/parameterized_custom_source/build_xml.py | 2 +- examples/pincell/build_xml.py | 2 +- examples/pincell_depletion/restart_depletion.py | 2 +- examples/pincell_depletion/run_depletion.py | 2 +- examples/pincell_multigroup/build_xml.py | 2 +- tests/unit_tests/weightwindows/test_ww_gen.py | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/examples/custom_source/build_xml.py b/examples/custom_source/build_xml.py index e9a9a065687..6db136216d7 100644 --- a/examples/custom_source/build_xml.py +++ b/examples/custom_source/build_xml.py @@ -18,7 +18,7 @@ settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.IndependentSource() +source = openmc.CompiledSource() source.library = 'build/libsource.so' settings.source = source settings.export_to_xml() diff --git a/examples/lattice/hexagonal/build_xml.py b/examples/lattice/hexagonal/build_xml.py index c0aa815b412..96ff3f34a11 100644 --- a/examples/lattice/hexagonal/build_xml.py +++ b/examples/lattice/hexagonal/build_xml.py @@ -115,7 +115,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings_file.source = openmc.source.Source(space=uniform_dist) +settings_file.source = openmc.IndependentSource(space=uniform_dist) settings_file.keff_trigger = {'type' : 'std_dev', 'threshold' : 5E-4} settings_file.trigger_active = True diff --git a/examples/lattice/nested/build_xml.py b/examples/lattice/nested/build_xml.py index 06641f5ac57..407a53a2327 100644 --- a/examples/lattice/nested/build_xml.py +++ b/examples/lattice/nested/build_xml.py @@ -125,7 +125,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings_file.source = openmc.source.Source(space=uniform_dist) +settings_file.source = openmc.IndependentSource(space=uniform_dist) settings_file.export_to_xml() diff --git a/examples/lattice/simple/build_xml.py b/examples/lattice/simple/build_xml.py index 17544b87f50..0da8d8cf086 100644 --- a/examples/lattice/simple/build_xml.py +++ b/examples/lattice/simple/build_xml.py @@ -116,7 +116,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-1, -1, -1, 1, 1, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings_file.source = openmc.source.Source(space=uniform_dist) +settings_file.source = openmc.IndependentSource(space=uniform_dist) settings_file.trigger_active = True settings_file.trigger_max_batches = 100 diff --git a/examples/parameterized_custom_source/build_xml.py b/examples/parameterized_custom_source/build_xml.py index 3c67e244dc4..23d9930c0f2 100644 --- a/examples/parameterized_custom_source/build_xml.py +++ b/examples/parameterized_custom_source/build_xml.py @@ -18,7 +18,7 @@ settings.run_mode = 'fixed source' settings.batches = 10 settings.particles = 1000 -source = openmc.IndependentSource() +source = openmc.CompiledSource() source.library = 'build/libparameterized_source.so' source.parameters = 'radius=3.0, energy=14.08e6' settings.source = source diff --git a/examples/pincell/build_xml.py b/examples/pincell/build_xml.py index c5d614ea90c..cd8923fbea1 100644 --- a/examples/pincell/build_xml.py +++ b/examples/pincell/build_xml.py @@ -68,7 +68,7 @@ lower_left = (-pitch/2, -pitch/2, -1) upper_right = (pitch/2, pitch/2, 1) uniform_dist = openmc.stats.Box(lower_left, upper_right, only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +settings.source = openmc.IndependentSource(space=uniform_dist) # For source convergence checks, add a mesh that can be used to calculate the # Shannon entropy diff --git a/examples/pincell_depletion/restart_depletion.py b/examples/pincell_depletion/restart_depletion.py index 6bb715f3b59..ac065d3402f 100644 --- a/examples/pincell_depletion/restart_depletion.py +++ b/examples/pincell_depletion/restart_depletion.py @@ -27,7 +27,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +settings.source = openmc.IndependentSource(space=uniform_dist) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] diff --git a/examples/pincell_depletion/run_depletion.py b/examples/pincell_depletion/run_depletion.py index 6a6c25f59bf..493e3117837 100644 --- a/examples/pincell_depletion/run_depletion.py +++ b/examples/pincell_depletion/run_depletion.py @@ -72,7 +72,7 @@ # Create an initial uniform spatial source distribution over fissionable zones bounds = [-0.62992, -0.62992, -1, 0.62992, 0.62992, 1] uniform_dist = openmc.stats.Box(bounds[:3], bounds[3:], only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +settings.source = openmc.IndependentSource(space=uniform_dist) entropy_mesh = openmc.RegularMesh() entropy_mesh.lower_left = [-0.39218, -0.39218, -1.e50] diff --git a/examples/pincell_multigroup/build_xml.py b/examples/pincell_multigroup/build_xml.py index 1f34683919c..48671698d0a 100644 --- a/examples/pincell_multigroup/build_xml.py +++ b/examples/pincell_multigroup/build_xml.py @@ -114,7 +114,7 @@ lower_left = (-pitch/2, -pitch/2, -1) upper_right = (pitch/2, pitch/2, 1) uniform_dist = openmc.stats.Box(lower_left, upper_right, only_fissionable=True) -settings.source = openmc.source.Source(space=uniform_dist) +settings.source = openmc.IndependentSource(space=uniform_dist) settings.export_to_xml() ############################################################################### diff --git a/tests/unit_tests/weightwindows/test_ww_gen.py b/tests/unit_tests/weightwindows/test_ww_gen.py index 74bbcfadaee..a5f65ff617b 100644 --- a/tests/unit_tests/weightwindows/test_ww_gen.py +++ b/tests/unit_tests/weightwindows/test_ww_gen.py @@ -62,7 +62,7 @@ def model(): # 10 keV neutron point source at the origin space = openmc.stats.Point() energy = openmc.stats.Discrete(x=[1e4], p=[1.0]) - settings.source = openmc.Source(space=space, energy=energy) + settings.source = openmc.IndependentSource(space=space, energy=energy) return openmc.Model(geometry=geometry, settings=settings) From e94d59c0fb232e47661c613460801204c678232f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 24 Jun 2023 18:03:23 -0500 Subject: [PATCH 37/45] Remove use of sscanf for reading surface coefficients (#2574) --- src/surface.cpp | 131 ++++++++++-------------------------------------- 1 file changed, 27 insertions(+), 104 deletions(-) diff --git a/src/surface.cpp b/src/surface.cpp index 2403d0c6ab6..3050cf104ee 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -34,100 +35,21 @@ vector> surfaces; // Helper functions for reading the "coeffs" node of an XML surface element //============================================================================== -void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1) -{ - // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 1) { - fatal_error(fmt::format( - "Surface {} expects 1 coeff but was given {}", surf_id, n_words)); - } - - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf", &c1); - if (stat != 1) { - fatal_error(fmt::format( - "Something went wrong reading coeffs for surface {}", surf_id)); - } -} - void read_coeffs( - pugi::xml_node surf_node, int surf_id, double& c1, double& c2, double& c3) -{ - // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 3) { - fatal_error(fmt::format( - "Surface {} expects 3 coeffs but was given {}", surf_id, n_words)); - } - - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf %lf %lf", &c1, &c2, &c3); - if (stat != 3) { - fatal_error(fmt::format( - "Something went wrong reading coeffs for surface {}", surf_id)); - } -} - -void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1, double& c2, - double& c3, double& c4) -{ - // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 4) { - fatal_error(fmt::format( - "Surface {} expects 4 coeffs but was given ", surf_id, n_words)); - } - - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf", &c1, &c2, &c3, &c4); - if (stat != 4) { - fatal_error(fmt::format( - "Something went wrong reading coeffs for surface {}", surf_id)); - } -} - -void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1, double& c2, - double& c3, double& c4, double& c5, double& c6) -{ - // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 6) { - fatal_error(fmt::format( - "Surface {} expects 6 coeffs but was given {}", surf_id, n_words)); - } - - // Parse the coefficients. - int stat = sscanf( - coeffs.c_str(), "%lf %lf %lf %lf %lf %lf", &c1, &c2, &c3, &c4, &c5, &c6); - if (stat != 6) { - fatal_error(fmt::format( - "Something went wrong reading coeffs for surface {}", surf_id)); - } -} - -void read_coeffs(pugi::xml_node surf_node, int surf_id, double& c1, double& c2, - double& c3, double& c4, double& c5, double& c6, double& c7, double& c8, - double& c9, double& c10) + pugi::xml_node surf_node, int surf_id, std::initializer_list coeffs) { // Check the given number of coefficients. - std::string coeffs = get_node_value(surf_node, "coeffs"); - int n_words = word_count(coeffs); - if (n_words != 10) { - fatal_error(fmt::format( - "Surface {} expects 10 coeffs but was given {}", surf_id, n_words)); + auto coeffs_file = get_node_array(surf_node, "coeffs"); + if (coeffs_file.size() != coeffs.size()) { + fatal_error( + fmt::format("Surface {} expects {} coefficient but was given {}", surf_id, + coeffs.size(), coeffs_file.size())); } - // Parse the coefficients. - int stat = sscanf(coeffs.c_str(), "%lf %lf %lf %lf %lf %lf %lf %lf %lf %lf", - &c1, &c2, &c3, &c4, &c5, &c6, &c7, &c8, &c9, &c10); - if (stat != 10) { - fatal_error(fmt::format( - "Something went wrong reading coeffs for surface {}", surf_id)); + // Copy the coefficients + int i = 0; + for (auto c : coeffs) { + *c = coeffs_file[i++]; } } @@ -279,7 +201,7 @@ double axis_aligned_plane_distance( SurfaceXPlane::SurfaceXPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_); + read_coeffs(surf_node, id_, {&x0_}); } double SurfaceXPlane::evaluate(Position r) const @@ -319,7 +241,7 @@ BoundingBox SurfaceXPlane::bounding_box(bool pos_side) const SurfaceYPlane::SurfaceYPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, y0_); + read_coeffs(surf_node, id_, {&y0_}); } double SurfaceYPlane::evaluate(Position r) const @@ -359,7 +281,7 @@ BoundingBox SurfaceYPlane::bounding_box(bool pos_side) const SurfaceZPlane::SurfaceZPlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, z0_); + read_coeffs(surf_node, id_, {&z0_}); } double SurfaceZPlane::evaluate(Position r) const @@ -399,7 +321,7 @@ BoundingBox SurfaceZPlane::bounding_box(bool pos_side) const SurfacePlane::SurfacePlane(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, A_, B_, C_, D_); + read_coeffs(surf_node, id_, {&A_, &B_, &C_, &D_}); } double SurfacePlane::evaluate(Position r) const @@ -518,7 +440,7 @@ Direction axis_aligned_cylinder_normal( SurfaceXCylinder::SurfaceXCylinder(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, y0_, z0_, radius_); + read_coeffs(surf_node, id_, {&y0_, &z0_, &radius_}); } double SurfaceXCylinder::evaluate(Position r) const @@ -561,7 +483,7 @@ BoundingBox SurfaceXCylinder::bounding_box(bool pos_side) const SurfaceYCylinder::SurfaceYCylinder(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, z0_, radius_); + read_coeffs(surf_node, id_, {&x0_, &z0_, &radius_}); } double SurfaceYCylinder::evaluate(Position r) const @@ -605,7 +527,7 @@ BoundingBox SurfaceYCylinder::bounding_box(bool pos_side) const SurfaceZCylinder::SurfaceZCylinder(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, radius_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &radius_}); } double SurfaceZCylinder::evaluate(Position r) const @@ -648,7 +570,7 @@ BoundingBox SurfaceZCylinder::bounding_box(bool pos_side) const SurfaceSphere::SurfaceSphere(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_}); } double SurfaceSphere::evaluate(Position r) const @@ -814,7 +736,7 @@ Direction axis_aligned_cone_normal( SurfaceXCone::SurfaceXCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); } double SurfaceXCone::evaluate(Position r) const @@ -846,7 +768,7 @@ void SurfaceXCone::to_hdf5_inner(hid_t group_id) const SurfaceYCone::SurfaceYCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); } double SurfaceYCone::evaluate(Position r) const @@ -878,7 +800,7 @@ void SurfaceYCone::to_hdf5_inner(hid_t group_id) const SurfaceZCone::SurfaceZCone(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, radius_sq_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &radius_sq_}); } double SurfaceZCone::evaluate(Position r) const @@ -910,7 +832,8 @@ void SurfaceZCone::to_hdf5_inner(hid_t group_id) const SurfaceQuadric::SurfaceQuadric(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, A_, B_, C_, D_, E_, F_, G_, H_, J_, K_); + read_coeffs( + surf_node, id_, {&A_, &B_, &C_, &D_, &E_, &F_, &G_, &H_, &J_, &K_}); } double SurfaceQuadric::evaluate(Position r) const @@ -1062,7 +985,7 @@ double torus_distance(double x1, double x2, double x3, double u1, double u2, SurfaceXTorus::SurfaceXTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, A_, B_, C_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); } void SurfaceXTorus::to_hdf5_inner(hid_t group_id) const @@ -1115,7 +1038,7 @@ Direction SurfaceXTorus::normal(Position r) const SurfaceYTorus::SurfaceYTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, A_, B_, C_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); } void SurfaceYTorus::to_hdf5_inner(hid_t group_id) const @@ -1168,7 +1091,7 @@ Direction SurfaceYTorus::normal(Position r) const SurfaceZTorus::SurfaceZTorus(pugi::xml_node surf_node) : CSGSurface(surf_node) { - read_coeffs(surf_node, id_, x0_, y0_, z0_, A_, B_, C_); + read_coeffs(surf_node, id_, {&x0_, &y0_, &z0_, &A_, &B_, &C_}); } void SurfaceZTorus::to_hdf5_inner(hid_t group_id) const From b489023340be41f3a18117ceeadb6bf278e685a3 Mon Sep 17 00:00:00 2001 From: Jonathan Shimwell Date: Sun, 25 Jun 2023 00:03:56 +0100 Subject: [PATCH 38/45] Option units for geometry plot (#2575) Co-authored-by: Paul Romano --- openmc/universe.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/openmc/universe.py b/openmc/universe.py index 6acecf8006a..447746e576a 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -303,7 +303,7 @@ def find(self, point): def plot(self, origin=None, width=None, pixels=40000, basis='xy', color_by='cell', colors=None, seed=None, - openmc_exec='openmc', axes=None, legend=False, + openmc_exec='openmc', axes=None, legend=False, axis_units='cm', legend_kwargs=_default_legend_kwargs, outline=False, **kwargs): """Display a slice plot of the universe. @@ -360,6 +360,10 @@ def plot(self, origin=None, width=None, pixels=40000, outline : bool Whether outlines between color boundaries should be drawn + .. versionadded:: 0.13.4 + axis_units : {'km', 'm', 'cm', 'mm'} + Units used on the plot axis + .. versionadded:: 0.13.4 **kwargs Keyword arguments passed to :func:`matplotlib.pyplot.imshow` @@ -377,13 +381,13 @@ def plot(self, origin=None, width=None, pixels=40000, # Determine extents of plot if basis == 'xy': x, y = 0, 1 - xlabel, ylabel = 'x [cm]', 'y [cm]' + xlabel, ylabel = f'x [{axis_units}]', f'y [{axis_units}]' elif basis == 'yz': x, y = 1, 2 - xlabel, ylabel = 'y [cm]', 'z [cm]' + xlabel, ylabel = f'y [{axis_units}]', f'z [{axis_units}]' elif basis == 'xz': x, y = 0, 2 - xlabel, ylabel = 'x [cm]', 'z [cm]' + xlabel, ylabel = f'x [{axis_units}]', f'z [{axis_units}]' bb = self.bounding_box # checks to see if bounding box contains -inf or inf values @@ -408,10 +412,12 @@ def plot(self, origin=None, width=None, pixels=40000, pixels_y = math.sqrt(pixels / aspect_ratio) pixels = (int(pixels / pixels_y), int(pixels_y)) - x_min = origin[x] - 0.5*width[0] - x_max = origin[x] + 0.5*width[0] - y_min = origin[y] - 0.5*width[1] - y_max = origin[y] + 0.5*width[1] + axis_scaling_factor = {'km': 0.00001, 'm': 0.01, 'cm': 1, 'mm': 10} + + x_min = (origin[x] - 0.5*width[0]) * axis_scaling_factor[axis_units] + x_max = (origin[x] + 0.5*width[0]) * axis_scaling_factor[axis_units] + y_min = (origin[y] - 0.5*width[1]) * axis_scaling_factor[axis_units] + y_max = (origin[y] + 0.5*width[1]) * axis_scaling_factor[axis_units] with TemporaryDirectory() as tmpdir: model = openmc.Model() From b5e54468a9de2b65d7856a8eaf98ccb6625dd63c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sun, 25 Jun 2023 00:27:54 -0500 Subject: [PATCH 39/45] Weight window update method fixes (#2578) --- src/weight_windows.cpp | 706 ++++++++++++++++++++--------------------- 1 file changed, 348 insertions(+), 358 deletions(-) diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index 104c3881540..dcdf13abe97 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -611,16 +611,16 @@ void WeightWindows::update_magic( // select all auto group_view = xt::view(new_bounds, e); - double group_max = *std::max_element(group_view.begin(), group_view.end()); - // normalize values in this energy group by the maximum value for this - // group - if (group_max > 0.0) - group_view /= group_max; - // divide by volume of mesh elements for (int i = 0; i < group_view.size(); i++) { group_view[i] /= mesh_vols[i]; } + + double group_max = *std::max_element(group_view.begin(), group_view.end()); + // normalize values in this energy group by the maximum value for this + // group + if (group_max > 0.0) + group_view /= 2.0 * group_max; } // make sure that values where the mean is zero are set s.t. the weight window @@ -659,7 +659,7 @@ void WeightWindows::check_tally_update_compatibility(const Tally* tally) if (allowed_filters.find(filter_pair.first) == allowed_filters.end()) { fatal_error(fmt::format("Invalid filter type '{}' found on tally " "used for weight window generation.", - model::tally_filters[filter_pair.second]->type_str())); + model::tally_filters[tally->filters(filter_pair.second)]->type_str())); } } @@ -695,431 +695,421 @@ void WeightWindows::check_tally_update_compatibility(const Tally* tally) } } - void WeightWindows::to_hdf5(hid_t group) const - { - hid_t ww_group = - create_group(group, fmt::format("weight_windows_{}", id())); - - write_dataset(ww_group, "mesh", this->mesh()->id()); - write_dataset( - ww_group, "particle_type", openmc::particle_type_to_str(particle_type_)); - write_dataset(ww_group, "energy_bounds", energy_bounds_); - write_dataset(ww_group, "lower_ww_bounds", lower_ww_); - write_dataset(ww_group, "upper_ww_bounds", upper_ww_); - write_dataset(ww_group, "survival_ratio", survival_ratio_); - write_dataset(ww_group, "max_lower_bound_ratio", max_lb_ratio_); - write_dataset(ww_group, "max_split", max_split_); - write_dataset(ww_group, "weight_cutoff", weight_cutoff_); - - close_group(ww_group); - } +void WeightWindows::to_hdf5(hid_t group) const +{ + hid_t ww_group = create_group(group, fmt::format("weight_windows_{}", id())); + + write_dataset(ww_group, "mesh", this->mesh()->id()); + write_dataset( + ww_group, "particle_type", openmc::particle_type_to_str(particle_type_)); + write_dataset(ww_group, "energy_bounds", energy_bounds_); + write_dataset(ww_group, "lower_ww_bounds", lower_ww_); + write_dataset(ww_group, "upper_ww_bounds", upper_ww_); + write_dataset(ww_group, "survival_ratio", survival_ratio_); + write_dataset(ww_group, "max_lower_bound_ratio", max_lb_ratio_); + write_dataset(ww_group, "max_split", max_split_); + write_dataset(ww_group, "weight_cutoff", weight_cutoff_); - WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) - { - // read information from the XML node - int32_t mesh_id = std::stoi(get_node_value(node, "mesh")); - int32_t mesh_idx = model::mesh_map[mesh_id]; - max_realizations_ = std::stoi(get_node_value(node, "max_realizations")); - - int active_batches = settings::n_batches - settings::n_inactive; - if (max_realizations_ > active_batches) { - auto msg = fmt::format( - "The maximum number of specified tally realizations ({}) is " - "greater than the number of active batches ({}).", + close_group(ww_group); +} + +WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) +{ + // read information from the XML node + int32_t mesh_id = std::stoi(get_node_value(node, "mesh")); + int32_t mesh_idx = model::mesh_map[mesh_id]; + max_realizations_ = std::stoi(get_node_value(node, "max_realizations")); + + int active_batches = settings::n_batches - settings::n_inactive; + if (max_realizations_ > active_batches) { + auto msg = + fmt::format("The maximum number of specified tally realizations ({}) is " + "greater than the number of active batches ({}).", max_realizations_, active_batches); - warning(msg); - } - auto tmp_str = get_node_value(node, "particle_type", true, true); - auto particle_type = str_to_particle_type(tmp_str); - - update_interval_ = std::stoi(get_node_value(node, "update_interval")); - on_the_fly_ = get_node_value_bool(node, "on_the_fly"); - - std::vector e_bounds; - if (check_for_node(node, "energy_bounds")) { - e_bounds = get_node_array(node, "energy_bounds"); - } else { - int p_type = static_cast(particle_type); - e_bounds.push_back(data::energy_min[p_type]); - e_bounds.push_back(data::energy_max[p_type]); - } + warning(msg); + } + auto tmp_str = get_node_value(node, "particle_type", true, true); + auto particle_type = str_to_particle_type(tmp_str); + + update_interval_ = std::stoi(get_node_value(node, "update_interval")); + on_the_fly_ = get_node_value_bool(node, "on_the_fly"); + + std::vector e_bounds; + if (check_for_node(node, "energy_bounds")) { + e_bounds = get_node_array(node, "energy_bounds"); + } else { + int p_type = static_cast(particle_type); + e_bounds.push_back(data::energy_min[p_type]); + e_bounds.push_back(data::energy_max[p_type]); + } - // create a tally based on the WWG information - Tally* ww_tally = Tally::create(); - tally_idx_ = model::tally_map[ww_tally->id()]; - ww_tally->set_scores({"flux"}); - - // see if there's already a mesh filter using this mesh - bool found_mesh_filter = false; - for (const auto& f : model::tally_filters) { - if (f->type() == FilterType::MESH) { - const auto* mesh_filter = dynamic_cast(f.get()); - if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated()) { - ww_tally->add_filter(f.get()); - found_mesh_filter = true; - break; - } + // create a tally based on the WWG information + Tally* ww_tally = Tally::create(); + tally_idx_ = model::tally_map[ww_tally->id()]; + ww_tally->set_scores({"flux"}); + + // see if there's already a mesh filter using this mesh + bool found_mesh_filter = false; + for (const auto& f : model::tally_filters) { + if (f->type() == FilterType::MESH) { + const auto* mesh_filter = dynamic_cast(f.get()); + if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated()) { + ww_tally->add_filter(f.get()); + found_mesh_filter = true; + break; } } + } - if (!found_mesh_filter) { - auto mesh_filter = Filter::create("mesh"); - openmc_mesh_filter_set_mesh( - mesh_filter->index(), model::mesh_map[mesh_id]); - ww_tally->add_filter(mesh_filter); - } + if (!found_mesh_filter) { + auto mesh_filter = Filter::create("mesh"); + openmc_mesh_filter_set_mesh(mesh_filter->index(), model::mesh_map[mesh_id]); + ww_tally->add_filter(mesh_filter); + } - if (e_bounds.size() > 0) { - auto energy_filter = Filter::create("energy"); - openmc_energy_filter_set_bins( - energy_filter->index(), e_bounds.size(), e_bounds.data()); - ww_tally->add_filter(energy_filter); - } + if (e_bounds.size() > 0) { + auto energy_filter = Filter::create("energy"); + openmc_energy_filter_set_bins( + energy_filter->index(), e_bounds.size(), e_bounds.data()); + ww_tally->add_filter(energy_filter); + } - // add a particle filter - auto particle_filter = Filter::create("particle"); - auto pf = dynamic_cast(particle_filter); - pf->set_particles({&particle_type, 1}); - ww_tally->add_filter(particle_filter); - - // set method and parameters for updates - method_ = get_node_value(node, "method"); - if (method_ == "magic") { - // parse non-default update parameters if specified - if (check_for_node(node, "update_parameters")) { - pugi::xml_node params_node = node.child("update_parameters"); - if (check_for_node(params_node, "value")) - tally_value_ = get_node_value(params_node, "value"); - if (check_for_node(params_node, "threshold")) - threshold_ = std::stod(get_node_value(params_node, "threshold")); - if (check_for_node(params_node, "ratio")) { - ratio_ = std::stod(get_node_value(params_node, "ratio")); - } + // add a particle filter + auto particle_filter = Filter::create("particle"); + auto pf = dynamic_cast(particle_filter); + pf->set_particles({&particle_type, 1}); + ww_tally->add_filter(particle_filter); + + // set method and parameters for updates + method_ = get_node_value(node, "method"); + if (method_ == "magic") { + // parse non-default update parameters if specified + if (check_for_node(node, "update_parameters")) { + pugi::xml_node params_node = node.child("update_parameters"); + if (check_for_node(params_node, "value")) + tally_value_ = get_node_value(params_node, "value"); + if (check_for_node(params_node, "threshold")) + threshold_ = std::stod(get_node_value(params_node, "threshold")); + if (check_for_node(params_node, "ratio")) { + ratio_ = std::stod(get_node_value(params_node, "ratio")); } - // check update parameter values - if (tally_value_ != "mean" && tally_value_ != "rel_err") { - fatal_error(fmt::format("Unsupported tally value '{}' specified for " - "weight window generation.", - tally_value_)); - } - if (threshold_ <= 0.0) - fatal_error( - fmt::format("Invalid relative error threshold '{}' (<= 0.0) " - "specified for weight window generation", - ratio_)); - if (ratio_ <= 1.0) - fatal_error(fmt::format("Invalid weight window ratio '{}' (<= 1.0) " - "specified for weight window generation")); - } else { - fatal_error(fmt::format( - "Unknown weight window update method '{}' specified", method_)); } - - // create a matching weight windows object - auto wws = WeightWindows::create(); - ww_idx_ = wws->index(); - if (e_bounds.size() > 0) - wws->set_energy_bounds(e_bounds); - wws->set_mesh(model::mesh_map[mesh_id]); - wws->set_particle_type(particle_type); - wws->set_defaults(); + // check update parameter values + if (tally_value_ != "mean" && tally_value_ != "rel_err") { + fatal_error(fmt::format("Unsupported tally value '{}' specified for " + "weight window generation.", + tally_value_)); + } + if (threshold_ <= 0.0) + fatal_error(fmt::format("Invalid relative error threshold '{}' (<= 0.0) " + "specified for weight window generation", + ratio_)); + if (ratio_ <= 1.0) + fatal_error(fmt::format("Invalid weight window ratio '{}' (<= 1.0) " + "specified for weight window generation")); + } else { + fatal_error(fmt::format( + "Unknown weight window update method '{}' specified", method_)); } - void WeightWindowsGenerator::update() const - { - const auto& wws = variance_reduction::weight_windows[ww_idx_]; - - Tally* tally = model::tallies[tally_idx_].get(); + // create a matching weight windows object + auto wws = WeightWindows::create(); + ww_idx_ = wws->index(); + if (e_bounds.size() > 0) + wws->set_energy_bounds(e_bounds); + wws->set_mesh(model::mesh_map[mesh_id]); + wws->set_particle_type(particle_type); + wws->set_defaults(); +} - // if we're beyond the number of max realizations or not at the corrrect - // update interval, skip the update - if (max_realizations_ < tally->n_realizations_ || - tally->n_realizations_ % update_interval_ != 0) - return; +void WeightWindowsGenerator::update() const +{ + const auto& wws = variance_reduction::weight_windows[ww_idx_]; - wws->update_magic(tally, tally_value_, threshold_, ratio_); + Tally* tally = model::tallies[tally_idx_].get(); - // if we're not doing on the fly generation, reset the tally results once - // we're done with the update - if (!on_the_fly_) - tally->reset(); + // if we're beyond the number of max realizations or not at the corrrect + // update interval, skip the update + if (max_realizations_ < tally->n_realizations_ || + tally->n_realizations_ % update_interval_ != 0) + return; - // TODO: deactivate or remove tally once weight window generation is - // complete - } + wws->update_magic(tally, tally_value_, threshold_, ratio_); - //============================================================================== - // C API - //============================================================================== + // if we're not doing on the fly generation, reset the tally results once + // we're done with the update + if (!on_the_fly_) + tally->reset(); - int verify_ww_index(int32_t index) - { - if (index < 0 || index >= variance_reduction::weight_windows.size()) { - set_errmsg( - fmt::format("Index '{}' for weight windows is invalid", index)); - return OPENMC_E_OUT_OF_BOUNDS; - } - return 0; - } + // TODO: deactivate or remove tally once weight window generation is + // complete +} - extern "C" int openmc_get_weight_windows_index(int32_t id, int32_t * idx) - { - auto it = variance_reduction::ww_map.find(id); - if (it == variance_reduction::ww_map.end()) { - set_errmsg(fmt::format("No weight windows exist with ID={}", id)); - return OPENMC_E_INVALID_ID; - } +//============================================================================== +// C API +//============================================================================== - *idx = it->second; - return 0; +int verify_ww_index(int32_t index) +{ + if (index < 0 || index >= variance_reduction::weight_windows.size()) { + set_errmsg(fmt::format("Index '{}' for weight windows is invalid", index)); + return OPENMC_E_OUT_OF_BOUNDS; } + return 0; +} - extern "C" int openmc_weight_windows_get_id(int32_t index, int32_t * id) - { - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows.at(index); - *id = wws->id(); - return 0; +extern "C" int openmc_get_weight_windows_index(int32_t id, int32_t* idx) +{ + auto it = variance_reduction::ww_map.find(id); + if (it == variance_reduction::ww_map.end()) { + set_errmsg(fmt::format("No weight windows exist with ID={}", id)); + return OPENMC_E_INVALID_ID; } - extern "C" int openmc_weight_windows_set_id(int32_t index, int32_t id) - { - if (int err = verify_ww_index(index)) - return err; - - const auto& wws = variance_reduction::weight_windows.at(index); - wws->set_id(id); - return 0; - } + *idx = it->second; + return 0; +} - extern "C" int openmc_weight_windows_update_magic(int32_t ww_idx, - int32_t tally_idx, const char* value, double threshold, double ratio) - { - if (int err = verify_ww_index(ww_idx)) - return err; +extern "C" int openmc_weight_windows_get_id(int32_t index, int32_t* id) +{ + if (int err = verify_ww_index(index)) + return err; - if (tally_idx < 0 || tally_idx >= model::tallies.size()) { - set_errmsg(fmt::format("Index '{}' for tally is invalid", tally_idx)); - return OPENMC_E_OUT_OF_BOUNDS; - } + const auto& wws = variance_reduction::weight_windows.at(index); + *id = wws->id(); + return 0; +} - // get the requested tally - const Tally* tally = model::tallies.at(tally_idx).get(); +extern "C" int openmc_weight_windows_set_id(int32_t index, int32_t id) +{ + if (int err = verify_ww_index(index)) + return err; - // get the WeightWindows object - const auto& wws = variance_reduction::weight_windows.at(ww_idx); + const auto& wws = variance_reduction::weight_windows.at(index); + wws->set_id(id); + return 0; +} - wws->update_magic(tally, value, threshold, ratio); +extern "C" int openmc_weight_windows_update_magic(int32_t ww_idx, + int32_t tally_idx, const char* value, double threshold, double ratio) +{ + if (int err = verify_ww_index(ww_idx)) + return err; - return 0; + if (tally_idx < 0 || tally_idx >= model::tallies.size()) { + set_errmsg(fmt::format("Index '{}' for tally is invalid", tally_idx)); + return OPENMC_E_OUT_OF_BOUNDS; } - extern "C" int openmc_weight_windows_set_mesh( - int32_t ww_idx, int32_t mesh_idx) - { - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows.at(ww_idx); - wws->set_mesh(mesh_idx); - return 0; - } + // get the requested tally + const Tally* tally = model::tallies.at(tally_idx).get(); - extern "C" int openmc_weight_windows_get_mesh( - int32_t ww_idx, int32_t * mesh_idx) - { - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows.at(ww_idx); - *mesh_idx = model::mesh_map.at(wws->mesh()->id()); - return 0; - } - - extern "C" int openmc_weight_windows_set_energy_bounds( - int32_t ww_idx, double* e_bounds, size_t e_bounds_size) - { - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows.at(ww_idx); - wws->set_energy_bounds({e_bounds, e_bounds_size}); - return 0; - } + // get the WeightWindows object + const auto& wws = variance_reduction::weight_windows.at(ww_idx); - extern "C" int openmc_weight_windows_get_energy_bounds( - int32_t ww_idx, const double** e_bounds, size_t* e_bounds_size) - { - if (int err = verify_ww_index(ww_idx)) - return err; - const auto& wws = variance_reduction::weight_windows[ww_idx].get(); - *e_bounds = wws->energy_bounds().data(); - *e_bounds_size = wws->energy_bounds().size(); - return 0; - } + wws->update_magic(tally, value, threshold, ratio); - extern "C" int openmc_weight_windows_set_particle(int32_t index, int particle) - { - if (int err = verify_ww_index(index)) - return err; + return 0; +} - const auto& wws = variance_reduction::weight_windows.at(index); - wws->set_particle_type(static_cast(particle)); - return 0; - } +extern "C" int openmc_weight_windows_set_mesh(int32_t ww_idx, int32_t mesh_idx) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + wws->set_mesh(mesh_idx); + return 0; +} - extern "C" int openmc_weight_windows_get_particle( - int32_t index, int* particle) - { - if (int err = verify_ww_index(index)) - return err; +extern "C" int openmc_weight_windows_get_mesh(int32_t ww_idx, int32_t* mesh_idx) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + *mesh_idx = model::mesh_map.at(wws->mesh()->id()); + return 0; +} - const auto& wws = variance_reduction::weight_windows.at(index); - *particle = static_cast(wws->particle_type()); - return 0; - } +extern "C" int openmc_weight_windows_set_energy_bounds( + int32_t ww_idx, double* e_bounds, size_t e_bounds_size) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows.at(ww_idx); + wws->set_energy_bounds({e_bounds, e_bounds_size}); + return 0; +} - extern "C" int openmc_weight_windows_get_bounds(int32_t index, - const double** lower_bounds, const double** upper_bounds, size_t* size) - { - if (int err = verify_ww_index(index)) - return err; +extern "C" int openmc_weight_windows_get_energy_bounds( + int32_t ww_idx, const double** e_bounds, size_t* e_bounds_size) +{ + if (int err = verify_ww_index(ww_idx)) + return err; + const auto& wws = variance_reduction::weight_windows[ww_idx].get(); + *e_bounds = wws->energy_bounds().data(); + *e_bounds_size = wws->energy_bounds().size(); + return 0; +} - const auto& wws = variance_reduction::weight_windows[index]; - *size = wws->lower_ww_bounds().size(); - *lower_bounds = wws->lower_ww_bounds().data(); - *upper_bounds = wws->upper_ww_bounds().data(); - return 0; - } +extern "C" int openmc_weight_windows_set_particle(int32_t index, int particle) +{ + if (int err = verify_ww_index(index)) + return err; - extern "C" int openmc_weight_windows_set_bounds(int32_t index, - const double* lower_bounds, const double* upper_bounds, size_t size) - { - if (int err = verify_ww_index(index)) - return err; + const auto& wws = variance_reduction::weight_windows.at(index); + wws->set_particle_type(static_cast(particle)); + return 0; +} - const auto& wws = variance_reduction::weight_windows[index]; - wws->set_bounds({lower_bounds, size}, {upper_bounds, size}); - return 0; - } +extern "C" int openmc_weight_windows_get_particle(int32_t index, int* particle) +{ + if (int err = verify_ww_index(index)) + return err; - extern "C" int openmc_extend_weight_windows( - int32_t n, int32_t * index_start, int32_t * index_end) - { - if (index_start) - *index_start = variance_reduction::weight_windows.size(); - if (index_end) - *index_end = variance_reduction::weight_windows.size() + n - 1; - for (int i = 0; i < n; ++i) - variance_reduction::weight_windows.push_back( - make_unique()); - return 0; - } + const auto& wws = variance_reduction::weight_windows.at(index); + *particle = static_cast(wws->particle_type()); + return 0; +} - extern "C" size_t openmc_weight_windows_size() - { - return variance_reduction::weight_windows.size(); - } +extern "C" int openmc_weight_windows_get_bounds(int32_t index, + const double** lower_bounds, const double** upper_bounds, size_t* size) +{ + if (int err = verify_ww_index(index)) + return err; + + const auto& wws = variance_reduction::weight_windows[index]; + *size = wws->lower_ww_bounds().size(); + *lower_bounds = wws->lower_ww_bounds().data(); + *upper_bounds = wws->upper_ww_bounds().data(); + return 0; +} - extern "C" int openmc_weight_windows_export(const char* filename) - { +extern "C" int openmc_weight_windows_set_bounds(int32_t index, + const double* lower_bounds, const double* upper_bounds, size_t size) +{ + if (int err = verify_ww_index(index)) + return err; - if (!mpi::master) - return 0; + const auto& wws = variance_reduction::weight_windows[index]; + wws->set_bounds({lower_bounds, size}, {upper_bounds, size}); + return 0; +} - std::string name = filename ? filename : "weight_windows.h5"; +extern "C" int openmc_extend_weight_windows( + int32_t n, int32_t* index_start, int32_t* index_end) +{ + if (index_start) + *index_start = variance_reduction::weight_windows.size(); + if (index_end) + *index_end = variance_reduction::weight_windows.size() + n - 1; + for (int i = 0; i < n; ++i) + variance_reduction::weight_windows.push_back(make_unique()); + return 0; +} - write_message(fmt::format("Exporting weight windows to {}...", name), 5); +extern "C" size_t openmc_weight_windows_size() +{ + return variance_reduction::weight_windows.size(); +} - hid_t ww_file = file_open(name, 'w'); +extern "C" int openmc_weight_windows_export(const char* filename) +{ - // Write file type - write_attribute(ww_file, "filetype", "weight_windows"); + if (!mpi::master) + return 0; - // Write revisiion number for state point file - write_attribute(ww_file, "version", VERSION_WEIGHT_WINDOWS); + std::string name = filename ? filename : "weight_windows.h5"; - hid_t weight_windows_group = create_group(ww_file, "weight_windows"); + write_message(fmt::format("Exporting weight windows to {}...", name), 5); - hid_t mesh_group = create_group(ww_file, "meshes"); + hid_t ww_file = file_open(name, 'w'); - std::vector mesh_ids; - std::vector ww_ids; - for (const auto& ww : variance_reduction::weight_windows) { + // Write file type + write_attribute(ww_file, "filetype", "weight_windows"); - ww->to_hdf5(weight_windows_group); - ww_ids.push_back(ww->id()); + // Write revisiion number for state point file + write_attribute(ww_file, "version", VERSION_WEIGHT_WINDOWS); - // if the mesh has already been written, move on - int32_t mesh_id = ww->mesh()->id(); - if (std::find(mesh_ids.begin(), mesh_ids.end(), mesh_id) != - mesh_ids.end()) - continue; + hid_t weight_windows_group = create_group(ww_file, "weight_windows"); - mesh_ids.push_back(mesh_id); - ww->mesh()->to_hdf5(mesh_group); - } + hid_t mesh_group = create_group(ww_file, "meshes"); - write_attribute(mesh_group, "n_meshes", mesh_ids.size()); - write_attribute(mesh_group, "ids", mesh_ids); - close_group(mesh_group); + std::vector mesh_ids; + std::vector ww_ids; + for (const auto& ww : variance_reduction::weight_windows) { - write_attribute(weight_windows_group, "n_weight_windows", ww_ids.size()); - write_attribute(weight_windows_group, "ids", ww_ids); - close_group(weight_windows_group); + ww->to_hdf5(weight_windows_group); + ww_ids.push_back(ww->id()); - file_close(ww_file); + // if the mesh has already been written, move on + int32_t mesh_id = ww->mesh()->id(); + if (std::find(mesh_ids.begin(), mesh_ids.end(), mesh_id) != mesh_ids.end()) + continue; - return 0; + mesh_ids.push_back(mesh_id); + ww->mesh()->to_hdf5(mesh_group); } - extern "C" int openmc_weight_windows_import(const char* filename) - { - std::string name = filename ? filename : "weight_windows.h5"; + write_attribute(mesh_group, "n_meshes", mesh_ids.size()); + write_attribute(mesh_group, "ids", mesh_ids); + close_group(mesh_group); - if (mpi::master) - write_message( - fmt::format("Importing weight windows from {}...", name), 5); + write_attribute(weight_windows_group, "n_weight_windows", ww_ids.size()); + write_attribute(weight_windows_group, "ids", ww_ids); + close_group(weight_windows_group); - if (!file_exists(name)) { - set_errmsg(fmt::format("File '{}' does not exist", name)); - } + file_close(ww_file); - hid_t ww_file = file_open(name, 'r'); + return 0; +} - // Check that filetype is correct - std::string filetype; - read_attribute(ww_file, "filetype", filetype); - if (filetype != "weight_windows") { - file_close(ww_file); - set_errmsg(fmt::format("File '{}' is not a weight windows file.", name)); - return OPENMC_E_INVALID_ARGUMENT; - } +extern "C" int openmc_weight_windows_import(const char* filename) +{ + std::string name = filename ? filename : "weight_windows.h5"; - // Check that the file version is compatible - std::array file_version; - read_attribute(ww_file, "version", file_version); - if (file_version[0] != VERSION_WEIGHT_WINDOWS[0]) { - std::string err_msg = - fmt::format("File '{}' has version {} which is incompatible with the " - "expected version ({}).", - name, file_version, VERSION_WEIGHT_WINDOWS); - set_errmsg(err_msg); - return OPENMC_E_INVALID_ARGUMENT; - } + if (mpi::master) + write_message(fmt::format("Importing weight windows from {}...", name), 5); - hid_t weight_windows_group = open_group(ww_file, "weight_windows"); + if (!file_exists(name)) { + set_errmsg(fmt::format("File '{}' does not exist", name)); + } - std::vector names = group_names(weight_windows_group); + hid_t ww_file = file_open(name, 'r'); - for (const auto& name : names) { - WeightWindows::from_hdf5(weight_windows_group, name); - } + // Check that filetype is correct + std::string filetype; + read_attribute(ww_file, "filetype", filetype); + if (filetype != "weight_windows") { + file_close(ww_file); + set_errmsg(fmt::format("File '{}' is not a weight windows file.", name)); + return OPENMC_E_INVALID_ARGUMENT; + } - close_group(weight_windows_group); + // Check that the file version is compatible + std::array file_version; + read_attribute(ww_file, "version", file_version); + if (file_version[0] != VERSION_WEIGHT_WINDOWS[0]) { + std::string err_msg = + fmt::format("File '{}' has version {} which is incompatible with the " + "expected version ({}).", + name, file_version, VERSION_WEIGHT_WINDOWS); + set_errmsg(err_msg); + return OPENMC_E_INVALID_ARGUMENT; + } - file_close(ww_file); + hid_t weight_windows_group = open_group(ww_file, "weight_windows"); - return 0; + std::vector names = group_names(weight_windows_group); + + for (const auto& name : names) { + WeightWindows::from_hdf5(weight_windows_group, name); } + close_group(weight_windows_group); + + file_close(ww_file); + + return 0; +} + } // namespace openmc From 19e4c370e53548c7929abcaa6616ab06bf244ebb Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sun, 25 Jun 2023 13:59:47 -0500 Subject: [PATCH 40/45] Remove use of mgxs module in MicroXS.from_model (#2572) Co-authored-by: Olek <45364492+yardasol@users.noreply.github.com> --- openmc/deplete/microxs.py | 65 ++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/openmc/deplete/microxs.py b/openmc/deplete/microxs.py index 67f6bf49d35..535f06a2c8d 100644 --- a/openmc/deplete/microxs.py +++ b/openmc/deplete/microxs.py @@ -7,13 +7,12 @@ import tempfile from copy import deepcopy -from pandas import DataFrame, read_csv +from pandas import DataFrame, read_csv, Series import numpy as np from openmc.checkvalue import check_type, check_value, check_iterable_type from openmc.exceptions import DataError -from openmc.mgxs import EnergyGroups, ArbitraryXS, FissionXS -from openmc import Tallies, StatePoint, Materials +from openmc import StatePoint, Materials import openmc from .chain import Chain, REACTIONS from .coupled_operator import _find_cross_sections, _get_nuclides_with_data @@ -67,26 +66,36 @@ def from_model(cls, Cross section data in [b] """ - groups = EnergyGroups(energy_bounds) - # Set up the reaction tallies original_tallies = model.tallies original_materials = deepcopy(model.materials) - tallies = Tallies() xs = {} - reactions, diluted_materials = cls._add_dilute_nuclides(chain_file, - model, - dilute_initial) + reactions, burnable_nucs, diluted_materials = cls._add_dilute_nuclides( + chain_file, model, dilute_initial) model.materials = diluted_materials - for rx in reactions: - if rx == 'fission': - xs[rx] = FissionXS(domain=reaction_domain, - energy_groups=groups, by_nuclide=True) - else: - xs[rx] = ArbitraryXS(rx, domain=reaction_domain, - energy_groups=groups, by_nuclide=True) - tallies += xs[rx].tallies.values() + energy_filter = openmc.EnergyFilter(energy_bounds) + if isinstance(reaction_domain, openmc.Material): + domain_filter = openmc.MaterialFilter([reaction_domain]) + elif isinstance(reaction_domain, openmc.Cell): + domain_filter = openmc.CellFilter([reaction_domain]) + elif isinstance(reaction_domain, openmc.Universe): + domain_filter = openmc.UniverseFilter([reaction_domain]) + else: + raise ValueError(f"Unsupported domain type: {type(reaction_domain)}") + + # TODO: Right now, we use all nuclides from the material but it probably + # should be based on the burnable nuclides + rr_tally = openmc.Tally(name='MicroXS RR') + rr_tally.filters = [domain_filter, energy_filter] + rr_tally.nuclides = reaction_domain.get_nuclides() + rr_tally.multiply_density = False + rr_tally.scores = reactions + + flux_tally = openmc.Tally(name='MicroXS flux') + flux_tally.filters = [domain_filter, energy_filter] + flux_tally.scores = ['flux'] + tallies = openmc.Tallies([rr_tally, flux_tally]) model.tallies = tallies @@ -98,14 +107,22 @@ def from_model(cls, statepoint_path = model.run(**run_kwargs) with StatePoint(statepoint_path) as sp: - for rx in xs: - xs[rx].load_from_statepoint(sp) + rr_tally = sp.tallies[rr_tally.id] + rr_tally._read_results() + flux_tally = sp.tallies[flux_tally.id] + flux_tally._read_results() + + # Get reaction rates and flux values + reaction_rates = rr_tally.mean.sum(axis=0) # (nuclides, reactions) + flux = flux_tally.mean[0, 0, 0] + + # Divide RR by flux to get microscopic cross sections + xs = reaction_rates / flux - # Build the DataFrame + # Build Series objects series = {} - for rx in xs: - df = xs[rx].get_pandas_dataframe(xs_type='micro') - series[rx] = df.set_index('nuclide')['mean'] + for i, rx in enumerate(reactions): + series[rx] = Series(xs[..., i], index=rr_tally.nuclides) # Revert to the original tallies and materials model.tallies = original_tallies @@ -170,7 +187,7 @@ def _add_dilute_nuclides(cls, chain_file, model, dilute_initial): dilute_density) diluted_materials.append(material) - return reactions, diluted_materials + return reactions, burnable_nucs, diluted_materials @classmethod def from_array(cls, nuclides, reactions, data): From f200e446aac1d720b2901bb8223f22151f77dd5a Mon Sep 17 00:00:00 2001 From: Olek <45364492+yardasol@users.noreply.github.com> Date: Mon, 26 Jun 2023 14:23:32 +0200 Subject: [PATCH 41/45] Allow transfer rates with nuclides. (#2564) Co-authored-by: Paul Romano Co-authored-by: Lorenzo Chierici --- openmc/deplete/abc.py | 10 +- openmc/deplete/chain.py | 7 +- openmc/deplete/transfer_rates.py | 100 ++++++++++++------ .../unit_tests/test_deplete_transfer_rates.py | 79 +++++++++++--- 4 files changed, 140 insertions(+), 56 deletions(-) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index e62cc2b5ecd..ae0d8602706 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -818,7 +818,7 @@ def integrate(self, final_step=True, output=True): self.operator.finalize() - def add_transfer_rate(self, material, elements, transfer_rate, + def add_transfer_rate(self, material, components, transfer_rate, transfer_rate_units='1/s', destination_material=None): """Add transfer rates to depletable material. @@ -826,8 +826,10 @@ def add_transfer_rate(self, material, elements, transfer_rate, ---------- material : openmc.Material or str or int Depletable material - elements : list of str - List of strings of elements that share transfer rate + components : list of str + List of strings of elements and/or nuclides that share transfer rate. + A transfer rate for a nuclide cannot be added to a material + alongside a transfer rate for its element and vice versa. transfer_rate : float Rate at which elements are transferred. A positive or negative values set removal of feed rates, respectively. @@ -841,7 +843,7 @@ def add_transfer_rate(self, material, elements, transfer_rate, if self.transfer_rates is None: self.transfer_rates = TransferRates(self.operator, self.operator.model) - self.transfer_rates.set_transfer_rate(material, elements, transfer_rate, + self.transfer_rates.set_transfer_rate(material, components, transfer_rate, transfer_rate_units, destination_material) @add_params diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index 63fde69834c..51fb0ad9cf1 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -724,8 +724,11 @@ def form_rr_term(self, transfer_rates, materials): # Build transfer terms matrices if isinstance(materials, str): material = materials - if element in transfer_rates.get_elements(material): + components = transfer_rates.get_components(material) + if element in components: matrix[i, i] = transfer_rates.get_transfer_rate(material, element) + elif nuclide.name in components: + matrix[i, i] = transfer_rates.get_transfer_rate(material, nuclide.name) else: matrix[i, i] = 0.0 #Build transfer terms matrices @@ -733,6 +736,8 @@ def form_rr_term(self, transfer_rates, materials): destination_material, material = materials if transfer_rates.get_destination_material(material, element) == destination_material: matrix[i, i] = transfer_rates.get_transfer_rate(material, element) + elif transfer_rates.get_destination_material(material, nuclide.name) == destination_material: + matrix[i, i] = transfer_rates.get_transfer_rate(material, nuclide.name) else: matrix[i, i] = 0.0 #Nothing else is allowed diff --git a/openmc/deplete/transfer_rates.py b/openmc/deplete/transfer_rates.py index fe21d7d6f41..ad75c6c20d0 100644 --- a/openmc/deplete/transfer_rates.py +++ b/openmc/deplete/transfer_rates.py @@ -1,4 +1,5 @@ from numbers import Real +import re from openmc.checkvalue import check_type, check_value from openmc import Material @@ -33,7 +34,8 @@ class TransferRates: local_mats : list of str All burnable material IDs being managed by a single process transfer_rates : dict of str to dict - Container of transfer rates, elements and destination material + Container of transfer rates, components (elements and/or nuclides) and + destination material index_transfer : Set of pair of str Pair of strings needed to build final matrix (destination_material, mat) """ @@ -77,15 +79,15 @@ def _get_material_id(self, val): return str(val) - def get_transfer_rate(self, material, element): + def get_transfer_rate(self, material, component): """Return transfer rate for given material and element. Parameters ---------- material : openmc.Material or str or int Depletable material - element : str - Element to get transfer rate value + component : str + Element or nuclide to get transfer rate value Returns ------- @@ -94,33 +96,34 @@ def get_transfer_rate(self, material, element): """ material_id = self._get_material_id(material) - check_value('element', element, ELEMENT_SYMBOL.values()) - return self.transfer_rates[material_id][element][0] + check_type('component', component, str) + return self.transfer_rates[material_id][component][0] - def get_destination_material(self, material, element): - """Return destination (or transfer) material for given material and - element, if defined. + def get_destination_material(self, material, component): + """Return destination material for given material and + component, if defined. Parameters ---------- material : openmc.Material or str or int Depletable material - element : str - Element that gets transferred to another material. + component : str + Element or nuclide that gets transferred to another material. Returns ------- destination_material_id : str - Depletable material ID to where the element gets transferred + Depletable material ID to where the element or nuclide gets + transferred """ material_id = self._get_material_id(material) - check_value('element', element, ELEMENT_SYMBOL.values()) - if element in self.transfer_rates[material_id]: - return self.transfer_rates[material_id][element][1] + check_type('component', component, str) + if component in self.transfer_rates[material_id]: + return self.transfer_rates[material_id][component][1] - def get_elements(self, material): - """Extract removing elements for a given material + def get_components(self, material): + """Extract removing elements and/or nuclides for a given material Parameters ---------- @@ -130,35 +133,38 @@ def get_elements(self, material): Returns ------- elements : list - List of elements where transfer rates exist + List of elements and nuclides where transfer rates exist """ material_id = self._get_material_id(material) if material_id in self.transfer_rates: return self.transfer_rates[material_id].keys() - def set_transfer_rate(self, material, elements, transfer_rate, transfer_rate_units='1/s', - destination_material=None): - """Set element transfer rates in a depletable material. + def set_transfer_rate(self, material, components, transfer_rate, + transfer_rate_units='1/s', destination_material=None): + """Set element and/or nuclide transfer rates in a depletable material. Parameters ---------- material : openmc.Material or str or int Depletable material - elements : list of str - List of strings of elements that share transfer rate + components : list of str + List of strings of elements and/or nuclides that share transfer rate. + Cannot add transfer rates for nuclides to a material where a + transfer rate for its element is specified and vice versa. transfer_rate : float - Rate at which elements are transferred. A positive or negative values - set removal of feed rates, respectively. + Rate at which elements and/or nuclides are transferred. A positive or + negative value corresponds to a removal or feed rate, respectively. destination_material : openmc.Material or str or int, Optional Destination material to where nuclides get fed. transfer_rate_units : {'1/s', '1/min', '1/h', '1/d', '1/a'} - Units for values specified in the transfer_rate argument. 's' means - seconds, 'min' means minutes, 'h' means hours, 'a' means Julian years. + Units for values specified in the transfer_rate argument. 's' for + seconds, 'min' for minutes, 'h' for hours, 'a' for Julian years. """ material_id = self._get_material_id(material) check_type('transfer_rate', transfer_rate, Real) + check_type('components', components, list, expected_iter_type=str) if destination_material is not None: destination_material_id = self._get_material_id(destination_material) @@ -166,8 +172,9 @@ def set_transfer_rate(self, material, elements, transfer_rate, transfer_rate_uni check_value('destination_material', str(destination_material_id), self.burnable_mats) else: - raise ValueError(f'Transfer to material {destination_material_id} '\ - 'is set, but there is only one depletable material') + raise ValueError('Transfer to material ' + f'{destination_material_id} is set, but there ' + 'is only one depletable material') else: destination_material_id = None @@ -182,10 +189,35 @@ def set_transfer_rate(self, material, elements, transfer_rate, transfer_rate_uni elif transfer_rate_units in ('1/a', '1/year'): unit_conv = 365.25*24*60*60 else: - raise ValueError("Invalid transfer rate unit '{}'".format(transfer_rate_units)) - - for element in elements: - check_value('element', element, ELEMENT_SYMBOL.values()) - self.transfer_rates[material_id][element] = transfer_rate / unit_conv, destination_material_id + raise ValueError('Invalid transfer rate unit ' + f'"{transfer_rate_units}"') + + for component in components: + current_components = self.transfer_rates[material_id].keys() + split_component = re.split(r'\d+', component) + element = split_component[0] + if element not in ELEMENT_SYMBOL.values(): + raise ValueError(f'{component} is not a valid nuclide or ' + 'element.') + else: + if len(split_component) == 1: + element_nucs = [c for c in current_components + if re.match(component + r'\d', c)] + if len(element_nucs) > 0: + nuc_str = ", ".join(element_nucs) + raise ValueError('Cannot add transfer rate for element ' + f'{component} to material {material_id} ' + f'with transfer rate(s) for nuclide(s) ' + f'{nuc_str}.') + + else: + if element in current_components: + raise ValueError('Cannot add transfer rate for nuclide ' + f'{component} to material {material_id} ' + f'where element {element} already has ' + 'a transfer rate.') + + self.transfer_rates[material_id][component] = \ + transfer_rate / unit_conv, destination_material_id if destination_material_id is not None: self.index_transfer.add((destination_material_id, material_id)) diff --git a/tests/unit_tests/test_deplete_transfer_rates.py b/tests/unit_tests/test_deplete_transfer_rates.py index 1572755c2db..35f2502df9f 100644 --- a/tests/unit_tests/test_deplete_transfer_rates.py +++ b/tests/unit_tests/test_deplete_transfer_rates.py @@ -45,29 +45,73 @@ def model(): return openmc.Model(geometry, materials, settings) - -def test_get_set(model): +@pytest.mark.parametrize("case_name, transfer_rates", [ + ('elements', {'U': 0.01, 'Xe': 0.1}), + ('nuclides', {'I135': 0.01, 'Gd156': 0.1, 'Gd157': 0.01}), + ('nuclides_elements', {'I135': 0.01, 'Gd156': 0.1, 'Gd157': 0.01, 'U': 0.01, + 'Xe': 0.1}), + ('elements_nuclides', {'U': 0.01, 'Xe': 0.1, 'I135': 0.01, 'Gd156': 0.1, + 'Gd157': 0.01}), + ('rates_invalid_1', {'Gd': 0.01, 'Gd157': 0.01, 'Gd156': 0.01}), + ('rates_invalid_2', {'Gd156': 0.01, 'Gd157': 0.01, 'Gd': 0.01}), + ('rates_invalid_3', {'Gb156': 0.01}), + ('rates_invalid_4', {'Gb': 0.01}) + ]) +def test_get_set(model, case_name, transfer_rates): """Tests the get/set methods""" - # create transfer rates for U and Xe - transfer_rates = {'U': 0.01, 'Xe': 0.1} op = CoupledOperator(model, CHAIN_PATH) transfer = TransferRates(op, model) # Test by Openmc material, material name and material id material, dest_material = [m for m in model.materials if m.depletable] - for material_input in [material, material.name, material.id]: for dest_material_input in [dest_material, dest_material.name, dest_material.id]: - for element, transfer_rate in transfer_rates.items(): - transfer.set_transfer_rate(material_input, [element], transfer_rate, - destination_material=dest_material_input) - assert transfer.get_transfer_rate(material_input, - element) == transfer_rate - assert transfer.get_destination_material(material_input, - element) == str(dest_material.id) - assert transfer.get_elements(material_input) == transfer_rates.keys() + if case_name == 'rates_invalid_1': + with pytest.raises(ValueError, match='Cannot add transfer ' + 'rate for nuclide Gd157 to material 1 ' + 'where element Gd already has a ' + 'transfer rate.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + elif case_name == 'rates_invalid_2': + with pytest.raises(ValueError, match='Cannot add transfer ' + f'rate for element Gd to material 1 with ' + 'transfer rate\(s\) for nuclide\(s\) ' + 'Gd156, Gd157.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + elif case_name == 'rates_invalid_3': + with pytest.raises(ValueError, match='Gb156 is not a valid ' + 'nuclide or element.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + elif case_name == 'rates_invalid_4': + with pytest.raises(ValueError, match='Gb is not a valid ' + 'nuclide or element.'): + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, + [component], + transfer_rate) + else: + for component, transfer_rate in transfer_rates.items(): + transfer.set_transfer_rate(material_input, [component], + transfer_rate, + destination_material=\ + dest_material_input) + assert transfer.get_transfer_rate( + material_input, component) == transfer_rate + assert transfer.get_destination_material( + material_input, component) == str(dest_material.id) + assert transfer.get_components(material_input) == \ + transfer_rates.keys() @pytest.mark.parametrize("transfer_rate_units, unit_conv", [ @@ -86,14 +130,15 @@ def test_get_set(model): def test_units(transfer_rate_units, unit_conv, model): """ Units testing""" # create transfer rate Xe - element = 'Xe' + components = ['Xe', 'U235'] transfer_rate = 1e-5 op = CoupledOperator(model, CHAIN_PATH) transfer = TransferRates(op, model) - transfer.set_transfer_rate('f', [element], transfer_rate * unit_conv, - transfer_rate_units=transfer_rate_units) - assert transfer.get_transfer_rate('f', element) == transfer_rate + for component in components: + transfer.set_transfer_rate('f', [component], transfer_rate * unit_conv, + transfer_rate_units=transfer_rate_units) + assert transfer.get_transfer_rate('f', component) == transfer_rate def test_transfer(run_in_tmpdir, model): From 51cf475723339f619bd119c6da635385ef2d26ae Mon Sep 17 00:00:00 2001 From: Olek <45364492+yardasol@users.noreply.github.com> Date: Mon, 26 Jun 2023 15:11:41 +0200 Subject: [PATCH 42/45] Add `get_mass()` function to `openmc.deplete.Results` (#2565) Co-authored-by: Paul Romano --- openmc/deplete/results.py | 54 ++++++++++++++++++++ tests/unit_tests/test_deplete_resultslist.py | 29 +++++++++++ 2 files changed, 83 insertions(+) diff --git a/openmc/deplete/results.py b/openmc/deplete/results.py index 9cc3b439a60..f250ab36397 100644 --- a/openmc/deplete/results.py +++ b/openmc/deplete/results.py @@ -10,6 +10,7 @@ from .stepresult import StepResult, VERSION_RESULTS import openmc.checkvalue as cv +from openmc.data import atomic_mass, AVOGADRO from openmc.data.library import DataLibrary from openmc.material import Material, Materials from openmc.exceptions import DataError @@ -157,6 +158,59 @@ def get_atoms( return times, concentrations + def get_mass(self, + mat: typing.Union[Material, str], + nuc: str, + mass_units: str = "g", + time_units: str = "s" + ) -> Tuple[np.ndarray, np.ndarray]: + """Get mass of nuclides over time from a single material + + .. versionadded:: 0.13.4 + + Parameters + ---------- + mat : openmc.Material, str + Material object or material id to evaluate + nuc : str + Nuclide name to evaluate + mass_units : {"g", "g/cm3", "kg"}, optional + Units for the returned mass. + time_units : {"s", "min", "h", "d", "a"}, optional + Units for the returned time array. Default is ``"s"`` to + return the value in seconds. Other options are minutes ``"min"``, + hours ``"h"``, days ``"d"``, and Julian years ``"a"``. + + Returns + ------- + times : numpy.ndarray + Array of times in units of ``time_units`` + mass : numpy.ndarray + Mass of specified nuclide in units of ``mass_units`` + + """ + cv.check_value("mass_units", mass_units, {"g", "g/cm3", "kg"}) + + if isinstance(mat, Material): + mat_id = str(mat.id) + elif isinstance(mat, str): + mat_id = mat + else: + raise TypeError('mat should be of type openmc.Material or str') + + times, atoms = self.get_atoms(mat, nuc, time_units=time_units) + + mass = atoms * atomic_mass(nuc) / AVOGADRO + + # Unit conversions + if mass_units == "g/cm3": + # Divide by volume to get density + mass /= self[0].volume[mat_id] + elif mass_units == "kg": + mass *= 1e3 + + return times, mass + def get_reaction_rate( self, mat: typing.Union[Material, str], diff --git a/tests/unit_tests/test_deplete_resultslist.py b/tests/unit_tests/test_deplete_resultslist.py index 6e4a4210bdd..457a6fea294 100644 --- a/tests/unit_tests/test_deplete_resultslist.py +++ b/tests/unit_tests/test_deplete_resultslist.py @@ -43,6 +43,35 @@ def test_get_atoms(res): assert t_hour == pytest.approx(t_ref / (60 * 60)) +def test_get_mass(res): + """Tests evaluating single nuclide concentration.""" + t, n = res.get_mass("1", "Xe135") + + t_ref = np.array([0.0, 1296000.0, 2592000.0, 3888000.0]) + n_ref = np.array( + [6.67473282e+08, 3.88942731e+14, 3.73091215e+14, 3.26987387e+14]) + + # Get g + n_ref *= openmc.data.atomic_mass('Xe135') / openmc.data.AVOGADRO + + np.testing.assert_allclose(t, t_ref) + np.testing.assert_allclose(n, n_ref) + + # Check alternate units + volume = res[0].volume["1"] + t_days, n_cm3 = res.get_mass("1", "Xe135", mass_units="g/cm3", time_units="d") + + assert t_days == pytest.approx(t_ref / (60 * 60 * 24)) + assert n_cm3 == pytest.approx(n_ref / volume) + + t_min, n_bcm = res.get_mass("1", "Xe135", mass_units="kg", time_units="min") + assert n_bcm == pytest.approx(n_ref * 1e3) + assert t_min == pytest.approx(t_ref / 60) + + t_hour, _n = res.get_mass("1", "Xe135", time_units="h") + assert t_hour == pytest.approx(t_ref / (60 * 60)) + + def test_get_reaction_rate(res): """Tests evaluating reaction rate.""" t, r = res.get_reaction_rate("1", "Xe135", "(n,gamma)") From b6c621f9b4bac7badbcffb71fe2b8e45d8e7c798 Mon Sep 17 00:00:00 2001 From: Jack Fletcher <115663563+j-fletcher@users.noreply.github.com> Date: Wed, 28 Jun 2023 18:57:44 -0400 Subject: [PATCH 43/45] Change "update_params" to "update_parameters" in test suite: test_ww_gen.py (#2577) --- tests/unit_tests/weightwindows/test_ww_gen.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit_tests/weightwindows/test_ww_gen.py b/tests/unit_tests/weightwindows/test_ww_gen.py index a5f65ff617b..a1aaca5b0eb 100644 --- a/tests/unit_tests/weightwindows/test_ww_gen.py +++ b/tests/unit_tests/weightwindows/test_ww_gen.py @@ -229,9 +229,9 @@ def test_ww_gen_roundtrip(run_in_tmpdir, model): particle_type = 'neutron' wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle_type) - wwg.update_params = {'ratio' : 5.0, - 'threshold': 0.8, - 'value' : 'mean'} + wwg.update_parameters = {'ratio' : 5.0, + 'threshold': 0.8, + 'value' : 'mean'} model.settings.weight_window_generators = wwg model.export_to_xml() From 36f229eb01de0a8cb7d482d9a9b7a2f2c615f3f5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 29 Jun 2023 04:06:35 -0500 Subject: [PATCH 44/45] Remove initial dilute nuclides in MicroXS (#2579) --- openmc/deplete/microxs.py | 125 ++++++------------ tests/regression_tests/microxs/test.py | 9 +- .../microxs/test_reference.csv | 24 ++-- 3 files changed, 57 insertions(+), 101 deletions(-) diff --git a/openmc/deplete/microxs.py b/openmc/deplete/microxs.py index 535f06a2c8d..050389cc26d 100644 --- a/openmc/deplete/microxs.py +++ b/openmc/deplete/microxs.py @@ -5,14 +5,13 @@ """ import tempfile -from copy import deepcopy from pandas import DataFrame, read_csv, Series import numpy as np from openmc.checkvalue import check_type, check_value, check_iterable_type from openmc.exceptions import DataError -from openmc import StatePoint, Materials +from openmc import StatePoint import openmc from .chain import Chain, REACTIONS from .coupled_operator import _find_cross_sections, _get_nuclides_with_data @@ -31,9 +30,10 @@ class MicroXS(DataFrame): @classmethod def from_model(cls, model, - reaction_domain, + domain, + nuclides=None, + reactions=None, chain_file=None, - dilute_initial=1.0e3, energy_bounds=(0, 20e6), run_kwargs=None): """Generate a one-group cross-section dataframe using OpenMC. @@ -44,17 +44,19 @@ def from_model(cls, ---------- model : openmc.Model OpenMC model object. Must contain geometry, materials, and settings. - reaction_domain : openmc.Material or openmc.Cell or openmc.Universe or openmc.RegularMesh + domain : openmc.Material or openmc.Cell or openmc.Universe Domain in which to tally reaction rates. + nuclides : list of str + Nuclides to get cross sections for. If not specified, all burnable + nuclides from the depletion chain file are used. + reactions : list of str + Reactions to get cross sections for. If not specified, all neutron + reactions listed in the depletion chain file are used. chain_file : str, optional Path to the depletion chain XML file that will be used in depletion simulation. Used to determine cross sections for materials not present in the inital composition. Defaults to ``openmc.config['chain_file']``. - dilute_initial : float, optional - Initial atom density [atoms/cm^3] to add for nuclides that - are zero in initial condition to ensure they exist in the cross - section data. Only done for nuclides with reaction rates. energy_bound : 2-tuple of float, optional Bounds for the energy group. run_kwargs : dict, optional @@ -66,29 +68,40 @@ def from_model(cls, Cross section data in [b] """ - # Set up the reaction tallies + # Save any original tallies on the model original_tallies = model.tallies - original_materials = deepcopy(model.materials) - xs = {} - reactions, burnable_nucs, diluted_materials = cls._add_dilute_nuclides( - chain_file, model, dilute_initial) - model.materials = diluted_materials + # Determine what reactions and nuclides are available in chain + if chain_file is None: + chain_file = openmc.config.get('chain_file') + if chain_file is None: + raise DataError( + "No depletion chain specified and could not find depletion " + "chain in openmc.config['chain_file']" + ) + chain = Chain.from_xml(chain_file) + if reactions is None: + reactions = chain.reactions + if not nuclides: + cross_sections = _find_cross_sections(model) + nuclides_with_data = _get_nuclides_with_data(cross_sections) + nuclides = [nuc.name for nuc in chain.nuclides + if nuc.name in nuclides_with_data] + + # Set up the reaction rate and flux tallies energy_filter = openmc.EnergyFilter(energy_bounds) - if isinstance(reaction_domain, openmc.Material): - domain_filter = openmc.MaterialFilter([reaction_domain]) - elif isinstance(reaction_domain, openmc.Cell): - domain_filter = openmc.CellFilter([reaction_domain]) - elif isinstance(reaction_domain, openmc.Universe): - domain_filter = openmc.UniverseFilter([reaction_domain]) + if isinstance(domain, openmc.Material): + domain_filter = openmc.MaterialFilter([domain]) + elif isinstance(domain, openmc.Cell): + domain_filter = openmc.CellFilter([domain]) + elif isinstance(domain, openmc.Universe): + domain_filter = openmc.UniverseFilter([domain]) else: - raise ValueError(f"Unsupported domain type: {type(reaction_domain)}") + raise ValueError(f"Unsupported domain type: {type(domain)}") - # TODO: Right now, we use all nuclides from the material but it probably - # should be based on the burnable nuclides rr_tally = openmc.Tally(name='MicroXS RR') rr_tally.filters = [domain_filter, energy_filter] - rr_tally.nuclides = reaction_domain.get_nuclides() + rr_tally.nuclides = nuclides rr_tally.multiply_density = False rr_tally.scores = reactions @@ -126,68 +139,8 @@ def from_model(cls, # Revert to the original tallies and materials model.tallies = original_tallies - model.materials = original_materials - - return cls(series) - - @classmethod - def _add_dilute_nuclides(cls, chain_file, model, dilute_initial): - """ - Add nuclides not present in burnable materials that have neutron data - and are present in the depletion chain to those materials. This allows - us to tally those specific nuclides for reactions to create one-group - cross sections. - - Parameters - ---------- - chain_file : str - Path to the depletion chain XML file that will be used in depletion - simulation. Used to determine cross sections for materials not - present in the inital composition. - model : openmc.Model - Model object - dilute_initial : float - Initial atom density [atoms/cm^3] to add for nuclides that - are zero in initial condition to ensure they exist in the cross - section data. Only done for nuclides with reaction rates. - Returns - ------- - reactions : list of str - List of reaction names - diluted_materials : openmc.Materials - :class:`openmc.Materials` object with nuclides added to burnable - materials. - """ - if chain_file is None: - chain_file = openmc.config.get('chain_file') - if chain_file is None: - raise DataError( - "No depletion chain specified and could not find depletion " - "chain in openmc.config['chain_file']" - ) - chain = Chain.from_xml(chain_file) - reactions = chain.reactions - cross_sections = _find_cross_sections(model) - nuclides_with_data = _get_nuclides_with_data(cross_sections) - burnable_nucs = [nuc.name for nuc in chain.nuclides - if nuc.name in nuclides_with_data] - diluted_materials = Materials() - for material in model.materials: - if material.depletable: - nuc_densities = material.get_nuclide_atom_densities() - dilute_density = 1.0e-24 * dilute_initial - material.set_density('sum') - for nuc, density in nuc_densities.items(): - material.remove_nuclide(nuc) - material.add_nuclide(nuc, density) - for burn_nuc in burnable_nucs: - if burn_nuc not in nuc_densities: - material.add_nuclide(burn_nuc, - dilute_density) - diluted_materials.append(material) - - return reactions, burnable_nucs, diluted_materials + return cls(series).rename_axis('nuclide') @classmethod def from_array(cls, nuclides, reactions, data): diff --git a/tests/regression_tests/microxs/test.py b/tests/regression_tests/microxs/test.py index f92f61479b9..3d67ee8a38d 100644 --- a/tests/regression_tests/microxs/test.py +++ b/tests/regression_tests/microxs/test.py @@ -40,14 +40,17 @@ def model(): settings = openmc.Settings() settings.particles = 1000 - settings.inactive = 10 - settings.batches = 50 + settings.inactive = 5 + settings.batches = 10 return openmc.Model(geometry, materials, settings) def test_from_model(model): - test_xs = MicroXS.from_model(model, model.materials[0], CHAIN_FILE) + fuel = model.materials[0] + nuclides = ['U234', 'U235', 'U238', 'U236', 'O16', 'O17', 'I135', 'Xe135', + 'Xe136', 'Cs135', 'Gd157', 'Gd156'] + test_xs = MicroXS.from_model(model, fuel, nuclides, chain_file=CHAIN_FILE) if config['update']: test_xs.to_csv('test_reference.csv') diff --git a/tests/regression_tests/microxs/test_reference.csv b/tests/regression_tests/microxs/test_reference.csv index 1804551eb5f..0fc41862d66 100644 --- a/tests/regression_tests/microxs/test_reference.csv +++ b/tests/regression_tests/microxs/test_reference.csv @@ -1,13 +1,13 @@ nuclide,"(n,gamma)",fission -U234,20.548033586079335,0.4951725071956495 -U235,10.593745111766133,48.86980740247932 -U238,0.8607296097035912,0.10623994948321437 -U236,8.697176401063281,0.32148140073986475 -O16,7.503456435273737e-05,0.0 -O17,0.0004107265933745623,0.0 -I135,6.896228129273278,0.0 -Xe135,229100.9245987756,0.0 -Xe136,0.02336047367105298,0.0 -Cs135,2.055822714073886,0.0 -Gd157,12927.465334134899,0.0 -Gd156,3.500756543915523,0.0 +U234,21.418670317831197,0.5014588470882195 +U235,10.343944102483244,47.46718472611891 +U238,0.8741166723597251,0.10829568455139126 +U236,9.083486784689326,0.3325287927011428 +O16,7.548646353912453e-05,0.0 +O17,0.0004018486221310307,0.0 +I135,6.6912565089429235,0.0 +Xe135,223998.64185667288,0.0 +Xe136,0.022934362666193576,0.0 +Cs135,2.28453952223533,0.0 +Gd157,12582.079620036275,0.0 +Gd156,2.9421127515332417,0.0 From 382bcb2e8ea63b5ffd9ead818c651e5aa9d4c7ce Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 30 Jun 2023 22:29:47 -0500 Subject: [PATCH 45/45] Updates to object lifecycle for WeightWindows and WeightWindowGenerators (#2582) --- include/openmc/weight_windows.h | 376 +++++++++--------- openmc/weight_windows.py | 13 +- src/initialize.cpp | 5 + src/weight_windows.cpp | 121 +++--- .../weightwindows/generators/test.py | 13 +- tests/unit_tests/weightwindows/test.py | 16 +- 6 files changed, 304 insertions(+), 240 deletions(-) diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index 75073e917cb..992c8fdc155 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -15,211 +15,215 @@ #include "openmc/tallies/tally.h" #include "openmc/vector.h" - namespace openmc -{ +namespace openmc { - enum class WeightWindowUpdateMethod { - MAGIC, - }; +enum class WeightWindowUpdateMethod { + MAGIC, +}; - //============================================================================== - // Constants - //============================================================================== +//============================================================================== +// Constants +//============================================================================== - constexpr double DEFAULT_WEIGHT_CUTOFF {1.0e-38}; // default low weight cutoff +constexpr double DEFAULT_WEIGHT_CUTOFF {1.0e-38}; // default low weight cutoff - //============================================================================== - // Non-member functions - //============================================================================== - - //! Apply weight windows to a particle - //! \param[in] p Particle to apply weight windows to - void apply_weight_windows(Particle & p); - - //! Free memory associated with weight windows - void free_memory_weight_windows(); +//============================================================================== +// Non-member functions +//============================================================================== - //============================================================================== - // Global variables - //============================================================================== +//! Apply weight windows to a particle +//! \param[in] p Particle to apply weight windows to +void apply_weight_windows(Particle& p); - class WeightWindows; - class WeightWindowsGenerator; +//! Free memory associated with weight windows +void free_memory_weight_windows(); - namespace variance_reduction { +//============================================================================== +// Global variables +//============================================================================== - extern std::unordered_map ww_map; - extern vector> weight_windows; - extern vector> weight_windows_generators; +class WeightWindows; +class WeightWindowsGenerator; - } // namespace variance_reduction +namespace variance_reduction { - //============================================================================== - //! Individual weight window information - //============================================================================== +extern std::unordered_map ww_map; +extern vector> weight_windows; +extern vector> weight_windows_generators; - struct WeightWindow { - double lower_weight {-1}; // -1 indicates invalid state - double upper_weight {1}; - double max_lb_ratio {1}; - double survival_weight {0.5}; - double weight_cutoff {DEFAULT_WEIGHT_CUTOFF}; - int max_split {1}; +} // namespace variance_reduction - //! Whether the weight window is in a valid state - bool is_valid() const { return lower_weight >= 0.0; } +//============================================================================== +//! Individual weight window information +//============================================================================== - //! Adjust the weight window by a constant factor - void scale(double factor) - { - lower_weight *= factor; - upper_weight *= factor; - } - }; +struct WeightWindow { + double lower_weight {-1}; // -1 indicates invalid state + double upper_weight {1}; + double max_lb_ratio {1}; + double survival_weight {0.5}; + double weight_cutoff {DEFAULT_WEIGHT_CUTOFF}; + int max_split {10}; - //============================================================================== - //! Weight window settings - //============================================================================== + //! Whether the weight window is in a valid state + bool is_valid() const { return lower_weight >= 0.0; } - class WeightWindows { - public: - //---------------------------------------------------------------------------- - // Constructors - WeightWindows(int32_t id = -1); - WeightWindows(pugi::xml_node node); - ~WeightWindows(); - static WeightWindows* create(int32_t id = -1); - static WeightWindows* from_hdf5( - hid_t wws_group, const std::string& group_name); + //! Adjust the weight window by a constant factor + void scale(double factor) + { + lower_weight *= factor; + upper_weight *= factor; + } +}; - //---------------------------------------------------------------------------- - // Methods - private: - template - void check_bounds(const T& lower, const T& upper) const; +//============================================================================== +//! Weight window settings +//============================================================================== - template - void check_bounds(const T& lower) const; +class WeightWindows { +public: + //---------------------------------------------------------------------------- + // Constructors + WeightWindows(int32_t id = -1); + WeightWindows(pugi::xml_node node); + ~WeightWindows(); + static WeightWindows* create(int32_t id = -1); + static WeightWindows* from_hdf5( + hid_t wws_group, const std::string& group_name); - void check_tally_update_compatibility(const Tally* tally); + //---------------------------------------------------------------------------- + // Methods +private: + template + void check_bounds(const T& lower, const T& upper) const; - public: - //! Set the weight window ID - void set_id(int32_t id = -1); - - void set_energy_bounds(gsl::span bounds); - - void set_mesh(const std::unique_ptr& mesh); - - void set_mesh(const Mesh* mesh); - - void set_mesh(int32_t mesh_idx); - - //! Ready the weight window class for use - void set_defaults(); - - //! Update weight window boundaries using tally results - //! \param[in] tally Pointer to the tally whose results will be used to - //! update weight windows \param[in] value String representing the type of - //! value to use for weight window generation (one of "mean" or "rel_err") - //! \param[in] threshold Relative error threshold. Results over this - //! threshold will be ignored \param[in] ratio Ratio of upper to lower - //! weight window bounds - void update_magic(const Tally* tally, const std::string& value = "mean", - double threshold = 1.0, double ratio = 5.0); - - // NOTE: This is unused for now but may be used in the future - //! Write weight window settings to an HDF5 file - //! \param[in] group HDF5 group to write to - void to_hdf5(hid_t group) const; - - //! Retrieve the weight window for a particle - //! \param[in] p Particle to get weight window for - WeightWindow get_weight_window(const Particle& p) const; - - std::array bounds_size() const; - - const vector& energy_bounds() const { return energy_bounds_; } - - void set_bounds(const xt::xtensor& lower_ww_bounds, - const xt::xtensor& upper_bounds); - - void set_bounds(const xt::xtensor& lower_bounds, double ratio); - - void set_bounds(gsl::span lower_bounds, - gsl::span upper_bounds); - - void set_bounds(gsl::span lower_bounds, double ratio); - - void set_particle_type(ParticleType p_type); - - //---------------------------------------------------------------------------- - // Accessors - int32_t id() const { return id_; } - int32_t& id() { return id_; } - - int32_t index() const { return index_; } - - vector& energy_bounds() { return energy_bounds_; } - - const std::unique_ptr& mesh() const - { - return model::meshes[mesh_idx_]; - } - - const xt::xtensor& lower_ww_bounds() const { return lower_ww_; } - xt::xtensor& lower_ww_bounds() { return lower_ww_; } - - const xt::xtensor& upper_ww_bounds() const { return upper_ww_; } - xt::xtensor& upper_ww_bounds() { return upper_ww_; } - - ParticleType particle_type() const { return particle_type_; } - - private: - //---------------------------------------------------------------------------- - // Data members - int32_t id_; //!< Unique ID - gsl::index index_; //!< Index into weight windows vector - ParticleType particle_type_ { - ParticleType::neutron}; //!< Particle type to apply weight windows to - vector energy_bounds_; //!< Energy boundaries [eV] - xt::xtensor lower_ww_; //!< Lower weight window bounds (shape: - //!< energy_bins, mesh_bins (k, j, i)) - xt::xtensor - upper_ww_; //!< Upper weight window bounds (shape: energy_bins, mesh_bins) - double survival_ratio_ {3.0}; //!< Survival weight ratio - double max_lb_ratio_ { - 1.0}; //!< Maximum lower bound to particle weight ratio - double weight_cutoff_ {DEFAULT_WEIGHT_CUTOFF}; //!< Weight cutoff - int max_split_ {10}; //!< Maximum value for particle splitting - int32_t mesh_idx_; //!< Index in meshes vector - }; - - class WeightWindowsGenerator { - public: - // Constructors - WeightWindowsGenerator(pugi::xml_node node); - - // Methods - void update() const; - - // Data members - int32_t - tally_idx_; //!< Index of the tally used to update the weight windows - int32_t ww_idx_; //!< Index of the weight windows object being generated - std::string method_; //!< Method used to update weight window. Only "magic" - //!< is valid for now. - int32_t max_realizations_; //!< Maximum number of tally realizations - int32_t update_interval_; //!< Determines how often updates occur - bool on_the_fly_; //!< Whether or not weight windows - - // MAGIC update parameters - std::string tally_value_ { - "mean"}; // + void check_bounds(const T& lower) const; + + void check_tally_update_compatibility(const Tally* tally); + +public: + //! Set the weight window ID + void set_id(int32_t id = -1); + + void set_energy_bounds(gsl::span bounds); + + void set_mesh(const std::unique_ptr& mesh); + + void set_mesh(const Mesh* mesh); + + void set_mesh(int32_t mesh_idx); + + //! Ready the weight window class for use + void set_defaults(); + + //! Ensure the weight window lower bounds are properly allocated + void allocate_ww_bounds(); + + //! Update weight window boundaries using tally results + //! \param[in] tally Pointer to the tally whose results will be used to + //! update weight windows \param[in] value String representing the type of + //! value to use for weight window generation (one of "mean" or "rel_err") + //! \param[in] threshold Relative error threshold. Results over this + //! threshold will be ignored \param[in] ratio Ratio of upper to lower + //! weight window bounds + void update_magic(const Tally* tally, const std::string& value = "mean", + double threshold = 1.0, double ratio = 5.0); + + // NOTE: This is unused for now but may be used in the future + //! Write weight window settings to an HDF5 file + //! \param[in] group HDF5 group to write to + void to_hdf5(hid_t group) const; + + //! Retrieve the weight window for a particle + //! \param[in] p Particle to get weight window for + WeightWindow get_weight_window(const Particle& p) const; + + std::array bounds_size() const; + + const vector& energy_bounds() const { return energy_bounds_; } + + void set_bounds(const xt::xtensor& lower_ww_bounds, + const xt::xtensor& upper_bounds); + + void set_bounds(const xt::xtensor& lower_bounds, double ratio); + + void set_bounds( + gsl::span lower_bounds, gsl::span upper_bounds); + + void set_bounds(gsl::span lower_bounds, double ratio); + + void set_particle_type(ParticleType p_type); + + //---------------------------------------------------------------------------- + // Accessors + int32_t id() const { return id_; } + int32_t& id() { return id_; } + + int32_t index() const { return index_; } + + vector& energy_bounds() { return energy_bounds_; } + + const std::unique_ptr& mesh() const { return model::meshes[mesh_idx_]; } + + const xt::xtensor& lower_ww_bounds() const { return lower_ww_; } + xt::xtensor& lower_ww_bounds() { return lower_ww_; } + + const xt::xtensor& upper_ww_bounds() const { return upper_ww_; } + xt::xtensor& upper_ww_bounds() { return upper_ww_; } + + ParticleType particle_type() const { return particle_type_; } + +private: + //---------------------------------------------------------------------------- + // Data members + int32_t id_; //!< Unique ID + gsl::index index_; //!< Index into weight windows vector + ParticleType particle_type_ { + ParticleType::neutron}; //!< Particle type to apply weight windows to + vector energy_bounds_; //!< Energy boundaries [eV] + xt::xtensor lower_ww_; //!< Lower weight window bounds (shape: + //!< energy_bins, mesh_bins (k, j, i)) + xt::xtensor + upper_ww_; //!< Upper weight window bounds (shape: energy_bins, mesh_bins) + double survival_ratio_ {3.0}; //!< Survival weight ratio + double max_lb_ratio_ {1.0}; //!< Maximum lower bound to particle weight ratio + double weight_cutoff_ {DEFAULT_WEIGHT_CUTOFF}; //!< Weight cutoff + int max_split_ {10}; //!< Maximum value for particle splitting + int32_t mesh_idx_ {-1}; //!< Index in meshes vector +}; + +class WeightWindowsGenerator { +public: + // Constructors + WeightWindowsGenerator(pugi::xml_node node); + + // Methods + void update() const; + + //! Create the tally used for weight window generation + void create_tally(); + + // Data members + int32_t tally_idx_; //!< Index of the tally used to update the weight windows + int32_t ww_idx_; //!< Index of the weight windows object being generated + std::string method_; //!< Method used to update weight window. Only "magic" + //!< is valid for now. + int32_t max_realizations_; //!< Maximum number of tally realizations + int32_t update_interval_; //!< Determines how often updates occur + bool on_the_fly_; //!< Whether or not to keep tally results between batches or + //!< realizations + + // MAGIC update parameters + std::string tally_value_ { + "mean"}; // int: if self.energy_bounds is None: - raise ValueError('Energy bounds are not set') + return 1 return self.energy_bounds.size - 1 @property @@ -650,7 +653,8 @@ class WeightWindowGenerator: Mesh used to represent the weight windows spatially energy_bounds : Iterable of Real A list of values for which each successive pair constitutes a range of - energies in [eV] for a single bin + energies in [eV] for a single bin. If no energy bins are provided, the + maximum and minimum energy for the data available at runtime. particle_type : {'neutron', 'photon'} Particle type the weight windows apply to @@ -681,6 +685,7 @@ class WeightWindowGenerator: def __init__(self, mesh, energy_bounds=None, particle_type='neutron'): self.mesh = mesh + self._energy_bounds = None if energy_bounds is not None: self.energy_bounds = energy_bounds self.particle_type = particle_type diff --git a/src/initialize.cpp b/src/initialize.cpp index 323da2cc08e..d667f4b03e2 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -33,6 +33,7 @@ #include "openmc/thermal.h" #include "openmc/timer.h" #include "openmc/vector.h" +#include "openmc/weight_windows.h" #ifdef LIBMESH #include "libmesh/libmesh.h" @@ -404,6 +405,8 @@ bool read_model_xml() } } + finalize_variance_reduction(); + return true; } @@ -427,6 +430,8 @@ void read_separate_xml_files() // Read the plots.xml regardless of plot mode in case plots are requested // via the API read_plots_xml(); + + finalize_variance_reduction(); } void initial_output() diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index dcdf13abe97..a1f8731f8e5 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -257,21 +257,26 @@ WeightWindows* WeightWindows::from_hdf5( void WeightWindows::set_defaults() { - // ensure default values are set + // set energy bounds to the min/max energy supported by the data if (energy_bounds_.size() == 0) { int p_type = static_cast(particle_type_); energy_bounds_.push_back(data::energy_min[p_type]); energy_bounds_.push_back(data::energy_max[p_type]); } +} - // some constructors won't allocate space for the bounds - // do that here so the object is valid - if (lower_ww_.size() == 0 || upper_ww_.size() == 0) { - lower_ww_ = xt::empty(bounds_size()); - lower_ww_.fill(-1); - upper_ww_ = xt::empty(bounds_size()); - upper_ww_.fill(-1); +void WeightWindows::allocate_ww_bounds() +{ + auto shape = bounds_size(); + if (shape[0] * shape[1] == 0) { + auto msg = fmt::format( + "Size of weight window bounds is zero for WeightWindows {}", id()); + warning(msg); } + lower_ww_ = xt::empty(shape); + lower_ww_.fill(-1); + upper_ww_ = xt::empty(shape); + upper_ww_.fill(-1); } void WeightWindows::set_id(int32_t id) @@ -308,6 +313,9 @@ void WeightWindows::set_energy_bounds(gsl::span bounds) { energy_bounds_.clear(); energy_bounds_.insert(energy_bounds_.begin(), bounds.begin(), bounds.end()); + // if the mesh is set, allocate space for weight window bounds + if (mesh_idx_ != C_NONE) + allocate_ww_bounds(); } void WeightWindows::set_particle_type(ParticleType p_type) @@ -325,6 +333,7 @@ void WeightWindows::set_mesh(int32_t mesh_idx) fatal_error(fmt::format("Could not find a mesh for index {}", mesh_idx)); mesh_idx_ = mesh_idx; + allocate_ww_bounds(); } void WeightWindows::set_mesh(const std::unique_ptr& mesh) @@ -743,43 +752,6 @@ WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) e_bounds.push_back(data::energy_max[p_type]); } - // create a tally based on the WWG information - Tally* ww_tally = Tally::create(); - tally_idx_ = model::tally_map[ww_tally->id()]; - ww_tally->set_scores({"flux"}); - - // see if there's already a mesh filter using this mesh - bool found_mesh_filter = false; - for (const auto& f : model::tally_filters) { - if (f->type() == FilterType::MESH) { - const auto* mesh_filter = dynamic_cast(f.get()); - if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated()) { - ww_tally->add_filter(f.get()); - found_mesh_filter = true; - break; - } - } - } - - if (!found_mesh_filter) { - auto mesh_filter = Filter::create("mesh"); - openmc_mesh_filter_set_mesh(mesh_filter->index(), model::mesh_map[mesh_id]); - ww_tally->add_filter(mesh_filter); - } - - if (e_bounds.size() > 0) { - auto energy_filter = Filter::create("energy"); - openmc_energy_filter_set_bins( - energy_filter->index(), e_bounds.size(), e_bounds.data()); - ww_tally->add_filter(energy_filter); - } - - // add a particle filter - auto particle_filter = Filter::create("particle"); - auto pf = dynamic_cast(particle_filter); - pf->set_particles({&particle_type, 1}); - ww_tally->add_filter(particle_filter); - // set method and parameters for updates method_ = get_node_value(node, "method"); if (method_ == "magic") { @@ -815,13 +787,59 @@ WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) // create a matching weight windows object auto wws = WeightWindows::create(); ww_idx_ = wws->index(); + wws->set_mesh(mesh_idx); if (e_bounds.size() > 0) wws->set_energy_bounds(e_bounds); - wws->set_mesh(model::mesh_map[mesh_id]); wws->set_particle_type(particle_type); wws->set_defaults(); } +void WeightWindowsGenerator::create_tally() +{ + const auto& wws = variance_reduction::weight_windows[ww_idx_]; + + // create a tally based on the WWG information + Tally* ww_tally = Tally::create(); + tally_idx_ = model::tally_map[ww_tally->id()]; + ww_tally->set_scores({"flux"}); + + int32_t mesh_id = wws->mesh()->id(); + int32_t mesh_idx = model::mesh_map.at(mesh_id); + // see if there's already a mesh filter using this mesh + bool found_mesh_filter = false; + for (const auto& f : model::tally_filters) { + if (f->type() == FilterType::MESH) { + const auto* mesh_filter = dynamic_cast(f.get()); + if (mesh_filter->mesh() == mesh_idx && !mesh_filter->translated()) { + ww_tally->add_filter(f.get()); + found_mesh_filter = true; + break; + } + } + } + + if (!found_mesh_filter) { + auto mesh_filter = Filter::create("mesh"); + openmc_mesh_filter_set_mesh(mesh_filter->index(), model::mesh_map[mesh_id]); + ww_tally->add_filter(mesh_filter); + } + + const auto& e_bounds = wws->energy_bounds(); + if (e_bounds.size() > 0) { + auto energy_filter = Filter::create("energy"); + openmc_energy_filter_set_bins( + energy_filter->index(), e_bounds.size(), e_bounds.data()); + ww_tally->add_filter(energy_filter); + } + + // add a particle filter + auto particle_type = wws->particle_type(); + auto particle_filter = Filter::create("particle"); + auto pf = dynamic_cast(particle_filter); + pf->set_particles({&particle_type, 1}); + ww_tally->add_filter(particle_filter); +} + void WeightWindowsGenerator::update() const { const auto& wws = variance_reduction::weight_windows[ww_idx_]; @@ -845,6 +863,17 @@ void WeightWindowsGenerator::update() const // complete } +//============================================================================== +// Non-member functions +//============================================================================== + +void finalize_variance_reduction() +{ + for (const auto& wwg : variance_reduction::weight_windows_generators) { + wwg->create_tally(); + } +} + //============================================================================== // C API //============================================================================== diff --git a/tests/regression_tests/weightwindows/generators/test.py b/tests/regression_tests/weightwindows/generators/test.py index f5bfc4dcd02..1d516db8dde 100644 --- a/tests/regression_tests/weightwindows/generators/test.py +++ b/tests/regression_tests/weightwindows/generators/test.py @@ -28,13 +28,20 @@ def test_ww_generator(run_in_tmpdir): energy_bounds = np.linspace(0.0, 1e6, 70) particle = 'neutron' + # include another tally to make sure user-specified tallies and those automaticaly + # created by weight window generators can coexist + tally = openmc.Tally() + ef = openmc.EnergyFilter(energy_bounds) + tally.filters = [ef] + tally.scores = ['flux'] + model.tallies = [tally] + wwg = openmc.WeightWindowGenerator(mesh, energy_bounds, particle) - wwg.update_parameters = {'ratio' : 5.0, 'threshold': 0.8, 'value' : 'mean'} + wwg.update_parameters = {'ratio': 5.0, 'threshold': 0.8, 'value': 'mean'} model.settings.weight_window_generators = wwg - model.export_to_xml() - model.run() + # we test the effectiveness of the update method elsewhere, so # just test that the generation happens successfully here assert os.path.exists('weight_windows.h5') diff --git a/tests/unit_tests/weightwindows/test.py b/tests/unit_tests/weightwindows/test.py index f8db66820dd..8af843cbdc0 100644 --- a/tests/unit_tests/weightwindows/test.py +++ b/tests/unit_tests/weightwindows/test.py @@ -241,7 +241,21 @@ def test_roundtrip(run_in_tmpdir, model, wws): assert(ww_out == ww_in) -def test_ww_attrs(run_in_tmpdir, model): +def test_ww_attrs_python(model): + mesh = openmc.RegularMesh.from_domain(model.geometry) + lower_bounds = np.ones(mesh.dimension) + + # ensure that creation of weight window objects with default arg values + # is successful + wws = openmc.WeightWindows(mesh, lower_bounds, upper_bound_ratio=10.0) + + assert wws.energy_bounds == None + + wwg = openmc.WeightWindowGenerator(mesh) + + assert wwg.energy_bounds == None + +def test_ww_attrs_capi(run_in_tmpdir, model): model.export_to_xml() openmc.lib.init()