diff --git a/CMakeLists.txt b/CMakeLists.txt index 626aadae8..2ccc457f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,11 @@ endif() #=============================================================================== add_library(pugixml vendor/pugixml/pugixml.cpp) -target_include_directories(pugixml PUBLIC vendor/pugixml/) +target_include_directories(pugixml + PUBLIC + $ + $ +) #=============================================================================== # xtensor header-only library @@ -126,6 +130,7 @@ if (NOT (CMAKE_VERSION VERSION_LESS 3.13)) endif() add_subdirectory(vendor/xtl) +set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl) add_subdirectory(vendor/xtensor) target_link_libraries(xtensor INTERFACE xtl) @@ -134,7 +139,11 @@ target_link_libraries(xtensor INTERFACE xtl) #=============================================================================== add_library(gsl INTERFACE) -target_include_directories(gsl INTERFACE vendor/gsl/include) +target_include_directories(gsl + INTERFACE + $ + $ +) # Make sure contract violations throw exceptions target_compile_definitions(gsl INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION) @@ -143,6 +152,9 @@ target_compile_definitions(gsl INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION) # RPATH information #=============================================================================== +# Provide install directory variables as defined by GNU coding standards +include(GNUInstallDirs) + # This block of code ensures that dynamic libraries can be found via the RPATH # whether the executable is the original one from the build directory or the # installed one in CMAKE_INSTALL_PREFIX. Ref: @@ -155,16 +167,14 @@ set(CMAKE_SKIP_BUILD_RPATH FALSE) # (but later on when installing) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) -set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") - # add the automatically determined parts of the RPATH # which point to directories outside the build tree to the install RPATH set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) # the RPATH to be used when installing, but only if it's not a system directory -list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir) +list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_FULL_LIBDIR}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") - set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib") + set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_FULL_LIBDIR}") endif() #=============================================================================== @@ -172,7 +182,11 @@ endif() #=============================================================================== add_library(faddeeva STATIC vendor/faddeeva/Faddeeva.cc) -target_include_directories(faddeeva PUBLIC vendor/faddeeva/) +target_include_directories(faddeeva + PUBLIC + $ + $ +) target_compile_options(faddeeva PRIVATE ${cxxflags}) #=============================================================================== @@ -283,7 +297,11 @@ set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) target_include_directories(libopenmc - PUBLIC include ${HDF5_INCLUDE_DIRS}) + PUBLIC + $ + $ + ${HDF5_INCLUDE_DIRS} +) # Set compile flags target_compile_options(libopenmc PRIVATE ${cxxflags}) @@ -343,12 +361,27 @@ add_custom_command(TARGET libopenmc POST_BUILD # Install executable, scripts, manpage, license #=============================================================================== -install(TARGETS openmc libopenmc - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - ) -install(DIRECTORY src/relaxng DESTINATION share/openmc) -install(FILES man/man1/openmc.1 DESTINATION share/man/man1) -install(FILES LICENSE DESTINATION "share/doc/openmc" RENAME copyright) -install(DIRECTORY include/ DESTINATION include) +set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) +install(TARGETS openmc libopenmc pugixml faddeeva gsl + EXPORT openmc-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +install(EXPORT openmc-targets + FILE OpenMCTargets.cmake + NAMESPACE OpenMC:: + DESTINATION ${INSTALL_CONFIGDIR}) + +install(DIRECTORY src/relaxng DESTINATION ${CMAKE_INSTALL_DATADIR}/openmc) +install(FILES cmake/OpenMCConfig.cmake DESTINATION ${INSTALL_CONFIGDIR}) +install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright) +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# Copy headers for vendored dependencies (note that xtensor/xtl are handled +# separately since they are managed by CMake) +install(DIRECTORY vendor/pugixml DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.hpp") +install(DIRECTORY vendor/gsl DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(DIRECTORY vendor/faddeeva DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..a061b7b6e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,48 @@ +# Data interface +openmc/data/ @paulromano + +# Python bindings to C/C++ API +openmc/lib/ @paulromano + +# Depletion +openmc/deplete/ @drewejohnson +tests/regression_tests/deplete/ @drewejohnson +tests/unit_tests/test_deplete_*.py @drewejohnson + +# MG-related functionality +openmc/mgxs_library.py @nelsonag +src/mgxs.cpp @nelsonag +src/mgxs_interface.cpp @nelsonag +src/physics_mg.cpp @nelsonag +src/scattdata.cpp @nelsonag +src/xsdata.cpp @nelsonag + +# CMFD +openmc/cmfd.py @shikhar413 +src/cmfd_solver.cpp @shikhar413 + +# DAGMC +src/dagmc.cpp @pshriwise +tests/regression_tests/dagmc/ @pshriwise +tests/unit_tests/dagmc/ @pshriwise + +# Photon transport +openmc/data/BREMX.DAT @amandalund +openmc/data/compton_profiles.h5 @amandalund +openmc/data/photon.py @amandalund +src/photon.cpp @amandalund +src/bremsstrahlung.cpp @amandalund +tests/regression_tests/photon_production/ @amandalund +tests/regression_tests/photon_source/ @amandalund + +# RCP and TRISOs +openmc/model/triso.py @amandalund +tests/regression_tests/triso/ @amandalund +tests/unit_tests/test_model_triso.py @amandalund + +# Geometry plotting +src/plot.cpp @pshriwise +openmc/lib/plot.py @pshriwise + +# Resonance covariance +openmc/data/resonance_covariance.py @icmeyer diff --git a/LICENSE b/LICENSE index cfa34033c..328f3ee46 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2018 Massachusetts Institute of Technology and OpenMC contributors +Copyright (c) 2011-2019 Massachusetts Institute of Technology and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/cmake/OpenMCConfig.cmake b/cmake/OpenMCConfig.cmake new file mode 100644 index 000000000..0bc86fa71 --- /dev/null +++ b/cmake/OpenMCConfig.cmake @@ -0,0 +1,8 @@ +get_filename_component(OpenMC_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) + +find_package(xtl REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtl) +find_package(xtensor REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtensor) + +if(NOT TARGET OpenMC::libopenmc) + include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake") +endif() diff --git a/docs/source/conf.py b/docs/source/conf.py index 55776b8f4..68caff888 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -27,7 +27,7 @@ MOCK_MODULES = [ 'scipy.interpolate', 'scipy.integrate', 'scipy.optimize', 'scipy.special', 'scipy.stats', 'scipy.spatial', 'h5py', 'pandas', 'uncertainties', 'matplotlib', 'matplotlib.pyplot', 'openmoc', - 'openmc.data.reconstruct' + 'openmc.data.reconstruct', 'openmc.checkvalue' ] sys.modules.update((mod_name, MagicMock()) for mod_name in MOCK_MODULES) @@ -79,9 +79,9 @@ copyright = '2011-2019, Massachusetts Institute of Technology and OpenMC contrib # built documents. # # The short X.Y version. -version = "0.11" +version = "0.12" # The full version, including alpha/beta/rc tags. -release = "0.11.0-dev" +release = "0.12.0-dev" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/devguide/docbuild.rst b/docs/source/devguide/docbuild.rst index 5cbbb65bb..38ef628df 100644 --- a/docs/source/devguide/docbuild.rst +++ b/docs/source/devguide/docbuild.rst @@ -5,27 +5,28 @@ Building Sphinx Documentation ============================= In order to build the documentation in the ``docs`` directory, you will need to -have the `Sphinx `_ third-party Python +have the `Sphinx `_ third-party Python package. The easiest way to install Sphinx is via pip: .. code-block:: sh - sudo pip install sphinx + pip install sphinx -Additionally, you will also need a Sphinx extension for numbering figures. The -`Numfig `_ package can be installed +Additionally, you will need several Sphinx extensions that can be installed directly with pip: .. code-block:: sh - sudo pip install sphinx-numfig + pip install sphinx-numfig + pip install sphinxcontrib-katex + pip install sphinxcontrib-svg2pdfconverter ----------------------------------- Building Documentation as a Webpage ----------------------------------- To build the documentation as a webpage (what appears at -http://openmc.readthedocs.io), simply go to the ``docs`` directory and run: +https://docs.openmc.org), simply go to the ``docs`` directory and run: .. code-block:: sh diff --git a/docs/source/devguide/docker.rst b/docs/source/devguide/docker.rst index 12c095c45..0b2191168 100644 --- a/docs/source/devguide/docker.rst +++ b/docs/source/devguide/docker.rst @@ -19,7 +19,7 @@ build a Docker image with OpenMC installed. The image includes OpenMC with MPICH and parallel HDF5 in the ``/opt/openmc`` directory, and `Miniconda3 `_ with all of the Python pre-requisites (NumPy, SciPy, Pandas, etc.) installed. The -`NJOY2016 `_ codebase is installed in +`NJOY2016 `_ codebase is installed in ``/opt/NJOY2016`` to support full functionality and testing of the ``openmc.data`` Python module. The publicly available nuclear data libraries necessary to run OpenMC's test suite -- including NNDC and WMP cross sections @@ -54,4 +54,3 @@ Docker container where you have access to use OpenMC. .. _Docker container: https://www.docker.com/resources/what-container .. _options: https://docs.docker.com/engine/reference/commandline/run/ .. _mounting volumes: https://docs.docker.com/storage/volumes/ - diff --git a/docs/source/devguide/styleguide.rst b/docs/source/devguide/styleguide.rst index cbf665cc8..562b75e89 100644 --- a/docs/source/devguide/styleguide.rst +++ b/docs/source/devguide/styleguide.rst @@ -207,8 +207,8 @@ Documentation ------------- Classes, structs, and functions are to be annotated for the `Doxygen -`_ documentation generation tool. Use the -``\`` form of Doxygen commands, e.g., ``\brief`` instead of ``@brief``. +`_ documentation generation tool. Use the ``\`` form of +Doxygen commands, e.g., ``\brief`` instead of ``@brief``. ------ Python @@ -231,7 +231,7 @@ represent a filesystem path should work with both strings and Path_ objects. .. _C++ Core Guidelines: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines .. _PEP8: https://www.python.org/dev/peps/pep-0008/ .. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html -.. _numpy: http://www.numpy.org/ +.. _numpy: https://numpy.org/ .. _scipy: https://www.scipy.org/ .. _matplotlib: https://matplotlib.org/ .. _pandas: https://pandas.pydata.org/ diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index 31dc08842..037b8b68a 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -124,7 +124,7 @@ can interfere with virtual environments. .. _GitHub: https://github.com/ .. _git flow: http://nvie.com/git-model .. _valgrind: http://valgrind.org/ -.. _style guide: http://openmc.readthedocs.io/en/latest/devguide/styleguide.html +.. _style guide: https://docs.openmc.org/en/latest/devguide/styleguide.html .. _pull request: https://help.github.com/articles/using-pull-requests .. _openmc-dev/openmc: https://github.com/openmc-dev/openmc .. _paid plan: https://github.com/plans diff --git a/docs/source/index.rst b/docs/source/index.rst index 2ce5072d0..198a9429e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,12 +2,14 @@ The OpenMC Monte Carlo Code =========================== -OpenMC is a Monte Carlo particle transport simulation code focused on neutron -criticality calculations. It is capable of simulating 3D models based on -constructive solid geometry with second-order surfaces. OpenMC supports either -continuous-energy or multi-group transport. The continuous-energy particle +OpenMC is a community-developed Monte Carlo neutron and photon transport +simulation code. It is capable of performing fixed source, k-eigenvalue, and +subcritical multiplication calculations on models built using either a +constructive solid geometry or CAD representation. OpenMC supports both +continuous-energy and multigroup transport. The continuous-energy particle interaction data is based on a native HDF5 format that can be generated from ACE -files used by the MCNP and Serpent Monte Carlo codes. +files produced by NJOY. Parallelism is enabled via a hybrid MPI and OpenMP +programming model. OpenMC was originally developed by members of the `Computational Reactor Physics Group `_ at the `Massachusetts Institute of Technology diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index 9c68a9730..c14767e46 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -333,7 +333,7 @@ or sub-elements: velocity sampling) or "dbrc" (Doppler broadening rejection correction). Descriptions of each of these methods are documented here_. - .. _here: http://dx.doi.org/10.1016/j.anucene.2017.12.044 + .. _here: https://doi.org/10.1016/j.anucene.2017.12.044 *Default*: "rvs" @@ -423,12 +423,16 @@ attributes/sub-elements: :type: The type of spatial distribution. Valid options are "box", "fission", - "point", and "cartesian". A "box" spatial distribution has coordinates - sampled uniformly in a parallelepiped. A "fission" spatial distribution - samples locations from a "box" distribution but only locations in - fissionable materials are accepted. A "point" spatial distribution has - coordinates specified by a triplet. An "cartesian" spatial distribution - specifies independent distributions of x-, y-, and z-coordinates. + "point", "cartesian", and "spherical". A "box" spatial distribution has + coordinates sampled uniformly in a parallelepiped. A "fission" spatial + distribution samples locations from a "box" distribution but only + locations in fissionable materials are accepted. A "point" spatial + distribution has coordinates specified by a triplet. An "cartesian" + spatial distribution specifies independent distributions of x-, y-, and + z-coordinates. A "spherical" spatial distribution specifies independent + distributions of r-, theta-, and phi-coordinates where theta is the angle + with respect to the z-axis, phi is the azimuthal angle, and the sphere is + centered on the coordinate (x0,y0,z0). *Default*: None @@ -446,6 +450,9 @@ attributes/sub-elements: For an "cartesian" distribution, no parameters are specified. Instead, the ``x``, ``y``, and ``z`` elements must be specified. + For a "spherical" distribution, no parameters are specified. Instead, + the ``r``, ``theta``, ``phi``, and ``origin`` elements must be specified. + *Default*: None :x: @@ -466,6 +473,28 @@ attributes/sub-elements: univariate probability distribution (see the description in :ref:`univariate`). + :r: + For a "spherical" distribution, this element specifies the distribution + of r-coordinates. The necessary sub-elements/attributes are those of a + univariate probability distribution (see the description in + :ref:`univariate`). + + :theta: + For a "spherical" distribution, this element specifies the distribution + of theta-coordinates. The necessary sub-elements/attributes are those of a + univariate probability distribution (see the description in + :ref:`univariate`). + + :phi: + For a "spherical" distribution, this element specifies the distribution + of phi-coordinates. The necessary sub-elements/attributes are those of a + univariate probability distribution (see the description in + :ref:`univariate`). + + :origin: + For a "spherical" distribution, this element specifies the coordinates of + the center of the sphere. + :angle: An element specifying the angular distribution of source sites. This element has the following attributes: diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 9c5b8f526..9156e848f 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -109,6 +109,11 @@ The current version of the statepoint file format is 17.0. **/tallies/tally /** +:Attributes: + - **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. + :Datasets: - **n_realizations** (*int*) -- Number of realizations. - **n_filters** (*int*) -- Number of filters used. - **filters** (*int[]*) -- User-defined unique IDs of the filters on diff --git a/docs/source/io_formats/volume.rst b/docs/source/io_formats/volume.rst index 456a06eef..c79255a1c 100644 --- a/docs/source/io_formats/volume.rst +++ b/docs/source/io_formats/volume.rst @@ -23,6 +23,8 @@ The current version of the volume file format is 1.0. bounding box - **upper_right** (*double[3]*) -- Upper-right coordinates of bounding box + - **threshold** (*double*) -- Threshold used for volume uncertainty + - **trigger_type** (*char[]*) -- Trigger type used for volume uncertainty **/domain_/** diff --git a/docs/source/methods/cmfd.rst b/docs/source/methods/cmfd.rst index b13004e10..344a4cc1a 100644 --- a/docs/source/methods/cmfd.rst +++ b/docs/source/methods/cmfd.rst @@ -538,7 +538,7 @@ Examples of CMFD simulations using OpenMC can be found in [HermanThesis]_. .. rubric:: References .. [BEAVRS] Nick Horelik, Bryan Herman. *Benchmark for Evaluation And Verification of Reactor - Simulations*. Massachusetts Institute of Technology, http://crpg.mit.edu/pub/beavrs + Simulations*. Massachusetts Institute of Technology, https://crpg.mit.edu/research/beavrs , 2013. .. [Gill] Daniel F. Gill. *Newton-Krylov methods for the solution of the k-eigenvalue problem in diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 4940275d3..c360805be 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -8,13 +8,14 @@ Cross Section Representations Continuous-Energy Data ---------------------- -The data governing the interaction of neutrons with -various nuclei for continous-energy problems are represented using the ACE -format which is used by MCNP_ and Serpent_. ACE-format data can be generated -with the NJOY_ nuclear data processing system which converts raw -`ENDF/B data`_ into linearly-interpolable data as required by most Monte Carlo -codes. The use of a standard cross section format allows for a direct comparison -of OpenMC with other codes since the same cross section libraries can be used. +In OpenMC, the data governing the interaction of neutrons with various nuclei +for continous-energy problems are represented using an HDF5 format that can be +produced by converting files in the ACE format, which is used by MCNP_ and +Serpent_. ACE-format data can be generated with the NJOY_ nuclear data +processing system, which converts raw `ENDF/B data`_ into linearly-interpolable +data as required by most Monte Carlo codes. Since ACE-format data can be +converted into OpenMC's HDF5 format, it is possible to perform direct comparison +of OpenMC with other codes using the same underlying nuclear data library. The ACE format contains continuous-energy cross sections for the following types of reactions: elastic scattering, fission (or first-chance fission, @@ -31,7 +32,7 @@ data can be used. Energy Grid Methods ------------------- -The method by which continuous energy cross sections for each nuclide in a +The method by which continuous-energy cross sections for each nuclide in a problem are stored as a function of energy can have a substantial effect on the performance of a Monte Carlo simulation. Since the ACE format is based on linearly-interpolable cross sections, each nuclide has cross sections tabulated @@ -72,9 +73,9 @@ Windowed Multipole Representation --------------------------------- In addition to the usual pointwise representation of cross sections, OpenMC -offers support for an experimental data format called windowed multipole (WMP). -This data format requires less memory than pointwise cross sections, and it -allows on-the-fly Doppler broadening to arbitrary temperature. +offers support for a data format called windowed multipole (WMP). This data +format requires less memory than pointwise cross sections, and it allows +on-the-fly Doppler broadening to arbitrary temperature. The multipole method was introduced by Hwang_ and the faster windowed multipole method by Josey_. In the multipole format, cross section resonances are @@ -258,7 +259,7 @@ where a material has a very large cross sections relative to the other material used to minimize this error. Finally, the above options for representing the physics do not have to be -consistent across the problem. The number of groups and the structure, however, +consistent across the problem. The number of groups and the structure, however, does have to be consistent across the data sets. That is to say that each microscopic or macroscopic data set does not have to apply the same scattering expansion, treatment of multiplicity or angular representation of the cross @@ -269,11 +270,11 @@ or even isotropic scattering. .. _logarithmic mapping technique: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-14-24530.pdf .. _Hwang: http://www.ans.org/pubs/journals/nse/a_16381 -.. _Josey: http://dx.doi.org/10.1016/j.jcp.2015.08.013 +.. _Josey: https://doi.org/10.1016/j.jcp.2015.08.013 .. _WMP Library: https://github.com/mit-crpg/WMP_Library .. _MCNP: http://mcnp.lanl.gov .. _Serpent: http://montecarlo.vtt.fi .. _NJOY: http://t2.lanl.gov/codes.shtml .. _ENDF/B data: http://www.nndc.bnl.gov/endf -.. _Leppanen: http://dx.doi.org/10.1016/j.anucene.2009.03.019 +.. _Leppanen: https://doi.org/10.1016/j.anucene.2009.03.019 .. _algorithms: http://ab-initio.mit.edu/wiki/index.php/Faddeeva_Package diff --git a/docs/source/methods/energy_deposition.rst b/docs/source/methods/energy_deposition.rst index af4962c55..86dfb9bf9 100644 --- a/docs/source/methods/energy_deposition.rst +++ b/docs/source/methods/energy_deposition.rst @@ -4,11 +4,11 @@ Heating and Energy Deposition ============================= -As particles traverse a problem, some portion of their energy is deposited at +As particles traverse a problem, some portion of their energy is deposited at collision sites. This energy is deposited when charged particles, including electrons and recoil nuclei, undergo electromagnetic interactions with surrounding electons and ions. The information describing how much energy -is deposited for a specific reaction is referred to as +is deposited for a specific reaction is referred to as "heating numbers" and can be computed using a program like NJOY with the ``heatr`` module. @@ -108,7 +108,7 @@ Neutron Transport For this case, OpenMC instructs ``heatr`` to produce heating coefficients assuming that energy from photons, :math:`E_{\gamma, p}` and :math:`E_{\gamma, d}`, is deposited at the fission site. -Let :math:`N901` represent the total heating number returned from this ``heatr`` +Let :math:`N901` represent the total heating number returned from this ``heatr`` run with :math:`N918` reflecting fission heating computed from NJOY. :math:`M901` represent the following modification @@ -119,7 +119,7 @@ run with :math:`N918` reflecting fission heating computed from NJOY. + E_{i, \gamma, d}\right]\sigma_{i, f}(E). This modified heating data is stored as the MT=901 reaction and will be scored -if ``901`` is included in :attr:`openmc.Tally.scores`. +if ``heating-local`` is included in :attr:`openmc.Tally.scores`. Coupled neutron-photon transport -------------------------------- @@ -146,4 +146,4 @@ References .. [Mack97] Abdou, M.A., Maynard, C.W., and Wright, R.Q. MACK: computer program to calculate neutron energy release parameters (fluence-to-kerma factors) and multigroup neutron reaction cross sections from nuclear data - in ENDF Format. Oak Ridge National Laboratory report ORNL-TM-3994. \ No newline at end of file + in ENDF Format. Oak Ridge National Laboratory report ORNL-TM-3994. diff --git a/docs/source/methods/geometry.rst b/docs/source/methods/geometry.rst index 7416aee5b..38d9eb172 100644 --- a/docs/source/methods/geometry.rst +++ b/docs/source/methods/geometry.rst @@ -960,8 +960,8 @@ normal using the equations from :ref:`transform-coordinates`. The white boundary condition can be applied to any kind of surface, as long as the normal to the surface is known as in :ref:`reflection`. -.. _constructive solid geometry: http://en.wikipedia.org/wiki/Constructive_solid_geometry -.. _surfaces: http://en.wikipedia.org/wiki/Surface +.. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry +.. _surfaces: https://en.wikipedia.org/wiki/Surface .. _MCNP: http://mcnp.lanl.gov .. _Serpent: http://montecarlo.vtt.fi .. _Monte Carlo Performance benchmark: https://github.com/mit-crpg/benchmarks/tree/master/mc-performance/openmc diff --git a/docs/source/methods/introduction.rst b/docs/source/methods/introduction.rst index dab1c544a..adb52c02e 100644 --- a/docs/source/methods/introduction.rst +++ b/docs/source/methods/introduction.rst @@ -139,9 +139,9 @@ be performed before the run is finished. This include the following: - If requested, a source file is written to disk. - - All allocatable arrays are deallocated. + - Dynamically-allocated memory should be freed. -.. _probability distributions: http://en.wikipedia.org/wiki/Probability_distribution -.. _Monte Carlo: http://en.wikipedia.org/wiki/Monte_Carlo_method -.. _central limit theorem: http://en.wikipedia.org/wiki/Central_limit_theorem -.. _pseudorandom number: http://en.wikipedia.org/wiki/Pseudorandom_number_generator +.. _probability distributions: https://en.wikipedia.org/wiki/Probability_distribution +.. _Monte Carlo: https://en.wikipedia.org/wiki/Monte_Carlo_method +.. _central limit theorem: https://en.wikipedia.org/wiki/Central_limit_theorem +.. _pseudorandom number: https://en.wikipedia.org/wiki/Pseudorandom_number_generator diff --git a/docs/source/methods/neutron_physics.rst b/docs/source/methods/neutron_physics.rst index 60d3c1468..384e79bdd 100644 --- a/docs/source/methods/neutron_physics.rst +++ b/docs/source/methods/neutron_physics.rst @@ -1298,11 +1298,10 @@ section over the range of velocities considered: where it should be noted that the maximum is taken over the range :math:`[v_n - 4/\beta, 4_n + 4\beta]`. This method is known as Doppler broadening rejection correction (DBRC) and was first introduced by `Becker et al.`_. OpenMC has an -implementation of DBRC as well as an accelerated sampling method that are -described fully in `Walsh et al.`_ +implementation of DBRC as well as an accelerated sampling method that samples the `relative velocity`_ directly. -.. _Becker et al.: http://dx.doi.org/10.1016/j.anucene.2008.12.001 -.. _Walsh et al.: http://dx.doi.org/10.1016/j.anucene.2014.01.017 +.. _Becker et al.: https://doi.org/10.1016/j.anucene.2008.12.001 +.. _relative velocity: https://doi.org/10.1016/j.anucene.2017.12.044 .. _sab_tables: @@ -1645,23 +1644,23 @@ another. .. |sab| replace:: S(:math:`\alpha,\beta,T`) -.. _SIGMA1 method: http://dx.doi.org/10.13182/NSE76-1 +.. _SIGMA1 method: https://doi.org/10.13182/NSE76-1 .. _scaled interpolation: http://www.ans.org/pubs/journals/nse/a_26575 -.. _probability table method: http://dx.doi.org/10.13182/NSE72-3 +.. _probability table method: https://doi.org/10.13182/NSE72-3 -.. _Watt fission spectrum: http://dx.doi.org/10.1103/PhysRev.87.1037 +.. _Watt fission spectrum: https://doi.org/10.1103/PhysRev.87.1037 .. _Foderaro: http://hdl.handle.net/1721.1/1716 -.. _OECD: http://www.oecd-nea.org/dbprog/MMRW-BOOKS.html +.. _OECD: http://www.oecd-nea.org/tools/abstract/detail/NEA-1792 -.. _NJOY: https://njoy.github.io/NJOY2016/ +.. _NJOY: https://www.njoy21.io/NJOY2016/ .. _PREPRO: http://www-nds.iaea.org/ndspub/endf/prepro/ -.. _ENDF-6 Format: http://www-nds.iaea.org/ndspub/documents/endf/endf102/endf102.pdf +.. _ENDF-6 Format: https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf .. _Monte Carlo Sampler: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-9721.pdf @@ -1669,7 +1668,7 @@ another. .. _MC21: http://www.osti.gov/bridge/servlets/purl/903083-HT5p1o/903083.pdf -.. _Romano: http://dx.doi.org/10.1016/j.cpc.2014.11.001 +.. _Romano: https://doi.org/10.1016/j.cpc.2014.11.001 .. _Sutton and Brown: http://www.osti.gov/bridge/product.biblio.jsp?osti_id=307911 diff --git a/docs/source/methods/parallelization.rst b/docs/source/methods/parallelization.rst index 63c4a9d21..5bf090a2b 100644 --- a/docs/source/methods/parallelization.rst +++ b/docs/source/methods/parallelization.rst @@ -607,33 +607,33 @@ is actually independent of the number of nodes: Radiation Penetration Calculations on a Parallel Computer," *Trans. Am. Nucl. Soc.*, **17**, 260 (1973). -.. _first paper: http://www.jstor.org/stable/2280232 +.. _first paper: https://doi.org/10.2307/2280232 .. _work of Forrest Brown: http://hdl.handle.net/2027.42/24996 -.. _Brissenden and Garlick: http://dx.doi.org/10.1016/0306-4549(86)90095-2 +.. _Brissenden and Garlick: https://doi.org/10.1016/0306-4549(86)90095-2 .. _MPICH2: http://www.mcs.anl.gov/mpi/mpich -.. _binomial tree: http://www.cs.auckland.ac.nz/~jmor159/PLDS210/trees.html +.. _binomial tree: https://www.mcs.anl.gov/~thakur/papers/ijhpca-coll.pdf -.. _Geary: http://www.jstor.org/stable/10.2307/2342070 +.. _Geary: https://doi.org/10.2307/2342070 .. _Barnett: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.7772 -.. _single-instruction multiple-data: http://en.wikipedia.org/wiki/SIMD +.. _single-instruction multiple-data: https://en.wikipedia.org/wiki/SIMD -.. _vector computers: http://en.wikipedia.org/wiki/Vector_processor +.. _vector computers: https://en.wikipedia.org/wiki/Vector_processor -.. _single program multiple data: http://en.wikipedia.org/wiki/SPMD +.. _single program multiple data: https://en.wikipedia.org/wiki/SPMD -.. _message-passing interface: http://en.wikipedia.org/wiki/Message_Passing_Interface +.. _message-passing interface: https://en.wikipedia.org/wiki/Message_Passing_Interface .. _PVM: http://www.csm.ornl.gov/pvm/pvm_home.html .. _MPI: http://www.mcs.anl.gov/research/projects/mpi/ -.. _embarrassingly parallel: http://en.wikipedia.org/wiki/Embarrassingly_parallel +.. _embarrassingly parallel: https://en.wikipedia.org/wiki/Embarrassingly_parallel .. _sends: http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Send.html @@ -643,8 +643,8 @@ is actually independent of the number of nodes: .. _allgather: http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Allgather.html -.. _Cauchy distribution: http://en.wikipedia.org/wiki/Cauchy_distribution +.. _Cauchy distribution: https://en.wikipedia.org/wiki/Cauchy_distribution -.. _latency: http://en.wikipedia.org/wiki/Latency_(engineering)#Packet-switched_networks +.. _latency: https://en.wikipedia.org/wiki/Latency_(engineering)#Packet-switched_networks -.. _bandwidth: http://en.wikipedia.org/wiki/Bandwidth_(computing) +.. _bandwidth: https://en.wikipedia.org/wiki/Bandwidth_(computing) diff --git a/docs/source/methods/random_numbers.rst b/docs/source/methods/random_numbers.rst index ce118556e..0cefc9156 100644 --- a/docs/source/methods/random_numbers.rst +++ b/docs/source/methods/random_numbers.rst @@ -67,6 +67,6 @@ the idea is to determine the new multiplicative and additive constants in .. rubric:: References -.. _L'Ecuyer: http://dx.doi.org/10.1090/S0025-5718-99-00996-5 +.. _L'Ecuyer: https://doi.org/10.1090/S0025-5718-99-00996-5 .. _Brown: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/anl-rn-arb-stride.pdf -.. _linear congruential generator: http://en.wikipedia.org/wiki/Linear_congruential_generator +.. _linear congruential generator: https://en.wikipedia.org/wiki/Linear_congruential_generator diff --git a/docs/source/methods/tallies.rst b/docs/source/methods/tallies.rst index 9e7bd93bb..d67584622 100644 --- a/docs/source/methods/tallies.rst +++ b/docs/source/methods/tallies.rst @@ -484,31 +484,31 @@ improve the estimate of the percentile. .. rubric:: References -.. _following approximation: http://dx.doi.org/10.1080/03610918708812641 +.. _following approximation: https://doi.org/10.1080/03610918708812641 -.. _Bessel's correction: http://en.wikipedia.org/wiki/Bessel's_correction +.. _Bessel's correction: https://en.wikipedia.org/wiki/Bessel's_correction -.. _random variable: http://en.wikipedia.org/wiki/Random_variable +.. _random variable: https://en.wikipedia.org/wiki/Random_variable -.. _stochastic process: http://en.wikipedia.org/wiki/Stochastic_process +.. _stochastic process: https://en.wikipedia.org/wiki/Stochastic_process -.. _independent, identically-distributed random variables: http://en.wikipedia.org/wiki/Independent_and_identically_distributed_random_variables +.. _independent, identically-distributed random variables: https://en.wikipedia.org/wiki/Independent_and_identically_distributed_random_variables -.. _law of large numbers: http://en.wikipedia.org/wiki/Law_of_large_numbers +.. _law of large numbers: https://en.wikipedia.org/wiki/Law_of_large_numbers -.. _expected value: http://en.wikipedia.org/wiki/Expected_value +.. _expected value: https://en.wikipedia.org/wiki/Expected_value -.. _converges in probability: http://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_probability +.. _converges in probability: https://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_probability -.. _normal distribution: http://en.wikipedia.org/wiki/Normal_distribution +.. _normal distribution: https://en.wikipedia.org/wiki/Normal_distribution -.. _converges in distribution: http://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_distribution +.. _converges in distribution: https://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_distribution -.. _confidence intervals: http://en.wikipedia.org/wiki/Confidence_interval +.. _confidence intervals: https://en.wikipedia.org/wiki/Confidence_interval -.. _Student's t-distribution: http://en.wikipedia.org/wiki/Student%27s_t-distribution +.. _Student's t-distribution: https://en.wikipedia.org/wiki/Student%27s_t-distribution -.. _Cauchy distribution: http://en.wikipedia.org/wiki/Cauchy_distribution +.. _Cauchy distribution: https://en.wikipedia.org/wiki/Cauchy_distribution .. _unpublished rational approximation: https://web.archive.org/web/20150926021742/http://home.online.no/~pjacklam/notes/invnorm/ diff --git a/docs/source/publications.rst b/docs/source/publications.rst index 32b911e5b..7439d2e34 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -142,6 +142,11 @@ Geometry and Visualization Miscellaneous ------------- +- Govatsa Acharya, "`Investigating the Application of Self-Actuated Passive + Shutdown System in a Small Lead-Cooled Reactor + `_," M.S. Thesis, KTH Royal + Institute of Technology (2019). + - Shikhar Kumar, Benoit Forget, and Kord Smith, "Analysis of fission source convergence for a 3-D SMR core using functional expansion tallies," *Proc. M&C*, 937-947, Portland, Oregon, Aug. 25-29 (2019). @@ -366,7 +371,7 @@ Nuclear Data - Jonathan A. Walsh, Benoit Forget, Kord S. Smith, and Forrest B. Brown, "`Uncertainty in Fast Reactor-Relevant Critical Benchmark Simulations Due to Unresolved Resonance Structure - `_," + `_," *Proc. Int. Conf. Mathematics & Computational Methods Applied to Nuclear Science and Engineering*, Jeju, Korea, Apr. 16-20, 2017. @@ -409,7 +414,7 @@ Parallelism - Paul K. Romano and Andrew R. Siegel, "`Limits on the efficiency of event-based algorithms for Monte Carlo neutron transport - `_," + `_," *Proc. Int. Conf. Mathematics & Computational Methods Applied to Nuclear Science and Engineering*, Jeju, Korea, Apr. 16-20, 2017. diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index 92cb78548..be29d7c0e 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -2,6 +2,8 @@ :mod:`openmc.data` -- Nuclear Data Interface -------------------------------------------- +.. module:: openmc.data + Core Classes ------------ @@ -13,15 +15,15 @@ and product yields. :nosignatures: :template: myclass.rst - openmc.data.IncidentNeutron - openmc.data.Reaction - openmc.data.Product - openmc.data.FissionEnergyRelease - openmc.data.DataLibrary - openmc.data.Decay - openmc.data.FissionProductYields - openmc.data.WindowedMultipole - openmc.data.ProbabilityTables + IncidentNeutron + Reaction + Product + FissionEnergyRelease + DataLibrary + Decay + FissionProductYields + WindowedMultipole + ProbabilityTables The following classes are used for storing atomic data (incident photon cross sections, atomic relaxation): @@ -31,9 +33,9 @@ sections, atomic relaxation): :nosignatures: :template: myclass.rst - openmc.data.IncidentPhoton - openmc.data.PhotonReaction - openmc.data.AtomicRelaxation + IncidentPhoton + PhotonReaction + AtomicRelaxation The following classes are used for storing thermal neutron scattering data: @@ -43,10 +45,10 @@ The following classes are used for storing thermal neutron scattering data: :nosignatures: :template: myclass.rst - openmc.data.ThermalScattering - openmc.data.ThermalScatteringReaction - openmc.data.CoherentElastic - openmc.data.IncoherentElastic + ThermalScattering + ThermalScatteringReaction + CoherentElastic + IncoherentElastic Core Functions @@ -57,12 +59,12 @@ Core Functions :nosignatures: :template: myfunction.rst - openmc.data.atomic_mass - openmc.data.gnd_name - openmc.data.linearize - openmc.data.thin - openmc.data.water_density - openmc.data.zam + atomic_mass + gnd_name + linearize + thin + water_density + zam One-dimensional Functions ------------------------- @@ -72,13 +74,13 @@ One-dimensional Functions :nosignatures: :template: myclass.rst - openmc.data.Function1D - openmc.data.Tabulated1D - openmc.data.Polynomial - openmc.data.Combination - openmc.data.Sum - openmc.data.Regions1D - openmc.data.ResonancesWithBackground + Function1D + Tabulated1D + Polynomial + Combination + Sum + Regions1D + ResonancesWithBackground Angle-Energy Distributions -------------------------- @@ -88,27 +90,27 @@ Angle-Energy Distributions :nosignatures: :template: myclass.rst - openmc.data.AngleEnergy - openmc.data.KalbachMann - openmc.data.CorrelatedAngleEnergy - openmc.data.UncorrelatedAngleEnergy - openmc.data.NBodyPhaseSpace - openmc.data.LaboratoryAngleEnergy - openmc.data.AngleDistribution - openmc.data.EnergyDistribution - openmc.data.ArbitraryTabulated - openmc.data.GeneralEvaporation - openmc.data.MaxwellEnergy - openmc.data.Evaporation - openmc.data.WattEnergy - openmc.data.MadlandNix - openmc.data.DiscretePhoton - openmc.data.LevelInelastic - openmc.data.ContinuousTabular - openmc.data.CoherentElasticAE - openmc.data.IncoherentElasticAE - openmc.data.IncoherentElasticAEDiscrete - openmc.data.IncoherentInelasticAEDiscrete + AngleEnergy + KalbachMann + CorrelatedAngleEnergy + UncorrelatedAngleEnergy + NBodyPhaseSpace + LaboratoryAngleEnergy + AngleDistribution + EnergyDistribution + ArbitraryTabulated + GeneralEvaporation + MaxwellEnergy + Evaporation + WattEnergy + MadlandNix + DiscretePhoton + LevelInelastic + ContinuousTabular + CoherentElasticAE + IncoherentElasticAE + IncoherentElasticAEDiscrete + IncoherentInelasticAEDiscrete Resonance Data -------------- @@ -118,20 +120,20 @@ Resonance Data :nosignatures: :template: myclass.rst - openmc.data.Resonances - openmc.data.ResonanceRange - openmc.data.SingleLevelBreitWigner - openmc.data.MultiLevelBreitWigner - openmc.data.ReichMoore - openmc.data.RMatrixLimited - openmc.data.ResonanceCovariances - openmc.data.ResonanceCovarianceRange - openmc.data.SingleLevelBreitWignerCovariance - openmc.data.MultiLevelBreitWignerCovariance - openmc.data.ReichMooreCovariance - openmc.data.ParticlePair - openmc.data.SpinGroup - openmc.data.Unresolved + Resonances + ResonanceRange + SingleLevelBreitWigner + MultiLevelBreitWigner + ReichMoore + RMatrixLimited + ResonanceCovariances + ResonanceCovarianceRange + SingleLevelBreitWignerCovariance + MultiLevelBreitWignerCovariance + ReichMooreCovariance + ParticlePair + SpinGroup + Unresolved ACE Format ---------- @@ -144,8 +146,8 @@ Classes :nosignatures: :template: myclass.rst - openmc.data.ace.Library - openmc.data.ace.Table + ace.Library + ace.Table Functions +++++++++ @@ -155,7 +157,7 @@ Functions :nosignatures: :template: myfunction.rst - openmc.data.ace.ascii_to_binary + ace.ascii_to_binary ENDF Format ----------- @@ -168,7 +170,7 @@ Classes :nosignatures: :template: myclass.rst - openmc.data.endf.Evaluation + endf.Evaluation Functions +++++++++ @@ -178,13 +180,13 @@ Functions :nosignatures: :template: myfunction.rst - openmc.data.endf.float_endf - openmc.data.endf.get_cont_record - openmc.data.endf.get_evaluations - openmc.data.endf.get_head_record - openmc.data.endf.get_tab1_record - openmc.data.endf.get_tab2_record - openmc.data.endf.get_text_record + endf.float_endf + endf.get_cont_record + endf.get_evaluations + endf.get_head_record + endf.get_tab1_record + endf.get_tab2_record + endf.get_text_record NJOY Interface -------------- @@ -194,7 +196,7 @@ NJOY Interface :nosignatures: :template: myfunction.rst - openmc.data.njoy.run - openmc.data.njoy.make_pendf - openmc.data.njoy.make_ace - openmc.data.njoy.make_ace_thermal + njoy.run + njoy.make_pendf + njoy.make_ace + njoy.make_ace_thermal diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index e18afd920..b9970ffb1 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -1,11 +1,11 @@ .. _pythonapi_deplete: +.. module:: openmc.deplete + ---------------------------------- :mod:`openmc.deplete` -- Depletion ---------------------------------- -.. module:: openmc.deplete - Primary API ----------- @@ -82,10 +82,10 @@ A minimal example for performing depletion would be: Internal Classes and Functions ------------------------------ -When running in parallel using `mpi4py `_, the MPI -intercommunicator used can be changed by modifying the following module -variable. If it is not explicitly modified, it defaults to -``mpi4py.MPI.COMM_WORLD``. +When running in parallel using `mpi4py +`_, the MPI intercommunicator used can +be changed by modifying the following module variable. If it is not explicitly +modified, it defaults to ``mpi4py.MPI.COMM_WORLD``. .. data:: comm @@ -126,8 +126,15 @@ data, such as number densities and reaction rates for each material. Results ResultsList -The following functions are used to solve the depletion equations, with -:func:`cram.CRAM48` being the default. +The following class and functions are used to solve the depletion equations, +with :func:`cram.CRAM48` being the default. + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myintegrator.rst + + cram.IPFCramSolver .. autosummary:: :toctree: generated @@ -161,7 +168,7 @@ Abstract Base Classes A good starting point for extending capabilities in :mod:`openmc.deplete` is to examine the following abstract base classes. Custom classes can -inherit from :class:`abc.TransportOperator` to implement alternative +inherit from :class:`abc.TransportOperator` to implement alternative schemes for collecting reaction rates and other data from a transport code prior to depleting materials @@ -185,8 +192,8 @@ OpenMC simulations back on to the :class:`abc.TransportOperator` abc.ReactionRateHelper abc.TalliedFissionYieldHelper -Custom integrators can be developed by subclassing from the following abstract -base classes: +Custom integrators or depletion solvers can be developed by subclassing from +the following abstract base classes: .. autosummary:: :toctree: generated @@ -195,3 +202,4 @@ base classes: abc.Integrator abc.SIIntegrator + abc.DepSystemSolver diff --git a/docs/source/pythonapi/index.rst b/docs/source/pythonapi/index.rst index 87d0d2a24..7f67f95ce 100644 --- a/docs/source/pythonapi/index.rst +++ b/docs/source/pythonapi/index.rst @@ -27,7 +27,7 @@ there are many substantial benefits to using the Python API, including: For those new to Python, there are many good tutorials available online. We recommend going through the modules from `Codecademy -`_ and/or the `Scipy lectures +`_ and/or the `Scipy lectures `_. The full API documentation serves to provide more information on a given module diff --git a/docs/source/pythonapi/stats.rst b/docs/source/pythonapi/stats.rst index 6ad0e6b03..cacbab31b 100644 --- a/docs/source/pythonapi/stats.rst +++ b/docs/source/pythonapi/stats.rst @@ -46,5 +46,6 @@ Spatial Distributions openmc.stats.Spatial openmc.stats.CartesianIndependent + openmc.stats.SphericalIndependent openmc.stats.Box openmc.stats.Point diff --git a/docs/source/releasenotes/0.11.0.rst b/docs/source/releasenotes/0.11.0.rst index 170630ea7..221d57658 100644 --- a/docs/source/releasenotes/0.11.0.rst +++ b/docs/source/releasenotes/0.11.0.rst @@ -2,11 +2,6 @@ What's New in 0.11.0 ==================== -.. note:: - These release notes are for a future release of OpenMC and are still subject - to change. The new features and bug fixes documented here reflect the - current status of the ``develop`` branch of OpenMC. - .. currentmodule:: openmc ------- @@ -40,6 +35,7 @@ random, non-overlapping configuration of spheres within the region. New Features ------------ +- White boundary conditions can be applied to surfaces - Support for rectilinear meshes through :class:`openmc.RectilinearMesh`. - The :class:`Geometry`, :class:`Materials`, and :class:`Settings` classes now have a ``from_xml`` method that will build an instance from an existing XML @@ -47,7 +43,8 @@ New Features - Predefined energy group structures can be found in :data:`openmc.mgxs.GROUP_STRUCTURES`. - New tally scores: ``H1-production``, ``H2-production``, ``H3-production``, - ``He3-production``, ``He4-production``, ``heating``, and ``damage-energy`` + ``He3-production``, ``He4-production``, ``heating``, ``heating-local``, and + ``damage-energy``. - Switched to cell-based neighor lists (`PR 1140 `_) - Two new probability distributions that can be used for source distributions: @@ -88,6 +85,7 @@ Python API Changes Bug Fixes --------- +- `Rotate azimuthal distributions correctly for source sampling `_ - `Fix reading ASCII ACE tables in Python 3 `_ - `Fix bug for distributed temperatures `_ - `Fix bug for distance to boundary in complex cells `_ @@ -106,6 +104,7 @@ This release contains new contributions from the following people: - `Brody Bassett `_ - `Will Boyd `_ - `Andrew Davis `_ +- `Iurii Drobyshev `_ - `Guillaume Giudicelli `_ - `Brittany Grayson `_ - `Zhuoran Han `_ @@ -123,9 +122,12 @@ This release contains new contributions from the following people: - `Isaac Meyer `_ - `April Novak `_ - `Adam Nelson `_ +- `Gavin Ridley `_ - `Jose Salcedo Perez `_ - `Paul Romano `_ - `Sam Shaner `_ - `Jonathan Shimwell `_ - `Patrick Shriwise `_ - `John Tramm `_ +- `Jiankai Yu `_ +- `Xiaokang Zhang `_ diff --git a/docs/source/releasenotes/0.4.1.rst b/docs/source/releasenotes/0.4.1.rst index 8ec96897e..4bc3bc658 100644 --- a/docs/source/releasenotes/0.4.1.rst +++ b/docs/source/releasenotes/0.4.1.rst @@ -45,9 +45,9 @@ Bug Fixes - `95cfac`_: Fixed error in cell neighbor searches. - `83a803`_: Fixed bug related to probability tables. -.. _b206a8: https://github.com/mit-crpg/openmc/commit/b206a8 -.. _800742: https://github.com/mit-crpg/openmc/commit/800742 -.. _a07c08: https://github.com/mit-crpg/openmc/commit/a07c08 -.. _a75283: https://github.com/mit-crpg/openmc/commit/a75283 -.. _95cfac: https://github.com/mit-crpg/openmc/commit/95cfac -.. _83a803: https://github.com/mit-crpg/openmc/commit/83a803 +.. _b206a8: https://github.com/openmc-dev/openmc/commit/b206a8 +.. _800742: https://github.com/openmc-dev/openmc/commit/800742 +.. _a07c08: https://github.com/openmc-dev/openmc/commit/a07c08 +.. _a75283: https://github.com/openmc-dev/openmc/commit/a75283 +.. _95cfac: https://github.com/openmc-dev/openmc/commit/95cfac +.. _83a803: https://github.com/openmc-dev/openmc/commit/83a803 diff --git a/docs/source/releasenotes/0.4.2.rst b/docs/source/releasenotes/0.4.2.rst index c0d399301..0e28eb6e6 100644 --- a/docs/source/releasenotes/0.4.2.rst +++ b/docs/source/releasenotes/0.4.2.rst @@ -42,13 +42,13 @@ Bug Fixes - d050c7_: Added Bessel's correction to make estimate of variance unbiased. - 2a5b9c_: Fixed regression in plotting. -.. _a27f8f: https://github.com/mit-crpg/openmc/commit/a27f8f -.. _afe121: https://github.com/mit-crpg/openmc/commit/afe121 -.. _e0968e: https://github.com/mit-crpg/openmc/commit/e0968e -.. _298db8: https://github.com/mit-crpg/openmc/commit/298db8 -.. _2f3bbe: https://github.com/mit-crpg/openmc/commit/2f3bbe -.. _671f30: https://github.com/mit-crpg/openmc/commit/671f30 -.. _b2c40e: https://github.com/mit-crpg/openmc/commit/b2c40e -.. _5524fd: https://github.com/mit-crpg/openmc/commit/5524fd -.. _d050c7: https://github.com/mit-crpg/openmc/commit/d050c7 -.. _2a5b9c: https://github.com/mit-crpg/openmc/commit/2a5b9c +.. _a27f8f: https://github.com/openmc-dev/openmc/commit/a27f8f +.. _afe121: https://github.com/openmc-dev/openmc/commit/afe121 +.. _e0968e: https://github.com/openmc-dev/openmc/commit/e0968e +.. _298db8: https://github.com/openmc-dev/openmc/commit/298db8 +.. _2f3bbe: https://github.com/openmc-dev/openmc/commit/2f3bbe +.. _671f30: https://github.com/openmc-dev/openmc/commit/671f30 +.. _b2c40e: https://github.com/openmc-dev/openmc/commit/b2c40e +.. _5524fd: https://github.com/openmc-dev/openmc/commit/5524fd +.. _d050c7: https://github.com/openmc-dev/openmc/commit/d050c7 +.. _2a5b9c: https://github.com/openmc-dev/openmc/commit/2a5b9c diff --git a/docs/source/releasenotes/0.4.3.rst b/docs/source/releasenotes/0.4.3.rst index 7ef12198d..4023cb525 100644 --- a/docs/source/releasenotes/0.4.3.rst +++ b/docs/source/releasenotes/0.4.3.rst @@ -40,12 +40,12 @@ Bug Fixes - 3212f5_: Fixed issue with blank line at beginning of XML files. .. _nelsonag: https://github.com/nelsonag -.. _33f29a: https://github.com/mit-crpg/openmc/commit/33f29a -.. _1c472d: https://github.com/mit-crpg/openmc/commit/1c472d -.. _3c6e80: https://github.com/mit-crpg/openmc/commit/3c6e80 -.. _3bd35b: https://github.com/mit-crpg/openmc/commit/3bd35b -.. _0069d5: https://github.com/mit-crpg/openmc/commit/0069d5 -.. _7af2cf: https://github.com/mit-crpg/openmc/commit/7af2cf -.. _460ef1: https://github.com/mit-crpg/openmc/commit/460ef1 -.. _85a60e: https://github.com/mit-crpg/openmc/commit/85a60e -.. _3212f5: https://github.com/mit-crpg/openmc/commit/3212f5 +.. _33f29a: https://github.com/openmc-dev/openmc/commit/33f29a +.. _1c472d: https://github.com/openmc-dev/openmc/commit/1c472d +.. _3c6e80: https://github.com/openmc-dev/openmc/commit/3c6e80 +.. _3bd35b: https://github.com/openmc-dev/openmc/commit/3bd35b +.. _0069d5: https://github.com/openmc-dev/openmc/commit/0069d5 +.. _7af2cf: https://github.com/openmc-dev/openmc/commit/7af2cf +.. _460ef1: https://github.com/openmc-dev/openmc/commit/460ef1 +.. _85a60e: https://github.com/openmc-dev/openmc/commit/85a60e +.. _3212f5: https://github.com/openmc-dev/openmc/commit/3212f5 diff --git a/docs/source/releasenotes/0.4.4.rst b/docs/source/releasenotes/0.4.4.rst index d700e610d..c5201b30f 100644 --- a/docs/source/releasenotes/0.4.4.rst +++ b/docs/source/releasenotes/0.4.4.rst @@ -36,8 +36,8 @@ Bug Fixes - 7fd617_: Fixed bug with restart runs in parallel. - dc4a8f_: Fixed bug with fixed source restart runs. -.. _4654ee: https://github.com/mit-crpg/openmc/commit/4654ee -.. _7ee461: https://github.com/mit-crpg/openmc/commit/7ee461 -.. _792eb3: https://github.com/mit-crpg/openmc/commit/792eb3 -.. _7fd617: https://github.com/mit-crpg/openmc/commit/7fd617 -.. _dc4a8f: https://github.com/mit-crpg/openmc/commit/dc4a8f +.. _4654ee: https://github.com/openmc-dev/openmc/commit/4654ee +.. _7ee461: https://github.com/openmc-dev/openmc/commit/7ee461 +.. _792eb3: https://github.com/openmc-dev/openmc/commit/792eb3 +.. _7fd617: https://github.com/openmc-dev/openmc/commit/7fd617 +.. _dc4a8f: https://github.com/openmc-dev/openmc/commit/dc4a8f diff --git a/docs/source/releasenotes/0.5.0.rst b/docs/source/releasenotes/0.5.0.rst index 443216e33..aa906a323 100644 --- a/docs/source/releasenotes/0.5.0.rst +++ b/docs/source/releasenotes/0.5.0.rst @@ -39,11 +39,11 @@ Bug Fixes - 6f8d9d_: Set default tally labels. - 6a3a5e_: Fix problem with corner-crossing in lattices. -.. _737b90: https://github.com/mit-crpg/openmc/commit/737b90 -.. _a819b4: https://github.com/mit-crpg/openmc/commit/a819b4 -.. _b11696: https://github.com/mit-crpg/openmc/commit/b11696 -.. _2bd46a: https://github.com/mit-crpg/openmc/commit/2bd46a -.. _7a1f08: https://github.com/mit-crpg/openmc/commit/7a1f08 -.. _c0e3ec: https://github.com/mit-crpg/openmc/commit/c0e3ec -.. _6f8d9d: https://github.com/mit-crpg/openmc/commit/6f8d9d -.. _6a3a5e: https://github.com/mit-crpg/openmc/commit/6a3a5e +.. _737b90: https://github.com/openmc-dev/openmc/commit/737b90 +.. _a819b4: https://github.com/openmc-dev/openmc/commit/a819b4 +.. _b11696: https://github.com/openmc-dev/openmc/commit/b11696 +.. _2bd46a: https://github.com/openmc-dev/openmc/commit/2bd46a +.. _7a1f08: https://github.com/openmc-dev/openmc/commit/7a1f08 +.. _c0e3ec: https://github.com/openmc-dev/openmc/commit/c0e3ec +.. _6f8d9d: https://github.com/openmc-dev/openmc/commit/6f8d9d +.. _6a3a5e: https://github.com/openmc-dev/openmc/commit/6a3a5e diff --git a/docs/source/releasenotes/0.5.1.rst b/docs/source/releasenotes/0.5.1.rst index 6fa584fcf..26a6927c7 100644 --- a/docs/source/releasenotes/0.5.1.rst +++ b/docs/source/releasenotes/0.5.1.rst @@ -36,8 +36,8 @@ Bug Fixes - 63bfd2_: Fix tracklength tallies with cell filter and universes. - 88daf7_: Fix analog tallies with survival biasing. -.. _94103e: https://github.com/mit-crpg/openmc/commit/94103e -.. _e77059: https://github.com/mit-crpg/openmc/commit/e77059 -.. _b0fe88: https://github.com/mit-crpg/openmc/commit/b0fe88 -.. _63bfd2: https://github.com/mit-crpg/openmc/commit/63bfd2 -.. _88daf7: https://github.com/mit-crpg/openmc/commit/88daf7 +.. _94103e: https://github.com/openmc-dev/openmc/commit/94103e +.. _e77059: https://github.com/openmc-dev/openmc/commit/e77059 +.. _b0fe88: https://github.com/openmc-dev/openmc/commit/b0fe88 +.. _63bfd2: https://github.com/openmc-dev/openmc/commit/63bfd2 +.. _88daf7: https://github.com/openmc-dev/openmc/commit/88daf7 diff --git a/docs/source/releasenotes/0.5.2.rst b/docs/source/releasenotes/0.5.2.rst index ba6374ea7..1a5702895 100644 --- a/docs/source/releasenotes/0.5.2.rst +++ b/docs/source/releasenotes/0.5.2.rst @@ -41,15 +41,15 @@ Bug Fixes - ab0793_: Corrected PETSC_NULL references to their correct types. - 182ebd_: Use analog estimator with energyout filter. -.. _7632f3: https://github.com/mit-crpg/openmc/commit/7632f3 -.. _f85ac4: https://github.com/mit-crpg/openmc/commit/f85ac4 -.. _49c36b: https://github.com/mit-crpg/openmc/commit/49c36b -.. _5ccc78: https://github.com/mit-crpg/openmc/commit/5ccc78 -.. _b1f52f: https://github.com/mit-crpg/openmc/commit/b1f52f -.. _eae7e5: https://github.com/mit-crpg/openmc/commit/eae7e5 -.. _10c1cc: https://github.com/mit-crpg/openmc/commit/10c1cc -.. _afdb50: https://github.com/mit-crpg/openmc/commit/afdb50 -.. _a3c593: https://github.com/mit-crpg/openmc/commit/a3c593 -.. _3a66e3: https://github.com/mit-crpg/openmc/commit/3a66e3 -.. _ab0793: https://github.com/mit-crpg/openmc/commit/ab0793 -.. _182ebd: https://github.com/mit-crpg/openmc/commit/182ebd +.. _7632f3: https://github.com/openmc-dev/openmc/commit/7632f3 +.. _f85ac4: https://github.com/openmc-dev/openmc/commit/f85ac4 +.. _49c36b: https://github.com/openmc-dev/openmc/commit/49c36b +.. _5ccc78: https://github.com/openmc-dev/openmc/commit/5ccc78 +.. _b1f52f: https://github.com/openmc-dev/openmc/commit/b1f52f +.. _eae7e5: https://github.com/openmc-dev/openmc/commit/eae7e5 +.. _10c1cc: https://github.com/openmc-dev/openmc/commit/10c1cc +.. _afdb50: https://github.com/openmc-dev/openmc/commit/afdb50 +.. _a3c593: https://github.com/openmc-dev/openmc/commit/a3c593 +.. _3a66e3: https://github.com/openmc-dev/openmc/commit/3a66e3 +.. _ab0793: https://github.com/openmc-dev/openmc/commit/ab0793 +.. _182ebd: https://github.com/openmc-dev/openmc/commit/182ebd diff --git a/docs/source/releasenotes/0.5.3.rst b/docs/source/releasenotes/0.5.3.rst index a7305da71..7b2878d91 100644 --- a/docs/source/releasenotes/0.5.3.rst +++ b/docs/source/releasenotes/0.5.3.rst @@ -40,8 +40,8 @@ Bug Fixes - c18a6e_: Check for valid secondary mode on S(a,b) tables. - 82c456_: Fix bug where last process could have zero particles. -.. _2b1e8a: https://github.com/mit-crpg/openmc/commit/2b1e8a -.. _5853d2: https://github.com/mit-crpg/openmc/commit/5853d2 -.. _e178c7: https://github.com/mit-crpg/openmc/commit/e178c7 -.. _c18a6e: https://github.com/mit-crpg/openmc/commit/c18a6e -.. _82c456: https://github.com/mit-crpg/openmc/commit/82c456 +.. _2b1e8a: https://github.com/openmc-dev/openmc/commit/2b1e8a +.. _5853d2: https://github.com/openmc-dev/openmc/commit/5853d2 +.. _e178c7: https://github.com/openmc-dev/openmc/commit/e178c7 +.. _c18a6e: https://github.com/openmc-dev/openmc/commit/c18a6e +.. _82c456: https://github.com/openmc-dev/openmc/commit/82c456 diff --git a/docs/source/releasenotes/0.5.4.rst b/docs/source/releasenotes/0.5.4.rst index 36d9ec4d5..ed40d29df 100644 --- a/docs/source/releasenotes/0.5.4.rst +++ b/docs/source/releasenotes/0.5.4.rst @@ -39,13 +39,13 @@ Bug Fixes - cf567c_: ENDF/B-VI data checked for compatibility - 6b9461_: Fix p_valid sampling inside of sample_energy -.. _32c03c: https://github.com/mit-crpg/openmc/commit/32c03c -.. _c71ef5: https://github.com/mit-crpg/openmc/commit/c71ef5 -.. _8884fb: https://github.com/mit-crpg/openmc/commit/8884fb -.. _b38af0: https://github.com/mit-crpg/openmc/commit/b38af0 -.. _d28750: https://github.com/mit-crpg/openmc/commit/d28750 -.. _cf567c: https://github.com/mit-crpg/openmc/commit/cf567c -.. _6b9461: https://github.com/mit-crpg/openmc/commit/6b9461 +.. _32c03c: https://github.com/openmc-dev/openmc/commit/32c03c +.. _c71ef5: https://github.com/openmc-dev/openmc/commit/c71ef5 +.. _8884fb: https://github.com/openmc-dev/openmc/commit/8884fb +.. _b38af0: https://github.com/openmc-dev/openmc/commit/b38af0 +.. _d28750: https://github.com/openmc-dev/openmc/commit/d28750 +.. _cf567c: https://github.com/openmc-dev/openmc/commit/cf567c +.. _6b9461: https://github.com/openmc-dev/openmc/commit/6b9461 ------------ Contributors diff --git a/docs/source/releasenotes/0.6.0.rst b/docs/source/releasenotes/0.6.0.rst index 63e234583..8d0d2957b 100644 --- a/docs/source/releasenotes/0.6.0.rst +++ b/docs/source/releasenotes/0.6.0.rst @@ -35,13 +35,13 @@ Bug Fixes - d7a7d0_: Fix bug with specifying xs attribute - 85b3cb_: Fix out-of-bounds error with OpenMP threading -.. _41f7ca: https://github.com/mit-crpg/openmc/commit/41f7ca -.. _038736: https://github.com/mit-crpg/openmc/commit/038736 -.. _46f9e8: https://github.com/mit-crpg/openmc/commit/46f9e8 -.. _d1ca35: https://github.com/mit-crpg/openmc/commit/d1ca35 -.. _0291c0: https://github.com/mit-crpg/openmc/commit/0291c0 -.. _d7a7d0: https://github.com/mit-crpg/openmc/commit/d7a7d0 -.. _85b3cb: https://github.com/mit-crpg/openmc/commit/85b3cb +.. _41f7ca: https://github.com/openmc-dev/openmc/commit/41f7ca +.. _038736: https://github.com/openmc-dev/openmc/commit/038736 +.. _46f9e8: https://github.com/openmc-dev/openmc/commit/46f9e8 +.. _d1ca35: https://github.com/openmc-dev/openmc/commit/d1ca35 +.. _0291c0: https://github.com/openmc-dev/openmc/commit/0291c0 +.. _d7a7d0: https://github.com/openmc-dev/openmc/commit/d7a7d0 +.. _85b3cb: https://github.com/openmc-dev/openmc/commit/85b3cb ------------ Contributors diff --git a/docs/source/releasenotes/0.6.1.rst b/docs/source/releasenotes/0.6.1.rst index a8c59aa51..c0f11ef68 100644 --- a/docs/source/releasenotes/0.6.1.rst +++ b/docs/source/releasenotes/0.6.1.rst @@ -38,16 +38,16 @@ Bug Fixes - 2a95ef_: Prevent segmentation fault on "current" score without mesh filter - 93e482_: Check for negative values in probability tables -.. _03e890: https://github.com/mit-crpg/openmc/commit/03e890 -.. _4439de: https://github.com/mit-crpg/openmc/commit/4439de -.. _5808ed: https://github.com/mit-crpg/openmc/commit/5808ed -.. _2e60c0: https://github.com/mit-crpg/openmc/commit/2e60c0 -.. _3e0870: https://github.com/mit-crpg/openmc/commit/3e0870 -.. _dc4776: https://github.com/mit-crpg/openmc/commit/dc4776 -.. _01178b: https://github.com/mit-crpg/openmc/commit/01178b -.. _62ec43: https://github.com/mit-crpg/openmc/commit/62ec43 -.. _2a95ef: https://github.com/mit-crpg/openmc/commit/2a95ef -.. _93e482: https://github.com/mit-crpg/openmc/commit/93e482 +.. _03e890: https://github.com/openmc-dev/openmc/commit/03e890 +.. _4439de: https://github.com/openmc-dev/openmc/commit/4439de +.. _5808ed: https://github.com/openmc-dev/openmc/commit/5808ed +.. _2e60c0: https://github.com/openmc-dev/openmc/commit/2e60c0 +.. _3e0870: https://github.com/openmc-dev/openmc/commit/3e0870 +.. _dc4776: https://github.com/openmc-dev/openmc/commit/dc4776 +.. _01178b: https://github.com/openmc-dev/openmc/commit/01178b +.. _62ec43: https://github.com/openmc-dev/openmc/commit/62ec43 +.. _2a95ef: https://github.com/openmc-dev/openmc/commit/2a95ef +.. _93e482: https://github.com/openmc-dev/openmc/commit/93e482 ------------ Contributors diff --git a/docs/source/releasenotes/0.6.2.rst b/docs/source/releasenotes/0.6.2.rst index 6fe6c28da..9a5400cac 100644 --- a/docs/source/releasenotes/0.6.2.rst +++ b/docs/source/releasenotes/0.6.2.rst @@ -33,10 +33,10 @@ Bug Fixes - e6abb9_: Fix segfault when tallying in a void material - 291b45_: Handle metastable nuclides in NNDC data and multiplicities in MT=5 data -.. _26fb93: https://github.com/mit-crpg/openmc/commit/26fb93 -.. _2f07c0: https://github.com/mit-crpg/openmc/commit/2f07c0 -.. _e6abb9: https://github.com/mit-crpg/openmc/commit/e6abb9 -.. _291b45: https://github.com/mit-crpg/openmc/commit/291b45 +.. _26fb93: https://github.com/openmc-dev/openmc/commit/26fb93 +.. _2f07c0: https://github.com/openmc-dev/openmc/commit/2f07c0 +.. _e6abb9: https://github.com/openmc-dev/openmc/commit/e6abb9 +.. _291b45: https://github.com/openmc-dev/openmc/commit/291b45 ------------ Contributors diff --git a/docs/source/releasenotes/0.7.0.rst b/docs/source/releasenotes/0.7.0.rst index 8f86631ea..2a3063a92 100644 --- a/docs/source/releasenotes/0.7.0.rst +++ b/docs/source/releasenotes/0.7.0.rst @@ -40,11 +40,11 @@ Bug Fixes - 6121d9_: Fix bugs related to particle track files - 2f0e89_: Fixes for nuclide specification in tallies -.. _b5f712: https://github.com/mit-crpg/openmc/commit/b5f712 -.. _e6675b: https://github.com/mit-crpg/openmc/commit/e6675b -.. _04e2c1: https://github.com/mit-crpg/openmc/commit/04e2c1 -.. _6121d9: https://github.com/mit-crpg/openmc/commit/6121d9 -.. _2f0e89: https://github.com/mit-crpg/openmc/commit/2f0e89 +.. _b5f712: https://github.com/openmc-dev/openmc/commit/b5f712 +.. _e6675b: https://github.com/openmc-dev/openmc/commit/e6675b +.. _04e2c1: https://github.com/openmc-dev/openmc/commit/04e2c1 +.. _6121d9: https://github.com/openmc-dev/openmc/commit/6121d9 +.. _2f0e89: https://github.com/openmc-dev/openmc/commit/2f0e89 ------------ Contributors diff --git a/docs/source/releasenotes/0.7.1.rst b/docs/source/releasenotes/0.7.1.rst index 5ee2c9f69..01af74239 100644 --- a/docs/source/releasenotes/0.7.1.rst +++ b/docs/source/releasenotes/0.7.1.rst @@ -62,15 +62,15 @@ Bug Fixes - 441fd4_: Fix bug in kappa-fission score - 7e5974_: Allow fixed source simulations from Python API -.. _299322: https://github.com/mit-crpg/openmc/commit/299322 -.. _d74840: https://github.com/mit-crpg/openmc/commit/d74840 -.. _c29a81: https://github.com/mit-crpg/openmc/commit/c29a81 -.. _3edc23: https://github.com/mit-crpg/openmc/commit/3edc23 -.. _629e3b: https://github.com/mit-crpg/openmc/commit/629e3b -.. _5dbe8b: https://github.com/mit-crpg/openmc/commit/5dbe8b -.. _ff66f4: https://github.com/mit-crpg/openmc/commit/ff66f4 -.. _441fd4: https://github.com/mit-crpg/openmc/commit/441fd4 -.. _7e5974: https://github.com/mit-crpg/openmc/commit/7e5974 +.. _299322: https://github.com/openmc-dev/openmc/commit/299322 +.. _d74840: https://github.com/openmc-dev/openmc/commit/d74840 +.. _c29a81: https://github.com/openmc-dev/openmc/commit/c29a81 +.. _3edc23: https://github.com/openmc-dev/openmc/commit/3edc23 +.. _629e3b: https://github.com/openmc-dev/openmc/commit/629e3b +.. _5dbe8b: https://github.com/openmc-dev/openmc/commit/5dbe8b +.. _ff66f4: https://github.com/openmc-dev/openmc/commit/ff66f4 +.. _441fd4: https://github.com/openmc-dev/openmc/commit/441fd4 +.. _7e5974: https://github.com/openmc-dev/openmc/commit/7e5974 ------------ Contributors diff --git a/docs/source/releasenotes/0.8.0.rst b/docs/source/releasenotes/0.8.0.rst index bd8a89a64..d4f5a878b 100644 --- a/docs/source/releasenotes/0.8.0.rst +++ b/docs/source/releasenotes/0.8.0.rst @@ -65,17 +65,17 @@ Bug Fixes - 8467ae_: Better threshold for allowable lost particles - 493c6f_: Fix type of return argument for h5pget_driver_f -.. _70daa7: https://github.com/mit-crpg/openmc/commit/70daa7 -.. _40b05f: https://github.com/mit-crpg/openmc/commit/40b05f -.. _9586ed: https://github.com/mit-crpg/openmc/commit/9586ed -.. _a855e8: https://github.com/mit-crpg/openmc/commit/a855e8 -.. _7294a1: https://github.com/mit-crpg/openmc/commit/7294a1 -.. _12f246: https://github.com/mit-crpg/openmc/commit/12f246 -.. _0227f4: https://github.com/mit-crpg/openmc/commit/0227f4 -.. _51deaa: https://github.com/mit-crpg/openmc/commit/51deaa -.. _fed74b: https://github.com/mit-crpg/openmc/commit/fed74b -.. _8467ae: https://github.com/mit-crpg/openmc/commit/8467ae -.. _493c6f: https://github.com/mit-crpg/openmc/commit/493c6f +.. _70daa7: https://github.com/openmc-dev/openmc/commit/70daa7 +.. _40b05f: https://github.com/openmc-dev/openmc/commit/40b05f +.. _9586ed: https://github.com/openmc-dev/openmc/commit/9586ed +.. _a855e8: https://github.com/openmc-dev/openmc/commit/a855e8 +.. _7294a1: https://github.com/openmc-dev/openmc/commit/7294a1 +.. _12f246: https://github.com/openmc-dev/openmc/commit/12f246 +.. _0227f4: https://github.com/openmc-dev/openmc/commit/0227f4 +.. _51deaa: https://github.com/openmc-dev/openmc/commit/51deaa +.. _fed74b: https://github.com/openmc-dev/openmc/commit/fed74b +.. _8467ae: https://github.com/openmc-dev/openmc/commit/8467ae +.. _493c6f: https://github.com/openmc-dev/openmc/commit/493c6f ------------ Contributors diff --git a/docs/source/releasenotes/0.9.0.rst b/docs/source/releasenotes/0.9.0.rst index 478c57096..778a7d135 100644 --- a/docs/source/releasenotes/0.9.0.rst +++ b/docs/source/releasenotes/0.9.0.rst @@ -111,25 +111,25 @@ Bug Fixes - 489540_: Check for void materials in tracklength tallies - f0214f_: Fixes/improvements to the ARES algorithm -.. _c5df6c: https://github.com/mit-crpg/openmc/commit/c5df6c -.. _1cfa39: https://github.com/mit-crpg/openmc/commit/1cfa39 -.. _335359: https://github.com/mit-crpg/openmc/commit/335359 -.. _17c678: https://github.com/mit-crpg/openmc/commit/17c678 -.. _23ec0b: https://github.com/mit-crpg/openmc/commit/23ec0b -.. _7eefb7: https://github.com/mit-crpg/openmc/commit/7eefb7 -.. _7880d4: https://github.com/mit-crpg/openmc/commit/7880d4 -.. _ad2d9f: https://github.com/mit-crpg/openmc/commit/ad2d9f -.. _59fdca: https://github.com/mit-crpg/openmc/commit/59fdca -.. _9eff5b: https://github.com/mit-crpg/openmc/commit/9eff5b -.. _7848a9: https://github.com/mit-crpg/openmc/commit/7848a9 -.. _f139ce: https://github.com/mit-crpg/openmc/commit/f139ce -.. _b8ddfa: https://github.com/mit-crpg/openmc/commit/b8ddfa -.. _ec3cfb: https://github.com/mit-crpg/openmc/commit/ec3cfb -.. _5e9b06: https://github.com/mit-crpg/openmc/commit/5e9b06 -.. _c39990: https://github.com/mit-crpg/openmc/commit/c39990 -.. _c6b67e: https://github.com/mit-crpg/openmc/commit/c6b67e -.. _489540: https://github.com/mit-crpg/openmc/commit/489540 -.. _f0214f: https://github.com/mit-crpg/openmc/commit/f0214f +.. _c5df6c: https://github.com/openmc-dev/openmc/commit/c5df6c +.. _1cfa39: https://github.com/openmc-dev/openmc/commit/1cfa39 +.. _335359: https://github.com/openmc-dev/openmc/commit/335359 +.. _17c678: https://github.com/openmc-dev/openmc/commit/17c678 +.. _23ec0b: https://github.com/openmc-dev/openmc/commit/23ec0b +.. _7eefb7: https://github.com/openmc-dev/openmc/commit/7eefb7 +.. _7880d4: https://github.com/openmc-dev/openmc/commit/7880d4 +.. _ad2d9f: https://github.com/openmc-dev/openmc/commit/ad2d9f +.. _59fdca: https://github.com/openmc-dev/openmc/commit/59fdca +.. _9eff5b: https://github.com/openmc-dev/openmc/commit/9eff5b +.. _7848a9: https://github.com/openmc-dev/openmc/commit/7848a9 +.. _f139ce: https://github.com/openmc-dev/openmc/commit/f139ce +.. _b8ddfa: https://github.com/openmc-dev/openmc/commit/b8ddfa +.. _ec3cfb: https://github.com/openmc-dev/openmc/commit/ec3cfb +.. _5e9b06: https://github.com/openmc-dev/openmc/commit/5e9b06 +.. _c39990: https://github.com/openmc-dev/openmc/commit/c39990 +.. _c6b67e: https://github.com/openmc-dev/openmc/commit/c6b67e +.. _489540: https://github.com/openmc-dev/openmc/commit/489540 +.. _f0214f: https://github.com/openmc-dev/openmc/commit/f0214f ------------ Contributors diff --git a/docs/source/usersguide/beginners.rst b/docs/source/usersguide/beginners.rst index 38e016d1e..85d50a2d4 100644 --- a/docs/source/usersguide/beginners.rst +++ b/docs/source/usersguide/beginners.rst @@ -141,13 +141,13 @@ and `Volume II`_. You may also find it helpful to review the following terms: - `Effective multiplication factor`_ - `Flux`_ -.. _nuclear reactor: http://en.wikipedia.org/wiki/Nuclear_reactor -.. _Monte Carlo: http://en.wikipedia.org/wiki/Monte_Carlo_method -.. _fission: http://en.wikipedia.org/wiki/Nuclear_fission -.. _deterministic: http://en.wikipedia.org/wiki/Deterministic_algorithm -.. _neutron transport: http://en.wikipedia.org/wiki/Neutron_transport -.. _discretization: http://en.wikipedia.org/wiki/Discretization -.. _constructive solid geometry: http://en.wikipedia.org/wiki/Constructive_solid_geometry +.. _nuclear reactor: https://en.wikipedia.org/wiki/Nuclear_reactor +.. _Monte Carlo: https://en.wikipedia.org/wiki/Monte_Carlo_method +.. _fission: https://en.wikipedia.org/wiki/Nuclear_fission +.. _deterministic: https://en.wikipedia.org/wiki/Deterministic_algorithm +.. _neutron transport: https://en.wikipedia.org/wiki/Neutron_transport +.. _discretization: https://en.wikipedia.org/wiki/Discretization +.. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry .. _git: http://git-scm.com/ .. _git tutorials: http://git-scm.com/documentation .. _Reactor Concepts Manual: http://www.tayloredge.com/periodic/trivia/ReactorConcepts.pdf @@ -156,6 +156,6 @@ and `Volume II`_. You may also find it helpful to review the following terms: .. _OpenMC source code: https://github.com/openmc-dev/openmc .. _GitHub: https://github.com/ .. _bug reports: https://github.com/openmc-dev/openmc/issues -.. _Neutron cross section: http://en.wikipedia.org/wiki/Neutron_cross_section +.. _Neutron cross section: https://en.wikipedia.org/wiki/Neutron_cross_section .. _Effective multiplication factor: https://en.wikipedia.org/wiki/Nuclear_chain_reaction#Effective_neutron_multiplication_factor -.. _Flux: http://en.wikipedia.org/wiki/Neutron_flux +.. _Flux: https://en.wikipedia.org/wiki/Neutron_flux diff --git a/docs/source/usersguide/cross_sections.rst b/docs/source/usersguide/cross_sections.rst index 636b44db4..144b1c152 100644 --- a/docs/source/usersguide/cross_sections.rst +++ b/docs/source/usersguide/cross_sections.rst @@ -16,10 +16,10 @@ recommended to use one of the pregenerated libraries. Alternatively, if you have ACE format data that was produced with NJOY_, such as that distributed with MCNP_ or Serpent_, it can be converted to the HDF5 format using the :ref:`using the Python API `. Several sources provide openly available -ACE data including the `ENDF/B`_, JEFF_, and TENDL_ -libraries. In addition to tabulated cross sections in the HDF5 files, OpenMC -relies on :ref:`windowed multipole ` data to perform -on-the-fly Doppler broadening. +ACE data including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the +`LANL Nuclear Data Team `_. In addition to +tabulated cross sections in the HDF5 files, OpenMC relies on :ref:`windowed +multipole ` data to perform on-the-fly Doppler broadening. In multi-group mode, OpenMC utilizes an HDF5-based library format which can be used to describe nuclide- or material-specific quantities. @@ -30,11 +30,11 @@ Environment Variables When :ref:`scripts_openmc` is run, it will look for several environment variables that indicate where cross sections can be found. While the location of -cross sections can also be indicated through the :class:`openmc.Materials` class -(or in the :ref:`materials.xml ` file), if you always use the same -set of cross section data, it is often easier to just set an environment -variable that will be picked up by default every time OpenMC is run. The -following environment variables are used: +cross sections can also be indicated through the +:attr:`openmc.Materials.cross_setion` attribute (or in the :ref:`materials.xml +` file), if you always use the same set of cross section data, it +is often easier to just set an environment variable that will be picked up by +default every time OpenMC is run. The following environment variables are used: :envvar:`OPENMC_CROSS_SECTIONS` Indicates the path to the :ref:`cross_sections.xml ` diff --git a/docs/source/usersguide/depletion.rst b/docs/source/usersguide/depletion.rst index 9e2693098..4a4c7b1f8 100644 --- a/docs/source/usersguide/depletion.rst +++ b/docs/source/usersguide/depletion.rst @@ -127,7 +127,9 @@ of the same material as a unique material definition with:: For our example problem, this would deplete fuel on the outer region of the problem with different reaction rates than those in the center. Materials will be depleted corresponding to their local neutron spectra, and have unique compositions at each -transport step. +transport step. The volume of the original ``fuel_3`` material must represent +the volume of **all** the ``fuel_3`` in the problem. When creating the unique +materials, this volume will be equally distributed across all material instances. .. note:: diff --git a/docs/source/usersguide/geometry.rst b/docs/source/usersguide/geometry.rst index 51daf7b5d..dc7dd978e 100644 --- a/docs/source/usersguide/geometry.rst +++ b/docs/source/usersguide/geometry.rst @@ -121,11 +121,11 @@ For many regions, a bounding-box can be determined automatically:: While a bounding box can be determined for regions involving half-spaces of spheres, cylinders, and axis-aligned planes, it generally cannot be determined if the region involves cones, non-axis-aligned planes, or other exotic -second-order surfaces. For example, the :func:`openmc.get_hexagonal_prism` +second-order surfaces. For example, the :func:`openmc.model.hexagonal_prism` function returns the interior region of a hexagonal prism; because it is bounded by a :class:`openmc.Plane`, trying to get its bounding box won't work:: - >>> hex = openmc.get_hexagonal_prism() + >>> hex = openmc.model.hexagonal_prism() >>> hex.bounding_box (array([-0.8660254, -inf, -inf]), array([ 0.8660254, inf, inf])) @@ -374,7 +374,7 @@ code would work:: hexlat.universes = [outer_ring, middle_ring, inner_ring] If you need to create a hexagonal boundary (composed of six planar surfaces) for -a hexagonal lattice, :func:`openmc.get_hexagonal_prism` can be used. +a hexagonal lattice, :func:`openmc.model.hexagonal_prism` can be used. .. _usersguide_geom_export: @@ -396,8 +396,15 @@ if needed, lattices, the last step is to create an instance of geom.root_universe = root_univ geom.export_to_xml() -.. _constructive solid geometry: http://en.wikipedia.org/wiki/Constructive_solid_geometry -.. _quadratic surfaces: http://en.wikipedia.org/wiki/Quadric +Note that it's not strictly required to manually create a root universe. You can +also pass a list of cells to the :class:`openmc.Geometry` constructor and it +will handle creating the unverse:: + + geom = openmc.Geometry([cell1, cell2, cell3]) + geom.export_to_xml() + +.. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry +.. _quadratic surfaces: https://en.wikipedia.org/wiki/Quadric -------------------------- Using CAD-based Geometry diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 96b4f5024..8ca7e0b35 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -17,7 +17,8 @@ system for installing multiple versions of software packages and their dependencies and switching easily between them. `conda-forge `_ is a community-led conda channel of installable packages. For instructions on installing conda, please consult their -`documentation `_. +`documentation +`_. Once you have `conda` installed on your system, add the `conda-forge` channel to your configuration with: @@ -444,7 +445,7 @@ as for OpenMC. .. admonition:: Optional :class: note - `mpi4py `_ + `mpi4py `_ mpi4py provides Python bindings to MPI for running distributed-memory parallel runs. This package is needed if you plan on running depletion simulations in parallel using MPI. @@ -483,9 +484,9 @@ Make sure to replace the last string on the second line with the path to the schemas.xml file in your own OpenMC source directory. .. _GNU Emacs: http://www.gnu.org/software/emacs/ -.. _validation: http://en.wikipedia.org/wiki/XML_validation +.. _validation: https://en.wikipedia.org/wiki/XML_validation .. _RELAX NG: http://relaxng.org/ .. _NNDC: http://www.nndc.bnl.gov/endf/b7.1/acefiles.html .. _ctest: http://www.cmake.org/cmake/help/v2.8.12/ctest.html -.. _Conda: https://conda.io/docs/ +.. _Conda: https://docs.conda.io/en/latest/ .. _pip: https://pip.pypa.io/en/stable/ diff --git a/docs/source/usersguide/plots.rst b/docs/source/usersguide/plots.rst index f21d2c8c5..a10f370d6 100644 --- a/docs/source/usersguide/plots.rst +++ b/docs/source/usersguide/plots.rst @@ -66,7 +66,7 @@ particular cells/materials should be given colors of your choosing:: } Note that colors can be given as RGB tuples or by a string indicating a valid -`SVG color `_. +`SVG color `_. When you're done creating your :class:`openmc.Plot` instances, you need to then assign them to a :class:`openmc.Plots` collection and export it to XML:: diff --git a/docs/source/usersguide/settings.rst b/docs/source/usersguide/settings.rst index 496d18f7f..1254c4ed5 100644 --- a/docs/source/usersguide/settings.rst +++ b/docs/source/usersguide/settings.rst @@ -221,26 +221,11 @@ selected:: settings.electron_treatment = 'led' -.. warning:: - Currently, collision stopping powers used in the TTB approximation come from - the `NIST ESTAR database`_, which provides data for each element calculated - using by default the material density at standard temperature and pressure. - In OpenMC, stopping powers for compounds are calculated from this elemental - data using Bragg's additivity rule. However, this is not a good - approximation --- the collision stopping power is a function of certain - quantities, such as the mean excitation energy and particularly the density - effect correction, that depend on material properties. Data for constituent - elements in a compound cannot simply be summed together, but rather these - quantities should be calculated for the material. This treatment will be - especially poor when the density of a material is different from the - densities used in the NIST data. - .. note:: Some features related to photon transport are not currently implemented, including: * Tallying photon energy deposition. - * Properly accounting for energy deposition in coupled n-p calculations. * Generating a photon source from a neutron calculation that can be used for a later fixed source photon calculation. * Photoneutron reactions. diff --git a/docs/source/usersguide/volume.rst b/docs/source/usersguide/volume.rst index e4bdbf715..c040eb2d7 100644 --- a/docs/source/usersguide/volume.rst +++ b/docs/source/usersguide/volume.rst @@ -37,6 +37,16 @@ arguments are not necessary. For example, Of course, the volumes that you *need* this capability for are often the ones with complex definitions. +A threshold can be applied for the calculation's variance, standard deviation, +or relative error of volume estimates using :meth:`openmc.VolumeCalculation.set_trigger`:: + + vol_calc.set_trigger(1e-05, 'std_dev') + +If a threshold is provided, calculations will be performed iteratively using the +number of samples specified on the calculation until all volume uncertainties are below +the threshold value. If no threshold is provided, the calculation will run the number of +samples specified once and return the result. + Once you have one or more :class:`openmc.VolumeCalculation` objects created, you can then assign then to :attr:`Settings.volume_calculations`:: diff --git a/examples/jupyter/chain_simple.xml b/examples/jupyter/chain_simple.xml new file mode 120000 index 000000000..96f6fa881 --- /dev/null +++ b/examples/jupyter/chain_simple.xml @@ -0,0 +1 @@ +../../tests/chain_simple.xml \ No newline at end of file diff --git a/examples/jupyter/mg-mode-part-iii.ipynb b/examples/jupyter/mg-mode-part-iii.ipynb index 2cf998188..e953d64d3 100644 --- a/examples/jupyter/mg-mode-part-iii.ipynb +++ b/examples/jupyter/mg-mode-part-iii.ipynb @@ -30,7 +30,6 @@ "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "\n", "import openmc\n", "\n", "%matplotlib inline" @@ -40,7 +39,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We will be running a rodded 8x8 assembly with Gadolinia fuel pins. Let's create all the elemental data we would need for this case." + "We will be running a rodded 8x8 assembly with Gadolinia fuel pins. Let's start by creating the materials that we will use later.\n", + "\n", + "Material Definition Simplifications:\n", + "\n", + "- This model will be run at room temperature so the NNDC ENDF-B/VII.1 data set can be used but the water density will be representative of a module with around 20% voiding. This water density will be non-physically used in all regions of the problem.\n", + "- Steel is composed of more than just iron, but we will only treat it as such here." ] }, { @@ -48,67 +52,43 @@ "execution_count": 2, "metadata": {}, "outputs": [], - "source": [ - "# Instantiate some elements\n", - "elements = {}\n", - "for elem in ['H', 'O', 'U', 'Zr', 'Gd', 'B', 'C', 'Fe']:\n", - " elements[elem] = openmc.Element(elem)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the elements we defined, we will now create the materials we will use later.\n", - "\n", - "Material Definition Simplifications:\n", - "\n", - "- This model will be run at room temperature so the NNDC ENDF-B/VII.1 data set can be used but the water density will be representative of a module with around 20% voiding. This water density will be non-physically used in all regions of the problem.\n", - "- Steel is composed of more than just iron, but we will only treat it as such here.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], "source": [ "materials = {}\n", "\n", "# Fuel\n", "materials['Fuel'] = openmc.Material(name='Fuel')\n", "materials['Fuel'].set_density('g/cm3', 10.32)\n", - "materials['Fuel'].add_element(elements['O'], 2)\n", - "materials['Fuel'].add_element(elements['U'], 1, enrichment=3.)\n", + "materials['Fuel'].add_element('O', 2)\n", + "materials['Fuel'].add_element('U', 1, enrichment=3.)\n", "\n", "# Gadolinia bearing fuel\n", "materials['Gad'] = openmc.Material(name='Gad')\n", "materials['Gad'].set_density('g/cm3', 10.23)\n", - "materials['Gad'].add_element(elements['O'], 2)\n", - "materials['Gad'].add_element(elements['U'], 1, enrichment=3.)\n", - "materials['Gad'].add_element(elements['Gd'], .02)\n", + "materials['Gad'].add_element('O', 2)\n", + "materials['Gad'].add_element('U', 1, enrichment=3.)\n", + "materials['Gad'].add_element('Gd', .02)\n", "\n", "# Zircaloy\n", "materials['Zirc2'] = openmc.Material(name='Zirc2')\n", "materials['Zirc2'].set_density('g/cm3', 6.55)\n", - "materials['Zirc2'].add_element(elements['Zr'], 1)\n", + "materials['Zirc2'].add_element('Zr', 1)\n", "\n", "# Boiling Water\n", "materials['Water'] = openmc.Material(name='Water')\n", "materials['Water'].set_density('g/cm3', 0.6)\n", - "materials['Water'].add_element(elements['H'], 2)\n", - "materials['Water'].add_element(elements['O'], 1)\n", + "materials['Water'].add_element('H', 2)\n", + "materials['Water'].add_element('O', 1)\n", "\n", "# Boron Carbide for the Control Rods\n", "materials['B4C'] = openmc.Material(name='B4C')\n", "materials['B4C'].set_density('g/cm3', 0.7 * 2.52)\n", - "materials['B4C'].add_element(elements['B'], 4)\n", - "materials['B4C'].add_element(elements['C'], 1)\n", + "materials['B4C'].add_element('B', 4)\n", + "materials['B4C'].add_element('C', 1)\n", "\n", "# Steel \n", "materials['Steel'] = openmc.Material(name='Steel')\n", "materials['Steel'].set_density('g/cm3', 7.75)\n", - "materials['Steel'].add_element(elements['Fe'], 1)" + "materials['Steel'].add_element('Fe', 1)" ] }, { @@ -120,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -147,7 +127,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -164,27 +144,27 @@ "surfaces = {}\n", "\n", "# Create boundary planes to surround the geometry\n", - "surfaces['Global x-'] = openmc.XPlane(x0=0., boundary_type='reflective')\n", - "surfaces['Global x+'] = openmc.XPlane(x0=length, boundary_type='reflective')\n", - "surfaces['Global y-'] = openmc.YPlane(y0=0., boundary_type='reflective')\n", - "surfaces['Global y+'] = openmc.YPlane(y0=length, boundary_type='reflective')\n", + "surfaces['Global x-'] = openmc.XPlane(0., boundary_type='reflective')\n", + "surfaces['Global x+'] = openmc.XPlane(length, boundary_type='reflective')\n", + "surfaces['Global y-'] = openmc.YPlane(0., boundary_type='reflective')\n", + "surfaces['Global y+'] = openmc.YPlane(length, boundary_type='reflective')\n", "\n", "# Create cylinders for the fuel and clad\n", - "surfaces['Fuel Radius'] = openmc.ZCylinder(R=fuel_rad)\n", - "surfaces['Clad Radius'] = openmc.ZCylinder(R=clad_rad)\n", + "surfaces['Fuel Radius'] = openmc.ZCylinder(r=fuel_rad)\n", + "surfaces['Clad Radius'] = openmc.ZCylinder(r=clad_rad)\n", "\n", - "surfaces['Assembly x-'] = openmc.XPlane(x0=pin_pitch)\n", - "surfaces['Assembly x+'] = openmc.XPlane(x0=length - pin_pitch)\n", - "surfaces['Assembly y-'] = openmc.YPlane(y0=pin_pitch)\n", - "surfaces['Assembly y+'] = openmc.YPlane(y0=length - pin_pitch)\n", + "surfaces['Assembly x-'] = openmc.XPlane(pin_pitch)\n", + "surfaces['Assembly x+'] = openmc.XPlane(length - pin_pitch)\n", + "surfaces['Assembly y-'] = openmc.YPlane(pin_pitch)\n", + "surfaces['Assembly y+'] = openmc.YPlane(length - pin_pitch)\n", "\n", "# Set surfaces for the control blades\n", - "surfaces['Top Blade y-'] = openmc.YPlane(y0=length - rod_thick)\n", - "surfaces['Top Blade x-'] = openmc.XPlane(x0=pin_pitch)\n", - "surfaces['Top Blade x+'] = openmc.XPlane(x0=rod_span)\n", - "surfaces['Left Blade x+'] = openmc.XPlane(x0=rod_thick)\n", - "surfaces['Left Blade y-'] = openmc.YPlane(y0=length - rod_span)\n", - "surfaces['Left Blade y+'] = openmc.YPlane(y0=9. * pin_pitch)" + "surfaces['Top Blade y-'] = openmc.YPlane(length - rod_thick)\n", + "surfaces['Top Blade x-'] = openmc.XPlane(pin_pitch)\n", + "surfaces['Top Blade x+'] = openmc.XPlane(rod_span)\n", + "surfaces['Left Blade x+'] = openmc.XPlane(rod_thick)\n", + "surfaces['Left Blade y-'] = openmc.YPlane(length - rod_span)\n", + "surfaces['Left Blade y+'] = openmc.YPlane(9. * pin_pitch)" ] }, { @@ -196,7 +176,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -240,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -280,7 +260,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -319,7 +299,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -353,7 +333,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -375,27 +355,29 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 11, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -422,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -444,7 +426,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -481,7 +463,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -499,7 +481,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -520,7 +502,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -540,7 +522,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -572,7 +554,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -602,7 +584,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -632,7 +614,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -652,14 +634,14 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mgxs/mgxs.py:4116: UserWarning: The legendre order will be ignored since the scatter format is set to histogram\n", + "/home/romano/openmc/openmc/mgxs/mgxs.py:4144: UserWarning: The legendre order will be ignored since the scatter format is set to histogram\n", " warnings.warn(msg)\n" ] } @@ -679,7 +661,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -698,26 +680,26 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=1.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=1.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=11.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=11.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=21.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=21.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=22.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=22.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=12.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=12.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=18.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=18.\n", " warn(msg, IDWarning)\n" ] } @@ -749,57 +731,58 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%%%%%%\n", + " ##################### %%%%%%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%\n", + " ################# %%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%\n", + " ############ %%%%%%%%%%%%%%%\n", + " ######## %%%%%%%%%%%%%%\n", + " %%%%%%%%%%%\n", "\n", " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", + " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-24 19:15:17\n", - " OpenMP Threads | 8\n", + " Version | 0.11.0-dev\n", + " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", + " Date/Time | 2019-10-04 10:54:35\n", + " OpenMP Threads | 4\n", "\n", + " Minimum neutron data temperature: 294.000000 K\n", + " Maximum neutron data temperature: 294.000000 K\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", "\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.83880 +/- 0.00101\n", - " k-effective (Track-length) = 0.83917 +/- 0.00118\n", - " k-effective (Absorption) = 0.83859 +/- 0.00104\n", - " Combined k-effective = 0.83879 +/- 0.00086\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", + " k-effective (Collision) = 0.83866 +/- 0.00102\n", + " k-effective (Track-length) = 0.83799 +/- 0.00118\n", + " k-effective (Absorption) = 0.83968 +/- 0.00103\n", + " Combined k-effective = 0.83900 +/- 0.00085\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] } @@ -818,7 +801,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -841,7 +824,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -858,7 +841,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -875,7 +858,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -912,14 +895,14 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] } @@ -947,7 +930,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 29, "metadata": {}, "outputs": [], "source": [ @@ -967,7 +950,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -990,27 +973,29 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 32, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1031,45 +1016,44 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%%%%%%\n", + " ##################### %%%%%%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%\n", + " ################# %%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%\n", + " ############ %%%%%%%%%%%%%%%\n", + " ######## %%%%%%%%%%%%%%\n", + " %%%%%%%%%%%\n", "\n", " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", + " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-24 19:16:03\n", - " OpenMP Threads | 8\n", + " Version | 0.11.0-dev\n", + " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", + " Date/Time | 2019-10-04 10:56:58\n", + " OpenMP Threads | 4\n", "\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", @@ -1077,11 +1061,11 @@ "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.82313 +/- 0.00100\n", - " k-effective (Track-length) = 0.82363 +/- 0.00102\n", - " k-effective (Absorption) = 0.82532 +/- 0.00076\n", - " Combined k-effective = 0.82484 +/- 0.00067\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", + " k-effective (Collision) = 0.82471 +/- 0.00104\n", + " k-effective (Track-length) = 0.82466 +/- 0.00103\n", + " k-effective (Absorption) = 0.82482 +/- 0.00075\n", + " Combined k-effective = 0.82477 +/- 0.00068\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] } @@ -1100,7 +1084,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 33, "metadata": {}, "outputs": [], "source": [ @@ -1125,14 +1109,14 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] } @@ -1153,45 +1137,44 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%%%%%%\n", + " ##################### %%%%%%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%\n", + " ################# %%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%\n", + " ############ %%%%%%%%%%%%%%%\n", + " ######## %%%%%%%%%%%%%%\n", + " %%%%%%%%%%%\n", "\n", " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", + " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-24 19:16:12\n", - " OpenMP Threads | 8\n", + " Version | 0.11.0-dev\n", + " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", + " Date/Time | 2019-10-04 10:57:24\n", + " OpenMP Threads | 4\n", "\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", @@ -1199,11 +1182,11 @@ "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.83745 +/- 0.00108\n", - " k-effective (Track-length) = 0.83712 +/- 0.00108\n", - " k-effective (Absorption) = 0.83694 +/- 0.00078\n", - " Combined k-effective = 0.83695 +/- 0.00070\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", + " k-effective (Collision) = 0.83564 +/- 0.00103\n", + " k-effective (Track-length) = 0.83572 +/- 0.00104\n", + " k-effective (Absorption) = 0.83478 +/- 0.00073\n", + " Combined k-effective = 0.83504 +/- 0.00066\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] } @@ -1225,7 +1208,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ @@ -1248,7 +1231,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ @@ -1257,8 +1240,8 @@ "angle_mg_keff = angle_mgsp.k_combined\n", "\n", "# Find eigenvalue bias\n", - "iso_bias = 1.0E5 * (ce_keff - iso_mg_keff)\n", - "angle_bias = 1.0E5 * (ce_keff - angle_mg_keff)" + "iso_bias = 1.0e5 * (ce_keff - iso_mg_keff)\n", + "angle_bias = 1.0e5 * (ce_keff - angle_mg_keff)" ] }, { @@ -1270,15 +1253,15 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Isotropic to CE Bias [pcm]: 1394.6\n", - "Angle to CE Bias [pcm]: 183.4\n" + "Isotropic to CE Bias [pcm]: 1423.5\n", + "Angle to CE Bias [pcm]: 396.6\n" ] } ], @@ -1305,19 +1288,21 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 39, "metadata": { "scrolled": false }, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1363,27 +1348,29 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 41, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1430,7 +1417,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.7" + "version": "3.7.0" } }, "nbformat": 4, diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 3d2e8f57b..82f01d60b 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -110,6 +110,7 @@ extern "C" { int openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n); int openmc_tally_get_scores(int32_t index, int** scores, int* n); int openmc_tally_get_type(int32_t index, int32_t* type); + int openmc_tally_get_writable(int32_t index, bool* writable); int openmc_tally_reset(int32_t index); int openmc_tally_results(int32_t index, double** ptr, size_t shape_[3]); int openmc_tally_set_active(int32_t index, bool active); @@ -119,6 +120,7 @@ extern "C" { 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_zernike_filter_get_order(int32_t index, int* order); int openmc_zernike_filter_get_params(int32_t index, double* x, double* y, double* r); int openmc_zernike_filter_set_order(int32_t index, int order); diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 7206938c4..8a330060c 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -179,10 +179,10 @@ public: //! \brief Rotational tranfsormation of the filled universe. // - //! The vector is empty if there is no rotation. Otherwise, the first three - //! values are the rotation angles respectively about the x-, y-, and z-, axes - //! in degrees. The next 9 values give the rotation matrix in row-major - //! order. + //! The vector is empty if there is no rotation. Otherwise, the first 9 values + //! give the rotation matrix in row-major order. When the user specifies + //! rotation angles about the x-, y- and z- axes in degrees, these values are + //! also present at the end of the vector, making it of length 12. std::vector rotation_; std::vector offset_; //!< Distribcell offset table diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 51df59acc..d55744117 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -20,7 +20,7 @@ using double_4dvec = std::vector>>>; // OpenMC major, minor, and release numbers constexpr int VERSION_MAJOR {0}; -constexpr int VERSION_MINOR {11}; +constexpr int VERSION_MINOR {12}; constexpr int VERSION_RELEASE {0}; constexpr bool VERSION_DEV {true}; constexpr std::array VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE}; diff --git a/include/openmc/distribution_spatial.h b/include/openmc/distribution_spatial.h index 248f03588..6cf6f52d6 100644 --- a/include/openmc/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -37,6 +37,24 @@ private: UPtrDist z_; //!< Distribution of z coordinates }; +//============================================================================== +//! Distribution of points specified by spherical coordinates r,theta,phi +//============================================================================== + +class SphericalIndependent : public SpatialDistribution { +public: + explicit SphericalIndependent(pugi::xml_node node); + + //! Sample a position from the distribution + //! \return Sampled position + Position sample() const; +private: + UPtrDist r_; //!< Distribution of r coordinates + UPtrDist theta_; //!< Distribution of theta coordinates + UPtrDist phi_; //!< Distribution of phi coordinates + Position origin_; //!< Cartesian coordinates of the sphere center +}; + //============================================================================== //! Uniform distribution of points over a box //============================================================================== diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index ffcdcf885..800baef26 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -7,9 +7,15 @@ #include #include #include +#include namespace openmc { +namespace model { + extern std::unordered_map> universe_cell_counts; + extern std::unordered_map universe_level_counts; +} // namespace model + void read_geometry_xml(); //============================================================================== diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index d0474c834..ee3419fa2 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -345,7 +345,7 @@ read_dataset(hid_t obj_id, const char* name, Position& r, bool indep=false) } template -void read_dataset_as_shape(hid_t obj_id, const char* name, +inline void read_dataset_as_shape(hid_t obj_id, const char* name, xt::xtensor& arr, bool indep=false) { hid_t dset = open_dataset(obj_id, name); @@ -367,7 +367,7 @@ void read_dataset_as_shape(hid_t obj_id, const char* name, template -void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +inline void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have=false) { if (object_exists(obj_id, name)) { diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 1b4062da9..3dfd6ba4c 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -11,6 +11,7 @@ #include "openmc/constants.h" #include "openmc/hdf5_interface.h" +#include "openmc/particle.h" #include "openmc/xsdata.h" @@ -110,7 +111,10 @@ class Mgxs { //! //! @param xs_id HDF5 group id for the cross section data. //! @param temperature Temperatures to read. - Mgxs(hid_t xs_id, const std::vector& temperature); + //! @param num_group number of energy groups + //! @param num_delay number of delayed groups + Mgxs(hid_t xs_id, const std::vector& temperature, + int num_group, int num_delay); //! \brief Constructor that initializes and populates all data to build a //! macroscopic cross section from microscopic cross section. @@ -119,8 +123,11 @@ class Mgxs { //! @param mat_kTs temperatures (in units of eV) that data is needed. //! @param micros Microscopic objects to combine. //! @param atom_densities Atom densities of those microscopic quantities. + //! @param num_group number of energy groups + //! @param num_delay number of delayed groups Mgxs(const std::string& in_name, const std::vector& mat_kTs, - const std::vector& micros, const std::vector& atom_densities); + const std::vector& micros, const std::vector& atom_densities, + int num_group, int num_delay); //! \brief Provides a cross section value given certain parameters //! @@ -137,6 +144,11 @@ class Mgxs { get_xs(int xstype, int gin, const int* gout, const double* mu, const int* dg); + inline double + get_xs(int xstype, int gin) + {return get_xs(xstype, gin, nullptr, nullptr, nullptr);} + + //! \brief Samples the fission neutron energy and if prompt or delayed. //! //! @param gin Incoming energy group. @@ -156,15 +168,9 @@ class Mgxs { //! \brief Calculates cross section quantities needed for tracking. //! - //! @param gin Incoming energy group. - //! @param sqrtkT Temperature of the material. - //! @param u Incoming particle direction. - //! @param total_xs Resultant total cross section. - //! @param abs_xs Resultant absorption cross section. - //! @param nu_fiss_xs Resultant nu-fission cross section. + //! @param p The particle whose attributes set which MGXS to get. void - calculate_xs(int gin, double sqrtkT, Direction u, - double& total_xs, double& abs_xs, double& nu_fiss_xs); + calculate_xs(Particle& p); //! \brief Sets the temperature index in cache given a temperature //! diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index bf72d675b..6beda5778 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -12,70 +12,71 @@ namespace openmc { //============================================================================== -// Global variables +// Global MGXS data container structure //============================================================================== +class MgxsInterface { +public: + + MgxsInterface() = default; + + // Construct from path to cross sections file, as well as a list + // of XS to read and the corresponding temperatures for each XS + MgxsInterface(const std::string& path_cross_sections, + const std::vector xs_to_read, + const std::vector> xs_temps); + + // Does things to construct after the nuclides and temperatures to + // read have been specified. + void init(); + + // Set which nuclides and temperatures are to be read + void set_nuclides_and_temperatures(std::vector xs_to_read, + std::vector> xs_temps); + + // Add an Mgxs object to be managed + void add_mgxs(hid_t file_id, const std::string& name, + const std::vector& temperature); + + // Reads just the header of the cross sections file, to find + // min & max energies as well as the available XS + void read_header(const std::string& path_cross_sections); + + // Calculate microscopic cross sections from nuclide macro XS + void create_macro_xs(); + + // Get the kT values which are used in the OpenMC model + std::vector> get_mat_kTs(); + + int num_energy_groups_; + int num_delayed_groups_; + std::vector xs_names_; // available names in HDF5 file + std::vector xs_to_read_; // XS which appear in materials + std::vector> xs_temps_to_read_; // temperatures used + std::string cross_sections_path_; // path to MGXS h5 file + std::vector nuclides_; + std::vector macro_xs_; + std::vector energy_bins_; + std::vector energy_bin_avg_; + std::vector rev_energy_bins_; + std::vector> nuc_temps_; // all available temperatures +}; + namespace data { + extern MgxsInterface mg; +} -extern std::vector nuclides_MG; -extern std::vector macro_xs; -extern int num_energy_groups; -extern int num_delayed_groups; -extern std::vector energy_bins; -extern std::vector energy_bin_avg; -extern std::vector rev_energy_bins; +// Puts available XS in MGXS file to globals so that when +// materials are read, the MGXS specified in a material can +// be ensured to be present in the available data. +void put_mgxs_header_data_to_globals(); -} // namespace data +// Set which nuclides and temperatures are to be read on +// mg through global data +void set_mg_interface_nuclides_and_temps(); -//============================================================================== -// Mgxs data loading interface methods -//============================================================================== - -void read_mgxs(); - -void -add_mgxs(hid_t file_id, const std::string& name, - const std::vector& temperature); - -void create_macro_xs(); - -std::vector> get_mat_kTs(); - -void read_mg_cross_sections_header(); - -//============================================================================== -// Mgxs tracking/transport/tallying interface methods -//============================================================================== - -extern "C" void -calculate_xs_c(int i_mat, int gin, double sqrtkT, Direction u, - double& total_xs, double& abs_xs, double& nu_fiss_xs); - -double -get_nuclide_xs(int index, int xstype, int gin, const int* gout, - const double* mu, const int* dg); - -inline double -get_nuclide_xs(int index, int xstype, int gin) -{return get_nuclide_xs(index, xstype, gin, nullptr, nullptr, nullptr);} - -double -get_macro_xs(int index, int xstype, int gin, const int* gout, - const double* mu, const int* dg); - -inline double -get_macro_xs(int index, int xstype, int gin) -{return get_macro_xs(index, xstype, gin, nullptr, nullptr, nullptr);} - -//============================================================================== -// General Mgxs methods -//============================================================================== - -extern "C" void -get_name_c(int index, int name_len, char* name); - -extern "C" double -get_awr_c(int index); +// After macro XS have been read, materials can be marked as fissionable +void mark_fissionable_mgxs_materials(); } // namespace openmc #endif // OPENMC_MGXS_INTERFACE_H diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 8f4376717..45cb7394c 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -31,7 +31,7 @@ extern "C" bool cmfd_run; //!< is a CMFD run? extern "C" bool dagmc; //!< indicator of DAGMC geometry extern "C" bool entropy_on; //!< calculate Shannon entropy? extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular? -extern bool output_summary; //!< write summary.h5? +extern "C" bool output_summary; //!< write summary.h5? extern bool output_tallies; //!< write tallies.out? extern bool particle_restart_run; //!< particle restart run? extern "C" bool photon_transport; //!< photon transport turned on? diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index 70a282222..71c83b5e8 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -37,6 +37,8 @@ public: void set_active(bool active) { active_ = active; } + void set_writable(bool writable) { writable_ = writable; } + void set_scores(pugi::xml_node node); void set_scores(const std::vector& scores); @@ -55,6 +57,8 @@ public: int32_t n_filter_bins() const {return n_filter_bins_;} + bool writable() const { return writable_;} + //---------------------------------------------------------------------------- // Other methods. @@ -98,6 +102,9 @@ public: //! (e.g. specific cell, specific energy group, etc.) xt::xtensor results_; + //! True if this tally should be written to statepoint files + bool writable_ {true}; + //---------------------------------------------------------------------------- // Miscellaneous public members. diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 7ee660d8b..1b49da814 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -2,12 +2,14 @@ #define OPENMC_VOLUME_CALC_H #include "openmc/position.h" +#include "openmc/tallies/trigger.h" #include "pugixml.hpp" #include "xtensor/xtensor.hpp" #include #include +#include namespace openmc { @@ -16,6 +18,7 @@ namespace openmc { //============================================================================== class VolumeCalculation { + public: // Aliases, types struct Result { @@ -23,6 +26,7 @@ public: std::vector nuclides; //!< Index of nuclides std::vector atoms; //!< Number of atoms for each nuclide std::vector uncertainty; //!< Uncertainty on number of atoms + int iterations; //!< Number of iterations needed to obtain the results }; // Results for a single domain // Constructors @@ -44,7 +48,9 @@ public: // Data members int domain_type_; //!< Type of domain (cell, material, etc.) - int n_samples_; //!< Number of samples to use + size_t n_samples_; //!< Number of samples to use + double threshold_ {-1.0}; //!< Error threshold for domain volumes + TriggerMetric trigger_type_ {TriggerMetric::not_active}; //!< Trigger metric for the volume calculation Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index a8aed5d17..3e9fc51cc 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -22,6 +22,7 @@ namespace openmc { class XsData { private: + //! \brief Reads scattering data from the HDF5 file void scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, @@ -61,6 +62,9 @@ class XsData { void fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang); + //! Number of energy and delayed neutron groups + size_t n_g_, n_dg_; + public: // The following quantities have the following dimensions: @@ -98,7 +102,10 @@ class XsData { //! @param scatter_format The scattering representation of the file. //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. - XsData(bool fissionable, int scatter_format, int n_pol, int n_azi); + //! @param n_groups Number of energy groups. + //! @param n_d_groups Number of delayed neutron groups. + XsData(bool fissionable, int scatter_format, int n_pol, int n_azi, + size_t n_groups, size_t n_d_groups); //! \brief Loads the XsData object from the HDF5 file //! diff --git a/openmc/__init__.py b/openmc/__init__.py index 1195db725..6af629422 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -34,4 +34,4 @@ from . import examples # Import a few convencience functions that used to be here from openmc.model import rectangular_prism, hexagonal_prism -__version__ = '0.11.0-dev' +__version__ = '0.12.0-dev' diff --git a/openmc/cell.py b/openmc/cell.py index 3fd70b345..ee883c796 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -63,6 +63,10 @@ class Cell(IDManagerMixin): \sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\ -\sin\theta & \sin\phi \cos\theta & \cos\phi \cos\theta \end{array} \right ] + + A rotation matrix can also be specified directly by setting this + attribute to a nested list (or 2D numpy array) that specifies each + element of the matrix. rotation_matrix : numpy.ndarray The rotation matrix defined by the angles specified in the :attr:`Cell.rotation` property. @@ -227,21 +231,24 @@ class Cell(IDManagerMixin): @rotation.setter def rotation(self, rotation): - cv.check_type('cell rotation', rotation, Iterable, Real) 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. - 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]]) + 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): @@ -343,7 +350,7 @@ class Cell(IDManagerMixin): return nuclides - def get_all_cells(self): + def get_all_cells(self, memo=None): """Return all cells that are contained within this one if it is filled with a universe or lattice @@ -357,12 +364,18 @@ class Cell(IDManagerMixin): cells = OrderedDict() + if memo and self in memo: + return cells + + if memo is not None: + memo.add(self) + if self.fill_type in ('universe', 'lattice'): - cells.update(self.fill.get_all_cells()) + cells.update(self.fill.get_all_cells(memo)) return cells - def get_all_materials(self): + def get_all_materials(self, memo=None): """Return all materials that are contained within the cell Returns @@ -381,9 +394,9 @@ class Cell(IDManagerMixin): materials[m.id] = m else: # Append all Cells in each Cell in the Universe to the dictionary - cells = self.get_all_cells() + cells = self.get_all_cells(memo) for cell in cells.values(): - materials.update(cell.get_all_materials()) + materials.update(cell.get_all_materials(memo)) return materials @@ -456,7 +469,24 @@ class Cell(IDManagerMixin): return memo[self] - def create_xml_subelement(self, xml_element): + def create_xml_subelement(self, xml_element, memo=None): + """Add the cell's xml representation to an incoming xml element + + Parameters + ---------- + xml_element : xml.etree.ElementTree.Element + XML element to be added to + + memo : set or None + A set of object IDs representing geometry entities already + written to ``xml_element``. This parameter is used internally + and should not be specified by users. + + Returns + ------- + None + + """ element = ET.Element("cell") element.set("id", str(self.id)) @@ -475,7 +505,7 @@ class Cell(IDManagerMixin): elif self.fill_type in ('universe', 'lattice'): element.set("fill", str(self.fill.id)) - self.fill.create_xml_subelement(xml_element) + self.fill.create_xml_subelement(xml_element, memo) if self.region is not None: # Set the region attribute with the region specification @@ -491,19 +521,22 @@ class Cell(IDManagerMixin): # tree. When it reaches a leaf (a Halfspace), it creates a # element for the corresponding surface if none has been created # thus far. - def create_surface_elements(node, element): + def create_surface_elements(node, element, memo=None): if isinstance(node, Halfspace): - path = "./surface[@id='{}']".format(node.surface.id) - if xml_element.find(path) is None: - xml_element.append(node.surface.to_xml_element()) + if memo and node.surface in memo: + return + if memo is not None: + memo.add(node.surface) + xml_element.append(node.surface.to_xml_element()) + elif isinstance(node, Complement): - create_surface_elements(node.node, element) + create_surface_elements(node.node, element, memo) else: for subnode in node: - create_surface_elements(subnode, element) + create_surface_elements(subnode, element, memo) # Call the recursive function from the top node - create_surface_elements(self.region, xml_element) + create_surface_elements(self.region, xml_element, memo) if self.temperature is not None: if isinstance(self.temperature, Iterable): @@ -516,7 +549,7 @@ class Cell(IDManagerMixin): element.set("translation", ' '.join(map(str, self.translation))) if self.rotation is not None: - element.set("rotation", ' '.join(map(str, self.rotation))) + element.set("rotation", ' '.join(map(str, self.rotation.ravel()))) return element diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 022cf8283..7420387da 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -118,7 +118,12 @@ class IncidentNeutron(EqualityMixin): if mt in self.reactions: return self.reactions[mt] else: - raise KeyError('No reaction with MT={}.'.format(mt)) + # Try to create a redundant cross section + mts = self.get_reaction_components(mt) + if len(mts) > 0: + return self._get_redundant_reaction(mt, mts) + else: + raise KeyError('No reaction with MT={}.'.format(mt)) def __repr__(self): return "".format(self.name) @@ -588,6 +593,9 @@ class IncidentNeutron(EqualityMixin): # If mass number hasn't been specified, make an educated guess zaid, xs = ace.name.split('.') + if not xs.endswith('c'): + raise TypeError( + "{} is not a continuous-energy neutron ACE table.".format(ace)) name, element, Z, mass_number, metastable = \ get_metadata(int(zaid), metastable_scheme) @@ -871,7 +879,7 @@ class IncidentNeutron(EqualityMixin): fission = data.reactions[18].xs[temp] kerma_fission = get_file3_xs(ev, 318, E) kerma.y = kerma.y - kerma_fission + ( - f.fragments(E) + f.betas(E)) * fission.y + f.fragments(E) + f.betas(E)) * fission(E) # For local KERMA, we first need to get the values from the # HEATR run with photon energy deposited locally and put @@ -884,7 +892,7 @@ class IncidentNeutron(EqualityMixin): kerma_fission_local = get_file3_xs(ev_local, 318, E) kerma_local = kerma_local - kerma_fission_local + ( f.fragments(E) + f.prompt_photons(E) - + f.delayed_photons(E) + f.betas(E))*fission.y + + f.delayed_photons(E) + f.betas(E))*fission(E) heating_local.xs[temp] = Tabulated1D(E, kerma_local) @@ -908,16 +916,17 @@ class IncidentNeutron(EqualityMixin): Redundant reaction """ - # Get energy grid - strT = self.temperatures[0] - energy = self.energy[strT] rx = Reaction(mt) - xss = [self.reactions[mt_i].xs[strT] for mt_i in mts] - idx = min([xs._threshold_idx if hasattr(xs, '_threshold_idx') - else 0 for xs in xss]) - rx.xs[strT] = Tabulated1D(energy[idx:], Sum(xss)(energy[idx:])) - rx.xs[strT]._threshold_idx = idx + # Get energy grid + for strT in self.temperatures: + energy = self.energy[strT] + xss = [self.reactions[mt_i].xs[strT] for mt_i in mts] + idx = min([xs._threshold_idx if hasattr(xs, '_threshold_idx') + else 0 for xs in xss]) + rx.xs[strT] = Tabulated1D(energy[idx:], Sum(xss)(energy[idx:])) + rx.xs[strT]._threshold_idx = idx + rx.redundant = True return rx diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 4983098f7..0c853102f 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -10,7 +10,7 @@ from . import endf # For a given MAT number, give a name for the ACE table and a list of ZAID -# identifiers +# identifiers. This is based on Appendix C in the ENDF manual. ThermalTuple = namedtuple('ThermalTuple', ['name', 'zaids', 'nmix']) _THERMAL_DATA = { 1: ThermalTuple('hh2o', [1001], 1), @@ -23,31 +23,77 @@ _THERMAL_DATA = { 11: ThermalTuple('dd2o', [1002], 1), 12: ThermalTuple('parad', [1002], 1), 13: ThermalTuple('orthod', [1002], 1), + 14: ThermalTuple('dice', [1002], 1), 26: ThermalTuple('be', [4009], 1), 27: ThermalTuple('bebeo', [4009], 1), - 31: ThermalTuple('graph', [6000, 6012, 6013], 1), + 28: ThermalTuple('bebe2c', [4009], 1), + 30: ThermalTuple('graph', [6000, 6012, 6013], 1), + 31: ThermalTuple('grph10', [6000, 6012, 6013], 1), + 32: ThermalTuple('grph30', [6000, 6012, 6013], 1), 33: ThermalTuple('lch4', [1001], 1), 34: ThermalTuple('sch4', [1001], 1), + 35: ThermalTuple('sch4p2', [1001], 1), 37: ThermalTuple('hch2', [1001], 1), + 38: ThermalTuple('mesi00', [1001], 1), 39: ThermalTuple('lucite', [1001], 1), 40: ThermalTuple('benz', [1001, 6000, 6012], 2), - 41: ThermalTuple('od2o', [8016, 8017, 8018], 1), + 42: ThermalTuple('tol00', [1001], 1), 43: ThermalTuple('sisic', [14028, 14029, 14030], 1), 44: ThermalTuple('csic', [6000, 6012, 6013], 1), + 45: ThermalTuple('ouo2', [8016, 8017, 8018], 1), 46: ThermalTuple('obeo', [8016, 8017, 8018], 1), 47: ThermalTuple('sio2-a', [8016, 8017, 8018, 14028, 14029, 14030], 3), - 48: ThermalTuple('uuo2', [92238], 1), + 48: ThermalTuple('osap00', [92238], 1), 49: ThermalTuple('sio2-b', [8016, 8017, 8018, 14028, 14029, 14030], 3), 50: ThermalTuple('oice', [8016, 8017, 8018], 1), + 51: ThermalTuple('od2o', [8016, 8017, 8018], 1), 52: ThermalTuple('mg24', [12024], 1), 53: ThermalTuple('al27', [13027], 1), 55: ThermalTuple('yyh2', [39089], 1), 56: ThermalTuple('fe56', [26056], 1), 58: ThermalTuple('zrzrh', [40000, 40090, 40091, 40092, 40094, 40096], 1), - 59: ThermalTuple('cacah2', [20040, 20042, 20043, 20044, 20046, 20048], 1), - 75: ThermalTuple('ouo2', [8016, 8017, 8018], 1), + 59: ThermalTuple('si00', [14028], 1), + 60: ThermalTuple('asap00', [13027], 1), + 71: ThermalTuple('n-un', [7014, 7015], 1), + 72: ThermalTuple('u-un', [92238], 1), + 75: ThermalTuple('uuo2', [8016, 8017, 8018], 1), } + +def _get_thermal_data(ev, mat): + """Return appropriate ThermalTuple, accounting for bugs.""" + + # JEFF assigns MAT=59 to Ca in CaH2 (which is supposed to be silicon). + if ev.info['library'][0] == 'JEFF': + if ev.material == 59: + if 'CaH2' in ''.join(ev.info['description']): + zaids = [20040, 20042, 20043, 20044, 20046, 20048] + return ThermalTuple('cacah2', zaids, 1) + + # Before ENDF/B-VIII.0, crystalline graphite was MAT=31 + if ev.info['library'] != ('ENDF/B', 8, 0): + if ev.material == 31: + return _THERMAL_DATA[30] + + # ENDF/B incorrectly assigns MAT numbers for UO2 + # + # Material | ENDF Manual | VII.0 | VII.1 | VIII.0 + # ---------|-------------|-------|-------|------- + # O in UO2 | 45 | 75 | 75 | 75 + # U in UO2 | 75 | 76 | 48 | 48 + if ev.info['library'][0] == 'ENDF/B': + if ev.material == 75: + return _THERMAL_DATA[45] + version = ev.info['library'][1:] + if version in ((7, 1), (8, 0)) and ev.material == 48: + return _THERMAL_DATA[75] + if version == (7, 0) and ev.material == 76: + return _THERMAL_DATA[75] + + # If not a problematic material, use the dictionary as is + return _THERMAL_DATA[mat] + + _TEMPLATE_RECONR = """ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% {nendf} {npendf} @@ -444,7 +490,8 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, mat_thermal = ev_thermal.material zsymam_thermal = ev_thermal.target['zsymam'] - data = _THERMAL_DATA[mat_thermal] + # Determine name, isotopes based on MAT number + data = _get_thermal_data(ev_thermal, mat_thermal) zaids = ' '.join(str(zaid) for zaid in data.zaids[:3]) # Determine name of library diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 0d0e52753..3766b697e 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -549,7 +549,9 @@ class IncidentPhoton(EqualityMixin): ace = get_table(ace_or_filename) # Get atomic number based on name of ACE table - zaid = ace.name.split('.')[0] + zaid, xs = ace.name.split('.') + if not xs.endswith('p'): + raise TypeError("{} is not a photoatomic transport ACE table.".format(ace)) Z = get_metadata(int(zaid))[2] # Read each reaction diff --git a/openmc/data/resonance.py b/openmc/data/resonance.py index 5e4bd7129..628ad184b 100644 --- a/openmc/data/resonance.py +++ b/openmc/data/resonance.py @@ -430,7 +430,7 @@ class MultiLevelBreitWigner(ResonanceRange): # Determine penetration at modified energy for competitive reaction if gx > 0: - Ex = E + self.q[l]*(A + 1)/A + Ex = E + self.q_value[l]*(A + 1)/A rho = k*self.channel_radius[l](Ex) rhohat = k*self.scattering_radius[l](Ex) px[i], sx[i] = penetration_shift(l, rho) @@ -915,7 +915,9 @@ class Unresolved(ResonanceRange): Minimum energy of the unresolved resonance range in eV energy_max : float Maximum energy of the unresolved resonance range in eV - scatter : openmc.data.Function1D + channel : openmc.data.Function1D + Channel radii as a function of energy + scattering : openmc.data.Function1D Scattering radii as a function of energy Attributes @@ -923,6 +925,10 @@ class Unresolved(ResonanceRange): add_to_background : bool If True, file 3 contains partial cross sections to be added to the average unresolved cross sections calculated from parameters. + atomic_weight_ratio : float + Atomic weight ratio of the target nuclide + channel_radius : openmc.data.Function1D + Channel radii as a function of energy energies : Iterable of float Energies at which parameters are tabulated energy_max : float @@ -938,11 +944,13 @@ class Unresolved(ResonanceRange): """ - def __init__(self, target_spin, energy_min, energy_max, scatter): - super().__init__(target_spin, energy_min, energy_max, None, scatter) + def __init__(self, target_spin, energy_min, energy_max, channel, scattering): + super().__init__(target_spin, energy_min, energy_max, channel, + scattering) self.energies = None self.parameters = None self.add_to_background = False + self.atomic_weight_ratio = None @classmethod def from_endf(cls, file_obj, items, fission_widths): @@ -967,9 +975,9 @@ class Unresolved(ResonanceRange): """ # Read energy-dependent scattering radius if present energy_min, energy_max = items[0:2] - nro = items[4] + nro, naps = items[4:6] if nro != 0: - params, scattering_radius = get_tab1_record(file_obj) + params, ape = get_tab1_record(file_obj) # Get SPI, AP, and LSSF formalism = items[3] @@ -977,22 +985,23 @@ class Unresolved(ResonanceRange): items = get_cont_record(file_obj) target_spin = items[0] if nro == 0: - scattering_radius = items[1] + ap = Polynomial((items[1],)) add_to_background = (items[2] == 0) if not fission_widths and formalism == 1: # Case A -- fission widths not given, all parameters are # energy-independent NLS = items[4] - columns = ['L', 'J', 'd', 'amun', 'gn', 'gg', 'gf'] + columns = ['L', 'J', 'd', 'amun', 'gn0', 'gg'] records = [] for ls in range(NLS): items, values = get_list_record(file_obj) + awri = items[0] l = items[2] NJS = items[5] for j in range(NJS): - d, j, amun, gn, gg = values[6*j:6*j + 5] - records.append([l, j, d, amun, gn, gg, 0.0]) + d, j, amun, gn0, gg = values[6*j:6*j + 5] + records.append([l, j, d, amun, gn0, gg]) parameters = pd.DataFrame.from_records(records, columns=columns) energies = None @@ -1002,14 +1011,14 @@ class Unresolved(ResonanceRange): items, energies = get_list_record(file_obj) target_spin = items[0] if nro == 0: - scattering_radius = items[1] + ap = Polynomial((items[1],)) add_to_background = (items[2] == 0) NE, NLS = items[4:6] - l_values = np.zeros(NLS, int) - records = [[] for e in energies] - columns = ['L', 'J', 'd', 'amun', 'gn0', 'gg', 'gf'] + records = [] + columns = ['L', 'J', 'E', 'd', 'amun', 'amuf', 'gn0', 'gg', 'gf'] for ls in range(NLS): items = get_cont_record(file_obj) + awri = items[0] l = items[2] NJS = items[4] for j in range(NJS): @@ -1020,18 +1029,20 @@ class Unresolved(ResonanceRange): amun = values[2] gn0 = values[3] gg = values[4] - gf = values[6:] - for k, gf_i in enumerate(gf): - records[k].append([l, j, d, amun, gn0, gg, gf]) - parameters = [pd.DataFrame(r, columns=columns) for r in records] + gfs = values[6:] + for E, gf in zip(energies, gfs): + records.append([l, j, E, d, amun, muf, gn0, gg, gf]) + parameters = pd.DataFrame.from_records(records, columns=columns) elif formalism == 2: # Case C -- all parameters are energy-dependent NLS = items[4] - columns = ['L', 'J', 'E', 'd', 'gx', 'gn0', 'gg', 'gf'] + columns = ['L', 'J', 'E', 'd', 'amux', 'amun', 'amuf', 'gx', 'gn0', + 'gg', 'gf'] records = [] for ls in range(NLS): items = get_cont_record(file_obj) + awri = items[0] l = items[2] NJS = items[4] for j in range(NJS): @@ -1040,8 +1051,8 @@ class Unresolved(ResonanceRange): j = items[0] amux = values[2] amun = values[3] - amug = values[4] amuf = values[5] + energies = [] for k in range(1, ne + 1): E = values[6*k] d = values[6*k + 1] @@ -1049,13 +1060,35 @@ class Unresolved(ResonanceRange): gn0 = values[6*k + 3] gg = values[6*k + 4] gf = values[6*k + 5] - records.append([l, j, E, d, gx, gn0, gg, gf]) + energies.append(E) + records.append([l, j, E, d, amux, amun, amuf, gx, gn0, + gg, gf]) parameters = pd.DataFrame.from_records(records, columns=columns) - energies = None - urr = cls(target_spin, energy_min, energy_max, scattering_radius) + # Calculate channel radius from ENDF-102 equation D.14 + a = Polynomial((0.123 * (NEUTRON_MASS*awri)**(1./3.) + 0.08,)) + + # Determine scattering and channel radius + if nro == 0: + scattering_radius = ap + if naps == 0: + channel_radius = a + elif naps == 1: + channel_radius = ap + elif nro == 1: + scattering_radius = ape + if naps == 0: + channel_radius = a + elif naps == 1: + channel_radius = ape + elif naps == 2: + channel_radius = ap + + urr = cls(target_spin, energy_min, energy_max, channel_radius, + scattering_radius) urr.parameters = parameters urr.add_to_background = add_to_background + urr.atomic_weight_ratio = awri urr.energies = energies return urr diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 06e50c661..067c0a703 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -33,10 +33,12 @@ _THERMAL_NAMES = { 'c_Be': ('be', 'be-metal', 'be-met', 'be00'), 'c_BeO': ('beo',), 'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o', 'bbeo00'), + 'c_Be_in_Be2C': ('bebe2c',), 'c_C6H6': ('benz', 'c6h6'), 'c_C_in_SiC': ('csic', 'c-sic'), 'c_Ca_in_CaH2': ('cah', 'cah00'), 'c_D_in_D2O': ('dd2o', 'd-d2o', 'hwtr', 'hw', 'dhw00'), + 'c_D_in_D2O_ice': ('dice',), 'c_Fe56': ('fe', 'fe56', 'fe-56'), 'c_Graphite': ('graph', 'grph', 'gr', 'gr00'), 'c_Graphite_10p': ('grph10',), @@ -45,6 +47,7 @@ _THERMAL_NAMES = { 'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly', 'pol00'), 'c_H_in_CH4_liquid': ('lch4', 'lmeth'), 'c_H_in_CH4_solid': ('sch4', 'smeth'), + 'c_H_in_CH4_solid_phase_II': ('sch4p2',), 'c_H_in_H2O': ('hh2o', 'h-h2o', 'lwtr', 'lw', 'lw00'), 'c_H_in_H2O_solid': ('hice', 'h-ice', 'ice00'), 'c_H_in_C5O2H8': ('lucite', 'c5o2h8', 'h-luci'), @@ -600,6 +603,8 @@ class ThermalScattering(EqualityMixin): # Get new name that is GND-consistent ace_name, xs = ace.name.split('.') + if not xs.endswith('t'): + raise TypeError("{} is not a thermal scattering ACE table.".format(ace)) name = get_thermal_name(ace_name) # Assign temperature to the running list diff --git a/openmc/deplete/__init__.py b/openmc/deplete/__init__.py index f0b04c3de..b54d7f11d 100644 --- a/openmc/deplete/__init__.py +++ b/openmc/deplete/__init__.py @@ -4,12 +4,11 @@ openmc.deplete A depletion front-end tool. """ -from sys import exit +import sys +from unittest.mock import Mock from h5py import get_config -from unittest.mock import Mock - from .dummy_comm import DummyCommunicator try: @@ -22,7 +21,7 @@ try: if not get_config().mpi and comm.size > 1: # Raise exception only on process 0 if comm.rank: - exit() + sys.exit() raise RuntimeError( "Need parallel HDF5 installed to perform depletion with MPI" ) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 565b9e2dc..10976dd0e 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -28,7 +28,7 @@ from .results_list import ResultsList __all__ = [ "OperatorResult", "TransportOperator", "ReactionRateHelper", "EnergyHelper", "FissionYieldHelper", "TalliedFissionYieldHelper", - "Integrator", "SIIntegrator"] + "Integrator", "SIIntegrator", "DepSystemSolver"] OperatorResult = namedtuple('OperatorResult', ['k', 'rates']) @@ -546,6 +546,7 @@ class TalliedFissionYieldHelper(FissionYieldHelper): # Tally group-wise fission reaction rates self._fission_rate_tally = Tally() + self._fission_rate_tally.writable = False self._fission_rate_tally.scores = ['fission'] self._fission_rate_tally.filters = [MaterialFilter(materials)] @@ -814,11 +815,11 @@ class SIIntegrator(Integrator): reset_particles = False if step_index == 0 and hasattr(self.operator, "settings"): reset_particles = True - self.operator.settings.particles *= self.n_stages + self.operator.settings.particles *= self.n_steps inherited = super()._get_bos_data_from_operator( step_index, step_power, bos_conc) if reset_particles: - self.operator.settings.particles //= self.n_stages + self.operator.settings.particles //= self.n_steps return inherited def integrate(self): @@ -855,3 +856,40 @@ class SIIntegrator(Integrator): Results.save(self.operator, [conc], [res_list[-1]], [t, t], p, self._i_res + len(self), proc_time) self.operator.write_bos_data(self._i_res + len(self)) + + +class DepSystemSolver(ABC): + r"""Abstract class for solving depletion equations + + Responsible for solving + + .. math:: + + \frac{\partial \vec{N}}{\partial t} = \bar{A}\vec{N}(t), + + for :math:`0< t\leq t +\Delta t`, given :math:`\vec{N}(0) = \vec{N}_0` + + """ + + @abstractmethod + def __call__(self, A, n0, dt): + """Solve the linear system of equations for depletion + + Parameters + ---------- + A : scipy.sparse.csr_matrix + Sparse transmutation matrix ``A[j, i]`` desribing rates at + which isotope ``i`` transmutes to isotope ``j`` + n0 : numpy.ndarray + Initial compositions, typically given in number of atoms in some + material or an atom density + dt : float + Time [s] of the specific interval to be solved + + Returns + ------- + numpy.ndarray + Final compositions after ``dt``. Should be of identical shape + to ``n0``. + + """ diff --git a/openmc/deplete/cram.py b/openmc/deplete/cram.py index 31049bb72..7dad820a9 100644 --- a/openmc/deplete/cram.py +++ b/openmc/deplete/cram.py @@ -3,6 +3,7 @@ Implements two different forms of CRAM for use in openmc.deplete. """ +import numbers from itertools import repeat from multiprocessing import Pool import time @@ -11,7 +12,12 @@ import numpy as np import scipy.sparse as sp import scipy.sparse.linalg as sla -from . import comm +from openmc.checkvalue import check_type, check_length +from .abc import DepSystemSolver + +__all__ = [ + "deplete", "timed_deplete", "CRAM16", "CRAM48", + "Cram16Solver", "Cram48Solver", "IPFCramSolver"] def deplete(chain, x, rates, dt, matrix_func=None): @@ -81,147 +87,169 @@ def timed_deplete(*args, **kwargs): return time.time() - start, results -def CRAM16(A, n0, dt): - """Chebyshev Rational Approximation Method, order 16 +class IPFCramSolver(DepSystemSolver): + r"""CRAM depletion solver that uses incomplete partial factorization - Algorithm is the 16th order Chebyshev Rational Approximation Method, - implemented in the more stable `incomplete partial fraction (IPF) - `_ form. + Provides a :meth:`__call__` that utilizes an incomplete + partial factorization (IPF) for the Chebyshev Rational Approximation + Method (CRAM), as described in the following paper: M. Pusa, "`Higher-Order + Chebyshev Rational Approximation Method and Application to Burnup Equations + `_," Nucl. Sci. Eng., 182:3, 297-318. Parameters ---------- - A : scipy.linalg.csr_matrix - Matrix to take exponent of. - n0 : numpy.array - Vector to operate a matrix exponent on. - dt : float - Time to integrate to. + alpha : numpy.ndarray + Complex residues of poles used in the factorization. Must be a + vector with even number of items. + theta : numpy.ndarray + Complex poles. Must have an equal size as ``alpha``. + alpha0 : float + Limit of the approximation at infinity - Returns - ------- - numpy.array - Results of the matrix exponent. - - """ - - alpha = np.array([+2.124853710495224e-16, - +5.464930576870210e+3 - 3.797983575308356e+4j, - +9.045112476907548e+1 - 1.115537522430261e+3j, - +2.344818070467641e+2 - 4.228020157070496e+2j, - +9.453304067358312e+1 - 2.951294291446048e+2j, - +7.283792954673409e+2 - 1.205646080220011e+5j, - +3.648229059594851e+1 - 1.155509621409682e+2j, - +2.547321630156819e+1 - 2.639500283021502e+1j, - +2.394538338734709e+1 - 5.650522971778156e+0j], - dtype=np.complex128) - theta = np.array([+0.0, - +3.509103608414918 + 8.436198985884374j, - +5.948152268951177 + 3.587457362018322j, - -5.264971343442647 + 16.22022147316793j, - +1.419375897185666 + 10.92536348449672j, - +6.416177699099435 + 1.194122393370139j, - +4.993174737717997 + 5.996881713603942j, - -1.413928462488886 + 13.49772569889275j, - -10.84391707869699 + 19.27744616718165j], - dtype=np.complex128) - - n = A.shape[0] - - alpha0 = 2.124853710495224e-16 - - k = 8 - - y = np.array(n0, dtype=np.float64) - for l in range(1, k+1): - y = 2.0*np.real(alpha[l]*sla.spsolve(A*dt - theta[l]*sp.eye(n), y)) + y - - y *= alpha0 - return y - - -def CRAM48(A, n0, dt): - """Chebyshev Rational Approximation Method, order 48 - - Algorithm is the 48th order Chebyshev Rational Approximation Method, - implemented in the more stable `incomplete partial fraction (IPF) - `_ form. - - Parameters + Attributes ---------- - A : scipy.linalg.csr_matrix - Matrix to take exponent of. - n0 : numpy.array - Vector to operate a matrix exponent on. - dt : float - Time to integrate to. - - Returns - ------- - numpy.array - Results of the matrix exponent. + alpha : numpy.ndarray + Complex residues of poles :attr:`theta` in the incomplete partial + factorization. Denoted as :math:`\tilde{\alpha}` + theta : numpy.ndarray + Complex poles :math:`\theta` of the rational approximation + alpha0 : float + Limit of the approximation at infinity """ - theta_r = np.array([-4.465731934165702e+1, -5.284616241568964e+0, - -8.867715667624458e+0, +3.493013124279215e+0, - +1.564102508858634e+1, +1.742097597385893e+1, - -2.834466755180654e+1, +1.661569367939544e+1, - +8.011836167974721e+0, -2.056267541998229e+0, - +1.449208170441839e+1, +1.853807176907916e+1, - +9.932562704505182e+0, -2.244223871767187e+1, - +8.590014121680897e-1, -1.286192925744479e+1, - +1.164596909542055e+1, +1.806076684783089e+1, - +5.870672154659249e+0, -3.542938819659747e+1, - +1.901323489060250e+1, +1.885508331552577e+1, - -1.734689708174982e+1, +1.316284237125190e+1]) - theta_i = np.array([+6.233225190695437e+1, +4.057499381311059e+1, - +4.325515754166724e+1, +3.281615453173585e+1, - +1.558061616372237e+1, +1.076629305714420e+1, - +5.492841024648724e+1, +1.316994930024688e+1, - +2.780232111309410e+1, +3.794824788914354e+1, - +1.799988210051809e+1, +5.974332563100539e+0, - +2.532823409972962e+1, +5.179633600312162e+1, - +3.536456194294350e+1, +4.600304902833652e+1, - +2.287153304140217e+1, +8.368200580099821e+0, - +3.029700159040121e+1, +5.834381701800013e+1, - +1.194282058271408e+0, +3.583428564427879e+0, - +4.883941101108207e+1, +2.042951874827759e+1]) - theta = np.array(theta_r + theta_i * 1j, dtype=np.complex128) + def __init__(self, alpha, theta, alpha0): + check_type("alpha", alpha, np.ndarray, numbers.Complex) + check_type("theta", theta, np.ndarray, numbers.Complex) + check_length("theta", theta, alpha.size) + check_type("alpha0", alpha0, numbers.Real) + self.alpha = alpha + self.theta = theta + self.alpha0 = alpha0 - alpha_r = np.array([+6.387380733878774e+2, +1.909896179065730e+2, - +4.236195226571914e+2, +4.645770595258726e+2, - +7.765163276752433e+2, +1.907115136768522e+3, - +2.909892685603256e+3, +1.944772206620450e+2, - +1.382799786972332e+5, +5.628442079602433e+3, - +2.151681283794220e+2, +1.324720240514420e+3, - +1.617548476343347e+4, +1.112729040439685e+2, - +1.074624783191125e+2, +8.835727765158191e+1, - +9.354078136054179e+1, +9.418142823531573e+1, - +1.040012390717851e+2, +6.861882624343235e+1, - +8.766654491283722e+1, +1.056007619389650e+2, - +7.738987569039419e+1, +1.041366366475571e+2]) - alpha_i = np.array([-6.743912502859256e+2, -3.973203432721332e+2, - -2.041233768918671e+3, -1.652917287299683e+3, - -1.783617639907328e+4, -5.887068595142284e+4, - -9.953255345514560e+3, -1.427131226068449e+3, - -3.256885197214938e+6, -2.924284515884309e+4, - -1.121774011188224e+3, -6.370088443140973e+4, - -1.008798413156542e+6, -8.837109731680418e+1, - -1.457246116408180e+2, -6.388286188419360e+1, - -2.195424319460237e+2, -6.719055740098035e+2, - -1.693747595553868e+2, -1.177598523430493e+1, - -4.596464999363902e+3, -1.738294585524067e+3, - -4.311715386228984e+1, -2.777743732451969e+2]) - alpha = np.array(alpha_r + alpha_i * 1j, dtype=np.complex128) - n = A.shape[0] + def __call__(self, A, n0, dt): + """Solve depletion equations using IPF CRAM - alpha0 = 2.258038182743983e-47 + Parameters + ---------- + A : scipy.sparse.csr_matrix + Sparse transmutation matrix ``A[j, i]`` desribing rates at + which isotope ``i`` transmutes to isotope ``j`` + n0 : numpy.ndarray + Initial compositions, typically given in number of atoms in some + material or an atom density + dt : float + Time [s] of the specific interval to be solved - k = 24 + Returns + ------- + numpy.ndarray + Final compositions after ``dt`` - y = np.array(n0, dtype=np.float64) - for l in range(k): - y = 2.0*np.real(alpha[l]*sla.spsolve(A*dt - theta[l]*sp.eye(n), y)) + y + """ + A = sp.csr_matrix(A * dt, dtype=np.float64) + y = np.asarray(n0, dtype=np.float64) + ident = sp.eye(A.shape[0]) + for alpha, theta in zip(self.alpha, self.theta): + y += 2*np.real(alpha*sla.spsolve(A - theta*ident, y)) + return y * self.alpha0 - y *= alpha0 - return y + +# Coefficients for IPF Cram 16 +c16_alpha = np.array([ + +5.464930576870210e+3 - 3.797983575308356e+4j, + +9.045112476907548e+1 - 1.115537522430261e+3j, + +2.344818070467641e+2 - 4.228020157070496e+2j, + +9.453304067358312e+1 - 2.951294291446048e+2j, + +7.283792954673409e+2 - 1.205646080220011e+5j, + +3.648229059594851e+1 - 1.155509621409682e+2j, + +2.547321630156819e+1 - 2.639500283021502e+1j, + +2.394538338734709e+1 - 5.650522971778156e+0j], + dtype=np.complex128) + +c16_theta = np.array([ + +3.509103608414918 + 8.436198985884374j, + +5.948152268951177 + 3.587457362018322j, + -5.264971343442647 + 16.22022147316793j, + +1.419375897185666 + 10.92536348449672j, + +6.416177699099435 + 1.194122393370139j, + +4.993174737717997 + 5.996881713603942j, + -1.413928462488886 + 13.49772569889275j, + -10.84391707869699 + 19.27744616718165j], + dtype=np.complex128) + +c16_alpha0 = 2.124853710495224e-16 +Cram16Solver = IPFCramSolver(c16_alpha, c16_theta, c16_alpha0) +CRAM16 = Cram16Solver.__call__ + +del c16_alpha, c16_alpha0, c16_theta + +# Coefficients for 48th order IPF Cram + +theta_r = np.array([ + -4.465731934165702e+1, -5.284616241568964e+0, + -8.867715667624458e+0, +3.493013124279215e+0, + +1.564102508858634e+1, +1.742097597385893e+1, + -2.834466755180654e+1, +1.661569367939544e+1, + +8.011836167974721e+0, -2.056267541998229e+0, + +1.449208170441839e+1, +1.853807176907916e+1, + +9.932562704505182e+0, -2.244223871767187e+1, + +8.590014121680897e-1, -1.286192925744479e+1, + +1.164596909542055e+1, +1.806076684783089e+1, + +5.870672154659249e+0, -3.542938819659747e+1, + +1.901323489060250e+1, +1.885508331552577e+1, + -1.734689708174982e+1, +1.316284237125190e+1]) + +theta_i = np.array([ + +6.233225190695437e+1, +4.057499381311059e+1, + +4.325515754166724e+1, +3.281615453173585e+1, + +1.558061616372237e+1, +1.076629305714420e+1, + +5.492841024648724e+1, +1.316994930024688e+1, + +2.780232111309410e+1, +3.794824788914354e+1, + +1.799988210051809e+1, +5.974332563100539e+0, + +2.532823409972962e+1, +5.179633600312162e+1, + +3.536456194294350e+1, +4.600304902833652e+1, + +2.287153304140217e+1, +8.368200580099821e+0, + +3.029700159040121e+1, +5.834381701800013e+1, + +1.194282058271408e+0, +3.583428564427879e+0, + +4.883941101108207e+1, +2.042951874827759e+1]) + +c48_theta = np.array(theta_r + theta_i * 1j, dtype=np.complex128) + +alpha_r = np.array([ + +6.387380733878774e+2, +1.909896179065730e+2, + +4.236195226571914e+2, +4.645770595258726e+2, + +7.765163276752433e+2, +1.907115136768522e+3, + +2.909892685603256e+3, +1.944772206620450e+2, + +1.382799786972332e+5, +5.628442079602433e+3, + +2.151681283794220e+2, +1.324720240514420e+3, + +1.617548476343347e+4, +1.112729040439685e+2, + +1.074624783191125e+2, +8.835727765158191e+1, + +9.354078136054179e+1, +9.418142823531573e+1, + +1.040012390717851e+2, +6.861882624343235e+1, + +8.766654491283722e+1, +1.056007619389650e+2, + +7.738987569039419e+1, +1.041366366475571e+2]) + +alpha_i = np.array([ + -6.743912502859256e+2, -3.973203432721332e+2, + -2.041233768918671e+3, -1.652917287299683e+3, + -1.783617639907328e+4, -5.887068595142284e+4, + -9.953255345514560e+3, -1.427131226068449e+3, + -3.256885197214938e+6, -2.924284515884309e+4, + -1.121774011188224e+3, -6.370088443140973e+4, + -1.008798413156542e+6, -8.837109731680418e+1, + -1.457246116408180e+2, -6.388286188419360e+1, + -2.195424319460237e+2, -6.719055740098035e+2, + -1.693747595553868e+2, -1.177598523430493e+1, + -4.596464999363902e+3, -1.738294585524067e+3, + -4.311715386228984e+1, -2.777743732451969e+2]) + +c48_alpha = np.array(alpha_r + alpha_i * 1j, dtype=np.complex128) + +c48_alpha0 = 2.258038182743983e-47 + +Cram48Solver = IPFCramSolver(c48_alpha, c48_theta, c48_alpha0) + +del c48_alpha, c48_alpha0, c48_theta, alpha_r, alpha_i, theta_r, theta_i + +CRAM48 = Cram48Solver.__call__ diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index 9e3e379d5..d79a03111 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -59,6 +59,7 @@ class DirectReactionRateHelper(ReactionRateHelper): ``"(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)] @@ -194,6 +195,7 @@ class EnergyScoreHelper(EnergyHelper): """ self._tally = Tally() + self._tally.writable = False self._tally.scores = [self.score] def reset(self): @@ -570,6 +572,7 @@ class AveragedFissionYieldHelper(TalliedFissionYieldHelper): func_filter = EnergyFunctionFilter() func_filter.set_data((0, self._upper_energy), (0, self._upper_energy)) weighted_tally = Tally() + weighted_tally.writable = False weighted_tally.scores = ['fission'] weighted_tally.filters = filters + [func_filter] self._weighted_tally = weighted_tally diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index e3a767e57..8eb033783 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -82,6 +82,7 @@ class Operator(TransportOperator): in the previous results. diff_burnable_mats : bool, optional Whether to differentiate burnable materials with multiple instances. + Volumes are divided equally from the original material volume. Default: False. energy_mode : {"energy-deposition", "fission-q"} Indicator for computing system energy. ``"energy-deposition"`` will @@ -309,7 +310,12 @@ class Operator(TransportOperator): # Assign distribmats to cells for cell in self.geometry.get_all_material_cells().values(): if cell.fill in distribmats and cell.num_instances > 1: - cell.fill = [cell.fill.clone() + mat = cell.fill + if mat.volume is None: + raise RuntimeError("Volume not specified for depletable " + "material with ID={}.".format(mat.id)) + mat.volume /= mat.num_instances + cell.fill = [mat.clone() for i in range(cell.num_instances)] def _get_burnable_mats(self): diff --git a/openmc/geometry.py b/openmc/geometry.py index 260bb9e83..5424f30e5 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -88,7 +88,7 @@ class Geometry(object): """ # Create XML representation root_element = ET.Element("geometry") - self.root_universe.create_xml_subelement(root_element) + self.root_universe.create_xml_subelement(root_element, memo=set()) # Sort the elements in the file root_element[:] = sorted(root_element, key=lambda x: ( @@ -272,9 +272,9 @@ class Geometry(object): """ if self.root_universe is not None: - return self.root_universe.get_all_cells() + return self.root_universe.get_all_cells(memo=set()) else: - return [] + return OrderedDict() def get_all_universes(self): """Return all universes in the geometry. @@ -301,7 +301,10 @@ class Geometry(object): instances """ - return self.root_universe.get_all_materials() + if self.root_universe is not None: + return self.root_universe.get_all_materials(memo=set()) + else: + return OrderedDict() def get_all_material_cells(self): """Return all cells filled by a material diff --git a/openmc/lattice.py b/openmc/lattice.py index 4776222da..3377e709e 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -332,7 +332,7 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): return nuclides - def get_all_cells(self): + def get_all_cells(self, memo=None): """Return all cells that are contained within the lattice Returns @@ -342,16 +342,22 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): instances """ - cells = OrderedDict() + + if memo and self in memo: + return cells + + if memo is not None: + memo.add(self) + unique_universes = self.get_unique_universes() for universe_id, universe in unique_universes.items(): - cells.update(universe.get_all_cells()) + cells.update(universe.get_all_cells(memo)) return cells - def get_all_materials(self): + def get_all_materials(self, memo=None): """Return all materials that are contained within the lattice Returns @@ -365,9 +371,9 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): materials = OrderedDict() # Append all Cells in each Cell in the Universe to the dictionary - cells = self.get_all_cells() + cells = self.get_all_cells(memo) for cell_id, cell in cells.items(): - materials.update(cell.get_all_materials()) + materials.update(cell.get_all_materials(memo)) return materials @@ -468,7 +474,7 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): if memo is None: memo = {} - # If no nemoize'd clone exists, instantiate one + # If no memoize'd clone exists, instantiate one if self not in memo: clone = deepcopy(self) clone.id = None @@ -753,15 +759,29 @@ class RectLattice(Lattice): 0 <= idx[1] < self.shape[1] and 0 <= idx[2] < self.shape[2]) - def create_xml_subelement(self, xml_element): + def create_xml_subelement(self, xml_element, memo=None): + """Add the lattice xml representation to an incoming xml element - # Determine if XML element already contains subelement for this Lattice - path = './lattice[@id=\'{0}\']'.format(self._id) - test = xml_element.find(path) + Parameters + ---------- + xml_element : xml.etree.ElementTree.Element + XML element to be added to - # If the element does contain the Lattice subelement, then return - if test is not None: + memo : set or None + A set of object id's representing geometry entities already + written to the xml_element. This parameter is used internally + and should not be specified by users. + + Returns + ------- + None + + """ + # If the element already contains the Lattice subelement, then return + if memo and self in memo: return + if memo is not None: + memo.add(self) lattice_subelement = ET.Element("lattice") lattice_subelement.set("id", str(self._id)) @@ -777,7 +797,7 @@ class RectLattice(Lattice): if self._outer is not None: outer = ET.SubElement(lattice_subelement, "outer") outer.text = '{0}'.format(self._outer._id) - self._outer.create_xml_subelement(xml_element) + self._outer.create_xml_subelement(xml_element, memo) # Export Lattice cell dimensions dimension = ET.SubElement(lattice_subelement, "dimension") @@ -801,7 +821,7 @@ class RectLattice(Lattice): universe_ids += '{0} '.format(universe._id) # Create XML subelement for this Universe - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Add newline character when we reach end of row of cells universe_ids += '\n' @@ -819,7 +839,7 @@ class RectLattice(Lattice): universe_ids += '{0} '.format(universe._id) # Create XML subelement for this Universe - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Add newline character when we reach end of row of cells universe_ids += '\n' @@ -1274,14 +1294,12 @@ class HexLattice(Lattice): else: return g < self.num_rings and 0 <= idx[2] < self.num_axial - def create_xml_subelement(self, xml_element): - # Determine if XML element already contains subelement for this Lattice - path = './hex_lattice[@id=\'{0}\']'.format(self._id) - test = xml_element.find(path) - - # If the element does contain the Lattice subelement, then return - if test is not None: + def create_xml_subelement(self, xml_element, memo=None): + # If this subelement has already been written, return + if memo and self in memo: return + if memo is not None: + memo.add(self) lattice_subelement = ET.Element("hex_lattice") lattice_subelement.set("id", str(self._id)) @@ -1297,7 +1315,7 @@ class HexLattice(Lattice): if self._outer is not None: outer = ET.SubElement(lattice_subelement, "outer") outer.text = '{0}'.format(self._outer._id) - self._outer.create_xml_subelement(xml_element) + self._outer.create_xml_subelement(xml_element, memo) lattice_subelement.set("n_rings", str(self._num_rings)) # If orientation is "x" export it to XML @@ -1319,13 +1337,13 @@ class HexLattice(Lattice): for z in range(self._num_axial): # Initialize the center universe. universe = self._universes[z][-1][0] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Initialize the remaining universes. for r in range(self._num_rings-1): for theta in range(6*(self._num_rings - 1 - r)): universe = self._universes[z][r][theta] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Get a string representation of the universe IDs. slices.append(self._repr_axial_slice(self._universes[z])) @@ -1337,13 +1355,13 @@ class HexLattice(Lattice): else: # Initialize the center universe. universe = self._universes[-1][0] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Initialize the remaining universes. for r in range(self._num_rings - 1): for theta in range(6*(self._num_rings - 1 - r)): universe = self._universes[r][theta] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Get a string representation of the universe IDs. universe_ids = self._repr_axial_slice(self._universes) diff --git a/openmc/lib/settings.py b/openmc/lib/settings.py index 78794d856..275c73a93 100644 --- a/openmc/lib/settings.py +++ b/openmc/lib/settings.py @@ -26,6 +26,7 @@ class _Settings(object): restart_run = _DLLGlobal(c_bool, 'restart_run') run_CE = _DLLGlobal(c_bool, 'run_CE') verbosity = _DLLGlobal(c_int, 'verbosity') + output_summary = _DLLGlobal(c_bool, 'output_summary') @property def run_mode(self): diff --git a/openmc/lib/tally.py b/openmc/lib/tally.py index 97b7437ea..2e8d43ae8 100644 --- a/openmc/lib/tally.py +++ b/openmc/lib/tally.py @@ -53,6 +53,9 @@ _dll.openmc_tally_get_scores.errcheck = _error_handler _dll.openmc_tally_get_type.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_type.restype = c_int _dll.openmc_tally_get_type.errcheck = _error_handler +_dll.openmc_tally_get_writable.argtypes = [c_int32, POINTER(c_bool)] +_dll.openmc_tally_get_writable.restype = c_int +_dll.openmc_tally_get_writable.errcheck = _error_handler _dll.openmc_tally_reset.argtypes = [c_int32] _dll.openmc_tally_reset.restype = c_int _dll.openmc_tally_reset.errcheck = _error_handler @@ -81,6 +84,9 @@ _dll.openmc_tally_set_scores.errcheck = _error_handler _dll.openmc_tally_set_type.argtypes = [c_int32, c_char_p] _dll.openmc_tally_set_type.restype = c_int _dll.openmc_tally_set_type.errcheck = _error_handler +_dll.openmc_tally_set_writable.argtypes = [c_int32, c_bool] +_dll.openmc_tally_set_writable.restype = c_int +_dll.openmc_tally_set_writable.errcheck = _error_handler _dll.tallies_size.restype = c_size_t @@ -344,6 +350,16 @@ class Tally(_FortranObjectWithID): return std_dev + @property + def writable(self): + writable = c_bool() + _dll.openmc_tally_get_writable(self._index, writable) + return writable.value + + @writable.setter + def writable(self, writable): + _dll.openmc_tally_set_writable(self._index, writable) + def reset(self): """Reset results and num_realizations of tally""" _dll.openmc_tally_reset(self._index) diff --git a/openmc/mesh.py b/openmc/mesh.py index 0a8b51c5f..6ef8776fe 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -53,6 +53,12 @@ class MeshBase(IDManagerMixin, metaclass=ABCMeta): else: self._name = '' + def __repr__(self): + string = type(self).__name__ + '\n' + string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) + string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) + return string + @classmethod def from_hdf5(cls, group): """Create mesh from HDF5 group @@ -126,7 +132,10 @@ class RegularMesh(MeshBase): @property def n_dimension(self): - return len(self._dimension) + if self._dimension is not None: + return len(self._dimension) + else: + return None @property def lower_left(self): @@ -187,11 +196,9 @@ class RegularMesh(MeshBase): self._width = width def __repr__(self): - string = 'RegularMesh\n' - string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) - string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) - string += '{0: <16}{1}{2}\n'.format('\tBasis', '=\t', self._dimension) + string = super().__repr__() + string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) + string += '{0: <16}{1}{2}\n'.format('\tMesh Cells', '=\t', self._dimension) string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._lower_left) string += '{0: <16}{1}{2}\n'.format('\tOrigin', '=\t', self._upper_right) string += '{0: <16}{1}{2}\n'.format('\tPixels', '=\t', self._width) @@ -522,6 +529,27 @@ class RectilinearMesh(MeshBase): cv.check_type('mesh z_grid', grid, Iterable, Real) self._z_grid = grid + def __repr__(self): + fmt = '{0: <16}{1}{2}\n' + string = super().__repr__() + string += fmt.format('\tDimensions', '=\t', self.n_dimension) + x_grid_str = str(self._x_grid) if not self._x_grid else len(self._x_grid) + string += fmt.format('\tN X pnts:', '=\t', x_grid_str) + if self._x_grid: + string += fmt.format('\tX Min:', '=\t', self._x_grid[0]) + string += fmt.format('\tX Max:', '=\t', self._x_grid[-1]) + y_grid_str = str(self._y_grid) if not self._y_grid else len(self._y_grid) + string += fmt.format('\tN Y pnts:', '=\t', y_grid_str) + if self._y_grid: + string += fmt.format('\tY Min:', '=\t', self._y_grid[0]) + string += fmt.format('\tY Max:', '=\t', self._y_grid[-1]) + z_grid_str = str(self._z_grid) if not self._z_grid else len(self._z_grid) + string += fmt.format('\tN Z pnts:', '=\t', z_grid_str) + if self._z_grid: + string += fmt.format('\tZ Min:', '=\t', self._z_grid[0]) + string += fmt.format('\tZ Max:', '=\t', self._z_grid[-1]) + return string + @classmethod def from_hdf5(cls, group): mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index 886cc904a..1b1ad0dce 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -18,7 +18,7 @@ GROUP_STRUCTURES = {} .. _CASMO: https://www.studsvik.com/SharepointFiles/CASMO-5%20Development%20and%20Applications.pdf .. _XMAS-172: https://www-nds.iaea.org/wimsd/energy.htm -.. _SHEM-361: https://www.polymtl.ca/merlin/libraries.htm +.. _SHEM-361: https://www.polymtl.ca/merlin/downloads/FP214.pdf .. _activation: https://fispact.ukaea.uk/wiki/Keyword:GETXS .. _CCFE-709: https://fispact.ukaea.uk/wiki/CCFE-709_group_structure .. _UKAEA-1102: https://fispact.ukaea.uk/wiki/UKAEA-1102_group_structure diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index fbf08f85f..83d3178ff 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -986,7 +986,7 @@ class Library(object): xsdata.num_azimuthal = self.num_azimuthal if nuclide != 'total': - xsdata.atomic_weight_ratio = self._nuclides[nuclide][1] + xsdata.atomic_weight_ratio = self._nuclides[nuclide] if subdomain is None: subdomain = 'all' diff --git a/openmc/model/triso.py b/openmc/model/triso.py index 2afc88d64..2552623a0 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -827,13 +827,17 @@ def create_triso_lattice(trisos, lower_left, pitch, shape, background): triso_locations = {idx: [] for idx in indices} for t in trisos: for idx in t.classify(lattice): - if idx in sorted(triso_locations): + if idx in triso_locations: # Create copy of TRISO particle with materials preserved and # different cell/surface IDs - t_copy = copy.deepcopy(t) + t_copy = copy.copy(t) t_copy.id = None t_copy.fill = t.fill - t_copy._surface.id = None + t_copy._surface = openmc.Sphere(r=t._surface.r, + x0=t._surface.x0, + y0=t._surface.y0, + z0=t._surface.z0) + t_copy.region = -t_copy._surface triso_locations[idx].append(t_copy) else: warnings.warn('TRISO particle is partially or completely ' diff --git a/openmc/plots.py b/openmc/plots.py index b4712c902..10d773868 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -173,7 +173,7 @@ class Plot(IDManagerMixin): OpenMC is capable of generating two-dimensional slice plots and three-dimensional voxel plots. Colors that are used in plots can be given as RGB tuples, e.g. (255, 255, 255) would be white, or by a string indicating a - valid `SVG color `_. + valid `SVG color `_. Parameters ---------- diff --git a/openmc/statepoint.py b/openmc/statepoint.py index c9a8f9f9a..5802a74ca 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -375,13 +375,18 @@ class StatePoint(object): for tally_id in tally_ids: group = tallies_group['tally {}'.format(tally_id)] - # Read the number of realizations - n_realizations = group['n_realizations'][()] + # Check if tally is internal and therefore has no data + if group.attrs.get("internal"): + continue # Create Tally object and assign basic properties tally = openmc.Tally(tally_id) tally._sp_filename = self._f.filename tally.name = group['name'][()].decode() if 'name' in group else '' + + # Read the number of realizations + n_realizations = group['n_realizations'][()] + tally.estimator = group['estimator'][()].decode() tally.num_realizations = n_realizations diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index 35afc21dd..6a97e6192 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -272,6 +272,8 @@ class Spatial(metaclass=ABCMeta): distribution = get_text(elem, 'type') if distribution == 'cartesian': return CartesianIndependent.from_xml_element(elem) + elif distribution == 'spherical': + return SphericalIndependent.from_xml_element(elem) elif distribution == 'box' or distribution == 'fission': return Box.from_xml_element(elem) elif distribution == 'point': @@ -281,7 +283,7 @@ class Spatial(metaclass=ABCMeta): class CartesianIndependent(Spatial): """Spatial distribution with independent x, y, and z distributions. - This distribution allows one to specify a coordinates whose x-, y-, and z- + This distribution allows one to specify coordinates whose x-, y-, and z- components are sampled independently from one another. Parameters @@ -304,7 +306,6 @@ class CartesianIndependent(Spatial): """ - def __init__(self, x, y, z): super().__init__() self.x = x @@ -375,6 +376,122 @@ class CartesianIndependent(Spatial): return cls(x, y, z) +class SphericalIndependent(Spatial): + """Spatial distribution represented in spherical coordinates. + + This distribution allows one to specify coordinates whose :math:`r`, + :math:`\theta`, and :math:`\phi` components are sampled independently from + one another and centered on the coordinates (x0, y0, z0). + + Parameters + ---------- + r : openmc.stats.Univariate + Distribution of r-coordinates + theta : openmc.stats.Univariate + Distribution of theta-coordinates (angle relative to the z-axis) + phi : openmc.stats.Univariate + Distribution of phi-coordinates (azimuthal angle) + origin: Iterable of float, optional + coordinates (x0, y0, z0) of the center of the sphere. Defaults to + (0.0, 0.0, 0.0) + + Attributes + ---------- + r : openmc.stats.Univariate + Distribution of r-coordinates + theta : openmc.stats.Univariate + Distribution of theta-coordinates (angle relative to the z-axis) + phi : openmc.stats.Univariate + Distribution of phi-coordinates (azimuthal angle) + origin: Iterable of float, optional + coordinates (x0, y0, z0) of the center of the sphere. Defaults to + (0.0, 0.0, 0.0) + + """ + + def __init__(self, r, theta, phi, origin=(0.0, 0.0, 0.0)): + super().__init__() + self.r = r + self.theta = theta + self.phi = phi + self.origin = origin + + @property + def r(self): + return self._r + + @property + def theta(self): + return self._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 + + @theta.setter + def theta(self, theta): + cv.check_type('theta coordinate', theta, Univariate) + self._theta = theta + + @phi.setter + def phi(self, phi): + cv.check_type('phi coordinate', phi, Univariate) + self._phi = phi + + @origin.setter + def origin(self, origin): + cv.check_type('origin coordinates', origin, Iterable, Real) + origin = np.asarray(origin) + self._origin = origin + + def to_xml_element(self): + """Return XML representation of the spatial distribution + + Returns + ------- + element : xml.etree.ElementTree.Element + XML element containing spatial distribution data + + """ + element = ET.Element('space') + element.set('type', 'spherical') + element.append(self.r.to_xml_element('r')) + element.append(self.theta.to_xml_element('theta')) + element.append(self.phi.to_xml_element('phi')) + element.set("origin", ' '.join(map(str, self.origin))) + return element + + @classmethod + def from_xml_element(cls, elem): + """Generate spatial distribution from an XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.stats.SphericalIndependent + Spatial distribution generated from XML element + + """ + r = Univariate.from_xml_element(elem.find('r')) + theta = Univariate.from_xml_element(elem.find('theta')) + phi = Univariate.from_xml_element(elem.find('phi')) + origin = [float(x) for x in elem.get('origin').split()] + return cls(r, theta, phi, origin=origin) + + class Box(Spatial): """Uniform distribution of coordinates in a rectangular cuboid. diff --git a/openmc/summary.py b/openmc/summary.py index 2ab29c00a..bcb3ba33b 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -97,16 +97,17 @@ class Summary(object): self._macroscopics = name.decode() def _read_geometry(self): - if "dagmc" in self._f['geometry'].attrs.keys(): - return - # Read in and initialize the Materials and Geometry + # Read in and initialize the Materials self._read_materials() - self._read_surfaces() - cell_fills = self._read_cells() - self._read_universes() - self._read_lattices() - self._finalize_geometry(cell_fills) + + # Read native geometry only + if "dagmc" not in self._f['geometry'].attrs.keys(): + self._read_surfaces() + cell_fills = self._read_cells() + self._read_universes() + self._read_lattices() + self._finalize_geometry(cell_fills) def _read_materials(self): for group in self._f['materials'].values(): @@ -153,8 +154,9 @@ class Summary(object): if 'rotation' in group: rotation = group['rotation'][()] - rotation = np.asarray(rotation, dtype=np.int) - cell._rotation = rotation + if rotation.size == 9: + rotation.shape = (3, 3) + cell.rotation = rotation elif fill_type == 'material': cell.temperature = group['temperature'][()] diff --git a/openmc/universe.py b/openmc/universe.py index ee038ebef..cbcba72c4 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -418,7 +418,7 @@ class Universe(IDManagerMixin): return nuclides - def get_all_cells(self): + def get_all_cells(self, memo=None): """Return all cells that are contained within the universe Returns @@ -431,16 +431,22 @@ class Universe(IDManagerMixin): cells = OrderedDict() + if memo and self in memo: + return cells + + if memo is not None: + memo.add(self) + # Add this Universe's cells to the dictionary cells.update(self._cells) # Append all Cells in each Cell in the Universe to the dictionary for cell in self._cells.values(): - cells.update(cell.get_all_cells()) + cells.update(cell.get_all_cells(memo)) return cells - def get_all_materials(self): + def get_all_materials(self, memo=None): """Return all materials that are contained within the universe Returns @@ -454,9 +460,9 @@ class Universe(IDManagerMixin): materials = OrderedDict() # Append all Cells in each Cell in the Universe to the dictionary - cells = self.get_all_cells() + cells = self.get_all_cells(memo) for cell in cells.values(): - materials.update(cell.get_all_materials()) + materials.update(cell.get_all_materials(memo)) return materials @@ -512,19 +518,40 @@ class Universe(IDManagerMixin): return memo[self] - def create_xml_subelement(self, xml_element): + def create_xml_subelement(self, xml_element, memo=None): + """Add the universe xml representation to an incoming xml element + + Parameters + ---------- + xml_element : xml.etree.ElementTree.Element + XML element to be added to + + memo : set or None + A set of object id's representing geometry entities already + written to the xml_element. This parameter is used internally + and should not be specified by users. + + Returns + ------- + None + + """ # Iterate over all Cells for cell_id, cell in self._cells.items(): - path = "./cell[@id='{}']".format(cell_id) - # If the cell was not already written, write it - if xml_element.find(path) is None: - # Create XML subelement for this Cell - cell_element = cell.create_xml_subelement(xml_element) + # If the cell was already written, move on + if memo and cell in memo: + continue - # Append the Universe ID to the subelement and add to Element - cell_element.set("universe", str(self._id)) - xml_element.append(cell_element) + if memo is not None: + memo.add(cell) + + # Create XML subelement for this Cell + cell_element = cell.create_xml_subelement(xml_element, memo) + + # Append the Universe ID to the subelement and add to Element + cell_element.set("universe", str(self._id)) + xml_element.append(cell_element) def _determine_paths(self, path='', instances_only=False): """Count the number of instances for each cell in the universe, and diff --git a/openmc/volume.py b/openmc/volume.py index 7ac4fdd0c..a59fb2acf 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -45,6 +45,8 @@ class VolumeCalculation(object): Lower-left coordinates of bounding box used to sample points upper_right : Iterable of float Upper-right coordinates of bounding box used to sample points + threshold : float + Threshold for the maximum standard deviation of volume in the calculation atoms : dict Dictionary mapping unique IDs of domains to a mapping of nuclides to total number of atoms for each nuclide present in the domain. For @@ -54,12 +56,20 @@ class VolumeCalculation(object): in each domain specified. volumes : dict Dictionary mapping unique IDs of domains to estimated volumes in cm^3. + threshold : float + Threshold for the maxmimum standard deviation of volumes. + trigger_type : {'variance', 'std_dev', 'rel_err'} + Value type used to halt volume calculation + iterations : int + Number of iterations over samples (for calculations with a trigger). """ - def __init__(self, domains, samples, lower_left=None, - upper_right=None): + def __init__(self, domains, samples, lower_left=None, upper_right=None): self._atoms = {} self._volumes = {} + self._threshold = None + self._trigger_type = None + self._iterations = None cv.check_type('domains', domains, Iterable, (openmc.Cell, openmc.Material, openmc.Universe)) @@ -123,6 +133,18 @@ class VolumeCalculation(object): 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 @@ -170,6 +192,26 @@ class VolumeCalculation(object): cv.check_length(name, upper_right, 3) self._upper_right = upper_right + @threshold.setter + def threshold(self, threshold): + name = 'volume std. dev. threshold' + cv.check_type(name, threshold, Real) + cv.check_greater_than(name, threshold, 0.0) + self._threshold = threshold + + @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 + + @iterations.setter + def iterations(self, iterations): + name = 'volume calculation iterations' + cv.check_type(name, iterations, Integral) + cv.check_greater_than(name, iterations, 0) + self._iterations = iterations + @volumes.setter def volumes(self, volumes): cv.check_type('volumes', volumes, Mapping) @@ -180,6 +222,19 @@ class VolumeCalculation(object): cv.check_type('atoms', atoms, Mapping) self._atoms = atoms + def set_trigger(self, threshold, trigger_type): + """Set a trigger on the voulme calculation + + Parameters + ---------- + threshold : float + Threshold for the maxmimum standard deviation of volumes + trigger_type : {'variance', 'std_dev', 'rel_err'} + Value type used to halt volume calculation + """ + self.trigger_type = trigger_type + self.threshold = threshold + @classmethod def from_hdf5(cls, filename): """Load stochastic volume calculation results from HDF5 file. @@ -203,6 +258,10 @@ class VolumeCalculation(object): lower_left = f.attrs['lower_left'] upper_right = f.attrs['upper_right'] + threshold = f.attrs.get('threshold') + trigger_type = f.attrs.get('trigger_type') + iterations = f.attrs.get('iterations', 1) + volumes = {} atoms = {} ids = [] @@ -212,13 +271,12 @@ class VolumeCalculation(object): ids.append(domain_id) group = f[obj_name] volume = ufloat(*group['volume'][()]) + volumes[domain_id] = volume nucnames = group['nuclides'][()] atoms_ = group['atoms'][()] - atom_dict = OrderedDict() for name_i, atoms_i in zip(nucnames, atoms_): atom_dict[name_i.decode()] = ufloat(*atoms_i) - volumes[domain_id] = volume atoms[domain_id] = atom_dict # Instantiate some throw-away domains that are used by the constructor @@ -234,6 +292,11 @@ class VolumeCalculation(object): # Instantiate the class and assign results vol = cls(domains, samples, lower_left, upper_right) + + if trigger_type is not None: + vol.set_trigger(threshold, trigger_type.decode()) + + vol.iterations = iterations vol.volumes = volumes vol.atoms = atoms return vol @@ -278,4 +341,8 @@ class VolumeCalculation(object): ll_elem.text = ' '.join(str(x) for x in self.lower_left) ur_elem = ET.SubElement(element, "upper_right") ur_elem.text = ' '.join(str(x) for x in self.upper_right) + if self.threshold: + trigger_elem = ET.SubElement(element, "threshold") + trigger_elem.set("type", self.trigger_type) + trigger_elem.set("threshold", str(self.threshold)) return element diff --git a/scripts/openmc-plot-mesh-tally b/scripts/openmc-plot-mesh-tally index 183fe35c5..b4ce92587 100755 --- a/scripts/openmc-plot-mesh-tally +++ b/scripts/openmc-plot-mesh-tally @@ -176,8 +176,8 @@ class MeshPlotter(tk.Frame): # Set combobox items if filterType in ['Energy', 'Energyout']: - combobox['values'] = ['{0} to {1}'.format(*f.bins[i:i+2]) - for i in range(len(f.bins) - 1)] + combobox['values'] = ['{} to {}'.format(*ebin) + for ebin in f.bins] else: combobox['values'] = [str(i) for i in f.bins] @@ -210,7 +210,7 @@ class MeshPlotter(tk.Frame): continue elif f.short_name in ['Energy', 'Energyout']: index = self.filterBoxes[f.short_name].current() - ebin = (f.bins[index], f.bins[index + 1]) + ebin = f.bins[index] spec_list.append((type(f), (ebin,))) else: index = self.filterBoxes[f.short_name].current() diff --git a/scripts/openmc-update-inputs b/scripts/openmc-update-inputs index 0d25b5b97..3b4e9a359 100755 --- a/scripts/openmc-update-inputs +++ b/scripts/openmc-update-inputs @@ -298,4 +298,4 @@ if __name__ == '__main__': move(fname, fname + '.original') # Write a new geometry file. - tree.write(fname) + tree.write(fname, xml_declaration=True) diff --git a/setup.py b/setup.py index aff7834d7..99db83148 100755 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ kwargs = { 'pandas', 'lxml', 'uncertainties' ], 'extras_require': { - 'test': ['pytest', 'pytest-cov'], + 'test': ['pytest', 'pytest-cov', 'colorama'], 'vtk': ['vtk'], }, } diff --git a/src/cell.cpp b/src/cell.cpp index 3a7a2598f..94bae32eb 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -1,8 +1,10 @@ #include "openmc/cell.h" +#include #include #include +#include #include #include #include @@ -305,6 +307,10 @@ CSGCell::CSGCell(pugi::xml_node cell_node) if (fill_present) { fill_ = std::stoi(get_node_value(cell_node, "fill")); + if (fill_ == universe_) { + fatal_error("Cell " + std::to_string(id_) + + " is filled with the same universe that it is contained in."); + } } else { fill_ = C_NONE; } @@ -438,35 +444,39 @@ CSGCell::CSGCell(pugi::xml_node cell_node) } auto rot {get_node_array(cell_node, "rotation")}; - if (rot.size() != 3) { + if (rot.size() != 3 && rot.size() != 9) { std::stringstream err_msg; err_msg << "Non-3D rotation vector applied to cell " << id_; fatal_error(err_msg); } - // Store the rotation angles. - rotation_.reserve(12); - rotation_.push_back(rot[0]); - rotation_.push_back(rot[1]); - rotation_.push_back(rot[2]); - // Compute and store the rotation matrix. - auto phi = -rot[0] * PI / 180.0; - auto theta = -rot[1] * PI / 180.0; - auto psi = -rot[2] * PI / 180.0; - rotation_.push_back(std::cos(theta) * std::cos(psi)); - rotation_.push_back(-std::cos(phi) * std::sin(psi) - + std::sin(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::sin(phi) * std::sin(psi) - + std::cos(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::cos(theta) * std::sin(psi)); - rotation_.push_back(std::cos(phi) * std::cos(psi) - + std::sin(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(phi) * std::cos(psi) - + std::cos(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(theta)); - rotation_.push_back(std::sin(phi) * std::cos(theta)); - rotation_.push_back(std::cos(phi) * std::cos(theta)); + rotation_.reserve(rot.size() == 9 ? 9 : 12); + if (rot.size() == 3) { + double phi = -rot[0] * PI / 180.0; + double theta = -rot[1] * PI / 180.0; + double psi = -rot[2] * PI / 180.0; + rotation_.push_back(std::cos(theta) * std::cos(psi)); + rotation_.push_back(-std::cos(phi) * std::sin(psi) + + std::sin(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::sin(phi) * std::sin(psi) + + std::cos(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::cos(theta) * std::sin(psi)); + rotation_.push_back(std::cos(phi) * std::cos(psi) + + std::sin(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(phi) * std::cos(psi) + + std::cos(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(theta)); + rotation_.push_back(std::sin(phi) * std::cos(theta)); + rotation_.push_back(std::cos(phi) * std::cos(theta)); + + // When user specifies angles, write them at end of vector + rotation_.push_back(rot[0]); + rotation_.push_back(rot[1]); + rotation_.push_back(rot[2]); + } else { + std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_)); + } } } @@ -578,8 +588,12 @@ CSGCell::to_hdf5(hid_t cell_group) const write_dataset(group, "translation", translation_); } if (!rotation_.empty()) { - std::array rot {rotation_[0], rotation_[1], rotation_[2]}; - write_dataset(group, "rotation", rot); + if (rotation_.size() == 12) { + std::array rot {rotation_[9], rotation_[10], rotation_[11]}; + write_dataset(group, "rotation", rot); + } else { + write_dataset(group, "rotation", rotation_); + } } } else if (type_ == FILL_LATTICE) { diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index 3c29dd8e6..6245bca9f 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -155,7 +155,8 @@ void read_cross_sections_xml() if (settings::run_CE) { read_ce_cross_sections_xml(); } else { - read_mg_cross_sections_header(); + data::mg.read_header(settings::path_cross_sections); + put_mgxs_header_data_to_globals(); } // Establish mapping between (type, material) and index in libraries diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 04d4f08c1..9d14c1b86 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -268,14 +268,12 @@ void load_dagmc_geometry() std::string cmp_str = mat_value; to_lower(cmp_str); - if (cmp_str.find("graveyard") != std::string::npos) { + if (cmp_str == "graveyard") { graveyard = vol_handle; } // material void checks - if (cmp_str.find("void") != std::string::npos || - cmp_str.find("vacuum") != std::string::npos || - cmp_str.find("graveyard") != std::string::npos) { + if (cmp_str == "void" || cmp_str == "vacuum" || cmp_str == "graveyard") { c->material_.push_back(MATERIAL_VOID); } else { if (using_uwuw) { diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp index d4a728c71..c388254b6 100644 --- a/src/distribution_multi.cpp +++ b/src/distribution_multi.cpp @@ -61,6 +61,12 @@ Direction PolarAzimuthal::sample() const // Sample azimuthal angle double phi = phi_->sample(); + + // If the reference direction is along the z-axis, rotate the aziumthal angle + // to match spherical coordinate conventions. + // TODO: apply this change directly to rotate_angle + if (u_ref_.x == 0 && u_ref_.y == 0) phi += 0.5*PI; + return rotate_angle(u_ref_, mu, &phi); } diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp index 15098407b..e92601016 100644 --- a/src/distribution_spatial.cpp +++ b/src/distribution_spatial.cpp @@ -51,6 +51,73 @@ Position CartesianIndependent::sample() const return {x_->sample(), y_->sample(), z_->sample()}; } +//============================================================================== +// SphericalIndependent implementation +//============================================================================== + +SphericalIndependent::SphericalIndependent(pugi::xml_node node) +{ + // Read distribution for r-coordinate + if (check_for_node(node, "r")) { + pugi::xml_node node_dist = node.child("r"); + r_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at r=0 + double x[] {0.0}; + double p[] {1.0}; + r_ = std::make_unique(x, p, 1); + } + + // Read distribution for theta-coordinate + if (check_for_node(node, "theta")) { + pugi::xml_node node_dist = node.child("theta"); + theta_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at theta=0 + double x[] {0.0}; + double p[] {1.0}; + theta_ = std::make_unique(x, p, 1); + } + + // Read distribution for phi-coordinate + if (check_for_node(node, "phi")) { + pugi::xml_node node_dist = node.child("phi"); + phi_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at phi=0 + double x[] {0.0}; + double p[] {1.0}; + phi_ = std::make_unique(x, p, 1); + } + + // Read sphere center coordinates + if (check_for_node(node, "origin")) { + auto origin = get_node_array(node, "origin"); + if (origin.size() == 3) { + origin_ = origin; + } else { + std::stringstream err_msg; + err_msg << "Origin for spherical source distribution must be length 3"; + fatal_error(err_msg); + } + } else { + // If no coordinates were specified, default to (0, 0, 0) + origin_ = {0.0, 0.0, 0.0}; + } + +} + +Position SphericalIndependent::sample() const +{ + double r = r_->sample(); + double theta = theta_->sample(); + double phi = phi_->sample(); + double x = r*sin(theta)*cos(phi) + origin_.x; + double y = r*sin(theta)*sin(phi) + origin_.y; + double z = r*cos(theta) + origin_.z; + return {x, y, z}; +} + //============================================================================== // SpatialBox implementation //============================================================================== diff --git a/src/eigenvalue.cpp b/src/eigenvalue.cpp index a0b7f82c5..894157c5b 100644 --- a/src/eigenvalue.cpp +++ b/src/eigenvalue.cpp @@ -572,8 +572,9 @@ void ufs_count_sites() // distributed so that effectively the production of fission sites is not // biased - auto s = xt::view(simulation::source_frac, xt::all()); - s = simulation::ufs_mesh->volume_frac_; + std::size_t n = simulation::ufs_mesh->n_bins(); + double vol_frac = simulation::ufs_mesh->volume_frac_; + simulation::source_frac = xt::xtensor({n}, vol_frac); } else { // count number of source sites in each ufs mesh cell diff --git a/src/finalize.cpp b/src/finalize.cpp index 3de20d6d0..16ff0fbcc 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -135,6 +135,10 @@ int openmc_finalize() int openmc_reset() { + + model::universe_cell_counts.clear(); + model::universe_level_counts.clear(); + for (auto& t : model::tallies) { t->reset(); } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index d195a9de3..5ebee4aca 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -23,6 +23,21 @@ namespace openmc { +namespace model { + std::unordered_map> universe_cell_counts; + std::unordered_map universe_level_counts; +} // namespace model + + +// adds the cell counts of universe b to universe a +void update_universe_cell_count(int32_t a, int32_t b) { + auto& universe_a_counts = model::universe_cell_counts[a]; + const auto& universe_b_counts = model::universe_cell_counts[b]; + for (const auto& it : universe_b_counts) { + universe_a_counts[it.first] += it.second; + } +} + void read_geometry_xml() { #ifdef DAGMC @@ -395,19 +410,29 @@ prepare_distribcell() void count_cell_instances(int32_t univ_indx) { - for (int32_t cell_indx : model::universes[univ_indx]->cells_) { - Cell& c = *model::cells[cell_indx]; - ++c.n_instances_; - if (c.type_ == FILL_UNIVERSE) { - // This cell contains another universe. Recurse into that universe. - count_cell_instances(c.fill_); + const auto univ_counts = model::universe_cell_counts.find(univ_indx); + if (univ_counts != model::universe_cell_counts.end()) { + for (const auto& it : univ_counts->second) { + model::cells[it.first]->n_instances_ += it.second; + } + } else { + for (int32_t cell_indx : model::universes[univ_indx]->cells_) { + Cell& c = *model::cells[cell_indx]; + ++c.n_instances_; + model::universe_cell_counts[univ_indx][cell_indx] += 1; - } else if (c.type_ == FILL_LATTICE) { - // This cell contains a lattice. Recurse into the lattice universes. - Lattice& lat = *model::lattices[c.fill_]; - for (auto it = lat.begin(); it != lat.end(); ++it) { - count_cell_instances(*it); + if (c.type_ == FILL_UNIVERSE) { + // This cell contains another universe. Recurse into that universe. + count_cell_instances(c.fill_); + update_universe_cell_count(univ_indx, c.fill_); + } else if (c.type_ == FILL_LATTICE) { + // This cell contains a lattice. Recurse into the lattice universes. + Lattice& lat = *model::lattices[c.fill_]; + for (auto it = lat.begin(); it != lat.end(); ++it) { + count_cell_instances(*it); + update_universe_cell_count(univ_indx, *it); + } } } } @@ -529,6 +554,12 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) int maximum_levels(int32_t univ) { + + const auto level_count = model::universe_level_counts.find(univ); + if (level_count != model::universe_level_counts.end()) { + return level_count->second; + } + int levels_below {0}; for (int32_t cell_indx : model::universes[univ]->cells_) { @@ -546,6 +577,7 @@ maximum_levels(int32_t univ) } ++levels_below; + model::universe_level_counts[univ] = levels_below; return levels_below; } diff --git a/src/initialize.cpp b/src/initialize.cpp index fd524a2de..460db2436 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -260,8 +260,9 @@ void read_input_xml() read_ce_cross_sections(nuc_temps, thermal_temps); } else { // Create material macroscopic data for MGXS - read_mgxs(); - create_macro_xs(); + set_mg_interface_nuclides_and_temps(); + data::mg.init(); + mark_fissionable_mgxs_materials(); } simulation::time_read_xs.stop(); } diff --git a/src/lattice.cpp b/src/lattice.cpp index 6f10ed358..092ff3d11 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -895,8 +895,12 @@ HexLattice::get_indices(Position r, Direction u) const Position r_t = get_local_position(r, i_xyz); // calculate distance double d = r_t.x*r_t.x + r_t.y*r_t.y; - // check for coincidence - bool on_boundary = coincident(d, d_min); + // check for coincidence. Because the numerical error incurred + // in hex geometry is higher than other geometries, the relative + // coincidence is checked here so that coincidence is successfully + // detected on large hex lattice with particles far from the origin + // which have rounding errors larger than the FP_COINCIDENT thresdhold. + bool on_boundary = coincident(1.0, d_min/d); if (d < d_min || on_boundary) { // normalize r_t and find dot product r_t /= std::sqrt(d); diff --git a/src/material.cpp b/src/material.cpp index 685fd1da2..a5bc3dc13 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -368,7 +368,7 @@ void Material::normalize_density() // determine atomic weight ratio int i_nuc = nuclide_[i]; double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::nuclides_MG[i_nuc].awr; + data::nuclides[i_nuc]->awr_ : data::mg.nuclides_[i_nuc].awr; // if given weight percent, convert all values so that they are divided // by awr. thus, when a sum is done over the values, it's actually @@ -388,7 +388,7 @@ void Material::normalize_density() for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::nuclides_MG[i_nuc].awr; + data::nuclides[i_nuc]->awr_ : data::mg.nuclides_[i_nuc].awr; sum_percent += atom_density_(i)*awr; } sum_percent = 1.0 / sum_percent; @@ -726,7 +726,7 @@ void Material::init_bremsstrahlung() void Material::init_nuclide_index() { int n = settings::run_CE ? - data::nuclides.size() : data::nuclides_MG.size(); + data::nuclides.size() : data::mg.nuclides_.size(); mat_nuclide_index_.resize(n); std::fill(mat_nuclide_index_.begin(), mat_nuclide_index_.end(), C_NONE); for (int i = 0; i < nuclide_.size(); ++i) { @@ -873,8 +873,8 @@ void Material::set_id(int32_t id) // If no ID specified, auto-assign next ID in sequence if (id == -1) { id = 0; - for (const auto& f : model::materials) { - id = std::max(id, f->id_); + for (const auto& m : model::materials) { + id = std::max(id, m->id_); } ++id; } @@ -994,11 +994,11 @@ void Material::to_hdf5(hid_t group) const } else { for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; - if (data::nuclides_MG[i_nuc].awr != MACROSCOPIC_AWR) { - nuc_names.push_back(data::nuclides_MG[i_nuc].name); + if (data::mg.nuclides_[i_nuc].awr != MACROSCOPIC_AWR) { + nuc_names.push_back(data::mg.nuclides_[i_nuc].name); nuc_densities.push_back(atom_density_(i)); } else { - macro_names.push_back(data::nuclides_MG[i_nuc].name); + macro_names.push_back(data::mg.nuclides_[i_nuc].name); } } } diff --git a/src/math_functions.cpp b/src/math_functions.cpp index ec5d64eac..7525a7ddd 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -665,6 +665,12 @@ Direction rotate_angle(Direction u, double mu, const double* phi) return {mu*u.x + a*(u.x*u.y*cosphi + u.z*sinphi) / b, mu*u.y - a*b*cosphi, mu*u.z + a*(u.y*u.z*cosphi - u.x*sinphi) / b}; + // TODO: use the following code to make PolarAzimuthal distributions match + // spherical coordinate conventions. Remove the related fixup code in + // PolarAzimuthal::sample. + //return {mu*u.x + a*(-u.x*u.y*sinphi + u.z*cosphi) / b, + // mu*u.y + a*b*sinphi, + // mu*u.z - a*(u.y*u.z*sinphi + u.x*cosphi) / b}; } } diff --git a/src/mesh.cpp b/src/mesh.cpp index fcdc815cb..f679c402a 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -150,13 +150,16 @@ RegularMesh::RegularMesh(pugi::xml_node node) "the coordinates on a tally mesh."); } - // Set width and upper right coordinate - width_ = xt::eval((upper_right_ - lower_left_) / shape_); + // Set width + if (shape_.size() > 0) { + width_ = xt::eval((upper_right_ - lower_left_) / shape_); + } } else { fatal_error("Must specify either and on a mesh."); } - if (shape_.dimension() > 0) { + // Make sure lower_left and dimension match + if (shape_.size() > 0) { if (shape_.size() != lower_left_.size()) { fatal_error("Number of entries on must be the same " "as the number of entries on ."); @@ -524,6 +527,14 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } r1 = r; + // The TINY_BIT offsets above mean that the preceding logic cannot always find + // the correct ijk0 and ijk1 indices. For tracks shorter than 2*TINY_BIT, just + // assume the track lies in only one mesh bin. These tracks are very short so + // any error caused by this assumption will be small. + if (total_distance < 2*TINY_BIT) { + for (int i = 0; i < n; ++i) ijk0[i] = ijk1[i]; + } + // ======================================================================== // Find which mesh cells are traversed and the length of each traversal. @@ -901,6 +912,14 @@ void RectilinearMesh::bins_crossed(const Particle* p, std::vector& bins, } r1 = r; + // The TINY_BIT offsets above mean that the preceding logic cannot always find + // the correct ijk0 and ijk1 indices. For tracks shorter than 2*TINY_BIT, just + // assume the track lies in only one mesh bin. These tracks are very short so + // any error caused by this assumption will be small. + if (total_distance < 2*TINY_BIT) { + for (int i = 0; i < 3; ++i) ijk0[i] = ijk1[i]; + } + // ======================================================================== // Find which mesh cells are traversed and the length of each traversal. diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 1fca66308..0dd8c73cc 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -24,18 +24,6 @@ namespace openmc { -//============================================================================== -// Global variables -//============================================================================== - -namespace data { - -// Storage for the MGXS data -std::vector nuclides_MG; -std::vector macro_xs; - -} // namespace data - //============================================================================== // Mgxs base-class methods //============================================================================== @@ -53,8 +41,6 @@ Mgxs::init(const std::string& in_name, double in_awr, kTs = xt::adapt(in_kTs); fissionable = in_fissionable; scatter_format = in_scatter_format; - num_groups = data::num_energy_groups; - num_delayed_groups = data::num_delayed_groups; xs.resize(in_kTs.size()); is_isotropic = in_is_isotropic; n_pol = in_polar.size(); @@ -284,7 +270,10 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, const std::vector& temperature, //============================================================================== -Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature) +Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature, + int num_group, int num_delay) : + num_groups(num_group), + num_delayed_groups(num_delay) { // Call generic data gathering routine (will populate the metadata) int order_data; @@ -299,7 +288,8 @@ Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature) // Load the more specific XsData information for (int t = 0; t < temps_to_read.size(); t++) { - xs[t] = XsData(fissionable, final_scatter_format, n_pol, n_azi); + xs[t] = XsData(fissionable, final_scatter_format, n_pol, n_azi, + num_groups, num_delayed_groups); // Get the temperature as a string and then open the HDF5 group std::string temp_str = std::to_string(temps_to_read[t]) + "K"; hid_t xsdata_grp = open_group(xs_id, temp_str.c_str()); @@ -317,7 +307,10 @@ Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature) //============================================================================== Mgxs::Mgxs(const std::string& in_name, const std::vector& mat_kTs, - const std::vector& micros, const std::vector& atom_densities) + const std::vector& micros, const std::vector& atom_densities, + int num_group, int num_delay) : + num_groups(num_group), + num_delayed_groups(num_delay) { // Get the minimum data needed to initialize: // Dont need awr, but lets just initialize it anyways @@ -340,7 +333,7 @@ Mgxs::Mgxs(const std::string& in_name, const std::vector& mat_kTs, // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { xs[t] = XsData(in_fissionable, in_scatter_format, in_polar.size(), - in_azimuthal.size()); + in_azimuthal.size(), num_groups, num_delayed_groups); // Find the right temperature index to use double temp_desired = mat_kTs[t]; @@ -548,8 +541,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) double nu_fission = xs_t->nu_fission(cache[tid].a, gin); // Find the probability of having a prompt neutron - double prob_prompt = - xs_t->prompt_nu_fission(cache[tid].a, gin); + double prob_prompt = xs_t->prompt_nu_fission(cache[tid].a, gin); // sample random numbers double xi_pd = prn() * nu_fission; @@ -563,36 +555,29 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) dg = -1; // sample the outgoing energy group - gout = 0; - double prob_gout = - xs_t->chi_prompt(cache[tid].a, gin, gout); - while (prob_gout < xi_gout) { - gout++; + double prob_gout = 0.; + for (gout = 0; gout < num_groups; ++gout) { prob_gout += xs_t->chi_prompt(cache[tid].a, gin, gout); + if (xi_gout < prob_gout) break; } } else { // the neutron is delayed // get the delayed group - dg = 0; - while (xi_pd >= prob_prompt) { - dg++; - prob_prompt += - xs_t->delayed_nu_fission(cache[tid].a, dg, gin); + for (dg = 0; dg < num_delayed_groups; ++dg) { + prob_prompt += xs_t->delayed_nu_fission(cache[tid].a, dg, gin); + if (xi_pd < prob_prompt) break; } // adjust dg in case of round-off error dg = std::min(dg, num_delayed_groups - 1); // sample the outgoing energy group - gout = 0; - double prob_gout = - xs_t->chi_delayed(cache[tid].a, dg, gin, gout); - while (prob_gout < xi_gout) { - gout++; - prob_gout += - xs_t->chi_delayed(cache[tid].a, dg, gin, gout); + double prob_gout = 0.; + for (gout = 0; gout < num_groups; ++gout) { + prob_gout += xs_t->chi_delayed(cache[tid].a, dg, gin, gout); + if (xi_gout < prob_gout) break; } } } @@ -615,8 +600,7 @@ Mgxs::sample_scatter(int gin, int& gout, double& mu, double& wgt) //============================================================================== void -Mgxs::calculate_xs(int gin, double sqrtkT, Direction u, - double& total_xs, double& abs_xs, double& nu_fiss_xs) +Mgxs::calculate_xs(Particle& p) { // Set our indices #ifdef _OPENMP @@ -624,13 +608,13 @@ Mgxs::calculate_xs(int gin, double sqrtkT, Direction u, #else int tid = 0; #endif - set_temperature_index(sqrtkT); - set_angle_index(u); + set_temperature_index(p.sqrtkT_); + set_angle_index(p.u_local()); XsData* xs_t = &xs[cache[tid].t]; - total_xs = xs_t->total(cache[tid].a, gin); - abs_xs = xs_t->absorption(cache[tid].a, gin); - - nu_fiss_xs = fissionable ? xs_t->nu_fission(cache[tid].a, gin) : 0.; + p.macro_xs_.total = xs_t->total(cache[tid].a, p.g_); + p.macro_xs_.absorption = xs_t->absorption(cache[tid].a, p.g_); + p.macro_xs_.nu_fission = + fissionable ? xs_t->nu_fission(cache[tid].a, p.g_) : 0.; } //============================================================================== diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 29e5e8b36..936eeb31f 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -18,42 +18,53 @@ namespace openmc { -//============================================================================== -// Global variable definitions -//============================================================================== - -namespace data { - -int num_energy_groups; -int num_delayed_groups; -std::vector energy_bins; -std::vector energy_bin_avg; -std::vector rev_energy_bins; - -} // namesapce data - //============================================================================== // Mgxs data loading interface methods //============================================================================== -void read_mgxs() +namespace data { + MgxsInterface mg; +} + +MgxsInterface::MgxsInterface(const std::string& path_cross_sections, + const std::vector xs_to_read, + const std::vector> xs_temps) { + read_header(path_cross_sections); + set_nuclides_and_temperatures(xs_to_read, xs_temps); + init(); +} + +void MgxsInterface::set_nuclides_and_temperatures( + std::vector xs_to_read, + std::vector> xs_temps) +{ + // Check to remove all duplicates + xs_to_read_ = xs_to_read; + xs_temps_to_read_ = xs_temps; + if (xs_to_read_.size() != xs_temps.size()) + fatal_error("The list of macro XS temperatures to read does not " + "correspond in length to the number of XS names. "); +} + +void MgxsInterface::init() +{ + + // Check that at least some data was set to be read + if (xs_to_read_.size() == 0) + warning("No MGXS nuclides were set to be read."); + // Check if MGXS Library exists - if (!file_exists(settings::path_cross_sections)) { + if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file - fatal_error("Cross sections HDF5 file '" + settings::path_cross_sections + + fatal_error("Cross sections HDF5 file '" + cross_sections_path_ + "' does not exist."); } write_message("Loading cross section data...", 5); - // Get temperatures - std::vector> nuc_temps(data::nuclide_map.size()); - std::vector> dummy; - get_temperatures(nuc_temps, dummy); - // Open file for reading - hid_t file_id = file_open(settings::path_cross_sections, 'r'); + hid_t file_id = file_open(cross_sections_path_, 'r'); // Read filetype std::string type; @@ -73,38 +84,18 @@ void read_mgxs() // ========================================================================== // READ ALL MGXS CROSS SECTION TABLES - - std::unordered_set already_read; - - // Build vector of nuclide names - std::vector nuclide_names(data::nuclide_map.size()); - for (const auto& kv : data::nuclide_map) { - nuclide_names[kv.second] = kv.first; - } - - // Loop over all files - for (const auto& mat : model::materials) { - for (int i_nuc : mat->nuclide_) { - std::string& name = nuclide_names[i_nuc]; - - if (already_read.find(name) == already_read.end()) { - add_mgxs(file_id, name, nuc_temps[i_nuc]); - already_read.insert(name); - } - - if (data::nuclides_MG[i_nuc].fissionable) { - mat->fissionable_ = true; - } - } - } + for (unsigned i_nuc=0; i_nuc& temperature) { write_message("Loading " + std::string(name) + " data...", 6); @@ -118,13 +109,14 @@ add_mgxs(hid_t file_id, const std::string& name, + "provided MGXS Library"); } - data::nuclides_MG.emplace_back(xs_grp, temperature); + nuclides_.emplace_back(xs_grp, temperature, num_energy_groups_, + num_delayed_groups_); close_group(xs_grp); } //============================================================================== -void create_macro_xs() +void MgxsInterface::create_macro_xs() { // Get temperatures to read for each material auto kTs = get_mat_kTs(); @@ -140,24 +132,25 @@ void create_macro_xs() std::vector atom_densities(mat->atom_density_.begin(), mat->atom_density_.end()); - // Build array of pointers to nuclides_MG's Mgxs objects needed for this + // Build array of pointers to nuclides's Mgxs objects needed for this // material std::vector mgxs_ptr; for (int i_nuclide : mat->nuclide_) { - mgxs_ptr.push_back(&data::nuclides_MG[i_nuclide]); + mgxs_ptr.push_back(&nuclides_[i_nuclide]); } - data::macro_xs.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities); + macro_xs_.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities, + num_energy_groups_, num_delayed_groups_); } else { // Preserve the ordering of materials by including a blank entry - data::macro_xs.emplace_back(); + macro_xs_.emplace_back(); } } } //============================================================================== -std::vector> get_mat_kTs() +std::vector> MgxsInterface::get_mat_kTs() { std::vector> kTs(model::materials.size()); @@ -186,134 +179,112 @@ std::vector> get_mat_kTs() //============================================================================== -void read_mg_cross_sections_header() +void MgxsInterface::read_header(const std::string& path_cross_sections) { + // Save name of HDF5 file to be read to struct data + cross_sections_path_ = path_cross_sections; + // Check if MGXS Library exists - if (!file_exists(settings::path_cross_sections)) { + if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file - fatal_error("Cross sections HDF5 file '" + settings::path_cross_sections + + fatal_error("Cross sections HDF5 file '" + cross_sections_path_ + "' does not exist."); } write_message("Reading cross sections HDF5 file...", 5); // Open file for reading - hid_t file_id = file_open(settings::path_cross_sections, 'r', true); + hid_t file_id = file_open(cross_sections_path_, 'r', true); ensure_exists(file_id, "energy_groups", true); - read_attribute(file_id, "energy_groups", data::num_energy_groups); + read_attribute(file_id, "energy_groups", num_energy_groups_); if (attribute_exists(file_id, "delayed_groups")) { - read_attribute(file_id, "delayed_groups", data::num_delayed_groups); + read_attribute(file_id, "delayed_groups", num_delayed_groups_); } else { - data::num_delayed_groups = 0; + num_delayed_groups_ = 0; } ensure_exists(file_id, "group structure", true); - read_attribute(file_id, "group structure", data::rev_energy_bins); + read_attribute(file_id, "group structure", rev_energy_bins_); // Reverse energy bins - std::copy(data::rev_energy_bins.crbegin(), data::rev_energy_bins.crend(), - std::back_inserter(data::energy_bins)); + std::copy(rev_energy_bins_.crbegin(), rev_energy_bins_.crend(), + std::back_inserter(energy_bins_)); // Create average energies - for (int i = 0; i < data::energy_bins.size() - 1; ++i) { - data::energy_bin_avg.push_back(0.5*(data::energy_bins[i] + data::energy_bins[i+1])); + for (int i = 0; i < energy_bins_.size() - 1; ++i) { + energy_bin_avg_.push_back(0.5* + (energy_bins_[i] + energy_bins_[i+1])); } // Add entries into libraries for MG data - auto names = group_names(file_id); - if (names.empty()) { + xs_names_ = group_names(file_id); + if (xs_names_.empty()) { fatal_error("At least one MGXS data set must be present in mgxs " "library file!"); } - for (auto& name : names) { - Library lib {}; - lib.type_ = Library::Type::neutron; - lib.materials_.push_back(name); - data::libraries.push_back(lib); - } - - // Get the minimum and maximum energies - int neutron = static_cast(Particle::Type::neutron); - data::energy_min[neutron] = data::energy_bins.back(); - data::energy_max[neutron] = data::energy_bins.front(); - // Close MGXS HDF5 file file_close(file_id); } -//============================================================================== -// Mgxs tracking/transport/tallying interface methods -//============================================================================== - -void -calculate_xs_c(int i_mat, int gin, double sqrtkT, Direction u, - double& total_xs, double& abs_xs, double& nu_fiss_xs) +void put_mgxs_header_data_to_globals() { - data::macro_xs[i_mat].calculate_xs(gin - 1, sqrtkT, u, total_xs, abs_xs, - nu_fiss_xs); -} + // Get the minimum and maximum energies + int neutron = static_cast(Particle::Type::neutron); + data::energy_min[neutron] = data::mg.energy_bins_.back(); + data::energy_max[neutron] = data::mg.energy_bins_.front(); -//============================================================================== - -double -get_nuclide_xs(int index, int xstype, int gin, const int* gout, - const double* mu, const int* dg) -{ - int gout_c; - const int* gout_c_p; - if (gout != nullptr) { - gout_c = *gout - 1; - gout_c_p = &gout_c; - } else { - gout_c_p = gout; + // Save available XS names to library list, so that when + // materials are read, the specified mgxs can be confirmed + // as present + for (auto& name : data::mg.xs_names_) { + Library lib {}; + lib.type_ = Library::Type::neutron; + lib.materials_.push_back(name); + data::libraries.push_back(lib); } - return data::nuclides_MG[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); } -//============================================================================== - -double -get_macro_xs(int index, int xstype, int gin, const int* gout, - const double* mu, const int* dg) +void set_mg_interface_nuclides_and_temps() { - int gout_c; - const int* gout_c_p; - if (gout != nullptr) { - gout_c = *gout - 1; - gout_c_p = &gout_c; - } else { - gout_c_p = gout; + // Get temperatures from global data + std::vector> nuc_temps(data::nuclide_map.size()); + std::vector> dummy; + get_temperatures(nuc_temps, dummy); + + // Build vector of nuclide names which are to be read + std::vector nuclide_names(data::nuclide_map.size()); + for (const auto& kv : data::nuclide_map) { + nuclide_names[kv.second] = kv.first; + } + + std::unordered_set already_read; + + // Loop over materials to find xs and temperature to be read + for (const auto& mat : model::materials) { + for (int i_nuc : mat->nuclide_) { + std::string& name = nuclide_names[i_nuc]; + + if (already_read.find(name) == already_read.end()) { + data::mg.xs_to_read_.push_back(name); + data::mg.xs_temps_to_read_.push_back(nuc_temps[i_nuc]); + already_read.insert(name); + } + } } - return data::macro_xs[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); } -//============================================================================== -// General Mgxs methods -//============================================================================== - -void -get_name_c(int index, int name_len, char* name) +void mark_fissionable_mgxs_materials() { - // First blank out our input string - std::string str(name_len - 1, ' '); - std::strcpy(name, str.c_str()); - - // Now get the data and copy to the C-string - str = data::nuclides_MG[index - 1].name; - std::strcpy(name, str.c_str()); - - // Finally, remove the null terminator - name[std::strlen(name)] = ' '; -} - -//============================================================================== - -double -get_awr_c(int index) -{ - return data::nuclides_MG[index - 1].awr; + // Loop over all files + for (const auto& mat : model::materials) { + for (int i_nuc : mat->nuclide_) { + if (data::mg.nuclides_[i_nuc].fissionable) { + mat->fissionable_ = true; + } + } + } } } // namespace openmc diff --git a/src/output.cpp b/src/output.cpp index 40cd1dbfe..899bce86e 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -638,6 +638,16 @@ write_tallies() for (auto i_tally = 0; i_tally < model::tallies.size(); ++i_tally) { const auto& tally {*model::tallies[i_tally]}; + // Write header block. + std::string tally_header("TALLY " + std::to_string(tally.id_)); + if (!tally.name_.empty()) tally_header += ": " + tally.name_; + tallies_out << header(tally_header) << "\n\n"; + + if (!tally.writable_) { + tallies_out << " Internal\n\n"; + continue; + } + // Calculate t-value for confidence intervals double t_value = 1; if (settings::confidence_intervals) { @@ -645,11 +655,6 @@ write_tallies() t_value = t_percentile(1 - alpha*0.5, tally.n_realizations_ - 1); } - // Write header block. - std::string tally_header("TALLY " + std::to_string(tally.id_)); - if (!tally.name_.empty()) tally_header += ": " + tally.name_; - tallies_out << header(tally_header) << "\n\n"; - // Write derivative information. if (tally.deriv_ != C_NONE) { const auto& deriv {model::tally_derivs[tally.deriv_]}; @@ -705,7 +710,7 @@ write_tallies() << data::nuclides[i_nuclide]->name_ << "\n"; } else { tallies_out << std::string(indent+1, ' ') - << data::nuclides_MG[i_nuclide].name << "\n"; + << data::mg.nuclides_[i_nuclide].name << "\n"; } } diff --git a/src/particle.cpp b/src/particle.cpp index bf107a741..b430d3a06 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -123,7 +123,7 @@ Particle::from_source(const Bank* src) } else { g_ = static_cast(src->E); g_last_ = static_cast(src->E); - E_ = data::energy_bin_avg[g_ - 1]; + E_ = data::mg.energy_bin_avg_[g_]; } E_last_ = E_; } @@ -202,12 +202,12 @@ Particle::transport() model::materials[material_]->calculate_xs(*this); } } else { - // Get the MG data - calculate_xs_c(material_, g_, sqrtkT_, this->u_local(), - macro_xs_.total, macro_xs_.absorption, macro_xs_.nu_fission); + // Get the MG data; unlike the CE case above, we have to re-calculate + // cross sections for every collision since the cross sections may + // be angle-dependent + data::mg.macro_xs_[material_].calculate_xs(*this); - // Finally, update the particle group while we have already checked - // for if multi-group + // Update the particle's group while we know we are multi-group g_last_ = g_; } } else { @@ -428,7 +428,7 @@ Particle::cross_surface() } return; - } else if ((surf->bc_ == BC_REFLECT || surf->bc_ == BC_WHITE) + } else if ((surf->bc_ == BC_REFLECT || surf->bc_ == BC_WHITE) && (settings::run_mode != RUN_MODE_PLOTTING)) { // ======================================================================= // PARTICLE REFLECTS FROM SURFACE @@ -458,11 +458,11 @@ Particle::cross_surface() score_surface_tally(this, model::active_meshsurf_tallies); this->r() = r; } - + Direction u = (surf->bc_ == BC_REFLECT) ? surf->reflect(this->r(), this->u()) : surf->diffuse_reflect(this->r(), this->u()); - + // Make sure new particle direction is normalized this->u() = u / u.norm(); diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index b2017bbeb..ce6555608 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -52,7 +52,7 @@ void read_particle_restart(Particle& p, int& previous_run_mode) // Set energy group and average energy in multi-group mode if (!settings::run_CE) { p.g_ = p.E_; - p.E_ = data::energy_bin_avg[p.g_ - 1]; + p.E_ = data::mg.energy_bin_avg_[p.g_]; } // Set particle last attributes @@ -79,6 +79,9 @@ void run_particle_restart() int previous_run_mode; read_particle_restart(p, previous_run_mode); + // write track if that was requested on command line + if (settings::write_all_tracks) p.write_track_ = true; + // Set all tallies to 0 for now (just tracking errors) model::tallies.clear(); diff --git a/src/photon.cpp b/src/photon.cpp index 929822bfc..ddde4bd6c 100644 --- a/src/photon.cpp +++ b/src/photon.cpp @@ -180,9 +180,8 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) // Read Compton profiles read_dataset(rgroup, "J", profile_pdf_); - // Get Compton profile momentum grid. By deafult, an xtensor has a size of 1. - // TODO: Change to zero when xtensor is updated - if (data::compton_profile_pz.size() == 1) { + // Get Compton profile momentum grid + if (data::compton_profile_pz.size() == 0) { read_dataset(rgroup, "pz", data::compton_profile_pz); } close_group(rgroup); @@ -213,8 +212,7 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) // Get energy grids used for bremsstrahlung DCS and for stopping powers xt::xtensor electron_energy; read_dataset(rgroup, "electron_energy", electron_energy); - // TODO: Change to zero when xtensor is updated - if (data::ttb_k_grid.size() == 1) { + if (data::ttb_k_grid.size() == 0) { read_dataset(rgroup, "photon_energy", data::ttb_k_grid); } @@ -255,8 +253,7 @@ PhotonInteraction::PhotonInteraction(hid_t group, int i_element) } // Set incident particle energy grid - // TODO: Change to zero when xtensor is updated - if (data::ttb_e_grid.size() == 1) { + if (data::ttb_e_grid.size() == 0) { data::ttb_e_grid = electron_energy; } diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index f99d15aac..8808adbb2 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -77,22 +77,14 @@ sample_reaction(Particle* p) void scatter(Particle* p) { - // Adjust indices for Fortran to C++ indexing - // TODO: Remove when no longer needed - int gin = p->g_last_ - 1; - int gout = p->g_ - 1; - int i_mat = p->material_; - data::macro_xs[i_mat].sample_scatter(gin, gout, p->mu_, p->wgt_); - - // Adjust return value for fortran indexing - // TODO: Remove when no longer needed - p->g_ = gout + 1; + data::mg.macro_xs_[p->material_].sample_scatter(p->g_last_, p->g_, p->mu_, + p->wgt_); // Rotate the angle p->u() = rotate_angle(p->u(), p->mu_, nullptr); // Update energy value for downstream compatability (in tallying) - p->E_ = data::energy_bin_avg[gout]; + p->E_ = data::mg.energy_bin_avg_[p->g_]; // Set event component p->event_ = EVENT_SCATTER; @@ -144,12 +136,14 @@ create_fission_sites(Particle* p, std::vector& bank) site.u.y = std::sqrt(1. - mu * mu) * std::cos(phi); site.u.z = std::sqrt(1. - mu * mu) * std::sin(phi); - // Sample secondary energy distribution for the fission reaction and set - // the energy in the fission bank + // Sample secondary energy distribution for the fission reaction int dg; int gout; - data::macro_xs[p->material_].sample_fission_energy(p->g_ - 1, dg, gout); - site.E = gout + 1; + data::mg.macro_xs_[p->material_].sample_fission_energy(p->g_, dg, gout); + // Store the energy and delayed groups on the fission bank + site.E = gout; + // We add 1 to the delayed_group bc in MG, -1 is prompt, but in the rest + // of the code, 0 is prompt. site.delayed_group = dg + 1; // Set the delayed group on the particle as well diff --git a/src/plot.cpp b/src/plot.cpp index 98a3645c7..ba63da16b 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -908,11 +908,13 @@ void create_voxel(Plot pl) // generate ids using plotbase IdData ids = pltbase.get_map(); - // select only cell ID data and flip the y-axis - xt::xtensor data1 = xt::flip(xt::view(ids.data_, xt::all(), xt::all(), 0), 0); + // select only cell/material ID data and flip the y-axis + int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 1; + xt::xtensor data_slice = xt::view(ids.data_, xt::all(), xt::all(), idx); + xt::xtensor data_flipped = xt::flip(data_slice, 0); // Write to HDF5 dataset - voxel_write_slice(z, dspace, dset, memspace, &(data1(0,0))); + voxel_write_slice(z, dspace, dset, memspace, data_flipped.data()); } voxel_finalize(dspace, dset, memspace); diff --git a/src/position.cpp b/src/position.cpp index 1215bfb12..d29e8d81c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -88,9 +88,9 @@ Position Position::rotate(const std::vector& rotation) const { return { + x*rotation[0] + y*rotation[1] + z*rotation[2], x*rotation[3] + y*rotation[4] + z*rotation[5], - x*rotation[6] + y*rotation[7] + z*rotation[8], - x*rotation[9] + y*rotation[10] + z*rotation[11] + x*rotation[6] + y*rotation[7] + z*rotation[8] }; } diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc index 731aa70a9..eb27d8591 100644 --- a/src/relaxng/settings.rnc +++ b/src/relaxng/settings.rnc @@ -75,7 +75,11 @@ element settings { attribute parameters { list { xsd:double+ } })? & element x { distribution }? & element y { distribution }? & - element z { distribution }? + element z { distribution }? & + element r { distribution }? & + element theta { distribution }? & + element phi { distribution }? & + element origin { list { xsd:double, xsd:double, xsd:double } }? }? & element angle { (element type { xsd:string } | attribute type { xsd:string }) & diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng index 3ed15c3ed..0c825d0d8 100644 --- a/src/relaxng/settings.rng +++ b/src/relaxng/settings.rng @@ -348,6 +348,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/scattdata.cpp b/src/scattdata.cpp index a8f63d0f6..5fc19c41e 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -171,14 +171,12 @@ ScattData::sample_energy(int gin, int& gout, int& i_gout) { // Sample the outgoing group double xi = prn(); - + double prob = 0.; i_gout = 0; - gout = gmin[gin]; - double prob = energy[gin][i_gout]; - while((prob < xi) && (gout < gmax[gin])) { - gout++; - i_gout++; + for (gout = gmin[gin]; gout < gmax[gin]; ++gout) { prob += energy[gin][i_gout]; + if (xi < prob) break; + ++i_gout; } } @@ -358,20 +356,18 @@ ScattDataLegendre::sample(int gin, int& gout, double& mu, double& wgt) // Now we can sample mu using the scattering kernel using rejection // sampling from a rectangular bounding box double M = max_val[gin][i_gout]; - int samples = 0; - - while(true) { + int samples; + for (samples = 0; samples < MAX_SAMPLE; ++samples) { mu = 2. * prn() - 1.; double f = calc_f(gin, gout, mu); if (f > 0.) { double u = prn() * M; if (u <= f) break; } - samples++; - if (samples > MAX_SAMPLE) { - fatal_error("Maximum number of Legendre expansion samples reached"); - } - }; + } + if (samples == MAX_SAMPLE) { + fatal_error("Maximum number of Legendre expansion samples reached!"); + } // Update the weight to reflect neutron multiplicity wgt *= mult[gin][i_gout]; diff --git a/src/settings.cpp b/src/settings.cpp index 1c9d1161a..b647d32e8 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -512,7 +512,7 @@ void read_settings_xml() if (!m) fatal_error("Only regular meshes can be used as an entropy mesh"); simulation::entropy_mesh = m; - if (m->shape_.dimension() == 0) { + if (m->shape_.size() == 0) { // If the user did not specify how many mesh cells are to be used in // each direction, we automatically determine an appropriate number of // cells diff --git a/src/source.cpp b/src/source.cpp index 0baa21b17..251e295ec 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -86,6 +86,8 @@ SourceDistribution::SourceDistribution(pugi::xml_node node) type = get_node_value(node_space, "type", true, true); if (type == "cartesian") { space_ = UPtrSpace{new CartesianIndependent(node_space)}; + } else if (type == "spherical") { + space_ = UPtrSpace{new SphericalIndependent(node_space)}; } else if (type == "box") { space_ = UPtrSpace{new SpatialBox(node_space)}; } else if (type == "fission") { @@ -309,11 +311,11 @@ Particle::Bank sample_external_source() // Sample source site from i-th source distribution Particle::Bank site {model::external_sources[i].sample()}; - // If running in MG, convert site % E to group + // If running in MG, convert site.E to group if (!settings::run_CE) { - site.E = lower_bound_index(data::rev_energy_bins.begin(), - data::rev_energy_bins.end(), site.E); - site.E = data::num_energy_groups - site.E; + site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(), + data::mg.rev_energy_bins_.end(), site.E); + site.E = data::mg.num_energy_groups_ - site.E - 1.; } // Set the random number generator back to the tracking stream. diff --git a/src/state_point.cpp b/src/state_point.cpp index 7239f3284..4c159c167 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -165,54 +165,61 @@ openmc_statepoint_write(const char* filename, bool* write_source) write_attribute(tallies_group, "ids", tally_ids); // Write all tally information except results - for (const auto& tally_ptr : model::tallies) { - const auto& tally {*tally_ptr}; + for (const auto& tally : model::tallies) { hid_t tally_group = create_group(tallies_group, - "tally " + std::to_string(tally.id_)); + "tally " + std::to_string(tally->id_)); - write_dataset(tally_group, "name", tally.name_); + write_dataset(tally_group, "name", tally->name_); - if (tally.estimator_ == ESTIMATOR_ANALOG) { + if (tally->writable_) { + write_attribute(tally_group, "internal", 0); + } else { + write_attribute(tally_group, "internal", 1); + close_group(tally_group); + continue; + } + + if (tally->estimator_ == ESTIMATOR_ANALOG) { write_dataset(tally_group, "estimator", "analog"); - } else if (tally.estimator_ == ESTIMATOR_TRACKLENGTH) { + } else if (tally->estimator_ == ESTIMATOR_TRACKLENGTH) { write_dataset(tally_group, "estimator", "tracklength"); - } else if (tally.estimator_ == ESTIMATOR_COLLISION) { + } else if (tally->estimator_ == ESTIMATOR_COLLISION) { write_dataset(tally_group, "estimator", "collision"); } - write_dataset(tally_group, "n_realizations", tally.n_realizations_); + write_dataset(tally_group, "n_realizations", tally->n_realizations_); // Write the ID of each filter attached to this tally - write_dataset(tally_group, "n_filters", tally.filters().size()); - if (!tally.filters().empty()) { + write_dataset(tally_group, "n_filters", tally->filters().size()); + if (!tally->filters().empty()) { std::vector filter_ids; - filter_ids.reserve(tally.filters().size()); - for (auto i_filt : tally.filters()) + filter_ids.reserve(tally->filters().size()); + for (auto i_filt : tally->filters()) filter_ids.push_back(model::tally_filters[i_filt]->id()); write_dataset(tally_group, "filters", filter_ids); } // Write the nuclides this tally scores std::vector nuclides; - for (auto i_nuclide : tally.nuclides_) { + for (auto i_nuclide : tally->nuclides_) { if (i_nuclide == -1) { nuclides.push_back("total"); } else { if (settings::run_CE) { nuclides.push_back(data::nuclides[i_nuclide]->name_); } else { - nuclides.push_back(data::nuclides_MG[i_nuclide].name); + nuclides.push_back(data::mg.nuclides_[i_nuclide].name); } } } write_dataset(tally_group, "nuclides", nuclides); - if (tally.deriv_ != C_NONE) write_dataset(tally_group, "derivative", - model::tally_derivs[tally.deriv_].id); + if (tally->deriv_ != C_NONE) write_dataset(tally_group, "derivative", + model::tally_derivs[tally->deriv_].id); // Write the tally score bins std::vector scores; - for (auto sc : tally.scores_) scores.push_back(reaction_name(sc)); + for (auto sc : tally->scores_) scores.push_back(reaction_name(sc)); write_dataset(tally_group, "n_score_bins", scores.size()); write_dataset(tally_group, "score_bins", scores); @@ -232,6 +239,7 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write all tally results for (const auto& tally : model::tallies) { + if (!tally->writable_) continue; // Write sum and sum_sq for each bin std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); @@ -425,11 +433,21 @@ void load_state_point() // Read sum, sum_sq, and N for each bin std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); - auto& results = tally->results_; - read_tally_results(tally_group, results.shape()[0], - results.shape()[1], results.data()); - read_dataset(tally_group, "n_realizations", tally->n_realizations_); - close_group(tally_group); + + int internal=0; + if (attribute_exists(tally_group, "internal")) { + read_attribute(tally_group, "internal", internal); + } + if (internal) { + tally->writable_ = false; + } else { + + auto& results = tally->results_; + read_tally_results(tally_group, results.shape()[0], + results.shape()[1], results.data()); + read_dataset(tally_group, "n_realizations", tally->n_realizations_); + close_group(tally_group); + } } close_group(tallies_group); @@ -697,6 +715,7 @@ void write_tally_results_nr(hid_t file_id) for (const auto& t : model::tallies) { // Skip any tallies that are not active if (!t->active_) continue; + if (!t->writable_) continue; if (mpi::master && !object_exists(file_id, "tallies_present")) { write_attribute(file_id, "tallies_present", 1); diff --git a/src/summary.cpp b/src/summary.cpp index d2721f97e..1f5f7a097 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -57,7 +57,7 @@ void write_nuclides(hid_t file) nuc_names.push_back(nuc->name_); awrs.push_back(nuc->awr_); } else { - const auto& nuc {data::nuclides_MG[i]}; + const auto& nuc {data::mg.nuclides_[i]}; if (nuc.awr != MACROSCOPIC_AWR) { nuc_names.push_back(nuc.name); awrs.push_back(nuc.awr); diff --git a/src/tallies/filter_energy.cpp b/src/tallies/filter_energy.cpp index dde9b692a..7c8b5fbee 100644 --- a/src/tallies/filter_energy.cpp +++ b/src/tallies/filter_energy.cpp @@ -43,10 +43,10 @@ EnergyFilter::set_bins(gsl::span bins) // (after flipping for the different ordering of the library and tallying // systems). if (!settings::run_CE) { - if (n_bins_ == data::num_energy_groups) { + if (n_bins_ == data::mg.num_energy_groups_) { matches_transport_groups_ = true; for (gsl::index i = 0; i < n_bins_ + 1; ++i) { - if (data::rev_energy_bins[i] != bins_[i]) { + if (data::mg.rev_energy_bins_[i] != bins_[i]) { matches_transport_groups_ = false; break; } @@ -61,9 +61,9 @@ const { if (p->g_ != F90_NONE && matches_transport_groups_) { if (estimator == ESTIMATOR_TRACKLENGTH) { - match.bins_.push_back(data::num_energy_groups - p->g_); + match.bins_.push_back(data::mg.num_energy_groups_ - p->g_ - 1); } else { - match.bins_.push_back(data::num_energy_groups - p->g_last_); + match.bins_.push_back(data::mg.num_energy_groups_ - p->g_last_ - 1); } match.weights_.push_back(1.0); @@ -104,7 +104,7 @@ EnergyoutFilter::get_all_bins(const Particle* p, int estimator, FilterMatch& match) const { if (p->g_ != F90_NONE && matches_transport_groups_) { - match.bins_.push_back(data::num_energy_groups - p->g_); + match.bins_.push_back(data::mg.num_energy_groups_ - p->g_ - 1); match.weights_.push_back(1.0); } else { diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 563beee76..852918a0c 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -810,8 +810,7 @@ void Tally::init_results() void Tally::reset() { n_realizations_ = 0; - // TODO: Change to zero when xtensor is updated - if (results_.size() != 1) { + if (results_.size() != 0) { xt::view(results_, xt::all()) = 0.0; } } @@ -1047,6 +1046,7 @@ free_memory_tally() { model::tally_derivs.clear(); } + model::tally_deriv_map.clear(); model::tally_filters.clear(); model::filter_map.clear(); @@ -1220,6 +1220,30 @@ openmc_tally_set_active(int32_t index, bool active) return 0; } +extern "C" int +openmc_tally_get_writable(int32_t index, bool* writable) +{ + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *writable = model::tallies[index]->writable(); + + return 0; +} + +extern "C" int +openmc_tally_set_writable(int32_t index, bool writable) +{ + 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_writable(writable); + + return 0; +} + extern "C" int openmc_tally_get_scores(int32_t index, int** scores, int* n) { @@ -1374,8 +1398,7 @@ openmc_tally_results(int32_t index, double** results, size_t* shape) } const auto& t {model::tallies[index]}; - // TODO: Change to zero when xtensor is updated - if (t->results_.size() == 1) { + if (t->results_.size() == 0) { set_errmsg("Tally results have not been allocated yet."); return OPENMC_E_ALLOCATE; } diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 37310070f..7ca279966 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -348,9 +348,9 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) // determine outgoing energy group from fission bank auto g_out = static_cast(bank.E); - // modify the value so that g_out = 1 corresponds to the highest energy + // modify the value so that g_out = 0 corresponds to the highest energy // bin - g_out = eo_filt.n_bins() - g_out; + g_out = eo_filt.n_bins() - g_out - 1; // change outgoing energy bin simulation::filter_matches[i_eout_filt].bins_[i_bin] = g_out; @@ -361,7 +361,7 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) if (settings::run_CE) { E_out = bank.E; } else { - E_out = data::energy_bin_avg[static_cast(bank.E)]; + E_out = data::mg.energy_bin_avg_[static_cast(bank.E)]; } // Set EnergyoutFilter bin index @@ -1374,15 +1374,15 @@ score_general_mg(const Particle* p, int i_tally, int start_index, p_g = p->g_; } - // To significantly reduce de-referencing, point matxs to the macroscopic - // Mgxs for the material of interest - data::macro_xs[p->material_].set_angle_index(p_u); + // For shorthand, assign pointers to the material and nuclide xs set + auto& nuc_xs = data::mg.nuclides_[i_nuclide]; + auto& macro_xs = data::mg.macro_xs_[p->material_]; - // Do same for nucxs, point it to the microscopic nuclide data of interest + // Find the temperature and angle indices of interest + macro_xs.set_angle_index(p_u); if (i_nuclide >= 0) { - // And since we haven't calculated this temperature index yet, do so now - data::nuclides_MG[i_nuclide].set_temperature_index(p->sqrtkT_); - data::nuclides_MG[i_nuclide].set_angle_index(p_u); + nuc_xs.set_temperature_index(p->sqrtkT_); + nuc_xs.set_angle_index(p_u); } for (auto i = 0; i < tally.scores_.size(); ++i) { @@ -1426,14 +1426,12 @@ score_general_mg(const Particle* p, int i_tally, int start_index, } //TODO: should flux be multiplied in above instead of below? if (i_nuclide >= 0) { - score *= flux * atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_TOTAL, p_g) - / get_macro_xs(p->material_, MG_GET_XS_TOTAL, p_g); + score *= flux * atom_density * nuc_xs.get_xs(MG_GET_XS_TOTAL, p_g) + / macro_xs.get_xs(MG_GET_XS_TOTAL, p_g); } } else { if (i_nuclide >= 0) { - score = get_nuclide_xs(i_nuclide, MG_GET_XS_TOTAL, p_g) - * atom_density * flux; + score = atom_density * flux * nuc_xs.get_xs(MG_GET_XS_TOTAL, p_g); } else { score = p->macro_xs_.total * flux; } @@ -1455,21 +1453,17 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = p->wgt_last_; } if (i_nuclide >= 0) { - score *= flux - * get_nuclide_xs(i_nuclide, MG_GET_XS_INVERSE_VELOCITY, p_g) - / get_macro_xs(p->material_, MG_GET_XS_TOTAL, p_g); + score *= flux * nuc_xs.get_xs(MG_GET_XS_INVERSE_VELOCITY, p_g) + / macro_xs.get_xs(MG_GET_XS_TOTAL, p_g); } else { - score *= flux - * get_macro_xs(p->material_, MG_GET_XS_INVERSE_VELOCITY, p_g) - / get_macro_xs(p->material_, MG_GET_XS_TOTAL, p_g); + score *= flux * macro_xs.get_xs(MG_GET_XS_INVERSE_VELOCITY, p_g) + / macro_xs.get_xs(MG_GET_XS_TOTAL, p_g); } } else { if (i_nuclide >= 0) { - score = flux - * get_nuclide_xs(i_nuclide, MG_GET_XS_INVERSE_VELOCITY, p_g); + score = flux * nuc_xs.get_xs(MG_GET_XS_INVERSE_VELOCITY, p_g); } else { - score = flux - * get_macro_xs(p->material_, MG_GET_XS_INVERSE_VELOCITY, p_g); + score = flux * macro_xs.get_xs(MG_GET_XS_INVERSE_VELOCITY, p_g); } } break; @@ -1483,19 +1477,18 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // weight entering the collision as the estimator for the reaction rate score = p->wgt_last_ * flux; if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_SCATTER_FMU_MULT, - p->g_last_, &p->g_, &p->mu_, nullptr) - / get_macro_xs(p->material_, MG_GET_XS_SCATTER_FMU_MULT, - p->g_last_, &p->g_, &p->mu_, nullptr); + score *= atom_density * nuc_xs.get_xs( + MG_GET_XS_SCATTER_FMU_MULT, p->g_last_, &p->g_, &p->mu_, nullptr) + / macro_xs.get_xs( + MG_GET_XS_SCATTER_FMU_MULT, p->g_last_, &p->g_, &p->mu_, nullptr); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * get_nuclide_xs( - i_nuclide, MG_GET_XS_SCATTER_MULT, p_g, nullptr, &p->mu_, nullptr); + score = atom_density * flux * nuc_xs.get_xs( + MG_GET_XS_SCATTER_MULT, p_g, nullptr, &p->mu_, nullptr); } else { - score = flux * get_macro_xs( - p->material_, MG_GET_XS_SCATTER_MULT, p_g, nullptr, &p->mu_, nullptr); + score = flux * macro_xs.get_xs( + MG_GET_XS_SCATTER_MULT, p_g, nullptr, &p->mu_, nullptr); } } break; @@ -1514,17 +1507,16 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // adjust the score by the actual probability for that nuclide. if (i_nuclide >= 0) { score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_SCATTER_FMU, - p->g_last_, &p->g_, &p->mu_, nullptr) - / get_macro_xs(p->material_, MG_GET_XS_SCATTER_FMU, - p->g_last_, &p->g_, &p->mu_, nullptr); + * nuc_xs.get_xs(MG_GET_XS_SCATTER_FMU, p->g_last_, &p->g_, + &p->mu_, nullptr) + / macro_xs.get_xs(MG_GET_XS_SCATTER_FMU, p->g_last_, &p->g_, + &p->mu_, nullptr); } } else { if (i_nuclide >= 0) { - score = atom_density * flux * get_nuclide_xs( - i_nuclide, MG_GET_XS_SCATTER, p_g); + score = atom_density * flux * nuc_xs.get_xs(MG_GET_XS_SCATTER, p_g); } else { - score = flux * get_macro_xs(p->material_, MG_GET_XS_SCATTER, p_g); + score = flux * macro_xs.get_xs(MG_GET_XS_SCATTER, p_g); } } break; @@ -1544,14 +1536,13 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = p->wgt_last_ * flux; } if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_ABSORPTION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= atom_density * nuc_xs.get_xs(MG_GET_XS_ABSORPTION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } } else { if (i_nuclide >= 0) { score = atom_density * flux - * get_nuclide_xs(i_nuclide, MG_GET_XS_ABSORPTION, p_g); + * nuc_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } else { score = p->macro_xs_.absorption * flux; } @@ -1575,20 +1566,17 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = p->wgt_last_ * flux; } if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= atom_density * nuc_xs.get_xs(MG_GET_XS_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } else { - score *= - get_macro_xs(p->material_, MG_GET_XS_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= macro_xs.get_xs(MG_GET_XS_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } } else { if (i_nuclide >= 0) { - score = get_nuclide_xs(i_nuclide, MG_GET_XS_FISSION, p_g) - * atom_density * flux; + score = atom_density * flux * nuc_xs.get_xs(MG_GET_XS_FISSION, p_g); } else { - score = get_macro_xs(p->material_, MG_GET_XS_FISSION, p_g) * flux; + score = flux * macro_xs.get_xs(MG_GET_XS_FISSION, p_g); } } break; @@ -1610,13 +1598,11 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // nu-fission score = p->wgt_absorb_ * flux; if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_NU_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= atom_density * nuc_xs.get_xs(MG_GET_XS_NU_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } else { - score *= - get_macro_xs(p->material_, MG_GET_XS_NU_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= macro_xs.get_xs(MG_GET_XS_NU_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } } else { // Skip any non-fission events @@ -1628,17 +1614,16 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // score. score = simulation::keff * p->wgt_bank_ * flux; if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_FISSION, p_g); + score *= atom_density * nuc_xs.get_xs(MG_GET_XS_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_FISSION, p_g); } } } else { if (i_nuclide >= 0) { - score = get_nuclide_xs(i_nuclide, MG_GET_XS_NU_FISSION, p_g) - * atom_density * flux; + score = atom_density * flux + * nuc_xs.get_xs(MG_GET_XS_NU_FISSION, p_g); } else { - score = get_macro_xs(p->material_, MG_GET_XS_NU_FISSION, p_g) * flux; + score = flux * macro_xs.get_xs(MG_GET_XS_NU_FISSION, p_g); } } break; @@ -1660,13 +1645,12 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // prompt-nu-fission score = p->wgt_absorb_ * flux; if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= atom_density * + nuc_xs.get_xs(MG_GET_XS_PROMPT_NU_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } else { - score *= - get_macro_xs(p->material_, MG_GET_XS_PROMPT_NU_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= macro_xs.get_xs(MG_GET_XS_PROMPT_NU_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } } else { // Skip any non-fission events @@ -1681,18 +1665,16 @@ score_general_mg(const Particle* p, int i_tally, int start_index, auto prompt_frac = 1. - n_delayed / static_cast(p->n_bank_); score = simulation::keff * p->wgt_bank_ * prompt_frac * flux; if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_FISSION, p_g); + score *= atom_density * nuc_xs.get_xs(MG_GET_XS_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_FISSION, p_g); } } } else { if (i_nuclide >= 0) { - score = get_nuclide_xs(i_nuclide, MG_GET_XS_PROMPT_NU_FISSION, p_g) - * atom_density * flux; + score = atom_density * flux * + nuc_xs.get_xs(MG_GET_XS_PROMPT_NU_FISSION, p_g); } else { - score = get_macro_xs(p->material_, MG_GET_XS_PROMPT_NU_FISSION, p_g) - * flux; + score = flux * macro_xs.get_xs(MG_GET_XS_PROMPT_NU_FISSION, p_g); } } break; @@ -1712,7 +1694,8 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - if (get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g) > 0) { + double abs_xs = macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); + if (abs_xs > 0.) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; const DelayedGroupFilter& filt @@ -1720,21 +1703,18 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; score = p->wgt_absorb_ * flux; if (i_nuclide >= 0) { - score *= - get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= nuc_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d) + / abs_xs; } else { - score *= - get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= macro_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d) + / abs_xs; } - score_fission_delayed_dg(i_tally, d_bin, score, - score_index); + score_fission_delayed_dg(i_tally, d_bin, score, score_index); } continue; } else { @@ -1743,13 +1723,11 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // delayed-nu-fission xs to the absorption xs score = p->wgt_absorb_ * flux; if (i_nuclide >= 0) { - score *= - get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= nuc_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g) + / abs_xs; } else { - score *= - get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= macro_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g) + / abs_xs; } } } @@ -1774,9 +1752,8 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = simulation::keff * p->wgt_bank_ / p->n_bank_ * p->n_delayed_bank_[d-1] * flux; if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_FISSION, p_g); + score *= atom_density * nuc_xs.get_xs(MG_GET_XS_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_FISSION, p_g); } score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -1788,9 +1765,8 @@ score_general_mg(const Particle* p, int i_tally, int start_index, score = simulation::keff * p->wgt_bank_ / p->n_bank_ * n_delayed * flux; if (i_nuclide >= 0) { - score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_FISSION, p_g); + score *= atom_density * nuc_xs.get_xs(MG_GET_XS_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_FISSION, p_g); } } } @@ -1802,26 +1778,23 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; if (i_nuclide >= 0) { - score = flux * atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d); + score = flux * atom_density * nuc_xs.get_xs( + MG_GET_XS_DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); } else { - score = flux - * get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d); + score = flux * macro_xs.get_xs( + MG_GET_XS_DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); } score_fission_delayed_dg(i_tally, d_bin, score, score_index); } continue; } else { if (i_nuclide >= 0) { - score = flux * atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, p_g); + score = flux * atom_density * + nuc_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g); } else { - score = flux - * get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, p_g); + score = flux * macro_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g); } } } @@ -1834,7 +1807,8 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // No fission events occur if survival biasing is on -- need to // calculate fraction of absorptions that would have resulted in // delayed-nu-fission - if (get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g) > 0) { + double abs_xs = macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); + if (abs_xs > 0) { if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; const DelayedGroupFilter& filt @@ -1842,25 +1816,20 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; score = p->wgt_absorb_ * flux; if (i_nuclide >= 0) { - score *= - get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= nuc_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, + nullptr, nullptr, &d) + * nuc_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d) / abs_xs; } else { - score *= - get_macro_xs(p->material_, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + score *= macro_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, + nullptr, &d) + * macro_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d) / abs_xs; } - score_fission_delayed_dg(i_tally, d_bin, score, - score_index); + score_fission_delayed_dg(i_tally, d_bin, score, score_index); } continue; } else { @@ -1869,21 +1838,19 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // delayed-nu-fission xs to the absorption xs for all delayed // groups score = 0.; - for (auto d = 0; d < data::num_delayed_groups; ++d) { + for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { score += p->wgt_absorb_ * flux - * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + * nuc_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, + nullptr, &d) + * nuc_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d) / abs_xs; } else { score += p->wgt_absorb_ * flux - * get_macro_xs(p->material_, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + * macro_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, + nullptr, &d) + * macro_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, + nullptr, nullptr, &d) / abs_xs; } } } @@ -1902,18 +1869,16 @@ score_general_mg(const Particle* p, int i_tally, int start_index, for (auto i = 0; i < p->n_bank_; ++i) { auto i_bank = simulation::fission_bank.size() - p->n_bank_ + i; const auto& bank = simulation::fission_bank[i_bank]; - auto g = bank.delayed_group; - if (g != 0) { + auto d = bank.delayed_group - 1; + if (d != -1) { if (i_nuclide >= 0) { score += simulation::keff * atom_density * bank.wgt * flux - * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, - nullptr, nullptr, &g) - * get_nuclide_xs(i_nuclide, MG_GET_XS_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_FISSION, p_g); + * nuc_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, nullptr, &d) + * nuc_xs.get_xs(MG_GET_XS_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_FISSION, p_g); } else { score += simulation::keff * bank.wgt * flux - * get_macro_xs(p->material_, MG_GET_XS_DECAY_RATE, p_g, - nullptr, nullptr, &g); + * macro_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, nullptr, &d); } if (tally.delayedgroup_filter_ != C_NONE) { auto i_dg_filt = tally.filters()[tally.delayedgroup_filter_]; @@ -1922,10 +1887,10 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Find the corresponding filter bin and then score for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; - if (d == g) + auto dg = filt.groups()[d_bin]; + if (dg == d + 1) score_fission_delayed_dg(i_tally, d_bin, score, - score_index); + score_index); } score = 0.; } @@ -1941,38 +1906,34 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; if (i_nuclide >= 0) { score += atom_density * flux - * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d); + * nuc_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, + nullptr, &d) + * nuc_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, nullptr, + nullptr, &d); } else { score += flux - * get_macro_xs(p->material_, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d); + * macro_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, + nullptr, &d) + * macro_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, nullptr, + nullptr, &d); } score_fission_delayed_dg(i_tally, d_bin, score, score_index); } continue; } else { score = 0.; - for (auto d = 0; d < data::num_delayed_groups; ++d) { + for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { score += atom_density * flux - * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d); + * nuc_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, nullptr, &d) + * nuc_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); } else { score += flux - * get_macro_xs(p->material_, MG_GET_XS_DECAY_RATE, - p_g, nullptr, nullptr, &d) - * get_macro_xs(p->material_, MG_GET_XS_DELAYED_NU_FISSION, - p_g, nullptr, nullptr, &d); + * macro_xs.get_xs(MG_GET_XS_DECAY_RATE, p_g, nullptr, nullptr, &d) + * macro_xs.get_xs(MG_GET_XS_DELAYED_NU_FISSION, p_g, nullptr, nullptr, &d); } } } @@ -1997,25 +1958,22 @@ score_general_mg(const Particle* p, int i_tally, int start_index, } if (i_nuclide >= 0) { score *= atom_density - * get_nuclide_xs(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + * nuc_xs.get_xs(MG_GET_XS_KAPPA_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } else { score *= - get_macro_xs(p->material_, MG_GET_XS_KAPPA_FISSION, p_g) - / get_macro_xs(p->material_, MG_GET_XS_ABSORPTION, p_g); + macro_xs.get_xs(MG_GET_XS_KAPPA_FISSION, p_g) + / macro_xs.get_xs(MG_GET_XS_ABSORPTION, p_g); } } else { if (i_nuclide >= 0) { - score = get_nuclide_xs(i_nuclide, MG_GET_XS_KAPPA_FISSION, p_g) - * atom_density * flux; + score = atom_density * flux * nuc_xs.get_xs(MG_GET_XS_KAPPA_FISSION, p_g); } else { - score = get_macro_xs(p->material_, MG_GET_XS_KAPPA_FISSION, p_g) - * flux; + score = flux * macro_xs.get_xs(MG_GET_XS_KAPPA_FISSION, p_g); } } break; - case SCORE_EVENTS: // Simply count the number of scoring events score = 1.; diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 93b729bd6..419bf0ea5 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -59,7 +59,32 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) domain_ids_ = get_node_array(node, "domain_ids"); lower_left_ = get_node_array(node, "lower_left"); upper_right_ = get_node_array(node, "upper_right"); - n_samples_ = std::stoi(get_node_value(node, "samples")); + n_samples_ = std::stoull(get_node_value(node, "samples")); + + if (check_for_node(node, "threshold")) { + pugi::xml_node threshold_node = node.child("threshold"); + + threshold_ = std::stod(get_node_value(threshold_node, "threshold")); + if (threshold_ <= 0.0) { + std::stringstream msg; + msg << "Invalid error threshold " << threshold_ << " provided for a volume calculation."; + fatal_error(msg); + } + + std::string tmp = get_node_value(threshold_node, "type"); + if (tmp == "variance") { + trigger_type_ = TriggerMetric::variance; + } else if (tmp == "std_dev") { + trigger_type_ = TriggerMetric::standard_deviation; + } else if ( tmp == "rel_err") { + trigger_type_ = TriggerMetric::relative_error; + } else { + std::stringstream msg; + msg << "Invalid volume calculation trigger type '" << tmp << "' provided."; + fatal_error(msg); + } + + } // Ensure there are no duplicates by copying elements to a set and then // comparing the length with the original vector @@ -77,11 +102,12 @@ std::vector VolumeCalculation::execute() const int n = domain_ids_.size(); std::vector> master_indices(n); // List of material indices for each domain std::vector> master_hits(n); // Number of hits for each material in each domain + int iterations = 0; // Divide work over MPI processes - int min_samples = n_samples_ / mpi::n_procs; - int remainder = n_samples_ % mpi::n_procs; - int i_start, i_end; + size_t min_samples = n_samples_ / mpi::n_procs; + size_t remainder = n_samples_ % mpi::n_procs; + size_t i_start, i_end; if (mpi::rank < remainder) { i_start = (min_samples + 1)*mpi::rank; i_end = i_start + min_samples + 1; @@ -90,182 +116,230 @@ std::vector VolumeCalculation::execute() const i_end = i_start + min_samples; } - #pragma omp parallel - { - // Variables that are private to each thread - std::vector> indices(n); - std::vector> hits(n); - Particle p; + while (true) { - prn_set_stream(STREAM_VOLUME); + #pragma omp parallel + { + // Variables that are private to each thread + std::vector> indices(n); + std::vector> hits(n); + Particle p; - // Sample locations and count hits - #pragma omp for - for (int i = i_start; i < i_end; i++) { - set_particle_seed(i); + prn_set_stream(STREAM_VOLUME); - p.n_coord_ = 1; - Position xi {prn(), prn(), prn()}; - p.r() = lower_left_ + xi*(upper_right_ - lower_left_); - p.u() = {0.5, 0.5, 0.5}; + // Sample locations and count hits + #pragma omp for + for (size_t i = i_start; i < i_end; i++) { + set_particle_seed(iterations * n_samples_ + i); - // If this location is not in the geometry at all, move on to next block - if (!find_cell(&p, false)) continue; + p.n_coord_ = 1; + Position xi {prn(), prn(), prn()}; + p.r() = lower_left_ + xi*(upper_right_ - lower_left_); + p.u() = {0.5, 0.5, 0.5}; - if (domain_type_ == FILTER_MATERIAL) { - if (p.material_ != MATERIAL_VOID) { - for (int i_domain = 0; i_domain < n; i_domain++) { - if (model::materials[p.material_]->id_ == domain_ids_[i_domain]) { - this->check_hit(p.material_, indices[i_domain], hits[i_domain]); - break; + // If this location is not in the geometry at all, move on to next block + if (!find_cell(&p, false)) continue; + + if (domain_type_ == FILTER_MATERIAL) { + if (p.material_ != MATERIAL_VOID) { + for (int i_domain = 0; i_domain < n; i_domain++) { + if (model::materials[p.material_]->id_ == domain_ids_[i_domain]) { + this->check_hit(p.material_, indices[i_domain], hits[i_domain]); + break; + } } } - } - } else if (domain_type_ == FILTER_CELL) { - for (int level = 0; level < p.n_coord_; ++level) { - for (int i_domain=0; i_domain < n; i_domain++) { - if (model::cells[p.coord_[level].cell]->id_ == domain_ids_[i_domain]) { - this->check_hit(p.material_, indices[i_domain], hits[i_domain]); - break; + } else if (domain_type_ == FILTER_CELL) { + for (int level = 0; level < p.n_coord_; ++level) { + for (int i_domain=0; i_domain < n; i_domain++) { + if (model::cells[p.coord_[level].cell]->id_ == domain_ids_[i_domain]) { + this->check_hit(p.material_, indices[i_domain], hits[i_domain]); + break; + } } } - } - } else if (domain_type_ == FILTER_UNIVERSE) { - for (int level = 0; level < p.n_coord_; ++level) { - for (int i_domain = 0; i_domain < n; ++i_domain) { - if (model::universes[p.coord_[level].universe]->id_ == domain_ids_[i_domain]) { - check_hit(p.material_, indices[i_domain], hits[i_domain]); - break; + } else if (domain_type_ == FILTER_UNIVERSE) { + for (int level = 0; level < p.n_coord_; ++level) { + for (int i_domain = 0; i_domain < n; ++i_domain) { + if (model::universes[p.coord_[level].universe]->id_ == domain_ids_[i_domain]) { + check_hit(p.material_, indices[i_domain], hits[i_domain]); + break; + } } } } } - } - // At this point, each thread has its own pair of index/hits lists and we now - // need to reduce them. OpenMP is not nearly smart enough to do this on its own, - // so we have to manually reduce them + // At this point, each thread has its own pair of index/hits lists and we now + // need to reduce them. OpenMP is not nearly smart enough to do this on its own, + // so we have to manually reduce them -#ifdef _OPENMP - #pragma omp for ordered schedule(static) - for (int i = 0; i < omp_get_num_threads(); ++i) { - #pragma omp ordered - for (int i_domain = 0; i_domain < n; ++i_domain) { - for (int j = 0; j < indices[i_domain].size(); ++j) { - // Check if this material has been added to the master list and if so, - // accumulate the number of hits - bool already_added = false; - for (int k = 0; k < master_indices[i_domain].size(); k++) { - if (indices[i_domain][j] == master_indices[i_domain][k]) { - master_hits[i_domain][k] += hits[i_domain][j]; - already_added = true; + #ifdef _OPENMP + int n_threads = omp_get_num_threads(); + #else + int n_threads = 1; + #endif + + #pragma omp for ordered schedule(static) + for (int i = 0; i < n_threads; ++i) { + #pragma omp ordered + for (int i_domain = 0; i_domain < n; ++i_domain) { + for (int j = 0; j < indices[i_domain].size(); ++j) { + // Check if this material has been added to the master list and if so, + // accumulate the number of hits + bool already_added = false; + for (int k = 0; k < master_indices[i_domain].size(); k++) { + if (indices[i_domain][j] == master_indices[i_domain][k]) { + master_hits[i_domain][k] += hits[i_domain][j]; + already_added = true; + } + } + if (!already_added) { + // If we made it here, the material hasn't yet been added to the master + // list, so add entries to the master indices and master hits lists + master_indices[i_domain].push_back(indices[i_domain][j]); + master_hits[i_domain].push_back(hits[i_domain][j]); } - } - if (!already_added) { - // If we made it here, the material hasn't yet been added to the master - // list, so add entries to the master indices and master hits lists - master_indices[i_domain].push_back(indices[i_domain][j]); - master_hits[i_domain].push_back(hits[i_domain][j]); } } } - } -#else - master_indices = indices; - master_hits = hits; -#endif + prn_set_stream(STREAM_TRACKING); + } // omp parallel - prn_set_stream(STREAM_TRACKING); - } // omp parallel + // Reduce hits onto master process - // Reduce hits onto master process + // Determine volume of bounding box + Position d {upper_right_ - lower_left_}; + double volume_sample = d.x*d.y*d.z; - // Determine volume of bounding box - Position d {upper_right_ - lower_left_}; - double volume_sample = d.x*d.y*d.z; + // bump iteration counter and get total number + // of samples at this point + iterations++; + size_t total_samples = iterations * n_samples_; - // Set size for members of the Result struct - std::vector results(n); + // reset + double trigger_val = -INFTY; - for (int i_domain = 0; i_domain < n; ++i_domain) { - // Get reference to result for this domain - auto& result {results[i_domain]}; + // Set size for members of the Result struct + std::vector results(n); - // Create 2D array to store atoms/uncertainty for each nuclide. Later this - // is compressed into vectors storing only those nuclides that are non-zero - auto n_nuc = data::nuclides.size(); - xt::xtensor atoms({n_nuc, 2}, 0.0); + for (int i_domain = 0; i_domain < n; ++i_domain) { + // Get reference to result for this domain + auto& result {results[i_domain]}; + + // Create 2D array to store atoms/uncertainty for each nuclide. Later this + // is compressed into vectors storing only those nuclides that are non-zero + auto n_nuc = data::nuclides.size(); + xt::xtensor atoms({n_nuc, 2}, 0.0); #ifdef OPENMC_MPI - if (mpi::master) { - for (int j = 1; j < mpi::n_procs; j++) { - int q; - MPI_Recv(&q, 1, MPI_INTEGER, j, 0, mpi::intracomm, MPI_STATUS_IGNORE); - int buffer[2*q]; - MPI_Recv(&buffer[0], 2*q, MPI_INTEGER, j, 1, mpi::intracomm, MPI_STATUS_IGNORE); - for (int k = 0; k < q; ++k) { - for (int m = 0; m < master_indices[i_domain].size(); ++m) { - if (buffer[2*k] == master_indices[i_domain][m]) { - master_hits[i_domain][m] += buffer[2*k + 1]; - break; + if (mpi::master) { + for (int j = 1; j < mpi::n_procs; j++) { + int q; + MPI_Recv(&q, 1, MPI_INTEGER, j, 0, mpi::intracomm, MPI_STATUS_IGNORE); + int buffer[2*q]; + MPI_Recv(&buffer[0], 2*q, MPI_INTEGER, j, 1, mpi::intracomm, MPI_STATUS_IGNORE); + for (int k = 0; k < q; ++k) { + for (int m = 0; m < master_indices[i_domain].size(); ++m) { + if (buffer[2*k] == master_indices[i_domain][m]) { + master_hits[i_domain][m] += buffer[2*k + 1]; + break; + } } } } - } - } else { - int q = master_indices[i_domain].size(); - int buffer[2*q]; - for (int k = 0; k < q; ++k) { - buffer[2*k] = master_indices[i_domain][k]; - buffer[2*k + 1] = master_hits[i_domain][k]; - } + } else { + int q = master_indices[i_domain].size(); + int buffer[2*q]; + for (int k = 0; k < q; ++k) { + buffer[2*k] = master_indices[i_domain][k]; + buffer[2*k + 1] = master_hits[i_domain][k]; + } - MPI_Send(&q, 1, MPI_INTEGER, 0, 0, mpi::intracomm); - MPI_Send(&buffer[0], 2*q, MPI_INTEGER, 0, 1, mpi::intracomm); + MPI_Send(&q, 1, MPI_INTEGER, 0, 0, mpi::intracomm); + MPI_Send(&buffer[0], 2*q, MPI_INTEGER, 0, 1, mpi::intracomm); + } +#endif + + if (mpi::master) { + int total_hits = 0; + for (int j = 0; j < master_indices[i_domain].size(); ++j) { + total_hits += master_hits[i_domain][j]; + double f = static_cast(master_hits[i_domain][j]) / total_samples; + double var_f = f*(1.0 - f) / total_samples; + + int i_material = master_indices[i_domain][j]; + if (i_material == MATERIAL_VOID) continue; + + const auto& mat = model::materials[i_material]; + for (int k = 0; k < mat->nuclide_.size(); ++k) { + // Accumulate nuclide density + int i_nuclide = mat->nuclide_[k]; + atoms(i_nuclide, 0) += mat->atom_density_[k] * f; + atoms(i_nuclide, 1) += std::pow(mat->atom_density_[k], 2) * var_f; + } + } + + // Determine volume + result.volume[0] = static_cast(total_hits) / total_samples * volume_sample; + result.volume[1] = std::sqrt(result.volume[0] + * (volume_sample - result.volume[0]) / total_samples); + result.iterations = iterations; + + // update threshold value if needed + if (trigger_type_ != TriggerMetric::not_active) { + double val = 0.0; + switch (trigger_type_) { + case TriggerMetric::standard_deviation: + val = result.volume[1]; + break; + case TriggerMetric::relative_error: + val = result.volume[0] == 0.0 ? INFTY : result.volume[1] / result.volume[0]; + break; + case TriggerMetric::variance: + val = result.volume[1] * result.volume[1]; + break; + } + // update max if entry is valid + if (val > 0.0) { trigger_val = std::max(trigger_val, val); } + } + + for (int j = 0; j < n_nuc; ++j) { + // Determine total number of atoms. At this point, we have values in + // atoms/b-cm. To get to atoms we multiply by 10^24 V. + double mean = 1.0e24 * volume_sample * atoms(j, 0); + double stdev = 1.0e24 * volume_sample * std::sqrt(atoms(j, 1)); + + // Convert full arrays to vectors + if (mean > 0.0) { + result.nuclides.push_back(j); + result.atoms.push_back(mean); + result.uncertainty.push_back(stdev); + } + } + } + } // end domain loop + + // if no trigger is applied, we're done + if (trigger_type_ == TriggerMetric::not_active) { return results; } + +#ifdef OPENMC_MPI + // update maximum error value on all processes + MPI_Bcast(&trigger_val, 1, MPI_DOUBLE, 0, mpi::intracomm); +#endif + + // return results of the calculation + if (trigger_val < threshold_) { return results; } + +#ifdef OPENMC_MPI + // if iterating in an MPI run, need to zero indices and hits so they aren't counted twice + if (!mpi::master) { + for (auto& v : master_indices) { std::fill(v.begin(), v.end(), 0); } + for (auto& v : master_hits) { std::fill(v.begin(), v.end(), 0); } } #endif - if (mpi::master) { - int total_hits = 0; - for (int j = 0; j < master_indices[i_domain].size(); ++j) { - total_hits += master_hits[i_domain][j]; - double f = static_cast(master_hits[i_domain][j]) / n_samples_; - double var_f = f*(1.0 - f)/n_samples_; - - int i_material = master_indices[i_domain][j]; - if (i_material == MATERIAL_VOID) continue; - - const auto& mat = model::materials[i_material]; - for (int k = 0; k < mat->nuclide_.size(); ++k) { - // Accumulate nuclide density - int i_nuclide = mat->nuclide_[k]; - atoms(i_nuclide, 0) += mat->atom_density_[k] * f; - atoms(i_nuclide, 1) += std::pow(mat->atom_density_[k], 2) * var_f; - } - } - - // Determine volume - result.volume[0] = static_cast(total_hits) / n_samples_ * volume_sample; - result.volume[1] = std::sqrt(result.volume[0] - * (volume_sample - result.volume[0]) / n_samples_); - - for (int j = 0; j < n_nuc; ++j) { - // Determine total number of atoms. At this point, we have values in - // atoms/b-cm. To get to atoms we multiply by 10^24 V. - double mean = 1.0e24 * volume_sample * atoms(j, 0); - double stdev = 1.0e24 * volume_sample * std::sqrt(atoms(j, 1)); - - // Convert full arrays to vectors - if (mean > 0.0) { - result.nuclides.push_back(j); - result.atoms.push_back(mean); - result.uncertainty.push_back(stdev); - } - } - } - } - - return results; + } // end while } void VolumeCalculation::to_hdf5(const std::string& filename, @@ -289,6 +363,27 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "samples", n_samples_); write_attribute(file_id, "lower_left", lower_left_); write_attribute(file_id, "upper_right", upper_right_); + // Write trigger info + if (trigger_type_ != TriggerMetric::not_active) { + write_attribute(file_id, "iterations", results[0].iterations); + write_attribute(file_id, "threshold", threshold_); + std::string trigger_str; + switch(trigger_type_) { + case TriggerMetric::variance: + trigger_str = "variance"; + break; + case TriggerMetric::standard_deviation: + trigger_str = "std_dev"; + break; + case TriggerMetric::relative_error: + trigger_str = "rel_err"; + break; + } + write_attribute(file_id, "trigger_type", trigger_str); + } else { + write_attribute(file_id, "iterations", 1); + } + if (domain_type_ == FILTER_CELL) { write_attribute(file_id, "domain_type", "cell"); } @@ -311,22 +406,20 @@ void VolumeCalculation::to_hdf5(const std::string& filename, // Create array of nuclide names from the vector auto n_nuc = result.nuclides.size(); - if (!result.nuclides.empty()) { - std::vector nucnames; - for (int i_nuc : result.nuclides) { - nucnames.push_back(data::nuclides[i_nuc]->name_); - } - - // Create array of total # of atoms with uncertainty for each nuclide - xt::xtensor atom_data({n_nuc, 2}); - xt::view(atom_data, xt::all(), 0) = xt::adapt(result.atoms); - xt::view(atom_data, xt::all(), 1) = xt::adapt(result.uncertainty); - - // Write results - write_dataset(group_id, "nuclides", nucnames); - write_dataset(group_id, "atoms", atom_data); + std::vector nucnames; + for (int i_nuc : result.nuclides) { + nucnames.push_back(data::nuclides[i_nuc]->name_); } + // Create array of total # of atoms with uncertainty for each nuclide + xt::xtensor atom_data({n_nuc, 2}); + xt::view(atom_data, xt::all(), 0) = xt::adapt(result.atoms); + xt::view(atom_data, xt::all(), 1) = xt::adapt(result.uncertainty); + + // Write results + write_dataset(group_id, "nuclides", nucnames); + write_dataset(group_id, "atoms", atom_data); + close_group(group_id); } diff --git a/src/xsdata.cpp b/src/xsdata.cpp index cee36a938..d6b92958a 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -24,11 +24,12 @@ namespace openmc { // XsData class methods //============================================================================== -XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi) +XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi, + size_t n_groups, size_t n_d_groups) : + n_g_(n_groups), + n_dg_(n_d_groups) { size_t n_ang = n_pol * n_azi; - size_t n_dg = data::num_delayed_groups; - size_t n_g = data::num_energy_groups; // check to make sure scatter format is OK before we allocate if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && @@ -36,7 +37,7 @@ XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi) fatal_error("Invalid scatter_format!"); } // allocate all [temperature][angle][in group] quantities - std::vector shape {n_ang, n_g}; + std::vector shape {n_ang, n_g_}; total = xt::zeros(shape); absorption = xt::zeros(shape); inverse_velocity = xt::zeros(shape); @@ -48,20 +49,20 @@ XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi) } // allocate decay_rate; [temperature][angle][delayed group] - shape[1] = n_dg; + shape[1] = n_dg_; decay_rate = xt::zeros(shape); if (fissionable) { - shape = {n_ang, n_dg, n_g}; + shape = {n_ang, n_dg_, n_g_}; // allocate delayed_nu_fission; [temperature][angle][delay group][in group] delayed_nu_fission = xt::zeros(shape); // chi_prompt; [temperature][angle][in group][out group] - shape = {n_ang, n_g, n_g}; + shape = {n_ang, n_g_, n_g_}; chi_prompt = xt::zeros(shape); // chi_delayed; [temperature][angle][delay group][in group][out group] - shape = {n_ang, n_dg, n_g, n_g}; + shape = {n_ang, n_dg_, n_g_, n_g_}; chi_delayed = xt::zeros(shape); } @@ -127,11 +128,8 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, { // Data is provided as nu-fission and chi with a beta for delayed info - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; - // Get chi - xt::xtensor temp_chi({n_ang, n_g}, 0.); + xt::xtensor temp_chi({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle @@ -144,7 +142,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::all()); // Get nu-fission - xt::xtensor temp_nufiss({n_ang, n_g}, 0.); + xt::xtensor temp_nufiss({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_nufiss, true); // Get beta (strategy will depend upon the number of dimensions in beta) @@ -154,7 +152,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, int ndim_target = 1; if (!is_isotropic) ndim_target += 2; if (beta_ndims == ndim_target) { - xt::xtensor temp_beta({n_ang, n_dg}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); // Set prompt_nu_fission = (1. - beta_total)*nu_fission @@ -165,7 +163,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } else if (beta_ndims == ndim_target + 1) { - xt::xtensor temp_beta({n_ang, n_dg, n_g}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); // Set prompt_nu_fission = (1. - beta_total)*nu_fission @@ -182,18 +180,15 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; - // Get chi-prompt - xt::xtensor temp_chi_p({n_ang, n_g}, 0.); + xt::xtensor temp_chi_p({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); // Normalize chi by summing over the outgoing groups for each incoming angle temp_chi_p /= xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); // Get chi-delayed - xt::xtensor temp_chi_d({n_ang, n_dg, n_g}, 0.); + xt::xtensor temp_chi_d({n_ang, n_dg_, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); // Normalize chi by summing over the outgoing groups for each incoming angle @@ -218,10 +213,8 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. - size_t n_g = data::num_energy_groups; - // Get chi - xt::xtensor temp_chi({n_ang, n_g}, 0.); + xt::xtensor temp_chi({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle @@ -241,11 +234,8 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is { // Data is provided as nu-fission and chi with a beta for delayed info - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; - // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); + xt::xtensor temp_matrix({n_ang, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // Get beta (strategy will depend upon the number of dimensions in beta) @@ -255,7 +245,7 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is int ndim_target = 1; if (!is_isotropic) ndim_target += 2; if (beta_ndims == ndim_target) { - xt::xtensor temp_beta({n_ang, n_dg}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); xt::xtensor temp_beta_sum({n_ang}, 0.); @@ -281,10 +271,10 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); } else if (beta_ndims == ndim_target + 1) { - xt::xtensor temp_beta({n_ang, n_dg, n_g}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); - xt::xtensor temp_beta_sum({n_ang, n_g}, 0.); + xt::xtensor temp_beta_sum({n_ang, n_g_}, 0.); temp_beta_sum = xt::sum(temp_beta, {1}); // prompt_nu_fission is the sum of this matrix over outgoing groups and @@ -319,11 +309,8 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; - // Get the prompt nu-fission matrix - xt::xtensor temp_matrix_p({n_ang, n_g, n_g}, 0.); + xt::xtensor temp_matrix_p({n_ang, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); // prompt_nu_fission is the sum over outgoing groups @@ -335,7 +322,7 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); // Get the delayed nu-fission matrix - xt::xtensor temp_matrix_d({n_ang, n_dg, n_g, n_g}, 0.); + xt::xtensor temp_matrix_d({n_ang, n_dg_, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); // delayed_nu_fission is the sum over outgoing groups @@ -353,10 +340,8 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. - size_t n_g = data::num_energy_groups; - // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); + xt::xtensor temp_matrix({n_ang, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // prompt_nu_fission is the sum over outgoing groups @@ -381,7 +366,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) // as a nu-fission matrix or a set of chi and nu-fission vectors if (object_exists(xsdata_grp, "chi") || object_exists(xsdata_grp, "chi-prompt")) { - if (data::num_delayed_groups == 0) { + if (n_dg_ == 0) { fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -391,7 +376,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } } } else { - if (data::num_delayed_groups == 0) { + if (n_dg_ == 0) { fission_matrix_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -403,7 +388,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - if (data::num_delayed_groups == 0) { + if (n_dg_ == 0) { nu_fission = prompt_nu_fission; } else { nu_fission = prompt_nu_fission + xt::sum(delayed_nu_fission, {1}); @@ -422,10 +407,9 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - size_t n_g = data::num_energy_groups; - xt::xtensor gmin({n_ang, n_g}, 0.); + xt::xtensor gmin({n_ang, n_g_}, 0.); read_nd_vector(scatt_grp, "g_min", gmin, true); - xt::xtensor gmax({n_ang, n_g}, 0.); + xt::xtensor gmax({n_ang, n_g_}, 0.); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library @@ -436,7 +420,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // data. size_t length = order_data * xt::sum(gmax - gmin + 1)(); - double_4dvec input_scatt(n_ang, double_3dvec(n_g)); + double_4dvec input_scatt(n_ang, double_3dvec(n_g_)); xt::xtensor temp_arr({length}, 0.); read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); @@ -453,7 +437,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // scatt data size_t temp_idx = 0; for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < n_g; gin++) { + for (size_t gin = 0; gin < n_g_; gin++) { input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (size_t i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { input_scatt[a][gin][i_gout].resize(order_dim); @@ -467,7 +451,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, } // Get multiplication matrix - double_3dvec temp_mult(n_ang, double_2dvec(n_g)); + double_3dvec temp_mult(n_ang, double_2dvec(n_g_)); if (object_exists(scatt_grp, "multiplicity_matrix")) { temp_arr.resize({length / order_data}); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); @@ -475,7 +459,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // convert the flat temp_arr to a jagged array for passing to scatt data size_t temp_idx = 0; for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < n_g; gin++) { + for (size_t gin = 0; gin < n_g_; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = temp_arr[temp_idx++]; @@ -485,7 +469,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, } else { // Use a default: multiplicities are 1.0. for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < n_g; gin++) { + for (size_t gin = 0; gin < n_g_; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = 1.; diff --git a/tests/dummy_operator.py b/tests/dummy_operator.py index 35a526c30..13e8b7d41 100644 --- a/tests/dummy_operator.py +++ b/tests/dummy_operator.py @@ -1,4 +1,5 @@ from collections import namedtuple +from unittest.mock import Mock import numpy as np import scipy.sparse as sp @@ -133,6 +134,8 @@ class DummyOperator(TransportOperator): self.prev_res = previous_results self.chain = TestChain() self.output_dir = "." + self.settings = Mock() + self.settings.particles = 10 def __call__(self, vec, power, print_out=False): """Evaluates F(y) diff --git a/tests/regression_tests/dagmc/legacy/dagmc.h5m b/tests/regression_tests/dagmc/legacy/dagmc.h5m index fbbe9a34a..bd50a9691 100644 Binary files a/tests/regression_tests/dagmc/legacy/dagmc.h5m and b/tests/regression_tests/dagmc/legacy/dagmc.h5m differ diff --git a/tests/regression_tests/dagmc/legacy/inputs_true.dat b/tests/regression_tests/dagmc/legacy/inputs_true.dat index 8ca49c324..769a3384c 100644 --- a/tests/regression_tests/dagmc/legacy/inputs_true.dat +++ b/tests/regression_tests/dagmc/legacy/inputs_true.dat @@ -1,6 +1,6 @@ - + diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index 963e73226..5af18e5c8 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -8,7 +8,9 @@ pytestmark = pytest.mark.skipif( not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") -def test_dagmc(): +@pytest.fixture +def model(): + model = openmc.model.Model() # settings @@ -31,7 +33,7 @@ def test_dagmc(): model.tallies = [tally] # materials - u235 = openmc.Material(name="fuel") + u235 = openmc.Material(name="no-void fuel") u235.add_nuclide('U235', 1.0, 'ao') u235.set_density('g/cc', 11) u235.id = 40 @@ -46,4 +48,8 @@ def test_dagmc(): mats = openmc.Materials([u235, water]) model.materials = mats - model.export_to_xml() + return model + +def test_dagmc(model): + harness = PyAPITestHarness('statepoint.5.h5', model) + harness.main() diff --git a/tests/regression_tests/deplete/test.py b/tests/regression_tests/deplete/test.py index c7a9c162e..01ce21c01 100644 --- a/tests/regression_tests/deplete/test.py +++ b/tests/regression_tests/deplete/test.py @@ -108,11 +108,17 @@ def test_full(run_in_tmpdir): t_ref, k_ref = res_ref.get_eigenvalue() k_state = np.empty_like(k_ref) + n_tallies = np.empty(N + 1, dtype=int) + # Get statepoint files for all BOS points and EOL for n in range(N + 1): statepoint = openmc.StatePoint("openmc_simulation_n{}.h5".format(n)) k_n = statepoint.k_combined k_state[n] = [k_n.nominal_value, k_n.std_dev] + n_tallies[n] = len(statepoint.tallies) # Look for exact match pulling from statepoint and depletion_results assert np.all(k_state == k_test) assert np.allclose(k_test, k_ref) + + # Check that no additional tallies are loaded from the files + assert np.all(n_tallies == 0) diff --git a/tests/regression_tests/mg_tallies/results_true.dat b/tests/regression_tests/mg_tallies/results_true.dat index 50ec653e2..26a062fac 100644 --- a/tests/regression_tests/mg_tallies/results_true.dat +++ b/tests/regression_tests/mg_tallies/results_true.dat @@ -1 +1,1324 @@ -508cd056f2d9409a536e487512df34c683720ea45b9100316efb31c19927890c4cacd92f38817d74fcf491bbe4bdb78a0215a798d5a078e0575e3fd94cedf0bd \ No newline at end of file +k-combined: +9.934975E-01 2.679669E-02 +tally 1: +2.542000E+00 +1.343070E+00 +1.260000E-01 +3.298000E-03 +4.838111E-02 +4.857369E-04 +1.202865E-01 +3.119670E-03 +6.000347E-07 +8.163458E-14 +1.202865E-01 +3.119670E-03 +0.000000E+00 +0.000000E+00 +9.676221E+06 +1.942948E+13 +2.542000E+00 +1.343070E+00 +0.000000E+00 +0.000000E+00 +7.404202E+00 +1.141803E+01 +1.949000E+00 +8.324030E-01 +9.000000E-02 +1.762000E-03 +3.793334E-02 +3.031575E-04 +1.081691E-01 +2.457437E-03 +5.571912E-07 +6.439495E-14 +1.071378E-01 +2.411702E-03 +1.031308E-03 +1.063597E-06 +7.586669E+06 +1.212630E+13 +1.949000E+00 +8.324030E-01 +3.122595E-04 +9.750600E-08 +5.650158E+00 +7.016308E+00 +1.039000E+00 +2.447670E-01 +4.200000E-02 +4.120000E-04 +1.685968E-02 +6.389070E-05 +4.929366E-02 +5.628729E-04 +2.018053E-07 +1.119308E-14 +4.823620E-02 +5.371538E-04 +1.057461E-03 +1.118225E-06 +3.371936E+06 +2.555628E+12 +1.039000E+00 +2.447670E-01 +3.201782E-04 +1.025141E-07 +3.038326E+00 +2.108568E+00 +5.930000E-01 +7.205300E-02 +2.300000E-02 +1.110000E-04 +1.056715E-02 +2.338156E-05 +2.528379E-02 +1.491420E-04 +1.384831E-07 +6.031333E-15 +2.528379E-02 +1.491420E-04 +0.000000E+00 +0.000000E+00 +2.113430E+06 +9.352624E+11 +5.930000E-01 +7.205300E-02 +0.000000E+00 +0.000000E+00 +1.727671E+00 +6.138025E-01 +3.501000E+00 +2.515635E+00 +1.600000E-01 +5.250000E-03 +5.998847E-02 +7.320149E-04 +1.529867E-01 +4.932068E-03 +7.476127E-07 +1.267077E-13 +1.529867E-01 +4.932068E-03 +0.000000E+00 +0.000000E+00 +1.199769E+07 +2.928060E+13 +3.501000E+00 +2.515635E+00 +0.000000E+00 +0.000000E+00 +1.021925E+01 +2.143166E+01 +4.454000E+00 +4.082446E+00 +1.920000E-01 +7.726000E-03 +8.044824E-02 +1.327101E-03 +2.231973E-01 +1.024637E-02 +1.236154E-06 +3.183460E-13 +2.211081E-01 +1.008915E-02 +2.089232E-03 +2.182800E-06 +1.608965E+07 +5.308405E+13 +4.454000E+00 +4.082446E+00 +3.894344E-03 +9.877407E-06 +1.292241E+01 +3.441496E+01 +4.210000E+00 +3.829106E+00 +1.750000E-01 +6.549000E-03 +7.464456E-02 +1.228199E-03 +1.787859E-01 +7.634408E-03 +1.144154E-06 +3.572375E-13 +1.777141E-01 +7.525287E-03 +1.071750E-03 +1.148648E-06 +1.492891E+07 +4.912798E+13 +4.210000E+00 +3.829106E+00 +3.245044E-04 +1.053031E-07 +1.222119E+01 +3.220371E+01 +1.364000E+00 +3.933640E-01 +8.200000E-02 +1.378000E-03 +3.158206E-02 +2.047576E-04 +5.983520E-02 +7.581471E-04 +3.272437E-07 +2.772035E-14 +5.983520E-02 +7.581471E-04 +0.000000E+00 +0.000000E+00 +6.316412E+06 +8.190302E+12 +1.364000E+00 +3.933640E-01 +0.000000E+00 +0.000000E+00 +3.971532E+00 +3.348259E+00 +1.363000E+00 +4.205090E-01 +7.000000E-02 +1.130000E-03 +2.590153E-02 +1.476101E-04 +5.594611E-02 +6.902009E-04 +2.690262E-07 +1.501020E-14 +5.594611E-02 +6.902009E-04 +0.000000E+00 +0.000000E+00 +5.180306E+06 +5.904403E+12 +1.363000E+00 +4.205090E-01 +0.000000E+00 +0.000000E+00 +3.984609E+00 +3.608477E+00 +1.246000E+00 +3.852900E-01 +5.300000E-02 +6.650000E-04 +1.954836E-02 +9.404628E-05 +4.771133E-02 +6.866474E-04 +1.814542E-07 +1.125942E-14 +4.771133E-02 +6.866474E-04 +0.000000E+00 +0.000000E+00 +3.909672E+06 +3.761851E+12 +1.246000E+00 +3.852900E-01 +0.000000E+00 +0.000000E+00 +3.660351E+00 +3.335482E+00 +tally 2: +2.599889E+00 +1.402744E+00 +1.167830E-01 +2.830760E-03 +4.644159E-02 +4.578546E-04 +1.161040E-01 +2.861591E-03 +6.110737E-07 +8.591437E-14 +1.153679E-01 +2.825421E-03 +7.360997E-04 +1.150235E-07 +9.288319E+06 +1.831418E+13 +2.589000E+00 +1.391365E+00 +3.449004E-04 +2.525229E-08 +7.573543E+00 +1.191287E+01 +1.935337E+00 +8.143708E-01 +9.059861E-02 +1.758063E-03 +3.784648E-02 +3.023430E-04 +9.461621E-02 +1.889644E-03 +5.353929E-07 +5.956643E-14 +9.401634E-02 +1.865759E-03 +5.998671E-04 +7.595546E-08 +7.569296E+06 +1.209372E+13 +1.989000E+00 +8.632630E-01 +2.810685E-04 +1.667528E-08 +5.615484E+00 +6.866983E+00 +1.015076E+00 +2.265305E-01 +4.209446E-02 +3.711488E-04 +1.500394E-02 +4.824763E-05 +3.750984E-02 +3.015477E-04 +1.616914E-07 +8.025617E-15 +3.727203E-02 +2.977362E-04 +2.378125E-04 +1.212091E-08 +3.000787E+06 +1.929905E+12 +1.051000E+00 +2.509110E-01 +1.114274E-04 +2.661027E-09 +2.978146E+00 +1.962310E+00 +6.199894E-01 +7.878811E-02 +2.804937E-02 +1.607308E-04 +1.125386E-02 +2.891349E-05 +2.813466E-02 +1.807093E-04 +1.501221E-07 +7.165022E-15 +2.795628E-02 +1.784252E-04 +1.783738E-04 +7.263729E-09 +2.250773E+06 +1.156540E+12 +6.190000E-01 +7.822300E-02 +8.357728E-05 +1.594681E-09 +1.804831E+00 +6.709321E-01 +3.398516E+00 +2.363683E+00 +1.505108E-01 +4.655588E-03 +5.879057E-02 +7.289809E-04 +1.469764E-01 +4.556130E-03 +7.516677E-07 +1.300615E-13 +1.460446E-01 +4.498542E-03 +9.318311E-04 +1.831366E-07 +1.175811E+07 +2.915923E+13 +3.542000E+00 +2.572512E+00 +4.366106E-04 +4.020586E-08 +9.912955E+00 +2.011678E+01 +4.395956E+00 +3.964331E+00 +2.146513E-01 +9.286938E-03 +9.388516E-02 +1.784380E-03 +2.347129E-01 +1.115237E-02 +1.410768E-06 +4.182007E-13 +2.332248E-01 +1.101141E-02 +1.488081E-03 +4.482769E-07 +1.877703E+07 +7.137519E+13 +4.497000E+00 +4.157935E+00 +6.972420E-04 +9.841483E-08 +1.270142E+01 +3.319405E+01 +4.157899E+00 +3.751197E+00 +1.897379E-01 +8.038105E-03 +7.692709E-02 +1.413632E-03 +1.923177E-01 +8.835202E-03 +1.042521E-06 +3.025447E-13 +1.910984E-01 +8.723527E-03 +1.219295E-03 +3.551367E-07 +1.538542E+07 +5.654529E+13 +4.268000E+00 +3.930780E+00 +5.713023E-04 +7.796680E-08 +1.209407E+01 +3.169559E+01 +1.357524E+00 +3.878228E-01 +5.983682E-02 +7.460748E-04 +2.322979E-02 +1.144334E-04 +5.807447E-02 +7.152085E-04 +2.940107E-07 +2.024706E-14 +5.770628E-02 +7.061684E-04 +3.681924E-04 +2.874827E-08 +4.645957E+06 +4.577335E+12 +1.390000E+00 +4.083140E-01 +1.725170E-04 +6.311403E-09 +3.961412E+00 +3.308776E+00 +1.376941E+00 +4.321098E-01 +6.198249E-02 +8.400785E-04 +2.471448E-02 +1.321749E-04 +6.178621E-02 +8.260929E-04 +3.265418E-07 +2.485223E-14 +6.139448E-02 +8.156513E-04 +3.917248E-04 +3.320534E-08 +4.942896E+06 +5.286995E+12 +1.395000E+00 +4.400290E-01 +1.835431E-04 +7.289909E-09 +4.010262E+00 +3.684656E+00 +1.267762E+00 +4.052744E-01 +5.233659E-02 +6.929809E-04 +1.852753E-02 +9.379170E-05 +4.631882E-02 +5.861981E-04 +1.967460E-07 +1.534801E-14 +4.602516E-02 +5.787887E-04 +2.936615E-04 +2.356261E-08 +3.705506E+06 +3.751668E+12 +1.284000E+00 +4.070420E-01 +1.375955E-04 +5.172942E-09 +3.720938E+00 +3.496554E+00 +tally 3: +1.131330E+02 +2.561428E+03 +4.988000E+00 +4.976048E+00 +1.993967E+00 +7.956428E-01 +5.135468E+00 +5.291611E+00 +2.697394E-05 +1.462336E-10 +5.101779E+00 +5.222461E+00 +3.368875E-02 +2.575850E-04 +3.987934E+08 +3.182571E+16 +1.131330E+02 +2.561428E+03 +1.464422E-02 +8.408713E-05 +3.294536E+02 +2.172280E+04 +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +tally 4: +1.131330E+02 +2.561428E+03 +5.099217E+00 +5.202791E+00 +2.036481E+00 +8.305328E-01 +5.091203E+00 +5.190830E+00 +4.963770E-05 +4.951715E-10 +5.058925E+00 +5.125219E+00 +3.227825E-02 +2.086488E-04 +4.072963E+08 +3.322131E+16 +1.131330E+02 +2.561428E+03 +1.512401E-02 +4.580681E-05 +3.294536E+02 +2.172280E+04 +tally 5: +1.126689E+02 +2.540742E+03 +5.072428E+00 +5.150411E+00 +2.022883E+00 +8.201638E-01 +5.057207E+00 +5.126024E+00 +2.673439E-05 +1.438788E-10 +5.025144E+00 +5.061232E+00 +3.206271E-02 +2.060439E-04 +4.045765E+08 +3.280655E+16 +1.133620E+02 +2.571755E+03 +1.502302E-02 +4.523492E-05 +3.281376E+02 +2.155147E+04 +tally 6: +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +5.135468E+00 +5.291611E+00 +tally 7: +6.429000E+00 +8.307829E+00 +1.410000E+00 +3.992220E-01 +1.119414E+00 +2.516273E-01 +2.887237E+00 +1.682974E+00 +2.674702E-05 +1.437976E-10 +2.870392E+00 +1.663680E+00 +1.684448E-02 +5.768606E-05 +2.238828E+08 +1.006509E+16 +6.429000E+00 +8.307829E+00 +3.761262E-03 +3.156399E-06 +1.176869E+01 +2.783921E+01 +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +1.067040E+02 +2.278956E+03 +3.578000E+00 +2.562210E+00 +8.745532E-01 +1.530758E-01 +2.248231E+00 +1.013550E+00 +2.269178E-07 +1.030651E-14 +2.231387E+00 +9.980240E-01 +1.684427E-02 +8.005737E-05 +1.749106E+08 +6.123032E+15 +1.067040E+02 +2.278956E+03 +1.088296E-02 +6.231251E-05 +3.176849E+02 +2.020075E+04 +1.031260E+02 +2.128783E+03 +1.031260E+02 +2.128783E+03 +tally 8: +6.429000E+00 +8.307829E+00 +1.437899E+00 +4.155824E-01 +1.141563E+00 +2.619392E-01 +2.853907E+00 +1.637120E+00 +4.896211E-05 +4.818601E-10 +2.835814E+00 +1.616427E+00 +1.809378E-02 +6.580509E-05 +2.283126E+08 +1.047757E+16 +6.429000E+00 +8.307829E+00 +8.477865E-03 +1.444687E-05 +1.176869E+01 +2.783921E+01 +1.067040E+02 +2.278956E+03 +3.661318E+00 +2.683178E+00 +8.949183E-01 +1.603029E-01 +2.237296E+00 +1.001893E+00 +6.755918E-07 +9.135730E-14 +2.223111E+00 +9.892292E-01 +1.418446E-02 +4.027174E-05 +1.789837E+08 +6.412115E+15 +1.067040E+02 +2.278956E+03 +6.646148E-03 +8.841267E-06 +3.176849E+02 +2.020075E+04 +tally 9: +6.371628E+00 +8.173477E+00 +1.425067E+00 +4.088618E-01 +1.131376E+00 +2.577032E-01 +2.828439E+00 +1.610645E+00 +2.650833E-05 +1.414721E-10 +2.810507E+00 +1.590286E+00 +1.793232E-02 +6.474091E-05 +2.262751E+08 +1.030813E+16 +6.432000E+00 +8.315518E+00 +8.402208E-03 +1.421324E-05 +1.166367E+01 +2.738901E+01 +1.062973E+02 +2.261709E+03 +3.647362E+00 +2.662872E+00 +8.915070E-01 +1.590897E-01 +2.228767E+00 +9.943106E-01 +2.260528E-07 +1.022851E-14 +2.214637E+00 +9.817427E-01 +1.413039E-02 +3.996696E-05 +1.783014E+08 +6.363588E+15 +1.069300E+02 +2.288574E+03 +6.620813E-03 +8.774357E-06 +3.164739E+02 +2.004788E+04 +tally 10: +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.887237E+00 +1.682974E+00 +1.410000E+00 +3.992220E-01 +1.410000E+00 +3.992220E-01 +0.000000E+00 +0.000000E+00 +1.017160E+02 +2.071035E+03 +1.017160E+02 +2.071035E+03 +2.248231E+00 +1.013550E+00 +tally 11: +2.542000E+00 +1.343070E+00 +1.260000E-01 +3.298000E-03 +4.838111E-02 +4.857369E-04 +1.202865E-01 +3.119670E-03 +6.000347E-07 +8.163458E-14 +1.202865E-01 +3.119670E-03 +0.000000E+00 +0.000000E+00 +9.676221E+06 +1.942948E+13 +2.542000E+00 +1.343070E+00 +0.000000E+00 +0.000000E+00 +1.949000E+00 +8.324030E-01 +9.000000E-02 +1.762000E-03 +3.793334E-02 +3.031575E-04 +1.081691E-01 +2.457437E-03 +5.571912E-07 +6.439495E-14 +1.071378E-01 +2.411702E-03 +1.031308E-03 +1.063597E-06 +7.586669E+06 +1.212630E+13 +1.949000E+00 +8.324030E-01 +3.122595E-04 +9.750600E-08 +1.039000E+00 +2.447670E-01 +4.200000E-02 +4.120000E-04 +1.685968E-02 +6.389070E-05 +4.929366E-02 +5.628729E-04 +2.018053E-07 +1.119308E-14 +4.823620E-02 +5.371538E-04 +1.057461E-03 +1.118225E-06 +3.371936E+06 +2.555628E+12 +1.039000E+00 +2.447670E-01 +3.201782E-04 +1.025141E-07 +5.930000E-01 +7.205300E-02 +2.300000E-02 +1.110000E-04 +1.056715E-02 +2.338156E-05 +2.528379E-02 +1.491420E-04 +1.384831E-07 +6.031333E-15 +2.528379E-02 +1.491420E-04 +0.000000E+00 +0.000000E+00 +2.113430E+06 +9.352624E+11 +5.930000E-01 +7.205300E-02 +0.000000E+00 +0.000000E+00 +3.501000E+00 +2.515635E+00 +1.600000E-01 +5.250000E-03 +5.998847E-02 +7.320149E-04 +1.529867E-01 +4.932068E-03 +7.476127E-07 +1.267077E-13 +1.529867E-01 +4.932068E-03 +0.000000E+00 +0.000000E+00 +1.199769E+07 +2.928060E+13 +3.501000E+00 +2.515635E+00 +0.000000E+00 +0.000000E+00 +4.454000E+00 +4.082446E+00 +1.920000E-01 +7.726000E-03 +8.044824E-02 +1.327101E-03 +2.231973E-01 +1.024637E-02 +1.236154E-06 +3.183460E-13 +2.211081E-01 +1.008915E-02 +2.089232E-03 +2.182800E-06 +1.608965E+07 +5.308405E+13 +4.454000E+00 +4.082446E+00 +3.894344E-03 +9.877407E-06 +4.210000E+00 +3.829106E+00 +1.750000E-01 +6.549000E-03 +7.464456E-02 +1.228199E-03 +1.787859E-01 +7.634408E-03 +1.144154E-06 +3.572375E-13 +1.777141E-01 +7.525287E-03 +1.071750E-03 +1.148648E-06 +1.492891E+07 +4.912798E+13 +4.210000E+00 +3.829106E+00 +3.245044E-04 +1.053031E-07 +1.364000E+00 +3.933640E-01 +8.200000E-02 +1.378000E-03 +3.158206E-02 +2.047576E-04 +5.983520E-02 +7.581471E-04 +3.272437E-07 +2.772035E-14 +5.983520E-02 +7.581471E-04 +0.000000E+00 +0.000000E+00 +6.316412E+06 +8.190302E+12 +1.364000E+00 +3.933640E-01 +0.000000E+00 +0.000000E+00 +1.363000E+00 +4.205090E-01 +7.000000E-02 +1.130000E-03 +2.590153E-02 +1.476101E-04 +5.594611E-02 +6.902009E-04 +2.690262E-07 +1.501020E-14 +5.594611E-02 +6.902009E-04 +0.000000E+00 +0.000000E+00 +5.180306E+06 +5.904403E+12 +1.363000E+00 +4.205090E-01 +0.000000E+00 +0.000000E+00 +1.246000E+00 +3.852900E-01 +5.300000E-02 +6.650000E-04 +1.954836E-02 +9.404628E-05 +4.771133E-02 +6.866474E-04 +1.814542E-07 +1.125942E-14 +4.771133E-02 +6.866474E-04 +0.000000E+00 +0.000000E+00 +3.909672E+06 +3.761851E+12 +1.246000E+00 +3.852900E-01 +0.000000E+00 +0.000000E+00 +tally 12: +2.599889E+00 +1.402744E+00 +1.167830E-01 +2.830760E-03 +4.644159E-02 +4.578546E-04 +1.161040E-01 +2.861591E-03 +6.110737E-07 +8.591437E-14 +1.153679E-01 +2.825421E-03 +7.360997E-04 +1.150235E-07 +9.288319E+06 +1.831418E+13 +2.589000E+00 +1.391365E+00 +3.449004E-04 +2.525229E-08 +1.935337E+00 +8.143708E-01 +9.059861E-02 +1.758063E-03 +3.784648E-02 +3.023430E-04 +9.461621E-02 +1.889644E-03 +5.353929E-07 +5.956643E-14 +9.401634E-02 +1.865759E-03 +5.998671E-04 +7.595546E-08 +7.569296E+06 +1.209372E+13 +1.989000E+00 +8.632630E-01 +2.810685E-04 +1.667528E-08 +1.015076E+00 +2.265305E-01 +4.209446E-02 +3.711488E-04 +1.500394E-02 +4.824763E-05 +3.750984E-02 +3.015477E-04 +1.616914E-07 +8.025617E-15 +3.727203E-02 +2.977362E-04 +2.378125E-04 +1.212091E-08 +3.000787E+06 +1.929905E+12 +1.051000E+00 +2.509110E-01 +1.114274E-04 +2.661027E-09 +6.199894E-01 +7.878811E-02 +2.804937E-02 +1.607308E-04 +1.125386E-02 +2.891349E-05 +2.813466E-02 +1.807093E-04 +1.501221E-07 +7.165022E-15 +2.795628E-02 +1.784252E-04 +1.783738E-04 +7.263729E-09 +2.250773E+06 +1.156540E+12 +6.190000E-01 +7.822300E-02 +8.357728E-05 +1.594681E-09 +3.398516E+00 +2.363683E+00 +1.505108E-01 +4.655588E-03 +5.879057E-02 +7.289809E-04 +1.469764E-01 +4.556130E-03 +7.516677E-07 +1.300615E-13 +1.460446E-01 +4.498542E-03 +9.318311E-04 +1.831366E-07 +1.175811E+07 +2.915923E+13 +3.542000E+00 +2.572512E+00 +4.366106E-04 +4.020586E-08 +4.395956E+00 +3.964331E+00 +2.146513E-01 +9.286938E-03 +9.388516E-02 +1.784380E-03 +2.347129E-01 +1.115237E-02 +1.410768E-06 +4.182007E-13 +2.332248E-01 +1.101141E-02 +1.488081E-03 +4.482769E-07 +1.877703E+07 +7.137519E+13 +4.497000E+00 +4.157935E+00 +6.972420E-04 +9.841483E-08 +4.157899E+00 +3.751197E+00 +1.897379E-01 +8.038105E-03 +7.692709E-02 +1.413632E-03 +1.923177E-01 +8.835202E-03 +1.042521E-06 +3.025447E-13 +1.910984E-01 +8.723527E-03 +1.219295E-03 +3.551367E-07 +1.538542E+07 +5.654529E+13 +4.268000E+00 +3.930780E+00 +5.713023E-04 +7.796680E-08 +1.357524E+00 +3.878228E-01 +5.983682E-02 +7.460748E-04 +2.322979E-02 +1.144334E-04 +5.807447E-02 +7.152085E-04 +2.940107E-07 +2.024706E-14 +5.770628E-02 +7.061684E-04 +3.681924E-04 +2.874827E-08 +4.645957E+06 +4.577335E+12 +1.390000E+00 +4.083140E-01 +1.725170E-04 +6.311403E-09 +1.376941E+00 +4.321098E-01 +6.198249E-02 +8.400785E-04 +2.471448E-02 +1.321749E-04 +6.178621E-02 +8.260929E-04 +3.265418E-07 +2.485223E-14 +6.139448E-02 +8.156513E-04 +3.917248E-04 +3.320534E-08 +4.942896E+06 +5.286995E+12 +1.395000E+00 +4.400290E-01 +1.835431E-04 +7.289909E-09 +1.267762E+00 +4.052744E-01 +5.233659E-02 +6.929809E-04 +1.852753E-02 +9.379170E-05 +4.631882E-02 +5.861981E-04 +1.967460E-07 +1.534801E-14 +4.602516E-02 +5.787887E-04 +2.936615E-04 +2.356261E-08 +3.705506E+06 +3.751668E+12 +1.284000E+00 +4.070420E-01 +1.375955E-04 +5.172942E-09 +tally 13: +1.131330E+02 +2.561428E+03 +4.988000E+00 +4.976048E+00 +1.993967E+00 +7.956428E-01 +5.135468E+00 +5.291611E+00 +2.697394E-05 +1.462336E-10 +5.101779E+00 +5.222461E+00 +3.368875E-02 +2.575850E-04 +3.987934E+08 +3.182571E+16 +1.131330E+02 +2.561428E+03 +1.464422E-02 +8.408713E-05 +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +tally 14: +1.131330E+02 +2.561428E+03 +5.099217E+00 +5.202791E+00 +2.036481E+00 +8.305328E-01 +5.091203E+00 +5.190830E+00 +4.963770E-05 +4.951715E-10 +5.058925E+00 +5.125219E+00 +3.227825E-02 +2.086488E-04 +4.072963E+08 +3.322131E+16 +1.131330E+02 +2.561428E+03 +1.512401E-02 +4.580681E-05 +tally 15: +1.126689E+02 +2.540742E+03 +5.072428E+00 +5.150411E+00 +2.022883E+00 +8.201638E-01 +5.057207E+00 +5.126024E+00 +2.673439E-05 +1.438788E-10 +5.025144E+00 +5.061232E+00 +3.206271E-02 +2.060439E-04 +4.045765E+08 +3.280655E+16 +1.133620E+02 +2.571755E+03 +1.502302E-02 +4.523492E-05 +tally 16: +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +5.135468E+00 +5.291611E+00 +tally 17: +6.429000E+00 +8.307829E+00 +1.410000E+00 +3.992220E-01 +1.119414E+00 +2.516273E-01 +2.887237E+00 +1.682974E+00 +2.674702E-05 +1.437976E-10 +2.870392E+00 +1.663680E+00 +1.684448E-02 +5.768606E-05 +2.238828E+08 +1.006509E+16 +6.429000E+00 +8.307829E+00 +3.761262E-03 +3.156399E-06 +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +1.067040E+02 +2.278956E+03 +3.578000E+00 +2.562210E+00 +8.745532E-01 +1.530758E-01 +2.248231E+00 +1.013550E+00 +2.269178E-07 +1.030651E-14 +2.231387E+00 +9.980240E-01 +1.684427E-02 +8.005737E-05 +1.749106E+08 +6.123032E+15 +1.067040E+02 +2.278956E+03 +1.088296E-02 +6.231251E-05 +1.031260E+02 +2.128783E+03 +1.031260E+02 +2.128783E+03 +tally 18: +6.429000E+00 +8.307829E+00 +1.437899E+00 +4.155824E-01 +1.141563E+00 +2.619392E-01 +2.853907E+00 +1.637120E+00 +4.896211E-05 +4.818601E-10 +2.835814E+00 +1.616427E+00 +1.809378E-02 +6.580509E-05 +2.283126E+08 +1.047757E+16 +6.429000E+00 +8.307829E+00 +8.477865E-03 +1.444687E-05 +1.067040E+02 +2.278956E+03 +3.661318E+00 +2.683178E+00 +8.949183E-01 +1.603029E-01 +2.237296E+00 +1.001893E+00 +6.755918E-07 +9.135730E-14 +2.223111E+00 +9.892292E-01 +1.418446E-02 +4.027174E-05 +1.789837E+08 +6.412115E+15 +1.067040E+02 +2.278956E+03 +6.646148E-03 +8.841267E-06 +tally 19: +6.371628E+00 +8.173477E+00 +1.425067E+00 +4.088618E-01 +1.131376E+00 +2.577032E-01 +2.828439E+00 +1.610645E+00 +2.650833E-05 +1.414721E-10 +2.810507E+00 +1.590286E+00 +1.793232E-02 +6.474091E-05 +2.262751E+08 +1.030813E+16 +6.432000E+00 +8.315518E+00 +8.402208E-03 +1.421324E-05 +1.062973E+02 +2.261709E+03 +3.647362E+00 +2.662872E+00 +8.915070E-01 +1.590897E-01 +2.228767E+00 +9.943106E-01 +2.260528E-07 +1.022851E-14 +2.214637E+00 +9.817427E-01 +1.413039E-02 +3.996696E-05 +1.783014E+08 +6.363588E+15 +1.069300E+02 +2.288574E+03 +6.620813E-03 +8.774357E-06 +tally 20: +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.887237E+00 +1.682974E+00 +1.410000E+00 +3.992220E-01 +1.410000E+00 +3.992220E-01 +0.000000E+00 +0.000000E+00 +1.017160E+02 +2.071035E+03 +1.017160E+02 +2.071035E+03 +2.248231E+00 +1.013550E+00 diff --git a/tests/regression_tests/mg_tallies/test.py b/tests/regression_tests/mg_tallies/test.py index e1c19e6b7..f4e9693f6 100644 --- a/tests/regression_tests/mg_tallies/test.py +++ b/tests/regression_tests/mg_tallies/test.py @@ -5,7 +5,7 @@ import numpy as np import openmc from openmc.examples import slab_mg -from tests.testing_harness import HashedPyAPITestHarness +from tests.testing_harness import PyAPITestHarness def create_library(): @@ -49,7 +49,7 @@ def create_library(): mg_cross_sections_file.export_to_hdf5('2g.h5') -class MGXSTestHarness(HashedPyAPITestHarness): +class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() f = '2g.h5' @@ -144,5 +144,5 @@ def test_mg_tallies(): t.nuclides = nuclides model.tallies.append(t) - harness = HashedPyAPITestHarness('statepoint.10.h5', model) + harness = MGXSTestHarness('statepoint.10.h5', model) harness.main() diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/__init__.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/__init__.py new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..576f27966 --- /dev/null +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 3 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + total + flux + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-fission + analog + + + 1 2 + total + flux + analog + + + 1 2 7 11 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + scatter + analog + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 15 2 + total + flux + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 15 2 + total + flux + analog + + + 15 2 7 11 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + total + tracklength + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + absorption + tracklength + + + 29 2 + total + flux + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-fission + analog + + + 29 2 + total + flux + analog + + + 29 2 7 11 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + scatter + analog + + diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat new file mode 100644 index 000000000..b494a4b4f --- /dev/null +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +5.350442E-01 1.484490E-02 diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py new file mode 100644 index 000000000..b624140d4 --- /dev/null +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py @@ -0,0 +1,85 @@ +import os + +import openmc +import openmc.mgxs +from openmc.examples import pwr_pin_cell + +from tests.testing_harness import PyAPITestHarness +from tests.regression_tests import config + + +class MGXSTestHarness(PyAPITestHarness): + def __init__(self, *args, **kwargs): + # Generate inputs using parent class routine + super().__init__(*args, **kwargs) + + # Initialize a two-group structure + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + + # Initialize MGXS Library for a few cross section types + self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) + self.mgxs_lib.by_nuclide = True + self.mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission matrix', + 'nu-scatter matrix', 'multiplicity matrix'] + self.mgxs_lib.energy_groups = energy_groups + self.mgxs_lib.correction = None + self.mgxs_lib.legendre_order = 3 + self.mgxs_lib.domain_type = 'material' + self.mgxs_lib.build_library() + + # Initialize a tallies file + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) + + def _run_openmc(self): + # Initial run + if config['mpi']: + mpi_args = [config['mpiexec'], '-n', config['mpi_np']] + openmc.run(openmc_exec=config['exe'], mpi_args=mpi_args) + else: + openmc.run(openmc_exec=config['exe']) + + # Build MG Inputs + # Get data needed to execute Library calculations. + sp = openmc.StatePoint(self._sp_name) + self.mgxs_lib.load_from_statepoint(sp) + self._model.mgxs_file, self._model.materials, \ + self._model.geometry = self.mgxs_lib.create_mg_mode() + + # Modify materials and settings so we can run in MG mode + self._model.materials.cross_sections = './mgxs.h5' + self._model.settings.energy_mode = 'multi-group' + + # Write modified input files + self._model.settings.export_to_xml() + self._model.geometry.export_to_xml() + self._model.materials.export_to_xml() + self._model.mgxs_file.export_to_hdf5() + # Dont need tallies.xml, so remove the file + if os.path.exists('tallies.xml'): + os.remove('tallies.xml') + + # Enforce closing statepoint and summary files so HDF5 + # does not throw an error during the next OpenMC execution + sp._f.close() + sp._summary._f.close() + + # Re-run MG mode. + if config['mpi']: + mpi_args = [config['mpiexec'], '-n', config['mpi_np']] + openmc.run(openmc_exec=config['exe'], mpi_args=mpi_args) + else: + openmc.run(openmc_exec=config['exe']) + + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mgxs_library_ce_to_mg(): + # Set the input set to use the pincell model + model = pwr_pin_cell() + + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/regression_tests/source/inputs_true.dat b/tests/regression_tests/source/inputs_true.dat index 7eeefbc00..6f05eb3a7 100644 --- a/tests/regression_tests/source/inputs_true.dat +++ b/tests/regression_tests/source/inputs_true.dat @@ -41,7 +41,7 @@ - + 1.2 -2.3 0.781 @@ -50,4 +50,17 @@ 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.7853981633974483 1.5707963267948966 2.356194490192345 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 + + diff --git a/tests/regression_tests/source/results_true.dat b/tests/regression_tests/source/results_true.dat index 90cc3ec1f..8f24644f0 100644 --- a/tests/regression_tests/source/results_true.dat +++ b/tests/regression_tests/source/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.026614E-01 3.952008E-03 +3.004769E-01 3.944044E-03 diff --git a/tests/regression_tests/source/test.py b/tests/regression_tests/source/test.py index cd468c5b8..5fd06286b 100644 --- a/tests/regression_tests/source/test.py +++ b/tests/regression_tests/source/test.py @@ -29,9 +29,16 @@ class SourceTestHarness(PyAPITestHarness): x_dist = openmc.stats.Uniform(-3., 3.) y_dist = openmc.stats.Discrete([-4., -1., 3.], [0.2, 0.3, 0.5]) z_dist = openmc.stats.Tabular([-2., 0., 2.], [0.2, 0.3, 0.2]) + r_dist = openmc.stats.Uniform(2., 3.) + theta_dist = openmc.stats.Discrete([pi/4, pi/2, 3*pi/4], + [0.3, 0.4, 0.3]) + phi_dist = openmc.stats.Uniform(0.0, 2*pi) spatial1 = openmc.stats.CartesianIndependent(x_dist, y_dist, z_dist) spatial2 = openmc.stats.Box([-4., -4., -4.], [4., 4., 4.]) spatial3 = openmc.stats.Point([1.2, -2.3, 0.781]) + spatial4 = openmc.stats.SphericalIndependent(r_dist, theta_dist, + phi_dist, + origin=(1.0, 1.0, 0.0)) mu_dist = openmc.stats.Discrete([-1., 0., 1.], [0.5, 0.25, 0.25]) phi_dist = openmc.stats.Uniform(0., 6.28318530718) @@ -48,13 +55,14 @@ class SourceTestHarness(PyAPITestHarness): source1 = openmc.Source(spatial1, angle1, energy1, strength=0.5) source2 = openmc.Source(spatial2, angle2, energy2, strength=0.3) - source3 = openmc.Source(spatial3, angle3, energy3, strength=0.2) + source3 = openmc.Source(spatial3, angle3, energy3, strength=0.1) + source4 = openmc.Source(spatial4, angle3, energy3, strength=0.1) settings = openmc.Settings() settings.batches = 10 settings.inactive = 5 settings.particles = 1000 - settings.source = [source1, source2, source3] + settings.source = [source1, source2, source3, source4] settings.export_to_xml() diff --git a/tests/regression_tests/volume_calc/inputs_true.dat b/tests/regression_tests/volume_calc/inputs_true.dat index 607921af2..aaf6d8b00 100644 --- a/tests/regression_tests/volume_calc/inputs_true.dat +++ b/tests/regression_tests/volume_calc/inputs_true.dat @@ -48,4 +48,28 @@ -1.0 -1.0 -6.0 1.0 1.0 6.0 + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + material + 1 2 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + diff --git a/tests/regression_tests/volume_calc/results_true.dat b/tests/regression_tests/volume_calc/results_true.dat index 466139cd6..800356e35 100644 --- a/tests/regression_tests/volume_calc/results_true.dat +++ b/tests/regression_tests/volume_calc/results_true.dat @@ -1,4 +1,7 @@ Volume calculation 0 +Trigger Type: None +Trigger threshold: None +Iterations: 1 Domain 1: 31.47+/-0.07 cm^3 Domain 2: 2.093+/-0.031 cm^3 Domain 3: 2.049+/-0.031 cm^3 @@ -12,6 +15,9 @@ Domain 3: 2.049+/-0.031 cm^3 6 3 O16 (6.85+/-0.10)e+22 7 3 B10 (6.85+/-0.10)e+18 Volume calculation 1 +Trigger Type: None +Trigger threshold: None +Iterations: 1 Domain 1: 4.14+/-0.04 cm^3 Domain 2: 31.47+/-0.07 cm^3 Material Nuclide Atoms @@ -21,6 +27,9 @@ Domain 2: 31.47+/-0.07 cm^3 3 2 U235 (3.482+/-0.008)e+23 4 2 Mo99 (3.482+/-0.008)e+22 Volume calculation 2 +Trigger Type: None +Trigger threshold: None +Iterations: 1 Domain 0: 35.61+/-0.07 cm^3 Universe Nuclide Atoms 0 0 H1 (2.770+/-0.029)e+23 @@ -28,3 +37,47 @@ Domain 0: 35.61+/-0.07 cm^3 2 0 B10 (1.385+/-0.014)e+19 3 0 U235 (3.482+/-0.008)e+23 4 0 Mo99 (3.482+/-0.008)e+22 +Volume calculation 3 +Trigger Type: std_dev +Trigger threshold: 0.1 +Iterations: 521 +Domain 1: 31.47+/-0.10 cm^3 +Domain 2: 2.10+/-0.04 cm^3 +Domain 3: 2.11+/-0.04 cm^3 + Cell Nuclide Atoms +0 1 U235 (3.481+/-0.011)e+23 +1 1 Mo99 (3.481+/-0.011)e+22 +2 2 H1 (1.403+/-0.029)e+23 +3 2 O16 (7.01+/-0.14)e+22 +4 2 B10 (7.01+/-0.14)e+18 +5 3 H1 (1.412+/-0.029)e+23 +6 3 O16 (7.06+/-0.14)e+22 +7 3 B10 (7.06+/-0.14)e+18 +Volume calculation 4 +Trigger Type: rel_err +Trigger threshold: 0.1 +Iterations: 10 +Domain 1: 4.5+/-0.4 cm^3 +Domain 2: 30.5+/-0.7 cm^3 + Material Nuclide Atoms +0 1 H1 (3.02+/-0.30)e+23 +1 1 O16 (1.51+/-0.15)e+23 +2 1 B10 (1.51+/-0.15)e+19 +3 2 U235 (3.38+/-0.08)e+23 +4 2 Mo99 (3.38+/-0.08)e+22 +Volume calculation 5 +Trigger Type: variance +Trigger threshold: 0.05 +Iterations: 105 +Domain 1: 31.51+/-0.22 cm^3 +Domain 2: 2.13+/-0.10 cm^3 +Domain 3: 2.11+/-0.10 cm^3 + Cell Nuclide Atoms +0 1 U235 (3.486+/-0.025)e+23 +1 1 Mo99 (3.486+/-0.025)e+22 +2 2 H1 (1.42+/-0.06)e+23 +3 2 O16 (7.11+/-0.32)e+22 +4 2 B10 (7.11+/-0.32)e+18 +5 3 H1 (1.41+/-0.06)e+23 +6 3 O16 (7.05+/-0.32)e+22 +7 3 B10 (7.05+/-0.32)e+18 diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 8ea4ab04e..f7b9a27a0 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -8,6 +8,14 @@ from tests.testing_harness import PyAPITestHarness class VolumeTest(PyAPITestHarness): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.exp_std_dev = 1e-01 + self.exp_rel_err = 1e-01 + self.exp_variance = 5e-02 + def _build_inputs(self): # Define materials water = openmc.Material(1) @@ -45,9 +53,18 @@ class VolumeTest(PyAPITestHarness): vol_calcs = [ openmc.VolumeCalculation(list(root.cells.values()), 100000), openmc.VolumeCalculation([water, fuel], 100000, ll, ur), - openmc.VolumeCalculation([root], 100000, ll, ur) + openmc.VolumeCalculation([root], 100000, ll, ur), + openmc.VolumeCalculation(list(root.cells.values()), 100), + openmc.VolumeCalculation([water, fuel], 100, ll, ur), + openmc.VolumeCalculation(list(root.cells.values()), 100) ] + vol_calcs[3].set_trigger(self.exp_std_dev, 'std_dev') + + vol_calcs[4].set_trigger(self.exp_rel_err, 'rel_err') + + vol_calcs[5].set_trigger(self.exp_variance, 'variance') + # Define settings settings = openmc.Settings() settings.run_mode = 'volume' @@ -62,6 +79,33 @@ class VolumeTest(PyAPITestHarness): # Read volume calculation results volume_calc = openmc.VolumeCalculation.from_hdf5(filename) + outstr += 'Trigger Type: {}\n'.format(volume_calc.trigger_type) + outstr += 'Trigger threshold: {}\n'.format(volume_calc.threshold) + outstr += 'Iterations: {}\n'.format(volume_calc.iterations) + + if i == 3: + assert(volume_calc.trigger_type == 'std_dev') + assert(volume_calc.threshold == self.exp_std_dev) + elif i == 4: + assert(volume_calc.trigger_type == 'rel_err') + assert(volume_calc.threshold == self.exp_rel_err) + elif i == 5: + assert(volume_calc.trigger_type == 'variance') + assert(volume_calc.threshold == self.exp_variance) + else: + assert(volume_calc.trigger_type == None) + assert(volume_calc.threshold == None) + assert(volume_calc.iterations == 1) + + # if a trigger is applied, make sure the calculation satisfies the trigger + for vol in volume_calc.volumes.values(): + if volume_calc.trigger_type == 'std_dev': + assert(vol.std_dev <= self.exp_std_dev) + if volume_calc.trigger_type == 'rel_err': + assert(vol.std_dev/vol.nominal_value <= self.exp_rel_err) + if volume_calc.trigger_type == 'variance': + assert(vol.std_dev * vol.std_dev <= self.exp_variance) + # Write cell volumes and total # of atoms for each nuclide for uid, volume in sorted(volume_calc.volumes.items()): outstr += 'Domain {}: {} cm^3\n'.format(uid, volume) diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 0d3c4bec0..2266189c0 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -10,9 +10,25 @@ import sys import numpy as np import openmc from openmc.examples import pwr_core +from colorama import Fore, init from tests.regression_tests import config +init() + + +def colorize(diff): + """Produce colored diff for test results""" + for line in diff: + if line.startswith('+'): + yield Fore.RED + line + Fore.RESET + elif line.startswith('-'): + yield Fore.GREEN + line + Fore.RESET + elif line.startswith('^'): + yield Fore.BLUE + line + Fore.RESET + else: + yield line + class TestHarness(object): """General class for running OpenMC regression tests.""" @@ -108,11 +124,17 @@ class TestHarness(object): shutil.copyfile('results_test.dat', 'results_true.dat') def _compare_results(self): - """Make sure the current results agree with the _true standard.""" + """Make sure the current results agree with the reference.""" compare = filecmp.cmp('results_test.dat', 'results_true.dat') if not compare: + expected = open('results_true.dat').readlines() + actual = open('results_test.dat').readlines() + diff = unified_diff(expected, actual, 'results_true.dat', + 'results_test.dat') + print('Result differences:') + print(''.join(colorize(diff))) os.rename('results_test.dat', 'results_error.dat') - assert compare, 'Results do not agree.' + assert compare, 'Results do not agree' def _cleanup(self): """Delete statepoints, tally, and test files.""" @@ -325,11 +347,13 @@ class PyAPITestHarness(TestHarness): """Make sure the current inputs agree with the _true standard.""" compare = filecmp.cmp('inputs_test.dat', 'inputs_true.dat') if not compare: + expected = open('inputs_true.dat', 'r').readlines() + actual = open('inputs_error.dat', 'r').readlines() + diff = unified_diff(expected, actual, 'inputs_true.dat', + 'inputs_error.dat') + print('Input differences:') + print(''.join(colorize(diff))) os.rename('inputs_test.dat', 'inputs_error.dat') - for line in unified_diff(open('inputs_true.dat', 'r').readlines(), - open('inputs_error.dat', 'r').readlines(), - 'inputs_true.dat', 'inputs_error.dat'): - print(line, end='') assert compare, 'Input files are broken.' def _cleanup(self): diff --git a/tests/unit_tests/dagmc/test.py b/tests/unit_tests/dagmc/test.py index f7b2844f6..e5d772555 100644 --- a/tests/unit_tests/dagmc/test.py +++ b/tests/unit_tests/dagmc/test.py @@ -38,7 +38,7 @@ def dagmc_model(request): model.tallies = [tally] # materials - u235 = openmc.Material(name="fuel") + u235 = openmc.Material(name="no-void fuel") u235.add_nuclide('U235', 1.0, 'ao') u235.set_density('g/cc', 11) u235.id = 40 diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index 69211f72e..70d90b615 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -280,3 +280,24 @@ def test_from_xml(run_in_tmpdir, mixed_lattice_model): ll, ur = geom.bounding_box assert ll == pytest.approx((-6.0, -6.0, -np.inf)) assert ur == pytest.approx((6.0, 6.0, np.inf)) + + +def test_rotation_matrix(): + """Test ability to set a rotation matrix directly""" + y = openmc.YPlane() + cyl1 = openmc.ZCylinder(r=1.0) + cyl2 = openmc.ZCylinder(r=2.0, boundary_type='vacuum') + + # Create a universe and then reflect in the y-direction + c1 = openmc.Cell(region=-cyl1 & +y) + c2 = openmc.Cell(region=+cyl1 & +y) + c3 = openmc.Cell(region=-y) + univ = openmc.Universe(cells=[c1, c2, c3]) + c = openmc.Cell(fill=univ, region=-cyl2) + c.rotation = [[1, 0, 0], [0, -1, 0], [0, 0, 1]] + assert np.all(c.rotation_matrix == c.rotation) + geom = openmc.Geometry([c]) + + assert geom.find((0.0, 0.5, 0.0))[-1] == c3 + assert geom.find((0.0, -0.5, 0.0))[-1] == c1 + assert geom.find((0.0, -1.5, 0.0))[-1] == c2 diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 2f39f0b0d..ad198f255 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -50,24 +50,24 @@ def pincell_model(): @pytest.fixture(scope='module') -def capi_init(pincell_model, mpi_intracomm): +def lib_init(pincell_model, mpi_intracomm): openmc.lib.init(intracomm=mpi_intracomm) yield openmc.lib.finalize() @pytest.fixture(scope='module') -def capi_simulation_init(capi_init): +def lib_simulation_init(lib_init): openmc.lib.simulation_init() yield @pytest.fixture(scope='module') -def capi_run(capi_simulation_init): +def lib_run(lib_simulation_init): openmc.lib.run() -def test_cell_mapping(capi_init): +def test_cell_mapping(lib_init): cells = openmc.lib.cells assert isinstance(cells, Mapping) assert len(cells) == 3 @@ -76,7 +76,7 @@ def test_cell_mapping(capi_init): assert cell_id == cell.id -def test_cell(capi_init): +def test_cell(lib_init): cell = openmc.lib.cells[1] assert isinstance(cell.fill, openmc.lib.Material) cell.fill = openmc.lib.materials[1] @@ -85,7 +85,7 @@ def test_cell(capi_init): cell.name = "Not fuel" assert cell.name == "Not fuel" -def test_cell_temperature(capi_init): +def test_cell_temperature(lib_init): cell = openmc.lib.cells[1] cell.set_temperature(100.0, 0) assert cell.get_temperature(0) == 100.0 @@ -93,7 +93,7 @@ def test_cell_temperature(capi_init): assert cell.get_temperature() == 200.0 -def test_new_cell(capi_init): +def test_new_cell(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Cell(1) new_cell = openmc.lib.Cell() @@ -101,7 +101,7 @@ def test_new_cell(capi_init): assert len(openmc.lib.cells) == 5 -def test_material_mapping(capi_init): +def test_material_mapping(lib_init): mats = openmc.lib.materials assert isinstance(mats, Mapping) assert len(mats) == 3 @@ -110,7 +110,7 @@ def test_material_mapping(capi_init): assert mat_id == mat.id -def test_material(capi_init): +def test_material(lib_init): m = openmc.lib.materials[3] assert m.nuclides == ['H1', 'O16', 'B10', 'B11'] @@ -136,14 +136,14 @@ def test_material(capi_init): m.name = "Not hot borated water" assert m.name == "Not hot borated water" -def test_material_add_nuclide(capi_init): +def test_material_add_nuclide(lib_init): m = openmc.lib.materials[3] m.add_nuclide('Xe135', 1e-12) assert m.nuclides[-1] == 'Xe135' assert m.densities[-1] == 1e-12 -def test_new_material(capi_init): +def test_new_material(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Material(1) new_mat = openmc.lib.Material() @@ -151,7 +151,7 @@ def test_new_material(capi_init): assert len(openmc.lib.materials) == 5 -def test_nuclide_mapping(capi_init): +def test_nuclide_mapping(lib_init): nucs = openmc.lib.nuclides assert isinstance(nucs, Mapping) assert len(nucs) == 13 @@ -160,7 +160,7 @@ def test_nuclide_mapping(capi_init): assert name == nuc.name -def test_settings(capi_init): +def test_settings(lib_init): settings = openmc.lib.settings assert settings.batches == 10 settings.batches = 10 @@ -175,7 +175,7 @@ def test_settings(capi_init): settings.run_mode = 'eigenvalue' -def test_tally_mapping(capi_init): +def test_tally_mapping(lib_init): tallies = openmc.lib.tallies assert isinstance(tallies, Mapping) assert len(tallies) == 3 @@ -184,7 +184,7 @@ def test_tally_mapping(capi_init): assert tally_id == tally.id -def test_energy_function_filter(capi_init): +def test_energy_function_filter(lib_init): """Test special __new__ and __init__ for EnergyFunctionFilter""" efunc = openmc.lib.EnergyFunctionFilter([0.0, 1.0], [0.0, 2.0]) assert len(efunc.energy) == 2 @@ -193,7 +193,7 @@ def test_energy_function_filter(capi_init): assert (efunc.y == [0.0, 2.0]).all() -def test_tally(capi_init): +def test_tally(lib_init): t = openmc.lib.tallies[1] assert t.type == 'volume' assert len(t.filters) == 2 @@ -239,7 +239,7 @@ def test_tally(capi_init): assert len(t3_f.y) == 3 -def test_new_tally(capi_init): +def test_new_tally(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Material(1) new_tally = openmc.lib.Tally() @@ -249,16 +249,25 @@ def test_new_tally(capi_init): assert len(openmc.lib.tallies) == 5 -def test_tally_activate(capi_simulation_init): +def test_tally_activate(lib_simulation_init): t = openmc.lib.tallies[1] assert not t.active t.active = True assert t.active -def test_tally_results(capi_run): +def test_tally_writable(lib_simulation_init): t = openmc.lib.tallies[1] - assert t.num_realizations == 10 # t was made active in test_tally + assert t.writable + t.writable = False + assert not t.writable + # Revert tally to writable state for lib_run fixtures + t.writable = True + + +def test_tally_results(lib_run): + t = openmc.lib.tallies[1] + assert t.num_realizations == 10 # t was made active in test_tally_active assert np.all(t.mean >= 0) nonzero = (t.mean > 0.0) assert np.all(t.std_dev[nonzero] >= 0) @@ -269,26 +278,26 @@ def test_tally_results(capi_run): assert t2.mean.size == (n + 1) * (n + 2) // 2 * 3 # Number of Zernike coeffs * 3 cells -def test_global_tallies(capi_run): +def test_global_tallies(lib_run): assert openmc.lib.num_realizations() == 5 gt = openmc.lib.global_tallies() for mean, std_dev in gt: assert mean >= 0 -def test_statepoint(capi_run): +def test_statepoint(lib_run): openmc.lib.statepoint_write('test_sp.h5') assert os.path.exists('test_sp.h5') -def test_source_bank(capi_run): +def test_source_bank(lib_run): source = openmc.lib.source_bank() assert np.all(source['E'] > 0.0) assert np.all(source['wgt'] == 1.0) assert np.allclose(np.linalg.norm(source['u'], axis=1), 1.0) -def test_by_batch(capi_run): +def test_by_batch(lib_run): openmc.lib.hard_reset() # Running next batch before simulation is initialized should raise an @@ -313,7 +322,7 @@ def test_by_batch(capi_run): openmc.lib.simulation_finalize() -def test_reset(capi_run): +def test_reset(lib_run): # Init and run 10 batches. openmc.lib.hard_reset() openmc.lib.simulation_init() @@ -344,7 +353,7 @@ def test_reset(capi_run): openmc.lib.simulation_finalize() -def test_reproduce_keff(capi_init): +def test_reproduce_keff(lib_init): # Get k-effective after run openmc.lib.hard_reset() openmc.lib.run() @@ -357,7 +366,7 @@ def test_reproduce_keff(capi_init): assert keff0 == pytest.approx(keff1) -def test_find_cell(capi_init): +def test_find_cell(lib_init): cell, instance = openmc.lib.find_cell((0., 0., 0.)) assert cell is openmc.lib.cells[1] cell, instance = openmc.lib.find_cell((0.4, 0., 0.)) @@ -366,14 +375,14 @@ def test_find_cell(capi_init): openmc.lib.find_cell((100., 100., 100.)) -def test_find_material(capi_init): +def test_find_material(lib_init): mat = openmc.lib.find_material((0., 0., 0.)) assert mat is openmc.lib.materials[1] mat = openmc.lib.find_material((0.4, 0., 0.)) assert mat is openmc.lib.materials[2] -def test_mesh(capi_init): +def test_mesh(lib_init): mesh = openmc.lib.RegularMesh() mesh.dimension = (2, 3, 4) assert mesh.dimension == (2, 3, 4) @@ -408,7 +417,7 @@ def test_mesh(capi_init): assert msf.mesh == mesh -def test_restart(capi_init, mpi_intracomm): +def test_restart(lib_init, mpi_intracomm): # Finalize and re-init to make internal state consistent with XML. openmc.lib.hard_reset() openmc.lib.finalize() @@ -440,7 +449,7 @@ def test_restart(capi_init, mpi_intracomm): assert keff0 == pytest.approx(keff1) -def test_load_nuclide(capi_init): +def test_load_nuclide(lib_init): # load multiple nuclides openmc.lib.load_nuclide('H3') assert 'H3' in openmc.lib.nuclides @@ -451,7 +460,7 @@ def test_load_nuclide(capi_init): openmc.lib.load_nuclide('Pu3') -def test_id_map(capi_init): +def test_id_map(lib_init): expected_ids = np.array([[(3, 3), (2, 2), (3, 3)], [(2, 2), (1, 1), (2, 2)], [(3, 3), (2, 2), (3, 3)]], dtype='int32') @@ -469,7 +478,7 @@ def test_id_map(capi_init): ids = openmc.lib.plot.id_map(s) assert np.array_equal(expected_ids, ids) -def test_property_map(capi_init): +def test_property_map(lib_init): expected_properties = np.array( [[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)], [ (293.6, 6.55), (293.6, 10.29769), (293.6, 6.55)], @@ -489,7 +498,7 @@ def test_property_map(capi_init): assert np.allclose(expected_properties, properties, atol=1e-04) -def test_position(capi_init): +def test_position(lib_init): pos = openmc.lib.plot._Position(1.0, 2.0, 3.0) @@ -502,7 +511,7 @@ def test_position(capi_init): assert tuple(pos) == (1.3, 2.3, 3.3) -def test_global_bounding_box(capi_init): +def test_global_bounding_box(lib_init): expected_llc = (-0.63, -0.63, -np.inf) expected_urc = (0.63, 0.63, np.inf) diff --git a/vendor/vendor.txt b/vendor/vendor.txt new file mode 100644 index 000000000..4291ee375 --- /dev/null +++ b/vendor/vendor.txt @@ -0,0 +1,4 @@ +gsl-lite==0.34.0 +pugixml==1.8 +xtensor==0.20.8 +xtl==0.6.5 diff --git a/vendor/xtensor/CMakeLists.txt b/vendor/xtensor/CMakeLists.txt index d4d3b355d..ce5fe9e6a 100644 --- a/vendor/xtensor/CMakeLists.txt +++ b/vendor/xtensor/CMakeLists.txt @@ -1,5 +1,6 @@ ############################################################################ -# Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # @@ -28,16 +29,71 @@ message(STATUS "Building xtensor v${${PROJECT_NAME}_VERSION}") # Dependencies # ============ -#find_package(xtl 0.4.9 REQUIRED) +set(xtl_REQUIRED_VERSION 0.6.7) +find_package(xtl ${xtl_REQUIRED_VERSION} REQUIRED) +message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") -#message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") +find_package(nlohmann_json 3.1.1 QUIET) -#find_package(nlohmann_json 3.1.1) +# Optional dependencies +# ===================== + +OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) +OPTION(XTENSOR_USE_TBB "enable parallelization using intel TBB" OFF) +OPTION(XTENSOR_USE_OPENMP "enable parallelization using OpenMP" OFF) +if(XTENSOR_USE_TBB AND XTENSOR_USE_OPENMP) + message( + FATAL + "XTENSOR_USE_TBB and XTENSOR_USE_OPENMP cannot both be active at once" + ) +endif() + +if(XTENSOR_USE_XSIMD) + set(xsimd_REQUIRED_VERSION 7.4.0) + find_package(xsimd ${xsimd_REQUIRED_VERSION} REQUIRED) + message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") +endif() + +if(XTENSOR_USE_TBB) + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + find_package(TBB REQUIRED) + message(STATUS "Found intel TBB: ${TBB_INCLUDE_DIRS}") +endif() + +if(XTENSOR_USE_OPENMP) + find_package(OpenMP REQUIRED) + if (OPENMP_FOUND) + # Set openmp variables now + + # Create private target just for this lib + # https://cliutils.gitlab.io/modern-cmake/chapters/packages/OpenMP.html + # Probably not safe for cmake < 3.4 .. + find_package(Threads REQUIRED) + add_library(OpenMP::OpenMP_CXX_xtensor IMPORTED INTERFACE) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS} + ) + # Only works if the same flag is passed to the linker; use CMake 3.9+ otherwise (Intel, AppleClang) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS} Threads::Threads) + + message(STATUS "OpenMP Found") + else() + message(FATAL "Failed to locate OpenMP") + endif() +endif() # Build # ===== set(XTENSOR_HEADERS + ${XTENSOR_INCLUDE_DIR}/xtensor/xaccessible.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xaccumulator.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xadapt.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xarray.hpp @@ -47,16 +103,19 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xbuffer_adaptor.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xbuilder.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcomplex.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xconcepts.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcontainer.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcsv.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xdynamic_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xeval.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xexception.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression_holder.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression_traits.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfixed.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfunction.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfunctor_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xgenerator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xhistogram.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xindex_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xinfo.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xio.hpp @@ -64,7 +123,10 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xiterator.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xjson.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xlayout.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmanipulation.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmasked_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xmath.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmime.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnoalias.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnorm.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnpy.hpp @@ -74,6 +136,7 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_base.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_storage.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xpad.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xrandom.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xreducer.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xscalar.hpp @@ -102,13 +165,13 @@ target_link_libraries(xtensor INTERFACE xtl) OPTION(XTENSOR_ENABLE_ASSERT "xtensor bound check" OFF) OPTION(XTENSOR_CHECK_DIMENSION "xtensor dimension check" OFF) -OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) OPTION(BUILD_TESTS "xtensor test suite" OFF) OPTION(BUILD_BENCHMARK "xtensor benchmark" OFF) OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) OPTION(DOWNLOAD_GBENCHMARK "download google benchmark and build from source" ON) OPTION(DEFAULT_COLUMN_MAJOR "set default layout to column major" OFF) OPTION(DISABLE_VS2017 "disables the compilation of some test with Visual Studio 2017" OFF) +OPTION(CPP17 "enables C++17" OFF) if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) set(BUILD_TESTS ON) @@ -122,13 +185,6 @@ if(XTENSOR_CHECK_DIMENSION) add_definitions(-DXTENSOR_ENABLE_CHECK_DIMENSION) endif() -if(XTENSOR_USE_XSIMD) - add_definitions(-DXTENSOR_USE_XSIMD) - find_package(xsimd 4.1.6 REQUIRED) - message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") - target_link_libraries(xtensor INTERFACE xsimd) -endif() - if(DEFAULT_COLUMN_MAJOR) add_definitions(-DXTENSOR_DEFAULT_LAYOUT=layout_type::column_major) endif() @@ -145,6 +201,11 @@ if(BUILD_BENCHMARK) add_subdirectory(benchmark) endif() +if(XTENSOR_USE_OPENMP) + # Link xtensor itself to OpenMP to propagate to user projects + target_link_libraries(xtensor INTERFACE OpenMP::OpenMP_CXX_xtensor) +endif() + # Installation # ============ diff --git a/vendor/xtensor/include/xtensor/xaccessible.hpp b/vendor/xtensor/include/xtensor/xaccessible.hpp new file mode 100644 index 000000000..8d8c6b3b2 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xaccessible.hpp @@ -0,0 +1,307 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ACCESSIBLE_HPP +#define XTENSOR_ACCESSIBLE_HPP + +#include "xexception.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" + +namespace xt +{ + /** + * @class xconst_accessible + * @brief Base class for implementation of common expression constant access methods. + * + * The xaccessible class implements constant access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xconst_accessible + * + * + */ + template + class xconst_accessible + { + public: + + using derived_type = D; + using inner_types = xcontainer_inner_types; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using size_type = typename inner_types::size_type; + + size_type size() const noexcept; + size_type dimension() const noexcept; + size_type shape(size_type index) const; + + template + const_reference at(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference periodic(Args... args) const; + + template + bool in_bounds(Args... args) const; + + protected: + + xconst_accessible() = default; + ~xconst_accessible() = default; + + xconst_accessible(const xconst_accessible&) = default; + xconst_accessible& operator=(const xconst_accessible&) = default; + + xconst_accessible(xconst_accessible&&) = default; + xconst_accessible& operator=(xconst_accessible&&) = default; + + private: + + const derived_type& derived_cast() const noexcept; + }; + + /** + * @class xaccessible + * @brief Base class for implementation of common expression access methods. + * + * The xaccessible class implements access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xaccessible + * provides the interface. + */ + template + class xaccessible : public xconst_accessible + { + public: + + using base_type = xconst_accessible; + using derived_type = typename base_type::derived_type; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + + template + reference at(Args... args); + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference periodic(Args... args); + + using base_type::at; + using base_type::operator[]; + using base_type::periodic; + + protected: + + xaccessible() = default; + ~xaccessible() = default; + + xaccessible(const xaccessible&) = default; + xaccessible& operator=(const xaccessible&) = default; + + xaccessible(xaccessible&&) = default; + xaccessible& operator=(xaccessible&&) = default; + + private: + + derived_type& derived_cast() noexcept; + }; + + /************************************ + * xconst_accessible implementation * + ************************************/ + + /** + * Returns the size of the expression. + */ + template + inline auto xconst_accessible::size() const noexcept -> size_type + { + return compute_size(derived_cast().shape()); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xconst_accessible::dimension() const noexcept -> size_type + { + return derived_cast().shape().size(); + } + + /** + * Returns the i-th dimension of the expression. + */ + template + inline auto xconst_accessible::shape(size_type index) const -> size_type + { + return derived_cast().shape()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xconst_accessible::at(Args... args) const -> const_reference + { + check_access(derived_cast().shape(), static_cast(args)...); + return derived_cast().operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xconst_accessible::operator[](const S& index) const + -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xconst_accessible::operator[](std::initializer_list index) const -> const_reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xconst_accessible::operator[](size_type i) const -> const_reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xconst_accessible::periodic(Args... args) const -> const_reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(static_cast(args)...); + } + + /** + * Returns ``true`` only if the the specified position is a valid entry in the expression. + * @param args a list of indices specifying the position in the expression. + * @return bool + */ + template + template + inline bool xconst_accessible::in_bounds(Args... args) const + { + return check_in_bounds(derived_cast().shape(), args...); + } + + template + inline auto xconst_accessible::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + /****************************** + * xaccessible implementation * + ******************************/ + + /** + * Returns a reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xaccessible::at(Args... args) -> reference + { + check_access(derived_cast().shape(), static_cast(args)...); + return derived_cast().operator()(args...); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xaccessible::operator[](const S& index) + -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xaccessible::operator[](std::initializer_list index) -> reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xaccessible::operator[](size_type i) -> reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xaccessible::periodic(Args... args) -> reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(static_cast(args)...); + } + + + template + inline auto xaccessible::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + +} + +#endif + diff --git a/vendor/xtensor/include/xtensor/xaccumulator.hpp b/vendor/xtensor/include/xtensor/xaccumulator.hpp index f2b446ff3..7bba8a5ae 100644 --- a/vendor/xtensor/include/xtensor/xaccumulator.hpp +++ b/vendor/xtensor/include/xtensor/xaccumulator.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -21,7 +22,7 @@ namespace xt { -#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate +#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate_type /************** * accumulate * @@ -73,13 +74,13 @@ namespace xt template xarray::value_type> accumulator_impl(F&&, E&&, std::size_t, EVS) { - static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); } template xarray::value_type> accumulator_impl(F&&, E&&, EVS) { - static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); } template @@ -88,15 +89,57 @@ namespace xt using type = xarray; }; - template - struct xaccumulator_return_type, R> + template + struct xaccumulator_return_type, R> { - using type = xtensor; + using type = xarray; + }; + + template + struct xaccumulator_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_return_type, L>, R> + { + using type = xtensor_fixed, L>; }; template using xaccumulator_return_type_t = typename xaccumulator_return_type::type; + template + struct fixed_compute_size; + + template + struct xaccumulator_linear_return_type + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, L>, R> + { + using type = xtensor_fixed>::value>, L>; + }; + + template + using xaccumulator_linear_return_type_t = typename xaccumulator_linear_return_type::type; + template inline auto accumulator_init_with_f(F&& f, E& e, std::size_t axis) { @@ -104,7 +147,8 @@ namespace xt // e[:, 0, :, :, ...] = f(e[:, 0, :, :, ...]) // so that all "first" values are initialized in a first pass - std::size_t outer_loop_size, inner_loop_size, outer_stride, inner_stride, pos = 0; + std::size_t outer_loop_size, inner_loop_size, pos = 0; + std::size_t outer_stride, inner_stride; auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { outer_loop_size = std::accumulate(first, first + ax, @@ -113,9 +157,10 @@ namespace xt std::size_t(1), std::multiplies()); }; + // Note: add check that strides > 0 auto set_loop_strides = [&outer_stride, &inner_stride](auto first, auto last, std::ptrdiff_t ax) { - outer_stride = ax == 0 ? 1 : *std::min_element(first, first + ax); - inner_stride = (ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last); + outer_stride = static_cast(ax == 0 ? 1 : *std::min_element(first, first + ax)); + inner_stride = static_cast((ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last)); }; set_loop_sizes(e.shape().begin(), e.shape().end(), static_cast(axis)); @@ -140,9 +185,9 @@ namespace xt } template - inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate) + inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate_type) { - using accumulate_functor = std::decay_t(f))>; + using accumulate_functor = std::decay_t(f))>; using function_return_type = typename accumulate_functor::result_type; using result_type = xaccumulator_return_type_t, function_return_type>; @@ -153,74 +198,80 @@ namespace xt result_type result = e; // assign + make a copy, we need it anyways - std::size_t inner_stride = result.strides()[axis]; - std::size_t outer_stride = 1; // this is either going row- or column-wise (strides.back / strides.front) - std::size_t outer_loop_size = 0; - std::size_t inner_loop_size = 0; - - auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { - outer_loop_size = std::accumulate(first, - first + ax, - std::size_t(1), std::multiplies()); - - inner_loop_size = std::accumulate(first + ax, - last, - std::size_t(1), std::multiplies()); - }; - - if (result_type::static_layout == layout_type::row_major) + if(result.shape(axis) != std::size_t(0)) { - set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); - } - else - { - set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); - std::swap(inner_loop_size, outer_loop_size); - } + std::size_t inner_stride = static_cast(result.strides()[axis]); + std::size_t outer_stride = 1; // this is either going row- or column-wise (strides.back / strides.front) + std::size_t outer_loop_size = 0; + std::size_t inner_loop_size = 0; + std::size_t init_size = e.shape()[axis] != std::size_t(1) ? std::size_t(1) : std::size_t(0); - std::size_t pos = 0; + auto set_loop_sizes = [&outer_loop_size, &inner_loop_size, init_size](auto first, auto last, std::ptrdiff_t ax) { + outer_loop_size = std::accumulate(first, + first + ax, + init_size, std::multiplies()); - inner_loop_size = inner_loop_size - inner_stride; + inner_loop_size = std::accumulate(first + ax, + last, + std::size_t(1), std::multiplies()); + }; - // activate the init loop if we have an init function other than identity - if (!std::is_same(f)), xtl::identity>::value) - { - accumulator_init_with_f(std::get<1>(f), result, axis); - } - - pos = 0; - for (std::size_t i = 0; i < outer_loop_size; ++i) - { - for (std::size_t j = 0; j < inner_loop_size; ++j) + if (result_type::static_layout == layout_type::row_major) { - result.storage()[pos + inner_stride] = std::get<0>(f)(result.storage()[pos], - result.storage()[pos + inner_stride]); - pos += outer_stride; + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); + } + else + { + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); + std::swap(inner_loop_size, outer_loop_size); + } + + std::size_t pos = 0; + + inner_loop_size = inner_loop_size - inner_stride; + + // activate the init loop if we have an init function other than identity + if (!std::is_same(f))>, xtl::identity>::value) + { + accumulator_init_with_f(xt::get<1>(f), result, axis); + } + + pos = 0; + for (std::size_t i = 0; i < outer_loop_size; ++i) + { + for (std::size_t j = 0; j < inner_loop_size; ++j) + { + result.storage()[pos + inner_stride] = xt::get<0>(f)(result.storage()[pos], + result.storage()[pos + inner_stride]); + pos += outer_stride; + } + pos += inner_stride; } - pos += inner_stride; } return result; } template - inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate) + inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate_type) { - using accumulate_functor = std::decay_t(f))>; + using accumulate_functor = std::decay_t(f))>; using T = typename accumulate_functor::result_type; - using result_type = xtensor; + using result_type = xaccumulator_linear_return_type_t, T>; std::size_t sz = e.size(); auto result = result_type::from_shape({sz}); - auto it = e.template begin(); - - result.storage()[0] = std::get<1>(f)(*it); - ++it; - - for (std::size_t idx = 0; it != e.template end(); ++it) + if(sz != std::size_t(0)) { - result.storage()[idx + 1] = std::get<0>(f)(result.storage()[idx], *it); - ++idx; + auto it = e.template begin(); + result.storage()[0] = xt::get<1>(f)(*it); + ++it; + + for (std::size_t idx = 0; it != e.template end(); ++it) + { + result.storage()[idx + 1] = xt::get<0>(f)(result.storage()[idx], *it); + ++idx; + } } return result; } @@ -237,7 +288,7 @@ namespace xt * @return returns xarray filled with accumulated values */ template ::value, int> = 0> + XTL_REQUIRES(is_evaluation_strategy)> inline auto accumulate(F&& f, E&& e, EVS evaluation_strategy = EVS()) { // Note we need to check is_integral above in order to prohibit EVS = int, and not taking the std::size_t @@ -257,9 +308,10 @@ namespace xt * @return returns xarray filled with accumulated values */ template - inline auto accumulate(F&& f, E&& e, std::size_t axis, EVS evaluation_strategy = EVS()) + inline auto accumulate(F&& f, E&& e, std::ptrdiff_t axis, EVS evaluation_strategy = EVS()) { - return detail::accumulator_impl(std::forward(f), std::forward(e), axis, evaluation_strategy); + std::size_t ax = normalize_axis(e.dimension(), axis); + return detail::accumulator_impl(std::forward(f), std::forward(e), ax, evaluation_strategy); } } diff --git a/vendor/xtensor/include/xtensor/xadapt.hpp b/vendor/xtensor/include/xtensor/xadapt.hpp index b080bd0b7..5dac517a2 100644 --- a/vendor/xtensor/include/xtensor/xadapt.hpp +++ b/vendor/xtensor/include/xtensor/xadapt.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -18,6 +19,8 @@ #include "xarray.hpp" #include "xtensor.hpp" +#include "xfixed.hpp" +#include "xbuffer_adaptor.hpp" namespace xt { @@ -34,6 +37,24 @@ namespace xt template using array_size = array_size_impl>; + + template + struct default_allocator_for_ptr + { + using type = std::allocator>>>; + }; + + template + using default_allocator_for_ptr_t = typename default_allocator_for_ptr

::type; + + template + using not_an_array = xtl::negation>; + + template + using not_a_pointer = xtl::negation>; + + template + using not_a_layout = xtl::negation>; } /************************** @@ -48,9 +69,31 @@ namespace xt * @param l the layout_type of the xarray_adaptor */ template >::value, int> = 0> - xarray_adaptor, L, std::decay_t> - adapt(C&& container, const SC& shape, layout_type l = L); + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_pointer)> + inline xarray_adaptor, L, std::decay_t> + adapt(C&& container, const SC& shape, layout_type l = L) + { + using return_type = xarray_adaptor, L, std::decay_t>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xarray_adaptor from a pointer with the specified shape and layout. + * @param pointer the container to adapt + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >, + std::is_pointer)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + using buffer_type = xbuffer_adaptor>; + using return_type = xarray_adaptor>; + std::size_t size = compute_size(shape); + return return_type(buffer_type(pointer, size), shape, l); + } /** * Constructs an xarray_adaptor of the given stl-like container, @@ -60,10 +103,16 @@ namespace xt * @param strides the strides of the xarray_adaptor */ template >::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, layout_type::dynamic, std::decay_t> - adapt(C&& container, SC&& shape, SS&& strides); + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_layout>)> + inline xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides) + { + using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } /** * Constructs an xarray_adaptor of the given dynamically allocated C array, @@ -71,32 +120,79 @@ namespace xt * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param shape the shape of the xarray_adaptor * @param l the layout_type of the xarray_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, O, A>, L, SC> - adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); + template , + XTL_REQUIRES(detail::not_an_array>)> + inline xarray_adaptor, O, A>, L, SC> + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()) + { + (void)ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), shape, l); + } /** * Constructs an xarray_adaptor of the given dynamically allocated C array, - * with the specified shape and layout. + * with the specified shape and strides. * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param shape the shape of the xarray_adaptor * @param strides the strides of the xarray_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>, - typename std::enable_if_t>::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> - adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + template , + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_layout>)> + inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) + { + (void)ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor>; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } + + /** + * Contructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Contructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and stirdes. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template >, + detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), + std::forward(shape), + std::forward(strides)); + } /*************************** * xtensor_adaptor builder * @@ -109,8 +205,13 @@ namespace xt * @param l the layout_type of the xtensor_adaptor */ template - xtensor_adaptor - adapt(C&& container, layout_type l = L); + inline xtensor_adaptor + adapt(C&& container, layout_type l = L) + { + const std::array::size_type, 1> shape{container.size()}; + using return_type = xtensor_adaptor, 1, L>; + return return_type(std::forward(container), shape, l); + } /** * Constructs an xtensor_adaptor of the given stl-like container, @@ -120,9 +221,32 @@ namespace xt * @param l the layout_type of the xtensor_adaptor */ template >::value, int> = 0> - xtensor_adaptor::value, L> - adapt(C&& container, const SC& shape, layout_type l = L); + XTL_REQUIRES(detail::is_array>, + detail::not_a_pointer)> + inline xtensor_adaptor::value, L> + adapt(C&& container, const SC& shape, layout_type l = L) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, L>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xtensor_adaptor from a pointer with the specified shape and layout. + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + */ + template >, + std::is_pointer)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + using buffer_type = xbuffer_adaptor>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + return return_type(buffer_type(pointer, compute_size(shape)), shape, l); + } /** * Constructs an xtensor_adaptor of the given stl-like container, @@ -132,10 +256,17 @@ namespace xt * @param strides the strides of the xtensor_adaptor */ template >::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor::value, layout_type::dynamic> - adapt(C&& container, SC&& shape, SS&& strides); + XTL_REQUIRES(detail::is_array>, + detail::not_a_layout>)> + inline xtensor_adaptor::value, layout_type::dynamic> + adapt(C&& container, SC&& shape, SS&& strides) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, layout_type::dynamic>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } /** * Constructs a 1-D xtensor_adaptor of the given dynamically allocated C array, @@ -143,145 +274,15 @@ namespace xt * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param l the layout_type of the xtensor_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>> - xtensor_adaptor, O, A>, 1, L> - adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()); - - /** - * Constructs an xtensor_adaptor of the given dynamically allocated C array, - * with the specified shape and layout. - * @param pointer the pointer to the beginning of the dynamic array - * @param size the size of the dynamic array - * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` - * @param shape the shape of the xtensor_adaptor - * @param l the layout_type of the xtensor_adaptor - * @param alloc the allocator used for allocating / deallocating the dynamic array - */ - template >>>, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor, O, A>, detail::array_size::value, L> - adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); - - /** - * Constructs an xtensor_adaptor of the given dynamically allocated C array, - * with the specified shape and strides. - * @param pointer the pointer to the beginning of the dynamic array - * @param size the size of the dynamic array - * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` - * @param shape the shape of the xtensor_adaptor - * @param strides the strides of the xtensor_adaptor - * @param alloc the allocator used for allocating / deallocating the dynamic array - */ - template >>>, - typename std::enable_if_t>::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> - adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); - - /***************************************** - * xarray_adaptor builder implementation * - *****************************************/ - - // shape only - container version - template >::value, int>> - inline xarray_adaptor, L, std::decay_t> - adapt(C&& container, const SC& shape, layout_type l) - { - using return_type = xarray_adaptor, L, std::decay_t>; - return return_type(std::forward(container), shape, l); - } - - // shape and strides - container version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xarray_adaptor, layout_type::dynamic, std::decay_t> - adapt(C&& container, SC&& shape, SS&& strides) - { - using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; - return return_type(std::forward(container), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - // shape only - buffer version - template >::value, int>> - inline xarray_adaptor, O, A>, L, SC> - adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) - { - using buffer_type = xbuffer_adaptor, O, A>; - using return_type = xarray_adaptor; - buffer_type buf(std::forward

(pointer), size, alloc); - return return_type(std::move(buf), shape, l); - } - - // shape and strides - buffer version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> - adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) - { - using buffer_type = xbuffer_adaptor, O, A>; - using return_type = xarray_adaptor>; - buffer_type buf(std::forward

(pointer), size, alloc); - return return_type(std::move(buf), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - /****************************************** - * xtensor_adaptor builder implementation * - ******************************************/ - - // 1-D case - container version - template - inline xtensor_adaptor - adapt(C&& container, layout_type l) - { - const std::array::size_type, 1> shape{container.size()}; - using return_type = xtensor_adaptor, 1, L>; - return return_type(std::forward(container), shape, l); - } - - // shape only - container version - template >::value, int>> - inline xtensor_adaptor::value, L> - adapt(C&& container, const SC& shape, layout_type l) - { - constexpr std::size_t N = detail::array_size::value; - using return_type = xtensor_adaptor, N, L>; - return return_type(std::forward(container), shape, l); - } - - // shape and strides - container version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xtensor_adaptor::value, layout_type::dynamic> - adapt(C&& container, SC&& shape, SS&& strides) - { - constexpr std::size_t N = detail::array_size::value; - using return_type = xtensor_adaptor, N, layout_type::dynamic>; - return return_type(std::forward(container), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - // 1-D case - buffer version - template + template > inline xtensor_adaptor, O, A>, 1, L> - adapt(P&& pointer, typename A::size_type size, O, layout_type l, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; using return_type = xtensor_adaptor; buffer_type buf(std::forward

(pointer), size, alloc); @@ -289,12 +290,23 @@ namespace xt return return_type(std::move(buf), shape, l); } - // shape only - buffer version - template >::value, int>> + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template , + XTL_REQUIRES(detail::is_array>)> inline xtensor_adaptor, O, A>, detail::array_size::value, L> - adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; constexpr std::size_t N = detail::array_size::value; using return_type = xtensor_adaptor; @@ -302,21 +314,185 @@ namespace xt return return_type(std::move(buf), shape, l); } - // shape and strides - buffer version - template >::value, int>, - typename std::enable_if_t>::value, int>> + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and strides. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template , + XTL_REQUIRES(detail::is_array>, + detail::not_a_layout>)> inline xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> - adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; constexpr std::size_t N = detail::array_size::value; using return_type = xtensor_adaptor; buffer_type buf(std::forward

(pointer), size, alloc); return return_type(std::move(buf), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); } + + /** + * Contructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Contructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and stirdes. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template >, + detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), + std::forward(shape), + std::forward(strides)); + } + /** + * Constructs an non-owning xtensor_fixed_adaptor from a pointer with the + * specified shape and layout. + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_fixed_adaptor + */ + template )> + inline auto adapt(C&& ptr, const fixed_shape& /*shape*/) + { + using buffer_type = xbuffer_adaptor>; + using return_type = xfixed_adaptor, L>; + return return_type(buffer_type(ptr, detail::fixed_compute_size>::value)); + } + +#ifndef X_OLD_CLANG + template + inline auto adapt(C&& ptr, const T(&shape)[N]) + { + using shape_type = std::array; + return adapt(std::forward(ptr), xtl::forward_sequence(shape)); + } +#else + template + inline auto adapt(C&& ptr, std::initializer_list shape) + { + using shape_type = xt::dynamic_shape; + return adapt(std::forward(ptr), xtl::forward_sequence(shape)); + } +#endif + +#ifndef X_OLD_CLANG + /** + * Adapt a smart pointer to a typed memory block (unique_ptr or shared_ptr) + * + * \code{.cpp} + * #include + * #include + * + * std::shared_ptr sptr(new double[8], std::default_delete()); + * sptr.get()[2] = 321.; + * auto xptr = adapt_smart_ptr(sptr, {4, 2}); + * xptr(1, 3) = 123.; + * std::cout << xptr; + * \endcode + * + * @param smart_ptr a smart pointer to a memory block of T[] + * @param shape The desired shape + * + * @return xtensor_adaptor for memory + */ + template + auto adapt_smart_ptr(P&& smart_ptr, const I(&shape)[N]) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>(shape); + return xtensor_adaptor( + buffer_adaptor(smart_ptr.get(), compute_size(fshape), + std::forward

(smart_ptr)), + std::move(fshape) + ); + } + + /** + * Adapt a smart pointer (shared_ptr or unique_ptr) + * + * This function allows to automatically adapt a shared or unique pointer to + * a given shape and operate naturally on it. Memory will be automatically + * handled by the smart pointer implementation. + * + * \code{.cpp} + * #include + * #include + * + * struct Buffer { + * Buffer(std::vector& buf) : m_buf(buf) {} + * ~Buffer() { std::cout << "deleted" << std::endl; } + * std::vector m_buf; + * }; + * + * auto data = std::vector{1,2,3,4,5,6,7,8}; + * auto shared_buf = std::make_shared(data); + * auto unique_buf = std::make_unique(data); + * + * std::cout << shared_buf.use_count() << std::endl; + * { + * auto obj = adapt_smart_ptr(shared_buf.get()->m_buf.data(), + * {2, 4}, shared_buf); + * // Use count increased to 2 + * std::cout << shared_buf.use_count() << std::endl; + * std::cout << obj << std::endl; + * } + * // Use count reset to 1 + * std::cout << shared_buf.use_count() << std::endl; + * + * { + * auto obj = adapt_smart_ptr(unique_buf.get()->m_buf.data(), + * {2, 4}, std::move(unique_buf)); + * std::cout << obj << std::endl; + * } + * \endcode + * + * @param data_ptr A pointer to a typed data block (e.g. double*) + * @param shape The desired shape + * @param smart_ptr A smart pointer to move or copy, in order to manage memory + * + * @return xtensor_adaptor on the memory + */ + template + auto adapt_smart_ptr(P&& data_ptr, const I(&shape)[N], D&& smart_ptr) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>(shape); + + return xtensor_adaptor( + buffer_adaptor(data_ptr, compute_size(fshape), std::forward(smart_ptr)), + std::move(fshape) + ); + } +#endif } #endif diff --git a/vendor/xtensor/include/xtensor/xarray.hpp b/vendor/xtensor/include/xtensor/xarray.hpp index 7c51f2812..69bdb474e 100644 --- a/vendor/xtensor/include/xtensor/xarray.hpp +++ b/vendor/xtensor/include/xtensor/xarray.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -26,13 +27,31 @@ namespace xt * xarray_container declaration * ********************************/ + namespace extension + { + template + struct xarray_container_base; + + template + struct xarray_container_base + { + using type = xtensor_empty_base; + }; + + template + using xarray_container_base_t = typename xarray_container_base::type; + } + template struct xcontainer_inner_types> { using storage_type = EC; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; - using strides_type = shape_type; - using backstrides_type = shape_type; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; @@ -57,17 +76,19 @@ namespace xt * @tparam L The layout_type of the container. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. - * @sa xarray + * @sa xarray, xstrided_container, xcontainer */ template class xarray_container : public xstrided_container>, - public xcontainer_semantic> + public xcontainer_semantic>, + public extension::xarray_container_base_t { public: using self_type = xarray_container; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; + using extension_base = extension::xarray_container_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using value_type = typename base_type::value_type; @@ -80,6 +101,7 @@ namespace xt using strides_type = typename base_type::strides_type; using backstrides_type = typename base_type::backstrides_type; using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; @@ -108,6 +130,11 @@ namespace xt xarray_container(xarray_container&&) = default; xarray_container& operator=(xarray_container&&) = default; + template + explicit xarray_container(xtensor_container&& rhs); + template + xarray_container& operator=(xtensor_container&& rhs); + template xarray_container(const xexpression& e); @@ -128,13 +155,31 @@ namespace xt * xarray_adaptor declaration * ******************************/ + namespace extension + { + template + struct xarray_adaptor_base; + + template + struct xarray_adaptor_base + { + using type = xtensor_empty_base; + }; + + template + using xarray_adaptor_base_t = typename xarray_adaptor_base::type; + } + template struct xcontainer_inner_types> { using storage_type = std::remove_reference_t; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; - using strides_type = shape_type; - using backstrides_type = shape_type; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; @@ -162,10 +207,12 @@ namespace xt * @tparam L The layout_type of the adaptor. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. + * @sa xstrided_container, xcontainer */ template class xarray_adaptor : public xstrided_container>, - public xcontainer_semantic> + public xcontainer_semantic>, + public extension::xarray_adaptor_base_t { public: @@ -174,6 +221,7 @@ namespace xt using self_type = xarray_adaptor; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; + using extension_base = extension::xarray_adaptor_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using shape_type = typename base_type::shape_type; @@ -210,7 +258,6 @@ namespace xt storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; - friend class xcontainer>; }; @@ -386,10 +433,33 @@ namespace xt template inline xarray_container xarray_container::from_shape(S&& s) { - shape_type shape = xtl::forward_sequence(s); + shape_type shape = xtl::forward_sequence(s); return self_type(shape); } + template + template + inline xarray_container::xarray_container(xtensor_container&& rhs) + : base_type(inner_shape_type(rhs.shape().cbegin(), rhs.shape().cend()), + inner_strides_type(rhs.strides().cbegin(), rhs.strides().cend()), + inner_backstrides_type(rhs.backstrides().cbegin(), rhs.backstrides().cend()), + std::move(rhs.layout())), + m_storage(std::move(rhs.storage())) + { + } + + template + template + inline xarray_container& xarray_container::operator=(xtensor_container&& rhs) + { + this->shape_impl().assign(rhs.shape().cbegin(), rhs.shape().cend()); + this->strides_impl().assign(rhs.strides().cbegin(), rhs.strides().cend()); + this->backstrides_impl().assign(rhs.backstrides().cbegin(), rhs.backstrides().cend()); + this->mutable_layout() = rhs.layout(); + m_storage = std::move(rhs.storage()); + return *this; + } + /** * @name Extended copy semantic */ diff --git a/vendor/xtensor/include/xtensor/xassign.hpp b/vendor/xtensor/include/xtensor/xassign.hpp index 1b2f4c00d..86ea51ff3 100644 --- a/vendor/xtensor/include/xtensor/xassign.hpp +++ b/vendor/xtensor/include/xtensor/xassign.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -15,12 +16,16 @@ #include -#include "xconcepts.hpp" #include "xexpression.hpp" #include "xiterator.hpp" #include "xstrides.hpp" #include "xtensor_forward.hpp" #include "xutils.hpp" +#include "xfunction.hpp" + +#if defined(XTENSOR_USE_TBB) +#include +#endif namespace xt { @@ -74,7 +79,7 @@ namespace xt using base_type = xexpression_assigner_base; template - static void assign_xexpression(xexpression& e1, const xexpression& e2); + static void assign_xexpression(E1& e1, const E2& e2); template static void computed_assign(xexpression& e1, const xexpression& e2); @@ -88,15 +93,19 @@ namespace xt private: template - static bool resize(xexpression& e1, const xexpression& e2); + static bool resize(E1& e1, const E2& e2); + + template + static bool resize(E1& e1, const xfunction& e2); + }; - /***************** - * data_assigner * - *****************/ + /******************** + * stepper_assigner * + ********************/ template - class data_assigner + class stepper_assigner { public: @@ -107,7 +116,7 @@ namespace xt using size_type = typename lhs_iterator::size_type; using difference_type = typename lhs_iterator::difference_type; - data_assigner(E1& e1, const E2& e2); + stepper_assigner(E1& e1, const E2& e2); void run(); @@ -127,13 +136,45 @@ namespace xt index_type m_index; }; - /******************** - * trivial_assigner * - ********************/ + /******************* + * linear_assigner * + *******************/ template - struct trivial_assigner + class linear_assigner { + public: + + template + static void run(E1& e1, const E2& e2); + }; + + template <> + class linear_assigner + { + public: + + template + static void run(E1& e1, const E2& e2); + + private: + + template + static void run_impl(E1& e1, const E2& e2, std::true_type); + + template + static void run_impl(E1& e1, const E2& e2, std::false_type); + }; + + /************************* + * strided_loop_assigner * + *************************/ + + template + class strided_loop_assigner + { + public: + template static void run(E1& e1, const E2& e2); }; @@ -190,59 +231,28 @@ namespace xt namespace detail { template - inline bool is_trivial_broadcast(const E1& e1, const E2& e2) + constexpr bool linear_static_layout() { - return (E1::contiguous_layout && E2::contiguous_layout && (E1::static_layout == E2::static_layout)) - || e2.is_trivial_broadcast(e1.strides()); + // A row_major or column_major container with a dimension <= 1 is computed as + // layout any, leading to some performance improvements, for example when + // assigning a col-major vector to a row-major vector etc + return compute_layout(select_layout::value, + select_layout::value) != layout_type::dynamic; } - template - inline bool is_trivial_broadcast(const xview&, const E2&) + template + inline auto is_linear_assign(const E1& e1, const E2& e2) -> std::enable_if_t::value, bool> + { + return (E1::contiguous_layout && E2::contiguous_layout && linear_static_layout()) || + (e1.layout() != layout_type::dynamic && e2.has_linear_assign(e1.strides())); + } + + template + inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t::value, bool> { return false; } - template > - struct forbid_simd_assign - { - static constexpr bool value = true; - }; - - // Double steps check for xfunction because the default - // parameter void_t of forbid_simd_assign prevents additional - // specializations. - template - struct xfunction_forbid_simd; - - template - struct forbid_simd_assign().template load_simd(typename E::size_type(0)))>> - { - static constexpr bool value = false || xfunction_forbid_simd::value; - }; - - template - struct xfunction_forbid_simd - { - static constexpr bool value = false; - }; - - template - struct xfunction_forbid_simd> - { - static constexpr bool value = xtl::disjunction< - std::integral_constant::type>::value>...>::value; - }; - - template - struct has_simd_apply : std::false_type {}; - - template - struct has_simd_apply)>> - : std::true_type - { - }; - template struct has_step_leading : std::false_type { @@ -267,25 +277,49 @@ namespace xt static constexpr bool value = true; }; - template - struct use_strided_loop> + template + struct use_strided_loop> { - static constexpr bool value = xtl::conjunction>...>::value && - has_simd_apply>::value; + static constexpr bool value = xtl::conjunction>...>::value; }; } template - struct xassign_traits + class xassign_traits { - // constexpr methods instead of constexpr data members avoid the need of difinitions at namespace - // scope of these data members (since they are odr-used). + private: + + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + + template + using is_bool = std::is_same; + static constexpr bool contiguous_layout() { return E1::contiguous_layout && E2::contiguous_layout; } - static constexpr bool same_type() { return std::is_same::value; } - static constexpr bool simd_size() { return xsimd::simd_traits::size > 1; } - static constexpr bool forbid_simd() { return detail::forbid_simd_assign::value; } - static constexpr bool simd_assign() { return contiguous_layout() && same_type() && simd_size() && !forbid_simd(); } - static constexpr bool simd_strided_loop() { return same_type() && simd_size() && detail::use_strided_loop::value && detail::use_strided_loop::value; } + static constexpr bool convertible_types() { return std::is_convertible::value; } + + static constexpr bool use_xsimd() { return xt_simd::simd_traits::size > 1; } + + template + static constexpr bool simd_size_impl() { return xt_simd::simd_traits::size > 1 || (is_bool::value && use_xsimd()); } + static constexpr bool simd_size() { return simd_size_impl() && simd_size_impl(); } + static constexpr bool simd_interface() { return has_simd_interface(); } + static constexpr bool simd_assign() { return convertible_types() && simd_size() && simd_interface(); } + + public: + + // constexpr methods instead of constexpr data members avoid the need of definitions at namespace + // scope of these data members (since they are odr-used). + + static constexpr bool linear_assign(const E1& e1, const E2& e2, bool trivial) { return trivial && detail::is_linear_assign(e1, e2); } + static constexpr bool strided_assign() { return detail::use_strided_loop::value && detail::use_strided_loop::value; } + static constexpr bool simd_linear_assign() { return contiguous_layout() && simd_assign(); } + static constexpr bool simd_strided_assign() { return strided_assign() && simd_assign(); } + + using requested_value_type = std::conditional_t::value, + typename E2::bool_load_type, + e2_value_type>; + }; template @@ -293,30 +327,31 @@ namespace xt { E1& de1 = e1.derived_cast(); const E2& de2 = e2.derived_cast(); + using traits = xassign_traits; - bool trivial_broadcast = trivial && detail::is_trivial_broadcast(de1, de2); - - if (trivial_broadcast) + bool linear_assign = traits::linear_assign(de1, de2, trivial); + constexpr bool simd_linear_assign = traits::simd_linear_assign(); + constexpr bool simd_strided_assign = traits::simd_strided_assign(); + if (linear_assign) { - constexpr bool simd_assign = xassign_traits::simd_assign(); - trivial_assigner::run(de1, de2); + linear_assigner::run(de1, de2); } - else if (xassign_traits::simd_strided_loop()) + else if (simd_strided_assign) { - strided_assign(de1, de2, std::integral_constant::simd_strided_loop()>{}); + strided_loop_assigner::run(de1, de2); } else { - data_assigner assigner(de1, de2); + stepper_assigner assigner(de1, de2); assigner.run(); } } template template - inline void xexpression_assigner::assign_xexpression(xexpression& e1, const xexpression& e2) + inline void xexpression_assigner::assign_xexpression(E1& e1, const E2& e2) { - bool trivial_broadcast = resize(e1, e2); + bool trivial_broadcast = resize(e1.derived_cast(), e2.derived_cast()); base_type::assign_data(e1, e2, trivial_broadcast); } @@ -331,7 +366,7 @@ namespace xt const E2& de2 = e2.derived_cast(); size_type dim = de2.dimension(); - shape_type shape = xtl::make_sequence(dim, size_type(0)); + shape_type shape = uninitialized_shape(dim); bool trivial_broadcast = de2.broadcast_shape(shape, true); if (dim > de1.dimension() || shape > de1.shape()) @@ -372,26 +407,98 @@ namespace xt } } - template - template - inline bool xexpression_assigner::resize(xexpression& e1, const xexpression& e2) + namespace detail { - using shape_type = typename E1::shape_type; - using size_type = typename E1::size_type; - const E2& de2 = e2.derived_cast(); - size_type size = de2.dimension(); - shape_type shape = xtl::make_sequence(size, size_type(0)); - bool trivial_broadcast = de2.broadcast_shape(shape, true); - e1.derived_cast().resize(std::move(shape)); - return trivial_broadcast; + template + struct static_trivial_broadcast; + + template + struct static_trivial_broadcast + { + static constexpr bool value = detail::promote_index::shape_type...>::value; + }; + + template + struct static_trivial_broadcast + { + static constexpr bool value = false; + }; } - /******************************** - * data_assigner implementation * - ********************************/ + template + template + inline bool xexpression_assigner::resize(E1& e1, const E2& e2) + { + // If our RHS is not a xfunction, we know that the RHS is at least potentially trivial + // We check the strides of the RHS in detail::is_trivial_broadcast to see if they match up! + // So we can skip a shape copy and a call to broadcast_shape(...) + e1.resize(e2.shape()); + return true; + } + + template + template + inline bool xexpression_assigner::resize(E1& e1, const xfunction& e2) + { + return xtl::mpl::static_if::shape_type>::value>( + [&](auto /*self*/) { + /* + * If the shape of the xfunction is statically known, we can compute the broadcast triviality + * at compile time plus we can resize right away. + */ + // resize in case LHS is not a fixed size container. If it is, this is a NOP + e1.resize(typename xfunction::shape_type{}); + return detail::static_trivial_broadcast::shape_type>::value, CT...>::value; + }, + /* else */ [&](auto /*self*/) + { + using index_type = xindex_type_t; + using size_type = typename E1::size_type; + size_type size = e2.dimension(); + index_type shape = uninitialized_shape(size); + bool trivial_broadcast = e2.broadcast_shape(shape, true); + e1.resize(std::move(shape)); + return trivial_broadcast; + } + ); + } + + /*********************************** + * stepper_assigner implementation * + ***********************************/ + + template + struct is_narrowing_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_arithmetic::value && + (sizeof(result_type) < sizeof(argument_type) || + (std::is_integral::value && std::is_floating_point::value)); + }; + + template + struct has_sign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_signed::value != std::is_signed::value; + }; + + template + struct has_assign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = is_narrowing_conversion::value || + has_sign_conversion::value; + }; template - inline data_assigner::data_assigner(E1& e1, const E2& e2) + inline stepper_assigner::stepper_assigner(E1& e1, const E2& e2) : m_e1(e1), m_lhs(e1.stepper_begin(e1.shape())), m_rhs(e2.stepper_begin(e1.shape())), m_index(xtl::make_sequence(e1.shape().size(), size_type(0))) @@ -399,128 +506,152 @@ namespace xt } template - inline void data_assigner::run() + inline void stepper_assigner::run() { using size_type = typename E1::size_type; using argument_type = std::decay_t; using result_type = std::decay_t; - constexpr bool is_narrowing = is_narrowing_conversion::value; + constexpr bool needs_cast = has_assign_conversion::value; size_type s = m_e1.size(); for (size_type i = 0; i < s; ++i) { - *m_lhs = conditional_cast(*m_rhs); + *m_lhs = conditional_cast(*m_rhs); stepper_tools::increment_stepper(*this, m_index, m_e1.shape()); } } template - inline void data_assigner::step(size_type i) + inline void stepper_assigner::step(size_type i) { m_lhs.step(i); m_rhs.step(i); } template - inline void data_assigner::step(size_type i, size_type n) + inline void stepper_assigner::step(size_type i, size_type n) { m_lhs.step(i, n); m_rhs.step(i, n); } template - inline void data_assigner::reset(size_type i) + inline void stepper_assigner::reset(size_type i) { m_lhs.reset(i); m_rhs.reset(i); } template - inline void data_assigner::to_end(layout_type l) + inline void stepper_assigner::to_end(layout_type l) { m_lhs.to_end(l); m_rhs.to_end(l); } - /*********************************** - * trivial_assigner implementation * - ***********************************/ + /********************************** + * linear_assigner implementation * + **********************************/ template template - inline void trivial_assigner::run(E1& e1, const E2& e2) + inline void linear_assigner::run(E1& e1, const E2& e2) { - using lhs_align_mode = xsimd::container_alignment_t; + using lhs_align_mode = xt_simd::container_alignment_t; constexpr bool is_aligned = std::is_same::value; using rhs_align_mode = std::conditional_t; - using value_type = std::common_type_t; - using simd_type = xsimd::simd_type; + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = xt_simd::simd_type; using size_type = typename E1::size_type; size_type size = e1.size(); - size_type simd_size = simd_type::size; + constexpr size_type simd_size = simd_type::size; + constexpr bool needs_cast = has_assign_conversion::value; - size_type align_begin = is_aligned ? 0 : xsimd::get_alignment_offset(e1.data(), size, simd_size); + size_type align_begin = is_aligned ? 0 : xt_simd::get_alignment_offset(e1.data(), size, simd_size); size_type align_end = align_begin + ((size - align_begin) & ~(simd_size - 1)); for (size_type i = 0; i < align_begin; ++i) { - e1.data_element(i) = e2.data_element(i); + e1.data_element(i) = conditional_cast(e2.data_element(i)); } + +#if defined(XTENSOR_USE_TBB) + tbb::parallel_for(align_begin, align_end, simd_size, [&](size_t i) + { + e1.template store_simd(i, e2.template load_simd(i)); + }); +#elif defined(XTENSOR_USE_OPENMP) + #pragma omp parallel for default(none) shared(align_begin, align_end, e1, e2) for (size_type i = align_begin; i < align_end; i += simd_size) { - e1.template store_simd(i, e2.template load_simd(i)); + e1.template store_simd(i, e2.template load_simd(i)); } +#else + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } +#endif for (size_type i = align_end; i < size; ++i) { - e1.data_element(i) = e2.data_element(i); + e1.data_element(i) = conditional_cast(e2.data_element(i)); } } - namespace assigner_detail - { - template - inline void assign_loop(It src, Ot dst, std::size_t n) - { - for(; n > 0; --n) - { - *dst = static_cast(*src); - ++src; - ++dst; - } - } - - template - inline void trivial_assigner_run_impl(E1& e1, const E2& e2, std::true_type) - { - using size_type = typename E1::size_type; - auto src = e2.storage_cbegin(); - auto dst = e1.storage_begin(); - assign_loop(src, dst, e1.size()); - } - - template - inline void trivial_assigner_run_impl(E1&, const E2&, std::false_type) - { - XTENSOR_PRECONDITION(false, - "Internal error: trivial_assigner called with unrelated types."); - } - } - - template <> template - inline void trivial_assigner::run(E1& e1, const E2& e2) + inline void linear_assigner::run(E1& e1, const E2& e2) { - using is_convertible = std::is_convertible::value_type, - typename std::decay_t::value_type>; + using is_convertible = std::is_convertible::value_type, + typename std::decay_t::value_type>; // If the types are not compatible, this function is still instantiated but never called. // To avoid compilation problems in effectively unused code trivial_assigner_run_impl is // empty in this case. - assigner_detail::trivial_assigner_run_impl(e1, e2, is_convertible()); + run_impl(e1, e2, is_convertible()); } - /*********************** - * Strided assign loop * - ***********************/ + template + inline void linear_assigner::run_impl(E1& e1, const E2& e2, std::true_type /*is_convertible*/) + { + using value_type = typename E1::value_type; + using size_type = typename E1::size_type; + auto src = linear_begin(e2); + auto dst = linear_begin(e1); + size_type n = e1.size(); + +#if defined(XTENSOR_USE_TBB) + tbb::parallel_for(std::ptrdiff_t(0), static_cast(n), [&](std::ptrdiff_t i) + { + *(dst + i) = static_cast(*(src + i)); + }); +#elif defined(XTENSOR_USE_OPENMP) + #pragma omp parallel for default(none) shared(src, dst, n) + for (std::ptrdiff_t i = std::ptrdiff_t(0); i < static_cast(n) ; i++) + { + *(dst + i) = static_cast(*(src + i)); + } +#else + for (; n > size_type(0); --n) + { + *dst = static_cast(*src); + ++src; + ++dst; + } +#endif + } + + template + inline void linear_assigner::run_impl(E1&, const E2&, std::false_type /*is_convertible*/) + { + XTENSOR_PRECONDITION(false, + "Internal error: linear_assigner called with unrelated types."); + + } + + /**************************************** + * strided_loop_assigner implementation * + ****************************************/ namespace strided_assign_detail { @@ -614,35 +745,35 @@ namespace xt return m_cut; } - template - std::size_t operator()(const xt::xfunction& xf) + template + std::size_t operator()(const xt::xfunction& xf) { xt::for_each(*this, xf.arguments()); return m_cut; } - private: + private: std::size_t m_cut; const strides_type& m_strides; }; template - auto get_loop_sizes(const E1& e1, const E2& e2) + auto get_loop_sizes(const E1& e1, const E2& e2, bool is_row_major) { std::size_t cut = 0; - // TODO! if E1 is !contigous --> initialize cut to sensible value! - if (e1.strides().back() == 1) + // TODO! if E1 is !contiguous --> initialize cut to sensible value! + if (E1::static_layout == layout_type::row_major || is_row_major) { auto csf = check_strides_functor(e1.strides()); cut = csf(e2); } - else if (e1.strides().front() == 1) + else if (E1::static_layout == layout_type::column_major || !is_row_major) { auto csf = check_strides_functor(e1.strides()); cut = csf(e2); - } + } // can't reach here because this would have already triggered the fallback using shape_value_type = typename E1::shape_type::value_type; std::size_t outer_loop_size = static_cast( @@ -652,7 +783,7 @@ namespace xt std::accumulate(e1.shape().begin() + static_cast(cut), e1.shape().end(), shape_value_type(1), std::multiplies{})); - if (e1.strides().back() != 1) // column major mode + if (E1::static_layout == layout_type::column_major || !is_row_major) { std::swap(outer_loop_size, inner_loop_size); } @@ -661,73 +792,80 @@ namespace xt } } + template template - void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/) + inline void strided_loop_assigner::run(E1& e1, const E2& e2) { - bool fallback = false, is_row_major = true; + bool is_row_major = true; + using fallback_assigner = stepper_assigner; - std::size_t inner_loop_size, outer_loop_size, cut; - std::tie(inner_loop_size, outer_loop_size, cut) = strided_assign_detail::get_loop_sizes(e1, e2); - - if (E1::static_layout == layout_type::row_major || e1.strides().back() == 1) // row major case + if (E1::static_layout == layout_type::dynamic) { - if (cut == e1.dimension()) + layout_type dynamic_layout = e1.layout(); + switch (dynamic_layout) { - fallback = true; + case layout_type::row_major: + is_row_major = true; + break; + case layout_type::column_major: + is_row_major = false; + break; + default: + return fallback_assigner(e1, e2).run(); } } - else if (E1::static_layout == layout_type::column_major || e1.strides().front() == 1) // col major case + else if (E1::static_layout == layout_type::row_major) + { + is_row_major = true; + } + else if (E1::static_layout == layout_type::column_major) { is_row_major = false; - if (cut == 0) - { - fallback = true; - } } else { - fallback = true; + throw std::runtime_error("Illegal layout set (layout_type::any?)."); } - if (fallback) + std::size_t inner_loop_size, outer_loop_size, cut; + std::tie(inner_loop_size, outer_loop_size, cut) = strided_assign_detail::get_loop_sizes(e1, e2, is_row_major); + + if ((is_row_major && cut == e1.dimension()) || (!is_row_major && cut == 0)) { - data_assigner assigner(e1, e2); - assigner.run(); - return; + return fallback_assigner(e1, e2).run(); } // TODO can we get rid of this and use `shape_type`? - dynamic_shape idx; + dynamic_shape idx, max_shape; - using iterator_type = decltype(e1.shape().begin()); - iterator_type max_shape_begin, max_shape_end; if (is_row_major) { xt::resize_container(idx, cut); - max_shape_begin = e1.shape().begin(); - max_shape_end = e1.shape().begin() + static_cast(cut); + max_shape.assign(e1.shape().begin(), e1.shape().begin() + static_cast(cut)); } else { xt::resize_container(idx, e1.shape().size() - cut); - max_shape_begin = e1.shape().begin() + static_cast(cut); - max_shape_end = e1.shape().end(); + max_shape.assign(e1.shape().begin() + static_cast(cut), e1.shape().end()); } // add this when we have std::array index! // std::fill(idx.begin(), idx.end(), 0); - - dynamic_shape max(max_shape_begin, max_shape_end); - - using simd_type = xsimd::simd_type; + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + constexpr bool needs_cast = has_assign_conversion::value; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = std::conditional_t::value, + xt_simd::simd_bool_type, + xt_simd::simd_type>; std::size_t simd_size = inner_loop_size / simd_type::size; std::size_t simd_rest = inner_loop_size % simd_type::size; auto fct_stepper = e2.stepper_begin(e1.shape()); auto res_stepper = e1.stepper_begin(e1.shape()); - - // TODO in 1D case this is ambigous -- could be RM or CM. + + // TODO in 1D case this is ambigous -- could be RM or CM. // Use default layout to make decision std::size_t step_dim = 0; if (!is_row_major) // row major case @@ -737,20 +875,20 @@ namespace xt for (std::size_t ox = 0; ox < outer_loop_size; ++ox) { - for (std::size_t i = 0; i < simd_size; i++) + for (std::size_t i = 0; i < simd_size; ++i) { - res_stepper.template store_simd(fct_stepper.template step_simd()); + res_stepper.template store_simd(fct_stepper.template step_simd()); } for (std::size_t i = 0; i < simd_rest; ++i) { - *(res_stepper) = *(fct_stepper); + *(res_stepper) = conditional_cast(*(fct_stepper)); res_stepper.step_leading(); fct_stepper.step_leading(); } is_row_major ? - strided_assign_detail::idx_tools::next_idx(idx, max) : - strided_assign_detail::idx_tools::next_idx(idx, max); + strided_assign_detail::idx_tools::next_idx(idx, max_shape) : + strided_assign_detail::idx_tools::next_idx(idx, max_shape); fct_stepper.to_begin(); @@ -774,8 +912,9 @@ namespace xt } } + template <> template - inline void strided_assign(E1& /*e1*/, const E2& /*e2*/, std::false_type /*disable*/) + inline void strided_loop_assigner::run(E1& /*e1*/, const E2& /*e2*/) { } } diff --git a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp index e544791b8..3c3cfb632 100644 --- a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp +++ b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * diff --git a/vendor/xtensor/include/xtensor/xbroadcast.hpp b/vendor/xtensor/include/xtensor/xbroadcast.hpp index 77c04f041..121981dae 100644 --- a/vendor/xtensor/include/xtensor/xbroadcast.hpp +++ b/vendor/xtensor/include/xtensor/xbroadcast.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -19,6 +20,7 @@ #include +#include "xaccessible.hpp" #include "xexpression.hpp" #include "xiterable.hpp" #include "xscalar.hpp" @@ -43,6 +45,31 @@ namespace xt auto broadcast(E&& e, const I (&s)[L]); #endif + /************************* + * xbroadcast extensions * + *************************/ + + namespace extension + { + template + struct xbroadcast_base_impl; + + template + struct xbroadcast_base_impl + { + using type = xtensor_empty_base; + }; + + template + struct xbroadcast_base + : xbroadcast_base_impl, CT, X> + { + }; + + template + using xbroadcast_base_t = typename xbroadcast_base::type; + } + /************** * xbroadcast * **************/ @@ -59,6 +86,43 @@ namespace xt using stepper = const_stepper; }; + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using reference = typename xexpression_type::const_reference; + using const_reference = typename xexpression_type::const_reference; + using size_type = typename xexpression_type::size_type; + }; + + /***************************** + * linear_begin / linear_end * + *****************************/ + + template + XTENSOR_CONSTEXPR_RETURN auto linear_begin(xbroadcast& c) noexcept + { + return linear_begin(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_end(xbroadcast& c) noexcept + { + return linear_end(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xbroadcast& c) noexcept + { + return linear_begin(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_end(const xbroadcast& c) noexcept + { + return linear_end(c.expression()); + } + /** * @class xbroadcast * @brief Broadcasted xexpression to a specified shape. @@ -73,20 +137,25 @@ namespace xt * @sa broadcast */ template - class xbroadcast : public xexpression>, - public xconst_iterable> + class xbroadcast : public xsharable_expression>, + public xconst_iterable>, + public xconst_accessible>, + public extension::xbroadcast_base_t { public: using self_type = xbroadcast; using xexpression_type = std::decay_t; + using extension_base = extension::xbroadcast_base_t; + using expression_tag = typename extension_base::expression_tag; + using inner_types = xcontainer_inner_types; using value_type = typename xexpression_type::value_type; - using reference = typename xexpression_type::reference; - using const_reference = typename xexpression_type::const_reference; - using pointer = typename xexpression_type::pointer; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using pointer = typename xexpression_type::const_pointer; using const_pointer = typename xexpression_type::const_pointer; - using size_type = typename xexpression_type::size_type; + using size_type = typename inner_types::size_type; using difference_type = typename xexpression_type::difference_type; using iterable_base = xconst_iterable; @@ -96,41 +165,37 @@ namespace xt using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; - static constexpr layout_type static_layout = xexpression_type::static_layout; - //static constexpr bool contiguous_layout = xexpression_type::contiguous_layout; + using bool_load_type = typename xexpression_type::bool_load_type; + + static constexpr layout_type static_layout = layout_type::dynamic; static constexpr bool contiguous_layout = false; template - xbroadcast(CTA&& e, S&& s); + xbroadcast(CTA&& e, const S& s); + + template + xbroadcast(CTA&& e, shape_type&& s); - size_type size() const noexcept; - size_type dimension() const noexcept; const inner_shape_type& shape() const noexcept; + size_type shape(size_type i) const noexcept; layout_type layout() const noexcept; template const_reference operator()(Args... args) const; - template - const_reference at(Args... args) const; - template const_reference unchecked(Args... args) const; - template - disable_integral_t operator[](const S& index) const; - template - const_reference operator[](std::initializer_list index) const; - const_reference operator[](size_type i) const; - template const_reference element(It first, It last) const; + const xexpression_type& expression() const noexcept; + template bool broadcast_shape(S& shape, bool reuse_cache = false) const; template - bool is_trivial_broadcast(const S& strides) const noexcept; + bool has_linear_assign(const S& strides) const noexcept; template const_stepper stepper_begin(const S& shape) const noexcept; @@ -140,6 +205,12 @@ namespace xt template ::value>> void assign_to(xexpression& e) const; + template + using rebind_t = xbroadcast; + + template + rebind_t build_broadcast(E&& e) const; + private: CT m_e; @@ -164,8 +235,7 @@ namespace xt inline auto broadcast(E&& e, const S& s) { using broadcast_type = xbroadcast, S>; - using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), s); } #ifdef X_OLD_CLANG @@ -174,7 +244,7 @@ namespace xt { using broadcast_type = xbroadcast, std::vector>; using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); } #else template @@ -182,7 +252,7 @@ namespace xt { using broadcast_type = xbroadcast, std::array>; using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); } #endif @@ -203,8 +273,29 @@ namespace xt */ template template - inline xbroadcast::xbroadcast(CTA&& e, S&& s) - : m_e(std::forward(e)), m_shape(std::forward(s)) + inline xbroadcast::xbroadcast(CTA&& e, const S& s) + : m_e(std::forward(e)) + { + if (s.size() < m_e.dimension()) + { + throw xt::broadcast_error("Broadcast shape has fewer elements than original expression."); + } + xt::resize_container(m_shape, s.size()); + std::copy(s.begin(), s.end(), m_shape.begin()); + xt::broadcast_shape(m_e.shape(), m_shape); + } + + /** + * Constructs an xbroadcast expression broadcasting the specified + * \ref xexpression to the given shape + * + * @param e the expression to broadcast + * @param s the shape to apply + */ + template + template + inline xbroadcast::xbroadcast(CTA&& e, shape_type&& s) + : m_e(std::forward(e)), m_shape(std::move(s)) { xt::broadcast_shape(m_e.shape(), m_shape); } @@ -213,24 +304,7 @@ namespace xt /** * @name Size and shape */ - /** - * Returns the size of the expression. - */ - template - inline auto xbroadcast::size() const noexcept -> size_type - { - return compute_size(shape()); - } - - /** - * Returns the number of dimensions of the expression. - */ - template - inline auto xbroadcast::dimension() const noexcept -> size_type - { - return m_shape.size(); - } - + //@{ /** * Returns the shape of the expression. */ @@ -240,6 +314,15 @@ namespace xt return m_shape; } + /** + * Returns the shape of the expression. + */ + template + inline auto xbroadcast::shape(size_type i) const noexcept -> size_type + { + return m_shape[i]; + } + /** * Returns the layout_type of the expression. */ @@ -266,23 +349,6 @@ namespace xt return m_e(args...); } - /** - * Returns a constant reference to the element at the specified position in the expression, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the function. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the expression. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xbroadcast::at(Args... args) const -> const_reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - /** * Returns a constant reference to the element at the specified position in the expression. * @param args a list of indices specifying the position in the expression. Indices @@ -309,33 +375,6 @@ namespace xt return this->operator()(args...); } - /** - * Returns a constant reference to the element at the specified position in the expression. - * @param index a sequence of indices specifying the position in the function. Indices - * must be unsigned integers, the number of indices in the sequence should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xbroadcast::operator[](const S& index) const - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xbroadcast::operator[](std::initializer_list index) const -> const_reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xbroadcast::operator[](size_type i) const -> const_reference - { - return operator()(i); - } - /** * Returns a constant reference to the element at the specified position in the expression. * @param first iterator starting the sequence of indices @@ -347,7 +386,16 @@ namespace xt template inline auto xbroadcast::element(It, It last) const -> const_reference { - return m_e.element(last - dimension(), last); + return m_e.element(last - this->dimension(), last); + } + + /** + * Returns a constant reference to the underlying expression of the broadcast expression. + */ + template + inline auto xbroadcast::expression() const noexcept -> const xexpression_type& + { + return m_e; } //@} @@ -369,17 +417,17 @@ namespace xt } /** - * Compares the specified strides with those of the container to see whether - * the broadcasting is trivial. - * @return a boolean indicating whether the broadcasting is trivial + * Checks whether the xbroadcast can be linearly assigned to an expression + * with the specified strides. + * @return a boolean indicating whether a linear assign is possible */ template template - inline bool xbroadcast::is_trivial_broadcast(const S& strides) const noexcept + inline bool xbroadcast::has_linear_assign(const S& strides) const noexcept { - return dimension() == m_e.dimension() && + return this->dimension() == m_e.dimension() && std::equal(m_shape.cbegin(), m_shape.cend(), m_e.shape().cbegin()) && - m_e.is_trivial_broadcast(strides); + m_e.has_linear_assign(strides); } //@} @@ -407,6 +455,13 @@ namespace xt ed.resize(m_shape); std::fill(ed.begin(), ed.end(), m_e()); } + + template + template + inline auto xbroadcast::build_broadcast(E&& e) const -> rebind_t + { + return rebind_t(std::forward(e), inner_shape_type(m_shape)); + } } #endif diff --git a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp index d8d331685..6bec4f3be 100644 --- a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp +++ b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -21,14 +22,13 @@ namespace xt { - /****************************** - * xbuffer_adator declaration * - ******************************/ struct no_ownership { }; + using smart_ownership = no_ownership; + struct acquire_ownership { }; @@ -36,9 +36,9 @@ namespace xt template >>> class xbuffer_adaptor; - /********************************* - * xbuffer_adator implementation * - *********************************/ + /******************** + * buffer_storage_t * + ********************/ namespace detail { @@ -49,6 +49,7 @@ namespace xt using self_type = xbuffer_storage; using allocator_type = A; + using destructor_type = allocator_type; using value_type = typename allocator_type::value_type; using reference = std::conditional_t>>::value, typename allocator_type::const_reference, @@ -80,6 +81,46 @@ namespace xt size_type m_size; }; + template + class xbuffer_smart_pointer + { + public: + + using self_type = xbuffer_storage; + using destructor_type = D; + using value_type = std::remove_const_t>>; + using allocator_type = std::allocator; + using reference = std::conditional_t>>::value, + typename allocator_type::const_reference, + typename allocator_type::reference>; + using const_reference = typename allocator_type::const_reference; + using pointer = std::conditional_t>>::value, + typename allocator_type::const_pointer, + typename allocator_type::pointer>; + using const_pointer = typename allocator_type::const_pointer; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + + xbuffer_smart_pointer(); + + template + xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + pointer p_data; + size_type m_size; + destructor_type m_destruct; + }; + template class xbuffer_owner_storage { @@ -87,6 +128,7 @@ namespace xt using self_type = xbuffer_owner_storage; using allocator_type = A; + using destructor_type = allocator_type; using value_type = typename allocator_type::value_type; using reference = std::conditional_t>>::value, typename allocator_type::const_reference, @@ -130,10 +172,41 @@ namespace xt allocator_type m_allocator; }; + // Workaround for MSVC2015: using void_t results in some + // template instantiation caching that leads to wrong + // type deduction later in xfunction. + template + struct msvc2015_void + { + using type = void; + }; + + template + using msvc2015_void_t = typename msvc2015_void::type; + + template + struct is_lambda_type : std::false_type + { + }; + + // check if operator() is available + template + struct is_lambda_type> + : std::true_type + { + }; + + template + struct self_type + { + using type = T; + }; template struct get_buffer_storage { - using type = xbuffer_storage; + using type = xtl::mpl::eval_if_t, + self_type>, + self_type>>; }; template @@ -142,37 +215,165 @@ namespace xt using type = xbuffer_owner_storage; }; + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + template using buffer_storage_t = typename get_buffer_storage::type; } - template - class xbuffer_adaptor : private detail::buffer_storage_t + /************************ + * xbuffer_adaptor_base * + ************************/ + + template + struct buffer_inner_types; + + template + class xbuffer_adaptor_base { public: + using self_type = xbuffer_adaptor_base; + using derived_type = D; + using inner_types = buffer_inner_types; + using value_type = typename inner_types::value_type; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using pointer = typename inner_types::pointer; + using const_pointer = typename inner_types::const_pointer; + using size_type = typename inner_types::size_type; + using difference_type = typename inner_types::difference_type; + using iterator = typename inner_types::iterator; + using const_iterator = typename inner_types::const_iterator; + using reverse_iterator = typename inner_types::reverse_iterator; + using const_reverse_iterator = typename inner_types::const_reverse_iterator; + using index_type = typename inner_types::index_type; + + bool empty() const noexcept; + + reference operator[](size_type i); + const_reference operator[](size_type i) const; + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + iterator begin() noexcept; + iterator end() noexcept; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + reverse_iterator rbegin() noexcept; + reverse_iterator rend() noexcept; + + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + derived_type& derived_cast() noexcept; + const derived_type& derived_cast() const noexcept; + + protected: + + xbuffer_adaptor_base() = default; + ~xbuffer_adaptor_base() = default; + + xbuffer_adaptor_base(const self_type&) = default; + self_type& operator=(const self_type&) = default; + + xbuffer_adaptor_base(self_type&&) = default; + self_type& operator=(self_type&&) = default; + }; + + template + bool operator==(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator!=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator<(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator<=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator>(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator>=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + /******************* + * xbuffer_adaptor * + *******************/ + + template + struct buffer_inner_types> + { using base_type = detail::buffer_storage_t; - using self_type = xbuffer_adaptor; - using allocator_type = typename base_type::allocator_type; using value_type = typename base_type::value_type; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using pointer = typename base_type::pointer; using const_pointer = typename base_type::const_pointer; - using temporary_type = uvector; - using size_type = typename base_type::size_type; using difference_type = typename base_type::difference_type; - using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + using index_type = size_type; + }; + + template + class xbuffer_adaptor : private detail::buffer_storage_t, + public xbuffer_adaptor_base> + { + public: + + using self_type = xbuffer_adaptor; + using base_type = detail::buffer_storage_t; + using buffer_base_type = xbuffer_adaptor_base; + using allocator_type = typename base_type::allocator_type; + using destructor_type = typename base_type::destructor_type; + using value_type = typename buffer_base_type::value_type; + using reference = typename buffer_base_type::reference; + using const_reference = typename buffer_base_type::const_reference; + using pointer = typename buffer_base_type::pointer; + using const_pointer = typename buffer_base_type::const_pointer; + using size_type = typename buffer_base_type::size_type; + using difference_type = typename buffer_base_type::difference_type; + using iterator = typename buffer_base_type::iterator; + using const_iterator = typename buffer_base_type::const_iterator; + using reverse_iterator = typename buffer_base_type::reverse_iterator; + using const_reverse_iterator = typename buffer_base_type::const_reverse_iterator; + using temporary_type = uvector; xbuffer_adaptor() = default; - template - xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + using base_type::base_type; ~xbuffer_adaptor() = default; @@ -184,67 +385,93 @@ namespace xt self_type& operator=(temporary_type&&); - bool empty() const noexcept; using base_type::size; using base_type::resize; - - reference operator[](size_type i); - const_reference operator[](size_type i) const; - - reference front(); - const_reference front() const; - - reference back(); - const_reference back() const; - - iterator begin(); - iterator end(); - - const_iterator begin() const; - const_iterator end() const; - const_iterator cbegin() const; - const_iterator cend() const; - - reverse_iterator rbegin(); - reverse_iterator rend(); - - const_reverse_iterator rbegin() const; - const_reverse_iterator rend() const; - const_reverse_iterator crbegin() const; - const_reverse_iterator crend() const; - using base_type::data; using base_type::swap; }; - template - bool operator==(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator!=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator<(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator<=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator>(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator>=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - template void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept; + /********************* + * xiterator_adaptor * + *********************/ + + template + class xiterator_adaptor; + + template + struct buffer_inner_types> + { + using traits = std::iterator_traits; + using const_traits = std::iterator_traits; + + using value_type = std::common_type_t; + using reference = typename traits::reference; + using const_reference = typename const_traits::reference; + using pointer = typename traits::pointer; + using const_pointer = typename const_traits::pointer; + using difference_type = std::common_type_t; + using size_type = std::make_unsigned_t; + + using iterator = I; + using const_iterator = CI; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using index_type = difference_type; + }; + + template + class xiterator_adaptor : public xbuffer_adaptor_base> + { + public: + + using self_type = xiterator_adaptor; + using base_type = xbuffer_adaptor_base; + using value_type = typename base_type::value_type; + using allocator_type = std::allocator; + using size_type = typename base_type::size_type; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using temporary_type = uvector; + + xiterator_adaptor() = default; + xiterator_adaptor(I it, CI cit, size_type size); + + ~xiterator_adaptor() = default; + + xiterator_adaptor(const self_type&) = default; + xiterator_adaptor& operator=(const self_type&) = default; + + xiterator_adaptor(self_type&&) = default; + xiterator_adaptor& operator=(self_type&&) = default; + + xiterator_adaptor& operator=(const temporary_type& rhs); + xiterator_adaptor& operator=(temporary_type&& rhs); + + size_type size() const noexcept; + void resize(size_type size); + + iterator data() noexcept; + const_iterator data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + I m_it; + CI m_cit; + size_type m_size; + }; + + template + void swap(xiterator_adaptor& lhs, + xiterator_adaptor& rhs) noexcept; + /************************************ * temporary_container metafunction * ************************************/ @@ -261,6 +488,12 @@ namespace xt using type = typename xbuffer_adaptor::temporary_type; }; + template + struct temporary_container> + { + using type = typename xiterator_adaptor::temporary_type; + }; + template using temporary_container_t = typename temporary_container::type; @@ -378,7 +611,6 @@ namespace xt inline auto xbuffer_owner_storage::operator=(self_type&& rhs) -> self_type& { swap(rhs); - rhs.m_moved_from = true; return *this; } @@ -429,195 +661,320 @@ namespace xt } } + /**************************************** + * xbuffer_smart_pointer implementation * + ****************************************/ + + namespace detail + { + template + template + xbuffer_smart_pointer::xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct) + : p_data(data_ptr), m_size(size), m_destruct(std::forward

(destruct)) + { + } + + template + auto xbuffer_smart_pointer::size() const noexcept -> size_type + { + return m_size; + } + + template + void xbuffer_smart_pointer::resize(size_type size) + { + if (m_size != size) + { + throw std::runtime_error("xbuffer_storage not resizable"); + } + } + + template + auto xbuffer_smart_pointer::data() noexcept -> pointer + { + return p_data; + } + template + auto xbuffer_smart_pointer::data() const noexcept -> const_pointer + { + return p_data; + } + + template + void xbuffer_smart_pointer::swap(self_type& rhs) noexcept + { + using std::swap; + swap(p_data, rhs.p_data); + swap(m_size, rhs.m_size); + swap(m_destruct, rhs.m_destruct); + } + } + + /*************************************** + * xbuffer_adaptor_base implementation * + ***************************************/ + + template + inline bool xbuffer_adaptor_base::empty() const noexcept + { + return derived_cast().size() == size_type(0); + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) -> reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) const -> const_reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::front() -> reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::front() const -> const_reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::back() -> reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::back() const -> const_reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::begin() noexcept -> iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() noexcept-> iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::begin() const noexcept -> const_iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() const noexcept -> const_iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::cbegin() const noexcept -> const_iterator + { + return begin(); + } + + template + inline auto xbuffer_adaptor_base::cend() const noexcept -> const_iterator + { + return end(); + } + + template + inline auto xbuffer_adaptor_base::rbegin() noexcept-> reverse_iterator + { + return reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() noexcept -> reverse_iterator + { + return reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::rbegin() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::crbegin() const noexcept -> const_reverse_iterator + { + return rbegin(); + } + + template + inline auto xbuffer_adaptor_base::crend() const noexcept -> const_reverse_iterator + { + return rend(); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + template + inline bool operator==(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return lhs.derived_cast().size() == rhs.derived_cast().size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + inline bool operator!=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return !(lhs == rhs); + } + + template + inline bool operator<(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less()); + } + + template + inline bool operator<=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less_equal()); + } + + template + inline bool operator>(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater()); + } + + template + inline bool operator>=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater_equal()); + } + /********************************** * xbuffer_adaptor implementation * **********************************/ - template - template - inline xbuffer_adaptor::xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc) - : base_type(std::forward

(data), size, alloc) - { - } - template inline auto xbuffer_adaptor::operator=(temporary_type&& tmp) -> self_type& { base_type::resize(tmp.size()); - std::copy(tmp.cbegin(), tmp.cend(), begin()); + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); return *this; } - template - bool xbuffer_adaptor::empty() const noexcept - { - return size() == 0; - } - - template - inline auto xbuffer_adaptor::operator[](size_type i) -> reference - { - return data()[i]; - } - - template - inline auto xbuffer_adaptor::operator[](size_type i) const -> const_reference - { - return data()[i]; - } - - template - inline auto xbuffer_adaptor::front() -> reference - { - return data()[0]; - } - - template - inline auto xbuffer_adaptor::front() const -> const_reference - { - return data()[0]; - } - - template - inline auto xbuffer_adaptor::back() -> reference - { - return data()[size() - 1]; - } - - template - inline auto xbuffer_adaptor::back() const -> const_reference - { - return data()[size() - 1]; - } - - template - inline auto xbuffer_adaptor::begin() -> iterator - { - return data(); - } - - template - inline auto xbuffer_adaptor::end() -> iterator - { - return data() + size(); - } - - template - inline auto xbuffer_adaptor::begin() const -> const_iterator - { - return data(); - } - - template - inline auto xbuffer_adaptor::end() const -> const_iterator - { - return data() + size(); - } - - template - inline auto xbuffer_adaptor::cbegin() const -> const_iterator - { - return begin(); - } - - template - inline auto xbuffer_adaptor::cend() const -> const_iterator - { - return end(); - } - - template - inline auto xbuffer_adaptor::rbegin() -> reverse_iterator - { - return reverse_iterator(end()); - } - - template - inline auto xbuffer_adaptor::rend() -> reverse_iterator - { - return reverse_iterator(begin()); - } - - template - inline auto xbuffer_adaptor::rbegin() const -> const_reverse_iterator - { - return const_reverse_iterator(end()); - } - - template - inline auto xbuffer_adaptor::rend() const -> const_reverse_iterator - { - return const_reverse_iterator(begin()); - } - - template - inline auto xbuffer_adaptor::crbegin() const -> const_reverse_iterator - { - return rbegin(); - } - - template - inline auto xbuffer_adaptor::crend() const -> const_reverse_iterator - { - return rend(); - } - - template - inline bool operator==(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - - template - inline bool operator!=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return !(lhs == rhs); - } - - template - inline bool operator<(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::less()); - } - - template - inline bool operator<=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::less_equal()); - } - - template - inline bool operator>(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::greater()); - } - - template - inline bool operator>=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::greater_equal()); - } - template inline void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept { lhs.swap(rhs); } + + /************************************ + * xiterator_adaptor implementation * + ************************************/ + + template + inline xiterator_adaptor::xiterator_adaptor(I it, CI cit, size_type size) + : m_it(it), m_cit(cit), m_size(size) + { + } + + template + inline auto xiterator_adaptor::operator=(const temporary_type& rhs) -> self_type& + { + resize(rhs.size()); + std::copy(rhs.cbegin(), rhs.cend(), m_it); + return *this; + } + + template + inline auto xiterator_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + return (*this = rhs); + } + + template + inline auto xiterator_adaptor::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xiterator_adaptor::resize(size_type size) + { + if (m_size != size) + { + throw std::runtime_error("xiterator_adaptor not resizable"); + } + } + + template + inline auto xiterator_adaptor::data() noexcept -> iterator + { + return m_it; + } + + template + inline auto xiterator_adaptor::data() const noexcept -> const_iterator + { + return m_cit; + } + + template + inline void xiterator_adaptor::swap(self_type& rhs) noexcept + { + using std::swap; + swap(m_it, rhs.m_it); + swap(m_cit, rhs.m_cit); + swap(m_size, rhs.m_size); + } + + template + inline void swap(xiterator_adaptor& lhs, + xiterator_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } } #endif diff --git a/vendor/xtensor/include/xtensor/xbuilder.hpp b/vendor/xtensor/include/xtensor/xbuilder.hpp index c3e34b8ac..dfbb2f3cd 100644 --- a/vendor/xtensor/include/xtensor/xbuilder.hpp +++ b/vendor/xtensor/include/xtensor/xbuilder.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -14,6 +15,7 @@ #define XTENSOR_BUILDER_HPP #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include +#include #include "xbroadcast.hpp" #include "xfunction.hpp" @@ -111,7 +114,7 @@ namespace xt inline xtensor empty(const std::array& shape) { using shape_type = typename xtensor::shape_type; - return xtensor(xtl::forward_sequence(shape)); + return xtensor(xtl::forward_sequence(shape)); } #ifndef X_OLD_CLANG @@ -119,7 +122,13 @@ namespace xt inline xtensor empty(const I(&shape)[N]) { using shape_type = typename xtensor::shape_type; - return xtensor(xtl::forward_sequence(shape)); + return xtensor(xtl::forward_sequence(shape)); + } +#else + template + inline xarray empty(const std::initializer_list& init) + { + return xarray::from_shape(init); } #endif @@ -136,9 +145,10 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type empty_like(const xexpression& e) + inline auto empty_like(const xexpression& e) { - typename E::temporary_type res(e.derived_cast().shape()); + using xtype = temporary_type_t; + auto res = xtype::from_shape(e.derived_cast().shape()); return res; } @@ -150,9 +160,11 @@ namespace xt * @param fill_value the value used to set each element of the returned xcontainer. */ template - inline typename E::temporary_type full_like(const xexpression& e, typename E::value_type fill_value) + inline auto full_like(const xexpression& e, typename E::value_type fill_value) { - typename E::temporary_type res(e.derived_cast().shape(), fill_value); + using xtype = temporary_type_t; + auto res = xtype::from_shape(e.derived_cast().shape()); + res.fill(fill_value); return res; } @@ -166,7 +178,7 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type zeros_like(const xexpression& e) + inline auto zeros_like(const xexpression& e) { return full_like(e, typename E::value_type(0)); } @@ -181,68 +193,130 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type ones_like(const xexpression& e) + inline auto ones_like(const xexpression& e) { return full_like(e, typename E::value_type(1)); } namespace detail { - template - class arange_impl + template + struct get_mult_type_impl + { + using type = T; + }; + + template + struct get_mult_type_impl> + { + using type = R; + }; + + template + using get_mult_type = typename get_mult_type_impl::type; + + // These methods should be private methods of arange_generator, however thi leads + // to ICE on VS2015 + template )> + inline void arange_assign_to(xexpression& e, U start, X step) noexcept + { + auto& de = e.derived_cast(); + U value = start; + + for (auto&& el : de.storage()) + { + el = static_cast(value); + value += step; + } + } + + template >)> + inline void arange_assign_to(xexpression& e, U start, X step) noexcept + { + auto& buf = e.derived_cast().storage(); + using size_type = decltype(buf.size()); + using mult_type = get_mult_type; + for(size_type i = 0; i < buf.size(); ++i) + { + buf[i] = static_cast(start + step * mult_type(i)); + } + } + + template + class arange_generator { public: - using value_type = T; + using value_type = R; + using step_type = S; - arange_impl(T start, T stop, T step) + arange_generator(T start, T stop, S step) : m_start(start), m_stop(stop), m_step(step) { } template - inline T operator()(Args... args) const + inline R operator()(Args... args) const { return access_impl(args...); } template - inline T element(It first, It) const + inline R element(It first, It) const { - return m_start + m_step * T(*first); + // Avoids warning when T = char (because char + char => int!) + using mult_type = get_mult_type; + return static_cast(m_start + m_step * mult_type(*first)); } template inline void assign_to(xexpression& e) const noexcept { - auto& de = e.derived_cast(); - value_type value = m_start; - - for (auto& el : de.storage()) - { - el = value; - value += m_step; - } + arange_assign_to(e, m_start, m_step); } private: - value_type m_start; - value_type m_stop; - value_type m_step; + T m_start; + T m_stop; + step_type m_step; template - inline T access_impl(T1 t, Args...) const + inline R access_impl(T1 t, Args...) const { - return m_start + m_step * T(t); + using mult_type = get_mult_type; + return static_cast(m_start + m_step * mult_type(t)); } - inline T access_impl() const + inline R access_impl() const { - return m_start; + return static_cast(m_start); } }; + template + using both_integer = xtl::conjunction, std::is_integral>; + + template >)> + inline auto arange_impl(T start, T stop, S step = 1) noexcept + { + std::size_t shape = static_cast(std::ceil((stop - start) / step)); + return detail::make_xgenerator(detail::arange_generator(start, stop, step), {shape}); + } + + template )> + inline auto arange_impl(T start, T stop, S step = 1) noexcept + { + bool empty_cond = (stop - start) / step <= 0; + std::size_t shape = 0; + if(!empty_cond) + { + shape = stop > start ? static_cast((stop - start + step - S(1)) / step) + : static_cast((start - stop - step - S(1)) / -step); + } + return detail::make_xgenerator(detail::arange_generator(start, stop, step), {shape}); + } + template class fn_impl { @@ -301,12 +375,12 @@ namespace xt inline T operator()(const It& /*begin*/, const It& end) const { using lvalue_type = typename std::iterator_traits::value_type; - return *(end - 1) == *(end - 2) + static_cast(static_cast(m_k)) ? T(1) : T(0); + return *(end - 1) == *(end - 2) + static_cast(m_k) ? T(1) : T(0); } private: - int m_k; + std::ptrdiff_t m_k; }; } @@ -348,11 +422,10 @@ namespace xt * @tparam T value_type of xexpression * @return xgenerator that generates the values on access */ - template - inline auto arange(T start, T stop, T step = 1) noexcept + template + inline auto arange(T start, T stop, S step = 1) noexcept { - std::size_t shape = static_cast(std::ceil((stop - start) / step)); - return detail::make_xgenerator(detail::arange_impl(start, stop, step), {shape}); + return detail::arange_impl(start, stop, step); } /** @@ -381,8 +454,8 @@ namespace xt inline auto linspace(T start, T stop, std::size_t num_samples = 50, bool endpoint = true) noexcept { using fp_type = std::common_type_t; - fp_type step = fp_type(stop - start) / fp_type(num_samples - (endpoint ? 1 : 0)); - return cast(detail::make_xgenerator(detail::arange_impl(fp_type(start), fp_type(stop), step), {num_samples})); + fp_type step = fp_type(stop - start) / std::fmax(fp_type(1), fp_type(num_samples - (endpoint ? 1 : 0))); + return detail::make_xgenerator(detail::arange_generator(fp_type(start), fp_type(stop), step), {num_samples}); } /** @@ -398,7 +471,7 @@ namespace xt template inline auto logspace(T start, T stop, std::size_t num_samples, T base = 10, bool endpoint = true) noexcept { - return cast(pow(std::move(base), linspace(start, stop, num_samples, endpoint))); + return pow(std::move(base), linspace(start, stop, num_samples, endpoint)); } namespace detail @@ -409,7 +482,7 @@ namespace xt public: using size_type = std::size_t; - using value_type = promote_type_t::value_type...>; + using value_type = xtl::promote_type_t::value_type...>; inline concatenate_impl(std::tuple&& t, size_type axis) : m_t(t), m_axis(axis) @@ -468,7 +541,7 @@ namespace xt public: using size_type = std::size_t; - using value_type = promote_type_t::value_type...>; + using value_type = xtl::promote_type_t::value_type...>; inline stack_impl(std::tuple&& t, size_type axis) : m_t(t), m_axis(axis) @@ -569,11 +642,28 @@ namespace xt inline auto concatenate(std::tuple&& t, std::size_t axis = 0) { using shape_type = promote_shape_t::shape_type...>; - shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + using source_shape_type = decltype(std::get<0>(t).shape()); + shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + + auto check_shape = [&axis, &new_shape](auto& arr) { + std::size_t s = new_shape.size(); + bool res = s == arr.dimension(); + for(std::size_t i = 0; i < s; ++i) + { + res = res && (i == axis || new_shape[i] == arr.shape(i)); + } + if(!res) + { + throw_concatenate_error(new_shape, arr.shape()); + } + }; + for_each(check_shape, t); + auto shape_at_axis = [&axis](std::size_t prev, auto& arr) -> std::size_t { return prev + arr.shape()[axis]; }; new_shape[axis] += accumulate(shape_at_axis, std::size_t(0), t) - new_shape[axis]; + return detail::make_xgenerator(detail::concatenate_impl(std::forward>(t), axis), new_shape); } @@ -620,7 +710,8 @@ namespace xt inline auto stack(std::tuple&& t, std::size_t axis = 0) { using shape_type = promote_shape_t::shape_type...>; - auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); + using source_shape_type = decltype(std::get<0>(t).shape()); + auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); return detail::make_xgenerator(detail::stack_impl(std::forward>(t), axis), new_shape); } diff --git a/vendor/xtensor/include/xtensor/xcomplex.hpp b/vendor/xtensor/include/xtensor/xcomplex.hpp index e47842aa1..5bae3266d 100644 --- a/vendor/xtensor/include/xtensor/xcomplex.hpp +++ b/vendor/xtensor/include/xtensor/xcomplex.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -20,7 +21,6 @@ namespace xt { - /****************************** * real and imag declarations * ******************************/ @@ -61,7 +61,7 @@ namespace xt template static inline decltype(auto) real(E&& e) noexcept { - return e; + return std::forward(e); } template @@ -75,15 +75,15 @@ namespace xt struct complex_expression_helper { template - static inline auto real(E&& e) noexcept + static inline decltype(auto) real(E&& e) noexcept { - return detail::complex_helper::value_type>::value>::real(e); + return detail::complex_helper::value_type>::value>::real(std::forward(e)); } template - static inline auto imag(E&& e) noexcept + static inline decltype(auto) imag(E&& e) noexcept { - return detail::complex_helper::value_type>::value>::imag(e); + return detail::complex_helper::value_type>::value>::imag(std::forward(e)); } }; @@ -132,56 +132,70 @@ namespace xt return detail::complex_expression_helper>::value>::imag(std::forward(e)); } -#define UNARY_COMPLEX_FUNCTOR(NAME) \ - template \ +#define UNARY_COMPLEX_FUNCTOR(NS, NAME) \ struct NAME##_fun \ { \ - using argument_type = T; \ - using result_type = decltype(std::NAME(std::declval())); \ - constexpr result_type operator()(const T& t) const \ + template \ + constexpr auto operator()(const T& t) const \ { \ - using std::NAME; \ + using NS::NAME; \ + return NAME(t); \ + } \ + \ + template \ + constexpr auto simd_apply(const B& t) const \ + { \ + using NS::NAME; \ return NAME(t); \ } \ } namespace math { - UNARY_COMPLEX_FUNCTOR(norm); - UNARY_COMPLEX_FUNCTOR(arg); - namespace detail { - // libc++ (OSX) conj is unfortunately broken and returns - // std::complex instead of T. template - constexpr T conj(const T& c) - { - return c; - } - - template - constexpr std::complex conj(const std::complex& c) + constexpr std::complex conj_impl(const std::complex& c) { return std::complex(c.real(), -c.imag()); } + +#ifdef XTENSOR_USE_XSIMD + template + constexpr X conj_impl(const xsimd::simd_complex_batch& z) + { + return xsimd::conj(z); + } + + template + struct not_complex_batch + : xtl::negation, T>> + { + }; + + // libc++ (OSX) conj is unfortunately broken and returns + // std::complex instead of T. + // This function must be deactivated for complex batches, + // otherwise it will be a better match than the previous one. + template )> + constexpr T conj_impl(const T& c) + { + return c; + } +#else + // libc++ (OSX) conj is unfortunately broken and returns + // std::complex instead of T. + template + constexpr T conj_impl(const T& c) + { + return c; + } +#endif } - template - struct conj_fun - { - using argument_type = T; - using result_type = decltype(detail::conj(std::declval())); - using simd_value_type = xsimd::simd_type; - constexpr result_type operator()(const T& t) const - { - return detail::conj(t); - } - constexpr simd_value_type simd_apply(const simd_value_type& t) const - { - return detail::conj(t); - } - }; + UNARY_COMPLEX_FUNCTOR(std, norm); + UNARY_COMPLEX_FUNCTOR(std, arg); + UNARY_COMPLEX_FUNCTOR(detail, conj_impl); } #undef UNARY_COMPLEX_FUNCTOR @@ -194,10 +208,8 @@ namespace xt template inline auto conj(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::conj_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::conj_impl_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } @@ -208,10 +220,8 @@ namespace xt template inline auto arg(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::arg_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::arg_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } @@ -241,10 +251,8 @@ namespace xt template inline auto norm(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::norm_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::norm_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } } diff --git a/vendor/xtensor/include/xtensor/xcontainer.hpp b/vendor/xtensor/include/xtensor/xcontainer.hpp index 80df1907f..129016a7b 100644 --- a/vendor/xtensor/include/xtensor/xcontainer.hpp +++ b/vendor/xtensor/include/xtensor/xcontainer.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -11,13 +12,13 @@ #include #include -#include #include #include #include #include +#include "xaccessible.hpp" #include "xiterable.hpp" #include "xiterator.hpp" #include "xmath.hpp" @@ -36,8 +37,6 @@ namespace xt using const_stepper = xstepper; }; -#define DL XTENSOR_DEFAULT_LAYOUT - namespace detail { template @@ -56,7 +55,6 @@ namespace xt template using allocator_type_t = typename detail::allocator_type_impl::type; - /** * @class xcontainer * @brief Base class for dense multidimensional containers. @@ -69,7 +67,8 @@ namespace xt * provides the interface. */ template - class xcontainer : private xiterable + class xcontainer : public xcontiguous_iterable, + private xaccessible { public: @@ -79,15 +78,14 @@ namespace xt using storage_type = typename inner_types::storage_type; using allocator_type = allocator_type_t>; using value_type = typename storage_type::value_type; - using reference = std::conditional_t::value, - typename storage_type::const_reference, - typename storage_type::reference>; - using const_reference = typename storage_type::const_reference; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; using pointer = typename storage_type::pointer; using const_pointer = typename storage_type::const_pointer; - using size_type = typename storage_type::size_type; + using size_type = typename inner_types::size_type; using difference_type = typename storage_type::difference_type; - using simd_value_type = xsimd::simd_type; + using simd_value_type = xt_simd::simd_type; + using bool_load_type = xt::bool_load_type; using shape_type = typename inner_types::shape_type; using strides_type = typename inner_types::strides_type; @@ -97,24 +95,31 @@ namespace xt using inner_strides_type = typename inner_types::inner_strides_type; using inner_backstrides_type = typename inner_types::inner_backstrides_type; - using iterable_base = xiterable; + using iterable_base = xcontiguous_iterable; using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; + using accessible_base = xaccessible; + static constexpr layout_type static_layout = inner_types::layout; static constexpr bool contiguous_layout = static_layout != layout_type::dynamic; - using data_alignment = xsimd::container_alignment_t; - using simd_type = xsimd::simd_type; + using data_alignment = xt_simd::container_alignment_t; + using simd_type = xt_simd::simd_type; + + using storage_iterator = typename iterable_base::storage_iterator; + using const_storage_iterator = typename iterable_base::const_storage_iterator; + using reverse_storage_iterator = typename iterable_base::reverse_storage_iterator; + using const_reverse_storage_iterator = typename iterable_base::const_reverse_storage_iterator; static_assert(static_layout != layout_type::any, "Container layout can never be layout_type::any!"); size_type size() const noexcept; - constexpr size_type dimension() const noexcept; + XTENSOR_CONSTEXPR_RETURN size_type dimension() const noexcept; - constexpr const inner_shape_type& shape() const noexcept; - constexpr const inner_strides_type& strides() const noexcept; - constexpr const inner_backstrides_type& backstrides() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides() const noexcept; template void fill(const T& value); @@ -125,29 +130,17 @@ namespace xt template const_reference operator()(Args... args) const; - template - reference at(Args... args); - - template - const_reference at(Args... args) const; - template reference unchecked(Args... args); template const_reference unchecked(Args... args) const; - template - disable_integral_t operator[](const S& index); - template - reference operator[](std::initializer_list index); - reference operator[](size_type i); - - template - disable_integral_t operator[](const S& index) const; - template - const_reference operator[](std::initializer_list index) const; - const_reference operator[](size_type i) const; + using accessible_base::shape; + using accessible_base::at; + using accessible_base::operator[]; + using accessible_base::periodic; + using accessible_base::in_bounds; template reference element(It first, It last); @@ -165,8 +158,7 @@ namespace xt bool broadcast_shape(S& shape, bool reuse_cache = false) const; template - bool is_trivial_broadcast(const S& strides) const noexcept; - + bool has_linear_assign(const S& strides) const noexcept; template stepper stepper_begin(const S& shape) noexcept; template @@ -180,149 +172,30 @@ namespace xt reference data_element(size_type i); const_reference data_element(size_type i) const; - template - using simd_return_type = xsimd::simd_return_type; + template + using simd_return_type = xt_simd::simd_return_type; - template + template void store_simd(size_type i, const simd& e); - template - simd_return_type load_simd(size_type i) const; + template ::size> + container_simd_return_type_t + /*simd_return_type*/ load_simd(size_type i) const; -#if defined(_MSC_VER) && _MSC_VER >= 1910 - // Workaround for compiler bug in Visual Studio 2017 with respect to alias templates with non-type parameters. - template - using layout_iterator = xiterator; - template - using const_layout_iterator = xiterator; - template - using reverse_layout_iterator = std::reverse_iterator>; - template - using const_reverse_layout_iterator = std::reverse_iterator>; -#else - template - using layout_iterator = typename iterable_base::template layout_iterator; - template - using const_layout_iterator = typename iterable_base::template const_layout_iterator; - template - using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; - template - using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; -#endif - - template - using broadcast_iterator = typename iterable_base::template broadcast_iterator; - template - using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; - template - using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; - template - using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; - - using storage_iterator = typename storage_type::iterator; - using const_storage_iterator = typename storage_type::const_iterator; - using reverse_storage_iterator = typename storage_type::reverse_iterator; - using const_reverse_storage_iterator = typename storage_type::const_reverse_iterator; - - template - using select_iterator_impl = std::conditional_t; - - template - using select_iterator = select_iterator_impl>; - template - using select_const_iterator = select_iterator_impl>; - template - using select_reverse_iterator = select_iterator_impl>; - template - using select_const_reverse_iterator = select_iterator_impl>; - - using iterator = select_iterator

; - using const_iterator = select_const_iterator
; - using reverse_iterator = select_reverse_iterator
; - using const_reverse_iterator = select_const_reverse_iterator
; - - template - select_iterator begin() noexcept; - template - select_iterator end() noexcept; - - template - select_const_iterator begin() const noexcept; - template - select_const_iterator end() const noexcept; - template - select_const_iterator cbegin() const noexcept; - template - select_const_iterator cend() const noexcept; - - template - select_reverse_iterator rbegin() noexcept; - template - select_reverse_iterator rend() noexcept; - - template - select_const_reverse_iterator rbegin() const noexcept; - template - select_const_reverse_iterator rend() const noexcept; - template - select_const_reverse_iterator crbegin() const noexcept; - template - select_const_reverse_iterator crend() const noexcept; - - template - broadcast_iterator begin(const S& shape) noexcept; - template - broadcast_iterator end(const S& shape) noexcept; - - template - const_broadcast_iterator begin(const S& shape) const noexcept; - template - const_broadcast_iterator end(const S& shape) const noexcept; - template - const_broadcast_iterator cbegin(const S& shape) const noexcept; - template - const_broadcast_iterator cend(const S& shape) const noexcept; - - - template - reverse_broadcast_iterator rbegin(const S& shape) noexcept; - template - reverse_broadcast_iterator rend(const S& shape) noexcept; - - template - const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator rend(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator crend(const S& shape) const noexcept; - - template storage_iterator storage_begin() noexcept; - template storage_iterator storage_end() noexcept; - template const_storage_iterator storage_begin() const noexcept; - template const_storage_iterator storage_end() const noexcept; - template const_storage_iterator storage_cbegin() const noexcept; - template const_storage_iterator storage_cend() const noexcept; - template reverse_storage_iterator storage_rbegin() noexcept; - template reverse_storage_iterator storage_rend() noexcept; - template const_reverse_storage_iterator storage_rbegin() const noexcept; - template const_reverse_storage_iterator storage_rend() const noexcept; - template const_reverse_storage_iterator storage_crbegin() const noexcept; - template const_reverse_storage_iterator storage_crend() const noexcept; using container_iterator = storage_iterator; @@ -341,8 +214,8 @@ namespace xt container_iterator data_xbegin() noexcept; const_container_iterator data_xbegin() const noexcept; - container_iterator data_xend(layout_type l) noexcept; - const_container_iterator data_xend(layout_type l) const noexcept; + container_iterator data_xend(layout_type l, size_type offset) noexcept; + const_container_iterator data_xend(layout_type l, size_type offset) const noexcept; protected: @@ -352,21 +225,19 @@ namespace xt private: - friend class xiterable; - friend class xconst_iterable; - - template - friend class xstepper; - template - It data_xend_impl(It end, layout_type l) const noexcept; + It data_xend_impl(It begin, layout_type l, size_type offset) const noexcept; inner_shape_type& mutable_shape(); inner_strides_type& mutable_strides(); inner_backstrides_type& mutable_backstrides(); - }; -#undef DL + template + friend class xstepper; + + friend class xaccessible; + friend class xconst_accessible; + }; /** * @class xstrided_container @@ -409,6 +280,9 @@ namespace xt template void reshape(S&& shape, layout_type layout = base_type::static_layout); + template + void reshape(std::initializer_list shape, layout_type layout = base_type::static_layout); + layout_type layout() const noexcept; protected: @@ -423,6 +297,7 @@ namespace xt xstrided_container& operator=(xstrided_container&&) = default; explicit xstrided_container(inner_shape_type&&, inner_strides_type&&) noexcept; + explicit xstrided_container(inner_shape_type&&, inner_strides_type&&, inner_backstrides_type&&, layout_type&&) noexcept; inner_shape_type& shape_impl() noexcept; const inner_shape_type& shape_impl() const noexcept; @@ -433,6 +308,16 @@ namespace xt inner_backstrides_type& backstrides_impl() noexcept; const inner_backstrides_type& backstrides_impl() const noexcept; + template + void reshape_impl(S&& shape, std::true_type, layout_type layout = base_type::static_layout); + template + void reshape_impl(S&& shape, std::false_type, layout_type layout = base_type::static_layout); + + layout_type& mutable_layout() noexcept + { + return m_layout; + } + private: inner_shape_type m_shape; @@ -447,9 +332,9 @@ namespace xt template template - inline It xcontainer::data_xend_impl(It end, layout_type l) const noexcept + inline It xcontainer::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept { - return strided_data_end(*this, end, l); + return strided_data_end(*this, begin, l, offset); } template @@ -487,7 +372,7 @@ namespace xt * Returns the number of dimensions of the container. */ template - inline constexpr auto xcontainer::dimension() const noexcept -> size_type + XTENSOR_CONSTEXPR_RETURN auto xcontainer::dimension() const noexcept -> size_type { return shape().size(); } @@ -496,7 +381,7 @@ namespace xt * Returns the shape of the container. */ template - constexpr inline auto xcontainer::shape() const noexcept -> const inner_shape_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::shape() const noexcept -> const inner_shape_type& { return derived_cast().shape_impl(); } @@ -505,7 +390,7 @@ namespace xt * Returns the strides of the container. */ template - constexpr inline auto xcontainer::strides() const noexcept -> const inner_strides_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::strides() const noexcept -> const inner_strides_type& { return derived_cast().strides_impl(); } @@ -514,7 +399,7 @@ namespace xt * Returns the backstrides of the container. */ template - constexpr inline auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& { return derived_cast().backstrides_impl(); } @@ -548,7 +433,7 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), static_cast(args)...); return storage()[index]; } @@ -564,44 +449,10 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), static_cast(args)...); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) -> reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - - /** - * Returns a constant reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) const -> const_reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - /** * Returns a reference to the element at the specified position in the container. * @param args a list of indices specifying the position in the container. Indices @@ -625,7 +476,7 @@ namespace xt template inline auto xcontainer::unchecked(Args... args) -> reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); return storage()[index]; } @@ -652,64 +503,10 @@ namespace xt template inline auto xcontainer::unchecked(Args... args) const -> const_reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) -> reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) -> reference - { - return operator()(i); - } - - /** - * Returns a constant reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) const - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) const -> const_reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) const -> const_reference - { - return operator()(i); - } - /** * Returns a reference to the element at the specified position in the container. * @param first iterator starting the sequence of indices @@ -809,397 +606,19 @@ namespace xt } /** - * Compares the specified strides with those of the container to see whether - * the broadcasting is trivial. - * @return a boolean indicating whether the broadcasting is trivial + * Checks whether the xcontainer can be linearly assigned to an expression + * with the specified strides. + * @return a boolean indicating whether a linear assign is possible */ template template - inline bool xcontainer::is_trivial_broadcast(const S& str) const noexcept + inline bool xcontainer::has_linear_assign(const S& str) const noexcept { return str.size() == strides().size() && std::equal(str.cbegin(), str.cend(), strides().begin()); } //@} - /**************** - * Iterator api * - ****************/ - - template - template - inline auto xcontainer::begin() noexcept -> select_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_begin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template begin(); - }); - } - - template - template - inline auto xcontainer::end() noexcept -> select_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_end(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template end(); - }); - } - - template - template - inline auto xcontainer::begin() const noexcept -> select_const_iterator - { - return this->template cbegin(); - } - - template - template - inline auto xcontainer::end() const noexcept -> select_const_iterator - { - return this->template cend(); - } - - template - template - inline auto xcontainer::cbegin() const noexcept -> select_const_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_cbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template cbegin(); - }); - } - - template - template - inline auto xcontainer::cend() const noexcept -> select_const_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_cend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template cend(); - }); - } - - template - template - inline auto xcontainer::rbegin() noexcept -> select_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_rbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template rbegin(); - }); - } - - template - template - inline auto xcontainer::rend() noexcept -> select_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_rend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template rend(); - }); - } - - template - template - inline auto xcontainer::rbegin() const noexcept -> select_const_reverse_iterator - { - return this->template crbegin(); - } - - template - template - inline auto xcontainer::rend() const noexcept -> select_const_reverse_iterator - { - return this->template crend(); - } - - template - template - inline auto xcontainer::crbegin() const noexcept -> select_const_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_crbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template crbegin(); - }); - } - - template - template - inline auto xcontainer::crend() const noexcept -> select_const_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_crend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template crend(); - }); - } - - /***************************** - * Broadcasting iterator api * - *****************************/ - - template - template - inline auto xcontainer::begin(const S& shape) noexcept -> broadcast_iterator - { - return iterable_base::template begin(shape); - } - - template - template - inline auto xcontainer::end(const S& shape) noexcept -> broadcast_iterator - { - return iterable_base::template end(shape); - } - - template - template - inline auto xcontainer::begin(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template begin(shape); - } - - template - template - inline auto xcontainer::end(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template end(shape); - } - - template - template - inline auto xcontainer::cbegin(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template cbegin(shape); - } - - template - template - inline auto xcontainer::cend(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template cend(shape); - } - - template - template - inline auto xcontainer::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator - { - return iterable_base::template rbegin(shape); - } - - template - template - inline auto xcontainer::rend(const S& shape) noexcept -> reverse_broadcast_iterator - { - return iterable_base::template rend(shape); - } - - template - template - inline auto xcontainer::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template rbegin(shape); - } - - template - template - inline auto xcontainer::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template rend(shape); - } - - template - template - inline auto xcontainer::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template crbegin(shape); - } - - template - template - inline auto xcontainer::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template crend(shape); - } - - /*********************** - * Linear iterator api * - ***********************/ - - template - template - inline auto xcontainer::storage_begin() noexcept -> storage_iterator - { - return storage().begin(); - } - - template - template - inline auto xcontainer::storage_end() noexcept -> storage_iterator - { - return storage().end(); - } - - template - template - inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator - { - return storage().begin(); - } - - template - template - inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator - { - return storage().end(); - } - - template - template - inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator - { - return storage().cbegin(); - } - - template - template - inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator - { - return storage().cend(); - } - - template - template - inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator - { - return storage().rbegin(); - } - - template - template - inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator - { - return storage().rend(); - } - - template - template - inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator - { - return storage().rbegin(); - } - - template - template - inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator - { - return storage().rend(); - } - - template - template - inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator - { - return storage().crbegin(); - } - - template - template - inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator - { - return storage().crend(); - } - - /*************** - * stepper api * - ***************/ - - template - template - inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper - { - size_type offset = shape.size() - dimension(); - return stepper(static_cast(this), data_xbegin(), offset); - } - - template - template - inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper - { - size_type offset = shape.size() - dimension(); - return stepper(static_cast(this), data_xend(l), offset); - } - - template - template - inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper - { - size_type offset = shape.size() - dimension(); - return const_stepper(static_cast(this), data_xbegin(), offset); - } - - template - template - inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper - { - size_type offset = shape.size() - dimension(); - return const_stepper(static_cast(this), data_xend(l), offset); - } - - template - inline auto xcontainer::data_xbegin() noexcept -> container_iterator - { - return storage().begin(); - } - - template - inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator - { - return storage().begin(); - } - - template - inline auto xcontainer::data_xend(layout_type l) noexcept -> container_iterator - { - return data_xend_impl(storage().end(), l); - } - - template - inline auto xcontainer::data_xend(layout_type l) const noexcept -> const_container_iterator - { - return data_xend_impl(storage().end(), l); - } - - template - inline auto xcontainer::derived_cast() & noexcept -> derived_type& - { - return *static_cast(this); - } - template inline auto xcontainer::derived_cast() const & noexcept -> const derived_type& { @@ -1224,20 +643,160 @@ namespace xt return storage()[i]; } + /*************** + * stepper api * + ***************/ + + template + template + inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xend(l, offset), offset); + } + + template + template + inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xend(l, offset), offset); + } + + template + inline auto xcontainer::data_xbegin() noexcept -> container_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator + { + return storage().cbegin(); + } + + template + inline auto xcontainer::data_xend(layout_type l, size_type offset) noexcept -> container_iterator + { + return data_xend_impl(storage().begin(), l, offset); + } + + template + inline auto xcontainer::data_xend(layout_type l, size_type offset) const noexcept -> const_container_iterator + { + return data_xend_impl(storage().cbegin(), l, offset); + } + template template inline void xcontainer::store_simd(size_type i, const simd& e) { using align_mode = driven_align_mode_t; - xsimd::store_simd(&(storage()[i]), e, align_mode()); + xt_simd::store_simd(&(storage()[i]), e, align_mode()); } template - template - inline auto xcontainer::load_simd(size_type i) const -> simd_return_type + template + inline auto xcontainer::load_simd(size_type i) const + -> container_simd_return_type_t + //-> simd_return_type { using align_mode = driven_align_mode_t; - return xsimd::load_simd(&(storage()[i]), align_mode()); + return xt_simd::load_simd(&(storage()[i]), align_mode()); + } + + template + inline auto xcontainer::storage_begin() noexcept -> storage_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::storage_end() noexcept -> storage_iterator + { + return storage().end(); + } + + template + inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator + { + return storage().cbegin(); + } + + template + inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator + { + return storage().rbegin(); + } + + template + inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator + { + return storage().rend(); + } + + template + inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().rbegin(); + } + + template + inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return storage().rend(); + } + + template + inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().crbegin(); + } + + template + inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return storage().crend(); + } + + template + inline auto xcontainer::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); } /************************************* @@ -1248,7 +807,7 @@ namespace xt inline xstrided_container::xstrided_container() noexcept : base_type() { - m_shape = xtl::make_sequence(base_type::dimension(), 1); + m_shape = xtl::make_sequence(base_type::dimension(), 0); m_strides = xtl::make_sequence(base_type::dimension(), 0); m_backstrides = xtl::make_sequence(base_type::dimension(), 0); } @@ -1261,6 +820,12 @@ namespace xt adapt_strides(m_shape, m_strides, m_backstrides); } + template + inline xstrided_container::xstrided_container(inner_shape_type&& shape, inner_strides_type&& strides, inner_backstrides_type&& backstrides, layout_type&& layout) noexcept + : base_type(), m_shape(std::move(shape)), m_strides(std::move(strides)), m_backstrides(std::move(backstrides)), m_layout(std::move(layout)) + { + } + template inline auto xstrided_container::shape_impl() noexcept -> inner_shape_type& { @@ -1325,7 +890,9 @@ namespace xt } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param force force reshaping, even if the shape stays the same (default: false) */ @@ -1333,22 +900,25 @@ namespace xt template inline void xstrided_container::resize(S&& shape, bool force) { - if (m_shape.size() != shape.size() || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) + std::size_t dim = shape.size(); + if (m_shape.size() != dim || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) { - if (m_layout == layout_type::dynamic || m_layout == layout_type::any) + if (D::static_layout == layout_type::dynamic && m_layout == layout_type::dynamic) { m_layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout } - m_shape = xtl::forward_sequence(shape); - resize_container(m_strides, m_shape.size()); - resize_container(m_backstrides, m_shape.size()); - size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, dim); + resize_container(m_backstrides, dim); + size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); detail::resize_data_container(this->storage(), data_size); } } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param l the new layout_type */ @@ -1366,6 +936,8 @@ namespace xt /** * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param strides the new strides */ @@ -1377,7 +949,7 @@ namespace xt { throw std::runtime_error("Cannot resize with custom strides when layout() is != layout_type::dynamic."); } - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); m_strides = strides; resize_container(m_backstrides, m_strides.size()); adapt_strides(m_shape, m_strides, m_backstrides); @@ -1386,7 +958,14 @@ namespace xt } /** - * Reshapes the container and keeps old elements + * Reshapes the container and keeps old elements. The `shape` argument can have one of its value + * equal to `-1`, in this case the value is inferred from the number of elements in the container + * and the remaining values in the `shape`. + * \code{.cpp} + * xt::xarray a = { 1, 2, 3, 4, 5, 6, 7, 8 }; + * a.reshape({-1, 4}); + * //a.shape() is {2, 4} + * \endcode * @param shape the new shape (has to have same number of elements as the original container) * @param layout the layout to compute the strides (defaults to static layout of the container, * or for a container with dynamic layout to XTENSOR_DEFAULT_LAYOUT) @@ -1394,24 +973,74 @@ namespace xt template template inline void xstrided_container::reshape(S&& shape, layout_type layout) + { + reshape_impl(std::forward(shape), std::is_signed::value_type>>(), std::forward(layout)); + } + + template + template + inline void xstrided_container::reshape(std::initializer_list shape, layout_type layout) + { + using sh_type = rebind_container_t; + sh_type sh = xtl::make_sequence(shape.size()); + std::copy(shape.begin(), shape.end(), sh.begin()); + reshape_impl(std::move(sh), std::is_signed(), std::forward(layout)); + } + + template + template + inline void xstrided_container::reshape_impl(S&& shape, std::false_type /* is unsigned */, layout_type layout) { if (compute_size(shape) != this->size()) { throw std::runtime_error("Cannot reshape with incorrect number of elements. Do you mean to resize?"); } - if (layout == layout_type::dynamic || layout == layout_type::any) + if (D::static_layout == layout_type::dynamic && layout == layout_type::dynamic) { layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout } - if (layout != base_type::static_layout && base_type::static_layout != layout_type::dynamic) + if (D::static_layout != layout_type::dynamic && layout != D::static_layout) { throw std::runtime_error("Cannot reshape with different layout if static layout != dynamic."); } m_layout = layout; - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); resize_container(m_strides, m_shape.size()); resize_container(m_backstrides, m_shape.size()); - compute_strides(m_shape, m_layout, m_strides, m_backstrides); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); + } + template + template + inline void xstrided_container::reshape_impl(S&& _shape, std::true_type /* is signed */, layout_type layout) + { + using value_type = typename std::decay_t::value_type; + if (this->size() % compute_size(_shape)) + { + throw std::runtime_error("Negative axis size cannot be inferred. Shape mismatch."); + } + std::decay_t shape = _shape; + value_type accumulator = 1; + std::size_t neg_idx = 0; + std::size_t i = 0; + for(auto it = shape.begin(); it != shape.end(); ++it, i++) + { + auto&& dim = *it; + if(dim < 0) + { + XTENSOR_ASSERT(dim == -1 && !neg_idx); + neg_idx = i; + } + accumulator *= dim; + } + if(accumulator < 0) + { + shape[neg_idx] = static_cast(this->size()) / std::abs(accumulator); + } + m_layout = layout; + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, m_shape.size()); + resize_container(m_backstrides, m_shape.size()); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); } } diff --git a/vendor/xtensor/include/xtensor/xcsv.hpp b/vendor/xtensor/include/xtensor/xcsv.hpp index 4a2716d40..6a98fa449 100644 --- a/vendor/xtensor/include/xtensor/xcsv.hpp +++ b/vendor/xtensor/include/xtensor/xcsv.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -29,7 +30,7 @@ namespace xt using xcsv_tensor = xtensor_container, 2, layout_type::row_major>; template > - xcsv_tensor load_csv(std::istream& stream); + xcsv_tensor load_csv(std::istream& stream, const char delimiter = ',', const std::size_t skip_rows = 0, const ptrdiff_t max_rows = -1, const std::string comments = "#"); template void dump_csv(std::ostream& stream, const xexpression& e); @@ -49,6 +50,17 @@ namespace xt return res; } + template <> + inline std::string lexical_cast(const std::string& cell) + { + size_t first = cell.find_first_not_of(' '); + if (first == std::string::npos) + return cell; + + size_t last = cell.find_last_not_of(' '); + return cell.substr(first, last==std::string::npos?cell.size():last+1); + } + template <> inline float lexical_cast(const std::string& cell) { return std::stof(cell); } @@ -77,10 +89,10 @@ namespace xt inline unsigned long long lexical_cast(const std::string& cell) { return std::stoull(cell); } template - ST load_csv_row(std::istream& row_stream, OI output, std::string cell) + ST load_csv_row(std::istream& row_stream, OI output, std::string cell, const char delimiter = ',') { ST length = 0; - while (std::getline(row_stream, cell, ',')) + while (std::getline(row_stream, cell, delimiter)) { *output++ = lexical_cast(cell); ++length; @@ -94,9 +106,13 @@ namespace xt * * Returns an \ref xexpression for the parsed CSV * @param stream the input stream containing the CSV encoded values + * @param delimiter the character used to separate values. [default: ','] + * @param skip the first skip_rows lines. [default: 0] + * @param read max_rows lines of content after skip_rows lines; the default is to read all the lines. [default: -1] + * @param comments the string used to indicate the start of a comment. [default: "#"] */ template - xcsv_tensor load_csv(std::istream& stream) + xcsv_tensor load_csv(std::istream& stream, const char delimiter, const std::size_t skip_rows, const std::ptrdiff_t max_rows, const std::string comments) { using tensor_type = xcsv_tensor; using storage_type = typename tensor_type::storage_type; @@ -106,14 +122,27 @@ namespace xt using output_iterator = std::back_insert_iterator; storage_type data; - size_type nbrow = 0, nbcol = 0; + size_type nbrow = 0, nbcol = 0, nhead = 0; { output_iterator output(data); std::string row, cell; while (std::getline(stream, row)) { + if (nhead < skip_rows) + { + ++nhead; + continue; + } + if (std::equal(comments.begin(), comments.end(), row.begin())) + { + continue; + } + if (0 < max_rows && max_rows <= static_cast(nbrow)) + { + break; + } std::stringstream row_stream(row); - nbcol = detail::load_csv_row(row_stream, output, cell); + nbcol = detail::load_csv_row(row_stream, output, cell, delimiter); ++nbrow; } } diff --git a/vendor/xtensor/include/xtensor/xdynamic_view.hpp b/vendor/xtensor/include/xtensor/xdynamic_view.hpp new file mode 100644 index 000000000..345cb1420 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xdynamic_view.hpp @@ -0,0 +1,704 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_DYNAMIC_VIEW_HPP +#define XTENSOR_DYNAMIC_VIEW_HPP + +#include +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xlayout.hpp" +#include "xsemantic.hpp" +#include "xstrided_view_base.hpp" + +namespace xt +{ + + template + class xdynamic_view; + + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using undecay_expression = CT; + using reference = inner_reference_t; + using const_reference = typename xexpression_type::const_reference; + using size_type = typename xexpression_type::size_type; + using shape_type = std::decay_t; + using undecay_shape = S; + using storage_getter = FST; + using inner_storage_type = typename storage_getter::type; + using temporary_type = xarray, xexpression_type::static_layout>; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + { + using inner_shape_type = S; + using inner_strides_type = inner_shape_type; + using inner_backstrides_type = inner_shape_type; + +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 8 + constexpr static auto random_instantiation_var_for_gcc8_data_iface = has_data_interface>::value; + constexpr static auto random_instantiation_var_for_gcc8_has_strides = has_strides>::value; +#endif + + // TODO: implement efficient stepper specific to the dynamic_view + using const_stepper = xindexed_stepper, true>; + using stepper = xindexed_stepper, false>; + }; + + /**************************** + * xdynamic_view extensions * + ****************************/ + + namespace extension + { + template + struct xdynamic_view_base_impl; + + template + struct xdynamic_view_base_impl + { + using type = xtensor_empty_base; + }; + + template + struct xdynamic_view_base + : xdynamic_view_base_impl, CT, S, L, FST> + { + }; + + template + using xdynamic_view_base_t = typename xdynamic_view_base::type; + } + + /***************** + * xdynamic_view * + *****************/ + + namespace detail + { + template + class xfake_slice; + } + + template > + class xdynamic_view : public xview_semantic>, + public xiterable>, + public extension::xdynamic_view_base_t, + private xstrided_view_base> + { + public: + + using self_type = xdynamic_view; + using base_type = xstrided_view_base; + using semantic_base = xview_semantic; + using extension_base = extension::xdynamic_view_base_t; + using expression_tag = typename extension_base::expression_tag; + + using xexpression_type = typename base_type::xexpression_type; + using base_type::is_const; + + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using size_type = typename base_type::size_type; + using difference_type = typename base_type::difference_type; + + using inner_storage_type = typename base_type::inner_storage_type; + using storage_type = typename base_type::storage_type; + + using iterable_base = xiterable; + using inner_shape_type = typename iterable_base::inner_shape_type; + using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; + + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + using base_type::static_layout; + using base_type::contiguous_layout; + + using temporary_type = typename xcontainer_inner_types::temporary_type; + using base_index_type = xindex_type_t; + + using simd_value_type = typename base_type::simd_value_type; + using bool_load_type = typename base_type::bool_load_type; + + using strides_vt = typename strides_type::value_type; + using slice_type = xtl::variant, xkeep_slice, xdrop_slice>; + using slice_vector_type = std::vector; + + template + xdynamic_view(CTA&& e, SA&& shape, get_strides_t&& strides, std::size_t offset, layout_type layout, + slice_vector_type&& slices, get_strides_t&& adj_strides) noexcept; + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& operator=(const E& e); + + using base_type::size; + using base_type::dimension; + using base_type::shape; + using base_type::layout; + + // Explicitly deleting strides method to avoid compilers complaining + // about not being able to call the strides method from xstrided_view_base + // private base + const inner_strides_type& strides() const noexcept = delete; + + reference operator()(); + const_reference operator()() const; + + template + reference operator()(Args... args); + + template + const_reference operator()(Args... args) const; + + template + reference unchecked(Args... args); + + template + const_reference unchecked(Args... args) const; + + using base_type::operator[]; + using base_type::at; + using base_type::periodic; + using base_type::in_bounds; + + template + reference element(It first, It last); + + template + const_reference element(It first, It last) const; + + size_type data_offset() const noexcept; + + // Explicitly deleting data methods so has_data_interface results + // to false instead of having compilers complaining about not being + // able to call the methods from the private base + value_type* data() noexcept = delete; + const value_type* data() const noexcept = delete; + + using base_type::storage; + using base_type::expression; + using base_type::broadcast_shape; + + template + bool has_linear_assign(const O& str) const noexcept; + + template + void fill(const T& value); + + template + stepper stepper_begin(const ST& shape); + template + stepper stepper_end(const ST& shape, layout_type l); + + template + const_stepper stepper_begin(const ST& shape) const; + template + const_stepper stepper_end(const ST& shape, layout_type l) const; + + using container_iterator = std::conditional_t; + using const_container_iterator = typename storage_type::const_iterator; + + template + using rebind_t = xdynamic_view>; + + template + rebind_t build_view(E&& e) const; + + private: + + using offset_type = typename base_type::offset_type; + + slice_vector_type m_slices; + inner_strides_type m_adj_strides; + + container_iterator data_xbegin() noexcept; + const_container_iterator data_xbegin() const noexcept; + container_iterator data_xend(layout_type l, size_type offset) noexcept; + const_container_iterator data_xend(layout_type l, size_type offset) const noexcept; + + template + It data_xbegin_impl(It begin) const noexcept; + + template + It data_xend_impl(It end, layout_type l, size_type offset) const noexcept; + + void assign_temporary_impl(temporary_type&& tmp); + + template + offset_type adjust_offset(offset_type offset, T idx, Args... args) const noexcept; + offset_type adjust_offset(offset_type offset) const noexcept; + + template + offset_type adjust_offset_impl(offset_type offset, size_type idx_offset, T idx, Args... args) const noexcept; + offset_type adjust_offset_impl(offset_type offset, size_type idx_offset) const noexcept; + + template + offset_type adjust_element_offset(offset_type offset, It first, It last) const noexcept; + + template + friend class xstepper; + friend class xview_semantic; + friend class xaccessible; + friend class xconst_accessible; + }; + + /************************** + * xdynamic_view builders * + **************************/ + + template + using xdynamic_slice = xtl::variant< + T, + + xrange_adaptor, + xrange_adaptor, + xrange_adaptor, + + xrange_adaptor, + xrange_adaptor, + xrange_adaptor, + + xrange_adaptor, + xrange_adaptor, + + xrange, + xstepped_range, + + xkeep_slice, + xdrop_slice, + + xall_tag, + xellipsis_tag, + xnewaxis_tag + >; + + using xdynamic_slice_vector = std::vector>; + + template + auto dynamic_view(E&& e, const xdynamic_slice_vector& slices); + + /****************************** + * xfake_slice implementation * + ******************************/ + + namespace detail + { + template + class xfake_slice : public xslice> + { + public: + + using size_type = T; + using self_type = xfake_slice; + + xfake_slice() = default; + + size_type operator()(size_type /*i*/) const noexcept + { + return size_type(0); + } + + size_type size() const noexcept + { + return size_type(1); + } + + size_type step_size() const noexcept + { + return size_type(0); + } + + size_type step_size(std::size_t /*i*/, std::size_t /*n*/ = 1) const noexcept + { + return size_type(0); + } + + size_type revert_index(std::size_t i) const noexcept + { + return i; + } + + bool contains(size_type /*i*/) const noexcept + { + return true; + } + + bool operator==(const self_type& /*rhs*/) const noexcept + { + return true; + } + + bool operator!=(const self_type& /*rhs*/) const noexcept + { + return false; + } + }; + } + + /******************************** + * xdynamic_view implementation * + ********************************/ + + template + template + inline xdynamic_view::xdynamic_view(CTA&& e, SA&& shape, get_strides_t&& strides, + std::size_t offset, layout_type layout, + slice_vector_type&& slices, get_strides_t&& adj_strides) noexcept + : base_type(std::forward(e), std::forward(shape), std::move(strides), offset, layout), + m_slices(std::move(slices)), m_adj_strides(std::move(adj_strides)) + { + } + + template + template + inline auto xdynamic_view::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + + template + template + inline auto xdynamic_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(this->begin(), this->end(), e); + return *this; + } + + template + inline auto xdynamic_view::operator()() -> reference + { + return base_type::storage()[data_offset()]; + } + + template + inline auto xdynamic_view::operator()() const -> const_reference + { + return base_type::storage()[data_offset()]; + } + + template + template + inline auto xdynamic_view::operator()(Args... args) -> reference + { + XTENSOR_TRY(check_index(base_type::shape(), args...)); + XTENSOR_CHECK_DIMENSION(base_type::shape(), args...); + offset_type offset = base_type::compute_index(args...); + offset = adjust_offset(offset, args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(base_type::shape(), args...)); + XTENSOR_CHECK_DIMENSION(base_type::shape(), args...); + offset_type offset = base_type::compute_index(args...); + offset = adjust_offset(offset, args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline bool xdynamic_view::has_linear_assign(const O&) const noexcept + { + return false; + } + + template + template + inline auto xdynamic_view::unchecked(Args... args) -> reference + { + offset_type offset = base_type::compute_unchecked_index(args...); + offset = adjust_offset(args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::unchecked(Args... args) const -> const_reference + { + offset_type offset = base_type::compute_unchecked_index(args...); + offset = adjust_offset(args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::element(It first, It last) -> reference + { + XTENSOR_TRY(check_element_index(base_type::shape(), first, last)); + offset_type offset = base_type::compute_element_index(first, last); + offset = adjust_element_offset(offset, first, last); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::element(It first, It last) const -> const_reference + { + XTENSOR_TRY(check_element_index(base_type::shape(), first, last)); + offset_type offset = base_type::compute_element_index(first, last); + offset = adjust_element_offset(offset, first, last); + return base_type::storage()[static_cast(offset)]; + } + + template + inline auto xdynamic_view::data_offset() const noexcept -> size_type + { + size_type offset = base_type::data_offset(); + size_type sl_offset = xtl::visit([](const auto& sl) { return sl(size_type(0)); }, m_slices[0]); + return offset + sl_offset * m_adj_strides[0]; + } + + template + template + inline void xdynamic_view::fill(const T& value) + { + return std::fill(this->storage_begin(), this->storage_end(), value); + } + + template + template + inline auto xdynamic_view::stepper_begin(const ST& shape) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset); + } + + template + template + inline auto xdynamic_view::stepper_end(const ST& shape, layout_type /*l*/) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset, true); + } + + template + template + inline auto xdynamic_view::stepper_begin(const ST& shape) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xdynamic_view::stepper_end(const ST& shape, layout_type /*l*/) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset, true); + } + + template + template + inline auto xdynamic_view::build_view(E&& e) const -> rebind_t + { + inner_shape_type sh(this->shape()); + inner_strides_type str(base_type::strides()); + slice_vector_type svt(m_slices); + inner_strides_type adj_str(m_adj_strides); + return rebind_t(std::forward(e), std::move(sh), std::move(str), + base_type::data_offset(), this->layout(), std::move(svt), std::move(adj_str)); + } + + template + inline auto xdynamic_view::data_xbegin() noexcept -> container_iterator + { + return data_xbegin_impl(this->storage().begin()); + } + + template + inline auto xdynamic_view::data_xbegin() const noexcept -> const_container_iterator + { + return data_xbegin_impl(this->storage().cbegin()); + } + + template + inline auto xdynamic_view::data_xend(layout_type l, size_type offset) noexcept -> container_iterator + { + return data_xend_impl(this->storage().begin(), l, offset); + } + + template + inline auto xdynamic_view::data_xend(layout_type l, size_type offset) const noexcept -> const_container_iterator + { + return data_xend_impl(this->storage().cbegin(), l, offset); + } + + template + template + inline It xdynamic_view::data_xbegin_impl(It begin) const noexcept + { + return begin + static_cast(data_offset()); + } + + // TODO: fix the data_xend implementation and assign_temporary_impl + + template + template + inline It xdynamic_view::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept + { + return strided_data_end(*this, begin + std::ptrdiff_t(data_offset()), l, offset); + } + + template + inline void xdynamic_view::assign_temporary_impl(temporary_type&& tmp) + { + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); + } + + template + template + inline auto xdynamic_view::adjust_offset(offset_type offset, T idx, Args... args) const noexcept -> offset_type + { + constexpr size_type nb_args = sizeof...(Args) + 1; + size_type dim = base_type::dimension(); + offset_type res = nb_args > dim ? adjust_offset(offset, args...) : adjust_offset_impl(offset, dim - nb_args, idx, args...); + return res; + } + + template + inline auto xdynamic_view::adjust_offset(offset_type offset) const noexcept -> offset_type + { + return offset; + } + + template + template + inline auto xdynamic_view::adjust_offset_impl(offset_type offset, size_type idx_offset, T idx, Args... args) const noexcept + -> offset_type + { + offset_type sl_offset = xtl::visit([idx](const auto& sl) { + using type = typename std::decay_t::size_type; + return sl(type(idx)); + }, m_slices[idx_offset]); + offset_type res = offset + sl_offset * m_adj_strides[idx_offset]; + return adjust_offset_impl(res, idx_offset + 1, args...); + } + + template + inline auto xdynamic_view::adjust_offset_impl(offset_type offset, size_type) const noexcept + -> offset_type + { + return offset; + } + + template + template + inline auto xdynamic_view::adjust_element_offset(offset_type offset, It first, It last) const noexcept -> offset_type + { + auto dst = std::distance(first, last); + offset_type dim = static_cast(dimension()); + offset_type loop_offset = dst < dim ? dim - dst : offset_type(0); + offset_type idx_offset = dim < dst ? dst - dim : offset_type(0); + offset_type res = offset; + for (offset_type i = loop_offset; i < dim; ++i, ++first) + { + offset_type j = static_cast(first[idx_offset]); + offset_type sl_offset = xtl::visit([j](const auto& sl) { return static_cast(sl(j)); }, m_slices[static_cast(i)]); + res += sl_offset * m_adj_strides[static_cast(i)]; + } + return res; + } + + /***************************************** + * xdynamic_view builders implementation * + *****************************************/ + + namespace detail + { + template + struct adj_strides_policy + { + using slice_vector = V; + using strides_type = dynamic_shape; + + slice_vector new_slices; + strides_type new_adj_strides; + + protected: + + inline void resize(std::size_t size) + { + new_slices.resize(size); + new_adj_strides.resize(size); + } + + inline void set_fake_slice(std::size_t idx) + { + new_slices[idx] = xfake_slice(); + new_adj_strides[idx] = std::ptrdiff_t(0); + } + + template + bool fill_args(const xdynamic_slice_vector& slices, std::size_t sl_idx, + std::size_t i, std::size_t old_shape, + const ST& old_stride, + S& shape, get_strides_t& strides) + { + return fill_args_impl>(slices, sl_idx, i, old_shape, old_stride, shape, strides) + || fill_args_impl>(slices, sl_idx, i, old_shape, old_stride, shape, strides); + } + + template + bool fill_args_impl(const xdynamic_slice_vector& slices, std::size_t sl_idx, + std::size_t i, std::size_t old_shape, + const ST& old_stride, + S& shape, get_strides_t& strides) + { + auto* sl = xtl::get_if(&slices[sl_idx]); + if (sl != nullptr) + { + new_slices[i] = *sl; + auto& ns = xtl::get(new_slices[i]); + ns.normalize(old_shape); + shape[i] = static_cast(ns.size()); + strides[i] = std::ptrdiff_t(0); + new_adj_strides[i] = static_cast(old_stride); + } + return sl != nullptr; + } + }; + } + + template + inline auto dynamic_view(E&& e, const xdynamic_slice_vector& slices) + { + using view_type = xdynamic_view, dynamic_shape>; + using slice_vector = typename view_type::slice_vector_type; + using policy = detail::adj_strides_policy; + detail::strided_view_args args; + args.fill_args(e.shape(), detail::get_strides(e), detail::get_offset(e), e.layout(), slices); + return view_type(std::forward(e), std::move(args.new_shape), std::move(args.new_strides), args.new_offset, + args.new_layout, std::move(args.new_slices), std::move(args.new_adj_strides)); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xeval.hpp b/vendor/xtensor/include/xtensor/xeval.hpp index 18d53beea..04fc5fd26 100644 --- a/vendor/xtensor/include/xtensor/xeval.hpp +++ b/vendor/xtensor/include/xtensor/xeval.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -10,6 +11,7 @@ #define XTENSOR_EVAL_HPP #include "xtensor_forward.hpp" +#include "xshape.hpp" namespace xt { @@ -40,17 +42,25 @@ namespace xt /// @cond DOXYGEN_INCLUDE_SFINAE template > inline auto eval(T&& t) - -> std::enable_if_t::value && detail::is_array::value, xtensor::value>> + -> std::enable_if_t::value && detail::is_array::value && !detail::is_fixed::value, xtensor::value>> { return xtensor::value>(std::forward(t)); } template > inline auto eval(T&& t) - -> std::enable_if_t::value && !detail::is_array::value, xt::xarray> + -> std::enable_if_t::value && !detail::is_array::value && !detail::is_fixed::value, xt::xarray> { return xarray(std::forward(t)); } + + template > + inline auto eval(T&& t) + -> std::enable_if_t::value && detail::is_fixed::value && !detail::is_array::value, + xt::xtensor_fixed> + { + return xtensor_fixed(std::forward(t)); + } /// @endcond } diff --git a/vendor/xtensor/include/xtensor/xexception.hpp b/vendor/xtensor/include/xtensor/xexception.hpp index 689ce31e0..4daa90be5 100644 --- a/vendor/xtensor/include/xtensor/xexception.hpp +++ b/vendor/xtensor/include/xtensor/xexception.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -34,10 +35,49 @@ namespace xt template [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs); + /********************* + * concatenate_error * + *********************/ + + class concatenate_error : public std::runtime_error + { + public: + + explicit concatenate_error(const char* msg) + : std::runtime_error(msg) + { + } + }; + + template + [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs); + /********************************** * broadcast_error implementation * **********************************/ + namespace detail + { + template + inline std::string shape_error_message(const S1& lhs, const S2& rhs) + { + std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate); + + buf << "\n LHS shape = ("; + using size_type1 = typename S1::value_type; + std::ostream_iterator iter1(buf, ", "); + std::copy(lhs.cbegin(), lhs.cend(), iter1); + + buf << ")\n RHS shape = ("; + using size_type2 = typename S2::value_type; + std::ostream_iterator iter2(buf, ", "); + std::copy(rhs.cbegin(), rhs.cend(), iter2); + buf << ")"; + + return buf.str(); + } + } + #ifdef NDEBUG // Do not inline this function template @@ -49,20 +89,28 @@ namespace xt template [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs) { - std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate); + std::string msg = detail::shape_error_message(lhs, rhs); + throw broadcast_error(msg.c_str()); + } +#endif - buf << "\n LHS shape = ("; - using size_type1 = typename S1::value_type; - std::ostream_iterator iter1(buf, ", "); - std::copy(lhs.cbegin(), lhs.cend(), iter1); + /************************************ + * concatenate_error implementation * + ************************************/ - buf << ")\n RHS shape = ("; - using size_type2 = typename S2::value_type; - std::ostream_iterator iter2(buf, ", "); - std::copy(rhs.cbegin(), rhs.cend(), iter2); - buf << ")"; - - throw broadcast_error(buf.str().c_str()); +#ifdef NDEBUG + // Do not inline this function + template + [[noreturn]] void throw_concatenate_error(const S1&, const S2&) + { + throw concatenate_error("Incompatible dimension of arrays, compile in DEBUG for more info"); + } +#else + template + [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs) + { + std::string msg = detail::shape_error_message(lhs, rhs); + throw concatenate_error(msg.c_str()); } #endif @@ -97,8 +145,8 @@ namespace xt { } - template - inline void check_index_impl(const S& shape, std::size_t arg, Args... args) + template + inline void check_index_impl(const S& shape, T arg, Args... args) { if (sizeof...(Args) + 1 > shape.size()) { @@ -106,7 +154,7 @@ namespace xt } else { - if (arg >= std::size_t(shape[dim]) && shape[dim] != 1) + if (std::size_t(arg) >= std::size_t(shape[dim]) && shape[dim] != 1) { throw std::out_of_range("index " + std::to_string(arg) + " is out of bounds for axis " + std::to_string(dim) + " with size " + std::to_string(shape[dim])); @@ -127,17 +175,33 @@ namespace xt inline void check_element_index(const S& shape, It first, It last) { using value_type = typename std::iterator_traits::value_type; - auto dst = static_cast(last - first); + using size_type = typename S::size_type; + auto dst = static_cast(last - first); It efirst = last - static_cast((std::min)(shape.size(), dst)); std::size_t axis = 0; - while (efirst != last) + + if(shape.empty()) { - if (*efirst >= value_type(shape[axis]) && shape[axis] != 1) + if(first != last && *(--last) != value_type(0)) { - throw std::out_of_range("index " + std::to_string(*efirst) + " is out of bounds for axis " - + std::to_string(axis) + " with size " + std::to_string(shape[axis])); + throw std::out_of_range("index out of bound (empty array)"); + } + else + { + return; + } + } + else + { + while (efirst != last) + { + if (*efirst >= value_type(shape[axis]) && shape[axis] != 1) + { + throw std::out_of_range("index " + std::to_string(*efirst) + " is out of bounds for axis " + + std::to_string(axis) + " with size " + std::to_string(shape[axis])); + } + ++efirst, ++axis; } - ++efirst, ++axis; } } diff --git a/vendor/xtensor/include/xtensor/xexpression.hpp b/vendor/xtensor/include/xtensor/xexpression.hpp index a83ea0c58..caf914d58 100644 --- a/vendor/xtensor/include/xtensor/xexpression.hpp +++ b/vendor/xtensor/include/xtensor/xexpression.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -14,9 +15,12 @@ #include #include +#include #include +#include "xlayout.hpp" #include "xshape.hpp" +#include "xtensor_forward.hpp" #include "xutils.hpp" namespace xt @@ -61,6 +65,43 @@ namespace xt xexpression& operator=(xexpression&&) = default; }; + /************************************ + * xsharable_expression declaration * + ************************************/ + + template + class xshared_expression; + + template + class xsharable_expression; + + namespace detail + { + template + xshared_expression make_xshared_impl(xsharable_expression&&); + } + + template + class xsharable_expression : public xexpression + { + protected: + + xsharable_expression(); + ~xsharable_expression() = default; + + xsharable_expression(const xsharable_expression&) = default; + xsharable_expression& operator=(const xsharable_expression&) = default; + + xsharable_expression(xsharable_expression&&) = default; + xsharable_expression& operator=(xsharable_expression&&) = default; + + private: + + std::shared_ptr p_shared; + + friend xshared_expression detail::make_xshared_impl(xsharable_expression&&); + }; + /****************************** * xexpression implementation * ******************************/ @@ -97,21 +138,41 @@ namespace xt } //@} - namespace detail - { - template - struct is_xexpression_impl : std::is_base_of>, std::decay_t> - { - }; + /*************************************** + * xsharable_expression implementation * + ***************************************/ - template - struct is_xexpression_impl> : std::true_type - { - }; + template + inline xsharable_expression::xsharable_expression() + : p_shared(nullptr) + { } + /** + * is_crtp_base_of + * Resembles std::is_base_of, but adresses the problem of whether _some_ instantiation + * of a CRTP templated class B is a base of class E. A CRTP templated class is correctly + * templated with the most derived type in the CRTP hierarchy. Using this assumption, + * this implementation deals with either CRTP final classes (checks for inheritance + * with E as the CRTP parameter of B) or CRTP base classes (which are singly templated + * by the most derived class, and that's pulled out to use as a templete parameter for B). + */ + + namespace detail + { + template