Merge pull request #1042 from paulromano/cpp-nucdata

Move many nuclear data-related classes to C++
This commit is contained in:
Sterling Harper 2018-08-15 14:52:41 -04:00 committed by GitHub
commit 0ff0568a10
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
151 changed files with 50272 additions and 2113 deletions

View file

@ -1,16 +1,18 @@
sudo: required
dist: trusty
dist: xenial
language: python
python:
- "3.4"
- "3.5"
- "3.6"
- "3.7"
addons:
apt:
packages:
- gfortran
- mpich
- libmpich-dev
- gfortran
- mpich
- libmpich-dev
- libhdf5-serial-dev
- libhdf5-mpich-dev
cache:
directories:
- $HOME/nndc_hdf5
@ -31,10 +33,6 @@ env:
- OMP=y MPI=n PHDF5=n
- OMP=n MPI=y PHDF5=n
- OMP=n MPI=y PHDF5=y
before_install:
- sudo add-apt-repository ppa:nschloe/hdf5-backports -y
- sudo apt-get update -q
- sudo apt-get install libhdf5-serial-dev libhdf5-mpich-dev -y
install:
- ./tools/ci/travis-install.sh
before_script:

View file

@ -84,8 +84,8 @@ if(CMAKE_Fortran_COMPILER_ID STREQUAL GNU)
# Make sure version is sufficient
execute_process(COMMAND ${CMAKE_Fortran_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
if(GCC_VERSION VERSION_LESS 4.8)
message(FATAL_ERROR "gfortran version must be 4.8 or higher")
if(GCC_VERSION VERSION_LESS 4.9)
message(FATAL_ERROR "gcc version must be 4.9 or higher")
endif()
# GCC compiler options
@ -210,7 +210,7 @@ elseif(CMAKE_C_COMPILER_ID MATCHES Clang)
endif()
list(APPEND cxxflags -std=c++11 -O2)
list(APPEND cxxflags -std=c++14 -O2)
if(debug)
list(REMOVE_ITEM cxxflags -O2)
list(APPEND cxxflags -g -O0)
@ -236,6 +236,14 @@ message(STATUS "Linker flags: ${ldflags}")
add_library(pugixml vendor/pugixml/pugixml.cpp)
target_include_directories(pugixml PUBLIC vendor/pugixml/)
#===============================================================================
# xtensor header-only library
#===============================================================================
add_subdirectory(vendor/xtl)
add_subdirectory(vendor/xtensor)
target_link_libraries(xtensor INTERFACE xtl)
#===============================================================================
# RPATH information
#===============================================================================
@ -280,7 +288,6 @@ set_target_properties(faddeeva PROPERTIES
add_library(libopenmc SHARED
src/algorithm.F90
src/angle_distribution.F90
src/angleenergy_header.F90
src/bank_header.F90
src/api.F90
@ -298,7 +305,6 @@ add_library(libopenmc SHARED
src/eigenvalue.F90
src/endf.F90
src/endf_header.F90
src/energy_distribution.F90
src/error.F90
src/geometry.F90
src/geometry_header.F90
@ -326,7 +332,6 @@ add_library(libopenmc SHARED
src/physics_mg.F90
src/plot.F90
src/plot_header.F90
src/product_header.F90
src/progress_header.F90
src/pugixml/pugixml_f.F90
src/random_lcg.F90
@ -334,9 +339,6 @@ add_library(libopenmc SHARED
src/relaxng
src/sab_header.F90
src/secondary_correlated.F90
src/secondary_kalbach.F90
src/secondary_nbody.F90
src/secondary_uncorrelated.F90
src/set_header.F90
src/settings.F90
src/simulation_header.F90
@ -384,6 +386,12 @@ add_library(libopenmc SHARED
src/tallies/trigger.F90
src/tallies/trigger_header.F90
src/cell.cpp
src/distribution.cpp
src/distribution_angle.cpp
src/distribution_energy.cpp
src/distribution_multi.cpp
src/distribution_spatial.cpp
src/endf.cpp
src/initialize.cpp
src/finalize.cpp
src/geometry_aux.cpp
@ -398,6 +406,12 @@ add_library(libopenmc SHARED
src/position.cpp
src/pugixml/pugixml_c.cpp
src/random_lcg.cpp
src/reaction.cpp
src/reaction_product.cpp
src/secondary_correlated.cpp
src/secondary_kalbach.cpp
src/secondary_nbody.cpp
src/secondary_uncorrelated.cpp
src/scattdata.cpp
src/settings.cpp
src/simulation.cpp
@ -450,7 +464,7 @@ endif()
# target_link_libraries treats any arguments starting with - but not -l as
# linker flags. Thus, we can pass both linker flags and libraries together.
target_link_libraries(libopenmc ${ldflags} ${HDF5_LIBRARIES} pugixml
faddeeva)
faddeeva xtensor)
#===============================================================================
# openmc executable

View file

@ -174,9 +174,7 @@ Follow the `C++ Core Guidelines`_ except when they conflict with another
guideline listed here. For convenience, many important guidelines from that
list are repeated here.
Conform to the C++11 standard. Note that this is a significant difference
between our style and the C++ Core Guidelines. Many suggestions in those
Guidelines require C++14.
Conform to the C++14 standard.
Always use C++-style comments (``//``) as opposed to C-style (``/**/``). (It
is more difficult to comment out a large section of code that uses C-style

View file

@ -1,130 +0,0 @@
module angle_distribution
use algorithm, only: binary_search
use constants, only: ZERO, ONE, HISTOGRAM, LINEAR_LINEAR
use distribution_univariate, only: DistributionContainer, Tabular
use hdf5_interface, only: read_attribute, get_shape, read_dataset, &
open_dataset, close_dataset, HID_T, HSIZE_T
use random_lcg, only: prn
implicit none
private
!===============================================================================
! ANGLEDISTRIBUTION represents an angular distribution that is to be used in an
! uncorrelated angle-energy distribution. This occurs whenever the angle
! distrbution is given in File 4 in an ENDF file. The distribution of angles
! depends on the incoming energy of the neutron, so this type stores a
! distribution for each of a set of incoming energies.
!===============================================================================
type, public :: AngleDistribution
real(8), allocatable :: energy(:)
type(DistributionContainer), allocatable :: distribution(:)
contains
procedure :: sample => angle_sample
procedure :: from_hdf5 => angle_from_hdf5
end type AngleDistribution
contains
function angle_sample(this, E) result(mu)
class(AngleDistribution), intent(in) :: this
real(8), intent(in) :: E ! incoming energy
real(8) :: mu ! sampled cosine of scattering angle
integer :: i ! index on incoming energy grid
integer :: n ! number of incoming energies
real(8) :: r ! interpolation factor on incoming energy grid
! Determine number of incoming energies
n = size(this%energy)
! Find energy bin and calculate interpolation factor -- if the energy is
! outside the range of the tabulated energies, choose the first or last bins
if (E < this%energy(1)) then
i = 1
r = ZERO
elseif (E > this%energy(n)) then
i = n - 1
r = ONE
else
i = binary_search(this%energy, n, E)
r = (E - this%energy(i))/(this%energy(i+1) - this%energy(i))
end if
! Sample between the ith and (i+1)th bin
if (r > prn()) i = i + 1
! Sample i-th distribution
mu = this%distribution(i)%obj%sample()
! Make sure mu is in range [-1,1]
if (abs(mu) > ONE) mu = sign(ONE, mu)
end function angle_sample
subroutine angle_from_hdf5(this, group_id)
class(AngleDistribution), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer :: i, j
integer :: n
integer :: n_energy
integer(HID_T) :: dset_id
integer(HSIZE_T) :: dims(1), dims2(2)
integer, allocatable :: offsets(:)
integer, allocatable :: interp(:)
real(8), allocatable :: temp(:,:)
! Get incoming energies
dset_id = open_dataset(group_id, 'energy')
call get_shape(dset_id, dims)
n_energy = int(dims(1), 4)
allocate(this % energy(n_energy))
allocate(this % distribution(n_energy))
call read_dataset(this % energy, dset_id)
call close_dataset(dset_id)
! Get outgoing energy distribution data
dset_id = open_dataset(group_id, 'mu')
call read_attribute(offsets, dset_id, 'offsets')
call read_attribute(interp, dset_id, 'interpolation')
call get_shape(dset_id, dims2)
allocate(temp(dims2(1), dims2(2)))
call read_dataset(temp, dset_id)
call close_dataset(dset_id)
do i = 1, n_energy
! Determine number of outgoing energies
j = offsets(i)
if (i < n_energy) then
n = offsets(i+1) - j
else
n = size(temp, 1) - j
end if
! Create and initialize tabular distribution
allocate(Tabular :: this % distribution(i) % obj)
select type (mudist => this % distribution(i) % obj)
type is (Tabular)
mudist % interpolation = interp(i)
allocate(mudist % x(n), mudist % p(n), mudist % c(n))
mudist % x(:) = temp(j+1:j+n, 1)
mudist % p(:) = temp(j+1:j+n, 2)
! To get answers that match ACE data, for now we still use the tabulated
! CDF values that were passed through to the HDF5 library. At a later
! time, we can remove the CDF values from the HDF5 library and
! reconstruct them using the PDF
if (.true.) then
mudist % c(:) = temp(j+1:j+n, 3)
else
call mudist % initialize(temp(j+1:j+n, 1), temp(j+1:j+n, 2), interp(i))
end if
end select
j = j + n
end do
end subroutine angle_from_hdf5
end module angle_distribution

21
src/angle_energy.h Normal file
View file

@ -0,0 +1,21 @@
#ifndef OPENMC_ANGLE_ENERGY_H
#define OPENMC_ANGLE_ENERGY_H
namespace openmc {
//==============================================================================
//! Abstract type that defines a correlated or uncorrelated angle-energy
//! distribution that is a function of incoming energy. Each derived type must
//! implement a sample() method that returns an outgoing energy and
//! scattering cosine given an incoming energy.
//==============================================================================
class AngleEnergy {
public:
virtual void sample(double E_in, double& E_out, double& mu) const = 0;
virtual ~AngleEnergy() = default;
};
}
#endif // OPENMC_ANGLE_ENERGY_H

View file

@ -1,7 +1,6 @@
#include "cell.h"
#include <cmath>
#include <limits>
#include <sstream>
#include <string>
@ -19,14 +18,13 @@ namespace openmc {
// Constants
//==============================================================================
// TODO: Convert to enum
constexpr int32_t OP_LEFT_PAREN {std::numeric_limits<int32_t>::max()};
constexpr int32_t OP_RIGHT_PAREN {std::numeric_limits<int32_t>::max() - 1};
constexpr int32_t OP_COMPLEMENT {std::numeric_limits<int32_t>::max() - 2};
constexpr int32_t OP_INTERSECTION {std::numeric_limits<int32_t>::max() - 3};
constexpr int32_t OP_UNION {std::numeric_limits<int32_t>::max() - 4};
extern "C" double FP_PRECISION;
//==============================================================================
// Global variables
//==============================================================================

View file

@ -2,6 +2,7 @@
#define OPENMC_CELL_H
#include <cstdint>
#include <limits>
#include <string>
#include <unordered_map>
#include <vector>
@ -18,6 +19,7 @@ namespace openmc {
// Constants
//==============================================================================
// TODO: Convert to enum
extern "C" int FILL_MATERIAL;
extern "C" int FILL_UNIVERSE;
extern "C" int FILL_LATTICE;

View file

@ -131,34 +131,6 @@ module constants
! Void material
integer, parameter :: MATERIAL_VOID = -1
! Lattice types
integer, parameter :: &
LATTICE_RECT = 1, & ! Rectangular lattice
LATTICE_HEX = 2 ! Hexagonal lattice
! Lattice boundary crossings
integer, parameter :: &
LATTICE_LEFT = 1, & ! Flag for crossing left (x) lattice boundary
LATTICE_RIGHT = 2, & ! Flag for crossing right (x) lattice boundary
LATTICE_BACK = 3, & ! Flag for crossing back (y) lattice boundary
LATTICE_FRONT = 4, & ! Flag for crossing front (y) lattice boundary
LATTICE_BOTTOM = 5, & ! Flag for crossing bottom (z) lattice boundary
LATTICE_TOP = 6 ! Flag for crossing top (z) lattice boundary
! Surface types
integer, parameter :: &
SURF_PX = 1, & ! Plane parallel to x-plane
SURF_PY = 2, & ! Plane parallel to y-plane
SURF_PZ = 3, & ! Plane parallel to z-plane
SURF_PLANE = 4, & ! Arbitrary plane
SURF_CYL_X = 5, & ! Cylinder along x-axis
SURF_CYL_Y = 6, & ! Cylinder along y-axis
SURF_CYL_Z = 7, & ! Cylinder along z-axis
SURF_SPHERE = 8, & ! Sphere
SURF_CONE_X = 9, & ! Cone parallel to x-axis
SURF_CONE_Y = 10, & ! Cone parallel to y-axis
SURF_CONE_Z = 11 ! Cone parallel to z-axis
! Flag to say that the outside of a lattice is not defined
integer, parameter :: NO_OUTER_UNIVERSE = -1
@ -238,12 +210,6 @@ module constants
! Depletion reactions
integer, parameter :: DEPLETION_RX(6) = [N_GAMMA, N_P, N_A, N_2N, N_3N, N_4N]
! ACE table types
integer, parameter :: &
ACE_NEUTRON = 1, & ! continuous-energy neutron
ACE_THERMAL = 2, & ! thermal S(a,b) scattering data
ACE_DOSIMETRY = 3 ! dosimetry cross sections
! MGXS Table Types
integer, parameter :: &
MGXS_ISOTROPIC = 1, & ! Isotropically Weighted Data
@ -265,11 +231,6 @@ module constants
EMISSION_DELAYED = 2, & ! Delayed emission of secondary particle
EMISSION_TOTAL = 3 ! Yield represents total emission (prompt + delayed)
! Cross section filetypes
integer, parameter :: &
ASCII = 1, & ! ASCII cross section file
BINARY = 2 ! Binary cross section file
! Library types
integer, parameter :: &
LIBRARY_NEUTRON = 1, &
@ -350,9 +311,6 @@ module constants
SCORE_FISS_Q_RECOV = -15, & ! recoverable fission Q-value
SCORE_DECAY_RATE = -16 ! delayed neutron precursor decay rate
! Maximum scattering order supported
integer, parameter :: MAX_ANG_ORDER = 10
! Tally map bin finding
integer, parameter :: NO_BIN_FOUND = -1

View file

@ -1,8 +1,8 @@
//! \file constants.h
//! A collection of constants
#ifndef CONSTANTS_H
#define CONSTANTS_H
#ifndef OPENMC_CONSTANTS_H
#define OPENMC_CONSTANTS_H
#include <cmath>
#include <array>
@ -11,6 +11,7 @@
namespace openmc {
// TODO: Replace with xtensor/other library?
typedef std::vector<double> double_1dvec;
typedef std::vector<std::vector<double> > double_2dvec;
typedef std::vector<std::vector<std::vector<double> > > double_3dvec;
@ -21,29 +22,283 @@ typedef std::vector<int> int_1dvec;
typedef std::vector<std::vector<int> > int_2dvec;
typedef std::vector<std::vector<std::vector<int> > > int_3dvec;
constexpr int MAX_SAMPLE {10000};
// ============================================================================
// VERSIONING NUMBERS
constexpr std::array<int, 3> VERSION {0, 10, 0};
// OpenMC major, minor, and release numbers
constexpr int VERSION_MAJOR {0};
constexpr int VERSION_MINOR {10};
constexpr int VERSION_RELEASE {0};
constexpr std::array<int, 3> VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE};
// HDF5 data format
constexpr int HDF5_VERSION[] {1, 0};
// Version numbers for binary files
constexpr std::array<int, 2> VERSION_PARTICLE_RESTART {2, 0};
constexpr std::array<int, 2> VERSION_TRACK {2, 0};
constexpr std::array<int, 2> VERSION_SUMMARY {6, 0};
constexpr std::array<int, 2> VERSION_VOLUME {1, 0};
constexpr std::array<int, 2> VERSION_VOXEL {1, 0};
constexpr std::array<int, 2> VERSION_MGXS_LIBRARY {1, 0};
constexpr char VERSION_MULTIPOLE[] {"v0.2"};
// ============================================================================
// ADJUSTABLE PARAMETERS
// NOTE: This is the only section of the constants module that should ever be
// adjusted. Modifying constants in other sections may cause the code to fail.
// Monoatomic ideal-gas scattering treatment threshold
constexpr double FREE_GAS_THRESHOLD {400.0};
// Significance level for confidence intervals
constexpr double CONFIDENCE_LEVEL {0.95};
// Used for surface current tallies
constexpr double TINY_BIT {1e-8};
// User for precision in geometry
constexpr double FP_PRECISION {1e-14};
constexpr double FP_REL_PRECISION {1e-5};
constexpr double FP_COINCIDENT {1e-12};
// Maximum number of collisions/crossings
constexpr int MAX_EVENTS {1000000};
constexpr int MAX_SAMPLE {100000};
// Maximum number of words in a single line, length of line, and length of
// single word
constexpr int MAX_WORDS {500};
constexpr int MAX_LINE_LEN {250};
constexpr int MAX_WORD_LEN {150};
constexpr int MAX_FILE_LEN {255};
// Physical Constants
constexpr double K_BOLTZMANN {8.6173303e-5}; // Boltzmann constant in eV/K
// Maximum number of external source spatial resamples to encounter before an
// error is thrown.
constexpr int EXTSRC_REJECT_THRESHOLD {10000};
constexpr double EXTSRC_REJECT_FRACTION {0.05};
// ============================================================================
// MATH AND PHYSICAL CONSTANTS
// Values here are from the Committee on Data for Science and Technology
// (CODATA) 2014 recommendation (doi:10.1103/RevModPhys.88.035009).
// TODO: cmath::M_PI has 3 more digits precision than the Fortran constant we
// use so for now we will reuse the Fortran constant until we are OK with
// modifying test results
constexpr double PI {3.1415926535898};
const double SQRT_PI {std::sqrt(PI)};
constexpr double INFTY {std::numeric_limits<double>::max()};
// Physical constants
constexpr double MASS_NEUTRON {1.00866491588}; // mass of a neutron in amu
constexpr double MASS_NEUTRON_EV {939.5654133e6}; // mass of a neutron in eV/c^2
constexpr double MASS_PROTON {1.007276466879}; // mass of a proton in amu
constexpr double MASS_ELECTRON_EV {0.5109989461e6}; // electron mass energy equivalent in eV/c^2
constexpr double FINE_STRUCTURE {137.035999139}; // inverse fine structure constant
constexpr double PLANCK_C {1.2398419739062977e4}; // Planck's constant times c in eV-Angstroms
constexpr double AMU {1.660539040e-27}; // 1 amu in kg
constexpr double C_LIGHT {2.99792458e8}; // speed of light in m/s
constexpr double N_AVOGADRO {0.6022140857}; // Avogadro's number in 10^24/mol
constexpr double K_BOLTZMANN {8.6173303e-5}; // Boltzmann constant in eV/K
// Electron subshell labels
constexpr char SUBSHELLS[][4] {
"K ", "L1 ", "L2 ", "L3 ", "M1 ", "M2 ", "M3 ", "M4 ", "M5 ",
"N1 ", "N2 ", "N3 ", "N4 ", "N5 ", "N6 ", "N7 ", "O1 ", "O2 ",
"O3 ", "O4 ", "O5 ", "O6 ", "O7 ", "O8 ", "O9 ", "P1 ", "P2 ",
"P3 ", "P4 ", "P5 ", "P6 ", "P7 ", "P8 ", "P9 ", "P10", "P11",
"Q1 ", "Q2 ", "Q3 "
};
// Void material
// TODO: refactor and remove
constexpr int MATERIAL_VOID {-1};
// ============================================================================
// CROSS SECTION RELATED CONSTANTS
// Angular distribution type
// TODO: Convert to enum
constexpr int ANGLE_ISOTROPIC {1};
constexpr int ANGLE_32_EQUI {2};
constexpr int ANGLE_TABULAR {3};
constexpr int ANGLE_LEGENDRE {4};
constexpr int ANGLE_HISTOGRAM {5};
// Temperature treatment method
// TODO: Convert to enum?
constexpr int TEMPERATURE_NEAREST {1};
constexpr int TEMPERATURE_INTERPOLATION {2};
// Secondary energy mode for S(a,b) inelastic scattering
// TODO: Convert to enum
constexpr int SAB_SECONDARY_EQUAL {0}; // Equally-likely outgoing energy bins
constexpr int SAB_SECONDARY_SKEWED {1}; // Skewed outgoing energy bins
constexpr int SAB_SECONDARY_CONT {2}; // Continuous, linear-linear interpolation
// Elastic mode for S(a,b) elastic scattering
// TODO: Convert to enum
constexpr int SAB_ELASTIC_DISCRETE {3}; // Sample from discrete cosines
constexpr int SAB_ELASTIC_EXACT {4}; // Exact treatment for coherent elastic
// Reaction types
// TODO: Convert to enum
constexpr int TOTAL_XS {1};
constexpr int ELASTIC {2};
constexpr int N_NONELASTIC {3};
constexpr int N_LEVEL {4};
constexpr int MISC {5};
constexpr int N_2ND {11};
constexpr int N_2N {16};
constexpr int N_3N {17};
constexpr int N_FISSION {18};
constexpr int N_F {19};
constexpr int N_NF {20};
constexpr int N_2NF {21};
constexpr int N_NA {22};
constexpr int N_N3A {23};
constexpr int N_2NA {24};
constexpr int N_3NA {25};
constexpr int N_NP {28};
constexpr int N_N2A {29};
constexpr int N_2N2A {30};
constexpr int N_ND {32};
constexpr int N_NT {33};
constexpr int N_N3HE {34};
constexpr int N_ND2A {35};
constexpr int N_NT2A {36};
constexpr int N_4N {37};
constexpr int N_3NF {38};
constexpr int N_2NP {41};
constexpr int N_3NP {42};
constexpr int N_N2P {44};
constexpr int N_NPA {45};
constexpr int N_N1 {51};
constexpr int N_N40 {90};
constexpr int N_NC {91};
constexpr int N_DISAPPEAR {101};
constexpr int N_GAMMA {102};
constexpr int N_P {103};
constexpr int N_D {104};
constexpr int N_T {105};
constexpr int N_3HE {106};
constexpr int N_A {107};
constexpr int N_2A {108};
constexpr int N_3A {109};
constexpr int N_2P {111};
constexpr int N_PA {112};
constexpr int N_T2A {113};
constexpr int N_D2A {114};
constexpr int N_PD {115};
constexpr int N_PT {116};
constexpr int N_DA {117};
constexpr int N_5N {152};
constexpr int N_6N {153};
constexpr int N_2NT {154};
constexpr int N_TA {155};
constexpr int N_4NP {156};
constexpr int N_3ND {157};
constexpr int N_NDA {158};
constexpr int N_2NPA {159};
constexpr int N_7N {160};
constexpr int N_8N {161};
constexpr int N_5NP {162};
constexpr int N_6NP {163};
constexpr int N_7NP {164};
constexpr int N_4NA {165};
constexpr int N_5NA {166};
constexpr int N_6NA {167};
constexpr int N_7NA {168};
constexpr int N_4ND {169};
constexpr int N_5ND {170};
constexpr int N_6ND {171};
constexpr int N_3NT {172};
constexpr int N_4NT {173};
constexpr int N_5NT {174};
constexpr int N_6NT {175};
constexpr int N_2N3HE {176};
constexpr int N_3N3HE {177};
constexpr int N_4N3HE {178};
constexpr int N_3N2P {179};
constexpr int N_3N3A {180};
constexpr int N_3NPA {181};
constexpr int N_DT {182};
constexpr int N_NPD {183};
constexpr int N_NPT {184};
constexpr int N_NDT {185};
constexpr int N_NP3HE {186};
constexpr int N_ND3HE {187};
constexpr int N_NT3HE {188};
constexpr int N_NTA {189};
constexpr int N_2N2P {190};
constexpr int N_P3HE {191};
constexpr int N_D3HE {192};
constexpr int N_3HEA {193};
constexpr int N_4N2P {194};
constexpr int N_4N2A {195};
constexpr int N_4NPA {196};
constexpr int N_3P {197};
constexpr int N_N3P {198};
constexpr int N_3N2PA {199};
constexpr int N_5N2P {200};
constexpr int COHERENT {502};
constexpr int INCOHERENT {504};
constexpr int PAIR_PROD_ELEC {515};
constexpr int PAIR_PROD {516};
constexpr int PAIR_PROD_NUC {517};
constexpr int PHOTOELECTRIC {522};
constexpr int N_P0 {600};
constexpr int N_PC {649};
constexpr int N_D0 {650};
constexpr int N_DC {699};
constexpr int N_T0 {700};
constexpr int N_TC {749};
constexpr int N_3HE0 {750};
constexpr int N_3HEC {799};
constexpr int N_A0 {800};
constexpr int N_AC {849};
constexpr int N_2N0 {875};
constexpr int N_2NC {891};
// Fission neutron emission (nu) type
constexpr int NU_NONE {0}; // No nu values (non-fissionable)
constexpr int NU_POLYNOMIAL {1}; // Nu values given by polynomial
constexpr int NU_TABULAR {2}; // Nu values given by tabular distribution
// Library types
constexpr int LIBRARY_NEUTRON {1};
constexpr int LIBRARY_THERMAL {2};
constexpr int LIBRARY_PHOTON {3};
constexpr int LIBRARY_MULTIGROUP {4};
// Probability table parameters
constexpr int URR_CUM_PROB {1};
constexpr int URR_TOTAL {2};
constexpr int URR_ELASTIC {3};
constexpr int URR_FISSION {4};
constexpr int URR_N_GAMMA {5};
constexpr int URR_HEATING {6};
// Maximum number of partial fission reactions
constexpr int PARTIAL_FISSION_MAX {4};
// Resonance elastic scattering methods
// TODO: Convert to enum
constexpr int RES_SCAT_ARES {1};
constexpr int RES_SCAT_DBRC {2};
constexpr int RES_SCAT_WCM {3};
constexpr int RES_SCAT_CXS {4};
// Electron treatments
// TODO: Convert to enum
constexpr int ELECTRON_LED {1}; // Local Energy Deposition
constexpr int ELECTRON_TTB {2}; // Thick Target Bremsstrahlung
// ============================================================================
// MULTIGROUP RELATED
// MGXS Table Types
// TODO: Convert to enum
constexpr int MGXS_ISOTROPIC {1}; // Isotroically weighted data
constexpr int MGXS_ANGLE {2}; // Data by angular bins
@ -53,18 +308,8 @@ constexpr double MACROSCOPIC_AWR {-2.};
// Number of mu bins to use when converting Legendres to tabular type
constexpr int DEFAULT_NMU {33};
// Temperature treatment method
constexpr int TEMPERATURE_NEAREST {1};
constexpr int TEMPERATURE_INTERPOLATION {2};
// TODO: cmath::M_PI has 3 more digits precision than the Fortran constant we
// use so for now we will reuse the Fortran constant until we are OK with
// modifying test results
constexpr double PI {3.1415926535898};
const double SQRT_PI {std::sqrt(PI)};
// Mgxs::get_xs enumerated types
// TODO: Convert to enum
constexpr int MG_GET_XS_TOTAL {0};
constexpr int MG_GET_XS_ABSORPTION {1};
constexpr int MG_GET_XS_INVERSE_VELOCITY {2};
@ -81,11 +326,120 @@ constexpr int MG_GET_XS_NU_FISSION {12};
constexpr int MG_GET_XS_CHI_PROMPT {13};
constexpr int MG_GET_XS_CHI_DELAYED {14};
extern "C" double FP_COINCIDENT;
extern "C" double FP_PRECISION;
constexpr double INFTY {std::numeric_limits<double>::max()};
// ============================================================================
// TALLY-RELATED CONSTANTS
// Tally result entries
constexpr int RESULT_VALUE {1};
constexpr int RESULT_SUM {2};
constexpr int RESULT_SUM_SQ {3};
// Tally type
// TODO: Convert to enum
constexpr int TALLY_VOLUME {1};
constexpr int TALLY_MESH_SURFACE {2};
constexpr int TALLY_SURFACE {3};
// Tally estimator types
// TODO: Convert to enum
constexpr int ESTIMATOR_ANALOG {1};
constexpr int ESTIMATOR_TRACKLENGTH {2};
constexpr int ESTIMATOR_COLLISION {3};
// Event types for tallies
// TODO: Convert to enum
constexpr int EVENT_SURFACE {-2};
constexpr int EVENT_LATTICE {-1};
constexpr int EVENT_SCATTER {1};
constexpr int EVENT_ABSORB {2};
// Tally score type -- if you change these, make sure you also update the
// _SCORES dictionary in openmc/capi/tally.py
// TODO: Convert to enum
constexpr int SCORE_FLUX {-1}; // flux
constexpr int SCORE_TOTAL {-2}; // total reaction rate
constexpr int SCORE_SCATTER {-3}; // scattering rate
constexpr int SCORE_NU_SCATTER {-4}; // scattering production rate
constexpr int SCORE_ABSORPTION {-5}; // absorption rate
constexpr int SCORE_FISSION {-6}; // fission rate
constexpr int SCORE_NU_FISSION {-7}; // neutron production rate
constexpr int SCORE_KAPPA_FISSION {-8}; // fission energy production rate
constexpr int SCORE_CURRENT {-9}; // current
constexpr int SCORE_EVENTS {-10}; // number of events
constexpr int SCORE_DELAYED_NU_FISSION {-11}; // delayed neutron production rate
constexpr int SCORE_PROMPT_NU_FISSION {-12}; // prompt neutron production rate
constexpr int SCORE_INVERSE_VELOCITY {-13}; // flux-weighted inverse velocity
constexpr int SCORE_FISS_Q_PROMPT {-14}; // prompt fission Q-value
constexpr int SCORE_FISS_Q_RECOV {-15}; // recoverable fission Q-value
constexpr int SCORE_DECAY_RATE {-16}; // delayed neutron precursor decay rate
// Tally map bin finding
constexpr int NO_BIN_FOUND {-1};
// Tally filter and map types
// TODO: Refactor to remove or convert to enum
constexpr int FILTER_UNIVERSE {1};
constexpr int FILTER_MATERIAL {2};
constexpr int FILTER_CELL {3};
constexpr int FILTER_CELLBORN {4};
constexpr int FILTER_SURFACE {5};
constexpr int FILTER_MESH {6};
constexpr int FILTER_ENERGYIN {7};
constexpr int FILTER_ENERGYOUT {8};
constexpr int FILTER_DISTRIBCELL {9};
constexpr int FILTER_MU {10};
constexpr int FILTER_POLAR {11};
constexpr int FILTER_AZIMUTHAL {12};
constexpr int FILTER_DELAYEDGROUP {13};
constexpr int FILTER_ENERGYFUNCTION {14};
constexpr int FILTER_CELLFROM {15};
constexpr int FILTER_MESHSURFACE {16};
constexpr int FILTER_LEGENDRE {17};
constexpr int FILTER_SPH_HARMONICS {18};
constexpr int FILTER_SPTL_LEGENDRE {19};
constexpr int FILTER_ZERNIKE {20};
constexpr int FILTER_PARTICLE {21};
// Mesh types
constexpr int MESH_REGULAR {1};
// Tally surface current directions
constexpr int OUT_LEFT {1}; // x min
constexpr int IN_LEFT {2}; // x min
constexpr int OUT_RIGHT {3}; // x max
constexpr int IN_RIGHT {4}; // x max
constexpr int OUT_BACK {5}; // y min
constexpr int IN_BACK {6}; // y min
constexpr int OUT_FRONT {7}; // y max
constexpr int IN_FRONT {8}; // y max
constexpr int OUT_BOTTOM {9}; // z min
constexpr int IN_BOTTOM {10}; // z min
constexpr int OUT_TOP {11}; // z max
constexpr int IN_TOP {12}; // z max
// Tally trigger types and threshold
constexpr int VARIANCE {1};
constexpr int RELATIVE_ERROR {2};
constexpr int STANDARD_DEVIATION {3};
// Global tally parameters
constexpr int K_COLLISION {1};
constexpr int K_ABSORPTION {2};
constexpr int K_TRACKLENGTH {3};
constexpr int LEAKAGE {4};
// Differential tally independent variables
constexpr int DIFF_DENSITY {1};
constexpr int DIFF_NUCLIDE_DENSITY {2};
constexpr int DIFF_TEMPERATURE {3};
constexpr int C_NONE {-1};
// Interpolation rules
enum class Interpolation {
histogram, lin_lin, lin_log, log_lin, log_log
};
} // namespace openmc
#endif // CONSTANTS_H
#endif // OPENMC_CONSTANTS_H

266
src/distribution.cpp Normal file
View file

@ -0,0 +1,266 @@
#include "distribution.h"
#include <algorithm> // for copy
#include <cmath> // for sqrt, floor, max
#include <iterator> // for back_inserter
#include <numeric> // for accumulate
#include <string> // for string, stod
#include "error.h"
#include "math_functions.h"
#include "random_lcg.h"
#include "xml_interface.h"
namespace openmc {
//==============================================================================
// Discrete implementation
//==============================================================================
Discrete::Discrete(pugi::xml_node node)
{
auto params = get_node_array<double>(node, "parameters");
std::size_t n = params.size();
std::copy(params.begin(), params.begin() + n/2, std::back_inserter(x_));
std::copy(params.begin() + n/2, params.end(), std::back_inserter(p_));
normalize();
}
Discrete::Discrete(const double* x, const double* p, int n)
: x_{x, x+n}, p_{p, p+n}
{
normalize();
}
double Discrete::sample() const
{
int n = x_.size();
if (n > 1) {
double xi = prn();
double c = 0.0;
for (int i = 0; i < n; ++i) {
c += p_[i];
if (xi < c) return x_[i];
}
// throw exception?
} else {
return x_[0];
}
}
void Discrete::normalize()
{
// Renormalize density function so that it sums to unity
double norm = std::accumulate(p_.begin(), p_.end(), 0.0);
for (auto& p_i : p_)
p_i /= norm;
}
//==============================================================================
// Uniform implementation
//==============================================================================
Uniform::Uniform(pugi::xml_node node)
{
auto params = get_node_array<double>(node, "parameters");
if (params.size() != 2)
openmc::fatal_error("Uniform distribution must have two "
"parameters specified.");
a_ = params.at(0);
b_ = params.at(1);
}
double Uniform::sample() const
{
return a_ + prn()*(b_ - a_);
}
//==============================================================================
// Maxwell implementation
//==============================================================================
Maxwell::Maxwell(pugi::xml_node node)
{
theta_ = std::stod(get_node_value(node, "parameters"));
}
double Maxwell::sample() const
{
return maxwell_spectrum_c(theta_);
}
//==============================================================================
// Watt implementation
//==============================================================================
Watt::Watt(pugi::xml_node node)
{
auto params = get_node_array<double>(node, "parameters");
if (params.size() != 2)
openmc::fatal_error("Watt energy distribution must have two "
"parameters specified.");
a_ = params.at(0);
b_ = params.at(1);
}
double Watt::sample() const
{
return watt_spectrum_c(a_, b_);
}
//==============================================================================
// Tabular implementation
//==============================================================================
Tabular::Tabular(pugi::xml_node node)
{
if (check_for_node(node, "interpolation")) {
std::string temp = get_node_value(node, "interpolation");
if (temp == "histogram") {
interp_ = Interpolation::histogram;
} else if (temp == "linear-linear") {
interp_ = Interpolation::lin_lin;
} else {
openmc::fatal_error("Unknown interpolation type for distribution: " + temp);
}
} else {
interp_ = Interpolation::histogram;
}
// Read and initialize tabular distribution
auto params = get_node_array<double>(node, "parameters");
std::size_t n = params.size() / 2;
const double* x = params.data();
const double* p = x + n;
init(x, p, n);
}
Tabular::Tabular(const double* x, const double* p, int n, Interpolation interp, const double* c)
: interp_{interp}
{
init(x, p, n, c);
}
void Tabular::init(const double* x, const double* p, std::size_t n, const double* c)
{
// Copy x/p arrays into vectors
std::copy(x, x + n, std::back_inserter(x_));
std::copy(p, p + n, std::back_inserter(p_));
// Check interpolation parameter
if (interp_ != Interpolation::histogram &&
interp_ != Interpolation::lin_lin) {
openmc::fatal_error("Only histogram and linear-linear interpolation "
"for tabular distribution is supported.");
}
// Calculate cumulative distribution function
if (c) {
std::copy(c, c + n, std::back_inserter(c_));
} else {
c_.resize(n);
c_[0] = 0.0;
for (int i = 1; i < n; ++i) {
if (interp_ == Interpolation::histogram) {
c_[i] = c_[i-1] + p_[i-1]*(x_[i] - x_[i-1]);
} else if (interp_ == Interpolation::lin_lin) {
c_[i] = c_[i-1] + 0.5*(p_[i-1] + p_[i]) * (x_[i] - x_[i-1]);
}
}
}
// Normalize density and distribution functions
for (int i = 0; i < n; ++i) {
p_[i] = p_[i]/c_[n-1];
c_[i] = c_[i]/c_[n-1];
}
}
double Tabular::sample() const
{
// Sample value of CDF
double c = prn();
// Find first CDF bin which is above the sampled value
double c_i = c_[0];
int i;
std::size_t n = c_.size();
for (i = 0; i < n - 1; ++i) {
if (c <= c_[i+1]) break;
c_i = c_[i+1];
}
// Determine bounding PDF values
double x_i = x_[i];
double p_i = p_[i];
if (interp_ == Interpolation::histogram) {
// Histogram interpolation
if (p_i > 0.0) {
return x_i + (c - c_i)/p_i;
} else {
return x_i;
}
} else {
// Linear-linear interpolation
double x_i1 = x_[i + 1];
double p_i1 = p_[i + 1];
double m = (p_i1 - p_i)/(x_i1 - x_i);
if (m == 0.0) {
return x_i + (c - c_i)/p_i;
} else {
return x_i + (std::sqrt(std::max(0.0, p_i*p_i + 2*m*(c - c_i))) - p_i)/m;
}
}
}
//==============================================================================
// Equiprobable implementation
//==============================================================================
double Equiprobable::sample() const
{
std::size_t n = x_.size();
double r = prn();
int i = std::floor((n - 1)*r);
double xl = x_[i];
double xr = x_[i+i];
return xl + ((n - 1)*r - i) * (xr - xl);
}
//==============================================================================
// Helper function
//==============================================================================
UPtrDist distribution_from_xml(pugi::xml_node node)
{
if (!check_for_node(node, "type"))
openmc::fatal_error("Distribution type must be specified.");
// Determine type of distribution
std::string type = get_node_value(node, "type", true, true);
// Allocate extension of Distribution
if (type == "uniform") {
return UPtrDist{new Uniform(node)};
} else if (type == "maxwell") {
return UPtrDist{new Maxwell(node)};
} else if (type == "watt") {
return UPtrDist{new Watt(node)};
} else if (type == "discrete") {
return UPtrDist{new Discrete(node)};
} else if (type == "tabular") {
return UPtrDist{new Tabular(node)};
} else {
openmc::fatal_error("Invalid distribution type: " + type);
}
}
} // namespace openmc

150
src/distribution.h Normal file
View file

@ -0,0 +1,150 @@
//! \file distribution.h
//! Univariate probability distributions
#ifndef OPENMC_DISTRIBUTION_H
#define OPENMC_DISTRIBUTION_H
#include <cstddef> // for size_t
#include <memory> // for unique_ptr
#include <vector> // for vector
#include "pugixml.hpp"
#include "constants.h"
namespace openmc {
//==============================================================================
//! Abstract class representing a univariate probability distribution
//==============================================================================
class Distribution {
public:
virtual ~Distribution() = default;
virtual double sample() const = 0;
};
//==============================================================================
//! A discrete distribution (probability mass function)
//==============================================================================
class Discrete : public Distribution {
public:
explicit Discrete(pugi::xml_node node);
Discrete(const double* x, const double* p, int n);
//! Sample a value from the distribution
//! \return Sampled value
double sample() const;
private:
std::vector<double> x_; //!< Possible outcomes
std::vector<double> p_; //!< Probability of each outcome
//! Normalize distribution so that probabilities sum to unity
void normalize();
};
//==============================================================================
//! Uniform distribution over the interval [a,b]
//==============================================================================
class Uniform : public Distribution {
public:
explicit Uniform(pugi::xml_node node);
Uniform(double a, double b) : a_{a}, b_{b} {};
//! Sample a value from the distribution
//! \return Sampled value
double sample() const;
private:
double a_; //!< Lower bound of distribution
double b_; //!< Upper bound of distribution
};
//==============================================================================
//! Maxwellian distribution of form c*E*exp(-E/theta)
//==============================================================================
class Maxwell : public Distribution {
public:
explicit Maxwell(pugi::xml_node node);
Maxwell(double theta) : theta_{theta} { };
//! Sample a value from the distribution
//! \return Sampled value
double sample() const;
private:
double theta_; //!< Factor in exponential [eV]
};
//==============================================================================
//! Watt fission spectrum with form c*exp(-E/a)*sinh(sqrt(b*E))
//==============================================================================
class Watt : public Distribution {
public:
explicit Watt(pugi::xml_node node);
Watt(double a, double b) : a_{a}, b_{b} { };
//! Sample a value from the distribution
//! \return Sampled value
double sample() const;
private:
double a_; //!< Factor in exponential [eV]
double b_; //!< Factor in square root [1/eV]
};
//==============================================================================
//! Histogram or linear-linear interpolated tabular distribution
//==============================================================================
class Tabular : public Distribution {
public:
explicit Tabular(pugi::xml_node node);
Tabular(const double* x, const double* p, int n, Interpolation interp,
const double* c=nullptr);
//! Sample a value from the distribution
//! \return Sampled value
double sample() const;
private:
std::vector<double> x_; //!< tabulated independent variable
std::vector<double> p_; //!< tabulated probability density
std::vector<double> c_; //!< cumulative distribution at tabulated values
Interpolation interp_; //!< interpolation rule
//! Initialize tabulated probability density function
//! \param x Array of values for independent variable
//! \param p Array of tabulated probabilities
//! \param n Number of tabulated values
void init(const double* x, const double* p, std::size_t n,
const double* c=nullptr);
};
//==============================================================================
//! Equiprobable distribution
//==============================================================================
class Equiprobable : public Distribution {
public:
explicit Equiprobable(pugi::xml_node node);
Equiprobable(const double* x, int n) : x_{x, x+n} { };
//! Sample a value from the distribution
//! \return Sampled value
double sample() const;
private:
std::vector<double> x_; //! Possible outcomes
};
using UPtrDist = std::unique_ptr<Distribution>;
//! Return univariate probability distribution specified in XML file
//! \param[in] node XML node representing distribution
//! \return Unique pointer to distribution
UPtrDist distribution_from_xml(pugi::xml_node node);
} // namespace openmc
#endif // OPENMC_DISTRIBUTION_H

View file

@ -0,0 +1,95 @@
#include "distribution_angle.h"
#include <cmath> // for abs, copysign
#include <vector> // for vector
#include "endf.h"
#include "hdf5_interface.h"
#include "random_lcg.h"
#include "search.h"
#include "xtensor/xarray.hpp"
#include "xtensor/xview.hpp"
namespace openmc {
//==============================================================================
// AngleDistribution implementation
//==============================================================================
AngleDistribution::AngleDistribution(hid_t group)
{
// Get incoming energies
read_dataset(group, "energy", energy_);
int n_energy = energy_.size();
// Get outgoing energy distribution data
std::vector<int> offsets;
std::vector<int> interp;
hid_t dset = open_dataset(group, "mu");
read_attribute(dset, "offsets", offsets);
read_attribute(dset, "interpolation", interp);
xt::xarray<double> temp;
read_dataset(dset, temp);
close_dataset(dset);
for (int i = 0; i < n_energy; ++i) {
// Determine number of outgoing energies
int j = offsets[i];
int n;
if (i < n_energy - 1) {
n = offsets[i+1] - j;
} else {
n = temp.shape()[1] - j;
}
// Create and initialize tabular distribution
auto xs = xt::view(temp, 0, xt::range(j, j+n));
auto ps = xt::view(temp, 1, xt::range(j, j+n));
auto cs = xt::view(temp, 2, xt::range(j, j+n));
std::vector<double> x {xs.begin(), xs.end()};
std::vector<double> p {ps.begin(), ps.end()};
std::vector<double> c {cs.begin(), cs.end()};
// To get answers that match ACE data, for now we still use the tabulated
// CDF values that were passed through to the HDF5 library. At a later
// time, we can remove the CDF values from the HDF5 library and
// reconstruct them using the PDF
Tabular* mudist = new Tabular{x.data(), p.data(), n, int2interp(interp[i]),
c.data()};
distribution_.emplace_back(mudist);
}
}
double AngleDistribution::sample(double E) const
{
// Determine number of incoming energies
auto n = energy_.size();
// Find energy bin and calculate interpolation factor -- if the energy is
// outside the range of the tabulated energies, choose the first or last bins
int i;
double r;
if (E < energy_[0]) {
i = 0;
r = 0.0;
} else if (E > energy_[n - 1]) {
i = n - 2;
r = 1.0;
} else {
i = lower_bound_index(energy_.begin(), energy_.end(), E);
r = (E - energy_[i])/(energy_[i+1] - energy_[i]);
}
// Sample between the ith and (i+1)th bin
if (r > prn()) ++i;
// Sample i-th distribution
double mu = distribution_[i]->sample();
// Make sure mu is in range [-1,1] and return
if (std::abs(mu) > 1.0) mu = std::copysign(1.0, mu);
return mu;
}
} // namespace openmc

39
src/distribution_angle.h Normal file
View file

@ -0,0 +1,39 @@
//! \file distribution_angle.h
//! Angle distribution dependent on incident particle energy
#ifndef OPENMC_DISTRIBUTION_ANGLE_H
#define OPENMC_DISTRIBUTION_ANGLE_H
#include <vector> // for vector
#include "distribution.h"
#include "hdf5.h"
namespace openmc {
//==============================================================================
//! Angle distribution that depends on incident particle energy
//==============================================================================
class AngleDistribution {
public:
AngleDistribution() = default;
explicit AngleDistribution(hid_t group);
//! Sample an angle given an incident particle energy
//! \param[in] E Particle energy in [eV]
//! \return Cosine of the angle in the range [-1,1]
double sample(double E) const;
//! Determine whether angle distribution is empty
//! \return Whether distribution is empty
bool empty() const { return energy_.empty(); }
private:
std::vector<double> energy_;
std::vector<UPtrDist> distribution_;
};
} // namespace openmc
#endif // OPENMC_DISTRIBUTION_ANGLE_H

337
src/distribution_energy.cpp Normal file
View file

@ -0,0 +1,337 @@
#include "distribution_energy.h"
#include <algorithm> // for max, min, copy, move
#include <cstddef> // for size_t
#include <iterator> // for back_inserter
#include "endf.h"
#include "hdf5_interface.h"
#include "math_functions.h"
#include "random_lcg.h"
#include "search.h"
#include "xtensor/xview.hpp"
namespace openmc {
//==============================================================================
// DiscretePhoton implementation
//==============================================================================
DiscretePhoton::DiscretePhoton(hid_t group)
{
read_attribute(group, "primary_flag", primary_flag_);
read_attribute(group, "energy", energy_);
read_attribute(group, "atomic_weight_ratio", A_);
}
double DiscretePhoton::sample(double E) const
{
if (primary_flag_ == 2) {
return energy_ + A_/(A_+ 1)*E;
} else {
return energy_;
}
}
//==============================================================================
// LevelInelastic implementation
//==============================================================================
LevelInelastic::LevelInelastic(hid_t group)
{
read_attribute(group, "threshold", threshold_);
read_attribute(group, "mass_ratio", mass_ratio_);
}
double LevelInelastic::sample(double E) const
{
return mass_ratio_*(E - threshold_);
}
//==============================================================================
// ContinuousTabular implementation
//==============================================================================
ContinuousTabular::ContinuousTabular(hid_t group)
{
// Open incoming energy dataset
hid_t dset = open_dataset(group, "energy");
// Get interpolation parameters
xt::xarray<int> temp;
read_attribute(dset, "interpolation", temp);
auto temp_b = xt::view(temp, 0); // view of breakpoints
auto temp_i = xt::view(temp, 1); // view of interpolation parameters
std::copy(temp_b.begin(), temp_b.end(), std::back_inserter(breakpoints_));
for (const auto i : temp_i)
interpolation_.push_back(int2interp(i));
n_region_ = breakpoints_.size();
// Get incoming energies
read_dataset(dset, energy_);
std::size_t n_energy = energy_.size();
close_dataset(dset);
// Get outgoing energy distribution data
dset = open_dataset(group, "distribution");
std::vector<int> offsets;
std::vector<int> interp;
std::vector<int> n_discrete;
read_attribute(dset, "offsets", offsets);
read_attribute(dset, "interpolation", interp);
read_attribute(dset, "n_discrete_lines", n_discrete);
xt::xarray<double> eout;
read_dataset(dset, eout);
close_dataset(dset);
for (int i = 0; i < n_energy; ++i) {
// Determine number of outgoing energies
int j = offsets[i];
int n;
if (i < n_energy - 1) {
n = offsets[i+1] - j;
} else {
n = eout.shape()[1] - j;
}
// Assign interpolation scheme and number of discrete lines
CTTable d;
d.interpolation = int2interp(interp[i]);
d.n_discrete = n_discrete[i];
// Copy data
d.e_out = xt::view(eout, 0, xt::range(j, j+n));
d.p = xt::view(eout, 1, xt::range(j, j+n));
// To get answers that match ACE data, for now we still use the tabulated
// CDF values that were passed through to the HDF5 library. At a later
// time, we can remove the CDF values from the HDF5 library and
// reconstruct them using the PDF
if (true) {
d.c = xt::view(eout, 2, xt::range(j, j+n));
} else {
// Calculate cumulative distribution function -- discrete portion
for (int k = 0; k < d.n_discrete; ++k) {
if (k == 0) {
d.c[k] = d.p[k];
} else {
d.c[k] = d.c[k-1] + d.p[k];
}
}
// Continuous portion
for (int k = d.n_discrete; k < n; ++k) {
if (k == d.n_discrete) {
d.c[k] = d.c[k-1] + d.p[k];
} else {
if (d.interpolation == Interpolation::histogram) {
d.c[k] = d.c[k-1] + d.p[k-1]*(d.e_out[k] - d.e_out[k-1]);
} else if (d.interpolation == Interpolation::lin_lin) {
d.c[k] = d.c[k-1] + 0.5*(d.p[k-1] + d.p[k]) *
(d.e_out[k] - d.e_out[k-1]);
}
}
}
// Normalize density and distribution functions
d.p /= d.c[n - 1];
d.c /= d.c[n - 1];
}
distribution_.push_back(std::move(d));
} // incoming energies
}
double ContinuousTabular::sample(double E) const
{
// Read number of interpolation regions and incoming energies
bool histogram_interp;
if (n_region_ == 1) {
histogram_interp = (interpolation_[0] == Interpolation::histogram);
} else {
histogram_interp = false;
}
// Find energy bin and calculate interpolation factor -- if the energy is
// outside the range of the tabulated energies, choose the first or last bins
auto n_energy_in = energy_.size();
int i;
double r;
if (E < energy_[0]) {
i = 0;
r = 0.0;
} else if (E > energy_[n_energy_in - 1]) {
i = n_energy_in - 2;
r = 1.0;
} else {
i = lower_bound_index(energy_.begin(), energy_.end(), E);
r = (E - energy_[i]) / (energy_[i+1] - energy_[i]);
}
// Sample between the ith and [i+1]th bin
int l;
if (histogram_interp) {
l = i;
} else {
l = r > prn() ? i + 1 : i;
}
// Interpolation for energy E1 and EK
int n_energy_out = distribution_[i].e_out.size();
double E_i_1 = distribution_[i].e_out[0];
double E_i_K = distribution_[i].e_out[n_energy_out - 1];
n_energy_out = distribution_[i+1].e_out.size();
double E_i1_1 = distribution_[i+1].e_out[0];
double E_i1_K = distribution_[i+1].e_out[n_energy_out - 1];
double E_1 = E_i_1 + r*(E_i1_1 - E_i_1);
double E_K = E_i_K + r*(E_i1_K - E_i_K);
// Determine outgoing energy bin
n_energy_out = distribution_[l].e_out.size();
double r1 = prn();
double c_k = distribution_[l].c[0];
double c_k1;
int k;
for (k = 0; k < n_energy_out - 2; ++k) {
c_k1 = distribution_[l].c[k+1];
if (r1 < c_k1) break;
c_k = c_k1;
}
// Check to make sure 1 <= k <= NP - 1
k = std::max(0, std::min(k, n_energy_out - 2));
double E_l_k = distribution_[l].e_out[k];
double p_l_k = distribution_[l].p[k];
double E_out;
if (distribution_[l].interpolation == Interpolation::histogram) {
// Histogram interpolation
if (p_l_k > 0.0) {
E_out = E_l_k + (r1 - c_k)/p_l_k;
} else {
E_out = E_l_k;
}
} else if (distribution_[l].interpolation == Interpolation::lin_lin) {
// Linear-linear interpolation
double E_l_k1 = distribution_[l].e_out[k+1];
double p_l_k1 = distribution_[l].p[k+1];
double frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k);
if (frac == 0.0) {
E_out = E_l_k + (r1 - c_k)/p_l_k;
} else {
E_out = E_l_k + (std::sqrt(std::max(0.0, p_l_k*p_l_k +
2.0*frac*(r1 - c_k))) - p_l_k)/frac;
}
}
// Now interpolate between incident energy bins i and i + 1
if (!histogram_interp && n_energy_out > 1) {
if (l == i) {
return E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1);
} else {
return E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1);
}
} else {
return E_out;
}
}
//==============================================================================
// MaxwellEnergy implementation
//==============================================================================
MaxwellEnergy::MaxwellEnergy(hid_t group)
{
read_attribute(group, "u", u_);
hid_t dset = open_dataset(group, "theta");
theta_ = Tabulated1D{dset};
close_dataset(dset);
}
double MaxwellEnergy::sample(double E) const
{
// Get temperature corresponding to incoming energy
double theta = theta_(E);
while (true) {
// Sample maxwell fission spectrum
double E_out = maxwell_spectrum_c(theta);
// Accept energy based on restriction energy
if (E_out <= E - u_) return E_out;
}
}
//==============================================================================
// Evaporation implementation
//==============================================================================
Evaporation::Evaporation(hid_t group)
{
read_attribute(group, "u", u_);
hid_t dset = open_dataset(group, "theta");
theta_ = Tabulated1D{dset};
close_dataset(dset);
}
double Evaporation::sample(double E) const
{
// Get temperature corresponding to incoming energy
double theta = theta_(E);
double y = (E - u_)/theta;
double v = 1.0 - std::exp(-y);
// Sample outgoing energy based on evaporation spectrum probability
// density function
double x;
while (true) {
x = -std::log((1.0 - v*prn())*(1.0 - v*prn()));
if (x <= y) break;
}
return x*theta;
}
//==============================================================================
// WattEnergy implementation
//==============================================================================
WattEnergy::WattEnergy(hid_t group)
{
// Read restriction energy
read_attribute(group, "u", u_);
// Read tabulated functions
hid_t dset = open_dataset(group, "a");
a_ = Tabulated1D{dset};
close_dataset(dset);
dset = open_dataset(group, "b");
b_ = Tabulated1D{dset};
close_dataset(dset);
}
double WattEnergy::sample(double E) const
{
// Determine Watt parameters at incident energy
double a = a_(E);
double b = b_(E);
while (true) {
// Sample energy-dependent Watt fission spectrum
double E_out = watt_spectrum_c(a, b);
// Accept energy based on restriction energy
if (E_out <= E - u_) return E_out;
}
}
}

152
src/distribution_energy.h Normal file
View file

@ -0,0 +1,152 @@
//! \file distribution_energy.h
//! Energy distributions that depend on incident particle energy
#ifndef OPENMC_DISTRIBUTION_ENERGY_H
#define OPENMC_DISTRIBUTION_ENERGY_H
#include <vector>
#include "xtensor/xtensor.hpp"
#include "hdf5.h"
#include "constants.h"
#include "endf.h"
namespace openmc {
//===============================================================================
//! Abstract class defining an energy distribution that is a function of the
//! incident energy of a projectile. Each derived type must implement a sample()
//! function that returns a sampled outgoing energy given an incoming energy
//===============================================================================
class EnergyDistribution {
public:
virtual double sample(double E) const = 0;
virtual ~EnergyDistribution() = default;
};
//===============================================================================
//! Discrete photon energy distribution
//===============================================================================
class DiscretePhoton : public EnergyDistribution {
public:
explicit DiscretePhoton(hid_t group);
//! Sample energy distribution
//! \param[in] E Incident particle energy in [eV]
//! \return Sampled energy in [eV]
double sample(double E) const;
private:
int primary_flag_; //!< Indicator of whether the photon is a primary or
//!< non-primary photon.
double energy_; //!< Photon energy or binding energy
double A_; //!< Atomic weight ratio of the target nuclide
};
//===============================================================================
//! Level inelastic scattering distribution
//===============================================================================
class LevelInelastic : public EnergyDistribution {
public:
explicit LevelInelastic(hid_t group);
//! Sample energy distribution
//! \param[in] E Incident particle energy in [eV]
//! \return Sampled energy in [eV]
double sample(double E) const;
private:
double threshold_; //!< Energy threshold in lab, (A + 1)/A * |Q|
double mass_ratio_; //!< (A/(A+1))^2
};
//===============================================================================
//! An energy distribution represented as a tabular distribution with histogram
//! or linear-linear interpolation. This corresponds to ACE law 4, which NJOY
//! produces for a number of ENDF energy distributions.
//===============================================================================
class ContinuousTabular : public EnergyDistribution {
public:
explicit ContinuousTabular(hid_t group);
//! Sample energy distribution
//! \param[in] E Incident particle energy in [eV]
//! \return Sampled energy in [eV]
double sample(double E) const;
private:
//! Outgoing energy for a single incoming energy
struct CTTable {
Interpolation interpolation; //!< Interpolation law
int n_discrete; //!< Number of of discrete energies
xt::xtensor<double, 1> e_out; //!< Outgoing energies in [eV]
xt::xtensor<double, 1> p; //!< Probability density
xt::xtensor<double, 1> c; //!< Cumulative distribution
};
int n_region_; //!< Number of inteprolation regions
std::vector<int> breakpoints_; //!< Breakpoints between regions
std::vector<Interpolation> interpolation_; //!< Interpolation laws
std::vector<double> energy_; //!< Incident energy in [eV]
std::vector<CTTable> distribution_; //!< Distributions for each incident energy
};
//===============================================================================
//! Evaporation spectrum corresponding to ACE law 9 and ENDF File 5, LF=9.
//===============================================================================
class Evaporation : public EnergyDistribution {
public:
explicit Evaporation(hid_t group);
//! Sample energy distribution
//! \param[in] E Incident particle energy in [eV]
//! \return Sampled energy in [eV]
double sample(double E) const;
private:
Tabulated1D theta_; //!< Incoming energy dependent parameter
double u_; //!< Restriction energy
};
//===============================================================================
//! Energy distribution of neutrons emitted from a Maxwell fission spectrum.
//! This corresponds to ACE law 7 and ENDF File 5, LF=7.
//===============================================================================
class MaxwellEnergy : public EnergyDistribution {
public:
explicit MaxwellEnergy(hid_t group);
//! Sample energy distribution
//! \param[in] E Incident particle energy in [eV]
//! \return Sampled energy in [eV]
double sample(double E) const;
private:
Tabulated1D theta_; //!< Incoming energy dependent parameter
double u_; //!< Restriction energy
};
//===============================================================================
//! Energy distribution of neutrons emitted from a Watt fission spectrum. This
//! corresponds to ACE law 11 and ENDF File 5, LF=11.
//===============================================================================
class WattEnergy : public EnergyDistribution {
public:
explicit WattEnergy(hid_t group);
//! Sample energy distribution
//! \param[in] E Incident particle energy in [eV]
//! \return Sampled energy in [eV]
double sample(double E) const;
private:
Tabulated1D a_; //!< Energy-dependent 'a' parameter
Tabulated1D b_; //!< Energy-dependent 'b' parameter
double u_; //!< Restriction energy
};
} // namespace openmc
#endif // OPENMC_DISTRIBUTION_ENERGY_H

View file

@ -0,0 +1,51 @@
#include "distribution_multi.h"
#include <algorithm> // for move
#include <cmath> // for sqrt, sin, cos, max
#include "constants.h"
#include "math_functions.h"
#include "random_lcg.h"
namespace openmc {
//==============================================================================
// PolarAzimuthal implementation
//==============================================================================
PolarAzimuthal::PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi) :
UnitSphereDistribution{u}, mu_{std::move(mu)}, phi_{std::move(phi)} { }
Direction PolarAzimuthal::sample() const
{
// Sample cosine of polar angle
double mu = mu_->sample();
if (mu == 1.0) return u_ref;
// Sample azimuthal angle
double phi = phi_->sample();
return rotate_angle(u_ref, mu, &phi);
}
//==============================================================================
// Isotropic implementation
//==============================================================================
Direction Isotropic::sample() const
{
double phi = 2.0*PI*prn();
double mu = 2.0*prn() - 1.0;
return {mu, std::sqrt(1.0 - mu*mu) * std::cos(phi),
std::sqrt(1.0 - mu*mu) * std::sin(phi)};
}
//==============================================================================
// Monodirectional implementation
//==============================================================================
Direction Monodirectional::sample() const
{
return u_ref;
}
} // namespace openmc

73
src/distribution_multi.h Normal file
View file

@ -0,0 +1,73 @@
#ifndef DISTRIBUTION_MULTI_H
#define DISTRIBUTION_MULTI_H
#include <memory>
#include "distribution.h"
#include "position.h"
namespace openmc {
//==============================================================================
//! Probability density function for points on the unit sphere. Extensions of
//! this type are used to sample angular distributions for starting sources
//==============================================================================
class UnitSphereDistribution {
public:
UnitSphereDistribution() { };
explicit UnitSphereDistribution(Direction u) : u_ref{u} { };
virtual ~UnitSphereDistribution() = default;
//! Sample a direction from the distribution
//! \return Direction sampled
virtual Direction sample() const = 0;
Direction u_ref {0.0, 0.0, 1.0}; //!< reference direction
};
//==============================================================================
//! Explicit distribution of polar and azimuthal angles
//==============================================================================
class PolarAzimuthal : public UnitSphereDistribution {
public:
PolarAzimuthal(Direction u, UPtrDist mu, UPtrDist phi);
//! Sample a direction from the distribution
//! \return Direction sampled
Direction sample() const;
private:
UPtrDist mu_; //!< Distribution of polar angle
UPtrDist phi_; //!< Distribution of azimuthal angle
};
//==============================================================================
//! Uniform distribution on the unit sphere
//==============================================================================
class Isotropic : public UnitSphereDistribution {
public:
Isotropic() { };
//! Sample a direction from the distribution
//! \return Sampled direction
Direction sample() const;
};
//==============================================================================
//! Monodirectional distribution
//==============================================================================
class Monodirectional : public UnitSphereDistribution {
public:
Monodirectional(Direction u) : UnitSphereDistribution{u} { };
//! Sample a direction from the distribution
//! \return Sampled direction
Direction sample() const;
};
} // namespace openmc
#endif // DISTRIBUTION_MULTI_H

View file

@ -0,0 +1,97 @@
#include "distribution_spatial.h"
#include "error.h"
#include "random_lcg.h"
#include "xml_interface.h"
namespace openmc {
//==============================================================================
// CartesianIndependent implementation
//==============================================================================
CartesianIndependent::CartesianIndependent(pugi::xml_node node)
{
// Read distribution for x coordinate
if (check_for_node(node, "x")) {
pugi::xml_node node_dist = node.child("x");
x_ = distribution_from_xml(node_dist);
} else {
// If no distribution was specified, default to a single point at x=0
double x[] {0.0};
double p[] {1.0};
x_ = UPtrDist{new Discrete{x, p, 1}};
}
// Read distribution for y coordinate
if (check_for_node(node, "y")) {
pugi::xml_node node_dist = node.child("y");
y_ = distribution_from_xml(node_dist);
} else {
// If no distribution was specified, default to a single point at y=0
double x[] {0.0};
double p[] {1.0};
y_ = UPtrDist{new Discrete{x, p, 1}};
}
// Read distribution for z coordinate
if (check_for_node(node, "z")) {
pugi::xml_node node_dist = node.child("z");
z_ = distribution_from_xml(node_dist);
} else {
// If no distribution was specified, default to a single point at z=0
double x[] {0.0};
double p[] {1.0};
z_ = UPtrDist{new Discrete{x, p, 1}};
}
}
Position CartesianIndependent::sample() const
{
return {x_->sample(), y_->sample(), z_->sample()};
}
//==============================================================================
// SpatialBox implementation
//==============================================================================
SpatialBox::SpatialBox(pugi::xml_node node)
{
// Read lower-right/upper-left coordinates
auto params = get_node_array<double>(node, "parameters");
if (params.size() != 6)
openmc::fatal_error("Box/fission spatial source must have six "
"parameters specified.");
lower_left_ = Position{params[0], params[1], params[2]};
upper_right_ = Position{params[3], params[4], params[5]};
}
Position SpatialBox::sample() const
{
Position xi {prn(), prn(), prn()};
return lower_left_ + xi*(upper_right_ - lower_left_);
}
//==============================================================================
// SpatialPoint implementation
//==============================================================================
SpatialPoint::SpatialPoint(pugi::xml_node node)
{
// Read location of point source
auto params = get_node_array<double>(node, "parameters");
if (params.size() != 3)
openmc::fatal_error("Point spatial source must have three "
"parameters specified.");
// Set position
r_ = Position{params.data()};
}
Position SpatialPoint::sample() const
{
return r_;
}
} // namespace openmc

View file

@ -0,0 +1,74 @@
#ifndef OPENMC_DISTRIBTUION_SPATIAL_H
#define OPENMC_DISTRIBUTION_SPATIAL_H
#include "pugixml.hpp"
#include "distribution.h"
#include "position.h"
namespace openmc {
//==============================================================================
//! Probability density function for points in Euclidean space
//==============================================================================
class SpatialDistribution {
public:
virtual ~SpatialDistribution() = default;
//! Sample a position from the distribution
virtual Position sample() const = 0;
};
//==============================================================================
//! Distribution of points specified by independent distributions in x,y,z
//==============================================================================
class CartesianIndependent : public SpatialDistribution {
public:
explicit CartesianIndependent(pugi::xml_node node);
//! Sample a position from the distribution
//! \return Sampled position
Position sample() const;
private:
UPtrDist x_; //!< Distribution of x coordinates
UPtrDist y_; //!< Distribution of y coordinates
UPtrDist z_; //!< Distribution of z coordinates
};
//==============================================================================
//! Uniform distribution of points over a box
//==============================================================================
class SpatialBox : public SpatialDistribution {
public:
explicit SpatialBox(pugi::xml_node node);
//! Sample a position from the distribution
//! \return Sampled position
Position sample() const;
private:
Position lower_left_; //!< Lower-left coordinates of box
Position upper_right_; //!< Upper-right coordinates of box
bool only_fissionable {false}; //!< Only accept sites in fissionable region?
};
//==============================================================================
//! Distribution at a single point
//==============================================================================
class SpatialPoint : public SpatialDistribution {
public:
explicit SpatialPoint(pugi::xml_node node);
//! Sample a position from the distribution
//! \return Sampled position
Position sample() const;
private:
Position r_; //!< Single position at which sites are generated
};
} // namespace openmc
#endif // OPENMC_DISTRIBUTION_SPATIAL_H

147
src/endf.cpp Normal file
View file

@ -0,0 +1,147 @@
#include "endf.h"
#include <algorithm> // for copy
#include <cmath> // for log, exp
#include <iterator> // for back_inserter
#include "constants.h"
#include "hdf5_interface.h"
#include "search.h"
#include "xtensor/xarray.hpp"
#include "xtensor/xview.hpp"
namespace openmc {
//==============================================================================
// Functions
//==============================================================================
Interpolation int2interp(int i)
{
switch (i) {
case 1:
return Interpolation::histogram;
case 2:
return Interpolation::lin_lin;
case 3:
return Interpolation::lin_log;
case 4:
return Interpolation::log_lin;
case 5:
return Interpolation::log_log;
}
}
bool is_fission(int mt)
{
return mt == 18 || mt == 19 || mt == 20 || mt == 21 || mt == 38;
}
//==============================================================================
// Polynomial implementation
//==============================================================================
Polynomial::Polynomial(hid_t dset)
{
// Read coefficients into a vector
read_dataset(dset, coef_);
}
double Polynomial::operator()(double x) const
{
// Use Horner's rule to evaluate polynomial. Note that coefficients are
// ordered in increasing powers of x.
double y = 0.0;
for (auto c = coef_.crbegin(); c != coef_.crend(); ++c) {
y = y*x + *c;
}
return y;
}
//==============================================================================
// Tabulated1D implementation
//==============================================================================
Tabulated1D::Tabulated1D(hid_t dset)
{
read_attribute(dset, "breakpoints", nbt_);
n_regions_ = nbt_.size();
// Change 1-indexing to 0-indexing
for (auto& b : nbt_) --b;
std::vector<int> int_temp;
read_attribute(dset, "interpolation", int_temp);
// Convert vector of ints into Interpolation
for (const auto i : int_temp)
int_.push_back(int2interp(i));
xt::xarray<double> arr;
read_dataset(dset, arr);
auto xs = xt::view(arr, 0);
auto ys = xt::view(arr, 1);
std::copy(xs.begin(), xs.end(), std::back_inserter(x_));
std::copy(ys.begin(), ys.end(), std::back_inserter(y_));
n_pairs_ = x_.size();
}
double Tabulated1D::operator()(double x) const
{
// find which bin the abscissa is in -- if the abscissa is outside the
// tabulated range, the first or last point is chosen, i.e. no interpolation
// is done outside the energy range
int i;
if (x < x_[0]) {
return y_[0];
} else if (x > x_[n_pairs_ - 1]) {
return y_[n_pairs_ - 1];
} else {
i = lower_bound_index(x_.begin(), x_.end(), x);
}
// determine interpolation scheme
Interpolation interp;
if (n_regions_ == 0) {
interp = Interpolation::lin_lin;
} else if (n_regions_ == 1) {
interp = int_[0];
} else if (n_regions_ > 1) {
for (int j = 0; j < n_regions_; ++j) {
if (i < nbt_[j]) {
interp = int_[j];
break;
}
}
}
// handle special case of histogram interpolation
if (interp == Interpolation::histogram) return y_[i];
// determine bounding values
double x0 = x_[i];
double x1 = x_[i + 1];
double y0 = y_[i];
double y1 = y_[i + 1];
// determine interpolation factor and interpolated value
double r;
switch (interp) {
case Interpolation::lin_lin:
r = (x - x0)/(x1 - x0);
return y0 + r*(y1 - y0);
case Interpolation::lin_log:
r = log(x/x0)/log(x1/x0);
return y0 + r*(y1 - y0);
case Interpolation::log_lin:
r = (x - x0)/(x1 - x0);
return y0*exp(r*log(y1/y0));
case Interpolation::log_log:
r = log(x/x0)/log(x1/x0);
return y0*exp(r*log(y1/y0));
}
}
} // namespace openmc

78
src/endf.h Normal file
View file

@ -0,0 +1,78 @@
//! \file endf.h
//! Classes and functions related to the ENDF-6 format
#ifndef OPENMC_ENDF_H
#define OPENMC_ENDF_H
#include <vector>
#include "constants.h"
#include "hdf5.h"
namespace openmc {
//! Convert integer representing interpolation law to enum
//! \param[in] i Intereger (e.g. 1=histogram, 2=lin-lin)
//! \return Corresponding enum value
Interpolation int2interp(int i);
//! Determine whether MT number corresponds to a fission reaction
//! \param[in] MT ENDF MT value
//! \return Whether corresponding reaction is a fission reaction
bool is_fission(int MT);
//==============================================================================
//! Abstract one-dimensional function
//==============================================================================
class Function1D {
public:
virtual double operator()(double x) const = 0;
};
//==============================================================================
//! One-dimensional function expressed as a polynomial
//==============================================================================
class Polynomial : public Function1D {
public:
//! Construct polynomial from HDF5 data
//! \param[in] dset Dataset containing coefficients
explicit Polynomial(hid_t dset);
//! Evaluate the polynomials
//! \param[in] x independent variable
//! \return Polynomial evaluated at x
double operator()(double x) const;
private:
std::vector<double> coef_; //!< Polynomial coefficients
};
//==============================================================================
//! One-dimensional interpolable function
//==============================================================================
class Tabulated1D : public Function1D {
public:
Tabulated1D() = default;
//! Construct function from HDF5 data
//! \param[in] dset Dataset containing tabulated data
explicit Tabulated1D(hid_t dset);
//! Evaluate the tabulated function
//! \param[in] x independent variable
//! \return Function evaluated at x
double operator()(double x) const;
private:
std::size_t n_regions_ {0}; //!< number of interpolation regions
std::vector<int> nbt_; //!< values separating interpolation regions
std::vector<Interpolation> int_; //!< interpolation schemes
std::size_t n_pairs_; //!< number of (x,y) pairs
std::vector<double> x_; //!< values of abscissa
std::vector<double> y_; //!< values of ordinate
};
} // namespace openmc
#endif // OPENMC_ENDF_H

View file

@ -1,583 +0,0 @@
module energy_distribution
use algorithm, only: binary_search
use constants, only: ZERO, ONE, HALF, TWO, PI, HISTOGRAM, LINEAR_LINEAR
use endf_header, only: Tabulated1D
use hdf5_interface
use math, only: maxwell_spectrum, watt_spectrum
use random_lcg, only: prn
!===============================================================================
! ENERGYDISTRIBUTION (abstract) defines an energy distribution that is a
! function of the incident energy of a projectile. Each derived type must
! implement a sample() function that returns a sampled outgoing energy given an
! incoming energy
!===============================================================================
type, abstract :: EnergyDistribution
contains
procedure(energy_distribution_sample_), deferred :: sample
procedure(energy_distribution_from_hdf5_), deferred :: from_hdf5
end type EnergyDistribution
abstract interface
function energy_distribution_sample_(this, E_in) result(E_out)
import EnergyDistribution
class(EnergyDistribution), intent(in) :: this
real(8), intent(in) :: E_in
real(8) :: E_out
end function energy_distribution_sample_
subroutine energy_distribution_from_hdf5_(this, group_id)
import EnergyDistribution
import HID_T
class(EnergyDistribution), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
end subroutine energy_distribution_from_hdf5_
end interface
type :: EnergyDistributionContainer
class(EnergyDistribution), allocatable :: obj
end type EnergyDistributionContainer
!===============================================================================
! Derived classes
!===============================================================================
!===============================================================================
! TABULAREQUIPROBABLE represents an energy distribution with tabular
! equiprobable energy bins as given in ACE law 1. This is an older
! representation that has largely been replaced with ACE laws 4, 44, and 61.
!===============================================================================
type, extends(EnergyDistribution) :: TabularEquiprobable
integer :: n_region ! number of interpolation regions
integer, allocatable :: breakpoints(:) ! breakpoints of interpolation regions
integer, allocatable :: interpolation(:) ! interpolation region codes
real(8), allocatable :: energy_in(:) ! incoming energies
real(8), allocatable :: energy_out(:,:) ! table of outgoing energies for
! each incoming energy
contains
procedure :: sample => equiprobable_sample
procedure :: from_hdf5 => equiprobable_from_hdf5
end type TabularEquiprobable
!===============================================================================
! DISCRETEPHOTON gives the energy distribution for a discrete photon (usually
! used for photon production from an incident-neutron reaction)
!===============================================================================
type, extends(EnergyDistribution) :: DiscretePhoton
integer :: primary_flag
real(8) :: energy
real(8) :: A
contains
procedure :: sample => discrete_photon_sample
procedure :: from_hdf5 => discrete_photon_from_hdf5
end type DiscretePhoton
!===============================================================================
! LEVELINELASTIC gives the energy distribution for level inelastic scattering by
! neutrons as in ENDF MT=51--90.
!===============================================================================
type, extends(EnergyDistribution) :: LevelInelastic
real(8) :: threshold
real(8) :: mass_ratio
contains
procedure :: sample => level_inelastic_sample
procedure :: from_hdf5 => level_inelastic_from_hdf5
end type LevelInelastic
!===============================================================================
! CONTINUOUSTABULAR gives an energy distribution represented as a tabular
! distribution with histogram or linear-linear interpolation. This corresponds
! to ACE law 4, which NJOY produces for a number of ENDF energy distributions.
!===============================================================================
type CTTable
integer :: interpolation
integer :: n_discrete
real(8), allocatable :: e_out(:)
real(8), allocatable :: p(:)
real(8), allocatable :: c(:)
end type CTTable
type, extends(EnergyDistribution) :: ContinuousTabular
integer :: n_region
integer, allocatable :: breakpoints(:)
integer, allocatable :: interpolation(:)
real(8), allocatable :: energy(:)
type(CTTable), allocatable :: distribution(:)
contains
procedure :: sample => continuous_sample
procedure :: from_hdf5 => continuous_from_hdf5
end type ContinuousTabular
!===============================================================================
! MAXWELLENERGY gives the energy distribution of neutrons emitted from a Maxwell
! fission spectrum. This corresponds to ACE law 7 and ENDF File 5, LF=7.
!===============================================================================
type, extends(EnergyDistribution) :: MaxwellEnergy
type(Tabulated1D) :: theta ! incoming-energy-dependent parameter
real(8) :: u ! restriction energy
contains
procedure :: sample => maxwellenergy_sample
procedure :: from_hdf5 => maxwellenergy_from_hdf5
end type MaxwellEnergy
!===============================================================================
! EVAPORATION represents an evaporation spectrum corresponding to ACE law 9 and
! ENDF File 5, LF=9.
!===============================================================================
type, extends(EnergyDistribution) :: Evaporation
type(Tabulated1D) :: theta
real(8) :: u
contains
procedure :: sample => evaporation_sample
procedure :: from_hdf5 => evaporation_from_hdf5
end type Evaporation
!===============================================================================
! WATTENERGY gives the energy distribution of neutrons emitted from a Watt
! fission spectrum. This corresponds to ACE law 11 and ENDF File 5, LF=11.
!===============================================================================
type, extends(EnergyDistribution) :: WattEnergy
type(Tabulated1D) :: a
type(Tabulated1D) :: b
real(8) :: u
contains
procedure :: sample => watt_sample
procedure :: from_hdf5 => watt_from_hdf5
end type WattEnergy
contains
function equiprobable_sample(this, E_in) result(E_out)
class(TabularEquiprobable), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8) :: E_out ! sampled outgoing energy
integer :: i, k, l ! indices
integer :: n_energy_in ! number of incoming energies
integer :: n_energy_out ! number of outgoing energies
real(8) :: r ! interpolation factor on incoming energy
real(8) :: E_i_1, E_i_K ! endpoints on outgoing grid i
real(8) :: E_i1_1, E_i1_K ! endpoints on outgoing grid i+1
real(8) :: E_1, E_K ! endpoints interpolated between i and i+1
real(8) :: E_l_k, E_l_k1 ! adjacent E on outgoing grid l
! Determine number of incoming/outgoing energies
n_energy_in = size(this%energy_in)
n_energy_out = size(this%energy_out, 1)
! Determine index on incoming energy grid and interpolation factor
i = binary_search(this%energy_in, size(this%energy_in), E_in)
r = (E_in - this%energy_in(i)) / &
(this%energy_in(i+1) - this%energy_in(i))
! Sample outgoing energy bin
k = 1 + int(n_energy_out * prn())
! Determine E_1 and E_K
E_i_1 = this%energy_out(1, i)
E_i_K = this%energy_out(n_energy_out, i)
E_i1_1 = this%energy_out(1, i+1)
E_i1_K = this%energy_out(n_energy_out, i+1)
E_1 = E_i_1 + r*(E_i1_1 - E_i_1)
E_K = E_i_K + r*(E_i1_K - E_i_K)
! Randomly select between the outgoing table for incoming energy E_i and
! E_(i+1)
if (prn() < r) then
l = i + 1
else
l = i
end if
! Determine E_l_k and E_l_k+1
E_l_k = this%energy_out(k, l)
E_l_k1 = this%energy_out(k+1, l)
! Determine E' (denoted here as E_out)
E_out = E_l_k + prn()*(E_l_k1 - E_l_k)
! Now interpolate between incident energy bins i and i + 1
if (l == i) then
E_out = E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1)
else
E_out = E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1)
end if
end function equiprobable_sample
subroutine equiprobable_from_hdf5(this, group_id)
class(TabularEquiprobable), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
end subroutine equiprobable_from_hdf5
function discrete_photon_sample(this, E_in) result(E_out)
class(DiscretePhoton), intent(in) :: this
real(8), intent(in) :: E_in
real(8) :: E_out
if (this % primary_flag == 2) then
E_out = this % energy + this % A/(this % A + 1)*E_in
else
E_out = this % energy
end if
end function discrete_photon_sample
subroutine discrete_photon_from_hdf5(this, group_id)
class(DiscretePhoton), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
call read_attribute(this % primary_flag, group_id, 'primary_flag')
call read_attribute(this % energy, group_id, 'energy')
call read_attribute(this % A, group_id, 'atomic_weight_ratio')
end subroutine discrete_photon_from_hdf5
function level_inelastic_sample(this, E_in) result(E_out)
class(LevelInelastic), intent(in) :: this
real(8), intent(in) :: E_in
real(8) :: E_out
E_out = this%mass_ratio*(E_in - this%threshold)
end function level_inelastic_sample
subroutine level_inelastic_from_hdf5(this, group_id)
class(LevelInelastic), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
call read_attribute(this%threshold, group_id, 'threshold')
call read_attribute(this%mass_ratio, group_id, 'mass_ratio')
end subroutine level_inelastic_from_hdf5
function continuous_sample(this, E_in) result(E_out)
class(ContinuousTabular), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8) :: E_out ! sampled outgoing energy
integer :: i, k, l ! indices
integer :: n_energy_in ! number of incoming energies
integer :: n_energy_out ! number of outgoing energies
real(8) :: r ! interpolation factor on incoming energy
real(8) :: r1 ! random number on [0,1)
real(8) :: frac ! interpolation factor on outgoing energy
real(8) :: E_i_1, E_i_K ! endpoints on outgoing grid i
real(8) :: E_i1_1, E_i1_K ! endpoints on outgoing grid i+1
real(8) :: E_1, E_K ! endpoints interpolated between i and i+1
real(8) :: E_l_k, E_l_k1 ! adjacent E on outgoing grid l
real(8) :: p_l_k, p_l_k1 ! adjacent p on outgoing grid l
real(8) :: c_k, c_k1 ! cumulative probability
logical :: histogram_interp ! whether histogram interpolation is used
! Read number of interpolation regions and incoming energies
if (this%n_region == 1) then
histogram_interp = (this%interpolation(1) == 1)
else
histogram_interp = .false.
end if
! Find energy bin and calculate interpolation factor -- if the energy is
! outside the range of the tabulated energies, choose the first or last bins
n_energy_in = size(this%energy)
if (E_in < this%energy(1)) then
i = 1
r = ZERO
elseif (E_in > this%energy(n_energy_in)) then
i = n_energy_in - 1
r = ONE
else
i = binary_search(this%energy, n_energy_in, E_in)
r = (E_in - this%energy(i)) / &
(this%energy(i+1) - this%energy(i))
end if
! Sample between the ith and (i+1)th bin
if (histogram_interp) then
l = i
else
if (r > prn()) then
l = i + 1
else
l = i
end if
end if
! Interpolation for energy E1 and EK
n_energy_out = size(this%distribution(i)%e_out)
E_i_1 = this%distribution(i)%e_out(1)
E_i_K = this%distribution(i)%e_out(n_energy_out)
n_energy_out = size(this%distribution(i+1)%e_out)
E_i1_1 = this%distribution(i+1)%e_out(1)
E_i1_K = this%distribution(i+1)%e_out(n_energy_out)
E_1 = E_i_1 + r*(E_i1_1 - E_i_1)
E_K = E_i_K + r*(E_i1_K - E_i_K)
! Determine outgoing energy bin
n_energy_out = size(this%distribution(l)%e_out)
r1 = prn()
c_k = this%distribution(l)%c(1)
do k = 1, n_energy_out - 1
c_k1 = this%distribution(l)%c(k+1)
if (r1 < c_k1) exit
c_k = c_k1
end do
! Check to make sure 1 <= k <= NP - 1
k = max(1, min(k, n_energy_out - 1))
E_l_k = this%distribution(l)%e_out(k)
p_l_k = this%distribution(l)%p(k)
if (this%distribution(l)%interpolation == HISTOGRAM) then
! Histogram interpolation
if (p_l_k > ZERO) then
E_out = E_l_k + (r1 - c_k)/p_l_k
else
E_out = E_l_k
end if
elseif (this%distribution(l)%interpolation == LINEAR_LINEAR) then
! Linear-linear interpolation
E_l_k1 = this%distribution(l)%e_out(k+1)
p_l_k1 = this%distribution(l)%p(k+1)
frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k)
if (frac == ZERO) then
E_out = E_l_k + (r1 - c_k)/p_l_k
else
E_out = E_l_k + (sqrt(max(ZERO, p_l_k*p_l_k + &
TWO*frac*(r1 - c_k))) - p_l_k)/frac
end if
end if
! Now interpolate between incident energy bins i and i + 1
if (.not. histogram_interp .and. n_energy_out > 1) then
if (l == i) then
E_out = E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1)
else
E_out = E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1)
end if
end if
end function continuous_sample
subroutine continuous_from_hdf5(this, group_id)
class(ContinuousTabular), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer :: i, j, k
integer :: n
integer :: n_energy
integer(HID_T) :: dset_id
integer(HSIZE_T) :: dims(1), dims2(2)
integer, allocatable :: temp(:,:)
integer, allocatable :: offsets(:)
integer, allocatable :: interp(:)
integer, allocatable :: n_discrete(:)
real(8), allocatable :: eout(:,:)
! Open incoming energy dataset
dset_id = open_dataset(group_id, 'energy')
! Get interpolation parameters
call read_attribute(temp, dset_id, 'interpolation')
allocate(this%breakpoints(size(temp, 1)))
allocate(this%interpolation(size(temp, 1)))
this%breakpoints(:) = temp(:, 1)
this%interpolation(:) = temp(:, 2)
this%n_region = size(this%breakpoints)
! Get incoming energies
call get_shape(dset_id, dims)
n_energy = int(dims(1), 4)
allocate(this%energy(n_energy))
allocate(this%distribution(n_energy))
call read_dataset(this%energy, dset_id)
call close_dataset(dset_id)
! Get outgoing energy distribution data
dset_id = open_dataset(group_id, 'distribution')
call read_attribute(offsets, dset_id, 'offsets')
call read_attribute(interp, dset_id, 'interpolation')
call read_attribute(n_discrete, dset_id, 'n_discrete_lines')
call get_shape(dset_id, dims2)
allocate(eout(dims2(1), dims2(2)))
call read_dataset(eout, dset_id)
call close_dataset(dset_id)
do i = 1, n_energy
! Determine number of outgoing energies
j = offsets(i)
if (i < n_energy) then
n = offsets(i+1) - j
else
n = size(eout, 1) - j
end if
associate (d => this % distribution(i))
! Assign interpolation scheme and number of discrete lines
d % interpolation = interp(i)
d % n_discrete = n_discrete(i)
! Allocate arrays for energies and PDF/CDF
allocate(d % e_out(n))
allocate(d % p(n))
allocate(d % c(n))
! Copy data
d % e_out(:) = eout(j+1:j+n, 1)
d % p(:) = eout(j+1:j+n, 2)
! To get answers that match ACE data, for now we still use the tabulated
! CDF values that were passed through to the HDF5 library. At a later
! time, we can remove the CDF values from the HDF5 library and
! reconstruct them using the PDF
if (.true.) then
d % c(:) = eout(j+1:j+n, 3)
else
! Calculate cumulative distribution function -- discrete portion
do k = 1, n_discrete(i)
if (k == 1) then
d % c(k) = d % p(k)
else
d % c(k) = d % c(k-1) + d % p(k)
end if
end do
! Continuous portion
do k = d % n_discrete + 1, n
if (k == d % n_discrete + 1) then
d % c(k) = sum(d % p(1:d % n_discrete))
else
if (d % interpolation == HISTOGRAM) then
d % c(k) = d % c(k-1) + d % p(k-1) * &
(d % e_out(k) - d % e_out(k-1))
elseif (d % interpolation == LINEAR_LINEAR) then
d % c(k) = d % c(k-1) + HALF*(d % p(k-1) + d % p(k)) * &
(d % e_out(k) - d % e_out(k-1))
end if
end if
end do
! Normalize density and distribution functions
d % p(:) = d % p(:)/d % c(n)
d % c(:) = d % c(:)/d % c(n)
end if
end associate
end do
end subroutine continuous_from_hdf5
function maxwellenergy_sample(this, E_in) result(E_out)
class(MaxwellEnergy), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8) :: E_out ! sampled outgoing energy
real(8) :: theta ! Maxwell distribution parameter
! Get temperature corresponding to incoming energy
theta = this % theta % evaluate(E_in)
do
! Sample maxwell fission spectrum
E_out = maxwell_spectrum(theta)
! Accept energy based on restriction energy
if (E_out <= E_in - this%u) exit
end do
end function maxwellenergy_sample
subroutine maxwellenergy_from_hdf5(this, group_id)
class(MaxwellEnergy), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer(HID_T) :: dset_id
call read_attribute(this%u, group_id, 'u')
dset_id = open_dataset(group_id, 'theta')
call this%theta%from_hdf5(dset_id)
call close_dataset(dset_id)
end subroutine maxwellenergy_from_hdf5
function evaporation_sample(this, E_in) result(E_out)
class(Evaporation), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8) :: E_out ! sampled outgoing energy
real(8) :: theta ! evaporation spectrum parameter
real(8) :: x, y, v
! Get temperature corresponding to incoming energy
theta = this % theta % evaluate(E_in)
y = (E_in - this%u)/theta
v = 1 - exp(-y)
! Sample outgoing energy based on evaporation spectrum probability
! density function
do
x = -log((ONE - v*prn())*(ONE - v*prn()))
if (x <= y) exit
end do
E_out = x*theta
end function evaporation_sample
subroutine evaporation_from_hdf5(this, group_id)
class(Evaporation), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer(HID_T) :: dset_id
call read_attribute(this%u, group_id, 'u')
dset_id = open_dataset(group_id, 'theta')
call this%theta%from_hdf5(dset_id)
call close_dataset(dset_id)
end subroutine evaporation_from_hdf5
function watt_sample(this, E_in) result(E_out)
class(WattEnergy), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8) :: E_out ! sampled outgoing energy
real(8) :: a, b ! Watt spectrum parameters
! Determine Watt parameter 'a' from tabulated function
a = this % a % evaluate(E_in)
! Determine Watt parameter 'b' from tabulated function
b = this % b % evaluate(E_in)
do
! Sample energy-dependent Watt fission spectrum
E_out = watt_spectrum(a, b)
! Accept energy based on restriction energy
if (E_out <= E_in - this%u) exit
end do
end function watt_sample
subroutine watt_from_hdf5(this, group_id)
class(WattEnergy), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer(HID_T) :: dset_id
call read_attribute(this%u, group_id, 'u')
dset_id = open_dataset(group_id, 'a')
call this%a%from_hdf5(dset_id)
call close_dataset(dset_id)
dset_id = open_dataset(group_id, 'b')
call this%b%from_hdf5(dset_id)
call close_dataset(dset_id)
end subroutine watt_from_hdf5
end module energy_distribution

View file

@ -51,6 +51,35 @@ get_shape(hid_t obj_id, hsize_t* dims)
}
std::vector<hsize_t> attribute_shape(hid_t obj_id, const char* name)
{
hid_t attr = H5Aopen(obj_id, name, H5P_DEFAULT);
std::vector<hsize_t> shape = object_shape(attr);
H5Aclose(attr);
return shape;
}
std::vector<hsize_t> object_shape(hid_t obj_id)
{
// Get number of dimensions
auto type = H5Iget_type(obj_id);
hid_t dspace;
if (type == H5I_DATASET) {
dspace = H5Dget_space(obj_id);
} else if (type == H5I_ATTR) {
dspace = H5Aget_space(obj_id);
}
int n = H5Sget_simple_extent_ndims(dspace);
// Get shape of array
std::vector<hsize_t> shape(n);
H5Sget_simple_extent_dims(dspace, shape.data(), nullptr);
// Free resources and return
H5Sclose(dspace);
return shape;
}
void
get_shape_attr(hid_t obj_id, const char* name, hsize_t* dims)
{
@ -116,6 +145,18 @@ dataset_typesize(hid_t dset)
}
void
ensure_exists(hid_t group_id, const char* name)
{
if (!object_exists(group_id, name)) {
std::stringstream err_msg;
err_msg << "Object \"" << name << "\" does not exist in group "
<< object_name(group_id);
fatal_error(err_msg);
}
}
hid_t
file_open(const char* filename, char mode, bool parallel)
{
@ -285,6 +326,36 @@ get_groups(hid_t group_id, char* name[])
}
}
std::vector<std::string>
group_names(hid_t group_id)
{
// Determine number of links in the group
H5G_info_t info;
H5Gget_info(group_id, &info);
// Iterate over links to get names
H5O_info_t oinfo;
size_t size;
std::vector<std::string> names;
for (hsize_t i = 0; i < info.nlinks; ++i) {
// Determine type of object (and skip non-group)
H5Oget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo,
H5P_DEFAULT);
if (oinfo.type != H5O_TYPE_GROUP) continue;
// Get size of name
size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC,
i, nullptr, 0, H5P_DEFAULT);
// Read name
char buffer[size];
H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i,
buffer, size, H5P_DEFAULT);
names.emplace_back(&buffer[0], size);
}
return names;
}
bool
object_exists(hid_t object_id, const char* name)
@ -299,14 +370,23 @@ object_exists(hid_t object_id, const char* name)
}
std::string
object_name(hid_t obj_id)
{
// Determine size and create buffer
size_t size = 1 + H5Iget_name(obj_id, nullptr, 0);
char buffer[size];
// Read and return name
H5Iget_name(obj_id, buffer, size);
return {buffer, size};
}
hid_t
open_dataset(hid_t group_id, const char* name)
{
if (!object_exists(group_id, name)) {
std::stringstream err_msg;
err_msg << "Group \"" << name << "\" does not exist";
fatal_error(err_msg);
}
ensure_exists(group_id, name);
return H5Dopen(group_id, name, H5P_DEFAULT);
}
@ -314,11 +394,7 @@ open_dataset(hid_t group_id, const char* name)
hid_t
open_group(hid_t group_id, const char* name)
{
if (!object_exists(group_id, name)) {
std::stringstream err_msg;
err_msg << "Group \"" << name << "\" does not exist";
fatal_error(err_msg);
}
ensure_exists(group_id, name);
return H5Gopen(group_id, name, H5P_DEFAULT);
}
@ -425,7 +501,7 @@ read_string(hid_t obj_id, const char* name, size_t slen, char* buffer, bool inde
void
read_complex(hid_t obj_id, const char* name, double _Complex* buffer, bool indep)
read_complex(hid_t obj_id, const char* name, std::complex<double>* buffer, bool indep)
{
// Create compound datatype for complex numbers
struct complex_t {

View file

@ -1,19 +1,20 @@
#ifndef OPENMC_HDF5_INTERFACE_H
#define OPENMC_HDF5_INTERFACE_H
#include "hdf5.h"
#include "hdf5_hl.h"
#include <array>
#include <complex>
#include <cstddef>
#include <string>
#include <sstream>
#include <vector>
#include <complex.h>
#include "hdf5.h"
#include "hdf5_hl.h"
#include "xtensor/xadapt.hpp"
#include "xtensor/xarray.hpp"
#include "position.h"
namespace openmc {
//==============================================================================
@ -21,7 +22,7 @@ namespace openmc {
//==============================================================================
void read_attr(hid_t obj_id, const char* name, hid_t mem_type_id,
const void* buffer);
void* buffer);
void write_attr(hid_t obj_id, int ndim, const hsize_t* dims, const char* name,
hid_t mem_type_id, const void* buffer);
void read_dataset(hid_t obj_id, const char* name, hid_t mem_type_id,
@ -72,6 +73,12 @@ read_nd_vector(hid_t obj_id, const char* name,
std::vector<std::vector<std::vector<std::vector<std::vector<double> > > > >& result,
bool must_have = false);
std::vector<hsize_t> attribute_shape(hid_t obj_id, const char* name);
void ensure_exists(hid_t group_id, const char* name);
std::vector<std::string> group_names(hid_t group_id);
std::vector<hsize_t> object_shape(hid_t obj_id);
std::string object_name(hid_t obj_id);
//==============================================================================
// Fortran compatibility functions
//==============================================================================
@ -101,7 +108,7 @@ extern "C" {
void read_attr_string(hid_t obj_id, const char* name, size_t slen,
char* buffer);
void read_complex(hid_t obj_id, const char* name,
double _Complex* buffer, bool indep);
std::complex<double>* buffer, bool indep);
void read_double(hid_t obj_id, const char* name, double* buffer,
bool indep);
void read_int(hid_t obj_id, const char* name, int* buffer,
@ -142,7 +149,127 @@ template<typename T>
struct H5TypeMap { static const hid_t type_id; };
//==============================================================================
// Template functions used to provide simple interface to lower-level functions
// Templates/overloads for read_attribute
//==============================================================================
// Scalar version
template<typename T>
void read_attribute(hid_t obj_id, const char* name, T& buffer)
{
read_attr(obj_id, name, H5TypeMap<T>::type_id, &buffer);
}
// vector version
template<typename T>
void read_attribute(hid_t obj_id, const char* name, std::vector<T>& vec)
{
// Get shape of attribute array
auto shape = attribute_shape(obj_id, name);
// Allocate new array to read data into
std::size_t size = 1;
for (const auto x : shape)
size *= x;
vec.resize(size);
// Read data from attribute
read_attr(obj_id, name, H5TypeMap<T>::type_id, vec.data());
}
// Generic array version
template<typename T>
void read_attribute(hid_t obj_id, const char* name, xt::xarray<T>& arr)
{
// Get shape of attribute array
auto shape = attribute_shape(obj_id, name);
// Allocate new array to read data into
std::size_t size = 1;
for (const auto x : shape)
size *= x;
T* buffer = new T[size];
// Read data from attribute
read_attr(obj_id, name, H5TypeMap<T>::type_id, buffer);
// Adapt array into xarray
arr = xt::adapt(buffer, size, xt::acquire_ownership(), shape);
}
// overload for std::string
inline void
read_attribute(hid_t obj_id, const char* name, std::string& str)
{
// Create buffer to read data into
auto n = attribute_typesize(obj_id, name);
char buffer[n];
// Read attribute and set string
read_attr_string(obj_id, name, n, buffer);
str = std::string{buffer, n};
}
//==============================================================================
// Templates/overloads for read_dataset
//==============================================================================
template<typename T>
void read_dataset(hid_t obj_id, const char* name, T buffer, bool indep=false)
{
read_dataset(obj_id, name, H5TypeMap<T>::type_id, &buffer, indep);
}
template <typename T>
void read_dataset(hid_t dset, std::vector<T>& vec, bool indep=false)
{
// Get shape of dataset
std::vector<hsize_t> shape = object_shape(dset);
// Resize vector to appropriate size
vec.resize(shape[0]);
// Read data into vector
read_dataset(dset, nullptr, H5TypeMap<T>::type_id, vec.data(), indep);
}
template <typename T>
void read_dataset(hid_t obj_id, const char* name, std::vector<T>& vec, bool indep=false)
{
hid_t dset = open_dataset(obj_id, name);
read_dataset(dset, vec, indep);
close_dataset(dset);
}
template <typename T>
void read_dataset(hid_t dset, xt::xarray<T>& arr, bool indep=false)
{
// Get shape of dataset
std::vector<hsize_t> shape = object_shape(dset);
// Allocate new array to read data into
std::size_t size = 1;
for (const auto x : shape)
size *= x;
T* buffer = new T[size];
// Read data from attribute
read_dataset(dset, nullptr, H5TypeMap<T>::type_id, buffer, indep);
// Adapt into xarray
arr = xt::adapt(buffer, size, xt::acquire_ownership(), shape);
}
template <typename T>
void read_dataset(hid_t obj_id, const char* name, xt::xarray<T>& arr, bool indep=false)
{
// Open dataset and read array
hid_t dset = open_dataset(obj_id, name);
read_dataset(dset, arr, indep);
close_dataset(dset);
}
//==============================================================================
// Templates/overloads for write_attribute
//==============================================================================
template<typename T> inline void
@ -151,8 +278,8 @@ write_attribute(hid_t obj_id, const char* name, T buffer)
write_attr(obj_id, name, 0, nullptr, H5TypeMap<T>::type_id, &buffer);
}
template<> inline void
write_attribute<const char*>(hid_t obj_id, const char* name, const char* buffer)
inline void
write_attribute(hid_t obj_id, const char* name, const char* buffer)
{
write_attr_string(obj_id, name, buffer);
}
@ -164,14 +291,18 @@ write_attribute(hid_t obj_id, const char* name, const std::array<T, N>& buffer)
write_attr(obj_id, 1, dims, name, H5TypeMap<T>::type_id, buffer.data());
}
//==============================================================================
// Templates/overloads for write_dataset
//==============================================================================
template<typename T> inline void
write_dataset(hid_t obj_id, const char* name, T buffer)
{
write_dataset(obj_id, 0, nullptr, name, H5TypeMap<T>::type_id, &buffer, false);
}
template<> inline void
write_dataset<const char*>(hid_t obj_id, const char* name, const char* buffer)
inline void
write_dataset(hid_t obj_id, const char* name, const char* buffer)
{
write_string(obj_id, name, buffer, false);
}

View file

@ -3254,7 +3254,7 @@ contains
! Check if the specified tally mesh exists
if (mesh_dict % has(meshid)) then
pl % meshlines_mesh => meshes(mesh_dict % get(meshid))
if (meshes(meshid) % type /= LATTICE_RECT) then
if (meshes(meshid) % type /= MESH_REGULAR) then
call fatal_error("Non-rectangular mesh specified in &
&meshlines for plot " // trim(to_str(pl % id)))
end if

View file

@ -650,6 +650,14 @@ void rotate_angle_c(double uvw[3], double mu, double* phi) {
}
Direction rotate_angle(Direction u, double mu, double* phi)
{
double uvw[] {u.x, u.y, u.z};
rotate_angle_c(uvw, mu, phi);
return {uvw[0], uvw[1], uvw[2]};
}
double maxwell_spectrum_c(double T) {
// Set the random numbers
double r1 = prn();

View file

@ -1,13 +1,14 @@
//! \file math_functions.h
//! A collection of elementary math functions.
#ifndef MATH_FUNCTIONS_H
#define MATH_FUNCTIONS_H
#ifndef OPENMC_MATH_FUNCTIONS_H
#define OPENMC_MATH_FUNCTIONS_H
#include <cmath>
#include <cstdlib>
#include "constants.h"
#include "position.h"
#include "random_lcg.h"
@ -124,6 +125,8 @@ extern "C" void calc_zn_rad_c(int n, double rho, double zn_rad[]);
extern "C" void rotate_angle_c(double uvw[3], double mu, double* phi);
Direction rotate_angle(Direction u, double mu, double* phi);
//==============================================================================
//! Samples an energy from the Maxwell fission distribution based on a direct
//! sampling scheme.
@ -220,4 +223,4 @@ extern "C" double spline_integrate_c(int n, const double x[], const double y[],
const double z[], double xa, double xb);
} // namespace openmc
#endif // MATH_FUNCTIONS_H
#endif // OPENMC_MATH_FUNCTIONS_H

View file

@ -17,11 +17,9 @@ module nuclide_header
FIT_T, FIT_A, FIT_F, MultipoleArray
use message_passing
use multipole_header, only: MultipoleArray
use product_header, only: AngleEnergyContainer
use random_lcg, only: prn, future_prn, prn_set_stream
use reaction_header, only: Reaction
use sab_header, only: SAlphaBeta, sab_tables
use secondary_uncorrelated, only: UncorrelatedAngleEnergy
use settings
use stl_vector, only: VectorInt, VectorReal
use string
@ -642,29 +640,33 @@ contains
if (rx % MT >= N_2N0 .and. rx % MT <= N_2NC .and. find(MTs, N_2N) /= -1) cycle
do t = 1, n_temperature
j = rx % xs(t) % threshold
n = size(rx % xs(t) % value)
j = rx % xs_threshold(t)
n = rx % xs_size(t)
! Add contribution to total cross section
this % xs(t) % value(XS_TOTAL,j:j+n-1) = this % xs(t) % &
value(XS_TOTAL,j:j+n-1) + rx % xs(t) % value
do k = j, j + n - 1
this % xs(t) % value(XS_TOTAL,k) = this % xs(t) % &
value(XS_TOTAL,k) + rx % xs(t, k - j + 1)
end do
! Calculate photon production cross section
do k = 1, size(rx % products)
if (rx % products(k) % particle == PHOTON) then
do k = 1, rx % products_size()
if (rx % product_particle(k) == PHOTON) then
do l = 1, n
this % xs(t) % value(XS_PHOTON_PROD,l+j-1) = &
this % xs(t) % value(XS_PHOTON_PROD,l+j-1) + &
rx % xs(t) % value(l) * rx % products(k) % &
yield % evaluate(this % grid(t) % energy(l+j-1))
rx % xs(t, l) * rx % product_yield(k, &
this % grid(t) % energy(l+j-1))
end do
end if
end do
! Add contribution to absorption cross section
if (is_disappearance(rx % MT)) then
this % xs(t) % value(XS_ABSORPTION,j:j+n-1) = this % xs(t) % &
value(XS_ABSORPTION,j:j+n-1) + rx % xs(t) % value
do k = j, j + n - 1
this % xs(t) % value(XS_ABSORPTION,k) = this % xs(t) % &
value(XS_ABSORPTION,k) + rx % xs(t, k - j + 1)
end do
end if
! Information about fission reactions
@ -680,39 +682,20 @@ contains
! Add contribution to fission cross section
if (is_fission(rx % MT)) then
this % fissionable = .true.
this % xs(t) % value(XS_FISSION,j:j+n-1) = this % xs(t) % &
value(XS_FISSION,j:j+n-1) + rx % xs(t) % value
do k = j, j + n - 1
this % xs(t) % value(XS_FISSION,k) = this % xs(t) % &
value(XS_FISSION,k) + rx % xs(t, k - j + 1)
! Also need to add fission cross sections to absorption
this % xs(t) % value(XS_ABSORPTION,j:j+n-1) = this % xs(t) % &
value(XS_ABSORPTION,j:j+n-1) + rx % xs(t) % value
! Also need to add fission cross sections to absorption
this % xs(t) % value(XS_ABSORPTION,k) = this % xs(t) % &
value(XS_ABSORPTION,k) + rx % xs(t, k - j + 1)
end do
! Keep track of this reaction for easy searching later
if (t == 1) then
i_fission = i_fission + 1
this % index_fission(i_fission) = i
this % n_fission = this % n_fission + 1
! <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<
! Before the secondary distribution refactor, when the angle/energy
! distribution was uncorrelated, no angle was actually sampled. With
! the refactor, an angle is always sampled for an uncorrelated
! distribution even when no angle distribution exists in the ACE file
! (isotropic is assumed). To preserve the RNG stream, we explicitly
! mark fission reactions so that we avoid the angle sampling.
do k = 1, size(rx % products)
if (rx % products(k) % particle == NEUTRON) then
do m = 1, size(rx % products(k) % distribution)
associate (aedist => rx % products(k) % distribution(m) % obj)
select type (aedist)
type is (UncorrelatedAngleEnergy)
aedist % fission = .true.
end select
end associate
end do
end if
end do
! <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<
end if
end if ! fission
end do ! temperature
@ -721,12 +704,13 @@ contains
! Determine number of delayed neutron precursors
if (this % fissionable) then
do i = 1, size(this % reactions(this % index_fission(1)) % products)
if (this % reactions(this % index_fission(1)) % products(i) % &
emission_mode == EMISSION_DELAYED) then
this % n_precursor = this % n_precursor + 1
end if
end do
associate (rx => this % reactions(this % index_fission(1)))
do i = 1, rx % products_size()
if (rx % product_emission_mode(i) == EMISSION_DELAYED) then
this % n_precursor = this % n_precursor + 1
end if
end do
end associate
end if
! Calculate nu-fission cross section
@ -761,36 +745,30 @@ contains
select case (emission_mode)
case (EMISSION_PROMPT)
associate (product => this % reactions(this % index_fission(1)) % products(1))
nu = product % yield % evaluate(E)
associate (rx => this % reactions(this % index_fission(1)))
nu = rx % product_yield(1, E)
end associate
case (EMISSION_DELAYED)
if (this % n_precursor > 0) then
if (present(group) .and. group < &
size(this % reactions(this % index_fission(1)) % products)) then
! If delayed group specified, determine yield immediately
associate(p => this % reactions(this % index_fission(1)) % products(1 + group))
nu = p % yield % evaluate(E)
end associate
associate(rx => this % reactions(this % index_fission(1)))
if (present(group) .and. group < rx % products_size()) then
! If delayed group specified, determine yield immediately
nu = rx % product_yield(1 + group, E)
else
nu = ZERO
else
nu = ZERO
do i = 2, rx % products_size()
! Skip any non-neutron products
if (rx % product_particle(i) /= NEUTRON) exit
associate (rx => this % reactions(this % index_fission(1)))
do i = 2, size(rx % products)
associate (product => rx % products(i))
! Skip any non-neutron products
if (product % particle /= NEUTRON) exit
! Evaluate yield
if (product % emission_mode == EMISSION_DELAYED) then
nu = nu + product % yield % evaluate(E)
end if
end associate
! Evaluate yield
if (rx % product_emission_mode(i) == EMISSION_DELAYED) then
nu = nu + rx % product_yield(i, E)
end if
end do
end associate
end if
end if
end associate
else
nu = ZERO
end if
@ -799,8 +777,8 @@ contains
if (allocated(this % total_nu)) then
nu = this % total_nu % evaluate(E)
else
associate (product => this % reactions(this % index_fission(1)) % products(1))
nu = product % yield % evaluate(E)
associate (rx => this % reactions(this % index_fission(1)))
nu = rx % product_yield(1, E)
end associate
end if
end select
@ -868,6 +846,7 @@ contains
integer :: i_high ! upper logarithmic mapping index
integer :: i_rxn ! reaction index
integer :: j ! index in DEPLETION_RX
integer :: threshold ! threshold energy index
real(8) :: f ! interp factor on nuclide energy grid
real(8) :: kT ! temperature in eV
real(8) :: sig_t, sig_a, sig_f ! Intermediate multipole variables
@ -1009,10 +988,11 @@ contains
! need to specifically check its threshold index
i_rxn = this % reaction_index(DEPLETION_RX(1))
if (i_rxn > 0) then
associate (xs => this % reactions(i_rxn) % xs(i_temp))
associate (rx => this % reactions(i_rxn))
threshold = rx % xs_threshold(i_temp)
micro_xs % reaction(1) = (ONE - f) * &
xs % value(i_grid - xs % threshold + 1) + &
f * xs % value(i_grid - xs % threshold + 2)
rx % xs(i_temp, i_grid - threshold + 1) + &
f * rx % xs(i_temp, i_grid - threshold + 2)
end associate
end if
@ -1022,11 +1002,12 @@ contains
! reaction xs appropriately
i_rxn = this % reaction_index(DEPLETION_RX(j))
if (i_rxn > 0) then
associate (xs => this % reactions(i_rxn) % xs(i_temp))
if (i_grid >= xs % threshold) then
associate (rx => this % reactions(i_rxn))
threshold = rx % xs_threshold(i_temp)
if (i_grid >= threshold) then
micro_xs % reaction(j) = (ONE - f) * &
xs % value(i_grid - xs % threshold + 1) + &
f * xs % value(i_grid - xs % threshold + 2)
rx % xs(i_temp, i_grid - threshold + 1) + &
f * rx % xs(i_temp, i_grid - threshold + 2)
elseif (j >= 4) then
! One can show that the the threshold for (n,(x+1)n) is always
! higher than the threshold for (n,xn). Thus, if we are below
@ -1091,8 +1072,9 @@ contains
f = micro_xs % interp_factor
if (i_temp > 0) then
associate (xs => this % reactions(1) % xs(i_temp) % value)
micro_xs % elastic = (ONE - f) * xs(i_grid) + f * xs(i_grid + 1)
associate (rx => this % reactions(1))
micro_xs % elastic = (ONE - f) * rx % xs(i_temp, i_grid) + &
f * rx % xs(i_temp, i_grid + 1)
end associate
else
! For multipole, elastic is total - absorption
@ -1459,6 +1441,7 @@ contains
integer :: i_energy ! index for energy
integer :: i_low ! band index at lower bounding energy
integer :: i_up ! band index at upper bounding energy
integer :: threshold ! threshold energy index
real(8) :: f ! interpolation factor
real(8) :: r ! pseudo-random number
real(8) :: elastic ! elastic cross section
@ -1551,10 +1534,11 @@ contains
f = micro_xs % interp_factor
! Determine inelastic scattering cross section
associate (xs => this % reactions(this % urr_inelastic) % xs(i_temp))
if (i_energy >= xs % threshold) then
inelastic = (ONE - f) * xs % value(i_energy - xs % threshold + 1) + &
f * xs % value(i_energy - xs % threshold + 2)
associate (rx => this % reactions(this % urr_inelastic))
threshold = rx % xs_threshold(i_temp)
if (i_energy >= threshold) then
inelastic = (ONE - f) * rx % xs(i_temp, i_energy - threshold + 1) + &
f * rx % xs(i_temp, i_energy - threshold + 2)
end if
end associate
end if

View file

@ -62,7 +62,7 @@ Particle::initialize()
clear();
// Set particle to neutron that's alive
type = NEUTRON;
type = static_cast<int>(ParticleType::neutron);
alive = true;
// clear attributes

View file

@ -15,12 +15,27 @@ namespace openmc {
// Constants
//==============================================================================
// Since cross section libraries come with different numbers of delayed groups
// (e.g. ENDF/B-VII.1 has 6 and JEFF 3.1.1 has 8 delayed groups) and we don't
// yet know what cross section library is being used when the tallies.xml file
// is read in, we want to have an upper bound on the size of the array we
// use to store the bins for delayed group tallies.
constexpr int MAX_DELAYED_GROUPS {8};
// Maximum number of secondary particles created
constexpr int MAX_SECONDARY {1000};
constexpr int NEUTRON {1};
// Maximum number of lost particles
constexpr int MAX_LOST_PARTICLES {10};
// Maximum number of lost particles, relative to the total number of particles
constexpr double REL_MAX_LOST_PARTICLES {1.0e-6};
//! Particle types
enum class ParticleType {
neutron, photon, electron, positron
};
extern "C" {
struct LocalCoord {

View file

@ -18,7 +18,6 @@ module physics
use random_lcg, only: prn, advance_prn_seed, prn_set_stream
use reaction_header, only: Reaction
use sab_header, only: sab_tables
use secondary_uncorrelated, only: UncorrelatedAngleEnergy
use settings
use simulation_header
use string, only: to_str
@ -506,6 +505,7 @@ contains
integer :: i
integer :: i_grid
integer :: i_temp
integer :: threshold
real(8) :: f
real(8) :: prob
real(8) :: cutoff
@ -545,13 +545,14 @@ contains
FISSION_REACTION_LOOP: do i = 1, nuc % n_fission
i_reaction = nuc % index_fission(i)
associate (xs => nuc % reactions(i_reaction) % xs(i_temp))
associate (rx => nuc % reactions(i_reaction))
! if energy is below threshold for this reaction, skip it
if (i_grid < xs % threshold) cycle
threshold = rx % xs_threshold(i_temp)
if (i_grid < threshold) cycle
! add to cumulative probability
prob = prob + ((ONE - f) * xs % value(i_grid - xs % threshold + 1) &
+ f*(xs % value(i_grid - xs % threshold + 2)))
prob = prob + ((ONE - f) * rx % xs(i_temp, i_grid - threshold + 1) &
+ f*(rx % xs(i_temp, i_grid - threshold + 2)))
end associate
! Create fission bank sites if fission occurs
@ -593,17 +594,17 @@ contains
! Loop through each reaction type
REACTION_LOOP: do i_reaction = 1, size(nuc % reactions)
associate (rx => nuc % reactions(i_reaction))
threshold = rx % xs(i_temp) % threshold
threshold = rx % xs_threshold(i_temp)
! if energy is below threshold for this reaction, skip it
if (i_grid < threshold) cycle
do i_product = 1, size(rx % products)
if (rx % products(i_product) % particle == PHOTON) then
do i_product = 1, rx % products_size()
if (rx % product_particle(i_product) == PHOTON) then
! add to cumulative probability
yield = rx % products(i_product) % yield % evaluate(E)
prob = prob + ((ONE - f) * rx % xs(i_temp) % value(i_grid - threshold + 1) &
+ f*(rx % xs(i_temp) % value(i_grid - threshold + 2))) * yield
yield = rx % product_yield(i_product, E)
prob = prob + ((ONE - f) * rx % xs(i_temp, i_grid - threshold + 1) &
+ f*(rx % xs(i_temp, i_grid - threshold + 2))) * yield
if (prob > cutoff) return
last_valid_reaction = i_reaction
@ -672,6 +673,7 @@ contains
integer :: j
integer :: i_temp
integer :: i_grid
integer :: threshold
real(8) :: f
real(8) :: prob
real(8) :: cutoff
@ -750,14 +752,14 @@ contains
&// trim(nuc % name))
end if
associate (rx => nuc % reactions(i), &
xs => nuc % reactions(i) % xs(i_temp))
associate (rx => nuc % reactions(i))
! if energy is below threshold for this reaction, skip it
if (i_grid < xs % threshold) cycle
threshold = rx % xs_threshold(i_temp)
if (i_grid < threshold) cycle
! add to cumulative probability
prob = prob + ((ONE - f)*xs % value(i_grid - xs % threshold + 1) &
+ f*(xs % value(i_grid - xs % threshold + 2)))
prob = prob + ((ONE - f)*rx % xs(i_temp, i_grid - threshold + 1) &
+ f*(rx % xs(i_temp, i_grid - threshold + 2)))
end associate
end do
@ -839,14 +841,7 @@ contains
vel = sqrt(dot_product(v_n, v_n))
! Sample scattering angle
select type (dist => rxn % products(1) % distribution(1) % obj)
type is (UncorrelatedAngleEnergy)
if (allocated(dist % angle % energy)) then
mu_cm = dist % angle % sample(E)
else
mu_cm = TWO*prn() - ONE
end if
end select
mu_cm = rxn % sample_elastic_mu(E)
! Determine direction cosines in CM
uvw_cm = v_n/vel
@ -1581,7 +1576,7 @@ contains
do group = 1, nuc % n_precursor
! determine delayed neutron precursor yield for group j
yield = rxn % products(1 + group) % yield % evaluate(E_in)
yield = rxn % product_yield(1 + group, E_in)
! Check if this group is sampled
prob = prob + yield
@ -1600,7 +1595,7 @@ contains
do
! sample from energy/angle distribution -- note that mu has already been
! sampled above and doesn't need to be resampled
call rxn % products(1 + group) % sample(E_in, site % E, mu)
call rxn % product_sample(1 + group, E_in, site % E, mu)
! resample if energy is greater than maximum neutron energy
if (site % E < energy_max(NEUTRON)) exit
@ -1624,7 +1619,7 @@ contains
! sample from prompt neutron energy distribution
n_sample = 0
do
call rxn % products(1) % sample(E_in, site % E, mu)
call rxn % product_sample(1, E_in, site % E, mu)
! resample if energy is greater than maximum neutron energy
if (site % E < energy_max(NEUTRON)) exit
@ -1663,7 +1658,7 @@ contains
E_in = p % E
! sample outgoing energy and scattering cosine
call rxn % products(1) % sample(E_in, E, mu)
call rxn % product_sample(1, E_in, E, mu)
! if scattering system is in center-of-mass, transfer cosine of scattering
! angle and outgoing energy from CM to LAB
@ -1692,7 +1687,7 @@ contains
p % coord(1) % uvw = rotate_angle(p % coord(1) % uvw, mu)
! evaluate yield
yield = rxn % products(1) % yield % evaluate(E_in)
yield = rxn % product_yield(1, E_in)
if (mod(yield, ONE) == ZERO) then
! If yield is integral, create exactly that many secondary particles
do i = 1, nint(yield) - 1
@ -1740,8 +1735,8 @@ contains
call sample_photon_product(i_nuclide, p % E, i_reaction, i_product)
! Sample the outgoing energy and angle
call nuclides(i_nuclide) % reactions(i_reaction) % products(i_product) &
% sample(p % E, E, mu)
call nuclides(i_nuclide) % reactions(i_reaction) % &
product_sample(i_product, p % E, E, mu)
! Sample the new direction
uvw = rotate_angle(p % coord(1) % uvw, mu)

View file

@ -1,153 +0,0 @@
module product_header
use angleenergy_header, only: AngleEnergyContainer
use constants, only: ZERO, MAX_WORD_LEN, EMISSION_PROMPT, EMISSION_DELAYED, &
EMISSION_TOTAL, NEUTRON, PHOTON
use endf_header, only: Tabulated1D, Function1D, Polynomial
use hdf5_interface, only: read_attribute, open_group, close_group, &
open_dataset, close_dataset, read_dataset, HID_T
use random_lcg, only: prn
use secondary_correlated, only: CorrelatedAngleEnergy
use secondary_kalbach, only: KalbachMann
use secondary_nbody, only: NBodyPhaseSpace
use secondary_uncorrelated, only: UncorrelatedAngleEnergy
use string, only: to_str
!===============================================================================
! REACTIONPRODUCT stores a data for a reaction product including its yield and
! angle-energy distributions, each of which has a given probability of occurring
! for a given incoming energy. In general, most products only have one
! angle-energy distribution, but for some cases (e.g., (n,2n) in certain
! nuclides) multiple distinct distributions exist.
!===============================================================================
type :: ReactionProduct
integer :: particle
integer :: emission_mode ! prompt, delayed, or total emission
real(8) :: decay_rate ! Decay rate for delayed neutron precursors
class(Function1D), pointer :: yield => null() ! Energy-dependent neutron yield
type(Tabulated1D), allocatable :: applicability(:)
type(AngleEnergyContainer), allocatable :: distribution(:)
contains
procedure :: sample => reactionproduct_sample
procedure :: from_hdf5 => reactionproduct_from_hdf5
end type ReactionProduct
contains
subroutine reactionproduct_sample(this, E_in, E_out, mu)
class(ReactionProduct), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8), intent(out) :: E_out ! sampled outgoing energy
real(8), intent(out) :: mu ! sampled scattering cosine
integer :: i ! loop counter
integer :: n ! number of angle-energy distributions
real(8) :: prob ! cumulative probability
real(8) :: c ! sampled cumulative probability
n = size(this%applicability)
if (n > 1) then
prob = ZERO
c = prn()
do i = 1, n
! Determine probability that i-th energy distribution is sampled
prob = prob + this % applicability(i) % evaluate(E_in)
! If i-th distribution is sampled, sample energy from the distribution
if (c <= prob) then
call this%distribution(i)%obj%sample(E_in, E_out, mu)
exit
end if
end do
else
! If only one distribution is present, go ahead and sample it
call this%distribution(1)%obj%sample(E_in, E_out, mu)
end if
end subroutine reactionproduct_sample
subroutine reactionproduct_from_hdf5(this, group_id)
class(ReactionProduct), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer :: i
integer :: n
integer(HID_T) :: dgroup
integer(HID_T) :: app
integer(HID_T) :: yield
character(MAX_WORD_LEN) :: temp
! Read particle type
call read_attribute(temp, group_id, 'particle')
select case (temp)
case ('neutron')
this % particle = NEUTRON
case ('photon')
this % particle = PHOTON
end select
! Read emission mode and decay rate
call read_attribute(temp, group_id, 'emission_mode')
select case (temp)
case ('prompt')
this % emission_mode = EMISSION_PROMPT
case ('delayed')
this % emission_mode = EMISSION_DELAYED
case ('total')
this % emission_mode = EMISSION_TOTAL
end select
! Read decay rate for delayed emission
if (this % emission_mode == EMISSION_DELAYED) then
call read_attribute(this % decay_rate, group_id, 'decay_rate')
end if
! Read secondary particle yield
yield = open_dataset(group_id, 'yield')
call read_attribute(temp, yield, 'type')
select case (temp)
case ('Tabulated1D')
allocate(Tabulated1D :: this % yield)
case ('Polynomial')
allocate(Polynomial :: this % yield)
end select
call this % yield % from_hdf5(yield)
call close_dataset(yield)
call read_attribute(n, group_id, 'n_distribution')
allocate(this%applicability(n))
allocate(this%distribution(n))
do i = 1, n
dgroup = open_group(group_id, trim('distribution_' // to_str(i - 1)))
! Read applicability
if (n > 1) then
app = open_dataset(dgroup, 'applicability')
call this%applicability(i)%from_hdf5(app)
call close_dataset(app)
end if
! Read type of distribution and allocate accordingly
call read_attribute(temp, dgroup, 'type')
select case (temp)
case ('uncorrelated')
allocate(UncorrelatedAngleEnergy :: this%distribution(i)%obj)
case ('correlated')
allocate(CorrelatedAngleEnergy :: this%distribution(i)%obj)
case ('nbody')
allocate(NBodyPhaseSpace :: this%distribution(i)%obj)
case ('kalbach-mann')
allocate(KalbachMann :: this%distribution(i)%obj)
end select
! Read distribution data
call this%distribution(i)%obj%from_hdf5(dgroup)
call close_group(dgroup)
end do
end subroutine reactionproduct_from_hdf5
end module product_header

161
src/reaction.cpp Normal file
View file

@ -0,0 +1,161 @@
#include "reaction.h"
#include <string>
#include <utility> // for move
#include "hdf5_interface.h"
#include "endf.h"
#include "random_lcg.h"
#include "secondary_uncorrelated.h"
namespace openmc {
Reaction::Reaction(hid_t group, const std::vector<int>& temperatures)
{
read_attribute(group, "Q_value", q_value_);
read_attribute(group, "mt", mt_);
int cm;
read_attribute(group, "center_of_mass", cm);
scatter_in_cm_ = (cm == 1);
// Read cross section and threshold_idx data
for (auto t : temperatures) {
// Get group corresponding to temperature
std::string temp_str {std::to_string(t) + "K"};
hid_t temp_group = open_group(group, temp_str.c_str());
hid_t dset = open_dataset(temp_group, "xs");
// Get threshold index
TemperatureXS xs;
read_attribute(dset, "threshold_idx", xs.threshold);
// Read cross section values
read_dataset(dset, xs.value);
close_dataset(dset);
close_group(temp_group);
// create new entry in xs vector
xs_.push_back(std::move(xs));
}
// Read products
for (const auto& name : group_names(group)) {
if (name.rfind("product_", 0) == 0) {
hid_t pgroup = open_group(group, name.c_str());
products_.emplace_back(pgroup);
close_group(pgroup);
}
}
// <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<
// Before the secondary distribution refactor, when the angle/energy
// distribution was uncorrelated, no angle was actually sampled. With
// the refactor, an angle is always sampled for an uncorrelated
// distribution even when no angle distribution exists in the ACE file
// (isotropic is assumed). To preserve the RNG stream, we explicitly
// mark fission reactions so that we avoid the angle sampling.
if (is_fission(mt_)) {
for (auto& p : products_) {
if (p.particle_ == ParticleType::neutron) {
for (auto& d : p.distribution_) {
auto d_ = dynamic_cast<UncorrelatedAngleEnergy*>(d.get());
if (d_) d_->fission() = true;
}
}
}
}
// <<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<
}
//==============================================================================
// Fortran compatibility functions
//==============================================================================
Reaction* reaction_from_hdf5(hid_t group, int* temperatures, int n)
{
std::vector<int> temps {temperatures, temperatures + n};
return new Reaction{group, temps};
}
void reaction_delete(Reaction* rx) { delete rx; }
int reaction_mt(Reaction* rx) { return rx->mt_; }
double reaction_q_value(Reaction* rx) { return rx->q_value_; }
bool reaction_scatter_in_cm(Reaction* rx) { return rx->scatter_in_cm_; }
double reaction_product_decay_rate(Reaction* rx, int product)
{
return rx->products_[product - 1].decay_rate_;
}
int reaction_product_emission_mode(Reaction* rx, int product)
{
switch (rx->products_[product - 1].emission_mode_) {
case ReactionProduct::EmissionMode::prompt:
return 1;
case ReactionProduct::EmissionMode::delayed:
return 2;
case ReactionProduct::EmissionMode::total:
return 3;
}
}
int reaction_product_particle(Reaction* rx, int product)
{
switch (rx->products_[product - 1].particle_) {
case ParticleType::neutron:
return 1;
case ParticleType::photon:
return 2;
case ParticleType::electron:
return 3;
case ParticleType::positron:
return 4;
}
}
void reaction_product_sample(Reaction* rx, int product, double E_in, double* E_out, double* mu)
{
rx->products_[product - 1].sample(E_in, *E_out, *mu);
}
double reaction_product_yield(Reaction* rx, int product, double E)
{
return (*rx->products_[product - 1].yield_)(E);
}
int reaction_products_size(Reaction* rx) { return rx->products_.size(); }
double reaction_xs(Reaction* rx, int temperature, int energy)
{
return rx->xs_[temperature - 1].value[energy - 1];
}
double reaction_sample_elastic_mu(Reaction* rx, double E)
{
// Get elastic scattering distribution
auto& d = rx->products_[0].distribution_[0];
// Check if it is an uncorrelated angle-energy distribution
auto d_ = dynamic_cast<UncorrelatedAngleEnergy*>(d.get());
if (d_) {
return d_->angle().sample(E);
} else {
return 2.0*prn() - 1.0;
}
}
int reaction_xs_size(Reaction* rx, int temperature)
{
return rx->xs_[temperature - 1].value.size();
}
int reaction_xs_threshold(Reaction* rx, int temperature)
{
return rx->xs_[temperature - 1].threshold;
}
}

65
src/reaction.h Normal file
View file

@ -0,0 +1,65 @@
//! \file reaction.h
//! Data for an incident neutron reaction
#ifndef OPENMC_REACTION_H
#define OPENMC_REACTION_H
#include <vector>
#include "hdf5.h"
#include "reaction_product.h"
namespace openmc {
//==============================================================================
//! Data for a single reaction including cross sections (possibly at multiple
//! temperatures) and reaction products (with secondary angle-energy
//! distributions)
//==============================================================================
class Reaction {
public:
//! Construct reaction from HDF5 data
//! \param[in] group HDF5 group containing reaction data
//! \param[in] temperatures Desired temperatures for cross sections
explicit Reaction(hid_t group, const std::vector<int>& temperatures);
//! Cross section at a single temperature
struct TemperatureXS {
int threshold;
std::vector<double> value;
};
int mt_; //!< ENDF MT value
double q_value_; //!< Reaction Q value in [eV]
bool scatter_in_cm_; //!< scattering system in center-of-mass?
std::vector<TemperatureXS> xs_; //!< Cross section at each temperature
std::vector<ReactionProduct> products_; //!< Reaction products
};
//==============================================================================
// Fortran compatibility functions
//==============================================================================
extern "C" {
Reaction* reaction_from_hdf5(hid_t group, int* temperatures, int n);
void reaction_delete(Reaction* rx);
int reaction_mt(Reaction* rx);
double reaction_q_value(Reaction* rx);
bool reaction_scatter_in_cm(Reaction* rx);
double reaction_product_decay_rate(Reaction* rx, int product);
int reaction_product_emission_mode(Reaction* rx, int product);
int reaction_product_particle(Reaction* rx, int product);
void reaction_product_sample(Reaction* rx, int product, double E_in,
double* E_out, double* mu);
int reaction_products_size(Reaction* rx);
double reaction_product_yield(Reaction* rx, int product, double E);
double reaction_sample_elastic_mu(Reaction* rx, double E);
double reaction_xs(Reaction* xs, int temperature, int energy);
int reaction_xs_size(Reaction* xs, int temperature);
int reaction_xs_threshold(Reaction* xs, int temperature);
}
} // namespace openmc
#endif // OPENMC_REACTION_H

View file

@ -1,83 +1,268 @@
module reaction_header
use, intrinsic :: ISO_C_BINDING
use constants, only: MAX_WORD_LEN
use hdf5_interface
use product_header, only: ReactionProduct
use stl_vector, only: VectorInt
use string, only: to_str, starts_with
implicit none
private
!===============================================================================
! REACTION contains the cross-section and secondary energy and angle
! distributions for a single reaction in a continuous-energy ACE-format table
!===============================================================================
type TemperatureXS
integer :: threshold ! Energy grid index of threshold
real(8), allocatable :: value(:) ! Cross section values
end type TemperatureXS
type Reaction
integer :: MT ! ENDF MT value
real(8) :: Q_value ! Reaction Q value
logical :: scatter_in_cm ! scattering system in center-of-mass?
type(TemperatureXS), allocatable :: xs(:)
type(ReactionProduct), allocatable :: products(:)
type, public :: Reaction
type(C_PTR) :: ptr
integer(C_INT) :: MT ! ENDF MT value
real(C_DOUBLE) :: Q_value ! Reaction Q value
logical(C_BOOL) :: scatter_in_cm ! scattering system in center-of-mass?
contains
procedure :: from_hdf5 => reaction_from_hdf5
procedure :: from_hdf5
procedure :: mt_
procedure :: q_value_
procedure :: scatter_in_cm_
procedure :: product_decay_rate
procedure :: product_emission_mode
procedure :: product_particle
procedure :: product_sample
procedure :: product_yield
procedure :: products_size
procedure :: sample_elastic_mu
procedure :: xs
procedure :: xs_size
procedure :: xs_threshold
end type Reaction
interface
function reaction_from_hdf5(group, temperatures, n) result(ptr) bind(C)
import C_PTR, HID_T, C_INT
integer(HID_T), value :: group
integer(C_INT), intent(in) :: temperatures
integer(C_INT), value :: n
type(C_PTR) :: ptr
end function
function reaction_mt(ptr) result(mt) bind(C)
import C_PTR, C_INT
type(C_PTR), value :: ptr
integer(C_INT) :: mt
end function
function reaction_q_value(ptr) result(q_value) bind(C)
import C_PTR, C_DOUBLE
type(C_PTR), value :: ptr
real(C_DOUBLE) :: q_value
end function
function reaction_scatter_in_cm(ptr) result(b) bind(C)
import C_PTR, C_BOOL
type(C_PTR), value :: ptr
logical(C_BOOL) :: b
end function
pure function reaction_product_decay_rate(ptr, product) result(rate) bind(C)
import C_PTR, C_INT, C_DOUBLE
type(C_PTR), value :: ptr
integer(C_INT), value :: product
real(C_DOUBLE) :: rate
end function
pure function reaction_product_emission_mode(ptr, product) result(m) bind(C)
import C_PTR, C_INT
type(C_PTR), value :: ptr
integer(C_INT), value :: product
integer(C_INT) :: m
end function
pure function reaction_product_particle(ptr, product) result(particle) bind(C)
import C_PTR, C_INT
type(C_PTR), value :: ptr
integer(C_INT), value :: product
integer(C_INT) :: particle
end function
subroutine reaction_product_sample(ptr, product, E_in, E_out, mu) bind(C)
import C_PTR, C_INT, C_DOUBLE
type(C_PTR), value :: ptr
integer(C_INT), value :: product
real(C_DOUBLE), value :: E_in
real(C_DOUBLE), intent(out) :: E_out
real(C_DOUBLE), intent(out) :: mu
end subroutine
pure function reaction_product_yield(ptr, product, E) result(val) bind(C)
import C_PTR, C_INT, C_DOUBLE
type(C_PTR), value :: ptr
integer(C_INT), value :: product
real(C_DOUBLE), value :: E
real(C_DOUBLE) :: val
end function
pure function reaction_products_size(ptr) result(sz) bind(C)
import C_PTR, C_INT
type(C_PTR), value :: ptr
integer(C_INT) :: sz
end function
function reaction_sample_elastic_mu(ptr, E) result(mu) bind(C)
import C_PTR, C_INT, C_DOUBLE
type(C_PTR), value :: ptr
real(C_DOUBLE), value :: E
real(C_DOUBLE) :: mu
end function
function reaction_xs(ptr, temperature, energy) result(xs) bind(C)
import C_PTR, C_INT, C_DOUBLE
type(C_PTR), value :: ptr
integer(C_INT), value :: temperature
integer(C_INT), value :: energy
real(C_DOUBLE) :: xs
end function
function reaction_xs_size(ptr, temperature) result(sz) bind(C)
import C_PTR, C_INT
type(C_PTR), value :: ptr
integer(C_INT), value :: temperature
integer(C_INT) :: sz
end function
function reaction_xs_threshold(ptr, temperature) result(threshold) bind(C)
import C_PTR, C_INT
type(C_PTR), value :: ptr
integer(C_INT), value :: temperature
integer(C_INT) :: threshold
end function
end interface
contains
subroutine reaction_from_hdf5(this, group_id, temperatures)
subroutine from_hdf5(this, group_id, temperatures)
class(Reaction), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
type(VectorInt), intent(in) :: temperatures
integer :: i
integer :: cm
integer :: n_product
integer(HID_T) :: pgroup
integer(HID_T) :: xs, temp_group
integer(HSIZE_T) :: dims(1)
integer(HSIZE_T) :: j
character(MAX_WORD_LEN) :: temp_str ! temperature dataset name, e.g. '294K'
character(MAX_WORD_LEN), allocatable :: grp_names(:)
integer(C_INT) :: dummy
integer(C_INT) :: n
call read_attribute(this % Q_value, group_id, 'Q_value')
call read_attribute(this % MT, group_id, 'mt')
call read_attribute(cm, group_id, 'center_of_mass')
this % scatter_in_cm = (cm == 1)
n = temperatures % size()
if (n > 0) then
this % ptr = reaction_from_hdf5(group_id, temperatures % data(1), n)
else
! In this case, temperatures % data(1) doesn't exist, so we just pass a
! dummy value
this % ptr = reaction_from_hdf5(group_id, dummy, n)
end if
this % MT = reaction_mt(this % ptr)
this % Q_value = reaction_q_value(this % ptr)
this % scatter_in_cm = reaction_scatter_in_cm(this % ptr)
end subroutine from_hdf5
! Read cross section and threshold_idx data
allocate(this % xs(temperatures % size()))
do i = 1, temperatures % size()
temp_str = trim(to_str(temperatures % data(i))) // "K"
temp_group = open_group(group_id, temp_str)
xs = open_dataset(temp_group, 'xs')
call read_attribute(this % xs(i) % threshold, xs, 'threshold_idx')
call get_shape(xs, dims)
allocate(this % xs(i) % value(dims(1)))
call read_dataset(this % xs(i) % value, xs)
call close_dataset(xs)
call close_group(temp_group)
end do
function mt_(this) result(mt)
class(Reaction), intent(in) :: this
integer(C_INT) :: MT
! Determine number of products
n_product = 0
call get_groups(group_id, grp_names)
do j = 1, size(grp_names)
if (starts_with(grp_names(j), "product_")) n_product = n_product + 1
end do
mt = reaction_mt(this % ptr)
end function
! Read products
allocate(this % products(n_product))
do i = 1, n_product
pgroup = open_group(group_id, 'product_' // trim(to_str(i - 1)))
call this % products(i) % from_hdf5(pgroup)
call close_group(pgroup)
end do
end subroutine reaction_from_hdf5
function q_value_(this) result(q_value)
class(Reaction), intent(in) :: this
real(C_DOUBLE) :: q_value
q_value = reaction_q_value(this % ptr)
end function
function scatter_in_cm_(this) result(cm)
class (Reaction), intent(in) :: this
logical(C_BOOL) :: cm
cm = reaction_scatter_in_cm(this % ptr)
end function
pure function product_decay_rate(this, product) result(rate)
class(Reaction), intent(in) :: this
integer(C_INT), intent(in) :: product
real(C_DOUBLE) :: rate
rate = reaction_product_decay_rate(this % ptr, product)
end function
pure function product_emission_mode(this, product) result(m)
class(Reaction), intent(in) :: this
integer(C_INT), intent(in) :: product
integer(C_INT) :: m
m = reaction_product_emission_mode(this % ptr, product)
end function
pure function product_particle(this, product) result(p)
class(Reaction), intent(in) :: this
integer(C_INT), intent(in) :: product
integer(C_INT) :: p
p = reaction_product_particle(this % ptr, product)
end function
subroutine product_sample(this, product, E_in, E_out, mu)
class(Reaction), intent(in) :: this
integer(C_INT), intent(in) :: product
real(C_DOUBLE), intent(in) :: E_in
real(C_DOUBLE), intent(out) :: E_out
real(C_DOUBLE), intent(out) :: mu
call reaction_product_sample(this % ptr, product, E_in, E_out, mu)
end subroutine
pure function product_yield(this, product, E) result(val)
class(Reaction), intent(in) :: this
integer(C_INT), intent(in) :: product
real(C_DOUBLE), intent(in) :: E
real(C_DOUBLE) :: val
val = reaction_product_yield(this % ptr, product, E)
end function
pure function products_size(this) result(sz)
class(Reaction), intent(in) :: this
integer(C_INT) :: sz
sz = reaction_products_size(this % ptr)
end function
function sample_elastic_mu(this, E) result(mu)
class(Reaction), intent(in) :: this
real(C_DOUBLE), intent(in) :: E
real(C_DOUBLE) :: mu
mu = reaction_sample_elastic_mu(this % ptr, E)
end function
function xs(this, temperature, energy) result(val)
class(Reaction), intent(in) :: this
integer(C_INT), intent(in) :: temperature
integer(C_INT), intent(in) :: energy
real(C_DOUBLE) :: val
val = reaction_xs(this % ptr, temperature, energy)
end function
function xs_size(this, temperature) result(sz)
class(Reaction), intent(in) :: this
integer(C_INT) :: temperature
integer(C_INT) :: sz
sz = reaction_xs_size(this % ptr, temperature)
end function
function xs_threshold(this, temperature) result(val)
class(Reaction), intent(in) :: this
integer(C_INT), intent(in) :: temperature
integer(C_INT) :: val
val = reaction_xs_threshold(this % ptr, temperature)
end function
end module reaction_header

107
src/reaction_product.cpp Normal file
View file

@ -0,0 +1,107 @@
#include "reaction_product.h"
#include <memory> // for unique_ptr
#include <string> // for string
#include "hdf5_interface.h"
#include "random_lcg.h"
#include "secondary_correlated.h"
#include "secondary_kalbach.h"
#include "secondary_nbody.h"
#include "secondary_uncorrelated.h"
namespace openmc {
//==============================================================================
// ReactionProduct implementation
//==============================================================================
ReactionProduct::ReactionProduct(hid_t group)
{
// Read particle type
std::string temp;
read_attribute(group, "particle", temp);
if (temp == "neutron") {
particle_ = ParticleType::neutron;
} else if (temp == "photon") {
particle_ = ParticleType::photon;
}
// Read emission mode and decay rate
read_attribute(group, "emission_mode", temp);
if (temp == "prompt") {
emission_mode_ = EmissionMode::prompt;
} else if (temp == "delayed") {
emission_mode_ = EmissionMode::delayed;
} else if (temp == "total") {
emission_mode_ = EmissionMode::total;
}
// Read decay rate for delayed emission
if (emission_mode_ == EmissionMode::delayed)
read_attribute(group, "decay_rate", decay_rate_);
// Read secondary particle yield
hid_t yield = open_dataset(group, "yield");
read_attribute(yield, "type", temp);
if (temp == "Tabulated1D") {
yield_ = std::unique_ptr<Function1D>{new Tabulated1D{yield}};
} else if (temp == "Polynomial") {
yield_ = std::unique_ptr<Function1D>{new Polynomial{yield}};
}
close_dataset(yield);
int n;
read_attribute(group, "n_distribution", n);
for (int i = 0; i < n; ++i) {
std::string s {"distribution_"};
s.append(std::to_string(i));
hid_t dgroup = open_group(group, s.c_str());
// Read applicability
if (n > 1) {
hid_t app = open_dataset(dgroup, "applicability");
applicability_.emplace_back(app);
close_dataset(app);
}
// Determine distribution type and read data
read_attribute(dgroup, "type", temp);
if (temp == "uncorrelated") {
distribution_.emplace_back(new UncorrelatedAngleEnergy{dgroup});
} else if (temp == "correlated") {
distribution_.emplace_back(new CorrelatedAngleEnergy{dgroup});
} else if (temp == "nbody") {
distribution_.emplace_back(new NBodyPhaseSpace{dgroup});
} else if (temp == "kalbach-mann") {
distribution_.emplace_back(new KalbachMann{dgroup});
}
close_group(dgroup);
}
}
void ReactionProduct::sample(double E_in, double& E_out, double& mu) const
{
auto n = applicability_.size();
if (n > 1) {
double prob = 0.0;
double c = prn();
for (int i = 0; i < n; ++i) {
// Determine probability that i-th energy distribution is sampled
prob += applicability_[i](E_in);
// If i-th distribution is sampled, sample energy from the distribution
if (c <= prob) {
distribution_[i]->sample(E_in, E_out, mu);
break;
}
}
} else {
// If only one distribution is present, go ahead and sample it
distribution_[0]->sample(E_in, E_out, mu);
}
}
}

56
src/reaction_product.h Normal file
View file

@ -0,0 +1,56 @@
//! \file reaction_product.h
//! Data for a reaction product
#ifndef OPENMC_REACTION_PRODUCT_H
#define OPENMC_REACTION_PRODUCT_H
#include <memory> // for unique_ptr
#include <vector> // for vector
#include "hdf5.h"
#include "angle_energy.h"
#include "endf.h"
#include "particle.h"
namespace openmc {
//==============================================================================
//! Data for a reaction product including its yield and angle-energy
//! distributions, each of which has a given probability of occurring for a
//! given incoming energy. In general, most products only have one angle-energy
//! distribution, but for some cases (e.g., (n,2n) in certain nuclides) multiple
//! distinct distributions exist.
//==============================================================================
class ReactionProduct {
public:
//! Emission mode for product
enum class EmissionMode {
prompt, // Prompt emission of secondary particle
total, // Delayed emission of secondary particle
delayed // Yield represents total emission (prompt + delayed)
};
using Secondary = std::unique_ptr<AngleEnergy>;
//! Construct reaction product from HDF5 data
//! \param[in] group HDF5 group containing data
explicit ReactionProduct(hid_t group);
//! Sample an outgoing angle and energy
//! \param[in] E_in Incoming energy in [eV]
//! \param[out] E_out Outgoing energy in [eV]
//! \param[out] mu Outgoing cosine with respect to current direction
void sample(double E_in, double& E_out, double& mu) const;
ParticleType particle_; //!< Particle type
EmissionMode emission_mode_; //!< Emission mode
double decay_rate_; //!< Decay rate (for delayed neutron precursors) in [1/s]
std::unique_ptr<Function1D> yield_; //!< Yield as a function of energy
std::vector<Tabulated1D> applicability_; //!< Applicability of distribution
std::vector<Secondary> distribution_; //!< Secondary angle-energy distribution
};
} // namespace opemc
#endif // OPENMC_REACTION_PRODUCT_H

View file

@ -18,6 +18,8 @@ class ScattDataTabular;
//==============================================================================
class ScattData {
public:
virtual ~ScattData() = default;
protected:
//! \brief Initializes the attributes of the base class.
void

23
src/search.h Normal file
View file

@ -0,0 +1,23 @@
//! \file search.h
//! Search algorithms
#ifndef OPENMC_SEARCH_H
#define OPENMC_SEARCH_H
#include <algorithm> // for lower_bound
namespace openmc {
//! Perform binary search
template<class It, class T>
typename std::iterator_traits<It>::difference_type
lower_bound_index(It first, It last, const T& value)
{
It index = std::lower_bound(first, last, value) - 1;
return (index == last) ? -1 : index - first;
}
} // namespace openmc
#endif // OPENMC_SEARCH_H

View file

@ -0,0 +1,244 @@
#include "secondary_correlated.h"
#include <algorithm> // for copy
#include <cmath>
#include <cstddef> // for size_t
#include <iterator> // for back_inserter
#include "hdf5_interface.h"
#include "xtensor/xarray.hpp"
#include "xtensor/xview.hpp"
#include "endf.h"
#include "random_lcg.h"
#include "search.h"
namespace openmc {
//==============================================================================
//! CorrelatedAngleEnergy implementation
//==============================================================================
CorrelatedAngleEnergy::CorrelatedAngleEnergy(hid_t group)
{
// Open incoming energy dataset
hid_t dset = open_dataset(group, "energy");
// Get interpolation parameters
xt::xarray<int> temp;
read_attribute(dset, "interpolation", temp);
auto temp_b = xt::view(temp, 0); // view of breakpoints
auto temp_i = xt::view(temp, 1); // view of interpolation parameters
std::copy(temp_b.begin(), temp_b.end(), std::back_inserter(breakpoints_));
for (const auto i : temp_i)
interpolation_.push_back(int2interp(i));
n_region_ = breakpoints_.size();
// Get incoming energies
read_dataset(dset, energy_);
std::size_t n_energy = energy_.size();
close_dataset(dset);
// Get outgoing energy distribution data
dset = open_dataset(group, "energy_out");
std::vector<int> offsets;
std::vector<int> interp;
std::vector<int> n_discrete;
read_attribute(dset, "offsets", offsets);
read_attribute(dset, "interpolation", interp);
read_attribute(dset, "n_discrete_lines", n_discrete);
xt::xarray<double> eout;
read_dataset(dset, eout);
close_dataset(dset);
// Read angle distributions
xt::xarray<double> mu;
read_dataset(group, "mu", mu);
for (int i = 0; i < n_energy; ++i) {
// Determine number of outgoing energies
int j = offsets[i];
int n;
if (i < n_energy - 1) {
n = offsets[i+1] - j;
} else {
n = eout.shape()[1] - j;
}
// Assign interpolation scheme and number of discrete lines
CorrTable d;
d.interpolation = int2interp(interp[i]);
d.n_discrete = n_discrete[i];
// Copy data
d.e_out = xt::view(eout, 0, xt::range(j, j+n));
d.p = xt::view(eout, 1, xt::range(j, j+n));
d.c = xt::view(eout, 2, xt::range(j, j+n));
// To get answers that match ACE data, for now we still use the tabulated
// CDF values that were passed through to the HDF5 library. At a later
// time, we can remove the CDF values from the HDF5 library and
// reconstruct them using the PDF
if (false) {
// Calculate cumulative distribution function -- discrete portion
for (int k = 0; k < d.n_discrete; ++k) {
if (k == 0) {
d.c[k] = d.p[k];
} else {
d.c[k] = d.c[k-1] + d.p[k];
}
}
// Continuous portion
for (int k = d.n_discrete; k < n; ++k) {
if (k == d.n_discrete) {
d.c[k] = d.c[k-1] + d.p[k];
} else {
if (d.interpolation == Interpolation::histogram) {
d.c[k] = d.c[k-1] + d.p[k-1]*(d.e_out[k] - d.e_out[k-1]);
} else if (d.interpolation == Interpolation::lin_lin) {
d.c[k] = d.c[k-1] + 0.5*(d.p[k-1] + d.p[k]) *
(d.e_out[k] - d.e_out[k-1]);
}
}
}
// Normalize density and distribution functions
d.p /= d.c[n - 1];
d.c /= d.c[n - 1];
}
for (j = 0; j < n; ++j) {
// Get interpolation scheme
int interp_mu = std::lround(eout(3, offsets[i] + j));
// Determine offset and size of distribution
int offset_mu = std::lround(eout(4, offsets[i] + j));
int m;
if (offsets[i] + j + 1 < eout.shape()[1]) {
m = std::lround(eout(4, offsets[i]+j+1)) - offset_mu;
} else {
m = mu.shape()[1] - offset_mu;
}
auto interp = int2interp(interp_mu);
auto xs = xt::view(mu, 0, xt::range(offset_mu, offset_mu + m));
auto ps = xt::view(mu, 1, xt::range(offset_mu, offset_mu + m));
auto cs = xt::view(mu, 2, xt::range(offset_mu, offset_mu + m));
std::vector<double> x {xs.begin(), xs.end()};
std::vector<double> p {ps.begin(), ps.end()};
std::vector<double> c {cs.begin(), cs.end()};
// To get answers that match ACE data, for now we still use the tabulated
// CDF values that were passed through to the HDF5 library. At a later
// time, we can remove the CDF values from the HDF5 library and
// reconstruct them using the PDF
Tabular* mudist = new Tabular{x.data(), p.data(), m, interp, c.data()};
d.angle.emplace_back(mudist);
} // outgoing energies
distribution_.push_back(std::move(d));
} // incoming energies
}
void CorrelatedAngleEnergy::sample(double E_in, double& E_out, double& mu) const
{
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Before the secondary distribution refactor, an isotropic polar cosine was
// always sampled but then overwritten with the polar cosine sampled from the
// correlated distribution. To preserve the random number stream, we keep
// this dummy sampling here but can remove it later (will change answers)
mu = 2.0*prn() - 1.0;
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Find energy bin and calculate interpolation factor -- if the energy is
// outside the range of the tabulated energies, choose the first or last bins
auto n_energy_in = energy_.size();
int i;
double r;
if (E_in < energy_[0]) {
i = 0;
r = 0.0;
} else if (E_in > energy_[n_energy_in - 1]) {
i = n_energy_in - 2;
r = 1.0;
} else {
i = lower_bound_index(energy_.begin(), energy_.end(), E_in);
r = (E_in - energy_[i]) / (energy_[i+1] - energy_[i]);
}
// Sample between the ith and [i+1]th bin
int l = r > prn() ? i + 1 : i;
// Interpolation for energy E1 and EK
int n_energy_out = distribution_[i].e_out.size();
double E_i_1 = distribution_[i].e_out[0];
double E_i_K = distribution_[i].e_out[n_energy_out - 1];
n_energy_out = distribution_[i+1].e_out.size();
double E_i1_1 = distribution_[i+1].e_out[0];
double E_i1_K = distribution_[i+1].e_out[n_energy_out - 1];
double E_1 = E_i_1 + r*(E_i1_1 - E_i_1);
double E_K = E_i_K + r*(E_i1_K - E_i_K);
// Determine outgoing energy bin
n_energy_out = distribution_[l].e_out.size();
double r1 = prn();
double c_k = distribution_[l].c[0];
double c_k1;
int k;
for (k = 0; k < n_energy_out - 2; ++k) {
c_k1 = distribution_[l].c[k+1];
if (r1 < c_k1) break;
c_k = c_k1;
}
// Check to make sure 1 <= k <= NP - 1
k = std::max(0, std::min(k, n_energy_out - 2));
double E_l_k = distribution_[l].e_out[k];
double p_l_k = distribution_[l].p[k];
if (distribution_[l].interpolation == Interpolation::histogram) {
// Histogram interpolation
if (p_l_k > 0.0) {
E_out = E_l_k + (r1 - c_k)/p_l_k;
} else {
E_out = E_l_k;
}
} else if (distribution_[l].interpolation == Interpolation::lin_lin) {
// Linear-linear interpolation
double E_l_k1 = distribution_[l].e_out[k+1];
double p_l_k1 = distribution_[l].p[k+1];
double frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k);
if (frac == 0.0) {
E_out = E_l_k + (r1 - c_k)/p_l_k;
} else {
E_out = E_l_k + (std::sqrt(std::max(0.0, p_l_k*p_l_k +
2.0*frac*(r1 - c_k))) - p_l_k)/frac;
}
}
// Now interpolate between incident energy bins i and i + 1
if (l == i) {
E_out = E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1);
} else {
E_out = E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1);
}
// Find correlated angular distribution for closest outgoing energy bin
if (r1 - c_k < c_k1 - r1) {
mu = distribution_[l].angle[k]->sample();
} else {
mu = distribution_[l].angle[k + 1]->sample();
}
}
} // namespace openmc

View file

@ -0,0 +1,52 @@
//! \file secondary_correlated.h
//! Correlated angle-energy distribution
#ifndef OPENMC_SECONDARY_CORRELATED_H
#define OPENMC_SECONDARY_CORRELATED_H
#include <vector>
#include "hdf5.h"
#include "xtensor/xtensor.hpp"
#include "angle_energy.h"
#include "endf.h"
#include "distribution.h"
namespace openmc {
//==============================================================================
//! Correlated angle-energy distribution corresponding to ACE law 61 and ENDF
//! File 6, LAW=1, LANG!=2.
//==============================================================================
class CorrelatedAngleEnergy : public AngleEnergy {
public:
explicit CorrelatedAngleEnergy(hid_t group);
//! Sample distribution for an angle and energy
//! \param[in] E_in Incoming energy in [eV]
//! \param[out] E_out Outgoing energy in [eV]
//! \param[out] mu Outgoing cosine with respect to current direction
void sample(double E_in, double& E_out, double& mu) const;
private:
//! Outgoing energy/angle at a single incoming energy
struct CorrTable {
int n_discrete; //!< Number of discrete lines
Interpolation interpolation; //!< Interpolation law
xt::xtensor<double, 1> e_out; //!< Outgoing energies [eV]
xt::xtensor<double, 1> p; //!< Probability density
xt::xtensor<double, 1> c; //!< Cumulative distribution
std::vector<UPtrDist> angle; //!< Angle distribution
};
int n_region_; //!< Number of interpolation regions
std::vector<int> breakpoints_; //!< Breakpoints between regions
std::vector<Interpolation> interpolation_; //!< Interpolation laws
std::vector<double> energy_; //!< Energies [eV] at which distributions
//!< are tabulated
std::vector<CorrTable> distribution_; //!< Distribution at each energy
};
} // namespace openmc
#endif // OPENMC_SECONDARY_CORRELATED_H

View file

@ -1,278 +0,0 @@
module secondary_kalbach
use algorithm, only: binary_search
use angleenergy_header, only: AngleEnergy
use constants, only: ZERO, HALF, ONE, TWO, HISTOGRAM, LINEAR_LINEAR
use hdf5_interface
use random_lcg, only: prn
!===============================================================================
! KalbachMann represents a correlated angle-energy distribution with the angular
! distribution represented using Kalbach-Mann systematics. This corresponds to
! ACE law 44 and ENDF File 6, LAW=1, LANG=2.
!===============================================================================
type KalbachMannTable
integer :: n_discrete
integer :: interpolation
real(8), allocatable :: e_out(:)
real(8), allocatable :: p(:)
real(8), allocatable :: c(:)
real(8), allocatable :: r(:)
real(8), allocatable :: a(:)
end type KalbachMannTable
type, extends(AngleEnergy) :: KalbachMann
integer :: n_region ! number of interpolation regions
integer, allocatable :: breakpoints(:) ! breakpoints of interpolation regions
integer, allocatable :: interpolation(:) ! interpolation region codes
real(8), allocatable :: energy(:) ! incoming energies
type(KalbachMannTable), allocatable :: distribution(:) ! outgoing E/mu parameters
contains
procedure :: sample => kalbachmann_sample
procedure :: from_hdf5 => kalbachmann_from_hdf5
end type KalbachMann
contains
subroutine kalbachmann_sample(this, E_in, E_out, mu)
class(KalbachMann), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8), intent(out) :: E_out ! sampled outgoing energy
real(8), intent(out) :: mu ! sampled scattering cosine
integer :: i, k, l ! indices
integer :: n_energy_in ! number of incoming energies
integer :: n_energy_out ! number of outgoing energies
real(8) :: r ! interpolation factor on incoming energy
real(8) :: r1 ! random number on [0,1)
real(8) :: frac ! interpolation factor on outgoing energy
real(8) :: E_i_1, E_i_K ! endpoints on outgoing grid i
real(8) :: E_i1_1, E_i1_K ! endpoints on outgoing grid i+1
real(8) :: E_1, E_K ! endpoints interpolated between i and i+1
real(8) :: E_l_k, E_l_k1 ! adjacent E on outgoing grid l
real(8) :: p_l_k, p_l_k1 ! adjacent p on outgoing grid l
real(8) :: c_k, c_k1 ! cumulative probability
real(8) :: km_r, km_a ! Kalbach-Mann parameters
real(8) :: T
! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
! Before the secondary distribution refactor, an isotropic polar cosine was
! always sampled but then overwritten with the polar cosine sampled from the
! correlated distribution. To preserve the random number stream, we keep
! this dummy sampling here but can remove it later (will change answers)
mu = TWO*prn() - ONE
! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
! find energy bin and calculate interpolation factor -- if the energy is
! outside the range of the tabulated energies, choose the first or last bins
n_energy_in = size(this%energy)
if (E_in < this%energy(1)) then
i = 1
r = ZERO
elseif (E_in > this%energy(n_energy_in)) then
i = n_energy_in - 1
r = ONE
else
i = binary_search(this%energy, n_energy_in, E_in)
r = (E_in - this%energy(i)) / &
(this%energy(i+1) - this%energy(i))
end if
! Sample between the ith and (i+1)th bin
if (r > prn()) then
l = i + 1
else
l = i
end if
! interpolation for energy E1 and EK
n_energy_out = size(this%distribution(i)%e_out)
E_i_1 = this%distribution(i)%e_out(1)
E_i_K = this%distribution(i)%e_out(n_energy_out)
n_energy_out = size(this%distribution(i+1)%e_out)
E_i1_1 = this%distribution(i+1)%e_out(1)
E_i1_K = this%distribution(i+1)%e_out(n_energy_out)
E_1 = E_i_1 + r*(E_i1_1 - E_i_1)
E_K = E_i_K + r*(E_i1_K - E_i_K)
! determine outgoing energy bin
n_energy_out = size(this%distribution(l)%e_out)
r1 = prn()
c_k = this%distribution(l)%c(1)
do k = 1, n_energy_out - 1
c_k1 = this%distribution(l)%c(k+1)
if (r1 < c_k1) exit
c_k = c_k1
end do
! check to make sure k is <= NP - 1
k = min(k, n_energy_out - 1)
E_l_k = this%distribution(l)%e_out(k)
p_l_k = this%distribution(l)%p(k)
if (this%distribution(l)%interpolation == HISTOGRAM) then
! Histogram interpolation
if (p_l_k > ZERO) then
E_out = E_l_k + (r1 - c_k)/p_l_k
else
E_out = E_l_k
end if
! Determine Kalbach-Mann parameters
km_r = this%distribution(l)%r(k)
km_a = this%distribution(l)%a(k)
elseif (this%distribution(l)%interpolation == LINEAR_LINEAR) then
! Linear-linear interpolation
E_l_k1 = this%distribution(l)%e_out(k+1)
p_l_k1 = this%distribution(l)%p(k+1)
frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k)
if (frac == ZERO) then
E_out = E_l_k + (r1 - c_k)/p_l_k
else
E_out = E_l_k + (sqrt(max(ZERO, p_l_k*p_l_k + &
TWO*frac*(r1 - c_k))) - p_l_k)/frac
end if
! Determine Kalbach-Mann parameters
km_r = this%distribution(l)%r(k) + (E_out - E_l_k)/(E_l_k1 - E_l_k) * &
(this%distribution(l)%r(k+1) - this%distribution(l)%r(k))
km_a = this%distribution(l)%a(k) + (E_out - E_l_k)/(E_l_k1 - E_l_k) * &
(this%distribution(l)%a(k+1) - this%distribution(l)%a(k))
end if
! Now interpolate between incident energy bins i and i + 1
if (l == i) then
E_out = E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1)
else
E_out = E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1)
end if
! Sampled correlated angle from Kalbach-Mann parameters
if (prn() > km_r) then
T = (TWO*prn() - ONE) * sinh(km_a)
mu = log(T + sqrt(T*T + ONE))/km_a
else
r1 = prn()
mu = log(r1*exp(km_a) + (ONE - r1)*exp(-km_a))/km_a
end if
end subroutine kalbachmann_sample
subroutine kalbachmann_from_hdf5(this, group_id)
class(KalbachMann), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer :: i, j, k
integer :: n
integer :: n_energy
integer(HID_T) :: dset_id
integer(HSIZE_T) :: dims(1), dims2(2)
integer, allocatable :: temp(:,:)
integer, allocatable :: offsets(:)
integer, allocatable :: interp(:)
integer, allocatable :: n_discrete(:)
real(8), allocatable :: eout(:,:)
! Open incoming energy dataset
dset_id = open_dataset(group_id, 'energy')
! Get interpolation parameters
call read_attribute(temp, dset_id, 'interpolation')
allocate(this%breakpoints(size(temp, 1)))
allocate(this%interpolation(size(temp, 1)))
this%breakpoints(:) = temp(:, 1)
this%interpolation(:) = temp(:, 2)
this%n_region = size(this%breakpoints)
! Get incoming energies
call get_shape(dset_id, dims)
n_energy = int(dims(1), 4)
allocate(this%energy(n_energy))
allocate(this%distribution(n_energy))
call read_dataset(this%energy, dset_id)
call close_dataset(dset_id)
! Get outgoing energy distribution data
dset_id = open_dataset(group_id, 'distribution')
call read_attribute(offsets, dset_id, 'offsets')
call read_attribute(interp, dset_id, 'interpolation')
call read_attribute(n_discrete, dset_id, 'n_discrete_lines')
call get_shape(dset_id, dims2)
allocate(eout(dims2(1), dims2(2)))
call read_dataset(eout, dset_id)
call close_dataset(dset_id)
do i = 1, n_energy
! Determine number of outgoing energies
j = offsets(i)
if (i < n_energy) then
n = offsets(i+1) - j
else
n = size(eout, 1) - j
end if
associate (d => this%distribution(i))
! Assign interpolation scheme and number of discrete lines
d % interpolation = interp(i)
d % n_discrete = n_discrete(i)
! Allocate arrays for energies and PDF/CDF
allocate(d % e_out(n))
allocate(d % p(n))
allocate(d % c(n))
allocate(d % r(n))
allocate(d % a(n))
! Copy data
d % e_out(:) = eout(j+1:j+n, 1)
d % p(:) = eout(j+1:j+n, 2)
d % c(:) = eout(j+1:j+n, 3)
d % r(:) = eout(j+1:j+n, 4)
d % a(:) = eout(j+1:j+n, 5)
! To get answers that match ACE data, for now we still use the tabulated
! CDF values that were passed through to the HDF5 library. At a later
! time, we can remove the CDF values from the HDF5 library and
! reconstruct them using the PDF
if (.false.) then
! Calculate cumulative distribution function -- discrete portion
do k = 1, d % n_discrete
if (k == 1) then
d % c(k) = d % p(k)
else
d % c(k) = d % c(k-1) + d % p(k)
end if
end do
! Continuous portion
do k = d % n_discrete + 1, n
if (k == d % n_discrete + 1) then
d % c(k) = sum(d % p(1:d % n_discrete))
else
if (d % interpolation == HISTOGRAM) then
d % c(k) = d % c(k-1) + d % p(k-1) * &
(d % e_out(k) - d % e_out(k-1))
elseif (d % interpolation == LINEAR_LINEAR) then
d % c(k) = d % c(k-1) + HALF*(d % p(k-1) + d % p(k)) * &
(d % e_out(k) - d % e_out(k-1))
end if
end if
end do
! Normalize density and distribution functions
d % p(:) = d % p(:)/d % c(n)
d % c(:) = d % c(:)/d % c(n)
end if
end associate
j = j + n
end do
end subroutine kalbachmann_from_hdf5
end module secondary_kalbach

223
src/secondary_kalbach.cpp Normal file
View file

@ -0,0 +1,223 @@
#include "secondary_kalbach.h"
#include <algorithm> // for copy, move
#include <cmath> // for log, sqrt, sinh
#include <cstddef> // for size_t
#include <iterator> // for back_inserter
#include <vector>
#include "xtensor/xarray.hpp"
#include "xtensor/xview.hpp"
#include "hdf5_interface.h"
#include "random_lcg.h"
#include "search.h"
namespace openmc {
//==============================================================================
//! KalbachMann implementation
//==============================================================================
KalbachMann::KalbachMann(hid_t group)
{
// Open incoming energy dataset
hid_t dset = open_dataset(group, "energy");
// Get interpolation parameters
xt::xarray<int> temp;
read_attribute(dset, "interpolation", temp);
auto temp_b = xt::view(temp, 0); // view of breakpoints
auto temp_i = xt::view(temp, 1); // view of interpolation parameters
std::copy(temp_b.begin(), temp_b.end(), std::back_inserter(breakpoints_));
for (const auto i : temp_i)
interpolation_.push_back(int2interp(i));
n_region_ = breakpoints_.size();
// Get incoming energies
read_dataset(dset, energy_);
std::size_t n_energy = energy_.size();
close_dataset(dset);
// Get outgoing energy distribution data
dset = open_dataset(group, "distribution");
std::vector<int> offsets;
std::vector<int> interp;
std::vector<int> n_discrete;
read_attribute(dset, "offsets", offsets);
read_attribute(dset, "interpolation", interp);
read_attribute(dset, "n_discrete_lines", n_discrete);
xt::xarray<double> eout;
read_dataset(dset, eout);
close_dataset(dset);
for (int i = 0; i < n_energy; ++i) {
// Determine number of outgoing energies
int j = offsets[i];
int n;
if (i < n_energy - 1) {
n = offsets[i+1] - j;
} else {
n = eout.shape()[1] - j;
}
// Assign interpolation scheme and number of discrete lines
KMTable d;
d.interpolation = int2interp(interp[i]);
d.n_discrete = n_discrete[i];
// Copy data
d.e_out = xt::view(eout, 0, xt::range(j, j+n));
d.p = xt::view(eout, 1, xt::range(j, j+n));
d.c = xt::view(eout, 2, xt::range(j, j+n));
d.r = xt::view(eout, 3, xt::range(j, j+n));
d.a = xt::view(eout, 4, xt::range(j, j+n));
// To get answers that match ACE data, for now we still use the tabulated
// CDF values that were passed through to the HDF5 library. At a later
// time, we can remove the CDF values from the HDF5 library and
// reconstruct them using the PDF
if (false) {
// Calculate cumulative distribution function -- discrete portion
for (int k = 0; k < d.n_discrete; ++k) {
if (k == 0) {
d.c[k] = d.p[k];
} else {
d.c[k] = d.c[k-1] + d.p[k];
}
}
// Continuous portion
for (int k = d.n_discrete; k < n; ++k) {
if (k == d.n_discrete) {
d.c[k] = d.c[k-1] + d.p[k];
} else {
if (d.interpolation == Interpolation::histogram) {
d.c[k] = d.c[k-1] + d.p[k-1]*(d.e_out[k] - d.e_out[k-1]);
} else if (d.interpolation == Interpolation::lin_lin) {
d.c[k] = d.c[k-1] + 0.5*(d.p[k-1] + d.p[k]) *
(d.e_out[k] - d.e_out[k-1]);
}
}
}
// Normalize density and distribution functions
d.p /= d.c[n - 1];
d.c /= d.c[n - 1];
}
distribution_.push_back(std::move(d));
} // incoming energies
}
void KalbachMann::sample(double E_in, double& E_out, double& mu) const
{
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Before the secondary distribution refactor, an isotropic polar cosine was
// always sampled but then overwritten with the polar cosine sampled from the
// correlated distribution. To preserve the random number stream, we keep
// this dummy sampling here but can remove it later (will change answers)
mu = 2.0*prn() - 1.0;
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// Find energy bin and calculate interpolation factor -- if the energy is
// outside the range of the tabulated energies, choose the first or last bins
auto n_energy_in = energy_.size();
int i;
double r;
if (E_in < energy_[0]) {
i = 0;
r = 0.0;
} else if (E_in > energy_[n_energy_in - 1]) {
i = n_energy_in - 2;
r = 1.0;
} else {
i = lower_bound_index(energy_.begin(), energy_.end(), E_in);
r = (E_in - energy_[i]) / (energy_[i+1] - energy_[i]);
}
// Sample between the ith and [i+1]th bin
int l = r > prn() ? i + 1 : i;
// Interpolation for energy E1 and EK
int n_energy_out = distribution_[i].e_out.size();
double E_i_1 = distribution_[i].e_out[0];
double E_i_K = distribution_[i].e_out[n_energy_out - 1];
n_energy_out = distribution_[i+1].e_out.size();
double E_i1_1 = distribution_[i+1].e_out[0];
double E_i1_K = distribution_[i+1].e_out[n_energy_out - 1];
double E_1 = E_i_1 + r*(E_i1_1 - E_i_1);
double E_K = E_i_K + r*(E_i1_K - E_i_K);
// Determine outgoing energy bin
n_energy_out = distribution_[l].e_out.size();
double r1 = prn();
double c_k = distribution_[l].c[0];
double c_k1;
int k;
for (k = 0; k < n_energy_out - 2; ++k) {
c_k1 = distribution_[l].c[k+1];
if (r1 < c_k1) break;
c_k = c_k1;
}
// Check to make sure 1 <= k <= NP - 1
k = std::max(0, std::min(k, n_energy_out - 2));
double E_l_k = distribution_[l].e_out[k];
double p_l_k = distribution_[l].p[k];
double km_r, km_a;
if (distribution_[l].interpolation == Interpolation::histogram) {
// Histogram interpolation
if (p_l_k > 0.0) {
E_out = E_l_k + (r1 - c_k)/p_l_k;
} else {
E_out = E_l_k;
}
// Determine Kalbach-Mann parameters
km_r = distribution_[l].r[k];
km_a = distribution_[l].a[k];
} else if (distribution_[l].interpolation == Interpolation::lin_lin) {
// Linear-linear interpolation
double E_l_k1 = distribution_[l].e_out[k+1];
double p_l_k1 = distribution_[l].p[k+1];
double frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k);
if (frac == 0.0) {
E_out = E_l_k + (r1 - c_k)/p_l_k;
} else {
E_out = E_l_k + (std::sqrt(std::max(0.0, p_l_k*p_l_k +
2.0*frac*(r1 - c_k))) - p_l_k)/frac;
}
// Determine Kalbach-Mann parameters
km_r = distribution_[l].r[k] + (E_out - E_l_k)/(E_l_k1 - E_l_k) *
(distribution_[l].r[k+1] - distribution_[l].r[k]);
km_a = distribution_[l].a[k] + (E_out - E_l_k)/(E_l_k1 - E_l_k) *
(distribution_[l].a[k+1] - distribution_[l].a[k]);
}
// Now interpolate between incident energy bins i and i + 1
if (l == i) {
E_out = E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1);
} else {
E_out = E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1);
}
// Sampled correlated angle from Kalbach-Mann parameters
if (prn() > km_r) {
double T = (2.0*prn() - 1.0) * std::sinh(km_a);
mu = std::log(T + std::sqrt(T*T + 1.0))/km_a;
} else {
double r1 = prn();
mu = std::log(r1*std::exp(km_a) + (1.0 - r1)*std::exp(-km_a))/km_a;
}
}
}

54
src/secondary_kalbach.h Normal file
View file

@ -0,0 +1,54 @@
//! \file secondary_kalbach.h
//! Kalbach-Mann angle-energy distribution
#ifndef OPENMC_SECONDARY_KALBACH_H
#define OPENMC_SECONDARY_KALBACH_H
#include <vector>
#include "hdf5.h"
#include "xtensor/xtensor.hpp"
#include "angle_energy.h"
#include "constants.h"
#include "endf.h"
namespace openmc {
//==============================================================================
//! Correlated angle-energy distribution with the angular distribution
//! represented using Kalbach-Mann systematics. This corresponds to ACE law 44
//! and ENDF File 6, LAW=1, LANG=2.
//==============================================================================
class KalbachMann : public AngleEnergy {
public:
explicit KalbachMann(hid_t group);
//! Sample distribution for an angle and energy
//! \param[in] E_in Incoming energy in [eV]
//! \param[out] E_out Outgoing energy in [eV]
//! \param[out] mu Outgoing cosine with respect to current direction
void sample(double E_in, double& E_out, double& mu) const;
private:
//! Outgoing energy/angle at a single incoming energy
struct KMTable {
int n_discrete; //!< Number of discrete lines
Interpolation interpolation; //!< Interpolation law
xt::xtensor<double, 1> e_out; //!< Outgoing energies [eV]
xt::xtensor<double, 1> p; //!< Probability density
xt::xtensor<double, 1> c; //!< Cumulative distribution
xt::xtensor<double, 1> r; //!< Pre-compound fraction
xt::xtensor<double, 1> a; //!< Parameterized function
};
int n_region_; //!< Number of interpolation regions
std::vector<int> breakpoints_; //!< Breakpoints between regions
std::vector<Interpolation> interpolation_; //!< Interpolation laws
std::vector<double> energy_; //!< Energies [eV] at which distributions
//!< are tabulated
std::vector<KMTable> distribution_; //!< Distribution at each energy
};
} // namespace openmc
#endif // OPENMC_SECONDARY_KALBACH_H

View file

@ -1,82 +0,0 @@
module secondary_nbody
use angleenergy_header, only: AngleEnergy
use constants, only: ONE, TWO, PI
use hdf5_interface, only: read_attribute, HID_T
use math, only: maxwell_spectrum
use random_lcg, only: prn
!===============================================================================
! NBODYPHASESPACE gives the energy distribution for particles emitted from
! neutron and charged-particle reactions. This corresponds to ACE law 66 and
! ENDF File 6, LAW=6.
!===============================================================================
type, extends(AngleEnergy) :: NBodyPhaseSpace
integer :: n_bodies
real(8) :: mass_ratio
real(8) :: A
real(8) :: Q
contains
procedure :: sample => nbody_sample
procedure :: from_hdf5 => nbody_from_hdf5
end type NBodyPhaseSpace
contains
subroutine nbody_sample(this, E_in, E_out, mu)
class(NBodyPhaseSpace), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8), intent(out) :: E_out ! sampled outgoing energy
real(8), intent(out) :: mu ! sampled outgoing energy
real(8) :: Ap ! total mass of particles in neutron masses
real(8) :: E_max ! maximum possible COM energy
real(8) :: x, y, v
real(8) :: r1, r2, r3, r4, r5, r6
! By definition, the distribution of the angle is isotropic for an N-body
! phase space distribution
mu = TWO*prn() - ONE
! Determine E_max parameter
Ap = this%mass_ratio
E_max = (Ap - ONE)/Ap * (this%A/(this%A + ONE)*E_in + this%Q)
! x is essentially a Maxwellian distribution
x = maxwell_spectrum(ONE)
select case (this%n_bodies)
case (3)
y = maxwell_spectrum(ONE)
case (4)
r1 = prn()
r2 = prn()
r3 = prn()
y = -log(r1*r2*r3)
case (5)
r1 = prn()
r2 = prn()
r3 = prn()
r4 = prn()
r5 = prn()
r6 = prn()
y = -log(r1*r2*r3*r4) - log(r5) * cos(PI/TWO*r6)**2
end select
! Now determine v and E_out
v = x/(x+y)
E_out = E_max * v
end subroutine nbody_sample
subroutine nbody_from_hdf5(this, group_id)
class(NBodyPhaseSpace), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
call read_attribute(this%mass_ratio, group_id, 'total_mass')
call read_attribute(this%n_bodies, group_id, 'n_particles')
call read_attribute(this%A, group_id, 'atomic_weight_ratio')
call read_attribute(this%Q, group_id, 'q_value')
end subroutine nbody_from_hdf5
end module secondary_nbody

65
src/secondary_nbody.cpp Normal file
View file

@ -0,0 +1,65 @@
#include "secondary_nbody.h"
#include <cmath> // for log
#include "constants.h"
#include "hdf5_interface.h"
#include "math_functions.h"
#include "random_lcg.h"
namespace openmc {
//==============================================================================
// NBodyPhaseSpace implementation
//==============================================================================
NBodyPhaseSpace::NBodyPhaseSpace(hid_t group)
{
read_attribute(group, "n_particles", n_bodies_);
read_attribute(group, "total_mass", mass_ratio_);
read_attribute(group, "atomic_weight_ratio", A_);
read_attribute(group, "q_value", Q_);
}
void NBodyPhaseSpace::sample(double E_in, double& E_out, double& mu) const
{
// By definition, the distribution of the angle is isotropic for an N-body
// phase space distribution
mu = 2.0*prn() - 1.0;
// Determine E_max parameter
double Ap = mass_ratio_;
double E_max = (Ap - 1.0)/Ap * (A_/(A_ + 1.0)*E_in + Q_);
// x is essentially a Maxwellian distribution
double x = maxwell_spectrum_c(1.0);
double y;
double r1, r2, r3, r4, r5, r6;
switch (n_bodies_) {
case 3:
y = maxwell_spectrum_c(1.0);
break;
case 4:
r1 = prn();
r2 = prn();
r3 = prn();
y = -std::log(r1*r2*r3);
break;
case 5:
r1 = prn();
r2 = prn();
r3 = prn();
r4 = prn();
r5 = prn();
r6 = prn();
y = -std::log(r1*r2*r3*r4) - std::log(r5) * std::pow(std::cos(PI/2.0*r6), 2);
break;
}
// Now determine v and E_out
double v = x/(x + y);
E_out = E_max * v;
}
} // namespace openmc

37
src/secondary_nbody.h Normal file
View file

@ -0,0 +1,37 @@
//! \file secondary_nbody.h
//! N-body phase space distribution
#ifndef OPENMC_SECONDARY_NBODY_H
#define OPENMC_SECONDARY_NBODY_H
#include "hdf5.h"
#include "angle_energy.h"
namespace openmc {
//==============================================================================
//! Angle-energy distribution for particles emitted from neutron and
//! charged-particle reactions. This corresponds to ACE law 66 and ENDF File 6,
//! LAW=6.
//==============================================================================
class NBodyPhaseSpace : public AngleEnergy {
public:
explicit NBodyPhaseSpace(hid_t group);
//! Sample distribution for an angle and energy
//! \param[in] E_in Incoming energy in [eV]
//! \param[out] E_out Outgoing energy in [eV]
//! \param[out] mu Outgoing cosine with respect to current direction
void sample(double E_in, double& E_out, double& mu) const;
private:
int n_bodies_; //!< Number of particles distributed
double mass_ratio_; //!< Total mass of particles [neutron mass]
double A_; //!< Atomic weight ratio
double Q_; //!< Reaction Q-value [eV]
};
} // namespace openmc
#endif // OPENMC_SECONDARY_NBODY_H

View file

@ -1,98 +0,0 @@
module secondary_uncorrelated
use angle_distribution, only: AngleDistribution
use angleenergy_header, only: AngleEnergy
use constants, only: ONE, TWO, MAX_WORD_LEN
use energy_distribution, only: EnergyDistribution, LevelInelastic, &
ContinuousTabular, MaxwellEnergy, Evaporation, WattEnergy, DiscretePhoton
use error, only: warning
use hdf5_interface, only: read_attribute, open_group, close_group, &
object_exists, HID_T
use random_lcg, only: prn
!===============================================================================
! UNCORRELATEDANGLEENERGY represents an uncorrelated angle-energy
! distribution. This corresponds to when an energy distribution is given in ENDF
! File 5/6 and an angular distribution is given in ENDF File 4.
!===============================================================================
type, extends(AngleEnergy) :: UncorrelatedAngleEnergy
logical :: fission = .false.
type(AngleDistribution) :: angle
class(EnergyDistribution), allocatable :: energy
contains
procedure :: sample => uncorrelated_sample
procedure :: from_hdf5 => uncorrelated_from_hdf5
end type UncorrelatedAngleEnergy
contains
subroutine uncorrelated_sample(this, E_in, E_out, mu)
class(UncorrelatedAngleEnergy), intent(in) :: this
real(8), intent(in) :: E_in ! incoming energy
real(8), intent(out) :: E_out ! sampled outgoing energy
real(8), intent(out) :: mu ! sampled scattering cosine
! Sample cosine of scattering angle
if (this%fission) then
! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
! For fission, the angle is not used, so just assign a dummy value
mu = ONE
! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
elseif (allocated(this%angle%energy)) then
mu = this%angle%sample(E_in)
else
! no angle distribution given => assume isotropic for all energies
mu = TWO*prn() - ONE
end if
! Sample outgoing energy
E_out = this%energy%sample(E_in)
end subroutine uncorrelated_sample
subroutine uncorrelated_from_hdf5(this, group_id)
class(UncorrelatedAngleEnergy), intent(inout) :: this
integer(HID_T), intent(in) :: group_id
integer(HID_T) :: energy_group
integer(HID_T) :: angle_group
character(MAX_WORD_LEN) :: type
! Check if angle group is present & read
if (object_exists(group_id, 'angle')) then
angle_group = open_group(group_id, 'angle')
call this%angle%from_hdf5(angle_group)
call close_group(angle_group)
end if
! Check if energy group is present & read
if (object_exists(group_id, 'energy')) then
energy_group = open_group(group_id, 'energy')
call read_attribute(type, energy_group, 'type')
select case (type)
case ('discrete_photon')
allocate(DiscretePhoton :: this%energy)
case ('level')
allocate(LevelInelastic :: this%energy)
case ('continuous')
allocate(ContinuousTabular :: this%energy)
case ('maxwell')
allocate(MaxwellEnergy :: this%energy)
case ('evaporation')
allocate(Evaporation :: this%energy)
case ('watt')
allocate(WattEnergy :: this%energy)
case default
call warning("Energy distribution type '" // trim(type) &
// "' not implemented.")
end select
if (allocated(this % energy)) then
call this%energy%from_hdf5(energy_group)
end if
call close_group(energy_group)
end if
end subroutine uncorrelated_from_hdf5
end module secondary_uncorrelated

View file

@ -0,0 +1,74 @@
#include "secondary_uncorrelated.h"
#include <sstream> // for stringstream
#include <string> // for string
#include "error.h"
#include "hdf5_interface.h"
#include "random_lcg.h"
namespace openmc {
//==============================================================================
// UncorrelatedAngleEnergy implementation
//==============================================================================
UncorrelatedAngleEnergy::UncorrelatedAngleEnergy(hid_t group)
{
// Check if angle group is present & read
if (object_exists(group, "angle")) {
hid_t angle_group = open_group(group, "angle");
angle_ = AngleDistribution{angle_group};
close_group(angle_group);
}
// Check if energy group is present & read
if (object_exists(group, "energy")) {
hid_t energy_group = open_group(group, "energy");
std::string type;
read_attribute(energy_group, "type", type);
using UPtrEDist = std::unique_ptr<EnergyDistribution>;
if (type == "discrete_photon") {
energy_ = UPtrEDist{new DiscretePhoton{energy_group}};
} else if (type == "level") {
energy_ = UPtrEDist{new LevelInelastic{energy_group}};
} else if (type == "continuous") {
energy_ = UPtrEDist{new ContinuousTabular{energy_group}};
} else if (type == "maxwell") {
energy_ = UPtrEDist{new MaxwellEnergy{energy_group}};
} else if (type == "evaporation") {
energy_ = UPtrEDist{new Evaporation{energy_group}};
} else if (type == "watt") {
energy_ = UPtrEDist{new WattEnergy{energy_group}};
} else {
std::stringstream msg;
msg << "Energy distribution type '" << type << "' not implemented.";
warning(msg);
}
close_group(energy_group);
}
}
void
UncorrelatedAngleEnergy::sample(double E_in, double& E_out, double& mu) const
{
// Sample cosine of scattering angle
if (fission_) {
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
// For fission, the angle is not used, so just assign a dummy value
mu = 1.0;
// <<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
} else if (!angle_.empty()) {
mu = angle_.sample(E_in);
} else {
// no angle distribution given => assume isotropic for all energies
mu = 2.0*prn() - 1.0;
}
// Sample outgoing energy
E_out = energy_->sample(E_in);
}
} // namespace openmc

View file

@ -0,0 +1,44 @@
//! \file secondary_uncorrelated.h
//! Uncorrelated angle-energy distribution
#ifndef OPENMC_SECONDARY_UNCORRELATED_H
#define OPENMC_SECONDARY_UNCORRELATED_H
#include <memory>
#include <vector>
#include "hdf5.h"
#include "angle_energy.h"
#include "distribution_angle.h"
#include "distribution_energy.h"
namespace openmc {
//==============================================================================
//! Uncorrelated angle-energy distribution. This corresponds to when an energy
//! distribution is given in ENDF File 5/6 and an angular distribution is given
//! in ENDF File 4.
//==============================================================================
class UncorrelatedAngleEnergy : public AngleEnergy {
public:
explicit UncorrelatedAngleEnergy(hid_t group);
//! Sample distribution for an angle and energy
//! \param[in] E_in Incoming energy in [eV]
//! \param[out] E_out Outgoing energy in [eV]
//! \param[out] mu Outgoing cosine with respect to current direction
void sample(double E_in, double& E_out, double& mu) const;
// Accessors
AngleDistribution& angle() { return angle_; }
bool& fission() { return fission_; }
private:
AngleDistribution angle_; //!< Angle distribution
std::unique_ptr<EnergyDistribution> energy_; //!< Energy distribution
bool fission_ {false}; //!< Whether distribution is use for fission
};
} // namespace openmc
#endif // OPENMC_SECONDARY_UNCORRELATED_H

View file

@ -151,7 +151,7 @@ Surface::Surface(pugi::xml_node surf_node)
}
if (check_for_node(surf_node, "boundary")) {
std::string surf_bc = get_node_value(surf_node, "boundary");
std::string surf_bc = get_node_value(surf_node, "boundary", true, true);
if (surf_bc == "transmission" || surf_bc == "transmit" ||surf_bc.empty()) {
bc = BC_TRANSMIT;
@ -1040,7 +1040,7 @@ read_surfaces(pugi::xml_node *node)
int i_surf;
for (surf_node = node->child("surface"), i_surf = 0; surf_node;
surf_node = surf_node.next_sibling("surface"), i_surf++) {
std::string surf_type = get_node_value(surf_node, "type");
std::string surf_type = get_node_value(surf_node, "type", true, true);
if (surf_type == "x-plane") {
surfaces_c[i_surf] = new SurfaceXPlane(surf_node);

View file

@ -18,6 +18,7 @@ namespace openmc {
// Module constant declarations (defined in .cpp)
//==============================================================================
// TODO: Convert to enum
extern "C" const int BC_TRANSMIT;
extern "C" const int BC_VACUUM;
extern "C" const int BC_REFLECT;

View file

@ -94,6 +94,7 @@ contains
integer :: k ! loop index for bank sites
integer :: d_bin ! delayed group bin index
integer :: dg_filter ! index of delayed group filter
integer :: threshold ! threshold energy index
real(8) :: yield ! delayed neutron yield
real(8) :: atom_density_ ! atom/b-cm
real(8) :: f ! interpolation factor
@ -227,7 +228,7 @@ contains
! Get yield and apply to score
associate (rxn => nuclides(p % event_nuclide) % reactions(m))
score = p % last_wgt * flux &
* rxn % products(1) % yield % evaluate(E)
* rxn % product_yield(1, E)
end associate
end if
@ -633,7 +634,7 @@ contains
score = p % absorb_wgt * yield * &
micro_xs(p % event_nuclide) % fission &
/ micro_xs(p % event_nuclide) % absorption &
* rxn % products(1 + d) % decay_rate * flux
* rxn % product_decay_rate(1 + d) * flux
end associate
! Tally to bin
@ -657,9 +658,8 @@ contains
! rxn % products array to be exceeded. Hence, we use the size
! of this array and not the MAX_DELAYED_GROUPS constant for
! this loop.
do d = 1, size(rxn % products) - 2
score = score + rxn % products(1 + d) % decay_rate * &
do d = 1, rxn % products_size() - 2
score = score + rxn % product_decay_rate(1 + d) * &
p % absorb_wgt &
* micro_xs(p % event_nuclide) % fission &
* nuclides(p % event_nuclide) % &
@ -699,7 +699,7 @@ contains
! determine score based on bank site weight and keff.
score = score + keff * fission_bank(n_bank - p % n_bank + k) &
% wgt * rxn % products(1 + g) % decay_rate * flux
% wgt * rxn % product_decay_rate(1 + g) * flux
end associate
! if the delayed group filter is present, tally to corresponding
@ -755,7 +755,7 @@ contains
! Compute the score and tally to bin
score = micro_xs(i_nuclide) % fission * yield * flux * &
atom_density * rxn % products(1 + d) % decay_rate
atom_density * rxn % product_decay_rate(1 + d)
end associate
! Tally to bin
@ -778,11 +778,10 @@ contains
! groups since this could cause the range of the rxn % products
! array to be exceeded. Hence, we use the size of this array
! and not the MAX_DELAYED_GROUPS constant for this loop.
do d = 1, size(rxn % products) - 2
do d = 1, rxn % products_size() - 2
score = score + micro_xs(i_nuclide) % fission * flux * &
nuclides(i_nuclide) % nu(E, EMISSION_DELAYED) * &
atom_density * rxn % products(1 + d) % decay_rate
atom_density * rxn % product_decay_rate(1 + d)
end do
end associate
end if
@ -824,7 +823,7 @@ contains
! Compute the score
score = micro_xs(i_nuc) % fission * yield * flux * &
atom_density_ &
* rxn % products(1 + d) % decay_rate
* rxn % product_decay_rate(1 + d)
end associate
! Tally to bin
@ -860,13 +859,13 @@ contains
! rxn % products array to be exceeded. Hence, we use the
! size of this array and not the MAX_DELAYED_GROUPS
! constant for this loop.
do d = 1, size(rxn % products) - 2
do d = 1, rxn % products_size() - 2
! Accumulate the contribution from each nuclide
score = score + micro_xs(i_nuc) % fission &
* nuclides(i_nuc) % nu(E, EMISSION_DELAYED) &
* atom_density_ * flux &
* rxn % products(1 + d) % decay_rate
* rxn % product_decay_rate(1 + d)
end do
end associate
end if
@ -1132,12 +1131,12 @@ contains
i_energy = micro_xs(i_nuclide) % index_grid
f = micro_xs(i_nuclide) % interp_factor
associate (xs => nuclides(i_nuclide) % reactions(m) &
% xs(i_temp))
if (i_energy >= xs % threshold) then
score = ((ONE - f) * xs % value(i_energy - &
xs % threshold + 1) + f * xs % value(i_energy - &
xs % threshold + 2)) * atom_density * flux
associate (rx => nuclides(i_nuclide) % reactions(m))
threshold = rx % xs_threshold(i_temp)
if (i_energy >= threshold) then
score = ((ONE - f) * rx % xs(i_temp, i_energy - &
threshold + 1) + f * rx % xs(i_temp, i_energy - &
threshold + 2)) * atom_density * flux
end if
end associate
else
@ -1165,12 +1164,12 @@ contains
i_energy = micro_xs(i_nuc) % index_grid
f = micro_xs(i_nuc) % interp_factor
associate (xs => nuclides(i_nuc) % reactions(m) &
% xs(i_temp))
if (i_energy >= xs % threshold) then
score = score + ((ONE - f) * xs % value(i_energy - &
xs % threshold + 1) + f * xs % value(i_energy - &
xs % threshold + 2)) * atom_density_ * flux
associate (rx => nuclides(i_nuc) % reactions(m))
threshold = rx % xs_threshold(i_temp)
if (i_energy >= threshold) then
score = score + ((ONE - f) * rx % xs(i_temp, i_energy - &
threshold + 1) + f * rx % xs(i_temp, i_energy - &
threshold + 2)) * atom_density_ * flux
end if
end associate
else

View file

@ -1,6 +1,6 @@
#include "xml_interface.h"
#include <algorithm> // for std::transform
#include <algorithm> // for transform
#include <sstream>
#include "error.h"
@ -9,10 +9,11 @@
namespace openmc {
std::string
get_node_value(pugi::xml_node node, const char *name)
get_node_value(pugi::xml_node node, const char* name, bool lowercase,
bool strip)
{
// Search for either an attribute or child tag and get the data as a char*.
const pugi::char_t *value_char;
const pugi::char_t* value_char;
if (node.attribute(name)) {
value_char = node.attribute(name).value();
} else if (node.child(name)) {
@ -23,14 +24,18 @@ get_node_value(pugi::xml_node node, const char *name)
<< node.name() << "\" XML node";
fatal_error(err_msg);
}
std::string value {value_char};
// Convert to lowercase string.
std::string value(value_char);
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
// Convert to lower-case if needed
if (lowercase) {
std::transform(value.begin(), value.end(), value.begin(), ::tolower);
}
// Remove whitespace.
value.erase(0, value.find_first_not_of(" \t\r\n"));
value.erase(value.find_last_not_of(" \t\r\n") + 1);
// Strip leading/trailing whitespace if needed
if (strip) {
value.erase(0, value.find_first_not_of(" \t\r\n"));
value.erase(value.find_last_not_of(" \t\r\n") + 1);
}
return value;
}

View file

@ -1,6 +1,7 @@
#ifndef XML_INTERFACE_H
#define XML_INTERFACE_H
#include <sstream> // for stringstream
#include <string>
#include <vector>
@ -15,7 +16,24 @@ check_for_node(pugi::xml_node node, const char *name)
return node.attribute(name) || node.child(name);
}
std::string get_node_value(pugi::xml_node node, const char *name);
std::string get_node_value(pugi::xml_node node, const char *name,
bool lowercase=false, bool strip=false);
template <typename T>
std::vector<T> get_node_array(pugi::xml_node node, const char* name)
{
// Get value of node attribute/child
std::string s {get_node_value(node, name)};
// Read values one by one into vector
std::stringstream iss {s};
T value;
std::vector<T> values;
while (iss >> value)
values.push_back(value);
return values;
}
} // namespace openmc
#endif // XML_INTERFACE_H

View file

@ -1,7 +1,15 @@
import numpy as np
import openmc
from pkg_resources import parse_version
import pytest
@pytest.fixture(scope='module', autouse=True)
def numpy_version_requirement():
assert parse_version(np.__version__) >= parse_version("1.14"), \
"Regression tests require NumPy 1.14 or greater"
@pytest.fixture(scope='module', autouse=True)
def setup_regression_test(request):
# Reset autogenerated IDs assigned to OpenMC objects

View file

@ -1,2 +1,2 @@
energyfunction nuclide score mean std. dev.
0 02180f5f310ee4 Am241 ((n,gamma) / (n,gamma)) 1.00e-01 9.97e-03
0 d2effa26cb3cf2 Am241 ((n,gamma) / (n,gamma)) 1.00e-01 9.97e-03

View file

@ -60,7 +60,7 @@
<bins>0.0 0.625 20000000.0</bins>
</filter>
<filter id="4" type="mu">
<bins>-1.0 -0.818181818182 -0.636363636364 -0.454545454545 -0.272727272727 -0.0909090909091 0.0909090909091 0.272727272727 0.454545454545 0.636363636364 0.818181818182 1.0</bins>
<bins>-1.0 -0.8181818181818181 -0.6363636363636364 -0.4545454545454546 -0.2727272727272727 -0.09090909090909083 0.09090909090909083 0.2727272727272727 0.4545454545454546 0.6363636363636365 0.8181818181818183 1.0</bins>
</filter>
<filter id="17" type="material">
<bins>2</bins>

View file

@ -37,5 +37,5 @@ Cell
Fill = Material 2
Region = -1
Rotation = None
Temperature = [ 500. 700. 0. 800.]
Temperature = [500. 700. 0. 800.]
Translation = None

View file

@ -48,7 +48,7 @@
</space>
<angle type="isotropic" />
<energy interpolation="histogram" type="tabular">
<parameters>1.0 1.38949549437 1.93069772888 2.68269579528 3.72759372031 5.17947467923 7.19685673001 10.0 13.8949549437 19.3069772888 26.8269579528 37.2759372031 51.7947467923 71.9685673001 100.0 138.949549437 193.069772888 268.269579528 372.759372031 517.947467923 719.685673001 1000.0 1389.49549437 1930.69772888 2682.69579528 3727.59372031 5179.47467923 7196.85673001 10000.0 13894.9549437 19306.9772888 26826.9579528 37275.9372031 51794.7467923 71968.5673001 100000.0 138949.549437 193069.772888 268269.579528 372759.372031 517947.467923 719685.673001 1000000.0 1389495.49437 1930697.72888 2682695.79528 3727593.72031 5179474.67923 7196856.73001 10000000.0 0.0 2.90864392994e-08 5.80533561806e-08 8.67817193689e-08 1.15153477858e-07 1.43052046006e-07 1.70362782612e-07 1.96973462002e-07 2.22774735186e-07 2.47660579198e-07 2.71528732767e-07 2.9428111653e-07 3.15824236062e-07 3.36069566065e-07 3.54933914133e-07 3.72339762616e-07 3.88215587147e-07 4.02496150558e-07 4.15122770952e-07 4.26043562837e-07 4.35213650335e-07 4.42595351592e-07 4.48158333612e-07 4.5187973691e-07 4.53744269441e-07 4.53744269441e-07 4.5187973691e-07 4.48158333612e-07 4.42595351592e-07 4.35213650335e-07 4.26043562837e-07 4.15122770952e-07 4.02496150558e-07 3.88215587147e-07 3.72339762616e-07 3.54933914133e-07 3.36069566065e-07 3.15824236062e-07 2.9428111653e-07 2.71528732767e-07 2.47660579198e-07 2.22774735186e-07 1.96973462002e-07 1.70362782612e-07 1.43052046006e-07 1.15153477858e-07 8.67817193689e-08 5.80533561806e-08 2.90864392994e-08 5.55962111528e-23</parameters>
<parameters>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</parameters>
</energy>
</source>
</settings>

View file

@ -48,10 +48,10 @@
<bins>0.0 4000000.0 20000000.0</bins>
</filter>
<filter id="2" type="polar">
<bins>0.0 0.785398163397 3.14159265359</bins>
<bins>0.0 0.7853981633974483 3.141592653589793</bins>
</filter>
<filter id="3" type="azimuthal">
<bins>0.0 0.785398163397 3.14159265359</bins>
<bins>0.0 0.7853981633974483 3.141592653589793</bins>
</filter>
<filter id="4" type="surface">
<bins>1</bins>

View file

@ -1 +1 @@
8294c7481b3433a4beb25541ae72c1ea915def0c0d0f393f7585371877187f4a2a25e70bb602232e2bc1e877e78db0e9384591e5c71575659f95abb10fae0af3
c8fb043c5321e698040544dbb0baa9ce82df0e189738fb6013b4f3ff7e05a989a7a59b9b55034b8c9de6bc604ba9f969dc08ad2752fc74da205c19ff5974c9a2

View file

@ -1,134 +1,139 @@
[[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
...,
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
...
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]][[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]][[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
...,
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
...
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]][[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]][[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
...,
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]
[ 0. 0. 0. 0.]]][[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
...
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
...,
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]][[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]][[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
...
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
...,
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]][[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[ 0. 0. 0.]
[ 0. 0. 0.]
[ 0. 0. 0.]]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
...
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]
[[0. 0. 0.]
[0. 0. 0.]
[0. 0. 0.]]]

View file

@ -6,170 +6,170 @@
<cell id="16" material="16" region="11 -12" universe="9" />
<cell id="17" material="17" region="12" universe="9" />
<cell fill="10" id="134" region="122 -123 124 -125 126 -127" universe="0" />
<cell fill="9" id="135" region="-128" translation="-0.00140620118176 -0.0152577471673 -0.0918476696602" universe="35" />
<cell fill="9" id="136" region="-129" translation="0.109099026398 -0.00417917776733 -0.0462409301859" universe="23" />
<cell fill="9" id="137" region="-130" translation="0.138783366528 -0.0690071053688 -0.0384882149749" universe="18" />
<cell fill="9" id="138" region="-131" translation="-0.194549966806 -0.0690071053688 -0.0384882149749" universe="19" />
<cell fill="9" id="139" region="-132" translation="-0.0984645519108 -0.0259403806947 -0.0615517493329" universe="26" />
<cell fill="9" id="140" region="-133" translation="-0.0932159178431 -0.122488574824 -0.0499980238428" universe="22" />
<cell fill="9" id="141" region="-134" translation="0.202819899608 0.0850151469064 0.0743119884463" universe="30" />
<cell fill="9" id="142" region="-135" translation="-0.130513433725 0.0850151469064 0.0743119884463" universe="31" />
<cell fill="9" id="143" region="-136" translation="0.03417350411 -0.0964115371994 -0.101120980927" universe="13" />
<cell fill="9" id="144" region="-137" translation="0.0379131188424 0.0687077251904 -0.108757520396" universe="27" />
<cell fill="9" id="145" region="-138" translation="0.0738800814064 -0.071302275054 -0.0978298256419" universe="14" />
<cell fill="9" id="146" region="-139" translation="0.0889721475441 0.0869416521141 0.075877373016" universe="11" />
<cell fill="9" id="147" region="-140" translation="-0.0369830271171 0.140878401491 -0.104742841496" universe="12" />
<cell fill="9" id="148" region="-141" translation="-0.0369830271171 -0.192454931842 -0.104742841496" universe="15" />
<cell fill="9" id="149" region="-142" translation="-0.0242806966142 0.0516839323883 0.130270489265" universe="25" />
<cell fill="9" id="150" region="-143" translation="-0.0242806966142 0.0516839323883 -0.203062844069" universe="34" />
<cell fill="9" id="151" region="-144" translation="0.0457805197599 0.117590160514 -0.00380228622125" universe="35" />
<cell fill="9" id="152" region="-145" translation="-0.0137419084645 0.180165775531 0.202768975142" universe="20" />
<cell fill="9" id="153" region="-146" translation="-0.0137419084645 -0.153167557803 0.202768975142" universe="23" />
<cell fill="9" id="154" region="-147" translation="-0.0137419084645 0.180165775531 -0.130564358191" universe="29" />
<cell fill="9" id="155" region="-148" translation="-0.0137419084645 -0.153167557803 -0.130564358191" universe="32" />
<cell fill="9" id="156" region="-149" translation="0.193346065156 0.0662280238816 -0.0713110415353" universe="27" />
<cell fill="9" id="157" region="-150" translation="-0.139987268177 0.0662280238816 -0.0713110415353" universe="28" />
<cell fill="9" id="158" region="-151" translation="-0.0311856561407 0.155914746052 0.153317205092" universe="16" />
<cell fill="9" id="159" region="-152" translation="-0.0311856561407 -0.177418587281 0.153317205092" universe="19" />
<cell fill="9" id="160" region="-153" translation="-0.0311856561407 0.155914746052 -0.180016128241" universe="25" />
<cell fill="9" id="161" region="-154" translation="-0.0311856561407 -0.177418587281 -0.180016128241" universe="28" />
<cell fill="9" id="162" region="-155" translation="0.0801800449244 0.0168261919282 -0.0163895967622" universe="36" />
<cell fill="9" id="163" region="-156" translation="0.00483733774062 0.081481567183 -0.0928082691631" universe="15" />
<cell fill="9" id="164" region="-157" translation="0.097811779112 -0.0610597446974 -0.0784455336401" universe="26" />
<cell fill="9" id="165" region="-158" translation="0.033971609479 0.0446752660509 0.185883817671" universe="23" />
<cell fill="9" id="166" region="-159" translation="0.033971609479 0.0446752660509 -0.147449515662" universe="32" />
<cell fill="9" id="167" region="-160" translation="0.159741777825 -0.114709384731 -0.0558806276942" universe="24" />
<cell fill="9" id="168" region="-161" translation="-0.173591555508 -0.114709384731 -0.0558806276942" universe="25" />
<cell fill="9" id="169" region="-162" translation="0.00771444999286 -0.0784191193007 0.0191691213248" universe="27" />
<cell fill="9" id="170" region="-163" translation="-0.0977249605603 -0.0094355820168 -0.097340787155" universe="15" />
<cell fill="9" id="171" region="-164" translation="-0.0846040523453 0.186196302117 0.109025021864" universe="32" />
<cell fill="9" id="172" region="-165" translation="-0.0846040523453 -0.147137031217 0.109025021864" universe="35" />
<cell fill="9" id="173" region="-166" translation="0.0853097051629 -0.097409487121 0.0315380230547" universe="15" />
<cell fill="9" id="174" region="-167" translation="0.00204940024585 0.108007828333 -0.0856693988182" universe="36" />
<cell fill="9" id="175" region="-168" translation="0.0362697740558 -0.00348804073157 0.088140578575" universe="18" />
<cell fill="9" id="176" region="-169" translation="0.0126079576483 0.0809005606263 0.071221146542" universe="27" />
<cell fill="9" id="177" region="-170" translation="-0.0374148994358 0.122108694931 0.0439406213164" universe="21" />
<cell fill="9" id="178" region="-171" translation="0.0851566223435 -0.119189958655 -0.0736469678739" universe="31" />
<cell fill="9" id="179" region="-172" translation="-0.0399284809656 0.0202140729129 -0.1131524598" universe="37" />
<cell fill="9" id="180" region="-173" translation="-0.0503157540846 0.0170999685653 0.0561731252046" universe="25" />
<cell fill="9" id="181" region="-174" translation="-0.0676639827455 -0.0730357877864 0.00541096373088" universe="30" />
<cell fill="9" id="182" region="-175" translation="0.0640843901638 0.0585363225055 0.00432158793112" universe="21" />
<cell fill="9" id="183" region="-176" translation="-0.0138010597555 0.202224545874 0.192417668194" universe="12" />
<cell fill="9" id="184" region="-177" translation="-0.0138010597555 -0.131108787459 0.192417668194" universe="15" />
<cell fill="9" id="185" region="-178" translation="-0.0138010597555 0.202224545874 -0.140915665139" universe="21" />
<cell fill="9" id="186" region="-179" translation="-0.0138010597555 -0.131108787459 -0.140915665139" universe="24" />
<cell fill="9" id="187" region="-180" translation="0.035227337498 0.113054594036 0.102950231509" universe="24" />
<cell fill="9" id="188" region="-181" translation="-0.0383166045087 -0.0988055687379 0.0857867394674" universe="12" />
<cell fill="9" id="189" region="-182" translation="0.0378202408916 0.0773239271977 -0.00282972122211" universe="32" />
<cell fill="9" id="190" region="-183" translation="-0.0601124832347 -0.0613405147405 -0.043634920585" universe="37" />
<cell fill="9" id="191" region="-184" translation="0.109305027033 -0.0204659393864 0.158485432539" universe="26" />
<cell fill="9" id="192" region="-185" translation="0.109305027033 -0.0204659393864 -0.174847900794" universe="35" />
<cell fill="9" id="193" region="-186" translation="-0.0482158135072 -0.109136394796 -0.111087009623" universe="11" />
<cell fill="9" id="194" region="-187" translation="-0.0993436405899 0.104054804419 -0.0241798283787" universe="13" />
<cell fill="9" id="195" region="-188" translation="0.114256308042 0.190902465414 -0.0607753376217" universe="12" />
<cell fill="9" id="196" region="-189" translation="0.114256308042 -0.14243086792 -0.0607753376217" universe="15" />
<cell fill="9" id="197" region="-190" translation="0.0217205011906 0.0250667553285 0.0295200316" universe="14" />
<cell fill="9" id="198" region="-191" translation="0.125436500241 0.193710578338 -0.0414706576932" universe="23" />
<cell fill="9" id="199" region="-192" translation="-0.207896833092 0.193710578338 -0.0414706576932" universe="24" />
<cell fill="9" id="200" region="-193" translation="0.125436500241 -0.139622754995 -0.0414706576932" universe="26" />
<cell fill="9" id="201" region="-194" translation="-0.207896833092 -0.139622754995 -0.0414706576932" universe="27" />
<cell fill="9" id="202" region="-195" translation="-0.103856970591 -0.0723989491841 0.0477333168332" universe="15" />
<cell fill="9" id="203" region="-196" translation="-0.0248453372329 0.0327005037426 0.0092611805402" universe="26" />
<cell fill="9" id="204" region="-197" translation="-0.105357688326 -0.108061697849 0.00966905666893" universe="11" />
<cell fill="9" id="205" region="-198" translation="0.200343875313 0.0222716943858 0.187316452299" universe="21" />
<cell fill="9" id="206" region="-199" translation="-0.13298945802 0.0222716943858 0.187316452299" universe="22" />
<cell fill="9" id="207" region="-200" translation="0.200343875313 0.0222716943858 -0.146016881035" universe="30" />
<cell fill="9" id="208" region="-201" translation="-0.13298945802 0.0222716943858 -0.146016881035" universe="31" />
<cell fill="9" id="209" region="-202" translation="0.163119940576 0.0409248307565 0.0775424026481" universe="15" />
<cell fill="9" id="210" region="-203" translation="-0.170213392757 0.0409248307565 0.0775424026481" universe="16" />
<cell fill="9" id="211" region="-204" translation="0.102073447729 -0.0606874931034 0.0151968577672" universe="28" />
<cell fill="9" id="212" region="-205" translation="0.0799190701492 0.13595762577 -0.0962208719747" universe="23" />
<cell fill="9" id="213" region="-206" translation="0.0799190701492 -0.197375707563 -0.0962208719747" universe="26" />
<cell fill="9" id="214" region="-207" translation="0.0694369789325 0.169683871789 0.119882766994" universe="21" />
<cell fill="9" id="215" region="-208" translation="0.0694369789325 -0.163649461545 0.119882766994" universe="24" />
<cell fill="9" id="216" region="-209" translation="-0.0705988927796 0.148957080213 0.0950321471098" universe="29" />
<cell fill="9" id="217" region="-210" translation="-0.0705988927796 -0.18437625312 0.0950321471098" universe="32" />
<cell fill="9" id="218" region="-211" translation="0.010468267264 0.156080284248 -0.0051133943139" universe="31" />
<cell fill="9" id="219" region="-212" translation="0.010468267264 -0.177253049085 -0.0051133943139" universe="34" />
<cell fill="9" id="220" region="-213" translation="0.159721234175 0.0688352262865 -0.110095873694" universe="35" />
<cell fill="9" id="221" region="-214" translation="-0.173612099158 0.0688352262865 -0.110095873694" universe="36" />
<cell fill="9" id="222" region="-215" translation="0.0898117967697 0.0643418620595 0.0326072339685" universe="16" />
<cell fill="9" id="223" region="-216" translation="0.0033702311569 0.100407895371 0.186783186803" universe="28" />
<cell fill="9" id="224" region="-217" translation="0.0033702311569 0.100407895371 -0.14655014653" universe="37" />
<cell fill="9" id="225" region="-218" translation="0.0532989528173 -0.0288162906553 0.151934117139" universe="20" />
<cell fill="9" id="226" region="-219" translation="0.0532989528173 -0.0288162906553 -0.181399216194" universe="29" />
<cell fill="9" id="227" region="-220" translation="0.146637865541 -0.000183171192208 0.173437280372" universe="14" />
<cell fill="9" id="228" region="-221" translation="-0.186695467792 -0.000183171192208 0.173437280372" universe="15" />
<cell fill="9" id="229" region="-222" translation="0.146637865541 -0.000183171192208 -0.159896052961" universe="23" />
<cell fill="9" id="230" region="-223" translation="-0.186695467792 -0.000183171192208 -0.159896052961" universe="24" />
<cell fill="9" id="231" region="-224" translation="0.00688615671293 0.0325721225173 -0.107852540144" universe="19" />
<cell fill="9" id="232" region="-225" translation="0.0594642653073 0.175629948849 0.11256068343" universe="29" />
<cell fill="9" id="233" region="-226" translation="0.0594642653073 -0.157703384484 0.11256068343" universe="32" />
<cell fill="9" id="234" region="-227" translation="-0.0745211393531 0.186025398941 0.07061211192" universe="13" />
<cell fill="9" id="235" region="-228" translation="-0.0745211393531 -0.147307934392 0.07061211192" universe="16" />
<cell fill="9" id="236" region="-229" translation="0.159713616332 -0.0241680036074 0.0623342971853" universe="36" />
<cell fill="9" id="237" region="-230" translation="-0.173619717001 -0.0241680036074 0.0623342971853" universe="37" />
<cell fill="9" id="238" region="-231" translation="-0.0141914194483 0.111149451072 0.0903966514578" universe="18" />
<cell fill="9" id="239" region="-232" translation="0.206413378004 -0.0468919157204 0.0309383201461" universe="12" />
<cell fill="9" id="240" region="-233" translation="-0.126919955329 -0.0468919157204 0.0309383201461" universe="13" />
<cell fill="9" id="241" region="-234" translation="0.0429259824683 0.070555715848 -0.0961124680564" universe="31" />
<cell fill="9" id="242" region="-235" translation="0.0917411839861 -0.0210268081646 -0.120747126544" universe="27" />
<cell fill="9" id="243" region="-236" translation="0.187114465978 0.142190928958 0.00303951516048" universe="29" />
<cell fill="9" id="244" region="-237" translation="-0.146218867356 0.142190928958 0.00303951516048" universe="30" />
<cell fill="9" id="245" region="-238" translation="0.187114465978 -0.191142404375 0.00303951516048" universe="32" />
<cell fill="9" id="246" region="-239" translation="-0.146218867356 -0.191142404375 0.00303951516048" universe="33" />
<cell fill="9" id="247" region="-240" translation="-0.0885860120512 -0.0574080917257 0.00189379783576" universe="29" />
<cell fill="9" id="248" region="-241" translation="-0.0695627245254 -0.0325861164534 0.187674961732" universe="19" />
<cell fill="9" id="249" region="-242" translation="-0.0695627245254 -0.0325861164534 -0.145658371601" universe="28" />
<cell fill="9" id="250" region="-243" translation="0.0648004866859 0.0803935669348 -0.0495807099831" universe="12" />
<cell fill="9" id="251" region="-244" translation="0.119768828483 0.0244148877182 0.0590010758314" universe="26" />
<cell fill="9" id="252" region="-245" translation="0.055815690197 -0.0386622433477 0.129344155705" universe="16" />
<cell fill="9" id="253" region="-246" translation="0.055815690197 -0.0386622433477 -0.203989177628" universe="25" />
<cell fill="9" id="254" region="-247" translation="-0.0705714088439 -0.0332615859242 -0.113081179589" universe="19" />
<cell fill="9" id="255" region="-248" translation="0.0191891610992 -0.0877751186437 0.0949676788695" universe="13" />
<cell fill="9" id="256" region="-249" translation="0.11357577214 -0.0723120607076 -0.0186231523344" universe="16" />
<cell fill="9" id="257" region="-250" translation="0.0288228703292 0.0966036043404 -0.109945458994" universe="29" />
<cell fill="9" id="258" region="-251" translation="-0.0302720060162 0.0427214916014 -0.111437158817" universe="26" />
<cell fill="9" id="259" region="-252" translation="0.0971933921082 0.0413100742886 0.144761925354" universe="19" />
<cell fill="9" id="260" region="-253" translation="0.0971933921082 0.0413100742886 -0.18857140798" universe="28" />
<cell fill="9" id="261" region="-254" translation="0.107580312879 -0.0210472571374 -0.03274843538" universe="14" />
<cell fill="9" id="262" region="-255" translation="0.139201957633 -0.0881443612864 -0.114798284951" universe="12" />
<cell fill="9" id="263" region="-256" translation="-0.194131375701 -0.0881443612864 -0.114798284951" universe="13" />
<cell fill="9" id="264" region="-257" translation="0.108471976774 0.146159230208 0.088410423839" universe="22" />
<cell fill="9" id="265" region="-258" translation="0.108471976774 -0.187174103125 0.088410423839" universe="25" />
<cell fill="9" id="266" region="-259" translation="0.0451270583821 0.096780721612 0.0967653665332" universe="37" />
<cell fill="9" id="267" region="-260" translation="-0.0224644717455 0.0725927720514 0.107852198651" universe="20" />
<cell fill="9" id="268" region="-261" translation="0.106063533699 0.0392870322973 0.172287769268" universe="25" />
<cell fill="9" id="269" region="-262" translation="0.106063533699 0.0392870322973 -0.161045564066" universe="34" />
<cell fill="9" id="270" region="-263" translation="0.148159419635 0.112776558875 0.0380868716968" universe="21" />
<cell fill="9" id="271" region="-264" translation="-0.185173913698 0.112776558875 0.0380868716968" universe="22" />
<cell fill="9" id="272" region="-265" translation="0.156935816691 0.101145318349 -0.0499235619578" universe="11" />
<cell fill="9" id="273" region="-266" translation="-0.176397516643 0.101145318349 -0.0499235619578" universe="12" />
<cell fill="9" id="274" region="-267" translation="0.132643578757 0.109198051281 -0.0476954987918" universe="26" />
<cell fill="9" id="275" region="-268" translation="-0.200689754577 0.109198051281 -0.0476954987918" universe="27" />
<cell fill="9" id="276" region="-269" translation="0.139165644346 0.131343196487 0.0701591217856" universe="33" />
<cell fill="9" id="277" region="-270" translation="-0.194167688987 0.131343196487 0.0701591217856" universe="34" />
<cell fill="9" id="278" region="-271" translation="0.139165644346 -0.201990136846 0.0701591217856" universe="36" />
<cell fill="9" id="279" region="-272" translation="-0.194167688987 -0.201990136846 0.0701591217856" universe="37" />
<cell fill="9" id="280" region="-273" translation="-0.100266886432 0.15644435527 0.175172848479" universe="12" />
<cell fill="9" id="281" region="-274" translation="-0.100266886432 -0.176888978063 0.175172848479" universe="15" />
<cell fill="9" id="282" region="-275" translation="-0.100266886432 0.15644435527 -0.158160484854" universe="21" />
<cell fill="9" id="283" region="-276" translation="-0.100266886432 -0.176888978063 -0.158160484854" universe="24" />
<cell fill="9" id="284" region="-277" translation="0.165554360307 -0.0155314552194 0.0269161414417" universe="35" />
<cell fill="9" id="285" region="-278" translation="-0.167778973026 -0.0155314552194 0.0269161414417" universe="36" />
<cell fill="9" id="286" region="-279" translation="0.152805274649 0.181665566207 0.0404883666838" universe="20" />
<cell fill="9" id="287" region="-280" translation="-0.180528058685 0.181665566207 0.0404883666838" universe="21" />
<cell fill="9" id="288" region="-281" translation="0.152805274649 -0.151667767127 0.0404883666838" universe="23" />
<cell fill="9" id="289" region="-282" translation="-0.180528058685 -0.151667767127 0.0404883666838" universe="24" />
<cell fill="9" id="290" region="-283" translation="0.0723111669483 0.0878537053709 0.0999705558994" universe="15" />
<cell fill="9" id="291" region="-284" translation="-0.105764243624 0.0987449723258 -0.0582008094074" universe="11" />
<cell fill="9" id="292" region="-285" translation="0.0468779531251 -0.0594927321842 -0.0556353418577" universe="12" />
<cell fill="9" id="293" region="-286" translation="0.123942306657 0.141830462742 -0.0658381874921" universe="30" />
<cell fill="9" id="294" region="-287" translation="0.123942306657 -0.191502870591 -0.0658381874921" universe="33" />
<cell fill="9" id="295" region="-288" translation="0.0013087859342 -0.0632759448088 -0.0538252207421" universe="18" />
<cell fill="9" id="296" region="-289" translation="0.110588836699 -0.0389541758206 0.16834558789" universe="19" />
<cell fill="9" id="297" region="-290" translation="0.110588836699 -0.0389541758206 -0.164987745443" universe="28" />
<cell fill="9" id="298" region="-291" translation="-0.0265701006572 0.0131449788411 0.0505879445141" universe="32" />
<cell fill="9" id="135" region="-128" translation="-0.0014062011817633224 -0.015257747167296776 -0.09184766966024316" universe="35" />
<cell fill="9" id="136" region="-129" translation="0.10909902639777394 -0.004179177767328068 -0.046240930185910245" universe="23" />
<cell fill="9" id="137" region="-130" translation="0.13878336652768952 -0.06900710536877097 -0.03848821497485455" universe="18" />
<cell fill="9" id="138" region="-131" translation="-0.19454996680564374 -0.06900710536877097 -0.03848821497485455" universe="19" />
<cell fill="9" id="139" region="-132" translation="-0.09846455191076986 -0.02594038069469251 -0.06155174933292362" universe="26" />
<cell fill="9" id="140" region="-133" translation="-0.09321591784308736 -0.12248857482372477 -0.04999802384282931" universe="22" />
<cell fill="9" id="141" region="-134" translation="0.2028198996079864 0.08501514690643278 0.07431198844628262" universe="30" />
<cell fill="9" id="142" region="-135" translation="-0.13051343372534685 0.08501514690643278 0.07431198844628262" universe="31" />
<cell fill="9" id="143" region="-136" translation="0.03417350410997999 -0.09641153719944834 -0.10112098092715327" universe="13" />
<cell fill="9" id="144" region="-137" translation="0.037913118842446136 0.06870772519039314 -0.10875752039644154" universe="27" />
<cell fill="9" id="145" region="-138" translation="0.07388008140640989 -0.07130227505402231 -0.09782982564187503" universe="14" />
<cell fill="9" id="146" region="-139" translation="0.08897214754414112 0.08694165211410448 0.07587737301598729" universe="11" />
<cell fill="9" id="147" region="-140" translation="-0.03698302711710488 0.1408784014909229 -0.10474284149572705" universe="12" />
<cell fill="9" id="148" region="-141" translation="-0.03698302711710488 -0.19245493184241047 -0.10474284149572705" universe="15" />
<cell fill="9" id="149" region="-142" translation="-0.02428069661424781 0.05168393238830282 0.1302704892646539" universe="25" />
<cell fill="9" id="150" region="-143" translation="-0.02428069661424781 0.05168393238830282 -0.20306284406867936" universe="34" />
<cell fill="9" id="151" region="-144" translation="0.04578051975994746 0.1175901605138544 -0.0038022862212453434" universe="35" />
<cell fill="9" id="152" region="-145" translation="-0.013741908464450836 0.18016577553053154 0.20276897514248216" universe="20" />
<cell fill="9" id="153" region="-146" translation="-0.013741908464450836 -0.15316755780280183 0.20276897514248216" universe="23" />
<cell fill="9" id="154" region="-147" translation="-0.013741908464450836 0.18016577553053154 -0.1305643581908511" universe="29" />
<cell fill="9" id="155" region="-148" translation="-0.013741908464450836 -0.15316755780280183 -0.1305643581908511" universe="32" />
<cell fill="9" id="156" region="-149" translation="0.19334606515602848 0.066228023881572 -0.07131104153532436" universe="27" />
<cell fill="9" id="157" region="-150" translation="-0.13998726817730478 0.066228023881572 -0.07131104153532436" universe="28" />
<cell fill="9" id="158" region="-151" translation="-0.031185656140686913 0.155914746052082 0.15331720509241947" universe="16" />
<cell fill="9" id="159" region="-152" translation="-0.031185656140686913 -0.17741858728125126 0.15331720509241947" universe="19" />
<cell fill="9" id="160" region="-153" translation="-0.031185656140686913 0.155914746052082 -0.1800161282409139" universe="25" />
<cell fill="9" id="161" region="-154" translation="-0.031185656140686913 -0.17741858728125126 -0.1800161282409139" universe="28" />
<cell fill="9" id="162" region="-155" translation="0.08018004492442865 0.016826191928232426 -0.016389596762212966" universe="36" />
<cell fill="9" id="163" region="-156" translation="0.00483733774062417 0.08148156718302602 -0.09280826916311341" universe="15" />
<cell fill="9" id="164" region="-157" translation="0.0978117791120118 -0.06105974469736897 -0.07844553364014112" universe="26" />
<cell fill="9" id="165" region="-158" translation="0.0339716094789545 0.044675266050854034 0.18588381767108564" universe="23" />
<cell fill="9" id="166" region="-159" translation="0.0339716094789545 0.044675266050854034 -0.14744951566224762" universe="32" />
<cell fill="9" id="167" region="-160" translation="0.15974177782488064 -0.11470938473074832 -0.055880627694202434" universe="24" />
<cell fill="9" id="168" region="-161" translation="-0.17359155550845262 -0.11470938473074832 -0.055880627694202434" universe="25" />
<cell fill="9" id="169" region="-162" translation="0.007714449992858363 -0.07841911930069978 0.019169121324834393" universe="27" />
<cell fill="9" id="170" region="-163" translation="-0.09772496056025104 -0.009435582016802613 -0.0973407871549632" universe="15" />
<cell fill="9" id="171" region="-164" translation="-0.08460405234526575 0.18619630211681182 0.10902502186367324" universe="32" />
<cell fill="9" id="172" region="-165" translation="-0.08460405234526575 -0.14713703121652144 0.10902502186367324" universe="35" />
<cell fill="9" id="173" region="-166" translation="0.08530970516294267 -0.09740948712101977 0.031538023054709596" universe="15" />
<cell fill="9" id="174" region="-167" translation="0.002049400245853761 0.10800782833319489 -0.08566939881823532" universe="36" />
<cell fill="9" id="175" region="-168" translation="0.036269774055772475 -0.0034880407315701634 0.08814057857502322" universe="18" />
<cell fill="9" id="176" region="-169" translation="0.012607957648281654 0.08090056062626749 0.0712211465420014" universe="27" />
<cell fill="9" id="177" region="-170" translation="-0.03741489943578313 0.1221086949309545 0.0439406213163509" universe="21" />
<cell fill="9" id="178" region="-171" translation="0.0851566223435044 -0.1191899586548319 -0.07364696787394387" universe="31" />
<cell fill="9" id="179" region="-172" translation="-0.03992848096555457 0.020214072912877246 -0.11315245980004196" universe="37" />
<cell fill="9" id="180" region="-173" translation="-0.050315754084578224 0.017099968565308377 0.056173125204605934" universe="25" />
<cell fill="9" id="181" region="-174" translation="-0.06766398274549851 -0.07303578778642877 0.005410963730880458" universe="30" />
<cell fill="9" id="182" region="-175" translation="0.06408439016382617 0.05853632250550789 0.00432158793112436" universe="21" />
<cell fill="9" id="183" region="-176" translation="-0.013801059755509382 0.20222454587424032 0.19241766819445416" universe="12" />
<cell fill="9" id="184" region="-177" translation="-0.013801059755509382 -0.13110878745909305 0.19241766819445416" universe="15" />
<cell fill="9" id="185" region="-178" translation="-0.013801059755509382 0.20222454587424032 -0.1409156651388792" universe="21" />
<cell fill="9" id="186" region="-179" translation="-0.013801059755509382 -0.13110878745909305 -0.1409156651388792" universe="24" />
<cell fill="9" id="187" region="-180" translation="0.03522733749799645 0.11305459403611595 0.10295023150858529" universe="24" />
<cell fill="9" id="188" region="-181" translation="-0.03831660450870228 -0.09880556873790897 0.08578673946744877" universe="12" />
<cell fill="9" id="189" region="-182" translation="0.03782024089160585 0.07732392719766301 -0.002829721222114334" universe="32" />
<cell fill="9" id="190" region="-183" translation="-0.060112483234699754 -0.06134051474053648 -0.04363492058502072" universe="37" />
<cell fill="9" id="191" region="-184" translation="0.10930502703326198 -0.020465939386398402 0.15848543253913627" universe="26" />
<cell fill="9" id="192" region="-185" translation="0.10930502703326198 -0.020465939386398402 -0.174847900794197" universe="35" />
<cell fill="9" id="193" region="-186" translation="-0.04821581350719811 -0.10913639479587178 -0.11108700962300094" universe="11" />
<cell fill="9" id="194" region="-187" translation="-0.09934364058994583 0.10405480441904197 -0.0241798283786806" universe="13" />
<cell fill="9" id="195" region="-188" translation="0.11425630804159204 0.19090246541367445 -0.06077533762167586" universe="12" />
<cell fill="9" id="196" region="-189" translation="0.11425630804159204 -0.14243086791965892 -0.06077533762167586" universe="15" />
<cell fill="9" id="197" region="-190" translation="0.0217205011905508 0.02506675532845576 0.029520031599966412" universe="14" />
<cell fill="9" id="198" region="-191" translation="0.12543650024083502 0.19371057833811733 -0.04147065769319469" universe="23" />
<cell fill="9" id="199" region="-192" translation="-0.20789683309249835 0.19371057833811733 -0.04147065769319469" universe="24" />
<cell fill="9" id="200" region="-193" translation="0.12543650024083502 -0.13962275499521593 -0.04147065769319469" universe="26" />
<cell fill="9" id="201" region="-194" translation="-0.20789683309249835 -0.13962275499521593 -0.04147065769319469" universe="27" />
<cell fill="9" id="202" region="-195" translation="-0.10385697059087434 -0.07239894918409101 0.047733316833160344" universe="15" />
<cell fill="9" id="203" region="-196" translation="-0.02484533723289073 0.03270050374260325 0.009261180540203251" universe="26" />
<cell fill="9" id="204" region="-197" translation="-0.10535768832641407 -0.10806169784882003 0.009669056668934639" universe="11" />
<cell fill="9" id="205" region="-198" translation="0.20034387531341857 0.02227169438582799 0.18731645229850835" universe="21" />
<cell fill="9" id="206" region="-199" translation="-0.13298945801991469 0.02227169438582799 0.18731645229850835" universe="22" />
<cell fill="9" id="207" region="-200" translation="0.20034387531341857 0.02227169438582799 -0.1460168810348249" universe="30" />
<cell fill="9" id="208" region="-201" translation="-0.13298945801991469 0.02227169438582799 -0.1460168810348249" universe="31" />
<cell fill="9" id="209" region="-202" translation="0.1631199405760454 0.04092483075648701 0.07754240264809376" universe="15" />
<cell fill="9" id="210" region="-203" translation="-0.17021339275728786 0.04092483075648701 0.07754240264809376" universe="16" />
<cell fill="9" id="211" region="-204" translation="0.102073447728939 -0.060687493103351975 0.01519685776716928" universe="28" />
<cell fill="9" id="212" region="-205" translation="0.07991907014916044 0.13595762576986914 -0.09622087197472673" universe="23" />
<cell fill="9" id="213" region="-206" translation="0.07991907014916044 -0.19737570756346412 -0.09622087197472673" universe="26" />
<cell fill="9" id="214" region="-207" translation="0.06943697893246592 0.16968387178879557 0.11988276699391809" universe="21" />
<cell fill="9" id="215" region="-208" translation="0.06943697893246592 -0.1636494615445378 0.11988276699391809" universe="24" />
<cell fill="9" id="216" region="-209" translation="-0.07059889277962383 0.1489570802132021 0.09503214710980579" universe="29" />
<cell fill="9" id="217" region="-210" translation="-0.07059889277962383 -0.18437625312013128 0.09503214710980579" universe="32" />
<cell fill="9" id="218" region="-211" translation="0.010468267263955 0.15608028424842002 -0.00511339431390323" universe="31" />
<cell fill="9" id="219" region="-212" translation="0.010468267263955 -0.17725304908491335 -0.00511339431390323" universe="34" />
<cell fill="9" id="220" region="-213" translation="0.15972123417512762 0.06883522628651784 -0.11009587369358387" universe="35" />
<cell fill="9" id="221" region="-214" translation="-0.17361209915820575 0.06883522628651784 -0.11009587369358387" universe="36" />
<cell fill="9" id="222" region="-215" translation="0.08981179676970563 0.06434186205946246 0.032607233968534766" universe="16" />
<cell fill="9" id="223" region="-216" translation="0.0033702311569031584 0.10040789537086448 0.1867831868031803" universe="28" />
<cell fill="9" id="224" region="-217" translation="0.0033702311569031584 0.10040789537086448 -0.14655014653015297" universe="37" />
<cell fill="9" id="225" region="-218" translation="0.05329895281727448 -0.02881629065525937 0.15193411713913396" universe="20" />
<cell fill="9" id="226" region="-219" translation="0.05329895281727448 -0.02881629065525937 -0.1813992161941993" universe="29" />
<cell fill="9" id="227" region="-220" translation="0.14663786554095865 -0.0001831711922081758 0.173437280372308" universe="14" />
<cell fill="9" id="228" region="-221" translation="-0.18669546779237473 -0.0001831711922081758 0.173437280372308" universe="15" />
<cell fill="9" id="229" region="-222" translation="0.14663786554095865 -0.0001831711922081758 -0.15989605296102538" universe="23" />
<cell fill="9" id="230" region="-223" translation="-0.18669546779237473 -0.0001831711922081758 -0.15989605296102538" universe="24" />
<cell fill="9" id="231" region="-224" translation="0.006886156712931468 0.0325721225173089 -0.10785254014381473" universe="19" />
<cell fill="9" id="232" region="-225" translation="0.05946426530734861 0.17562994884896627 0.11256068342977466" universe="29" />
<cell fill="9" id="233" region="-226" translation="0.05946426530734861 -0.1577033844843671 0.11256068342977466" universe="32" />
<cell fill="9" id="234" region="-227" translation="-0.0745211393530899 0.18602539894086317 0.07061211191996841" universe="13" />
<cell fill="9" id="235" region="-228" translation="-0.0745211393530899 -0.1473079343924702 0.07061211191996841" universe="16" />
<cell fill="9" id="236" region="-229" translation="0.15971361633210523 -0.02416800360737892 0.062334297185282495" universe="36" />
<cell fill="9" id="237" region="-230" translation="-0.17361971700122802 -0.02416800360737892 0.062334297185282495" universe="37" />
<cell fill="9" id="238" region="-231" translation="-0.014191419448261688 0.11114945107218455 0.0903966514577691" universe="18" />
<cell fill="9" id="239" region="-232" translation="0.20641337800388493 -0.04689191572037532 0.03093832014609521" universe="12" />
<cell fill="9" id="240" region="-233" translation="-0.12691995532944833 -0.04689191572037532 0.03093832014609521" universe="13" />
<cell fill="9" id="241" region="-234" translation="0.042925982468302815 0.0705557158479822 -0.09611246805643225" universe="31" />
<cell fill="9" id="242" region="-235" translation="0.09174118398607445 -0.02102680816462299 -0.12074712654412828" universe="27" />
<cell fill="9" id="243" region="-236" translation="0.1871144659776534 0.14219092895822716 0.0030395151604761805" universe="29" />
<cell fill="9" id="244" region="-237" translation="-0.14621886735567996 0.14219092895822716 0.0030395151604761805" universe="30" />
<cell fill="9" id="245" region="-238" translation="0.1871144659776534 -0.1911424043751062 0.0030395151604761805" universe="32" />
<cell fill="9" id="246" region="-239" translation="-0.14621886735567996 -0.1911424043751062 0.0030395151604761805" universe="33" />
<cell fill="9" id="247" region="-240" translation="-0.08858601205119498 -0.05740809172565153 0.0018937978357634888" universe="29" />
<cell fill="9" id="248" region="-241" translation="-0.06956272452538859 -0.03258611645335985 0.1876749617320655" universe="19" />
<cell fill="9" id="249" region="-242" translation="-0.06956272452538859 -0.03258611645335985 -0.14565837160126788" universe="28" />
<cell fill="9" id="250" region="-243" translation="0.06480048668590577 0.08039356693483157 -0.0495807099830502" universe="12" />
<cell fill="9" id="251" region="-244" translation="0.11976882848311299 0.024414887718198774 0.059001075831400684" universe="26" />
<cell fill="9" id="252" region="-245" translation="0.055815690196973966 -0.03866224334773988 0.12934415570493119" universe="16" />
<cell fill="9" id="253" region="-246" translation="0.055815690196973966 -0.03866224334773988 -0.20398917762840219" universe="25" />
<cell fill="9" id="254" region="-247" translation="-0.07057140884385227 -0.033261585924167725 -0.11308117958912334" universe="19" />
<cell fill="9" id="255" region="-248" translation="0.0191891610992464 -0.08777511864372084 0.09496767886953814" universe="13" />
<cell fill="9" id="256" region="-249" translation="0.11357577214048964 -0.07231206070759028 -0.01862315233444045" universe="16" />
<cell fill="9" id="257" region="-250" translation="0.028822870329182626 0.09660360434040871 -0.10994545899370212" universe="29" />
<cell fill="9" id="258" region="-251" translation="-0.030272006016200004 0.04272149160139638 -0.11143715881676097" universe="26" />
<cell fill="9" id="259" region="-252" translation="0.09719339210824351 0.04131007428864286 0.14476192535372884" universe="19" />
<cell fill="9" id="260" region="-253" translation="0.09719339210824351 0.04131007428864286 -0.18857140797960453" universe="28" />
<cell fill="9" id="261" region="-254" translation="0.1075803128789849 -0.02104725713738881 -0.03274843538002781" universe="14" />
<cell fill="9" id="262" region="-255" translation="0.1392019576325615 -0.08814436128642017 -0.11479828495132216" universe="12" />
<cell fill="9" id="263" region="-256" translation="-0.19413137570077177 -0.08814436128642017 -0.11479828495132216" universe="13" />
<cell fill="9" id="264" region="-257" translation="0.10847197677361597 0.1461592302081176 0.08841042383901798" universe="22" />
<cell fill="9" id="265" region="-258" translation="0.10847197677361597 -0.18717410312521576 0.08841042383901798" universe="25" />
<cell fill="9" id="266" region="-259" translation="0.045127058382085194 0.0967807216119615 0.0967653665331849" universe="37" />
<cell fill="9" id="267" region="-260" translation="-0.022464471745497094 0.07259277205138148 0.10785219865057927" universe="20" />
<cell fill="9" id="268" region="-261" translation="0.10606353369903221 0.03928703229725711 0.17228776926768086" universe="25" />
<cell fill="9" id="269" region="-262" translation="0.10606353369903221 0.03928703229725711 -0.1610455640656524" universe="34" />
<cell fill="9" id="270" region="-263" translation="0.14815941963538226 0.11277655887534538 0.03808687169681996" universe="21" />
<cell fill="9" id="271" region="-264" translation="-0.185173913697951 0.11277655887534538 0.03808687169681996" universe="22" />
<cell fill="9" id="272" region="-265" translation="0.15693581669068946 0.10114531834923532 -0.04992356195780889" universe="11" />
<cell fill="9" id="273" region="-266" translation="-0.17639751664264391 0.10114531834923532 -0.04992356195780889" universe="12" />
<cell fill="9" id="274" region="-267" translation="0.13264357875679378 0.10919805128102966 -0.04769549879176793" universe="26" />
<cell fill="9" id="275" region="-268" translation="-0.2006897545765396 0.10919805128102966 -0.04769549879176793" universe="27" />
<cell fill="9" id="276" region="-269" translation="0.13916564434634993 0.13134319648704007 0.07015912178562622" universe="33" />
<cell fill="9" id="277" region="-270" translation="-0.19416768898698333 0.13134319648704007 0.07015912178562622" universe="34" />
<cell fill="9" id="278" region="-271" translation="0.13916564434634993 -0.2019901368462932 0.07015912178562622" universe="36" />
<cell fill="9" id="279" region="-272" translation="-0.19416768898698333 -0.2019901368462932 0.07015912178562622" universe="37" />
<cell fill="9" id="280" region="-273" translation="-0.10026688643231585 0.1564443552698941 0.1751728484794038" universe="12" />
<cell fill="9" id="281" region="-274" translation="-0.10026688643231585 -0.17688897806343928 0.1751728484794038" universe="15" />
<cell fill="9" id="282" region="-275" translation="-0.10026688643231585 0.1564443552698941 -0.15816048485392958" universe="21" />
<cell fill="9" id="283" region="-276" translation="-0.10026688643231585 -0.17688897806343928 -0.15816048485392958" universe="24" />
<cell fill="9" id="284" region="-277" translation="0.16555436030710213 -0.015531455219433332 0.02691614144169241" universe="35" />
<cell fill="9" id="285" region="-278" translation="-0.16777897302623124 -0.015531455219433332 0.02691614144169241" universe="36" />
<cell fill="9" id="286" region="-279" translation="0.152805274648522 0.18166556620660584 0.040488366683789634" universe="20" />
<cell fill="9" id="287" region="-280" translation="-0.18052805868481137 0.18166556620660584 0.040488366683789634" universe="21" />
<cell fill="9" id="288" region="-281" translation="0.152805274648522 -0.15166776712672753 0.040488366683789634" universe="23" />
<cell fill="9" id="289" region="-282" translation="-0.18052805868481137 -0.15166776712672753 0.040488366683789634" universe="24" />
<cell fill="9" id="290" region="-283" translation="0.07231116694829032 0.08785370537091952 0.09997055589943346" universe="15" />
<cell fill="9" id="291" region="-284" translation="-0.10576424362412257 0.09874497232579027 -0.05820080940738992" universe="11" />
<cell fill="9" id="292" region="-285" translation="0.046877953125145755 -0.059492732184222796 -0.055635341857650844" universe="12" />
<cell fill="9" id="293" region="-286" translation="0.1239423066569788 0.14183046274229005 -0.06583818749209458" universe="30" />
<cell fill="9" id="294" region="-287" translation="0.1239423066569788 -0.19150287059104332 -0.06583818749209458" universe="33" />
<cell fill="9" id="295" region="-288" translation="0.0013087859341976982 -0.06327594480884835 -0.05382522074205143" universe="18" />
<cell fill="9" id="296" region="-289" translation="0.11058883669906516 -0.038954175820645864 0.16834558789033005" universe="19" />
<cell fill="9" id="297" region="-290" translation="0.11058883669906516 -0.038954175820645864 -0.16498774544300332" universe="28" />
<cell fill="9" id="298" region="-291" translation="-0.02657010065724863 0.013144978841080679 0.050587944514051575" universe="32" />
<cell id="299" material="18" region="139 186 197 265 284" universe="11" />
<cell id="300" material="18" region="140 176 181 188 232 243 255 266 273 285" universe="12" />
<cell id="301" material="18" region="136 187 227 233 248 256" universe="13" />
@ -199,7 +199,7 @@
<cell id="325" material="18" region="172 183 217 230 259 272" universe="37" />
<cell id="326" material="18" universe="38" />
<lattice id="10">
<pitch>0.333333333333 0.333333333333 0.333333333333</pitch>
<pitch>0.3333333333333333 0.3333333333333333 0.3333333333333333</pitch>
<outer>38</outer>
<dimension>3 3 3</dimension>
<lower_left>-0.5 -0.5 -0.5</lower_left>
@ -226,170 +226,170 @@
<surface boundary="reflective" coeffs="0.5" id="125" type="y-plane" />
<surface boundary="reflective" coeffs="-0.5" id="126" type="z-plane" />
<surface boundary="reflective" coeffs="0.5" id="127" type="z-plane" />
<surface coeffs="-0.00140620118176 -0.0152577471673 -0.0918476696602 0.04225" id="128" type="sphere" />
<surface coeffs="0.109099026398 -0.00417917776733 -0.0462409301859 0.04225" id="129" type="sphere" />
<surface coeffs="0.138783366528 -0.0690071053688 -0.0384882149749 0.04225" id="130" type="sphere" />
<surface coeffs="-0.194549966806 -0.0690071053688 -0.0384882149749 0.04225" id="131" type="sphere" />
<surface coeffs="-0.0984645519108 -0.0259403806947 -0.0615517493329 0.04225" id="132" type="sphere" />
<surface coeffs="-0.0932159178431 -0.122488574824 -0.0499980238428 0.04225" id="133" type="sphere" />
<surface coeffs="0.202819899608 0.0850151469064 0.0743119884463 0.04225" id="134" type="sphere" />
<surface coeffs="-0.130513433725 0.0850151469064 0.0743119884463 0.04225" id="135" type="sphere" />
<surface coeffs="0.03417350411 -0.0964115371994 -0.101120980927 0.04225" id="136" type="sphere" />
<surface coeffs="0.0379131188424 0.0687077251904 -0.108757520396 0.04225" id="137" type="sphere" />
<surface coeffs="0.0738800814064 -0.071302275054 -0.0978298256419 0.04225" id="138" type="sphere" />
<surface coeffs="0.0889721475441 0.0869416521141 0.075877373016 0.04225" id="139" type="sphere" />
<surface coeffs="-0.0369830271171 0.140878401491 -0.104742841496 0.04225" id="140" type="sphere" />
<surface coeffs="-0.0369830271171 -0.192454931842 -0.104742841496 0.04225" id="141" type="sphere" />
<surface coeffs="-0.0242806966142 0.0516839323883 0.130270489265 0.04225" id="142" type="sphere" />
<surface coeffs="-0.0242806966142 0.0516839323883 -0.203062844069 0.04225" id="143" type="sphere" />
<surface coeffs="0.0457805197599 0.117590160514 -0.00380228622125 0.04225" id="144" type="sphere" />
<surface coeffs="-0.0137419084645 0.180165775531 0.202768975142 0.04225" id="145" type="sphere" />
<surface coeffs="-0.0137419084645 -0.153167557803 0.202768975142 0.04225" id="146" type="sphere" />
<surface coeffs="-0.0137419084645 0.180165775531 -0.130564358191 0.04225" id="147" type="sphere" />
<surface coeffs="-0.0137419084645 -0.153167557803 -0.130564358191 0.04225" id="148" type="sphere" />
<surface coeffs="0.193346065156 0.0662280238816 -0.0713110415353 0.04225" id="149" type="sphere" />
<surface coeffs="-0.139987268177 0.0662280238816 -0.0713110415353 0.04225" id="150" type="sphere" />
<surface coeffs="-0.0311856561407 0.155914746052 0.153317205092 0.04225" id="151" type="sphere" />
<surface coeffs="-0.0311856561407 -0.177418587281 0.153317205092 0.04225" id="152" type="sphere" />
<surface coeffs="-0.0311856561407 0.155914746052 -0.180016128241 0.04225" id="153" type="sphere" />
<surface coeffs="-0.0311856561407 -0.177418587281 -0.180016128241 0.04225" id="154" type="sphere" />
<surface coeffs="0.0801800449244 0.0168261919282 -0.0163895967622 0.04225" id="155" type="sphere" />
<surface coeffs="0.00483733774062 0.081481567183 -0.0928082691631 0.04225" id="156" type="sphere" />
<surface coeffs="0.097811779112 -0.0610597446974 -0.0784455336401 0.04225" id="157" type="sphere" />
<surface coeffs="0.033971609479 0.0446752660509 0.185883817671 0.04225" id="158" type="sphere" />
<surface coeffs="0.033971609479 0.0446752660509 -0.147449515662 0.04225" id="159" type="sphere" />
<surface coeffs="0.159741777825 -0.114709384731 -0.0558806276942 0.04225" id="160" type="sphere" />
<surface coeffs="-0.173591555508 -0.114709384731 -0.0558806276942 0.04225" id="161" type="sphere" />
<surface coeffs="0.00771444999286 -0.0784191193007 0.0191691213248 0.04225" id="162" type="sphere" />
<surface coeffs="-0.0977249605603 -0.0094355820168 -0.097340787155 0.04225" id="163" type="sphere" />
<surface coeffs="-0.0846040523453 0.186196302117 0.109025021864 0.04225" id="164" type="sphere" />
<surface coeffs="-0.0846040523453 -0.147137031217 0.109025021864 0.04225" id="165" type="sphere" />
<surface coeffs="0.0853097051629 -0.097409487121 0.0315380230547 0.04225" id="166" type="sphere" />
<surface coeffs="0.00204940024585 0.108007828333 -0.0856693988182 0.04225" id="167" type="sphere" />
<surface coeffs="0.0362697740558 -0.00348804073157 0.088140578575 0.04225" id="168" type="sphere" />
<surface coeffs="0.0126079576483 0.0809005606263 0.071221146542 0.04225" id="169" type="sphere" />
<surface coeffs="-0.0374148994358 0.122108694931 0.0439406213164 0.04225" id="170" type="sphere" />
<surface coeffs="0.0851566223435 -0.119189958655 -0.0736469678739 0.04225" id="171" type="sphere" />
<surface coeffs="-0.0399284809656 0.0202140729129 -0.1131524598 0.04225" id="172" type="sphere" />
<surface coeffs="-0.0503157540846 0.0170999685653 0.0561731252046 0.04225" id="173" type="sphere" />
<surface coeffs="-0.0676639827455 -0.0730357877864 0.00541096373088 0.04225" id="174" type="sphere" />
<surface coeffs="0.0640843901638 0.0585363225055 0.00432158793112 0.04225" id="175" type="sphere" />
<surface coeffs="-0.0138010597555 0.202224545874 0.192417668194 0.04225" id="176" type="sphere" />
<surface coeffs="-0.0138010597555 -0.131108787459 0.192417668194 0.04225" id="177" type="sphere" />
<surface coeffs="-0.0138010597555 0.202224545874 -0.140915665139 0.04225" id="178" type="sphere" />
<surface coeffs="-0.0138010597555 -0.131108787459 -0.140915665139 0.04225" id="179" type="sphere" />
<surface coeffs="0.035227337498 0.113054594036 0.102950231509 0.04225" id="180" type="sphere" />
<surface coeffs="-0.0383166045087 -0.0988055687379 0.0857867394674 0.04225" id="181" type="sphere" />
<surface coeffs="0.0378202408916 0.0773239271977 -0.00282972122211 0.04225" id="182" type="sphere" />
<surface coeffs="-0.0601124832347 -0.0613405147405 -0.043634920585 0.04225" id="183" type="sphere" />
<surface coeffs="0.109305027033 -0.0204659393864 0.158485432539 0.04225" id="184" type="sphere" />
<surface coeffs="0.109305027033 -0.0204659393864 -0.174847900794 0.04225" id="185" type="sphere" />
<surface coeffs="-0.0482158135072 -0.109136394796 -0.111087009623 0.04225" id="186" type="sphere" />
<surface coeffs="-0.0993436405899 0.104054804419 -0.0241798283787 0.04225" id="187" type="sphere" />
<surface coeffs="0.114256308042 0.190902465414 -0.0607753376217 0.04225" id="188" type="sphere" />
<surface coeffs="0.114256308042 -0.14243086792 -0.0607753376217 0.04225" id="189" type="sphere" />
<surface coeffs="0.0217205011906 0.0250667553285 0.0295200316 0.04225" id="190" type="sphere" />
<surface coeffs="0.125436500241 0.193710578338 -0.0414706576932 0.04225" id="191" type="sphere" />
<surface coeffs="-0.207896833092 0.193710578338 -0.0414706576932 0.04225" id="192" type="sphere" />
<surface coeffs="0.125436500241 -0.139622754995 -0.0414706576932 0.04225" id="193" type="sphere" />
<surface coeffs="-0.207896833092 -0.139622754995 -0.0414706576932 0.04225" id="194" type="sphere" />
<surface coeffs="-0.103856970591 -0.0723989491841 0.0477333168332 0.04225" id="195" type="sphere" />
<surface coeffs="-0.0248453372329 0.0327005037426 0.0092611805402 0.04225" id="196" type="sphere" />
<surface coeffs="-0.105357688326 -0.108061697849 0.00966905666893 0.04225" id="197" type="sphere" />
<surface coeffs="0.200343875313 0.0222716943858 0.187316452299 0.04225" id="198" type="sphere" />
<surface coeffs="-0.13298945802 0.0222716943858 0.187316452299 0.04225" id="199" type="sphere" />
<surface coeffs="0.200343875313 0.0222716943858 -0.146016881035 0.04225" id="200" type="sphere" />
<surface coeffs="-0.13298945802 0.0222716943858 -0.146016881035 0.04225" id="201" type="sphere" />
<surface coeffs="0.163119940576 0.0409248307565 0.0775424026481 0.04225" id="202" type="sphere" />
<surface coeffs="-0.170213392757 0.0409248307565 0.0775424026481 0.04225" id="203" type="sphere" />
<surface coeffs="0.102073447729 -0.0606874931034 0.0151968577672 0.04225" id="204" type="sphere" />
<surface coeffs="0.0799190701492 0.13595762577 -0.0962208719747 0.04225" id="205" type="sphere" />
<surface coeffs="0.0799190701492 -0.197375707563 -0.0962208719747 0.04225" id="206" type="sphere" />
<surface coeffs="0.0694369789325 0.169683871789 0.119882766994 0.04225" id="207" type="sphere" />
<surface coeffs="0.0694369789325 -0.163649461545 0.119882766994 0.04225" id="208" type="sphere" />
<surface coeffs="-0.0705988927796 0.148957080213 0.0950321471098 0.04225" id="209" type="sphere" />
<surface coeffs="-0.0705988927796 -0.18437625312 0.0950321471098 0.04225" id="210" type="sphere" />
<surface coeffs="0.010468267264 0.156080284248 -0.0051133943139 0.04225" id="211" type="sphere" />
<surface coeffs="0.010468267264 -0.177253049085 -0.0051133943139 0.04225" id="212" type="sphere" />
<surface coeffs="0.159721234175 0.0688352262865 -0.110095873694 0.04225" id="213" type="sphere" />
<surface coeffs="-0.173612099158 0.0688352262865 -0.110095873694 0.04225" id="214" type="sphere" />
<surface coeffs="0.0898117967697 0.0643418620595 0.0326072339685 0.04225" id="215" type="sphere" />
<surface coeffs="0.0033702311569 0.100407895371 0.186783186803 0.04225" id="216" type="sphere" />
<surface coeffs="0.0033702311569 0.100407895371 -0.14655014653 0.04225" id="217" type="sphere" />
<surface coeffs="0.0532989528173 -0.0288162906553 0.151934117139 0.04225" id="218" type="sphere" />
<surface coeffs="0.0532989528173 -0.0288162906553 -0.181399216194 0.04225" id="219" type="sphere" />
<surface coeffs="0.146637865541 -0.000183171192208 0.173437280372 0.04225" id="220" type="sphere" />
<surface coeffs="-0.186695467792 -0.000183171192208 0.173437280372 0.04225" id="221" type="sphere" />
<surface coeffs="0.146637865541 -0.000183171192208 -0.159896052961 0.04225" id="222" type="sphere" />
<surface coeffs="-0.186695467792 -0.000183171192208 -0.159896052961 0.04225" id="223" type="sphere" />
<surface coeffs="0.00688615671293 0.0325721225173 -0.107852540144 0.04225" id="224" type="sphere" />
<surface coeffs="0.0594642653073 0.175629948849 0.11256068343 0.04225" id="225" type="sphere" />
<surface coeffs="0.0594642653073 -0.157703384484 0.11256068343 0.04225" id="226" type="sphere" />
<surface coeffs="-0.0745211393531 0.186025398941 0.07061211192 0.04225" id="227" type="sphere" />
<surface coeffs="-0.0745211393531 -0.147307934392 0.07061211192 0.04225" id="228" type="sphere" />
<surface coeffs="0.159713616332 -0.0241680036074 0.0623342971853 0.04225" id="229" type="sphere" />
<surface coeffs="-0.173619717001 -0.0241680036074 0.0623342971853 0.04225" id="230" type="sphere" />
<surface coeffs="-0.0141914194483 0.111149451072 0.0903966514578 0.04225" id="231" type="sphere" />
<surface coeffs="0.206413378004 -0.0468919157204 0.0309383201461 0.04225" id="232" type="sphere" />
<surface coeffs="-0.126919955329 -0.0468919157204 0.0309383201461 0.04225" id="233" type="sphere" />
<surface coeffs="0.0429259824683 0.070555715848 -0.0961124680564 0.04225" id="234" type="sphere" />
<surface coeffs="0.0917411839861 -0.0210268081646 -0.120747126544 0.04225" id="235" type="sphere" />
<surface coeffs="0.187114465978 0.142190928958 0.00303951516048 0.04225" id="236" type="sphere" />
<surface coeffs="-0.146218867356 0.142190928958 0.00303951516048 0.04225" id="237" type="sphere" />
<surface coeffs="0.187114465978 -0.191142404375 0.00303951516048 0.04225" id="238" type="sphere" />
<surface coeffs="-0.146218867356 -0.191142404375 0.00303951516048 0.04225" id="239" type="sphere" />
<surface coeffs="-0.0885860120512 -0.0574080917257 0.00189379783576 0.04225" id="240" type="sphere" />
<surface coeffs="-0.0695627245254 -0.0325861164534 0.187674961732 0.04225" id="241" type="sphere" />
<surface coeffs="-0.0695627245254 -0.0325861164534 -0.145658371601 0.04225" id="242" type="sphere" />
<surface coeffs="0.0648004866859 0.0803935669348 -0.0495807099831 0.04225" id="243" type="sphere" />
<surface coeffs="0.119768828483 0.0244148877182 0.0590010758314 0.04225" id="244" type="sphere" />
<surface coeffs="0.055815690197 -0.0386622433477 0.129344155705 0.04225" id="245" type="sphere" />
<surface coeffs="0.055815690197 -0.0386622433477 -0.203989177628 0.04225" id="246" type="sphere" />
<surface coeffs="-0.0705714088439 -0.0332615859242 -0.113081179589 0.04225" id="247" type="sphere" />
<surface coeffs="0.0191891610992 -0.0877751186437 0.0949676788695 0.04225" id="248" type="sphere" />
<surface coeffs="0.11357577214 -0.0723120607076 -0.0186231523344 0.04225" id="249" type="sphere" />
<surface coeffs="0.0288228703292 0.0966036043404 -0.109945458994 0.04225" id="250" type="sphere" />
<surface coeffs="-0.0302720060162 0.0427214916014 -0.111437158817 0.04225" id="251" type="sphere" />
<surface coeffs="0.0971933921082 0.0413100742886 0.144761925354 0.04225" id="252" type="sphere" />
<surface coeffs="0.0971933921082 0.0413100742886 -0.18857140798 0.04225" id="253" type="sphere" />
<surface coeffs="0.107580312879 -0.0210472571374 -0.03274843538 0.04225" id="254" type="sphere" />
<surface coeffs="0.139201957633 -0.0881443612864 -0.114798284951 0.04225" id="255" type="sphere" />
<surface coeffs="-0.194131375701 -0.0881443612864 -0.114798284951 0.04225" id="256" type="sphere" />
<surface coeffs="0.108471976774 0.146159230208 0.088410423839 0.04225" id="257" type="sphere" />
<surface coeffs="0.108471976774 -0.187174103125 0.088410423839 0.04225" id="258" type="sphere" />
<surface coeffs="0.0451270583821 0.096780721612 0.0967653665332 0.04225" id="259" type="sphere" />
<surface coeffs="-0.0224644717455 0.0725927720514 0.107852198651 0.04225" id="260" type="sphere" />
<surface coeffs="0.106063533699 0.0392870322973 0.172287769268 0.04225" id="261" type="sphere" />
<surface coeffs="0.106063533699 0.0392870322973 -0.161045564066 0.04225" id="262" type="sphere" />
<surface coeffs="0.148159419635 0.112776558875 0.0380868716968 0.04225" id="263" type="sphere" />
<surface coeffs="-0.185173913698 0.112776558875 0.0380868716968 0.04225" id="264" type="sphere" />
<surface coeffs="0.156935816691 0.101145318349 -0.0499235619578 0.04225" id="265" type="sphere" />
<surface coeffs="-0.176397516643 0.101145318349 -0.0499235619578 0.04225" id="266" type="sphere" />
<surface coeffs="0.132643578757 0.109198051281 -0.0476954987918 0.04225" id="267" type="sphere" />
<surface coeffs="-0.200689754577 0.109198051281 -0.0476954987918 0.04225" id="268" type="sphere" />
<surface coeffs="0.139165644346 0.131343196487 0.0701591217856 0.04225" id="269" type="sphere" />
<surface coeffs="-0.194167688987 0.131343196487 0.0701591217856 0.04225" id="270" type="sphere" />
<surface coeffs="0.139165644346 -0.201990136846 0.0701591217856 0.04225" id="271" type="sphere" />
<surface coeffs="-0.194167688987 -0.201990136846 0.0701591217856 0.04225" id="272" type="sphere" />
<surface coeffs="-0.100266886432 0.15644435527 0.175172848479 0.04225" id="273" type="sphere" />
<surface coeffs="-0.100266886432 -0.176888978063 0.175172848479 0.04225" id="274" type="sphere" />
<surface coeffs="-0.100266886432 0.15644435527 -0.158160484854 0.04225" id="275" type="sphere" />
<surface coeffs="-0.100266886432 -0.176888978063 -0.158160484854 0.04225" id="276" type="sphere" />
<surface coeffs="0.165554360307 -0.0155314552194 0.0269161414417 0.04225" id="277" type="sphere" />
<surface coeffs="-0.167778973026 -0.0155314552194 0.0269161414417 0.04225" id="278" type="sphere" />
<surface coeffs="0.152805274649 0.181665566207 0.0404883666838 0.04225" id="279" type="sphere" />
<surface coeffs="-0.180528058685 0.181665566207 0.0404883666838 0.04225" id="280" type="sphere" />
<surface coeffs="0.152805274649 -0.151667767127 0.0404883666838 0.04225" id="281" type="sphere" />
<surface coeffs="-0.180528058685 -0.151667767127 0.0404883666838 0.04225" id="282" type="sphere" />
<surface coeffs="0.0723111669483 0.0878537053709 0.0999705558994 0.04225" id="283" type="sphere" />
<surface coeffs="-0.105764243624 0.0987449723258 -0.0582008094074 0.04225" id="284" type="sphere" />
<surface coeffs="0.0468779531251 -0.0594927321842 -0.0556353418577 0.04225" id="285" type="sphere" />
<surface coeffs="0.123942306657 0.141830462742 -0.0658381874921 0.04225" id="286" type="sphere" />
<surface coeffs="0.123942306657 -0.191502870591 -0.0658381874921 0.04225" id="287" type="sphere" />
<surface coeffs="0.0013087859342 -0.0632759448088 -0.0538252207421 0.04225" id="288" type="sphere" />
<surface coeffs="0.110588836699 -0.0389541758206 0.16834558789 0.04225" id="289" type="sphere" />
<surface coeffs="0.110588836699 -0.0389541758206 -0.164987745443 0.04225" id="290" type="sphere" />
<surface coeffs="-0.0265701006572 0.0131449788411 0.0505879445141 0.04225" id="291" type="sphere" />
<surface coeffs="-0.0014062011817633224 -0.015257747167296776 -0.09184766966024316 0.04225" id="128" type="sphere" />
<surface coeffs="0.10909902639777394 -0.004179177767328068 -0.046240930185910245 0.04225" id="129" type="sphere" />
<surface coeffs="0.13878336652768952 -0.06900710536877097 -0.03848821497485455 0.04225" id="130" type="sphere" />
<surface coeffs="-0.19454996680564374 -0.06900710536877097 -0.03848821497485455 0.04225" id="131" type="sphere" />
<surface coeffs="-0.09846455191076986 -0.02594038069469251 -0.06155174933292362 0.04225" id="132" type="sphere" />
<surface coeffs="-0.09321591784308736 -0.12248857482372477 -0.04999802384282931 0.04225" id="133" type="sphere" />
<surface coeffs="0.2028198996079864 0.08501514690643278 0.07431198844628262 0.04225" id="134" type="sphere" />
<surface coeffs="-0.13051343372534685 0.08501514690643278 0.07431198844628262 0.04225" id="135" type="sphere" />
<surface coeffs="0.03417350410997999 -0.09641153719944834 -0.10112098092715327 0.04225" id="136" type="sphere" />
<surface coeffs="0.037913118842446136 0.06870772519039314 -0.10875752039644154 0.04225" id="137" type="sphere" />
<surface coeffs="0.07388008140640989 -0.07130227505402231 -0.09782982564187503 0.04225" id="138" type="sphere" />
<surface coeffs="0.08897214754414112 0.08694165211410448 0.07587737301598729 0.04225" id="139" type="sphere" />
<surface coeffs="-0.03698302711710488 0.1408784014909229 -0.10474284149572705 0.04225" id="140" type="sphere" />
<surface coeffs="-0.03698302711710488 -0.19245493184241047 -0.10474284149572705 0.04225" id="141" type="sphere" />
<surface coeffs="-0.02428069661424781 0.05168393238830282 0.1302704892646539 0.04225" id="142" type="sphere" />
<surface coeffs="-0.02428069661424781 0.05168393238830282 -0.20306284406867936 0.04225" id="143" type="sphere" />
<surface coeffs="0.04578051975994746 0.1175901605138544 -0.0038022862212453434 0.04225" id="144" type="sphere" />
<surface coeffs="-0.013741908464450836 0.18016577553053154 0.20276897514248216 0.04225" id="145" type="sphere" />
<surface coeffs="-0.013741908464450836 -0.15316755780280183 0.20276897514248216 0.04225" id="146" type="sphere" />
<surface coeffs="-0.013741908464450836 0.18016577553053154 -0.1305643581908511 0.04225" id="147" type="sphere" />
<surface coeffs="-0.013741908464450836 -0.15316755780280183 -0.1305643581908511 0.04225" id="148" type="sphere" />
<surface coeffs="0.19334606515602848 0.066228023881572 -0.07131104153532436 0.04225" id="149" type="sphere" />
<surface coeffs="-0.13998726817730478 0.066228023881572 -0.07131104153532436 0.04225" id="150" type="sphere" />
<surface coeffs="-0.031185656140686913 0.155914746052082 0.15331720509241947 0.04225" id="151" type="sphere" />
<surface coeffs="-0.031185656140686913 -0.17741858728125126 0.15331720509241947 0.04225" id="152" type="sphere" />
<surface coeffs="-0.031185656140686913 0.155914746052082 -0.1800161282409139 0.04225" id="153" type="sphere" />
<surface coeffs="-0.031185656140686913 -0.17741858728125126 -0.1800161282409139 0.04225" id="154" type="sphere" />
<surface coeffs="0.08018004492442865 0.016826191928232426 -0.016389596762212966 0.04225" id="155" type="sphere" />
<surface coeffs="0.00483733774062417 0.08148156718302602 -0.09280826916311341 0.04225" id="156" type="sphere" />
<surface coeffs="0.0978117791120118 -0.06105974469736897 -0.07844553364014112 0.04225" id="157" type="sphere" />
<surface coeffs="0.0339716094789545 0.044675266050854034 0.18588381767108564 0.04225" id="158" type="sphere" />
<surface coeffs="0.0339716094789545 0.044675266050854034 -0.14744951566224762 0.04225" id="159" type="sphere" />
<surface coeffs="0.15974177782488064 -0.11470938473074832 -0.055880627694202434 0.04225" id="160" type="sphere" />
<surface coeffs="-0.17359155550845262 -0.11470938473074832 -0.055880627694202434 0.04225" id="161" type="sphere" />
<surface coeffs="0.007714449992858363 -0.07841911930069978 0.019169121324834393 0.04225" id="162" type="sphere" />
<surface coeffs="-0.09772496056025104 -0.009435582016802613 -0.0973407871549632 0.04225" id="163" type="sphere" />
<surface coeffs="-0.08460405234526575 0.18619630211681182 0.10902502186367324 0.04225" id="164" type="sphere" />
<surface coeffs="-0.08460405234526575 -0.14713703121652144 0.10902502186367324 0.04225" id="165" type="sphere" />
<surface coeffs="0.08530970516294267 -0.09740948712101977 0.031538023054709596 0.04225" id="166" type="sphere" />
<surface coeffs="0.002049400245853761 0.10800782833319489 -0.08566939881823532 0.04225" id="167" type="sphere" />
<surface coeffs="0.036269774055772475 -0.0034880407315701634 0.08814057857502322 0.04225" id="168" type="sphere" />
<surface coeffs="0.012607957648281654 0.08090056062626749 0.0712211465420014 0.04225" id="169" type="sphere" />
<surface coeffs="-0.03741489943578313 0.1221086949309545 0.0439406213163509 0.04225" id="170" type="sphere" />
<surface coeffs="0.0851566223435044 -0.1191899586548319 -0.07364696787394387 0.04225" id="171" type="sphere" />
<surface coeffs="-0.03992848096555457 0.020214072912877246 -0.11315245980004196 0.04225" id="172" type="sphere" />
<surface coeffs="-0.050315754084578224 0.017099968565308377 0.056173125204605934 0.04225" id="173" type="sphere" />
<surface coeffs="-0.06766398274549851 -0.07303578778642877 0.005410963730880458 0.04225" id="174" type="sphere" />
<surface coeffs="0.06408439016382617 0.05853632250550789 0.00432158793112436 0.04225" id="175" type="sphere" />
<surface coeffs="-0.013801059755509382 0.20222454587424032 0.19241766819445416 0.04225" id="176" type="sphere" />
<surface coeffs="-0.013801059755509382 -0.13110878745909305 0.19241766819445416 0.04225" id="177" type="sphere" />
<surface coeffs="-0.013801059755509382 0.20222454587424032 -0.1409156651388792 0.04225" id="178" type="sphere" />
<surface coeffs="-0.013801059755509382 -0.13110878745909305 -0.1409156651388792 0.04225" id="179" type="sphere" />
<surface coeffs="0.03522733749799645 0.11305459403611595 0.10295023150858529 0.04225" id="180" type="sphere" />
<surface coeffs="-0.03831660450870228 -0.09880556873790897 0.08578673946744877 0.04225" id="181" type="sphere" />
<surface coeffs="0.03782024089160585 0.07732392719766301 -0.002829721222114334 0.04225" id="182" type="sphere" />
<surface coeffs="-0.060112483234699754 -0.06134051474053648 -0.04363492058502072 0.04225" id="183" type="sphere" />
<surface coeffs="0.10930502703326198 -0.020465939386398402 0.15848543253913627 0.04225" id="184" type="sphere" />
<surface coeffs="0.10930502703326198 -0.020465939386398402 -0.174847900794197 0.04225" id="185" type="sphere" />
<surface coeffs="-0.04821581350719811 -0.10913639479587178 -0.11108700962300094 0.04225" id="186" type="sphere" />
<surface coeffs="-0.09934364058994583 0.10405480441904197 -0.0241798283786806 0.04225" id="187" type="sphere" />
<surface coeffs="0.11425630804159204 0.19090246541367445 -0.06077533762167586 0.04225" id="188" type="sphere" />
<surface coeffs="0.11425630804159204 -0.14243086791965892 -0.06077533762167586 0.04225" id="189" type="sphere" />
<surface coeffs="0.0217205011905508 0.02506675532845576 0.029520031599966412 0.04225" id="190" type="sphere" />
<surface coeffs="0.12543650024083502 0.19371057833811733 -0.04147065769319469 0.04225" id="191" type="sphere" />
<surface coeffs="-0.20789683309249835 0.19371057833811733 -0.04147065769319469 0.04225" id="192" type="sphere" />
<surface coeffs="0.12543650024083502 -0.13962275499521593 -0.04147065769319469 0.04225" id="193" type="sphere" />
<surface coeffs="-0.20789683309249835 -0.13962275499521593 -0.04147065769319469 0.04225" id="194" type="sphere" />
<surface coeffs="-0.10385697059087434 -0.07239894918409101 0.047733316833160344 0.04225" id="195" type="sphere" />
<surface coeffs="-0.02484533723289073 0.03270050374260325 0.009261180540203251 0.04225" id="196" type="sphere" />
<surface coeffs="-0.10535768832641407 -0.10806169784882003 0.009669056668934639 0.04225" id="197" type="sphere" />
<surface coeffs="0.20034387531341857 0.02227169438582799 0.18731645229850835 0.04225" id="198" type="sphere" />
<surface coeffs="-0.13298945801991469 0.02227169438582799 0.18731645229850835 0.04225" id="199" type="sphere" />
<surface coeffs="0.20034387531341857 0.02227169438582799 -0.1460168810348249 0.04225" id="200" type="sphere" />
<surface coeffs="-0.13298945801991469 0.02227169438582799 -0.1460168810348249 0.04225" id="201" type="sphere" />
<surface coeffs="0.1631199405760454 0.04092483075648701 0.07754240264809376 0.04225" id="202" type="sphere" />
<surface coeffs="-0.17021339275728786 0.04092483075648701 0.07754240264809376 0.04225" id="203" type="sphere" />
<surface coeffs="0.102073447728939 -0.060687493103351975 0.01519685776716928 0.04225" id="204" type="sphere" />
<surface coeffs="0.07991907014916044 0.13595762576986914 -0.09622087197472673 0.04225" id="205" type="sphere" />
<surface coeffs="0.07991907014916044 -0.19737570756346412 -0.09622087197472673 0.04225" id="206" type="sphere" />
<surface coeffs="0.06943697893246592 0.16968387178879557 0.11988276699391809 0.04225" id="207" type="sphere" />
<surface coeffs="0.06943697893246592 -0.1636494615445378 0.11988276699391809 0.04225" id="208" type="sphere" />
<surface coeffs="-0.07059889277962383 0.1489570802132021 0.09503214710980579 0.04225" id="209" type="sphere" />
<surface coeffs="-0.07059889277962383 -0.18437625312013128 0.09503214710980579 0.04225" id="210" type="sphere" />
<surface coeffs="0.010468267263955 0.15608028424842002 -0.00511339431390323 0.04225" id="211" type="sphere" />
<surface coeffs="0.010468267263955 -0.17725304908491335 -0.00511339431390323 0.04225" id="212" type="sphere" />
<surface coeffs="0.15972123417512762 0.06883522628651784 -0.11009587369358387 0.04225" id="213" type="sphere" />
<surface coeffs="-0.17361209915820575 0.06883522628651784 -0.11009587369358387 0.04225" id="214" type="sphere" />
<surface coeffs="0.08981179676970563 0.06434186205946246 0.032607233968534766 0.04225" id="215" type="sphere" />
<surface coeffs="0.0033702311569031584 0.10040789537086448 0.1867831868031803 0.04225" id="216" type="sphere" />
<surface coeffs="0.0033702311569031584 0.10040789537086448 -0.14655014653015297 0.04225" id="217" type="sphere" />
<surface coeffs="0.05329895281727448 -0.02881629065525937 0.15193411713913396 0.04225" id="218" type="sphere" />
<surface coeffs="0.05329895281727448 -0.02881629065525937 -0.1813992161941993 0.04225" id="219" type="sphere" />
<surface coeffs="0.14663786554095865 -0.0001831711922081758 0.173437280372308 0.04225" id="220" type="sphere" />
<surface coeffs="-0.18669546779237473 -0.0001831711922081758 0.173437280372308 0.04225" id="221" type="sphere" />
<surface coeffs="0.14663786554095865 -0.0001831711922081758 -0.15989605296102538 0.04225" id="222" type="sphere" />
<surface coeffs="-0.18669546779237473 -0.0001831711922081758 -0.15989605296102538 0.04225" id="223" type="sphere" />
<surface coeffs="0.006886156712931468 0.0325721225173089 -0.10785254014381473 0.04225" id="224" type="sphere" />
<surface coeffs="0.05946426530734861 0.17562994884896627 0.11256068342977466 0.04225" id="225" type="sphere" />
<surface coeffs="0.05946426530734861 -0.1577033844843671 0.11256068342977466 0.04225" id="226" type="sphere" />
<surface coeffs="-0.0745211393530899 0.18602539894086317 0.07061211191996841 0.04225" id="227" type="sphere" />
<surface coeffs="-0.0745211393530899 -0.1473079343924702 0.07061211191996841 0.04225" id="228" type="sphere" />
<surface coeffs="0.15971361633210523 -0.02416800360737892 0.062334297185282495 0.04225" id="229" type="sphere" />
<surface coeffs="-0.17361971700122802 -0.02416800360737892 0.062334297185282495 0.04225" id="230" type="sphere" />
<surface coeffs="-0.014191419448261688 0.11114945107218455 0.0903966514577691 0.04225" id="231" type="sphere" />
<surface coeffs="0.20641337800388493 -0.04689191572037532 0.03093832014609521 0.04225" id="232" type="sphere" />
<surface coeffs="-0.12691995532944833 -0.04689191572037532 0.03093832014609521 0.04225" id="233" type="sphere" />
<surface coeffs="0.042925982468302815 0.0705557158479822 -0.09611246805643225 0.04225" id="234" type="sphere" />
<surface coeffs="0.09174118398607445 -0.02102680816462299 -0.12074712654412828 0.04225" id="235" type="sphere" />
<surface coeffs="0.1871144659776534 0.14219092895822716 0.0030395151604761805 0.04225" id="236" type="sphere" />
<surface coeffs="-0.14621886735567996 0.14219092895822716 0.0030395151604761805 0.04225" id="237" type="sphere" />
<surface coeffs="0.1871144659776534 -0.1911424043751062 0.0030395151604761805 0.04225" id="238" type="sphere" />
<surface coeffs="-0.14621886735567996 -0.1911424043751062 0.0030395151604761805 0.04225" id="239" type="sphere" />
<surface coeffs="-0.08858601205119498 -0.05740809172565153 0.0018937978357634888 0.04225" id="240" type="sphere" />
<surface coeffs="-0.06956272452538859 -0.03258611645335985 0.1876749617320655 0.04225" id="241" type="sphere" />
<surface coeffs="-0.06956272452538859 -0.03258611645335985 -0.14565837160126788 0.04225" id="242" type="sphere" />
<surface coeffs="0.06480048668590577 0.08039356693483157 -0.0495807099830502 0.04225" id="243" type="sphere" />
<surface coeffs="0.11976882848311299 0.024414887718198774 0.059001075831400684 0.04225" id="244" type="sphere" />
<surface coeffs="0.055815690196973966 -0.03866224334773988 0.12934415570493119 0.04225" id="245" type="sphere" />
<surface coeffs="0.055815690196973966 -0.03866224334773988 -0.20398917762840219 0.04225" id="246" type="sphere" />
<surface coeffs="-0.07057140884385227 -0.033261585924167725 -0.11308117958912334 0.04225" id="247" type="sphere" />
<surface coeffs="0.0191891610992464 -0.08777511864372084 0.09496767886953814 0.04225" id="248" type="sphere" />
<surface coeffs="0.11357577214048964 -0.07231206070759028 -0.01862315233444045 0.04225" id="249" type="sphere" />
<surface coeffs="0.028822870329182626 0.09660360434040871 -0.10994545899370212 0.04225" id="250" type="sphere" />
<surface coeffs="-0.030272006016200004 0.04272149160139638 -0.11143715881676097 0.04225" id="251" type="sphere" />
<surface coeffs="0.09719339210824351 0.04131007428864286 0.14476192535372884 0.04225" id="252" type="sphere" />
<surface coeffs="0.09719339210824351 0.04131007428864286 -0.18857140797960453 0.04225" id="253" type="sphere" />
<surface coeffs="0.1075803128789849 -0.02104725713738881 -0.03274843538002781 0.04225" id="254" type="sphere" />
<surface coeffs="0.1392019576325615 -0.08814436128642017 -0.11479828495132216 0.04225" id="255" type="sphere" />
<surface coeffs="-0.19413137570077177 -0.08814436128642017 -0.11479828495132216 0.04225" id="256" type="sphere" />
<surface coeffs="0.10847197677361597 0.1461592302081176 0.08841042383901798 0.04225" id="257" type="sphere" />
<surface coeffs="0.10847197677361597 -0.18717410312521576 0.08841042383901798 0.04225" id="258" type="sphere" />
<surface coeffs="0.045127058382085194 0.0967807216119615 0.0967653665331849 0.04225" id="259" type="sphere" />
<surface coeffs="-0.022464471745497094 0.07259277205138148 0.10785219865057927 0.04225" id="260" type="sphere" />
<surface coeffs="0.10606353369903221 0.03928703229725711 0.17228776926768086 0.04225" id="261" type="sphere" />
<surface coeffs="0.10606353369903221 0.03928703229725711 -0.1610455640656524 0.04225" id="262" type="sphere" />
<surface coeffs="0.14815941963538226 0.11277655887534538 0.03808687169681996 0.04225" id="263" type="sphere" />
<surface coeffs="-0.185173913697951 0.11277655887534538 0.03808687169681996 0.04225" id="264" type="sphere" />
<surface coeffs="0.15693581669068946 0.10114531834923532 -0.04992356195780889 0.04225" id="265" type="sphere" />
<surface coeffs="-0.17639751664264391 0.10114531834923532 -0.04992356195780889 0.04225" id="266" type="sphere" />
<surface coeffs="0.13264357875679378 0.10919805128102966 -0.04769549879176793 0.04225" id="267" type="sphere" />
<surface coeffs="-0.2006897545765396 0.10919805128102966 -0.04769549879176793 0.04225" id="268" type="sphere" />
<surface coeffs="0.13916564434634993 0.13134319648704007 0.07015912178562622 0.04225" id="269" type="sphere" />
<surface coeffs="-0.19416768898698333 0.13134319648704007 0.07015912178562622 0.04225" id="270" type="sphere" />
<surface coeffs="0.13916564434634993 -0.2019901368462932 0.07015912178562622 0.04225" id="271" type="sphere" />
<surface coeffs="-0.19416768898698333 -0.2019901368462932 0.07015912178562622 0.04225" id="272" type="sphere" />
<surface coeffs="-0.10026688643231585 0.1564443552698941 0.1751728484794038 0.04225" id="273" type="sphere" />
<surface coeffs="-0.10026688643231585 -0.17688897806343928 0.1751728484794038 0.04225" id="274" type="sphere" />
<surface coeffs="-0.10026688643231585 0.1564443552698941 -0.15816048485392958 0.04225" id="275" type="sphere" />
<surface coeffs="-0.10026688643231585 -0.17688897806343928 -0.15816048485392958 0.04225" id="276" type="sphere" />
<surface coeffs="0.16555436030710213 -0.015531455219433332 0.02691614144169241 0.04225" id="277" type="sphere" />
<surface coeffs="-0.16777897302623124 -0.015531455219433332 0.02691614144169241 0.04225" id="278" type="sphere" />
<surface coeffs="0.152805274648522 0.18166556620660584 0.040488366683789634 0.04225" id="279" type="sphere" />
<surface coeffs="-0.18052805868481137 0.18166556620660584 0.040488366683789634 0.04225" id="280" type="sphere" />
<surface coeffs="0.152805274648522 -0.15166776712672753 0.040488366683789634 0.04225" id="281" type="sphere" />
<surface coeffs="-0.18052805868481137 -0.15166776712672753 0.040488366683789634 0.04225" id="282" type="sphere" />
<surface coeffs="0.07231116694829032 0.08785370537091952 0.09997055589943346 0.04225" id="283" type="sphere" />
<surface coeffs="-0.10576424362412257 0.09874497232579027 -0.05820080940738992 0.04225" id="284" type="sphere" />
<surface coeffs="0.046877953125145755 -0.059492732184222796 -0.055635341857650844 0.04225" id="285" type="sphere" />
<surface coeffs="0.1239423066569788 0.14183046274229005 -0.06583818749209458 0.04225" id="286" type="sphere" />
<surface coeffs="0.1239423066569788 -0.19150287059104332 -0.06583818749209458 0.04225" id="287" type="sphere" />
<surface coeffs="0.0013087859341976982 -0.06327594480884835 -0.05382522074205143 0.04225" id="288" type="sphere" />
<surface coeffs="0.11058883669906516 -0.038954175820645864 0.16834558789033005 0.04225" id="289" type="sphere" />
<surface coeffs="0.11058883669906516 -0.038954175820645864 -0.16498774544300332 0.04225" id="290" type="sphere" />
<surface coeffs="-0.02657010065724863 0.013144978841080679 0.050587944514051575 0.04225" id="291" type="sphere" />
</geometry>
<?xml version='1.0' encoding='utf-8'?>
<materials>

View file

@ -1,2 +1,2 @@
k-combined:
1.681659E+00 7.262745E-02
1.683226E+00 7.383559E-02

View file

@ -19,21 +19,22 @@ def test_get_atoms(res):
t, n = res.get_atoms("1", "Xe135")
t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0]
n_ref = [6.6747328233649218e+08, 3.5421791038348462e+14,
3.6208592242443462e+14, 3.3799758969347038e+14]
n_ref = [6.6747328233649218e+08, 3.4589992012016338e+14,
3.5635060369969225e+14, 3.5195113630100188e+14]
np.testing.assert_allclose(t, t_ref)
np.testing.assert_allclose(n, n_ref)
def test_get_reaction_rate(res):
"""Tests evaluating reaction rate."""
t, r = res.get_reaction_rate("1", "Xe135", "(n,gamma)")
t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0]
n_ref = np.array([6.6747328233649218e+08, 3.5421791038348462e+14,
3.6208592242443462e+14, 3.3799758969347038e+14])
xs_ref = np.array([4.0594392323131994e-05, 3.9249546927524987e-05,
3.8394587728581798e-05, 4.1521845978371697e-05])
n_ref = np.array([6.6747328233649218e+08, 3.4589992012016338e+14,
3.5635060369969225e+14, 3.5195113630100188e+14])
xs_ref = np.array([4.1340608491478010e-05, 4.1120938620476115e-05,
4.3341529708654921e-05, 3.8716623651147821e-05])
np.testing.assert_allclose(t, t_ref)
np.testing.assert_allclose(r, n_ref * xs_ref)
@ -44,8 +45,8 @@ def test_get_eigenvalue(res):
t, k = res.get_eigenvalue()
t_ref = [0.0, 1296000.0, 2592000.0, 3888000.0]
k_ref = [1.181281798790367, 1.1798750921988739, 1.1965943696058159,
1.2207119847790813]
k_ref = [1.1798617938070866, 1.1745713141097096, 1.1732427763487678,
1.213699703239334]
np.testing.assert_allclose(t, t_ref)
np.testing.assert_allclose(k, k_ref)

View file

@ -3,6 +3,5 @@ set -ex
cd $HOME
git clone https://github.com/njoy/NJOY2016
cd NJOY2016
sed -i -e 's/5\.1/4.8/' CMakeLists.txt
mkdir build && cd build
cmake -Dstatic=on .. && make 2>/dev/null && sudo make install

View file

@ -7,20 +7,13 @@ set -ex
# Upgrade pip before doing anything else
pip install --upgrade pip
# Running OpenMC's setup.py requires numpy/cython already. NumPy float
# formatting changed in version 1.14, so stick with a lower version until we can
# handle it in our test suite
pip install 'numpy<1.14'
# Running OpenMC's setup.py requires numpy/cython already
pip install numpy
pip install cython
# pytest installed by default -- make sure we get latest
pip install --upgrade pytest
# Pandas stopped supporting Python 3.4 with version 0.21
if [[ $TRAVIS_PYTHON_VERSION == "3.4" ]]; then
pip install pandas==0.20.3
fi
# Install mpi4py for MPI configurations
if [[ $MPI == 'y' ]]; then
pip install --no-binary=mpi4py mpi4py

View file

@ -2,7 +2,7 @@
set -ex
# Run source check
if [[ $TRAVIS_PYTHON_VERSION == "3.4" && $OMP == 'n' && $MPI == 'n' ]]; then
if [[ $TRAVIS_PYTHON_VERSION == "3.5" && $OMP == 'n' && $MPI == 'n' ]]; then
pushd tests && python check_source.py && popd
fi

191
vendor/xtensor/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,191 @@
############################################################################
# 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. #
############################################################################
cmake_minimum_required(VERSION 3.1)
project(xtensor)
set(XTENSOR_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
# Versionning
# ===========
file(STRINGS "${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_config.hpp" xtensor_version_defines
REGEX "#define XTENSOR_VERSION_(MAJOR|MINOR|PATCH)")
foreach(ver ${xtensor_version_defines})
if(ver MATCHES "#define XTENSOR_VERSION_(MAJOR|MINOR|PATCH) +([^ ]+)$")
set(XTENSOR_VERSION_${CMAKE_MATCH_1} "${CMAKE_MATCH_2}" CACHE INTERNAL "")
endif()
endforeach()
set(${PROJECT_NAME}_VERSION
${XTENSOR_VERSION_MAJOR}.${XTENSOR_VERSION_MINOR}.${XTENSOR_VERSION_PATCH})
message(STATUS "Building xtensor v${${PROJECT_NAME}_VERSION}")
# Dependencies
# ============
#find_package(xtl 0.4.9 REQUIRED)
#message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl")
#find_package(nlohmann_json 3.1.1)
# Build
# =====
set(XTENSOR_HEADERS
${XTENSOR_INCLUDE_DIR}/xtensor/xaccumulator.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xadapt.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xarray.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xassign.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xaxis_iterator.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xbroadcast.hpp
${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/xeval.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xexception.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xexpression.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/xindex_view.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xinfo.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xio.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xiterable.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xiterator.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xjson.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xlayout.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xmath.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xnoalias.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xnorm.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xnpy.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xoffset_view.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xoperation.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xoptional.hpp
${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/xrandom.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xreducer.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xscalar.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xsemantic.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xshape.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xslice.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xsort.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xstorage.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xstrided_view.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xstrided_view_base.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xstrides.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xtensor.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_config.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_forward.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xtensor_simd.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xutils.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xvectorize.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xview.hpp
${XTENSOR_INCLUDE_DIR}/xtensor/xview_utils.hpp
)
add_library(xtensor INTERFACE)
target_include_directories(xtensor INTERFACE $<BUILD_INTERFACE:${XTENSOR_INCLUDE_DIR}>
$<INSTALL_INTERFACE:include>)
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)
if(DOWNLOAD_GTEST OR GTEST_SRC_DIR)
set(BUILD_TESTS ON)
endif()
if(XTENSOR_ENABLE_ASSERT OR XTENSOR_CHECK_DIMENSION)
add_definitions(-DXTENSOR_ENABLE_ASSERT)
endif()
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()
if(DISABLE_VS2017)
add_definitions(-DDISABLE_VS2017)
endif()
if(BUILD_TESTS)
add_subdirectory(test)
endif()
if(BUILD_BENCHMARK)
add_subdirectory(benchmark)
endif()
# Installation
# ============
include(GNUInstallDirs)
include(CMakePackageConfigHelpers)
install(TARGETS xtensor
EXPORT ${PROJECT_NAME}-targets)
# Makes the project importable from the build directory
export(EXPORT ${PROJECT_NAME}-targets
FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake")
install(FILES ${XTENSOR_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/xtensor)
set(XTENSOR_CMAKECONFIG_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE
STRING "install path for xtensorConfig.cmake")
configure_package_config_file(${PROJECT_NAME}Config.cmake.in
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION ${XTENSOR_CMAKECONFIG_INSTALL_DIR})
# xtensor is header-only and does not depend on the architecture.
# Remove CMAKE_SIZEOF_VOID_P from xtensorConfigVersion.cmake so that an xtensorConfig.cmake
# generated for a 64 bit target can be used for 32 bit targets and vice versa.
set(_XTENSOR_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
unset(CMAKE_SIZEOF_VOID_P)
write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
VERSION ${${PROJECT_NAME}_VERSION}
COMPATIBILITY AnyNewerVersion)
set(CMAKE_SIZEOF_VOID_P ${_XTENSOR_CMAKE_SIZEOF_VOID_P})
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION ${XTENSOR_CMAKECONFIG_INSTALL_DIR})
install(EXPORT ${PROJECT_NAME}-targets
FILE ${PROJECT_NAME}Targets.cmake
DESTINATION ${XTENSOR_CMAKECONFIG_INSTALL_DIR})
configure_file(${PROJECT_NAME}.pc.in
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
@ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig/")

View file

@ -0,0 +1,266 @@
/***************************************************************************
* 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_ACCUMULATOR_HPP
#define XTENSOR_ACCUMULATOR_HPP
#include <algorithm>
#include <cstddef>
#include <numeric>
#include <type_traits>
#include "xexpression.hpp"
#include "xstrides.hpp"
#include "xtensor_forward.hpp"
namespace xt
{
#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate
/**************
* accumulate *
**************/
template <class ACCUMULATE_FUNC, class INIT_FUNC = xtl::identity>
struct xaccumulator_functor
: public std::tuple<ACCUMULATE_FUNC, INIT_FUNC>
{
using self_type = xaccumulator_functor<ACCUMULATE_FUNC, INIT_FUNC>;
using base_type = std::tuple<ACCUMULATE_FUNC, INIT_FUNC>;
using accumulate_functor_type = ACCUMULATE_FUNC;
using init_functor_type = INIT_FUNC;
xaccumulator_functor()
: base_type()
{
}
template <class RF>
xaccumulator_functor(RF&& accumulate_func)
: base_type(std::forward<RF>(accumulate_func), INIT_FUNC())
{
}
template <class RF, class IF>
xaccumulator_functor(RF&& accumulate_func, IF&& init_func)
: base_type(std::forward<RF>(accumulate_func), std::forward<IF>(init_func))
{
}
};
template <class RF>
auto make_xaccumulator_functor(RF&& accumulate_func)
{
using accumulator_type = xaccumulator_functor<std::remove_reference_t<RF>>;
return accumulator_type(std::forward<RF>(accumulate_func));
}
template <class RF, class IF>
auto make_xaccumulator_functor(RF&& accumulate_func, IF&& init_func)
{
using accumulator_type = xaccumulator_functor<std::remove_reference_t<RF>, std::remove_reference_t<IF>>;
return accumulator_type(std::forward<RF>(accumulate_func), std::forward<IF>(init_func));
}
namespace detail
{
template <class F, class E, class EVS>
xarray<typename std::decay_t<E>::value_type> accumulator_impl(F&&, E&&, std::size_t, EVS)
{
static_assert(!std::is_same<evaluation_strategy::lazy, EVS>::value, "Lazy accumulators not yet implemented.");
}
template <class F, class E, class EVS>
xarray<typename std::decay_t<E>::value_type> accumulator_impl(F&&, E&&, EVS)
{
static_assert(!std::is_same<evaluation_strategy::lazy, EVS>::value, "Lazy accumulators not yet implemented.");
}
template <class T, class R>
struct xaccumulator_return_type
{
using type = xarray<R>;
};
template <class T, std::size_t N, class R>
struct xaccumulator_return_type<xtensor<T, N>, R>
{
using type = xtensor<R, N>;
};
template <class T, class R>
using xaccumulator_return_type_t = typename xaccumulator_return_type<T, R>::type;
template <class F, class E>
inline auto accumulator_init_with_f(F&& f, E& e, std::size_t axis)
{
// this function is the equivalent (but hopefully faster) to (if axis == 1)
// 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;
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<std::size_t>());
inner_loop_size = std::accumulate(first + ax + 1, last,
std::size_t(1), std::multiplies<std::size_t>());
};
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);
};
set_loop_sizes(e.shape().begin(), e.shape().end(), static_cast<std::ptrdiff_t>(axis));
set_loop_strides(e.strides().begin(), e.strides().end(), static_cast<std::ptrdiff_t>(axis));
if (e.layout() == layout_type::column_major)
{
// swap for better memory locality (smaller stride in the inner loop)
std::swap(outer_loop_size, inner_loop_size);
std::swap(outer_stride, inner_stride);
}
for (std::size_t i = 0; i < outer_loop_size; ++i)
{
pos = i * outer_stride;
for (std::size_t j = 0; j < inner_loop_size; ++j)
{
e.storage()[pos] = f(e.storage()[pos]);
pos += inner_stride;
}
}
}
template <class F, class E>
inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate)
{
using accumulate_functor = std::decay_t<decltype(std::get<0>(f))>;
using function_return_type = typename accumulate_functor::result_type;
using result_type = xaccumulator_return_type_t<std::decay_t<E>, function_return_type>;
if (axis >= e.dimension())
{
throw std::runtime_error("Axis larger than expression dimension in accumulator.");
}
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<std::size_t>());
inner_loop_size = std::accumulate(first + ax,
last,
std::size_t(1), std::multiplies<std::size_t>());
};
if (result_type::static_layout == layout_type::row_major)
{
set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast<std::ptrdiff_t>(axis));
}
else
{
set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast<std::ptrdiff_t>(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<decltype(std::get<1>(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)
{
result.storage()[pos + inner_stride] = std::get<0>(f)(result.storage()[pos],
result.storage()[pos + inner_stride]);
pos += outer_stride;
}
pos += inner_stride;
}
return result;
}
template <class F, class E>
inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate)
{
using accumulate_functor = std::decay_t<decltype(std::get<0>(f))>;
using T = typename accumulate_functor::result_type;
using result_type = xtensor<T, 1>;
std::size_t sz = e.size();
auto result = result_type::from_shape({sz});
auto it = e.template begin<XTENSOR_DEFAULT_LAYOUT>();
result.storage()[0] = std::get<1>(f)(*it);
++it;
for (std::size_t idx = 0; it != e.template end<XTENSOR_DEFAULT_LAYOUT>(); ++it)
{
result.storage()[idx + 1] = std::get<0>(f)(result.storage()[idx], *it);
++idx;
}
return result;
}
}
/**
* Accumulate and flatten array
* **NOTE** This function is not lazy!
*
* @param f functor to use for accumulation
* @param e xexpression to be accumulated
* @param evaluation_strategy evaluation strategy of the accumulation
*
* @return returns xarray<T> filled with accumulated values
*/
template <class F, class E, class EVS = DEFAULT_STRATEGY_ACCUMULATORS,
typename std::enable_if_t<!std::is_integral<EVS>::value, int> = 0>
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
// overload below!
return detail::accumulator_impl(std::forward<F>(f), std::forward<E>(e), evaluation_strategy);
}
/**
* Accumulate over axis
* **NOTE** This function is not lazy!
*
* @param f Functor to use for accumulation
* @param e xexpression to accumulate
* @param axis Axis to perform accumulation over
* @param evaluation_strategy evaluation strategy of the accumulation
*
* @return returns xarray<T> filled with accumulated values
*/
template <class F, class E, class EVS = DEFAULT_STRATEGY_ACCUMULATORS>
inline auto accumulate(F&& f, E&& e, std::size_t axis, EVS evaluation_strategy = EVS())
{
return detail::accumulator_impl(std::forward<F>(f), std::forward<E>(e), axis, evaluation_strategy);
}
}
#endif

View file

@ -0,0 +1,322 @@
/***************************************************************************
* 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_ADAPT_HPP
#define XTENSOR_ADAPT_HPP
#include <array>
#include <cstddef>
#include <memory>
#include <type_traits>
#include <xtl/xsequence.hpp>
#include "xarray.hpp"
#include "xtensor.hpp"
namespace xt
{
namespace detail
{
template <class>
struct array_size_impl;
template <class T, std::size_t N>
struct array_size_impl<std::array<T, N>>
{
static constexpr std::size_t value = N;
};
template <class C>
using array_size = array_size_impl<std::decay_t<C>>;
}
/**************************
* xarray_adaptor builder *
**************************/
/**
* Constructs an xarray_adaptor of the given stl-like container,
* with the specified shape and layout.
* @param container the container to adapt
* @param shape the shape of the xarray_adaptor
* @param l the layout_type of the xarray_adaptor
*/
template <layout_type L = XTENSOR_DEFAULT_LAYOUT, class C, class SC,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int> = 0>
xarray_adaptor<xtl::closure_type_t<C>, L, std::decay_t<SC>>
adapt(C&& container, const SC& shape, layout_type l = L);
/**
* Constructs an xarray_adaptor of the given stl-like container,
* with the specified shape and strides.
* @param container the container to adapt
* @param shape the shape of the xarray_adaptor
* @param strides the strides of the xarray_adaptor
*/
template <class C, class SC, class SS,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int> = 0,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int> = 0>
xarray_adaptor<xtl::closure_type_t<C>, layout_type::dynamic, std::decay_t<SC>>
adapt(C&& container, SC&& shape, SS&& strides);
/**
* Constructs an xarray_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 xarray_adaptor
* @param l the layout_type of the xarray_adaptor
* @param alloc the allocator used for allocating / deallocating the dynamic array
*/
template <layout_type L = XTENSOR_DEFAULT_LAYOUT, class P, class O, class SC, class A = std::allocator<std::remove_const_t<std::remove_pointer_t<std::remove_reference_t<P>>>>,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int> = 0>
xarray_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, 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());
/**
* Constructs an xarray_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 xarray_adaptor
* @param strides the strides of the xarray_adaptor
* @param alloc the allocator used for allocating / deallocating the dynamic array
*/
template <class P, class O, class SC, class SS, class A = std::allocator<std::remove_const_t<std::remove_pointer_t<std::remove_reference_t<P>>>>,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int> = 0,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int> = 0>
xarray_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, O, A>, layout_type::dynamic, std::decay_t<SC>>
adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A());
/***************************
* xtensor_adaptor builder *
***************************/
/**
* Constructs a 1-D xtensor_adaptor of the given stl-like container,
* with the specified layout_type.
* @param container the container to adapt
* @param l the layout_type of the xtensor_adaptor
*/
template <layout_type L = XTENSOR_DEFAULT_LAYOUT, class C>
xtensor_adaptor<C, 1, L>
adapt(C&& container, layout_type l = L);
/**
* Constructs an xtensor_adaptor of the given stl-like container,
* with the specified shape and layout_type.
* @param container the container to adapt
* @param shape the shape of the xtensor_adaptor
* @param l the layout_type of the xtensor_adaptor
*/
template <layout_type L = XTENSOR_DEFAULT_LAYOUT, class C, class SC,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int> = 0>
xtensor_adaptor<C, detail::array_size<SC>::value, L>
adapt(C&& container, const SC& shape, layout_type l = L);
/**
* Constructs an xtensor_adaptor of the given stl-like container,
* with the specified shape and strides.
* @param container the container to adapt
* @param shape the shape of the xtensor_adaptor
* @param strides the strides of the xtensor_adaptor
*/
template <class C, class SC, class SS,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int> = 0,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int> = 0>
xtensor_adaptor<C, detail::array_size<SC>::value, layout_type::dynamic>
adapt(C&& container, SC&& shape, SS&& strides);
/**
* Constructs a 1-D xtensor_adaptor of the given dynamically allocated C array,
* with the specified 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 l the layout_type of the xtensor_adaptor
* @param alloc the allocator used for allocating / deallocating the dynamic array
*/
template <layout_type L = XTENSOR_DEFAULT_LAYOUT, class P, class O, class A = std::allocator<std::remove_const_t<std::remove_pointer_t<std::remove_reference_t<P>>>>>
xtensor_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, 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 <layout_type L = XTENSOR_DEFAULT_LAYOUT, class P, class O, class SC, class A = std::allocator<std::remove_const_t<std::remove_pointer_t<std::remove_reference_t<P>>>>,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int> = 0>
xtensor_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, O, A>, detail::array_size<SC>::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 <class P, class O, class SC, class SS, class A = std::allocator<std::remove_const_t<std::remove_pointer_t<std::remove_reference_t<P>>>>,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int> = 0,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int> = 0>
xtensor_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, O, A>, detail::array_size<SC>::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 <layout_type L, class C, class SC,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int>>
inline xarray_adaptor<xtl::closure_type_t<C>, L, std::decay_t<SC>>
adapt(C&& container, const SC& shape, layout_type l)
{
using return_type = xarray_adaptor<xtl::closure_type_t<C>, L, std::decay_t<SC>>;
return return_type(std::forward<C>(container), shape, l);
}
// shape and strides - container version
template <class C, class SC, class SS,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int>,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int>>
inline xarray_adaptor<xtl::closure_type_t<C>, layout_type::dynamic, std::decay_t<SC>>
adapt(C&& container, SC&& shape, SS&& strides)
{
using return_type = xarray_adaptor<xtl::closure_type_t<C>, layout_type::dynamic, std::decay_t<SC>>;
return return_type(std::forward<C>(container),
xtl::forward_sequence<typename return_type::inner_shape_type>(shape),
xtl::forward_sequence<typename return_type::inner_strides_type>(strides));
}
// shape only - buffer version
template <layout_type L, class P, class O, class SC, class A,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int>>
inline xarray_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, 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<xtl::closure_type_t<P>, O, A>;
using return_type = xarray_adaptor<buffer_type, L, SC>;
buffer_type buf(std::forward<P>(pointer), size, alloc);
return return_type(std::move(buf), shape, l);
}
// shape and strides - buffer version
template <class P, class O, class SC, class SS, class A,
typename std::enable_if_t<!detail::is_array<std::decay_t<SC>>::value, int>,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int>>
inline xarray_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, O, A>, layout_type::dynamic, std::decay_t<SC>>
adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc)
{
using buffer_type = xbuffer_adaptor<xtl::closure_type_t<P>, O, A>;
using return_type = xarray_adaptor<buffer_type, layout_type::dynamic, std::decay_t<SC>>;
buffer_type buf(std::forward<P>(pointer), size, alloc);
return return_type(std::move(buf),
xtl::forward_sequence<typename return_type::inner_shape_type>(shape),
xtl::forward_sequence<typename return_type::inner_strides_type>(strides));
}
/******************************************
* xtensor_adaptor builder implementation *
******************************************/
// 1-D case - container version
template <layout_type L, class C>
inline xtensor_adaptor<C, 1, L>
adapt(C&& container, layout_type l)
{
const std::array<typename std::decay_t<C>::size_type, 1> shape{container.size()};
using return_type = xtensor_adaptor<xtl::closure_type_t<C>, 1, L>;
return return_type(std::forward<C>(container), shape, l);
}
// shape only - container version
template <layout_type L, class C, class SC,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int>>
inline xtensor_adaptor<C, detail::array_size<SC>::value, L>
adapt(C&& container, const SC& shape, layout_type l)
{
constexpr std::size_t N = detail::array_size<SC>::value;
using return_type = xtensor_adaptor<xtl::closure_type_t<C>, N, L>;
return return_type(std::forward<C>(container), shape, l);
}
// shape and strides - container version
template <class C, class SC, class SS,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int>,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int>>
inline xtensor_adaptor<C, detail::array_size<SC>::value, layout_type::dynamic>
adapt(C&& container, SC&& shape, SS&& strides)
{
constexpr std::size_t N = detail::array_size<SC>::value;
using return_type = xtensor_adaptor<xtl::closure_type_t<C>, N, layout_type::dynamic>;
return return_type(std::forward<C>(container),
xtl::forward_sequence<typename return_type::inner_shape_type>(shape),
xtl::forward_sequence<typename return_type::inner_strides_type>(strides));
}
// 1-D case - buffer version
template <layout_type L, class P, class O, class A>
inline xtensor_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, O, A>, 1, L>
adapt(P&& pointer, typename A::size_type size, O, layout_type l, const A& alloc)
{
using buffer_type = xbuffer_adaptor<xtl::closure_type_t<P>, O, A>;
using return_type = xtensor_adaptor<buffer_type, 1, L>;
buffer_type buf(std::forward<P>(pointer), size, alloc);
const std::array<typename A::size_type, 1> shape{size};
return return_type(std::move(buf), shape, l);
}
// shape only - buffer version
template <layout_type L, class P, class O, class SC, class A,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int>>
inline xtensor_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, O, A>, detail::array_size<SC>::value, L>
adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc)
{
using buffer_type = xbuffer_adaptor<xtl::closure_type_t<P>, O, A>;
constexpr std::size_t N = detail::array_size<SC>::value;
using return_type = xtensor_adaptor<buffer_type, N, L>;
buffer_type buf(std::forward<P>(pointer), size, alloc);
return return_type(std::move(buf), shape, l);
}
// shape and strides - buffer version
template <class P, class O, class SC, class SS, class A,
typename std::enable_if_t<detail::is_array<std::decay_t<SC>>::value, int>,
typename std::enable_if_t<!std::is_same<layout_type, std::decay_t<SS>>::value, int>>
inline xtensor_adaptor<xbuffer_adaptor<xtl::closure_type_t<P>, O, A>, detail::array_size<SC>::value, layout_type::dynamic>
adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc)
{
using buffer_type = xbuffer_adaptor<xtl::closure_type_t<P>, O, A>;
constexpr std::size_t N = detail::array_size<SC>::value;
using return_type = xtensor_adaptor<buffer_type, N, layout_type::dynamic>;
buffer_type buf(std::forward<P>(pointer), size, alloc);
return return_type(std::move(buf),
xtl::forward_sequence<typename return_type::inner_shape_type>(shape),
xtl::forward_sequence<typename return_type::inner_strides_type>(strides));
}
}
#endif

View file

@ -0,0 +1,550 @@
/***************************************************************************
* 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_ARRAY_HPP
#define XTENSOR_ARRAY_HPP
#include <algorithm>
#include <initializer_list>
#include <utility>
#include <xtl/xsequence.hpp>
#include "xbuffer_adaptor.hpp"
#include "xcontainer.hpp"
#include "xsemantic.hpp"
namespace xt
{
/********************************
* xarray_container declaration *
********************************/
template <class EC, layout_type L, class SC, class Tag>
struct xcontainer_inner_types<xarray_container<EC, L, SC, Tag>>
{
using storage_type = EC;
using shape_type = SC;
using strides_type = shape_type;
using backstrides_type = shape_type;
using inner_shape_type = shape_type;
using inner_strides_type = strides_type;
using inner_backstrides_type = backstrides_type;
using temporary_type = xarray_container<EC, L, SC, Tag>;
static constexpr layout_type layout = L;
};
template <class EC, layout_type L, class SC, class Tag>
struct xiterable_inner_types<xarray_container<EC, L, SC, Tag>>
: xcontainer_iterable_types<xarray_container<EC, L, SC, Tag>>
{
};
/**
* @class xarray_container
* @brief Dense multidimensional container with tensor semantic.
*
* The xarray_container class implements a dense multidimensional container
* with tensor semantic.
*
* @tparam EC The type of the container holding the elements.
* @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
*/
template <class EC, layout_type L, class SC, class Tag>
class xarray_container : public xstrided_container<xarray_container<EC, L, SC, Tag>>,
public xcontainer_semantic<xarray_container<EC, L, SC, Tag>>
{
public:
using self_type = xarray_container<EC, L, SC, Tag>;
using base_type = xstrided_container<self_type>;
using semantic_base = xcontainer_semantic<self_type>;
using storage_type = typename base_type::storage_type;
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 shape_type = typename base_type::shape_type;
using inner_shape_type = typename base_type::inner_shape_type;
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 temporary_type = typename semantic_base::temporary_type;
using expression_tag = Tag;
xarray_container();
explicit xarray_container(const shape_type& shape, layout_type l = L);
explicit xarray_container(const shape_type& shape, const_reference value, layout_type l = L);
explicit xarray_container(const shape_type& shape, const strides_type& strides);
explicit xarray_container(const shape_type& shape, const strides_type& strides, const_reference value);
explicit xarray_container(storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides);
xarray_container(const value_type& t);
xarray_container(nested_initializer_list_t<value_type, 1> t);
xarray_container(nested_initializer_list_t<value_type, 2> t);
xarray_container(nested_initializer_list_t<value_type, 3> t);
xarray_container(nested_initializer_list_t<value_type, 4> t);
xarray_container(nested_initializer_list_t<value_type, 5> t);
template <class S = shape_type>
static xarray_container from_shape(S&& s);
~xarray_container() = default;
xarray_container(const xarray_container&) = default;
xarray_container& operator=(const xarray_container&) = default;
xarray_container(xarray_container&&) = default;
xarray_container& operator=(xarray_container&&) = default;
template <class E>
xarray_container(const xexpression<E>& e);
template <class E>
xarray_container& operator=(const xexpression<E>& e);
private:
storage_type m_storage;
storage_type& storage_impl() noexcept;
const storage_type& storage_impl() const noexcept;
friend class xcontainer<xarray_container<EC, L, SC, Tag>>;
};
/******************************
* xarray_adaptor declaration *
******************************/
template <class EC, layout_type L, class SC, class Tag>
struct xcontainer_inner_types<xarray_adaptor<EC, L, SC, Tag>>
{
using storage_type = std::remove_reference_t<EC>;
using shape_type = SC;
using strides_type = shape_type;
using backstrides_type = shape_type;
using inner_shape_type = shape_type;
using inner_strides_type = strides_type;
using inner_backstrides_type = backstrides_type;
using temporary_type = xarray_container<temporary_container_t<storage_type>, L, SC, Tag>;
static constexpr layout_type layout = L;
};
template <class EC, layout_type L, class SC, class Tag>
struct xiterable_inner_types<xarray_adaptor<EC, L, SC, Tag>>
: xcontainer_iterable_types<xarray_adaptor<EC, L, SC, Tag>>
{
};
/**
* @class xarray_adaptor
* @brief Dense multidimensional container adaptor with
* tensor semantic.
*
* The xarray_adaptor class implements a dense multidimensional
* container adaptor with tensor semantic. It is used to provide
* a multidimensional container semantic and a tensor semantic to
* stl-like containers.
*
* @tparam EC The closure for the container type to adapt.
* @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.
*/
template <class EC, layout_type L, class SC, class Tag>
class xarray_adaptor : public xstrided_container<xarray_adaptor<EC, L, SC, Tag>>,
public xcontainer_semantic<xarray_adaptor<EC, L, SC, Tag>>
{
public:
using container_closure_type = EC;
using self_type = xarray_adaptor<EC, L, SC, Tag>;
using base_type = xstrided_container<self_type>;
using semantic_base = xcontainer_semantic<self_type>;
using storage_type = typename base_type::storage_type;
using allocator_type = typename base_type::allocator_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 temporary_type = typename semantic_base::temporary_type;
using expression_tag = Tag;
xarray_adaptor(storage_type&& storage);
xarray_adaptor(const storage_type& storage);
template <class D>
xarray_adaptor(D&& storage, const shape_type& shape, layout_type l = L);
template <class D>
xarray_adaptor(D&& storage, const shape_type& shape, const strides_type& strides);
~xarray_adaptor() = default;
xarray_adaptor(const xarray_adaptor&) = default;
xarray_adaptor& operator=(const xarray_adaptor&);
xarray_adaptor(xarray_adaptor&&) = default;
xarray_adaptor& operator=(xarray_adaptor&&);
xarray_adaptor& operator=(temporary_type&&);
template <class E>
xarray_adaptor& operator=(const xexpression<E>& e);
private:
container_closure_type m_storage;
storage_type& storage_impl() noexcept;
const storage_type& storage_impl() const noexcept;
friend class xcontainer<xarray_adaptor<EC, L, SC, Tag>>;
};
/***********************************
* xarray_container implementation *
***********************************/
/**
* @name Constructors
*/
//@{
/**
* Allocates an uninitialized xarray_container that holds 0 element.
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container()
: base_type(), m_storage(1, value_type())
{
}
/**
* Allocates an uninitialized xarray_container with the specified shape and
* layout_type.
* @param shape the shape of the xarray_container
* @param l the layout_type of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(const shape_type& shape, layout_type l)
: base_type()
{
base_type::resize(shape, l);
}
/**
* Allocates an xarray_container with the specified shape and layout_type. Elements
* are initialized to the specified value.
* @param shape the shape of the xarray_container
* @param value the value of the elements
* @param l the layout_type of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(const shape_type& shape, const_reference value, layout_type l)
: base_type()
{
base_type::resize(shape, l);
std::fill(m_storage.begin(), m_storage.end(), value);
}
/**
* Allocates an uninitialized xarray_container with the specified shape and strides.
* @param shape the shape of the xarray_container
* @param strides the strides of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(const shape_type& shape, const strides_type& strides)
: base_type()
{
base_type::resize(shape, strides);
}
/**
* Allocates an uninitialized xarray_container with the specified shape and strides.
* Elements are initialized to the specified value.
* @param shape the shape of the xarray_container
* @param strides the strides of the xarray_container
* @param value the value of the elements
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(const shape_type& shape, const strides_type& strides, const_reference value)
: base_type()
{
base_type::resize(shape, strides);
std::fill(m_storage.begin(), m_storage.end(), value);
}
/**
* Allocates an xarray_container that holds a single element initialized to the
* specified value.
* @param t the value of the element
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(const value_type& t)
: base_type()
{
base_type::resize(xt::shape<shape_type>(t), true);
nested_copy(m_storage.begin(), t);
}
/**
* Allocates an xarray_container by moving specified data, shape and strides
*
* @param storage the data for the xarray_container
* @param shape the shape of the xarray_container
* @param strides the strides of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(storage_type&& storage, inner_shape_type&& shape, inner_strides_type&& strides)
: base_type(std::move(shape), std::move(strides)), m_storage(std::move(storage))
{
}
//@}
/**
* @name Constructors from initializer list
*/
//@{
/**
* Allocates a one-dimensional xarray_container.
* @param t the elements of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(nested_initializer_list_t<value_type, 1> t)
: base_type()
{
base_type::resize(xt::shape<shape_type>(t));
L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t);
}
/**
* Allocates a two-dimensional xarray_container.
* @param t the elements of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(nested_initializer_list_t<value_type, 2> t)
: base_type()
{
base_type::resize(xt::shape<shape_type>(t));
L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t);
}
/**
* Allocates a three-dimensional xarray_container.
* @param t the elements of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(nested_initializer_list_t<value_type, 3> t)
: base_type()
{
base_type::resize(xt::shape<shape_type>(t));
L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t);
}
/**
* Allocates a four-dimensional xarray_container.
* @param t the elements of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(nested_initializer_list_t<value_type, 4> t)
: base_type()
{
base_type::resize(xt::shape<shape_type>(t));
L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t);
}
/**
* Allocates a five-dimensional xarray_container.
* @param t the elements of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_container<EC, L, SC, Tag>::xarray_container(nested_initializer_list_t<value_type, 5> t)
: base_type()
{
base_type::resize(xt::shape<shape_type>(t));
L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t);
}
//@}
/**
* Allocates and returns an xarray_container with the specified shape.
* @param s the shape of the xarray_container
*/
template <class EC, layout_type L, class SC, class Tag>
template <class S>
inline xarray_container<EC, L, SC, Tag> xarray_container<EC, L, SC, Tag>::from_shape(S&& s)
{
shape_type shape = xtl::forward_sequence<shape_type>(s);
return self_type(shape);
}
/**
* @name Extended copy semantic
*/
//@{
/**
* The extended copy constructor.
*/
template <class EC, layout_type L, class SC, class Tag>
template <class E>
inline xarray_container<EC, L, SC, Tag>::xarray_container(const xexpression<E>& e)
: base_type()
{
// Avoids unintialized data because of (m_shape == shape) condition
// in resize (called by assign), which is always true when dimension == 0.
if (e.derived_cast().dimension() == 0)
{
detail::resize_data_container(m_storage, std::size_t(1));
}
semantic_base::assign(e);
}
/**
* The extended assignment operator.
*/
template <class EC, layout_type L, class SC, class Tag>
template <class E>
inline auto xarray_container<EC, L, SC, Tag>::operator=(const xexpression<E>& e) -> self_type&
{
return semantic_base::operator=(e);
}
//@}
template <class EC, layout_type L, class SC, class Tag>
inline auto xarray_container<EC, L, SC, Tag>::storage_impl() noexcept -> storage_type&
{
return m_storage;
}
template <class EC, layout_type L, class SC, class Tag>
inline auto xarray_container<EC, L, SC, Tag>::storage_impl() const noexcept -> const storage_type&
{
return m_storage;
}
/******************
* xarray_adaptor *
******************/
/**
* @name Constructors
*/
//@{
/**
* Constructs an xarray_adaptor of the given stl-like container.
* @param storage the container to adapt
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_adaptor<EC, L, SC, Tag>::xarray_adaptor(storage_type&& storage)
: base_type(), m_storage(std::move(storage))
{
}
/**
* Constructs an xarray_adaptor of the given stl-like container.
* @param storage the container to adapt
*/
template <class EC, layout_type L, class SC, class Tag>
inline xarray_adaptor<EC, L, SC, Tag>::xarray_adaptor(const storage_type& storage)
: base_type(), m_storage(storage)
{
}
/**
* Constructs an xarray_adaptor of the given stl-like container,
* with the specified shape and layout_type.
* @param storage the container to adapt
* @param shape the shape of the xarray_adaptor
* @param l the layout_type of the xarray_adaptor
*/
template <class EC, layout_type L, class SC, class Tag>
template <class D>
inline xarray_adaptor<EC, L, SC, Tag>::xarray_adaptor(D&& storage, const shape_type& shape, layout_type l)
: base_type(), m_storage(std::forward<D>(storage))
{
base_type::resize(shape, l);
}
/**
* Constructs an xarray_adaptor of the given stl-like container,
* with the specified shape and strides.
* @param storage the container to adapt
* @param shape the shape of the xarray_adaptor
* @param strides the strides of the xarray_adaptor
*/
template <class EC, layout_type L, class SC, class Tag>
template <class D>
inline xarray_adaptor<EC, L, SC, Tag>::xarray_adaptor(D&& storage, const shape_type& shape, const strides_type& strides)
: base_type(), m_storage(std::forward<D>(storage))
{
base_type::resize(shape, strides);
}
//@}
template <class EC, layout_type L, class SC, class Tag>
inline auto xarray_adaptor<EC, L, SC, Tag>::operator=(const xarray_adaptor& rhs) -> self_type&
{
base_type::operator=(rhs);
m_storage = rhs.m_storage;
return *this;
}
template <class EC, layout_type L, class SC, class Tag>
inline auto xarray_adaptor<EC, L, SC, Tag>::operator=(xarray_adaptor&& rhs) -> self_type&
{
base_type::operator=(std::move(rhs));
m_storage = rhs.m_storage;
return *this;
}
template <class EC, layout_type L, class SC, class Tag>
inline auto xarray_adaptor<EC, L, SC, Tag>::operator=(temporary_type&& rhs) -> self_type&
{
base_type::shape_impl() = std::move(const_cast<shape_type&>(rhs.shape()));
base_type::strides_impl() = std::move(const_cast<strides_type&>(rhs.strides()));
base_type::backstrides_impl() = std::move(const_cast<backstrides_type&>(rhs.backstrides()));
m_storage = std::move(rhs.storage());
return *this;
}
/**
* @name Extended copy semantic
*/
//@{
/**
* The extended assignment operator.
*/
template <class EC, layout_type L, class SC, class Tag>
template <class E>
inline auto xarray_adaptor<EC, L, SC, Tag>::operator=(const xexpression<E>& e) -> self_type&
{
return semantic_base::operator=(e);
}
//@}
template <class EC, layout_type L, class SC, class Tag>
inline auto xarray_adaptor<EC, L, SC, Tag>::storage_impl() noexcept -> storage_type&
{
return m_storage;
}
template <class EC, layout_type L, class SC, class Tag>
inline auto xarray_adaptor<EC, L, SC, Tag>::storage_impl() const noexcept -> const storage_type&
{
return m_storage;
}
}
#endif

View file

@ -0,0 +1,783 @@
/***************************************************************************
* 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_ASSIGN_HPP
#define XTENSOR_ASSIGN_HPP
#include <algorithm>
#include <type_traits>
#include <utility>
#include <xtl/xsequence.hpp>
#include "xconcepts.hpp"
#include "xexpression.hpp"
#include "xiterator.hpp"
#include "xstrides.hpp"
#include "xtensor_forward.hpp"
#include "xutils.hpp"
namespace xt
{
/********************
* Assign functions *
********************/
template <class E1, class E2>
void assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial);
template <class E1, class E2>
void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2);
template <class E1, class E2>
void computed_assign(xexpression<E1>& e1, const xexpression<E2>& e2);
template <class E1, class E2, class F>
void scalar_computed_assign(xexpression<E1>& e1, const E2& e2, F&& f);
template <class E1, class E2>
void assert_compatible_shape(const xexpression<E1>& e1, const xexpression<E2>& e2);
template <class E1, class E2>
void strided_assign(E1& e1, const E2& e2, std::false_type /*disable*/);
template <class E1, class E2>
void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/);
/************************
* xexpression_assigner *
************************/
template <class Tag>
class xexpression_assigner_base;
template <>
class xexpression_assigner_base<xtensor_expression_tag>
{
public:
template <class E1, class E2>
static void assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial);
};
template <class Tag>
class xexpression_assigner : public xexpression_assigner_base<Tag>
{
public:
using base_type = xexpression_assigner_base<Tag>;
template <class E1, class E2>
static void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2);
template <class E1, class E2>
static void computed_assign(xexpression<E1>& e1, const xexpression<E2>& e2);
template <class E1, class E2, class F>
static void scalar_computed_assign(xexpression<E1>& e1, const E2& e2, F&& f);
template <class E1, class E2>
static void assert_compatible_shape(const xexpression<E1>& e1, const xexpression<E2>& e2);
private:
template <class E1, class E2>
static bool resize(xexpression<E1>& e1, const xexpression<E2>& e2);
};
/*****************
* data_assigner *
*****************/
template <class E1, class E2, layout_type L>
class data_assigner
{
public:
using lhs_iterator = typename E1::stepper;
using rhs_iterator = typename E2::const_stepper;
using shape_type = typename E1::shape_type;
using index_type = xindex_type_t<shape_type>;
using size_type = typename lhs_iterator::size_type;
using difference_type = typename lhs_iterator::difference_type;
data_assigner(E1& e1, const E2& e2);
void run();
void step(size_type i);
void step(size_type i, size_type n);
void reset(size_type i);
void to_end(layout_type);
private:
E1& m_e1;
lhs_iterator m_lhs;
rhs_iterator m_rhs;
index_type m_index;
};
/********************
* trivial_assigner *
********************/
template <bool simd_assign>
struct trivial_assigner
{
template <class E1, class E2>
static void run(E1& e1, const E2& e2);
};
/***********************************
* Assign functions implementation *
***********************************/
template <class E1, class E2>
inline void assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial)
{
using tag = xexpression_tag_t<E1, E2>;
xexpression_assigner<tag>::assign_data(e1, e2, trivial);
}
template <class E1, class E2>
inline void assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2)
{
xtl::mpl::static_if<has_assign_to<E1, E2>::value>([&](auto self)
{
self(e2).derived_cast().assign_to(e1);
}, /*else*/ [&](auto /*self*/)
{
using tag = xexpression_tag_t<E1, E2>;
xexpression_assigner<tag>::assign_xexpression(e1, e2);
});
}
template <class E1, class E2>
inline void computed_assign(xexpression<E1>& e1, const xexpression<E2>& e2)
{
using tag = xexpression_tag_t<E1, E2>;
xexpression_assigner<tag>::computed_assign(e1, e2);
}
template <class E1, class E2, class F>
inline void scalar_computed_assign(xexpression<E1>& e1, const E2& e2, F&& f)
{
using tag = xexpression_tag_t<E1, E2>;
xexpression_assigner<tag>::scalar_computed_assign(e1, e2, std::forward<F>(f));
}
template <class E1, class E2>
inline void assert_compatible_shape(const xexpression<E1>& e1, const xexpression<E2>& e2)
{
using tag = xexpression_tag_t<E1, E2>;
xexpression_assigner<tag>::assert_compatible_shape(e1, e2);
}
/***************************************
* xexpression_assigner implementation *
***************************************/
namespace detail
{
template <class E1, class E2>
inline bool is_trivial_broadcast(const E1& e1, const E2& e2)
{
return (E1::contiguous_layout && E2::contiguous_layout && (E1::static_layout == E2::static_layout))
|| e2.is_trivial_broadcast(e1.strides());
}
template <class D, class E2, class... SL>
inline bool is_trivial_broadcast(const xview<D, SL...>&, const E2&)
{
return false;
}
template <class E, class = void_t<>>
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 <class E>
struct xfunction_forbid_simd;
template <class E>
struct forbid_simd_assign<E,
void_t<decltype(std::declval<E>().template load_simd<aligned_mode>(typename E::size_type(0)))>>
{
static constexpr bool value = false || xfunction_forbid_simd<E>::value;
};
template <class E>
struct xfunction_forbid_simd
{
static constexpr bool value = false;
};
template <class F, class R, class... CT>
struct xfunction_forbid_simd<xfunction<F, R, CT...>>
{
static constexpr bool value = xtl::disjunction<
std::integral_constant<bool, forbid_simd_assign<typename std::decay<CT>::type>::value>...>::value;
};
template <class F, class B, class = void>
struct has_simd_apply : std::false_type {};
template <class F, class B>
struct has_simd_apply<F, B, void_t<decltype(&F::template simd_apply<B>)>>
: std::true_type
{
};
template <class E, class = void>
struct has_step_leading : std::false_type
{
};
template <class E>
struct has_step_leading<E, void_t<decltype(std::declval<E>().step_leading())>>
: std::true_type
{
};
template <class T>
struct use_strided_loop
{
static constexpr bool stepper_deref() { return std::is_reference<typename T::stepper::reference>::value; }
static constexpr bool value = has_strides<T>::value && has_step_leading<typename T::stepper>::value && stepper_deref();
};
template <class T>
struct use_strided_loop<xscalar<T>>
{
static constexpr bool value = true;
};
template <class F, class R, class... CT>
struct use_strided_loop<xfunction<F, R, CT...>>
{
static constexpr bool value = xtl::conjunction<use_strided_loop<std::decay_t<CT>>...>::value &&
has_simd_apply<F, xsimd::simd_type<R>>::value;
};
}
template <class E1, class E2>
struct 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).
static constexpr bool contiguous_layout() { return E1::contiguous_layout && E2::contiguous_layout; }
static constexpr bool same_type() { return std::is_same<typename E1::value_type, typename E2::value_type>::value; }
static constexpr bool simd_size() { return xsimd::simd_traits<typename E1::value_type>::size > 1; }
static constexpr bool forbid_simd() { return detail::forbid_simd_assign<E2>::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<E2>::value && detail::use_strided_loop<E1>::value; }
};
template <class E1, class E2>
inline void xexpression_assigner_base<xtensor_expression_tag>::assign_data(xexpression<E1>& e1, const xexpression<E2>& e2, bool trivial)
{
E1& de1 = e1.derived_cast();
const E2& de2 = e2.derived_cast();
bool trivial_broadcast = trivial && detail::is_trivial_broadcast(de1, de2);
if (trivial_broadcast)
{
constexpr bool simd_assign = xassign_traits<E1, E2>::simd_assign();
trivial_assigner<simd_assign>::run(de1, de2);
}
else if (xassign_traits<E1, E2>::simd_strided_loop())
{
strided_assign(de1, de2, std::integral_constant<bool, xassign_traits<E1, E2>::simd_strided_loop()>{});
}
else
{
data_assigner<E1, E2, default_assignable_layout(E1::static_layout)> assigner(de1, de2);
assigner.run();
}
}
template <class Tag>
template <class E1, class E2>
inline void xexpression_assigner<Tag>::assign_xexpression(xexpression<E1>& e1, const xexpression<E2>& e2)
{
bool trivial_broadcast = resize(e1, e2);
base_type::assign_data(e1, e2, trivial_broadcast);
}
template <class Tag>
template <class E1, class E2>
inline void xexpression_assigner<Tag>::computed_assign(xexpression<E1>& e1, const xexpression<E2>& e2)
{
using shape_type = typename E1::shape_type;
using size_type = typename E1::size_type;
E1& de1 = e1.derived_cast();
const E2& de2 = e2.derived_cast();
size_type dim = de2.dimension();
shape_type shape = xtl::make_sequence<shape_type>(dim, size_type(0));
bool trivial_broadcast = de2.broadcast_shape(shape, true);
if (dim > de1.dimension() || shape > de1.shape())
{
typename E1::temporary_type tmp(shape);
base_type::assign_data(tmp, e2, trivial_broadcast);
de1.assign_temporary(std::move(tmp));
}
else
{
base_type::assign_data(e1, e2, trivial_broadcast);
}
}
template <class Tag>
template <class E1, class E2, class F>
inline void xexpression_assigner<Tag>::scalar_computed_assign(xexpression<E1>& e1, const E2& e2, F&& f)
{
E1& d = e1.derived_cast();
using size_type = typename E1::size_type;
auto dst = d.storage().begin();
for (size_type i = d.size(); i > 0; --i)
{
*dst = f(*dst, e2);
++dst;
}
}
template <class Tag>
template <class E1, class E2>
inline void xexpression_assigner<Tag>::assert_compatible_shape(const xexpression<E1>& e1, const xexpression<E2>& e2)
{
const E1& de1 = e1.derived_cast();
const E2& de2 = e2.derived_cast();
if (!broadcastable(de2.shape(), de1.shape()))
{
throw_broadcast_error(de2.shape(), de1.shape());
}
}
template <class Tag>
template <class E1, class E2>
inline bool xexpression_assigner<Tag>::resize(xexpression<E1>& e1, const xexpression<E2>& e2)
{
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<shape_type>(size, size_type(0));
bool trivial_broadcast = de2.broadcast_shape(shape, true);
e1.derived_cast().resize(std::move(shape));
return trivial_broadcast;
}
/********************************
* data_assigner implementation *
********************************/
template <class E1, class E2, layout_type L>
inline data_assigner<E1, E2, L>::data_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<index_type>(e1.shape().size(), size_type(0)))
{
}
template <class E1, class E2, layout_type L>
inline void data_assigner<E1, E2, L>::run()
{
using size_type = typename E1::size_type;
using argument_type = std::decay_t<decltype(*m_rhs)>;
using result_type = std::decay_t<decltype(*m_lhs)>;
constexpr bool is_narrowing = is_narrowing_conversion<argument_type, result_type>::value;
size_type s = m_e1.size();
for (size_type i = 0; i < s; ++i)
{
*m_lhs = conditional_cast<is_narrowing, result_type>(*m_rhs);
stepper_tools<L>::increment_stepper(*this, m_index, m_e1.shape());
}
}
template <class E1, class E2, layout_type L>
inline void data_assigner<E1, E2, L>::step(size_type i)
{
m_lhs.step(i);
m_rhs.step(i);
}
template <class E1, class E2, layout_type L>
inline void data_assigner<E1, E2, L>::step(size_type i, size_type n)
{
m_lhs.step(i, n);
m_rhs.step(i, n);
}
template <class E1, class E2, layout_type L>
inline void data_assigner<E1, E2, L>::reset(size_type i)
{
m_lhs.reset(i);
m_rhs.reset(i);
}
template <class E1, class E2, layout_type L>
inline void data_assigner<E1, E2, L>::to_end(layout_type l)
{
m_lhs.to_end(l);
m_rhs.to_end(l);
}
/***********************************
* trivial_assigner implementation *
***********************************/
template <bool simd_assign>
template <class E1, class E2>
inline void trivial_assigner<simd_assign>::run(E1& e1, const E2& e2)
{
using lhs_align_mode = xsimd::container_alignment_t<E1>;
constexpr bool is_aligned = std::is_same<lhs_align_mode, aligned_mode>::value;
using rhs_align_mode = std::conditional_t<is_aligned, inner_aligned_mode, unaligned_mode>;
using value_type = std::common_type_t<typename E1::value_type, typename E2::value_type>;
using simd_type = xsimd::simd_type<value_type>;
using size_type = typename E1::size_type;
size_type size = e1.size();
size_type simd_size = simd_type::size;
size_type align_begin = is_aligned ? 0 : xsimd::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);
}
for (size_type i = align_begin; i < align_end; i += simd_size)
{
e1.template store_simd<lhs_align_mode, simd_type>(i, e2.template load_simd<rhs_align_mode, simd_type>(i));
}
for (size_type i = align_end; i < size; ++i)
{
e1.data_element(i) = e2.data_element(i);
}
}
namespace assigner_detail
{
template <class C, class It, class Ot>
inline void assign_loop(It src, Ot dst, std::size_t n)
{
for(; n > 0; --n)
{
*dst = static_cast<C>(*src);
++src;
++dst;
}
}
template <class E1, class E2>
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<typename E1::value_type>(src, dst, e1.size());
}
template <class E1, class E2>
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 <class E1, class E2>
inline void trivial_assigner<false>::run(E1& e1, const E2& e2)
{
using is_convertible = std::is_convertible<typename std::decay_t<E1>::value_type,
typename std::decay_t<E2>::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());
}
/***********************
* Strided assign loop *
***********************/
namespace strided_assign_detail
{
template <layout_type layout>
struct idx_tools;
template <>
struct idx_tools<layout_type::row_major>
{
template <class T>
static void next_idx(T& outer_index, T& outer_shape)
{
auto i = outer_index.size();
for (; i > 0; --i)
{
if (outer_index[i - 1] + 1 >= outer_shape[i - 1])
{
outer_index[i - 1] = 0;
}
else
{
outer_index[i - 1]++;
break;
}
}
}
};
template <>
struct idx_tools<layout_type::column_major>
{
template <class T>
static void next_idx(T& outer_index, T& outer_shape)
{
using size_type = typename T::size_type;
size_type i = 0;
auto sz = outer_index.size();
for (; i < sz; ++i)
{
if (outer_index[i] + 1 >= outer_shape[i])
{
outer_index[i] = 0;
}
else
{
outer_index[i]++;
break;
}
}
}
};
template <layout_type L, class S>
struct check_strides_functor
{
using strides_type = S;
check_strides_functor(const S& strides)
: m_cut(L == layout_type::row_major ? 0 : strides.size()),
m_strides(strides)
{
}
template <class T, layout_type LE = L>
std::enable_if_t<LE == layout_type::row_major, std::size_t>
operator()(const T& el)
{
auto var = check_strides_overlap<layout_type::row_major>::get(m_strides, el.strides());
if (var > m_cut)
{
m_cut = var;
}
return m_cut;
}
template <class T, layout_type LE = L>
std::enable_if_t<LE == layout_type::column_major, std::size_t>
operator()(const T& el)
{
auto var = check_strides_overlap<layout_type::column_major>::get(m_strides, el.strides());
if (var < m_cut)
{
m_cut = var;
}
return m_cut;
}
template <class T>
std::size_t operator()(const xt::xscalar<T>& /*el*/)
{
return m_cut;
}
template <class F, class R, class... CT>
std::size_t operator()(const xt::xfunction<F, R, CT...>& xf)
{
xt::for_each(*this, xf.arguments());
return m_cut;
}
private:
std::size_t m_cut;
const strides_type& m_strides;
};
template <class E1, class E2>
auto get_loop_sizes(const E1& e1, const E2& e2)
{
std::size_t cut = 0;
// TODO! if E1 is !contigous --> initialize cut to sensible value!
if (e1.strides().back() == 1)
{
auto csf = check_strides_functor<layout_type::row_major, decltype(e1.strides())>(e1.strides());
cut = csf(e2);
}
else if (e1.strides().front() == 1)
{
auto csf = check_strides_functor<layout_type::column_major, decltype(e1.strides())>(e1.strides());
cut = csf(e2);
}
using shape_value_type = typename E1::shape_type::value_type;
std::size_t outer_loop_size = static_cast<std::size_t>(
std::accumulate(e1.shape().begin(), e1.shape().begin() + static_cast<std::ptrdiff_t>(cut),
shape_value_type(1), std::multiplies<shape_value_type>{}));
std::size_t inner_loop_size = static_cast<std::size_t>(
std::accumulate(e1.shape().begin() + static_cast<std::ptrdiff_t>(cut), e1.shape().end(),
shape_value_type(1), std::multiplies<shape_value_type>{}));
if (e1.strides().back() != 1) // column major mode
{
std::swap(outer_loop_size, inner_loop_size);
}
return std::make_tuple(inner_loop_size, outer_loop_size, cut);
}
}
template <class E1, class E2>
void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/)
{
bool fallback = false, is_row_major = true;
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 (cut == e1.dimension())
{
fallback = true;
}
}
else if (E1::static_layout == layout_type::column_major || e1.strides().front() == 1) // col major case
{
is_row_major = false;
if (cut == 0)
{
fallback = true;
}
}
else
{
fallback = true;
}
if (fallback)
{
data_assigner<E1, E2, default_assignable_layout(E1::static_layout)> assigner(e1, e2);
assigner.run();
return;
}
// TODO can we get rid of this and use `shape_type`?
dynamic_shape<std::size_t> idx;
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<std::ptrdiff_t>(cut);
}
else
{
xt::resize_container(idx, e1.shape().size() - cut);
max_shape_begin = e1.shape().begin() + static_cast<std::ptrdiff_t>(cut);
max_shape_end = e1.shape().end();
}
// add this when we have std::array index!
// std::fill(idx.begin(), idx.end(), 0);
dynamic_shape<std::size_t> max(max_shape_begin, max_shape_end);
using simd_type = xsimd::simd_type<typename E1::value_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.
// Use default layout to make decision
std::size_t step_dim = 0;
if (!is_row_major) // row major case
{
step_dim = cut;
}
for (std::size_t ox = 0; ox < outer_loop_size; ++ox)
{
for (std::size_t i = 0; i < simd_size; i++)
{
res_stepper.template store_simd<simd_type>(fct_stepper.template step_simd<simd_type>());
}
for (std::size_t i = 0; i < simd_rest; ++i)
{
*(res_stepper) = *(fct_stepper);
res_stepper.step_leading();
fct_stepper.step_leading();
}
is_row_major ?
strided_assign_detail::idx_tools<layout_type::row_major>::next_idx(idx, max) :
strided_assign_detail::idx_tools<layout_type::column_major>::next_idx(idx, max);
fct_stepper.to_begin();
// need to step E1 as well if not contigous assign (e.g. view)
if (!E1::contiguous_layout)
{
res_stepper.to_begin();
for (std::size_t i = 0; i < idx.size(); ++i)
{
fct_stepper.step(i + step_dim, idx[i]);
res_stepper.step(i + step_dim, idx[i]);
}
}
else
{
for (std::size_t i = 0; i < idx.size(); ++i)
{
fct_stepper.step(i + step_dim, idx[i]);
}
}
}
}
template <class E1, class E2>
inline void strided_assign(E1& /*e1*/, const E2& /*e2*/, std::false_type /*disable*/)
{
}
}
#endif

View file

@ -0,0 +1,197 @@
/***************************************************************************
* 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_AXIS_ITERATOR_HPP
#define XTENSOR_AXIS_ITERATOR_HPP
#include <xtl/xclosure.hpp>
#include "xview.hpp"
namespace xt
{
/******************
* xaxis_iterator *
******************/
template <class CT>
class xaxis_iterator
{
public:
using self_type = xaxis_iterator<CT>;
using xexpression_type = std::decay_t<CT>;
using size_type = typename xexpression_type::size_type;
using difference_type = typename xexpression_type::difference_type;
using value_type = xview<CT, size_type>;
using reference = std::remove_reference_t<apply_cv_t<CT, value_type>>;
using pointer = xtl::xclosure_pointer<std::remove_reference_t<apply_cv_t<CT, value_type>>>;
using iterator_category = std::forward_iterator_tag;
xaxis_iterator();
template <class CTA>
xaxis_iterator(CTA&& e, size_type index);
self_type& operator++();
self_type operator++(int);
reference operator*() const;
pointer operator->() const;
bool equal(const self_type& rhs) const;
private:
using storing_type = xtl::ptr_closure_type_t<CT>;
mutable storing_type p_expression;
size_type m_index;
template <class T>
std::enable_if_t<std::is_pointer<T>::value, std::add_lvalue_reference_t<std::remove_pointer_t<T>>>
deref(T val) const;
template <class T>
std::enable_if_t<!std::is_pointer<T>::value, T>
deref(T& val) const;
template <class T, class CTA>
std::enable_if_t<std::is_pointer<T>::value, T>
get_storage_init(CTA&& e) const;
template <class T, class CTA>
std::enable_if_t<!std::is_pointer<T>::value, T>
get_storage_init(CTA&& e) const;
};
template <class CT>
bool operator==(const xaxis_iterator<CT>& lhs, const xaxis_iterator<CT>& rhs);
template <class CT>
bool operator!=(const xaxis_iterator<CT>& lhs, const xaxis_iterator<CT>& rhs);
template <class E>
auto axis_begin(E&& e);
template <class E>
auto axis_end(E&& e);
/*********************************
* xaxis_iterator implementation *
*********************************/
template <class CT>
template <class T>
inline std::enable_if_t<std::is_pointer<T>::value, std::add_lvalue_reference_t<std::remove_pointer_t<T>>>
xaxis_iterator<CT>::deref(T val) const
{
return *val;
}
template <class CT>
template <class T>
inline std::enable_if_t<!std::is_pointer<T>::value, T>
xaxis_iterator<CT>::deref(T& val) const
{
return val;
}
template <class CT>
template <class T, class CTA>
inline std::enable_if_t<std::is_pointer<T>::value, T>
xaxis_iterator<CT>::get_storage_init(CTA&& e) const
{
return &e;
}
template <class CT>
template <class T, class CTA>
inline std::enable_if_t<!std::is_pointer<T>::value, T>
xaxis_iterator<CT>::get_storage_init(CTA&& e) const
{
return e;
}
template <class CT>
inline xaxis_iterator<CT>::xaxis_iterator()
: p_expression(nullptr), m_index(0)
{
}
template <class CT>
template <class CTA>
inline xaxis_iterator<CT>::xaxis_iterator(CTA&& e, size_type index)
: p_expression(get_storage_init<storing_type>(std::forward<CTA>(e))), m_index(index)
{
}
template <class CT>
inline auto xaxis_iterator<CT>::operator++() -> self_type&
{
++m_index;
return *this;
}
template <class CT>
inline auto xaxis_iterator<CT>::operator++(int) -> self_type
{
self_type tmp(*this);
++(*this);
return tmp;
}
template <class CT>
inline auto xaxis_iterator<CT>::operator*() const -> reference
{
return view(deref(p_expression), size_type(m_index));
}
template <class CT>
inline auto xaxis_iterator<CT>::operator->() const -> pointer
{
return xtl::closure_pointer(operator*());
}
template <class CT>
inline bool xaxis_iterator<CT>::equal(const self_type& rhs) const
{
return p_expression == rhs.p_expression && m_index == rhs.m_index;
}
template <class CT>
inline bool operator==(const xaxis_iterator<CT>& lhs, const xaxis_iterator<CT>& rhs)
{
return lhs.equal(rhs);
}
template <class CT>
inline bool operator!=(const xaxis_iterator<CT>& lhs, const xaxis_iterator<CT>& rhs)
{
return !(lhs == rhs);
}
template <class E>
inline auto axis_begin(E&& e)
{
using return_type = xaxis_iterator<xtl::closure_type_t<E>>;
using size_type = typename std::decay_t<E>::size_type;
return return_type(std::forward<E>(e), size_type(0));
}
template <class E>
inline auto axis_end(E&& e)
{
using return_type = xaxis_iterator<xtl::closure_type_t<E>>;
using size_type = typename std::decay_t<E>::size_type;
return return_type(std::forward<E>(e), size_type(e.shape()[0]));
}
}
#endif

View file

@ -0,0 +1,412 @@
/***************************************************************************
* 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_BROADCAST_HPP
#define XTENSOR_BROADCAST_HPP
#include <algorithm>
#include <array>
#include <cstddef>
#include <iterator>
#include <numeric>
#include <type_traits>
#include <utility>
#include <xtl/xsequence.hpp>
#include "xexpression.hpp"
#include "xiterable.hpp"
#include "xscalar.hpp"
#include "xstrides.hpp"
#include "xutils.hpp"
namespace xt
{
/*************
* broadcast *
*************/
template <class E, class S>
auto broadcast(E&& e, const S& s);
#ifdef X_OLD_CLANG
template <class E, class I>
auto broadcast(E&& e, std::initializer_list<I> s);
#else
template <class E, class I, std::size_t L>
auto broadcast(E&& e, const I (&s)[L]);
#endif
/**************
* xbroadcast *
**************/
template <class CT, class X>
class xbroadcast;
template <class CT, class X>
struct xiterable_inner_types<xbroadcast<CT, X>>
{
using xexpression_type = std::decay_t<CT>;
using inner_shape_type = promote_shape_t<typename xexpression_type::shape_type, X>;
using const_stepper = typename xexpression_type::const_stepper;
using stepper = const_stepper;
};
/**
* @class xbroadcast
* @brief Broadcasted xexpression to a specified shape.
*
* The xbroadcast class implements the broadcasting of an \ref xexpression
* to a specified shape. xbroadcast is not meant to be used directly, but
* only with the \ref broadcast helper functions.
*
* @tparam CT the closure type of the \ref xexpression to broadcast
* @tparam X the type of the specified shape.
*
* @sa broadcast
*/
template <class CT, class X>
class xbroadcast : public xexpression<xbroadcast<CT, X>>,
public xconst_iterable<xbroadcast<CT, X>>
{
public:
using self_type = xbroadcast<CT, X>;
using xexpression_type = std::decay_t<CT>;
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 const_pointer = typename xexpression_type::const_pointer;
using size_type = typename xexpression_type::size_type;
using difference_type = typename xexpression_type::difference_type;
using iterable_base = xconst_iterable<self_type>;
using inner_shape_type = typename iterable_base::inner_shape_type;
using shape_type = inner_shape_type;
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;
static constexpr bool contiguous_layout = false;
template <class CTA, class S>
xbroadcast(CTA&& e, S&& s);
size_type size() const noexcept;
size_type dimension() const noexcept;
const inner_shape_type& shape() const noexcept;
layout_type layout() const noexcept;
template <class... Args>
const_reference operator()(Args... args) const;
template <class... Args>
const_reference at(Args... args) const;
template <class... Args>
const_reference unchecked(Args... args) const;
template <class S>
disable_integral_t<S, const_reference> operator[](const S& index) const;
template <class I>
const_reference operator[](std::initializer_list<I> index) const;
const_reference operator[](size_type i) const;
template <class It>
const_reference element(It first, It last) const;
template <class S>
bool broadcast_shape(S& shape, bool reuse_cache = false) const;
template <class S>
bool is_trivial_broadcast(const S& strides) const noexcept;
template <class S>
const_stepper stepper_begin(const S& shape) const noexcept;
template <class S>
const_stepper stepper_end(const S& shape, layout_type l) const noexcept;
template <class E, class XCT = CT, class = std::enable_if_t<xt::is_xscalar<XCT>::value>>
void assign_to(xexpression<E>& e) const;
private:
CT m_e;
inner_shape_type m_shape;
};
/****************************
* broadcast implementation *
****************************/
/**
* @brief Returns an \ref xexpression broadcasting the given expression to
* a specified shape.
*
* @tparam e the \ref xexpression to broadcast
* @tparam s the specified shape to broadcast.
*
* The returned expression either hold a const reference to \p e or a copy
* depending on whether \p e is an lvalue or an rvalue.
*/
template <class E, class S>
inline auto broadcast(E&& e, const S& s)
{
using broadcast_type = xbroadcast<const_xclosure_t<E>, S>;
using shape_type = typename broadcast_type::shape_type;
return broadcast_type(std::forward<E>(e), xtl::forward_sequence<shape_type>(s));
}
#ifdef X_OLD_CLANG
template <class E, class I>
inline auto broadcast(E&& e, std::initializer_list<I> s)
{
using broadcast_type = xbroadcast<const_xclosure_t<E>, std::vector<std::size_t>>;
using shape_type = typename broadcast_type::shape_type;
return broadcast_type(std::forward<E>(e), xtl::forward_sequence<shape_type>(s));
}
#else
template <class E, class I, std::size_t L>
inline auto broadcast(E&& e, const I (&s)[L])
{
using broadcast_type = xbroadcast<const_xclosure_t<E>, std::array<std::size_t, L>>;
using shape_type = typename broadcast_type::shape_type;
return broadcast_type(std::forward<E>(e), xtl::forward_sequence<shape_type>(s));
}
#endif
/*****************************
* xbroadcast implementation *
*****************************/
/**
* @name Constructor
*/
//@{
/**
* 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 <class CT, class X>
template <class CTA, class S>
inline xbroadcast<CT, X>::xbroadcast(CTA&& e, S&& s)
: m_e(std::forward<CTA>(e)), m_shape(std::forward<S>(s))
{
xt::broadcast_shape(m_e.shape(), m_shape);
}
//@}
/**
* @name Size and shape
*/
/**
* Returns the size of the expression.
*/
template <class CT, class X>
inline auto xbroadcast<CT, X>::size() const noexcept -> size_type
{
return compute_size(shape());
}
/**
* Returns the number of dimensions of the expression.
*/
template <class CT, class X>
inline auto xbroadcast<CT, X>::dimension() const noexcept -> size_type
{
return m_shape.size();
}
/**
* Returns the shape of the expression.
*/
template <class CT, class X>
inline auto xbroadcast<CT, X>::shape() const noexcept -> const inner_shape_type&
{
return m_shape;
}
/**
* Returns the layout_type of the expression.
*/
template <class CT, class X>
inline layout_type xbroadcast<CT, X>::layout() const noexcept
{
return m_e.layout();
}
//@}
/**
* @name Data
*/
/**
* 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 function. Indices
* must be unsigned integers, the number of indices should be equal or greater than
* the number of dimensions of the expression.
*/
template <class CT, class X>
template <class... Args>
inline auto xbroadcast<CT, X>::operator()(Args... args) const -> const_reference
{
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 <class CT, class X>
template <class... Args>
inline auto xbroadcast<CT, X>::at(Args... args) const -> const_reference
{
check_access(shape(), static_cast<size_type>(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
* must be unsigned integers, the number of indices must be equal to the number of
* dimensions of the expression, else the behavior is undefined.
*
* @warning This method is meant for performance, for expressions with a dynamic
* number of dimensions (i.e. not known at compile time). Since it may have
* undefined behavior (see parameters), operator() should be prefered whenever
* it is possible.
* @warning This method is NOT compatible with broadcasting, meaning the following
* code has undefined behavior:
* \code{.cpp}
* xt::xarray<double> a = {{0, 1}, {2, 3}};
* xt::xarray<double> b = {0, 1};
* auto fd = a + b;
* double res = fd.uncheked(0, 1);
* \endcode
*/
template <class CT, class X>
template <class... Args>
inline auto xbroadcast<CT, X>::unchecked(Args... args) const -> const_reference
{
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 <class CT, class X>
template <class S>
inline auto xbroadcast<CT, X>::operator[](const S& index) const
-> disable_integral_t<S, const_reference>
{
return element(index.cbegin(), index.cend());
}
template <class CT, class X>
template <class I>
inline auto xbroadcast<CT, X>::operator[](std::initializer_list<I> index) const -> const_reference
{
return element(index.begin(), index.end());
}
template <class CT, class X>
inline auto xbroadcast<CT, X>::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
* @param last iterator ending the sequence of indices
* The number of indices in the sequence should be equal to or greater
* than the number of dimensions of the function.
*/
template <class CT, class X>
template <class It>
inline auto xbroadcast<CT, X>::element(It, It last) const -> const_reference
{
return m_e.element(last - dimension(), last);
}
//@}
/**
* @name Broadcasting
*/
//@{
/**
* Broadcast the shape of the function to the specified parameter.
* @param shape the result shape
* @param reuse_cache parameter for internal optimization
* @return a boolean indicating whether the broadcasting is trivial
*/
template <class CT, class X>
template <class S>
inline bool xbroadcast<CT, X>::broadcast_shape(S& shape, bool) const
{
return xt::broadcast_shape(m_shape, shape);
}
/**
* 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
*/
template <class CT, class X>
template <class S>
inline bool xbroadcast<CT, X>::is_trivial_broadcast(const S& strides) const noexcept
{
return dimension() == m_e.dimension() &&
std::equal(m_shape.cbegin(), m_shape.cend(), m_e.shape().cbegin()) &&
m_e.is_trivial_broadcast(strides);
}
//@}
template <class CT, class X>
template <class S>
inline auto xbroadcast<CT, X>::stepper_begin(const S& shape) const noexcept -> const_stepper
{
// Could check if (broadcastable(shape, m_shape)
return m_e.stepper_begin(shape);
}
template <class CT, class X>
template <class S>
inline auto xbroadcast<CT, X>::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper
{
// Could check if (broadcastable(shape, m_shape)
return m_e.stepper_end(shape, l);
}
template <class CT, class X>
template <class E, class XCT, class>
inline void xbroadcast<CT, X>::assign_to(xexpression<E>& e) const
{
auto& ed = e.derived_cast();
ed.resize(m_shape);
std::fill(ed.begin(), ed.end(), m_e());
}
}
#endif

View file

@ -0,0 +1,623 @@
/***************************************************************************
* 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_BUFFER_ADAPTOR_HPP
#define XTENSOR_BUFFER_ADAPTOR_HPP
#include <algorithm>
#include <functional>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <xtl/xclosure.hpp>
#include "xstorage.hpp"
namespace xt
{
/******************************
* xbuffer_adator declaration *
******************************/
struct no_ownership
{
};
struct acquire_ownership
{
};
template <class CP, class O = no_ownership, class A = std::allocator<std::remove_pointer_t<std::remove_reference_t<CP>>>>
class xbuffer_adaptor;
/*********************************
* xbuffer_adator implementation *
*********************************/
namespace detail
{
template <class CP, class A>
class xbuffer_storage
{
public:
using self_type = xbuffer_storage<CP, A>;
using allocator_type = A;
using value_type = typename allocator_type::value_type;
using reference = std::conditional_t<std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
typename allocator_type::const_reference,
typename allocator_type::reference>;
using const_reference = typename allocator_type::const_reference;
using pointer = std::conditional_t<std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::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_storage();
template <class P>
xbuffer_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type());
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;
};
template <class CP, class A>
class xbuffer_owner_storage
{
public:
using self_type = xbuffer_owner_storage<CP, A>;
using allocator_type = A;
using value_type = typename allocator_type::value_type;
using reference = std::conditional_t<std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::value,
typename allocator_type::const_reference,
typename allocator_type::reference>;
using const_reference = typename allocator_type::const_reference;
using pointer = std::conditional_t<std::is_const<std::remove_pointer_t<std::remove_reference_t<CP>>>::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_owner_storage() = default;
template <class P>
xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc = allocator_type());
~xbuffer_owner_storage();
xbuffer_owner_storage(const self_type&) = delete;
self_type& operator=(const self_type&);
xbuffer_owner_storage(self_type&&);
self_type& operator=(self_type&&);
size_type size() const noexcept;
void resize(size_type size);
pointer data() noexcept;
const_pointer data() const noexcept;
allocator_type get_allocator() const noexcept;
void swap(self_type& rhs) noexcept;
private:
xtl::xclosure_wrapper<CP> m_data;
size_type m_size;
bool m_moved_from;
allocator_type m_allocator;
};
template <class CP, class A, class O>
struct get_buffer_storage
{
using type = xbuffer_storage<CP, A>;
};
template <class CP, class A>
struct get_buffer_storage<CP, A, acquire_ownership>
{
using type = xbuffer_owner_storage<CP, A>;
};
template <class CP, class A, class O>
using buffer_storage_t = typename get_buffer_storage<CP, A, O>::type;
}
template <class CP, class O, class A>
class xbuffer_adaptor : private detail::buffer_storage_t<CP, A, O>
{
public:
using base_type = detail::buffer_storage_t<CP, A, O>;
using self_type = xbuffer_adaptor<CP, O, A>;
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<value_type, allocator_type>;
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<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
xbuffer_adaptor() = default;
template <class P>
xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc = allocator_type());
~xbuffer_adaptor() = default;
xbuffer_adaptor(const self_type&) = default;
self_type& operator=(const self_type&) = default;
xbuffer_adaptor(self_type&&) = default;
xbuffer_adaptor& operator=(self_type&&) = default;
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 <class CP, class O, class A>
bool operator==(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs);
template <class CP, class O, class A>
bool operator!=(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs);
template <class CP, class O, class A>
bool operator<(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs);
template <class CP, class O, class A>
bool operator<=(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs);
template <class CP, class O, class A>
bool operator>(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs);
template <class CP, class O, class A>
bool operator>=(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs);
template <class CP, class O, class A>
void swap(xbuffer_adaptor<CP, O, A>& lhs,
xbuffer_adaptor<CP, O, A>& rhs) noexcept;
/************************************
* temporary_container metafunction *
************************************/
template <class C>
struct temporary_container
{
using type = C;
};
template <class CP, class O, class A>
struct temporary_container<xbuffer_adaptor<CP, O, A>>
{
using type = typename xbuffer_adaptor<CP, O, A>::temporary_type;
};
template <class C>
using temporary_container_t = typename temporary_container<C>::type;
/**********************************
* xbuffer_storage implementation *
**********************************/
namespace detail
{
template <class CP, class A>
inline xbuffer_storage<CP, A>::xbuffer_storage()
: p_data(nullptr), m_size(0)
{
}
template <class CP, class A>
template <class P>
inline xbuffer_storage<CP, A>::xbuffer_storage(P&& data, size_type size, const allocator_type&)
: p_data(std::forward<P>(data)), m_size(size)
{
}
template <class CP, class A>
inline auto xbuffer_storage<CP, A>::size() const noexcept -> size_type
{
return m_size;
}
template <class CP, class A>
inline void xbuffer_storage<CP, A>::resize(size_type size)
{
if (size != m_size)
{
throw std::runtime_error("xbuffer_storage not resizable");
}
}
template <class CP, class A>
inline auto xbuffer_storage<CP, A>::data() noexcept -> pointer
{
return p_data;
}
template <class CP, class A>
inline auto xbuffer_storage<CP, A>::data() const noexcept -> const_pointer
{
return p_data;
}
template <class CP, class A>
inline void xbuffer_storage<CP, A>::swap(self_type& rhs) noexcept
{
using std::swap;
swap(p_data, rhs.p_data);
swap(m_size, rhs.m_size);
}
}
/****************************************
* xbuffer_owner_storage implementation *
****************************************/
namespace detail
{
template <class CP, class A>
template <class P>
inline xbuffer_owner_storage<CP, A>::xbuffer_owner_storage(P&& data, size_type size, const allocator_type& alloc)
: m_data(std::forward<P>(data)), m_size(size), m_moved_from(false), m_allocator(alloc)
{
}
template <class CP, class A>
inline xbuffer_owner_storage<CP, A>::~xbuffer_owner_storage()
{
if (!m_moved_from)
{
safe_destroy_deallocate(m_allocator, m_data.get(), m_size);
m_size = 0;
}
}
template <class CP, class A>
inline auto xbuffer_owner_storage<CP, A>::operator=(const self_type& rhs) -> self_type&
{
using std::swap;
if (this != &rhs)
{
allocator_type al = std::allocator_traits<allocator_type>::select_on_container_copy_construction(rhs.get_allocator());
pointer tmp = safe_init_allocate(al, rhs.m_size);
if (xtrivially_default_constructible<value_type>::value)
{
std::uninitialized_copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp);
}
else
{
std::copy(rhs.m_data.get(), rhs.m_data.get() + rhs.m_size, tmp);
}
swap(m_data.get(), tmp);
m_size = rhs.m_size;
swap(m_allocator, al);
safe_destroy_deallocate(al, tmp, m_size);
}
return *this;
}
template <class CP, class A>
inline xbuffer_owner_storage<CP, A>::xbuffer_owner_storage(self_type&& rhs)
: m_data(std::move(rhs.m_data)), m_size(std::move(rhs.m_size)), m_moved_from(std::move(rhs.m_moved_from)), m_allocator(std::move(rhs.m_allocator))
{
rhs.m_moved_from = true;
rhs.m_size = 0;
}
template <class CP, class A>
inline auto xbuffer_owner_storage<CP, A>::operator=(self_type&& rhs) -> self_type&
{
swap(rhs);
rhs.m_moved_from = true;
return *this;
}
template <class CP, class A>
inline auto xbuffer_owner_storage<CP, A>::size() const noexcept -> size_type
{
return m_size;
}
template <class CP, class A>
void xbuffer_owner_storage<CP, A>::resize(size_type size)
{
using std::swap;
if (size != m_size)
{
pointer tmp = safe_init_allocate(m_allocator, size);
swap(m_data.get(), tmp);
swap(m_size, size);
safe_destroy_deallocate(m_allocator, tmp, size);
}
}
template <class CP, class A>
inline auto xbuffer_owner_storage<CP, A>::data() noexcept -> pointer
{
return m_data.get();
}
template <class CP, class A>
inline auto xbuffer_owner_storage<CP, A>::data() const noexcept -> const_pointer
{
return m_data.get();
}
template <class CP, class A>
inline auto xbuffer_owner_storage<CP, A>::get_allocator() const noexcept -> allocator_type
{
return allocator_type(m_allocator);
}
template <class CP, class A>
inline void xbuffer_owner_storage<CP, A>::swap(self_type& rhs) noexcept
{
using std::swap;
swap(m_data, rhs.m_data);
swap(m_size, rhs.m_size);
swap(m_allocator, rhs.m_allocator);
}
}
/**********************************
* xbuffer_adaptor implementation *
**********************************/
template <class CP, class O, class A>
template <class P>
inline xbuffer_adaptor<CP, O, A>::xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc)
: base_type(std::forward<P>(data), size, alloc)
{
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::operator=(temporary_type&& tmp) -> self_type&
{
base_type::resize(tmp.size());
std::copy(tmp.cbegin(), tmp.cend(), begin());
return *this;
}
template <class CP, class O, class A>
bool xbuffer_adaptor<CP, O, A>::empty() const noexcept
{
return size() == 0;
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::operator[](size_type i) -> reference
{
return data()[i];
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::operator[](size_type i) const -> const_reference
{
return data()[i];
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::front() -> reference
{
return data()[0];
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::front() const -> const_reference
{
return data()[0];
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::back() -> reference
{
return data()[size() - 1];
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::back() const -> const_reference
{
return data()[size() - 1];
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::begin() -> iterator
{
return data();
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::end() -> iterator
{
return data() + size();
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::begin() const -> const_iterator
{
return data();
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::end() const -> const_iterator
{
return data() + size();
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::cbegin() const -> const_iterator
{
return begin();
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::cend() const -> const_iterator
{
return end();
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::rbegin() -> reverse_iterator
{
return reverse_iterator(end());
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::rend() -> reverse_iterator
{
return reverse_iterator(begin());
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::rbegin() const -> const_reverse_iterator
{
return const_reverse_iterator(end());
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::rend() const -> const_reverse_iterator
{
return const_reverse_iterator(begin());
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::crbegin() const -> const_reverse_iterator
{
return rbegin();
}
template <class CP, class O, class A>
inline auto xbuffer_adaptor<CP, O, A>::crend() const -> const_reverse_iterator
{
return rend();
}
template <class CP, class O, class A>
inline bool operator==(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs)
{
return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin());
}
template <class CP, class O, class A>
inline bool operator!=(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs)
{
return !(lhs == rhs);
}
template <class CP, class O, class A>
inline bool operator<(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
std::less<typename A::value_type>());
}
template <class CP, class O, class A>
inline bool operator<=(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
std::less_equal<typename A::value_type>());
}
template <class CP, class O, class A>
inline bool operator>(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
std::greater<typename A::value_type>());
}
template <class CP, class O, class A>
inline bool operator>=(const xbuffer_adaptor<CP, O, A>& lhs,
const xbuffer_adaptor<CP, O, A>& rhs)
{
return std::lexicographical_compare(lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
std::greater_equal<typename A::value_type>());
}
template <class CP, class O, class A>
inline void swap(xbuffer_adaptor<CP, O, A>& lhs,
xbuffer_adaptor<CP, O, A>& rhs) noexcept
{
lhs.swap(rhs);
}
}
#endif

View file

@ -0,0 +1,918 @@
/***************************************************************************
* 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. *
****************************************************************************/
/**
* @brief standard mathematical functions for xexpressions
*/
#ifndef XTENSOR_BUILDER_HPP
#define XTENSOR_BUILDER_HPP
#include <array>
#include <cmath>
#include <cstddef>
#include <functional>
#include <utility>
#include <vector>
#ifdef X_OLD_CLANG
#include <initializer_list>
#endif
#include <xtl/xclosure.hpp>
#include <xtl/xsequence.hpp>
#include "xbroadcast.hpp"
#include "xfunction.hpp"
#include "xgenerator.hpp"
#include "xoperation.hpp"
namespace xt
{
/********
* ones *
********/
/**
* Returns an \ref xexpression containing ones of the specified shape.
* @tparam shape the shape of the returned expression.
*/
template <class T, class S>
inline auto ones(S shape) noexcept
{
return broadcast(T(1), std::forward<S>(shape));
}
#ifdef X_OLD_CLANG
template <class T, class I>
inline auto ones(std::initializer_list<I> shape) noexcept
{
return broadcast(T(1), shape);
}
#else
template <class T, class I, std::size_t L>
inline auto ones(const I (&shape)[L]) noexcept
{
return broadcast(T(1), shape);
}
#endif
/*********
* zeros *
*********/
/**
* Returns an \ref xexpression containing zeros of the specified shape.
* @tparam shape the shape of the returned expression.
*/
template <class T, class S>
inline auto zeros(S shape) noexcept
{
return broadcast(T(0), std::forward<S>(shape));
}
#ifdef X_OLD_CLANG
template <class T, class I>
inline auto zeros(std::initializer_list<I> shape) noexcept
{
return broadcast(T(0), shape);
}
#else
template <class T, class I, std::size_t L>
inline auto zeros(const I (&shape)[L]) noexcept
{
return broadcast(T(0), shape);
}
#endif
/**
* Create a xcontainer (xarray, xtensor or xtensor_fixed) with uninitialized values of
* with value_type T and shape. Selects the best container match automatically
* from the supplied shape.
*
* - ``std::vector`` ``xarray<T>``
* - ``std::array`` or ``initializer_list`` ``xtensor<T, N>``
* - ``xshape<N...>`` ``xtensor_fixed<T, xshape<N...>>``
*
* @param shape shape of the new xcontainer
*/
template <class T, layout_type L = XTENSOR_DEFAULT_LAYOUT, class S>
inline xarray<T, L> empty(const S& shape)
{
return xarray<T, L>::from_shape(shape);
}
template <class T, layout_type L = XTENSOR_DEFAULT_LAYOUT, class ST, std::size_t N>
inline xtensor<T, N, L> empty(const std::array<ST, N>& shape)
{
using shape_type = typename xtensor<T, N>::shape_type;
return xtensor<T, N, L>(xtl::forward_sequence<shape_type>(shape));
}
#ifndef X_OLD_CLANG
template <class T, layout_type L = XTENSOR_DEFAULT_LAYOUT, class I, std::size_t N>
inline xtensor<T, N, L> empty(const I(&shape)[N])
{
using shape_type = typename xtensor<T, N>::shape_type;
return xtensor<T, N, L>(xtl::forward_sequence<shape_type>(shape));
}
#endif
template <class T, layout_type L = XTENSOR_DEFAULT_LAYOUT, std::size_t... N>
inline xtensor_fixed<T, fixed_shape<N...>, L> empty(const fixed_shape<N...>& /*shape*/)
{
return xtensor_fixed<T, fixed_shape<N...>, L>();
}
/**
* Create a xcontainer (xarray, xtensor or xtensor_fixed) with uninitialized values of
* the same shape, value type and layout as the input xexpression *e*.
*
* @param e the xexpression from which to extract shape, value type and layout.
*/
template <class E>
inline typename E::temporary_type empty_like(const xexpression<E>& e)
{
typename E::temporary_type res(e.derived_cast().shape());
return res;
}
/**
* Create a xcontainer (xarray, xtensor or xtensor_fixed), filled with *fill_value* and of
* the same shape, value type and layout as the input xexpression *e*.
*
* @param e the xexpression from which to extract shape, value type and layout.
* @param fill_value the value used to set each element of the returned xcontainer.
*/
template <class E>
inline typename E::temporary_type full_like(const xexpression<E>& e, typename E::value_type fill_value)
{
typename E::temporary_type res(e.derived_cast().shape(), fill_value);
return res;
}
/**
* Create a xcontainer (xarray, xtensor or xtensor_fixed), filled with zeros and of
* the same shape, value type and layout as the input xexpression *e*.
*
* Note: contrary to zeros(shape), this function returns a non-lazy, allocated container!
* Use ``xt::zeros<double>(e.shape());` for a lazy version.
*
* @param e the xexpression from which to extract shape, value type and layout.
*/
template <class E>
inline typename E::temporary_type zeros_like(const xexpression<E>& e)
{
return full_like(e, typename E::value_type(0));
}
/**
* Create a xcontainer (xarray, xtensor or xtensor_fixed), filled with ones and of
* the same shape, value type and layout as the input xexpression *e*.
*
* Note: contrary to ones(shape), this function returns a non-lazy, evaluated container!
* Use ``xt::ones<double>(e.shape());`` for a lazy version.
*
* @param e the xexpression from which to extract shape, value type and layout.
*/
template <class E>
inline typename E::temporary_type ones_like(const xexpression<E>& e)
{
return full_like(e, typename E::value_type(1));
}
namespace detail
{
template <class T>
class arange_impl
{
public:
using value_type = T;
arange_impl(T start, T stop, T step)
: m_start(start), m_stop(stop), m_step(step)
{
}
template <class... Args>
inline T operator()(Args... args) const
{
return access_impl(args...);
}
template <class It>
inline T element(It first, It) const
{
return m_start + m_step * T(*first);
}
template <class E>
inline void assign_to(xexpression<E>& e) const noexcept
{
auto& de = e.derived_cast();
value_type value = m_start;
for (auto& el : de.storage())
{
el = value;
value += m_step;
}
}
private:
value_type m_start;
value_type m_stop;
value_type m_step;
template <class T1, class... Args>
inline T access_impl(T1 t, Args...) const
{
return m_start + m_step * T(t);
}
inline T access_impl() const
{
return m_start;
}
};
template <class F>
class fn_impl
{
public:
using value_type = typename F::value_type;
using size_type = std::size_t;
fn_impl(F&& f)
: m_ft(f)
{
}
inline value_type operator()() const
{
size_type idx[1] = {0ul};
return access_impl(std::begin(idx), std::end(idx));
}
template <class... Args>
inline value_type operator()(Args... args) const
{
size_type idx[sizeof...(Args)] = {static_cast<size_type>(args)...};
return access_impl(std::begin(idx), std::end(idx));
}
template <class It>
inline value_type element(It first, It last) const
{
return access_impl(first, last);
}
private:
F m_ft;
template <class It>
inline value_type access_impl(const It& begin, const It& end) const
{
return m_ft(begin, end);
}
};
template <class T>
class eye_fn
{
public:
using value_type = T;
eye_fn(int k)
: m_k(k)
{
}
template <class It>
inline T operator()(const It& /*begin*/, const It& end) const
{
using lvalue_type = typename std::iterator_traits<It>::value_type;
return *(end - 1) == *(end - 2) + static_cast<lvalue_type>(static_cast<unsigned int>(m_k)) ? T(1) : T(0);
}
private:
int m_k;
};
}
/**
* Generates an array with ones on the diagonal.
* @param shape shape of the resulting expression
* @param k index of the diagonal. 0 (default) refers to the main diagonal,
* a positive value refers to an upper diagonal, and a negative
* value to a lower diagonal.
* @tparam T value_type of xexpression
* @return xgenerator that generates the values on access
*/
template <class T = bool>
inline auto eye(const std::vector<std::size_t>& shape, int k = 0)
{
return detail::make_xgenerator(detail::fn_impl<detail::eye_fn<T>>(detail::eye_fn<T>(k)), shape);
}
/**
* Generates a (n x n) array with ones on the diagonal.
* @param n length of the diagonal.
* @param k index of the diagonal. 0 (default) refers to the main diagonal,
* a positive value refers to an upper diagonal, and a negative
* value to a lower diagonal.
* @tparam T value_type of xexpression
* @return xgenerator that generates the values on access
*/
template <class T = bool>
inline auto eye(std::size_t n, int k = 0)
{
return eye<T>({n, n}, k);
}
/**
* Generates numbers evenly spaced within given half-open interval [start, stop).
* @param start start of the interval
* @param stop stop of the interval
* @param step stepsize
* @tparam T value_type of xexpression
* @return xgenerator that generates the values on access
*/
template <class T>
inline auto arange(T start, T stop, T step = 1) noexcept
{
std::size_t shape = static_cast<std::size_t>(std::ceil((stop - start) / step));
return detail::make_xgenerator(detail::arange_impl<T>(start, stop, step), {shape});
}
/**
* Generate numbers evenly spaced within given half-open interval [0, stop)
* with a step size of 1.
* @param stop stop of the interval
* @tparam T value_type of xexpression
* @return xgenerator that generates the values on access
*/
template <class T>
inline auto arange(T stop) noexcept
{
return arange<T>(T(0), stop, T(1));
}
/**
* Generates @a num_samples evenly spaced numbers over given interval
* @param start start of interval
* @param stop stop of interval
* @param num_samples number of samples (defaults to 50)
* @param endpoint if true, include endpoint (defaults to true)
* @tparam T value_type of xexpression
* @return xgenerator that generates the values on access
*/
template <class T>
inline auto linspace(T start, T stop, std::size_t num_samples = 50, bool endpoint = true) noexcept
{
using fp_type = std::common_type_t<T, double>;
fp_type step = fp_type(stop - start) / fp_type(num_samples - (endpoint ? 1 : 0));
return cast<T>(detail::make_xgenerator(detail::arange_impl<fp_type>(fp_type(start), fp_type(stop), step), {num_samples}));
}
/**
* Generates @a num_samples numbers evenly spaced on a log scale over given interval
* @param start start of interval (pow(base, start) is the first value).
* @param stop stop of interval (pow(base, stop) is the final value, except if endpoint = false)
* @param num_samples number of samples (defaults to 50)
* @param base the base of the log space.
* @param endpoint if true, include endpoint (defaults to true)
* @tparam T value_type of xexpression
* @return xgenerator that generates the values on access
*/
template <class T>
inline auto logspace(T start, T stop, std::size_t num_samples, T base = 10, bool endpoint = true) noexcept
{
return cast<T>(pow(std::move(base), linspace(start, stop, num_samples, endpoint)));
}
namespace detail
{
template <class... CT>
class concatenate_impl
{
public:
using size_type = std::size_t;
using value_type = promote_type_t<typename std::decay_t<CT>::value_type...>;
inline concatenate_impl(std::tuple<CT...>&& t, size_type axis)
: m_t(t), m_axis(axis)
{
}
template <class... Args>
inline value_type operator()(Args... args) const
{
// TODO: avoid memory allocation
return access_impl(xindex({static_cast<size_type>(args)...}));
}
template <class It>
inline value_type element(It first, It last) const
{
// TODO: avoid memory allocation
return access_impl(xindex(first, last));
}
private:
inline value_type access_impl(xindex idx) const
{
auto match = [this, &idx](auto& arr) {
if (idx[this->m_axis] >= arr.shape()[this->m_axis])
{
idx[this->m_axis] -= arr.shape()[this->m_axis];
return false;
}
return true;
};
auto get = [&idx](auto& arr) {
return arr[idx];
};
size_type i = 0;
for (; i < sizeof...(CT); ++i)
{
if (apply<bool>(i, match, m_t))
{
break;
}
}
return apply<value_type>(i, get, m_t);
}
std::tuple<CT...> m_t;
size_type m_axis;
};
template <class... CT>
class stack_impl
{
public:
using size_type = std::size_t;
using value_type = promote_type_t<typename std::decay_t<CT>::value_type...>;
inline stack_impl(std::tuple<CT...>&& t, size_type axis)
: m_t(t), m_axis(axis)
{
}
template <class... Args>
inline value_type operator()(Args... args) const
{
// TODO: avoid memory allocation
return access_impl(xindex({static_cast<size_type>(args)...}));
}
template <class It>
inline value_type element(It first, It last) const
{
// TODO: avoid memory allocation
return access_impl(xindex(first, last));
}
private:
inline value_type access_impl(xindex idx) const
{
auto get_item = [&idx](auto& arr) {
return arr[idx];
};
size_type i = idx[m_axis];
idx.erase(idx.begin() + std::ptrdiff_t(m_axis));
return apply<value_type>(i, get_item, m_t);
}
const std::tuple<CT...> m_t;
const size_type m_axis;
};
template <class CT>
class repeat_impl
{
public:
using xexpression_type = std::decay_t<CT>;
using size_type = typename xexpression_type::size_type;
using value_type = typename xexpression_type::value_type;
template <class CTA>
repeat_impl(CTA&& source, size_type axis)
: m_source(std::forward<CTA>(source)), m_axis(axis)
{
}
template <class... Args>
value_type operator()(Args... args) const
{
std::array<size_type, sizeof...(Args)> args_arr = {static_cast<size_type>(args)...};
return m_source(args_arr[m_axis]);
}
template <class It>
inline value_type element(It first, It) const
{
return m_source(*(first + static_cast<std::ptrdiff_t>(m_axis)));
}
private:
CT m_source;
size_type m_axis;
};
}
/**
* @brief Creates tuples from arguments for \ref concatenate and \ref stack.
* Very similar to std::make_tuple.
*/
template <class... Types>
inline auto xtuple(Types&&... args)
{
return std::tuple<xtl::const_closure_type_t<Types>...>(std::forward<Types>(args)...);
}
/**
* @brief Concatenates xexpressions along \em axis.
*
* @param t \ref xtuple of xexpressions to concatenate
* @param axis axis along which elements are concatenated
* @returns xgenerator evaluating to concatenated elements
*
* \code{.cpp}
* xt::xarray<double> a = {{1, 2, 3}};
* xt::xarray<double> b = {{2, 3, 4}};
* xt::xarray<double> c = xt::concatenate(xt::xtuple(a, b)); // => {{1, 2, 3},
* {2, 3, 4}}
* xt::xarray<double> d = xt::concatenate(xt::xtuple(a, b), 1); // => {{1, 2, 3, 2, 3, 4}}
* \endcode
*/
template <class... CT>
inline auto concatenate(std::tuple<CT...>&& t, std::size_t axis = 0)
{
using shape_type = promote_shape_t<typename std::decay_t<CT>::shape_type...>;
shape_type new_shape = xtl::forward_sequence<shape_type>(std::get<0>(t).shape());
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<CT...>(std::forward<std::tuple<CT...>>(t), axis), new_shape);
}
namespace detail
{
template <class T, std::size_t N>
inline std::array<T, N + 1> add_axis(std::array<T, N> arr, std::size_t axis, std::size_t value)
{
std::array<T, N + 1> temp;
std::copy(arr.begin(), arr.begin() + axis, temp.begin());
temp[axis] = value;
std::copy(arr.begin() + axis, arr.end(), temp.begin() + axis + 1);
return temp;
}
template <class T>
inline T add_axis(T arr, std::size_t axis, std::size_t value)
{
T temp(arr);
temp.insert(temp.begin() + std::ptrdiff_t(axis), value);
return temp;
}
}
/**
* @brief Stack xexpressions along \em axis.
* Stacking always creates a new dimension along which elements are stacked.
*
* @param t \ref xtuple of xexpressions to concatenate
* @param axis axis along which elements are stacked
* @returns xgenerator evaluating to stacked elements
*
* \code{.cpp}
* xt::xarray<double> a = {1, 2, 3};
* xt::xarray<double> b = {5, 6, 7};
* xt::xarray<double> s = xt::stack(xt::xtuple(a, b)); // => {{1, 2, 3},
* {5, 6, 7}}
* xt::xarray<double> t = xt::stack(xt::xtuple(a, b), 1); // => {{1, 5},
* {2, 6},
* {3, 7}}
* \endcode
*/
template <class... CT>
inline auto stack(std::tuple<CT...>&& t, std::size_t axis = 0)
{
using shape_type = promote_shape_t<typename std::decay_t<CT>::shape_type...>;
auto new_shape = detail::add_axis(xtl::forward_sequence<shape_type>(std::get<0>(t).shape()), axis, sizeof...(CT));
return detail::make_xgenerator(detail::stack_impl<CT...>(std::forward<std::tuple<CT...>>(t), axis), new_shape);
}
namespace detail
{
template <std::size_t... I, class... E>
inline auto meshgrid_impl(std::index_sequence<I...>, E&&... e) noexcept
{
#if defined X_OLD_CLANG || defined _MSC_VER
const std::array<std::size_t, sizeof...(E)> shape = {e.shape()[0]...};
return std::make_tuple(
detail::make_xgenerator(
detail::repeat_impl<xclosure_t<E>>(std::forward<E>(e), I),
shape
)...
);
#else
return std::make_tuple(
detail::make_xgenerator(
detail::repeat_impl<xclosure_t<E>>(std::forward<E>(e), I),
{e.shape()[0]...}
)...
);
#endif
}
}
/**
* @brief Return coordinate tensors from coordinate vectors.
* Make N-D coordinate tensor expressions for vectorized evaluations of N-D scalar/vector
* fields over N-D grids, given one-dimensional coordinate arrays x1, x2,..., xn.
*
* @param e xexpressions to concatenate
* @returns tuple of xgenerator expressions.
*/
template <class... E>
inline auto meshgrid(E&&... e) noexcept
{
return detail::meshgrid_impl(std::make_index_sequence<sizeof...(E)>(), std::forward<E>(e)...);
}
namespace detail
{
template <class CT>
class diagonal_fn
{
public:
using xexpression_type = std::decay_t<CT>;
using value_type = typename xexpression_type::value_type;
template <class CTA>
diagonal_fn(CTA&& source, int offset, std::size_t axis_1, std::size_t axis_2)
: m_source(std::forward<CTA>(source)), m_offset(offset), m_axis_1(axis_1), m_axis_2(axis_2)
{
}
template <class It>
inline value_type operator()(It begin, It) const
{
xindex idx(m_source.shape().size());
for (std::size_t i = 0; i < idx.size(); i++)
{
if (i != m_axis_1 && i != m_axis_2)
{
idx[i] = *begin++;
}
}
using it_vtype = typename std::iterator_traits<It>::value_type;
it_vtype uoffset = static_cast<it_vtype>(m_offset);
if (m_offset >= 0)
{
idx[m_axis_1] = *(begin);
idx[m_axis_2] = *(begin) + uoffset;
}
else
{
idx[m_axis_1] = *(begin) - uoffset;
idx[m_axis_2] = *(begin);
}
return m_source[idx];
}
private:
CT m_source;
const int m_offset;
const std::size_t m_axis_1;
const std::size_t m_axis_2;
};
template <class CT>
class diag_fn
{
public:
using xexpression_type = std::decay_t<CT>;
using value_type = typename xexpression_type::value_type;
template <class CTA>
diag_fn(CTA&& source, int k)
: m_source(std::forward<CTA>(source)), m_k(k)
{
}
template <class It>
inline value_type operator()(It begin, It) const
{
using it_vtype = typename std::iterator_traits<It>::value_type;
it_vtype umk = static_cast<it_vtype>(m_k);
if (m_k > 0)
{
return *begin + umk == *(begin + 1) ? m_source(*begin) : value_type(0);
}
else
{
return *begin + umk == *(begin + 1) ? m_source(*begin + umk) : value_type(0);
}
}
private:
CT m_source;
const int m_k;
};
template <class CT, class Comp>
class trilu_fn
{
public:
using xexpression_type = std::decay_t<CT>;
using value_type = typename xexpression_type::value_type;
using signed_idx_type = long int;
template <class CTA>
trilu_fn(CTA&& source, int k, Comp comp)
: m_source(std::forward<CTA>(source)), m_k(k), m_comp(comp)
{
}
template <class It>
inline value_type operator()(It begin, It end) const
{
// have to cast to signed int otherwise -1 can lead to overflow
return m_comp(signed_idx_type(*begin) + m_k, signed_idx_type(*(begin + 1))) ? m_source.element(begin, end) : value_type(0);
}
private:
CT m_source;
const signed_idx_type m_k;
const Comp m_comp;
};
}
namespace detail
{
// meta-function returning the shape type for a diagonal
template <class ST, class... S>
struct diagonal_shape_type
{
using type = ST;
};
template <class I, std::size_t L>
struct diagonal_shape_type<std::array<I, L>>
{
using type = std::array<I, L - 1>;
};
}
/**
* @brief Returns the elements on the diagonal of arr
* If arr has more than two dimensions, then the axes specified by
* axis_1 and axis_2 are used to determine the 2-D sub-array whose
* diagonal is returned. The shape of the resulting array can be
* determined by removing axis1 and axis2 and appending an index
* to the right equal to the size of the resulting diagonals.
*
* @param arr the input array
* @param offset offset of the diagonal from the main diagonal. Can
* be positive or negative.
* @param axis_1 Axis to be used as the first axis of the 2-D sub-arrays
* from which the diagonals should be taken.
* @param axis_2 Axis to be used as the second axis of the 2-D sub-arrays
* from which the diagonals should be taken.
* @returns xexpression with values of the diagonal
*
* \code{.cpp}
* xt::xarray<double> a = {{1, 2, 3},
* {4, 5, 6}
* {7, 8, 9}};
* auto b = xt::diagonal(a); // => {1, 5, 9}
* \endcode
*/
template <class E>
inline auto diagonal(E&& arr, int offset = 0, std::size_t axis_1 = 0, std::size_t axis_2 = 1)
{
using CT = xclosure_t<E>;
using shape_type = typename detail::diagonal_shape_type<typename std::decay_t<E>::shape_type>::type;
auto shape = arr.shape();
auto dimension = arr.dimension();
// The following shape calculation code is an almost verbatim adaptation of numpy:
// https://github.com/numpy/numpy/blob/2aabeafb97bea4e1bfa29d946fbf31e1104e7ae0/numpy/core/src/multiarray/item_selection.c#L1799
auto ret_shape = xtl::make_sequence<shape_type>(dimension - 1, 0);
int dim_1 = static_cast<int>(shape[axis_1]);
int dim_2 = static_cast<int>(shape[axis_2]);
offset >= 0 ? dim_2 -= offset : dim_1 += offset;
auto diag_size = std::size_t(dim_2 < dim_1 ? dim_2 : dim_1);
std::size_t i = 0;
for (std::size_t idim = 0; idim < dimension; ++idim)
{
if (idim != axis_1 && idim != axis_2)
{
ret_shape[i++] = shape[idim];
}
}
ret_shape.back() = diag_size;
return detail::make_xgenerator(detail::fn_impl<detail::diagonal_fn<CT>>(detail::diagonal_fn<CT>(std::forward<E>(arr), offset, axis_1, axis_2)),
ret_shape);
}
/**
* @brief xexpression with values of arr on the diagonal, zeroes otherwise
*
* @param arr the 1D input array of length n
* @param k the offset of the considered diagonal
* @returns xexpression function with shape n x n and arr on the diagonal
*
* \code{.cpp}
* xt::xarray<double> a = {1, 5, 9};
* auto b = xt::diag(a); // => {{1, 0, 0},
* // {0, 5, 0},
* // {0, 0, 9}}
* \endcode
*/
template <class E>
inline auto diag(E&& arr, int k = 0)
{
using CT = xclosure_t<E>;
std::size_t sk = std::size_t(std::abs(k));
std::size_t s = arr.shape()[0] + sk;
return detail::make_xgenerator(detail::fn_impl<detail::diag_fn<CT>>(detail::diag_fn<CT>(std::forward<E>(arr), k)),
{s, s});
}
/**
* @brief Extract lower triangular matrix from xexpression. The parameter k selects the
* offset of the diagonal.
*
* @param arr the input array
* @param k the diagonal above which to zero elements. 0 (default) selects the main diagonal,
* k < 0 is below the main diagonal, k > 0 above.
* @returns xexpression containing lower triangle from arr, 0 otherwise
*/
template <class E>
inline auto tril(E&& arr, int k = 0)
{
using CT = xclosure_t<E>;
auto shape = arr.shape();
return detail::make_xgenerator(detail::fn_impl<detail::trilu_fn<CT, std::greater_equal<long int>>>(
detail::trilu_fn<CT, std::greater_equal<long int>>(std::forward<E>(arr), k, std::greater_equal<long int>())),
shape);
}
/**
* @brief Extract upper triangular matrix from xexpression. The parameter k selects the
* offset of the diagonal.
*
* @param arr the input array
* @param k the diagonal below which to zero elements. 0 (default) selects the main diagonal,
* k < 0 is below the main diagonal, k > 0 above.
* @returns xexpression containing lower triangle from arr, 0 otherwise
*/
template <class E>
inline auto triu(E&& arr, int k = 0)
{
using CT = xclosure_t<E>;
auto shape = arr.shape();
return detail::make_xgenerator(detail::fn_impl<detail::trilu_fn<CT, std::less_equal<long int>>>(
detail::trilu_fn<CT, std::less_equal<long int>>(std::forward<E>(arr), k, std::less_equal<long int>())),
shape);
}
}
#endif

View file

@ -0,0 +1,251 @@
/***************************************************************************
* 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_COMPLEX_HPP
#define XTENSOR_COMPLEX_HPP
#include <type_traits>
#include <utility>
#include <xtl/xcomplex.hpp>
#include "xtensor/xbuilder.hpp"
#include "xtensor/xexpression.hpp"
#include "xtensor/xoffset_view.hpp"
namespace xt
{
/******************************
* real and imag declarations *
******************************/
template <class E>
decltype(auto) real(E&& e) noexcept;
template <class E>
decltype(auto) imag(E&& e) noexcept;
/********************************
* real and imag implementation *
********************************/
namespace detail
{
template <bool iscomplex = true>
struct complex_helper
{
template <class E>
static inline auto real(E&& e) noexcept
{
using real_type = typename std::decay_t<E>::value_type::value_type;
return xoffset_view<xclosure_t<E>, real_type, 0>(std::forward<E>(e));
}
template <class E>
static inline auto imag(E&& e) noexcept
{
using real_type = typename std::decay_t<E>::value_type::value_type;
return xoffset_view<xclosure_t<E>, real_type, sizeof(real_type)>(std::forward<E>(e));
}
};
template <>
struct complex_helper<false>
{
template <class E>
static inline decltype(auto) real(E&& e) noexcept
{
return e;
}
template <class E>
static inline auto imag(E&& e) noexcept
{
return zeros<typename std::decay_t<E>::value_type>(e.shape());
}
};
template <bool isexpression = true>
struct complex_expression_helper
{
template <class E>
static inline auto real(E&& e) noexcept
{
return detail::complex_helper<xtl::is_complex<typename std::decay_t<E>::value_type>::value>::real(e);
}
template <class E>
static inline auto imag(E&& e) noexcept
{
return detail::complex_helper<xtl::is_complex<typename std::decay_t<E>::value_type>::value>::imag(e);
}
};
template <>
struct complex_expression_helper<false>
{
template <class E>
static inline decltype(auto) real(E&& e) noexcept
{
return xtl::forward_real(std::forward<E>(e));
}
template <class E>
static inline decltype(auto) imag(E&& e) noexcept
{
return xtl::forward_imag(std::forward<E>(e));
}
};
}
/**
* @brief Returns an \ref xexpression representing the real part of the given expression.
*
* @tparam e the \ref xexpression
*
* The returned expression either hold a const reference to \p e or a copy
* depending on whether \p e is an lvalue or an rvalue.
*/
template <class E>
inline decltype(auto) real(E&& e) noexcept
{
return detail::complex_expression_helper<is_xexpression<std::decay_t<E>>::value>::real(std::forward<E>(e));
}
/**
* @brief Returns an \ref xexpression representing the imaginary part of the given expression.
*
* @tparam e the \ref xexpression
*
* The returned expression either hold a const reference to \p e or a copy
* depending on whether \p e is an lvalue or an rvalue.
*/
template <class E>
inline decltype(auto) imag(E&& e) noexcept
{
return detail::complex_expression_helper<is_xexpression<std::decay_t<E>>::value>::imag(std::forward<E>(e));
}
#define UNARY_COMPLEX_FUNCTOR(NAME) \
template <class T> \
struct NAME##_fun \
{ \
using argument_type = T; \
using result_type = decltype(std::NAME(std::declval<T>())); \
constexpr result_type operator()(const T& t) const \
{ \
using std::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<T> instead of T.
template <class T>
constexpr T conj(const T& c)
{
return c;
}
template <class T>
constexpr std::complex<T> conj(const std::complex<T>& c)
{
return std::complex<T>(c.real(), -c.imag());
}
}
template <class T>
struct conj_fun
{
using argument_type = T;
using result_type = decltype(detail::conj(std::declval<T>()));
using simd_value_type = xsimd::simd_type<T>;
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);
}
};
}
#undef UNARY_COMPLEX_FUNCTOR
/**
* @brief Returns an \ref xfunction evaluating to the complex conjugate of the given expression.
*
* @param e the \ref xexpression
*/
template <class E>
inline auto conj(E&& e) noexcept
{
using value_type = typename std::decay_t<E>::value_type;
using functor = math::conj_fun<value_type>;
using result_type = typename functor::result_type;
using type = xfunction<functor, result_type, const_xclosure_t<E>>;
return type(functor(), std::forward<E>(e));
}
/**
* @brief Calculates the phase angle (in radians) elementwise for the complex numbers in e.
* @param e the \ref xexpression
*/
template <class E>
inline auto arg(E&& e) noexcept
{
using value_type = typename std::decay_t<E>::value_type;
using functor = math::arg_fun<value_type>;
using result_type = typename functor::result_type;
using type = xfunction<functor, result_type, const_xclosure_t<E>>;
return type(functor(), std::forward<E>(e));
}
/**
* @brief Calculates the phase angle elementwise for the complex numbers in e.
* Note that this function might be slightly less perfomant than \ref arg.
* @param e the \ref xexpression
* @param deg calculate angle in degrees instead of radians
*/
template <class E>
inline auto angle(E&& e, bool deg = false) noexcept
{
using value_type = xtl::complex_value_type_t<typename std::decay_t<E>::value_type>;
value_type multiplier = 1.0;
if (deg)
{
multiplier = value_type(180) / numeric_constants<value_type>::PI;
}
return arg(std::forward<E>(e)) * std::move(multiplier);
}
/**
* Calculates the squared magnitude elementwise for the complex numbers in e.
* Equivalent to pow(real(e), 2) + pow(imag(e), 2).
* @param e the \ref xexpression
*/
template <class E>
inline auto norm(E&& e) noexcept
{
using value_type = typename std::decay_t<E>::value_type;
using functor = math::norm_fun<value_type>;
using result_type = typename functor::result_type;
using type = xfunction<functor, result_type, const_xclosure_t<E>>;
return type(functor(), std::forward<E>(e));
}
}
#endif

View file

@ -0,0 +1,113 @@
/***************************************************************************
* Copyright (c) 2017, Ullrich Koethe *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#ifndef XTENSOR_CONCEPTS_HPP
#define XTENSOR_CONCEPTS_HPP
#include <type_traits>
/*****************************************************
* concept checking and type inference functionality *
*****************************************************/
namespace xt
{
/******************************************
* XTENSOR_REQUIRE concept checking macro *
******************************************/
struct concept_check_successful
{
};
template <bool CONCEPTS>
using concept_check = typename std::enable_if<CONCEPTS, concept_check_successful>::type;
/** @brief Concept checking macro (more readable than sfinae).
The macro is used as the last argument in a template declaration.
It must be followed by a static boolean expression in angle brackets.
The template will only be included in overload resolution when
this expression evaluates to 'true'.
Example:
\code
template <class T,
XTENSOR_REQUIRE<std::is_arithmetic<T>::value>>
T foo(T t)
{...}
\endcode
*/
#define XTENSOR_REQUIRE typename = concept_check
/********************
* iterator_concept *
********************/
/** @brief Traits class to check if a type is an iterator.
This is useful in concept checking to make sure that a given template
is only instantiated when the argument is an iterator.
Currently, we apply the simple rule that class @tparam T
is either a pointer or a C-array or has an embedded typedef
'iterator_category'. More sophisticated checks can easily
be added when needed.
If @tparam T is indeed an iterator, the class' <tt>value</tt> member
is <tt>true</tt>:
\code
template <class T,
XTENSOR_REQUIRE<iterator_concept<T>::value>>
T foo(T t)
{...}
\endcode
*/
template <class T>
struct iterator_concept
{
using V = std::decay_t<T>;
static char test(...);
template <class U>
static int test(U*, typename U::iterator_category* = 0);
static const bool value =
std::is_array<T>::value ||
std::is_pointer<T>::value ||
std::is_same<decltype(test(std::declval<V*>())), int>::value;
};
/** @brief Check if a conversion may loose information.
@tparam FROM source type
@tparam TO target type
When data is converted from a big type (e.g. <tt>int64_t</tt> or <tt>double</tt>)
to a smaller type (e.g. <tt>int32_t</tt>), most compilers issue a 'possible loss of data'
warning. This metafunction allows you to detect these situations and take appropriate
actions.
If loss of data may occur, member <tt>is_narrowing_conversion::value</tt> is true. Currently,
the check is only implemented for built-in types, i.e. types where <tt>std::is_arithmetic</tt>
is true.
*/
template <class FROM, class TO>
struct is_narrowing_conversion
{
using argument_type = std::decay_t<FROM>;
using result_type = std::decay_t<TO>;
static const bool value = std::is_arithmetic<result_type>::value &&
(sizeof(result_type) < sizeof(argument_type) ||
(std::is_integral<result_type>::value && std::is_floating_point<argument_type>::value));
};
} // namespace xt
#endif // XCONCEPTS_HPP

File diff suppressed because it is too large Load diff

169
vendor/xtensor/include/xtensor/xcsv.hpp vendored Normal file
View file

@ -0,0 +1,169 @@
/***************************************************************************
* 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_CSV_HPP
#define XTENSOR_CSV_HPP
#include <exception>
#include <istream>
#include <iterator>
#include <sstream>
#include <string>
#include <utility>
#include "xtensor.hpp"
namespace xt
{
/**************************************
* load_csv and dump_csv declarations *
**************************************/
template <class T, class A = std::allocator<T>>
using xcsv_tensor = xtensor_container<std::vector<T, A>, 2, layout_type::row_major>;
template <class T, class A = std::allocator<T>>
xcsv_tensor<T, A> load_csv(std::istream& stream);
template <class E>
void dump_csv(std::ostream& stream, const xexpression<E>& e);
/*****************************************
* load_csv and dump_csv implementations *
*****************************************/
namespace detail
{
template <class T>
inline T lexical_cast(const std::string& cell)
{
T res;
std::istringstream iss(cell);
iss >> res;
return res;
}
template <>
inline float lexical_cast<float>(const std::string& cell) { return std::stof(cell); }
template <>
inline double lexical_cast<double>(const std::string& cell) { return std::stod(cell); }
template <>
inline long double lexical_cast<long double>(const std::string& cell) { return std::stold(cell); }
template <>
inline int lexical_cast<int>(const std::string& cell) { return std::stoi(cell); }
template <>
inline long lexical_cast<long>(const std::string& cell) { return std::stol(cell); }
template <>
inline long long lexical_cast<long long>(const std::string& cell) { return std::stoll(cell); }
template <>
inline unsigned int lexical_cast<unsigned int>(const std::string& cell) { return static_cast<unsigned int>(std::stoul(cell)); }
template <>
inline unsigned long lexical_cast<unsigned long>(const std::string& cell) { return std::stoul(cell); }
template <>
inline unsigned long long lexical_cast<unsigned long long>(const std::string& cell) { return std::stoull(cell); }
template <class ST, class T, class OI>
ST load_csv_row(std::istream& row_stream, OI output, std::string cell)
{
ST length = 0;
while (std::getline(row_stream, cell, ','))
{
*output++ = lexical_cast<T>(cell);
++length;
}
return length;
}
}
/**
* @brief Load tensor from CSV.
*
* Returns an \ref xexpression for the parsed CSV
* @param stream the input stream containing the CSV encoded values
*/
template <class T, class A>
xcsv_tensor<T, A> load_csv(std::istream& stream)
{
using tensor_type = xcsv_tensor<T, A>;
using storage_type = typename tensor_type::storage_type;
using size_type = typename tensor_type::size_type;
using inner_shape_type = typename tensor_type::inner_shape_type;
using inner_strides_type = typename tensor_type::inner_strides_type;
using output_iterator = std::back_insert_iterator<storage_type>;
storage_type data;
size_type nbrow = 0, nbcol = 0;
{
output_iterator output(data);
std::string row, cell;
while (std::getline(stream, row))
{
std::stringstream row_stream(row);
nbcol = detail::load_csv_row<size_type, T, output_iterator>(row_stream, output, cell);
++nbrow;
}
}
inner_shape_type shape = {nbrow, nbcol};
inner_strides_type strides; // no need for initializer list for stack-allocated strides_type
size_type data_size = compute_strides(shape, layout_type::row_major, strides);
// Sanity check for data size.
if (data.size() != data_size)
{
throw std::runtime_error("Inconsistent row lengths in CSV");
}
return tensor_type(std::move(data), std::move(shape), std::move(strides));
}
/**
* @brief Dump tensor to CSV.
*
* @param stream the output stream to write the CSV encoded values
* @param e the tensor expression to serialize
*/
template <class E>
void dump_csv(std::ostream& stream, const xexpression<E>& e)
{
using size_type = typename E::size_type;
const E& ex = e.derived_cast();
if (ex.dimension() != 2)
{
throw std::runtime_error("Only 2-D expressions can be serialized to CSV");
}
size_type nbrows = ex.shape()[0], nbcols = ex.shape()[1];
auto st = ex.stepper_begin(ex.shape());
for (size_type r = 0; r != nbrows; ++r)
{
for (size_type c = 0; c != nbcols; ++c)
{
stream << *st;
if (c != nbcols - 1)
{
st.step(1);
stream << ',';
}
else
{
st.reset(1);
st.step(0);
stream << std::endl;
}
}
}
}
}
#endif

View file

@ -0,0 +1,57 @@
/***************************************************************************
* 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_EVAL_HPP
#define XTENSOR_EVAL_HPP
#include "xtensor_forward.hpp"
namespace xt
{
namespace detail
{
template <class T>
using is_container = std::is_base_of<xcontainer<std::remove_const_t<T>>, T>;
}
/**
* Force evaluation of xexpression.
* @return xarray or xtensor depending on shape type
*
* \code{.cpp}
* xarray<double> a = {1,2,3,4};
* auto&& b = xt::eval(a); // b is a reference to a, no copy!
* auto&& c = xt::eval(a + b); // c is xarray<double>, not an xexpression
* \endcode
*/
template <class T>
inline auto eval(T&& t)
-> std::enable_if_t<detail::is_container<std::decay_t<T>>::value, T&&>
{
return std::forward<T>(t);
}
/// @cond DOXYGEN_INCLUDE_SFINAE
template <class T, class I = std::decay_t<T>>
inline auto eval(T&& t)
-> std::enable_if_t<!detail::is_container<I>::value && detail::is_array<typename I::shape_type>::value, xtensor<typename I::value_type, std::tuple_size<typename I::shape_type>::value>>
{
return xtensor<typename I::value_type, std::tuple_size<typename I::shape_type>::value>(std::forward<T>(t));
}
template <class T, class I = std::decay_t<T>>
inline auto eval(T&& t)
-> std::enable_if_t<!detail::is_container<I>::value && !detail::is_array<typename I::shape_type>::value, xt::xarray<typename I::value_type>>
{
return xarray<typename I::value_type>(std::forward<T>(t));
}
/// @endcond
}
#endif

View file

@ -0,0 +1,219 @@
/***************************************************************************
* 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_EXCEPTION_HPP
#define XTENSOR_EXCEPTION_HPP
#include <iterator>
#include <sstream>
#include <stdexcept>
#include <string>
namespace xt
{
/*******************
* broadcast_error *
*******************/
class broadcast_error : public std::runtime_error
{
public:
explicit broadcast_error(const char* msg)
: std::runtime_error(msg)
{
}
};
template <class S1, class S2>
[[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs);
/**********************************
* broadcast_error implementation *
**********************************/
#ifdef NDEBUG
// Do not inline this function
template <class S1, class S2>
[[noreturn]] void throw_broadcast_error(const S1&, const S2&)
{
throw broadcast_error("Incompatible dimension of arrays, compile in DEBUG for more info");
}
#else
template <class S1, class S2>
[[noreturn]] void throw_broadcast_error(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<size_type1> iter1(buf, ", ");
std::copy(lhs.cbegin(), lhs.cend(), iter1);
buf << ")\n RHS shape = (";
using size_type2 = typename S2::value_type;
std::ostream_iterator<size_type2> iter2(buf, ", ");
std::copy(rhs.cbegin(), rhs.cend(), iter2);
buf << ")";
throw broadcast_error(buf.str().c_str());
}
#endif
/*******************
* transpose_error *
*******************/
class transpose_error : public std::runtime_error
{
public:
explicit transpose_error(const char* msg)
: std::runtime_error(msg)
{
}
};
/***************
* check_index *
***************/
template <class S, class... Args>
void check_index(const S& shape, Args... args);
template <class S, class It>
void check_element_index(const S& shape, It first, It last);
namespace detail
{
template <class S, std::size_t dim>
inline void check_index_impl(const S&)
{
}
template <class S, std::size_t dim, class... Args>
inline void check_index_impl(const S& shape, std::size_t arg, Args... args)
{
if (sizeof...(Args) + 1 > shape.size())
{
check_index_impl<S, dim>(shape, args...);
}
else
{
if (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]));
}
check_index_impl<S, dim + 1>(shape, args...);
}
}
}
template <class S, class... Args>
inline void check_index(const S& shape, Args... args)
{
using value_type = typename S::value_type;
detail::check_index_impl<S, 0>(shape, static_cast<value_type>(args)...);
}
template <class S, class It>
inline void check_element_index(const S& shape, It first, It last)
{
using value_type = typename std::iterator_traits<It>::value_type;
auto dst = static_cast<typename S::size_type>(last - first);
It efirst = last - static_cast<std::ptrdiff_t>((std::min)(shape.size(), dst));
std::size_t axis = 0;
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;
}
}
/*******************
* check_dimension *
*******************/
template <class S, class... Args>
inline void check_dimension(const S& shape, Args...)
{
if (sizeof...(Args) > shape.size())
{
throw std::out_of_range("Number of arguments (" + std::to_string(sizeof...(Args)) + ") us greater "
+ "than the number of dimensions (" + std::to_string(shape.size()) + ")");
}
}
/****************
* check_access *
****************/
template <class S, class... Args>
inline void check_access(const S& shape, Args... args)
{
check_dimension(shape, args...);
check_index(shape, args...);
}
#ifdef XTENSOR_ENABLE_ASSERT
#define XTENSOR_TRY(expr) XTENSOR_TRY_IMPL(expr, __FILE__, __LINE__)
#define XTENSOR_TRY_IMPL(expr, file, line) \
try \
{ \
expr; \
} \
catch (std::exception& e) \
{ \
throw std::runtime_error(std::string(file) + ':' + std::to_string(line) + ": check failed\n\t" + std::string(e.what())); \
}
#else
#define XTENSOR_TRY(expr)
#endif
#ifdef XTENSOR_ENABLE_ASSERT
#define XTENSOR_ASSERT(expr) XTENSOR_ASSERT_IMPL(expr, __FILE__, __LINE__)
#define XTENSOR_ASSERT_IMPL(expr, file, line) \
if (!(expr)) \
{ \
throw std::runtime_error(std::string(file) + ':' + std::to_string(line) + ": assertion failed (" #expr ") \n\t"); \
}
#else
#define XTENSOR_ASSERT(expr)
#endif
#ifdef XTENSOR_ENABLE_CHECK_DIMENSION
#define XTENSOR_CHECK_DIMENSION(S, ARGS) XTENSOR_TRY(check_dimension(S, ARGS))
#else
#define XTENSOR_CHECK_DIMENSION(S, ARGS)
#endif
#ifdef XTENSOR_ENABLE_ASSERT
#define XTENSOR_ASSERT_MSG(expr, msg) \
if (!(expr)) \
{ \
throw std::runtime_error(std::string("Assertion error!\n") + msg + \
"\n " + __FILE__ + '(' + std::to_string(__LINE__) + ")\n"); \
}
#else
#define XTENSOR_ASSERT_MSG(expr, msg)
#endif
#define XTENSOR_PRECONDITION(expr, msg) \
if (!(expr)) \
{ \
throw std::runtime_error(std::string("Precondition violation!\n") + msg + \
"\n " + __FILE__ + '(' + std::to_string(__LINE__) + ")\n"); \
}
}
#endif // XEXCEPTION_HPP

View file

@ -0,0 +1,307 @@
/***************************************************************************
* 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_EXPRESSION_HPP
#define XTENSOR_EXPRESSION_HPP
#include <cstddef>
#include <type_traits>
#include <vector>
#include <xtl/xclosure.hpp>
#include <xtl/xtype_traits.hpp>
#include "xshape.hpp"
#include "xutils.hpp"
namespace xt
{
/***************************
* xexpression declaration *
***************************/
/**
* @class xexpression
* @brief Base class for xexpressions
*
* The xexpression class is the base class for all classes representing an expression
* that can be evaluated to a multidimensional container with tensor semantic.
* Functions that can apply to any xexpression regardless of its specific type should take a
* xexpression argument.
*
* \tparam E The derived type.
*
*/
template <class D>
class xexpression
{
public:
using derived_type = D;
derived_type& derived_cast() & noexcept;
const derived_type& derived_cast() const & noexcept;
derived_type derived_cast() && noexcept;
protected:
xexpression() = default;
~xexpression() = default;
xexpression(const xexpression&) = default;
xexpression& operator=(const xexpression&) = default;
xexpression(xexpression&&) = default;
xexpression& operator=(xexpression&&) = default;
};
/******************************
* xexpression implementation *
******************************/
/**
* @name Downcast functions
*/
//@{
/**
* Returns a reference to the actual derived type of the xexpression.
*/
template <class D>
inline auto xexpression<D>::derived_cast() & noexcept -> derived_type&
{
return *static_cast<derived_type*>(this);
}
/**
* Returns a constant reference to the actual derived type of the xexpression.
*/
template <class D>
inline auto xexpression<D>::derived_cast() const & noexcept -> const derived_type&
{
return *static_cast<const derived_type*>(this);
}
/**
* Returns a constant reference to the actual derived type of the xexpression.
*/
template <class D>
inline auto xexpression<D>::derived_cast() && noexcept -> derived_type
{
return *static_cast<derived_type*>(this);
}
//@}
namespace detail
{
template <class E>
struct is_xexpression_impl : std::is_base_of<xexpression<std::decay_t<E>>, std::decay_t<E>>
{
};
template <class E>
struct is_xexpression_impl<xexpression<E>> : std::true_type
{
};
}
template <class E>
using is_xexpression = detail::is_xexpression_impl<E>;
template <class E, class R = void>
using enable_xexpression = typename std::enable_if<is_xexpression<E>::value, R>::type;
template <class E, class R = void>
using disable_xexpression = typename std::enable_if<!is_xexpression<E>::value, R>::type;
template <class... E>
using has_xexpression = xtl::disjunction<is_xexpression<E>...>;
/************
* xclosure *
************/
template <class T>
class xscalar;
template <class E, class EN = void>
struct xclosure
{
using type = xtl::closure_type_t<E>;
};
template <class E>
struct xclosure<E, disable_xexpression<std::decay_t<E>>>
{
using type = xscalar<xtl::closure_type_t<E>>;
};
template <class E>
using xclosure_t = typename xclosure<E>::type;
template <class E, class EN = void>
struct const_xclosure
{
using type = xtl::const_closure_type_t<E>;
};
template <class E>
struct const_xclosure<E, disable_xexpression<std::decay_t<E>>>
{
using type = xscalar<xtl::const_closure_type_t<E>>;
};
template <class E>
using const_xclosure_t = typename const_xclosure<E>::type;
/***************
* xvalue_type *
***************/
namespace detail
{
template <class E, class enable = void>
struct xvalue_type_impl
{
using type = E;
};
template <class E>
struct xvalue_type_impl<E, std::enable_if_t<is_xexpression<E>::value>>
{
using type = typename E::value_type;
};
}
template <class E>
using xvalue_type = detail::xvalue_type_impl<E>;
template <class E>
using xvalue_type_t = typename xvalue_type<E>::type;
/*************************
* expression tag system *
*************************/
struct xscalar_expression_tag
{
};
struct xtensor_expression_tag
{
};
struct xoptional_expression_tag
{
};
namespace detail
{
template <class E, class = void_t<int>>
struct get_expression_tag
{
using type = xtensor_expression_tag;
};
template <class E>
struct get_expression_tag<E, void_t<typename std::decay_t<E>::expression_tag>>
{
using type = typename std::decay_t<E>::expression_tag;
};
template <class E>
using get_expression_tag_t = typename get_expression_tag<E>::type;
template <class... T>
struct expression_tag_and;
template <class T>
struct expression_tag_and<T>
{
using type = T;
};
template <class T>
struct expression_tag_and<T, T>
{
using type = T;
};
template <>
struct expression_tag_and<xscalar_expression_tag, xscalar_expression_tag>
{
using type = xscalar_expression_tag;
};
template <class T>
struct expression_tag_and<xscalar_expression_tag, T>
{
using type = T;
};
template <class T>
struct expression_tag_and<T, xscalar_expression_tag>
: expression_tag_and<xscalar_expression_tag, T>
{
};
template <>
struct expression_tag_and<xtensor_expression_tag, xoptional_expression_tag>
{
using type = xoptional_expression_tag;
};
template <>
struct expression_tag_and<xoptional_expression_tag, xtensor_expression_tag>
: expression_tag_and<xtensor_expression_tag, xoptional_expression_tag>
{
};
template <class T1, class... T>
struct expression_tag_and<T1, T...>
: expression_tag_and<T1, typename expression_tag_and<T...>::type>
{
};
template <class... T>
using expression_tag_and_t = typename expression_tag_and<T...>::type;
}
template <class... T>
struct xexpression_tag
{
using type = detail::expression_tag_and_t<detail::get_expression_tag_t<std::decay_t<const_xclosure_t<T>>>...>;
};
template <class... T>
using xexpression_tag_t = typename xexpression_tag<T...>::type;
template <class E>
struct is_xtensor_expression : std::is_same<xexpression_tag_t<E>, xtensor_expression_tag>
{
};
template <class E>
struct is_xoptional_expression : std::is_same<xexpression_tag_t<E>, xoptional_expression_tag>
{
};
/********************************
* xoptional_comparable concept *
********************************/
template <class... E>
struct xoptional_comparable : xtl::conjunction<xtl::disjunction<is_xtensor_expression<E>,
is_xoptional_expression<E>
>...
>
{
};
}
#endif

View file

@ -0,0 +1,818 @@
/***************************************************************************
* 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_FIXED_HPP
#define XTENSOR_FIXED_HPP
#include <algorithm>
#include <array>
#include <cstddef>
#include <utility>
#include <vector>
#include "xcontainer.hpp"
#include "xstrides.hpp"
#include "xstorage.hpp"
#include "xsemantic.hpp"
#ifdef _MSC_VER
#define XTENSOR_CONSTEXPR_ENHANCED const
#define XTENSOR_CONSTEXPR_ENHANCED_STATIC const
#define XTENSOR_CONSTEXPR_RETURN
#else
#define XTENSOR_CONSTEXPR_ENHANCED constexpr
#define XTENSOR_CONSTEXPR_RETURN constexpr
#define XTENSOR_CONSTEXPR_ENHANCED_STATIC constexpr static
#define XTENSOR_HAS_CONSTEXPR_ENHANCED
#endif
namespace xt
{
/**
* @class fixed_shape
* Fixed shape implementation for compile time defined arrays.
* @sa xshape
*/
template <std::size_t... X>
class fixed_shape
{
public:
using cast_type = const_array<std::size_t, sizeof...(X)>;
constexpr static std::size_t size()
{
return sizeof...(X);
}
constexpr fixed_shape()
{
}
constexpr operator cast_type() const
{
return {{X...}};
}
};
}
namespace std
{
template <class T, size_t N>
class tuple_size<xt::const_array<T, N>> :
public integral_constant<size_t, N>
{
};
}
namespace xtl
{
namespace detail
{
template <class T, std::size_t N>
struct sequence_builder<xt::const_array<T, N>>
{
using sequence_type = xt::const_array<T, N>;
using value_type = typename sequence_type::value_type;
using size_type = typename sequence_type::size_type;
inline static sequence_type make(size_type /*size*/, value_type /*v*/)
{
return sequence_type();
}
};
}
}
namespace xt
{
/**********************
* xfixed declaration *
**********************/
template <class ET, class S, layout_type L, class Tag>
class xfixed_container;
namespace detail
{
/**************************************************************************************
The following is something we can currently only dream about -- for when we drop
support for a lot of the old compilers (e.g. GCC 4.9, MSVC 2017 ;)
template <class T>
constexpr std::size_t calculate_stride(T& shape, std::size_t idx, layout_type L)
{
if (shape[idx] == 1)
{
return std::size_t(0);
}
std::size_t data_size = 1;
std::size_t stride = 1;
if (L == layout_type::row_major)
{
// because we have a integer sequence that counts
// from 0 to sz - 1, we need to "invert" idx here
idx = shape.size() - idx;
for (std::size_t i = idx; i != 0; --i)
{
stride = data_size;
data_size = stride * shape[i - 1];
}
}
else
{
for (std::size_t i = 0; i < idx + 1; ++i)
{
stride = data_size;
data_size = stride * shape[i];
}
}
return stride;
}
*****************************************************************************************/
template <std::size_t IDX, std::size_t... X>
struct at
{
constexpr static std::size_t arr[sizeof...(X)] = {X...};
constexpr static std::size_t value = arr[IDX];
};
template <layout_type L, std::size_t I, std::size_t... X>
struct calculate_stride;
template <std::size_t I, std::size_t Y, std::size_t... X>
struct calculate_stride<layout_type::column_major, I, Y, X...>
{
constexpr static std::size_t value = Y * calculate_stride<layout_type::column_major, I - 1, X...>::value;
};
template <std::size_t Y, std::size_t... X>
struct calculate_stride<layout_type::column_major, 0, Y, X...>
{
constexpr static std::size_t value = 1;
};
template <std::size_t I, std::size_t... X>
struct calculate_stride_row_major
{
constexpr static std::size_t value = at<sizeof...(X) - I, X...>::value * calculate_stride_row_major<I - 1, X...>::value;
};
template <std::size_t... X>
struct calculate_stride_row_major<0, X...>
{
constexpr static std::size_t value = 1;
};
template <std::size_t I, std::size_t... X>
struct calculate_stride<layout_type::row_major, I, X...>
{
constexpr static std::size_t value = calculate_stride_row_major<sizeof...(X) - I - 1, X...>::value;
};
template <layout_type L, std::size_t... X, std::size_t... I>
constexpr const_array<std::size_t, sizeof...(X)>
get_strides_impl(const xt::fixed_shape<X...>& /*shape*/, std::index_sequence<I...>)
{
static_assert((L == layout_type::row_major) || (L == layout_type::column_major),
"Layout not supported for fixed array");
return {{at<I, X...>::value == 1 ? 0 : calculate_stride<L, I, X...>::value...}};
}
template <class T, std::size_t... I>
constexpr T get_backstrides_impl(const T& shape, const T& strides, std::index_sequence<I...>)
{
return {{(strides[I] * (shape[I] - 1))...}};
}
template <std::size_t... X>
struct compute_size_impl;
template <std::size_t Y, std::size_t... X>
struct compute_size_impl<Y, X...>
{
constexpr static std::size_t value = Y * compute_size_impl<X...>::value;
};
template <std::size_t X>
struct compute_size_impl<X>
{
constexpr static std::size_t value = X;
};
template <>
struct compute_size_impl<>
{
// support for 0D xtensor fixed (empty shape = xshape<>)
constexpr static std::size_t value = 1;
};
// TODO unify with constexpr compute_size when dropping MSVC 2015
template <class T>
struct fixed_compute_size;
template <std::size_t... X>
struct fixed_compute_size<xt::fixed_shape<X...>>
{
constexpr static std::size_t value = compute_size_impl<X...>::value;
};
template <class V, std::size_t... X>
struct get_init_type_impl;
template <class V, std::size_t Y>
struct get_init_type_impl<V, Y>
{
using type = V[Y];
};
template <class V>
struct get_init_type_impl<V>
{
using type = V[1];
};
template <class V, std::size_t Y, std::size_t... X>
struct get_init_type_impl<V, Y, X...>
{
using tmp_type = typename get_init_type_impl<V, X...>::type;
using type = tmp_type[Y];
};
}
template <layout_type L, std::size_t... X>
constexpr const_array<std::size_t, sizeof...(X)> get_strides(const fixed_shape<X...>& shape) noexcept
{
return detail::get_strides_impl<L>(shape, std::make_index_sequence<sizeof...(X)>{});
}
template <class T>
constexpr T get_backstrides(const T& shape, const T& strides) noexcept
{
return detail::get_backstrides_impl(shape, strides,
std::make_index_sequence<std::tuple_size<T>::value>{});
}
template <class V, class S>
struct get_init_type;
template <class V, std::size_t... X>
struct get_init_type<V, fixed_shape<X...>>
{
using type = typename detail::get_init_type_impl<V, X...>::type;
};
template <class V, class S>
using get_init_type_t = typename get_init_type<V, S>::type;
template <class ET, class S, layout_type L, class Tag>
struct xcontainer_inner_types<xfixed_container<ET, S, L, Tag>>
{
using inner_shape_type = typename S::cast_type;
using inner_strides_type = inner_shape_type;
using backstrides_type = inner_shape_type;
using inner_backstrides_type = backstrides_type;
using shape_type = std::array<typename inner_shape_type::value_type,
std::tuple_size<inner_shape_type>::value>;
using strides_type = shape_type;
using storage_type = aligned_array<ET, detail::fixed_compute_size<S>::value>;
using temporary_type = xfixed_container<ET, S, L, Tag>;
static constexpr layout_type layout = L;
};
template <class ET, class S, layout_type L, class Tag>
struct xiterable_inner_types<xfixed_container<ET, S, L, Tag>>
: xcontainer_iterable_types<xfixed_container<ET, S, L, Tag>>
{
};
/**
* @class xfixed_container
* @brief Dense multidimensional container with tensor semantic and fixed
* dimension.
*
* The xfixed_container class implements a dense multidimensional container
* with tensor semantic and fixed dimension
*
* @tparam ET The type of the elements.
* @tparam S The xshape template paramter of the container.
* @tparam L The layout_type of the tensor.
* @tparam Tag The expression tag.
* @sa xtensor_fixed
*/
template <class ET, class S, layout_type L, class Tag>
class xfixed_container : public xcontainer<xfixed_container<ET, S, L, Tag>>,
public xcontainer_semantic<xfixed_container<ET, S, L, Tag>>
{
public:
using self_type = xfixed_container<ET, S, L, Tag>;
using base_type = xcontainer<self_type>;
using semantic_base = xcontainer_semantic<self_type>;
using storage_type = typename base_type::storage_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 shape_type = typename base_type::shape_type;
using inner_shape_type = typename base_type::inner_shape_type;
using strides_type = typename base_type::strides_type;
using backstrides_type = typename base_type::backstrides_type;
using inner_backstrides_type = typename base_type::inner_backstrides_type;
using inner_strides_type = typename base_type::inner_strides_type;
using temporary_type = typename semantic_base::temporary_type;
using expression_tag = Tag;
constexpr static std::size_t N = std::tuple_size<shape_type>::value;
xfixed_container();
#if defined(_MSC_VER) && _MSC_VER < 1910
explicit xfixed_container(value_type v);
#else
[[deprecated]] explicit xfixed_container(value_type v);
#endif
explicit xfixed_container(const inner_shape_type& shape, layout_type l = L);
explicit xfixed_container(const inner_shape_type& shape, value_type v, layout_type l = L);
#ifndef X_OLD_CLANG
xfixed_container(const get_init_type_t<value_type, S>& init);
#else
// remove this enable_if when removing the other value_type constructor
template <class IX = std::integral_constant<std::size_t, N>, class EN = std::enable_if_t<IX::value != 0, int>>
xfixed_container(nested_initializer_list_t<value_type, N> t);
#endif
~xfixed_container() = default;
xfixed_container(const xfixed_container&) = default;
xfixed_container& operator=(const xfixed_container&) = default;
xfixed_container(xfixed_container&&) = default;
xfixed_container& operator=(xfixed_container&&) = default;
template <class E>
xfixed_container(const xexpression<E>& e);
template <class E>
xfixed_container& operator=(const xexpression<E>& e);
template <class ST = shape_type>
void resize(ST&& shape, bool force = false) const;
template <class ST = shape_type>
void reshape(ST&& shape, layout_type layout = L) const;
template <class ST>
bool broadcast_shape(ST& s, bool reuse_cache = false) const;
constexpr layout_type layout() const noexcept;
private:
storage_type m_storage;
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S();
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L>(S());
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides);
storage_type& storage_impl() noexcept;
const storage_type& storage_impl() const noexcept;
XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept;
XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept;
XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept;
friend class xcontainer<xfixed_container<ET, S, L, Tag>>;
};
#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
// Out of line definitions to prevent linker errors prior to C++17
template <class ET, class S, layout_type L, class Tag>
constexpr typename xfixed_container<ET, S, L, Tag>::inner_shape_type xfixed_container<ET, S, L, Tag>::m_shape;
template <class ET, class S, layout_type L, class Tag>
constexpr typename xfixed_container<ET, S, L, Tag>::inner_strides_type xfixed_container<ET, S, L, Tag>::m_strides;
template <class ET, class S, layout_type L, class Tag>
constexpr typename xfixed_container<ET, S, L, Tag>::inner_backstrides_type xfixed_container<ET, S, L, Tag>::m_backstrides;
#endif
/****************************************
* xfixed_container_adaptor declaration *
****************************************/
template <class EC, class S, layout_type L, class Tag>
class xfixed_adaptor;
template <class EC, class S, layout_type L, class Tag>
struct xcontainer_inner_types<xfixed_adaptor<EC, S, L, Tag>>
{
using storage_type = std::remove_reference_t<EC>;
using inner_shape_type = typename S::cast_type;
using inner_strides_type = inner_shape_type;
using backstrides_type = inner_shape_type;
using inner_backstrides_type = backstrides_type;
using shape_type = std::array<typename inner_shape_type::value_type,
std::tuple_size<inner_shape_type>::value>;
using strides_type = shape_type;
using temporary_type = xfixed_container<typename storage_type::value_type, S, L, Tag>;
static constexpr layout_type layout = L;
};
template <class EC, class S, layout_type L, class Tag>
struct xiterable_inner_types<xfixed_adaptor<EC, S, L, Tag>>
: xcontainer_iterable_types<xfixed_adaptor<EC, S, L, Tag>>
{
};
/**
* @class xfixed_adaptor
* @brief Dense multidimensional container adaptor with tensor semantic
* and fixed dimension.
*
* The xfixed_adaptor class implements a dense multidimensional
* container adaptor with tensor semantic and fixed dimension. It
* is used to provide a multidimensional container semantic and a
* tensor semantic to stl-like containers.
*
* @tparam EC The closure for the container type to adapt.
* @tparam S The xshape template parameter for the fixed shape of the adaptor
* @tparam L The layout_type of the adaptor.
* @tparam Tag The expression tag.
*/
template <class EC, class S, layout_type L, class Tag>
class xfixed_adaptor : public xcontainer<xfixed_adaptor<EC, S, L, Tag>>,
public xcontainer_semantic<xfixed_adaptor<EC, S, L, Tag>>
{
public:
using container_closure_type = EC;
using self_type = xfixed_adaptor<EC, S, L, Tag>;
using base_type = xcontainer<self_type>;
using semantic_base = xcontainer_semantic<self_type>;
using storage_type = typename base_type::storage_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 inner_shape_type = typename base_type::inner_shape_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;
xfixed_adaptor(storage_type&& data);
xfixed_adaptor(const storage_type& data);
template <class D>
xfixed_adaptor(D&& data);
~xfixed_adaptor() = default;
xfixed_adaptor(const xfixed_adaptor&) = default;
xfixed_adaptor& operator=(const xfixed_adaptor&);
xfixed_adaptor(xfixed_adaptor&&) = default;
xfixed_adaptor& operator=(xfixed_adaptor&&);
xfixed_adaptor& operator=(temporary_type&&);
template <class E>
xfixed_adaptor& operator=(const xexpression<E>& e);
constexpr layout_type layout() const noexcept;
private:
container_closure_type m_storage;
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_shape_type m_shape = S();
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_strides_type m_strides = get_strides<L>(S());
XTENSOR_CONSTEXPR_ENHANCED_STATIC inner_backstrides_type m_backstrides = get_backstrides(m_shape, m_strides);
storage_type& storage_impl() noexcept;
const storage_type& storage_impl() const noexcept;
XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape_impl() const noexcept;
XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides_impl() const noexcept;
XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides_impl() const noexcept;
friend class xcontainer<xfixed_adaptor<EC, S, L, Tag>>;
};
#ifdef XTENSOR_HAS_CONSTEXPR_ENHANCED
// Out of line definitions to prevent linker errors prior to C++17
template <class EC, class S, layout_type L, class Tag>
constexpr typename xfixed_adaptor<EC, S, L, Tag>::inner_shape_type xfixed_adaptor<EC, S, L, Tag>::m_shape;
template <class EC, class S, layout_type L, class Tag>
constexpr typename xfixed_adaptor<EC, S, L, Tag>::inner_strides_type xfixed_adaptor<EC, S, L, Tag>::m_strides;
template <class EC, class S, layout_type L, class Tag>
constexpr typename xfixed_adaptor<EC, S, L, Tag>::inner_backstrides_type xfixed_adaptor<EC, S, L, Tag>::m_backstrides;
#endif
/************************************
* xfixed_container implementation *
************************************/
/**
* @name Constructors
*/
//@{
/**
* Create an uninitialized xfixed_container according to the shape template parameter.
*/
template <class ET, class S, layout_type L, class Tag>
inline xfixed_container<ET, S, L, Tag>::xfixed_container()
{
}
/**
* Create an xfixed_container, and initialize with the value of v.
*
* @param v the fill value
*/
template <class ET, class S, layout_type L, class Tag>
inline xfixed_container<ET, S, L, Tag>::xfixed_container(value_type v)
{
std::fill(this->begin(), this->end(), v);
}
/**
* Create an uninitialized xfixed_container.
* Note this function is only provided for homogenity, and the shape & layout argument is
* disregarded (the template shape is always used).
*
* @param shape the shape of the xfixed_container (unused!)
* @param l the layout_type of the xfixed_container (unused!)
*/
template <class ET, class S, layout_type L, class Tag>
inline xfixed_container<ET, S, L, Tag>::xfixed_container(const inner_shape_type& /*shape*/, layout_type /*l*/)
{
}
/**
* Create an xfixed_container, and initialize with the value of v.
* Note, the shape argument to this function is only provided for homogenity,
* and the shape argument is disregarded (the template shape is always used).
*
* @param shape the shape of the xfixed_container (unused!)
* @param v the fill value
* @param l the layout_type of the xfixed_container (unused!)
*/
template <class ET, class S, layout_type L, class Tag>
inline xfixed_container<ET, S, L, Tag>::xfixed_container(const inner_shape_type& /*shape*/, value_type v, layout_type /*l*/)
: xfixed_container(v)
{
}
/**
* Allocates an xfixed_container with shape S with values from a C array.
* The type returned by get_init_type_t is raw C array ``value_type[X][Y][Z]`` for ``xt::xshape<X, Y, Z>``.
* C arrays can be initialized with the initializer list syntax, but the size is checked at compile
* time to prevent errors.
* Note: for clang < 3.8 this is an initializer_list and the size is not checked at compile-or runtime.
*/
#ifndef X_OLD_CLANG
template <class ET, class S, layout_type L, class Tag>
inline xfixed_container<ET, S, L, Tag>::xfixed_container(const get_init_type_t<value_type, S>& init)
{
std::copy(reinterpret_cast<const_pointer>(&init), reinterpret_cast<const_pointer>(&init) + this->size(),
this->template begin<layout_type::row_major>());
}
#else
template <class ET, class S, layout_type L, class Tag>
template <class IX, class EN>
inline xfixed_container<ET, S, L, Tag>::xfixed_container(nested_initializer_list_t<value_type, N> t)
{
L == layout_type::row_major ? nested_copy(m_storage.begin(), t) : nested_copy(this->template begin<layout_type::row_major>(), t);
}
#endif
//@}
/**
* @name Extended copy semantic
*/
//@{
/**
* The extended copy constructor.
*/
template <class ET, class S, layout_type L, class Tag>
template <class E>
inline xfixed_container<ET, S, L, Tag>::xfixed_container(const xexpression<E>& e)
{
semantic_base::assign(e);
}
/**
* The extended assignment operator.
*/
template <class ET, class S, layout_type L, class Tag>
template <class E>
inline auto xfixed_container<ET, S, L, Tag>::operator=(const xexpression<E>& e) -> self_type&
{
return semantic_base::operator=(e);
}
//@}
/**
* Note that the xfixed_container **cannot** be resized. Attempting to resize with a different
* size throws an assert in debug mode.
*/
template <class ET, class S, layout_type L, class Tag>
template <class ST>
inline void xfixed_container<ET, S, L, Tag>::resize(ST&& shape, bool) const
{
(void)(shape); // remove unused parameter warning if XTENSOR_ASSERT undefined
XTENSOR_ASSERT(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size());
}
/**
* Note that the xfixed_container **cannot** be reshaped to a shape different from ``S``.
*/
template <class ET, class S, layout_type L, class Tag>
template <class ST>
inline void xfixed_container<ET, S, L, Tag>::reshape(ST&& shape, layout_type layout) const
{
if (!(std::equal(shape.begin(), shape.end(), m_shape.begin()) && shape.size() == m_shape.size() && layout == L))
{
throw std::runtime_error("Trying to reshape xtensor_fixed with different shape or layout.");
}
}
template <class ET, class S, layout_type L, class Tag>
template <class ST>
inline bool xfixed_container<ET, S, L, Tag>::broadcast_shape(ST& shape, bool) const
{
return xt::broadcast_shape(m_shape, shape);
}
template <class ET, class S, layout_type L, class Tag>
constexpr layout_type xfixed_container<ET, S, L, Tag>::layout() const noexcept
{
return base_type::static_layout;
}
template <class ET, class S, layout_type L, class Tag>
inline auto xfixed_container<ET, S, L, Tag>::storage_impl() noexcept -> storage_type&
{
return m_storage;
}
template <class ET, class S, layout_type L, class Tag>
inline auto xfixed_container<ET, S, L, Tag>::storage_impl() const noexcept -> const storage_type&
{
return m_storage;
}
template <class ET, class S, layout_type L, class Tag>
XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, Tag>::shape_impl() const noexcept -> const inner_shape_type&
{
return m_shape;
}
template <class ET, class S, layout_type L, class Tag>
XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, Tag>::strides_impl() const noexcept -> const inner_strides_type&
{
return m_strides;
}
template <class ET, class S, layout_type L, class Tag>
XTENSOR_CONSTEXPR_RETURN auto xfixed_container<ET, S, L, Tag>::backstrides_impl() const noexcept -> const inner_backstrides_type&
{
return m_backstrides;
}
/*******************
* xfixed_adaptor *
*******************/
/**
* @name Constructors
*/
//@{
/**
* Constructs an xfixed_adaptor of the given stl-like container.
* @param data the container to adapt
*/
template <class EC, class S, layout_type L, class Tag>
inline xfixed_adaptor<EC, S, L, Tag>::xfixed_adaptor(storage_type&& data)
: base_type(), m_storage(std::move(data))
{
}
/**
* Constructs an xfixed_adaptor of the given stl-like container.
* @param data the container to adapt
*/
template <class EC, class S, layout_type L, class Tag>
inline xfixed_adaptor<EC, S, L, Tag>::xfixed_adaptor(const storage_type& data)
: base_type(), m_storage(data)
{
}
/**
* Constructs an xfixed_adaptor of the given stl-like container,
* with the specified shape and layout_type.
* @param data the container to adapt
*/
template <class EC, class S, layout_type L, class Tag>
template <class D>
inline xfixed_adaptor<EC, S, L, Tag>::xfixed_adaptor(D&& data)
: base_type(), m_storage(std::forward<D>(data))
{
}
//@}
template <class EC, class S, layout_type L, class Tag>
inline auto xfixed_adaptor<EC, S, L, Tag>::operator=(const xfixed_adaptor& rhs) -> self_type&
{
base_type::operator=(rhs);
m_storage = rhs.m_storage;
return *this;
}
template <class EC, class S, layout_type L, class Tag>
inline auto xfixed_adaptor<EC, S, L, Tag>::operator=(xfixed_adaptor&& rhs) -> self_type&
{
base_type::operator=(std::move(rhs));
m_storage = rhs.m_storage;
return *this;
}
template <class EC, class S, layout_type L, class Tag>
inline auto xfixed_adaptor<EC, S, L, Tag>::operator=(temporary_type&& rhs) -> self_type&
{
m_storage = xtl::forward_sequence<storage_type>(std::move(rhs.storage()));
return *this;
}
/**
* @name Extended copy semantic
*/
//@{
/**
* The extended assignment operator.
*/
template <class EC, class S, layout_type L, class Tag>
template <class E>
inline auto xfixed_adaptor<EC, S, L, Tag>::operator=(const xexpression<E>& e) -> self_type&
{
return semantic_base::operator=(e);
}
//@}
template <class EC, class S, layout_type L, class Tag>
inline auto xfixed_adaptor<EC, S, L, Tag>::storage_impl() noexcept -> storage_type&
{
return m_storage;
}
template <class EC, class S, layout_type L, class Tag>
inline auto xfixed_adaptor<EC, S, L, Tag>::storage_impl() const noexcept -> const storage_type&
{
return m_storage;
}
template <class EC, class S, layout_type L, class Tag>
constexpr layout_type xfixed_adaptor<EC, S, L, Tag>::layout() const noexcept
{
return base_type::static_layout;
}
template <class EC, class S, layout_type L, class Tag>
XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, Tag>::shape_impl() const noexcept -> const inner_shape_type&
{
return m_shape;
}
template <class EC, class S, layout_type L, class Tag>
XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, Tag>::strides_impl() const noexcept -> const inner_strides_type&
{
return m_strides;
}
template <class EC, class S, layout_type L, class Tag>
XTENSOR_CONSTEXPR_RETURN auto xfixed_adaptor<EC, S, L, Tag>::backstrides_impl() const noexcept -> const inner_backstrides_type&
{
return m_backstrides;
}
}
#undef XTENSOR_CONSTEXPR_ENHANCED
#undef XTENSOR_CONSTEXPR_RETURN
#undef XTENSOR_CONSTEXPR_ENHANCED_STATIC
#undef XTENSOR_HAS_CONSTEXPR_ENHANCED
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,401 @@
/***************************************************************************
* 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_GENERATOR_HPP
#define XTENSOR_GENERATOR_HPP
#include <algorithm>
#include <cstddef>
#include <numeric>
#include <tuple>
#include <type_traits>
#include <utility>
#include <xtl/xsequence.hpp>
#include "xexpression.hpp"
#include "xiterable.hpp"
#include "xstrides.hpp"
#include "xutils.hpp"
namespace xt
{
/**************
* xgenerator *
**************/
template <class F, class R, class S>
class xgenerator;
template <class C, class R, class S>
struct xiterable_inner_types<xgenerator<C, R, S>>
{
using inner_shape_type = S;
using const_stepper = xindexed_stepper<xgenerator<C, R, S>, true>;
using stepper = const_stepper;
};
/**
* @class xgenerator
* @brief Multidimensional function operating on indices.
*
* The xgenerator class implements a multidimensional function,
* generating a value from the supplied indices.
*
* @tparam F the function type
* @tparam R the return type of the function
* @tparam S the shape type of the generator
*/
template <class F, class R, class S>
class xgenerator : public xexpression<xgenerator<F, R, S>>,
public xconst_iterable<xgenerator<F, R, S>>
{
public:
using self_type = xgenerator<F, R, S>;
using functor_type = typename std::remove_reference<F>::type;
using value_type = R;
using reference = value_type;
using const_reference = value_type;
using pointer = value_type*;
using const_pointer = const value_type*;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using iterable_base = xconst_iterable<self_type>;
using inner_shape_type = typename iterable_base::inner_shape_type;
using shape_type = inner_shape_type;
using strides_type = S;
using stepper = typename iterable_base::stepper;
using const_stepper = typename iterable_base::const_stepper;
static constexpr layout_type static_layout = layout_type::any;
static constexpr bool contiguous_layout = false;
template <class Func>
xgenerator(Func&& f, const S& shape) noexcept;
size_type size() const noexcept;
size_type dimension() const noexcept;
const inner_shape_type& shape() const noexcept;
layout_type layout() const noexcept;
template <class... Args>
const_reference operator()(Args... args) const;
template <class... Args>
const_reference at(Args... args) const;
template <class... Args>
const_reference unchecked(Args... args) const;
template <class OS>
disable_integral_t<OS, const_reference> operator[](const OS& index) const;
template <class I>
const_reference operator[](std::initializer_list<I> index) const;
const_reference operator[](size_type i) const;
template <class It>
const_reference element(It first, It last) const;
template <class O>
bool broadcast_shape(O& shape, bool reuse_cache = false) const;
template <class O>
bool is_trivial_broadcast(const O& /*strides*/) const noexcept;
template <class O>
const_stepper stepper_begin(const O& shape) const noexcept;
template <class O>
const_stepper stepper_end(const O& shape, layout_type) const noexcept;
template <class E, class FE = F, class = std::enable_if_t<has_assign_to<E, FE>::value>>
void assign_to(xexpression<E>& e) const noexcept;
private:
template <std::size_t dim>
void adapt_index() const;
template <std::size_t dim, class I, class... Args>
void adapt_index(I& arg, Args&... args) const;
functor_type m_f;
inner_shape_type m_shape;
};
/*****************************
* xgenerator implementation *
*****************************/
/**
* @name Constructor
*/
//@{
/**
* Constructs an xgenerator applying the specified function over the
* given shape.
* @param f the function to apply
* @param shape the shape of the xgenerator
*/
template <class F, class R, class S>
template <class Func>
inline xgenerator<F, R, S>::xgenerator(Func&& f, const S& shape) noexcept
: m_f(std::forward<Func>(f)), m_shape(shape)
{
}
//@}
/**
* @name Size and shape
*/
//@{
/**
* Returns the size of the expression.
*/
template <class F, class R, class S>
inline auto xgenerator<F, R, S>::size() const noexcept -> size_type
{
return compute_size(shape());
}
/**
* Returns the number of dimensions of the function.
*/
template <class F, class R, class S>
inline auto xgenerator<F, R, S>::dimension() const noexcept -> size_type
{
return m_shape.size();
}
/**
* Returns the shape of the xgenerator.
*/
template <class F, class R, class S>
inline auto xgenerator<F, R, S>::shape() const noexcept -> const inner_shape_type&
{
return m_shape;
}
template <class F, class R, class S>
inline layout_type xgenerator<F, R, S>::layout() const noexcept
{
return static_layout;
}
//@}
/**
* @name Data
*/
/**
* Returns the evaluated element at the specified position in the function.
* @param args a list of indices specifying the position in the function. Indices
* must be unsigned integers, the number of indices should be equal or greater than
* the number of dimensions of the function.
*/
template <class F, class R, class S>
template <class... Args>
inline auto xgenerator<F, R, S>::operator()(Args... args) const -> const_reference
{
XTENSOR_TRY(check_index(shape(), args...));
adapt_index<0>(args...);
return m_f(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 <class F, class R, class S>
template <class... Args>
inline auto xgenerator<F, R, S>::at(Args... args) const -> const_reference
{
check_access(shape(), 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
* must be unsigned integers, the number of indices must be equal to the number of
* dimensions of the expression, else the behavior is undefined.
*
* @warning This method is meant for performance, for expressions with a dynamic
* number of dimensions (i.e. not known at compile time). Since it may have
* undefined behavior (see parameters), operator() should be prefered whenever
* it is possible.
* @warning This method is NOT compatible with broadcasting, meaning the following
* code has undefined behavior:
* \code{.cpp}
* xt::xarray<double> a = {{0, 1}, {2, 3}};
* xt::xarray<double> b = {0, 1};
* auto fd = a + b;
* double res = fd.uncheked(0, 1);
* \endcode
*/
template <class F, class R, class S>
template <class... Args>
inline auto xgenerator<F, R, S>::unchecked(Args... args) const -> const_reference
{
return m_f(args...);
}
template <class F, class R, class S>
template <class OS>
inline auto xgenerator<F, R, S>::operator[](const OS& index) const
-> disable_integral_t<OS, const_reference>
{
return element(index.cbegin(), index.cend());
}
template <class F, class R, class S>
template <class I>
inline auto xgenerator<F, R, S>::operator[](std::initializer_list<I> index) const
-> const_reference
{
return element(index.begin(), index.end());
}
template <class F, class R, class S>
inline auto xgenerator<F, R, S>::operator[](size_type i) const -> const_reference
{
return operator()(i);
}
/**
* Returns a constant reference to the element at the specified position in the function.
* @param first iterator starting the sequence of indices
* @param last iterator ending the sequence of indices
* The number of indices in the sequence should be equal to or greater
* than the number of dimensions of the container.
*/
template <class F, class R, class S>
template <class It>
inline auto xgenerator<F, R, S>::element(It first, It last) const -> const_reference
{
using bounded_iterator = xbounded_iterator<It, typename shape_type::const_iterator>;
XTENSOR_TRY(check_element_index(shape(), first, last));
return m_f.element(bounded_iterator(first, shape().cbegin()), bounded_iterator(last, shape().cend()));
}
//@}
/**
* @name Broadcasting
*/
//@{
/**
* Broadcast the shape of the function to the specified parameter.
* @param shape the result shape
* @param reuse_cache parameter for internal optimization
* @return a boolean indicating whether the broadcasting is trivial
*/
template <class F, class R, class S>
template <class O>
inline bool xgenerator<F, R, S>::broadcast_shape(O& shape, bool) const
{
return xt::broadcast_shape(m_shape, shape);
}
/**
* 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
*/
template <class F, class R, class S>
template <class O>
inline bool xgenerator<F, R, S>::is_trivial_broadcast(const O& /*strides*/) const noexcept
{
return false;
}
//@}
template <class F, class R, class S>
template <class O>
inline auto xgenerator<F, R, S>::stepper_begin(const O& shape) const noexcept -> const_stepper
{
size_type offset = shape.size() - dimension();
return const_stepper(this, offset);
}
template <class F, class R, class S>
template <class O>
inline auto xgenerator<F, R, S>::stepper_end(const O& shape, layout_type) const noexcept -> const_stepper
{
size_type offset = shape.size() - dimension();
return const_stepper(this, offset, true);
}
template <class F, class R, class S>
template <class E, class, class>
inline void xgenerator<F, R, S>::assign_to(xexpression<E>& e) const noexcept
{
e.derived_cast().resize(m_shape);
m_f.assign_to(e);
}
template <class F, class R, class S>
template <std::size_t dim>
inline void xgenerator<F, R, S>::adapt_index() const
{
}
template <class F, class R, class S>
template <std::size_t dim, class I, class... Args>
inline void xgenerator<F, R, S>::adapt_index(I& arg, Args&... args) const
{
using value_type = typename decltype(m_shape)::value_type;
if (sizeof...(Args) + 1 > m_shape.size())
{
adapt_index<dim>(args...);
}
else
{
if (static_cast<value_type>(arg) >= m_shape[dim] && m_shape[dim] == 1)
{
arg = 0;
}
adapt_index<dim + 1>(args...);
}
}
namespace detail
{
#ifdef X_OLD_CLANG
template <class Functor, class I>
inline auto make_xgenerator(Functor&& f, std::initializer_list<I> shape) noexcept
{
using shape_type = std::vector<std::size_t>;
using type = xgenerator<Functor, typename Functor::value_type, shape_type>;
return type(std::forward<Functor>(f), xtl::forward_sequence<shape_type>(shape));
}
#else
template <class Functor, class I, std::size_t L>
inline auto make_xgenerator(Functor&& f, const I (&shape)[L]) noexcept
{
using shape_type = std::array<std::size_t, L>;
using type = xgenerator<Functor, typename Functor::value_type, shape_type>;
return type(std::forward<Functor>(f), xtl::forward_sequence<shape_type>(shape));
}
#endif
template <class Functor, class S>
inline auto make_xgenerator(Functor&& f, S&& shape) noexcept
{
using type = xgenerator<Functor, typename Functor::value_type, std::decay_t<S>>;
return type(std::forward<Functor>(f), std::forward<S>(shape));
}
}
}
#endif

View file

@ -0,0 +1,745 @@
/***************************************************************************
* 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_INDEX_VIEW_HPP
#define XTENSOR_INDEX_VIEW_HPP
#include <algorithm>
#include <cstddef>
#include <tuple>
#include <type_traits>
#include <utility>
#include "xexpression.hpp"
#include "xiterable.hpp"
#include "xstrides.hpp"
#include "xutils.hpp"
namespace xt
{
template <class CT, class I>
class xindex_view;
template <class CT, class I>
struct xcontainer_inner_types<xindex_view<CT, I>>
{
using xexpression_type = std::decay_t<CT>;
using temporary_type = xarray<typename xexpression_type::value_type, xexpression_type::static_layout>;
};
template <class CT, class I>
struct xiterable_inner_types<xindex_view<CT, I>>
{
using inner_shape_type = std::array<std::size_t, 1>;
using const_stepper = xindexed_stepper<xindex_view<CT, I>, true>;
using stepper = xindexed_stepper<xindex_view<CT, I>, false>;
};
/***************
* xindex_view *
***************/
/**
* @class xindex_view
* @brief View of an xexpression from vector of indices.
*
* The xindex_view class implements a flat (1D) view into a multidimensional
* xexpression yielding the values at the indices of the index array.
* xindex_view is not meant to be used directly, but only with the \ref index_view
* and \ref filter helper functions.
*
* @tparam CT the closure type of the \ref xexpression type underlying this view
* @tparam I the index array type of the view
*
* @sa index_view, filter
*/
template <class CT, class I>
class xindex_view : public xview_semantic<xindex_view<CT, I>>,
public xiterable<xindex_view<CT, I>>
{
public:
using self_type = xindex_view<CT, I>;
using xexpression_type = std::decay_t<CT>;
using semantic_base = xview_semantic<self_type>;
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 const_pointer = typename xexpression_type::const_pointer;
using size_type = typename xexpression_type::size_type;
using difference_type = typename xexpression_type::difference_type;
using iterable_base = xiterable<self_type>;
using inner_shape_type = typename iterable_base::inner_shape_type;
using shape_type = inner_shape_type;
using strides_type = shape_type;
using indices_type = I;
using stepper = typename iterable_base::stepper;
using const_stepper = typename iterable_base::const_stepper;
using temporary_type = typename xcontainer_inner_types<self_type>::temporary_type;
using base_index_type = xindex_type_t<shape_type>;
static constexpr layout_type static_layout = layout_type::dynamic;
static constexpr bool contiguous_layout = false;
template <class CTA, class I2>
xindex_view(CTA&& e, I2&& indices) noexcept;
template <class E>
self_type& operator=(const xexpression<E>& e);
template <class E>
disable_xexpression<E, self_type>& operator=(const E& e);
size_type size() const noexcept;
size_type dimension() const noexcept;
const inner_shape_type& shape() const noexcept;
layout_type layout() const noexcept;
template <class T>
void fill(const T& value);
reference operator()(size_type idx = size_type(0));
template <class... Args>
reference operator()(size_type idx0, size_type idx1, Args... args);
reference unchecked(size_type idx);
template <class S>
disable_integral_t<S, reference> operator[](const S& index);
template <class OI>
reference operator[](std::initializer_list<OI> index);
reference operator[](size_type i);
template <class It>
reference element(It first, It last);
const_reference operator()(size_type idx = size_type(0)) const;
template <class... Args>
const_reference operator()(size_type idx0, size_type idx1, Args... args) const;
const_reference unchecked(size_type idx) const;
template <class S>
disable_integral_t<S, const_reference> operator[](const S& index) const;
template <class OI>
const_reference operator[](std::initializer_list<OI> index) const;
const_reference operator[](size_type i) const;
template <class It>
const_reference element(It first, It last) const;
template <class O>
bool broadcast_shape(O& shape, bool reuse_cache = false) const;
template <class O>
bool is_trivial_broadcast(const O& /*strides*/) const noexcept;
template <class ST>
stepper stepper_begin(const ST& shape);
template <class ST>
stepper stepper_end(const ST& shape, layout_type);
template <class ST>
const_stepper stepper_begin(const ST& shape) const;
template <class ST>
const_stepper stepper_end(const ST& shape, layout_type) const;
private:
CT m_e;
const indices_type m_indices;
const inner_shape_type m_shape;
void assign_temporary_impl(temporary_type&& tmp);
friend class xview_semantic<xindex_view<CT, I>>;
};
/***************
* xfiltration *
***************/
/**
* @class xfiltration
* @brief Filter of a xexpression for fast scalar assign.
*
* The xfiltration class implements a lazy filtration of a multidimentional
* \ref xexpression, optimized for scalar and computed scalar assignments.
* Actually, the \ref xfiltration class IS NOT an \ref xexpression and the
* scalar and computed scalar assignments are the only method it provides.
* The filtering condition is not evaluated until the filtration is assigned.
*
* xfiltration is not meant to be used directly, but only with the \ref filtration
* helper function.
*
* @tparam ECT the closure type of the \ref xexpression type underlying this filtration
* @tparam CCR the closure type of the filtering \ref xexpression type
*
* @sa filtration
*/
template <class ECT, class CCT>
class xfiltration
{
public:
using self_type = xfiltration<ECT, CCT>;
using xexpression_type = std::decay_t<ECT>;
using const_reference = typename xexpression_type::const_reference;
template <class ECTA, class CCTA>
xfiltration(ECTA&& e, CCTA&& condition);
template <class E>
disable_xexpression<E, self_type&> operator=(const E&);
template <class E>
disable_xexpression<E, self_type&> operator+=(const E&);
template <class E>
disable_xexpression<E, self_type&> operator-=(const E&);
template <class E>
disable_xexpression<E, self_type&> operator*=(const E&);
template <class E>
disable_xexpression<E, self_type&> operator/=(const E&);
template <class E>
disable_xexpression<E, self_type&> operator%=(const E&);
private:
template <class F>
self_type& apply(F&& func);
ECT m_e;
CCT m_condition;
};
/******************************
* xindex_view implementation *
******************************/
/**
* @name Constructor
*/
//@{
/**
* Constructs an xindex_view, selecting the indices specified by \a indices.
* The resulting xexpression has a 1D shape with a length of n for n indices.
*
* @param e the underlying xexpression for this view
* @param indices the indices to select
*/
template <class CT, class I>
template <class CTA, class I2>
inline xindex_view<CT, I>::xindex_view(CTA&& e, I2&& indices) noexcept
: m_e(std::forward<CTA>(e)), m_indices(std::forward<I2>(indices)), m_shape({ m_indices.size() })
{
}
//@}
/**
* @name Extended copy semantic
*/
//@{
/**
* The extended assignment operator.
*/
template <class CT, class I>
template <class E>
inline auto xindex_view<CT, I>::operator=(const xexpression<E>& e) -> self_type&
{
return semantic_base::operator=(e);
}
//@}
template <class CT, class I>
template <class E>
inline auto xindex_view<CT, I>::operator=(const E& e) -> disable_xexpression<E, self_type>&
{
std::fill(this->begin(), this->end(), e);
return *this;
}
template <class CT, class I>
inline void xindex_view<CT, I>::assign_temporary_impl(temporary_type&& tmp)
{
std::copy(tmp.cbegin(), tmp.cend(), this->begin());
}
/**
* @name Size and shape
*/
//@{
/**
* Returns the size of the xindex_view.
*/
template <class CT, class I>
inline auto xindex_view<CT, I>::size() const noexcept -> size_type
{
return compute_size(shape());
}
/**
* Returns the number of dimensions of the xindex_view.
*/
template <class CT, class I>
inline auto xindex_view<CT, I>::dimension() const noexcept -> size_type
{
return 1;
}
/**
* Returns the shape of the xindex_view.
*/
template <class CT, class I>
inline auto xindex_view<CT, I>::shape() const noexcept -> const inner_shape_type&
{
return m_shape;
}
template <class CT, class I>
inline layout_type xindex_view<CT, I>::layout() const noexcept
{
return static_layout;
}
//@}
/**
* @name Data
*/
//@{
/**
* Fills the view with the given value.
* @param value the value to fill the view with.
*/
template <class CT, class I>
template <class T>
inline void xindex_view<CT, I>::fill(const T& value)
{
std::fill(this->storage_begin(), this->storage_end(), value);
}
/**
* Returns a reference to the element at the specified position in the xindex_view.
* @param idx index specifying the position in the index_view. More indices may be provided,
* only the last one will be used.
*/
template <class CT, class I>
inline auto xindex_view<CT, I>::operator()(size_type idx) -> reference
{
return m_e[m_indices[idx]];
}
template <class CT, class I>
template <class... Args>
inline auto xindex_view<CT, I>::operator()(size_type, size_type idx1, Args... args) -> reference
{
return this->operator()(idx1, static_cast<size_type>(args)...);
}
/**
* Returns a reference to the element at the specified position in the xindex_view.
* @param idx index specifying the position in the index_view.
*/
template <class CT, class I>
inline auto xindex_view<CT, I>::unchecked(size_type idx) -> reference
{
return this->operator()(idx);
}
/**
* Returns a constant reference to the element at the specified position in the xindex_view.
* @param idx index specifying the position in the index_view. More indices may be provided,
* only the last one will be used.
*/
template <class CT, class I>
inline auto xindex_view<CT, I>::operator()(size_type idx) const -> const_reference
{
return m_e[m_indices[idx]];
}
template <class CT, class I>
template <class... Args>
inline auto xindex_view<CT, I>::operator()(size_type, size_type idx1, Args... args) const -> const_reference
{
return this->operator()(idx1, args...);
}
/**
* Returns a constant reference to the element at the specified position in the xindex_view.
* @param idx index specifying the position in the index_view.
*/
template <class CT, class I>
inline auto xindex_view<CT, I>::unchecked(size_type idx) const -> const_reference
{
return this->operator()(idx);
}
/**
* 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 <class CT, class I>
template <class S>
inline auto xindex_view<CT, I>::operator[](const S& index)
-> disable_integral_t<S, reference>
{
return m_e[m_indices[index[0]]];
}
template <class CT, class I>
template <class OI>
inline auto xindex_view<CT, I>::operator[](std::initializer_list<OI> index)
-> reference
{
return m_e[m_indices[*(index.begin())]];
}
template <class CT, class I>
inline auto xindex_view<CT, I>::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 <class CT, class I>
template <class S>
inline auto xindex_view<CT, I>::operator[](const S& index) const
-> disable_integral_t<S, const_reference>
{
return m_e[m_indices[index[0]]];
}
template <class CT, class I>
template <class OI>
inline auto xindex_view<CT, I>::operator[](std::initializer_list<OI> index) const
-> const_reference
{
return m_e[m_indices[*(index.begin())]];
}
template <class CT, class I>
inline auto xindex_view<CT, I>::operator[](size_type i) const -> const_reference
{
return operator()(i);
}
/**
* Returns a reference to the element at the specified position in the xindex_view.
* @param first iterator starting the sequence of indices
* The number of indices in the sequence should be equal to or greater 1.
*/
template <class CT, class I>
template <class It>
inline auto xindex_view<CT, I>::element(It first, It /*last*/) -> reference
{
return m_e[m_indices[(*first)]];
}
/**
* Returns a reference to the element at the specified position in the xindex_view.
* @param first iterator starting the sequence of indices
* The number of indices in the sequence should be equal to or greater 1.
*/
template <class CT, class I>
template <class It>
inline auto xindex_view<CT, I>::element(It first, It /*last*/) const -> const_reference
{
return m_e[m_indices[(*first)]];
}
//@}
/**
* @name Broadcasting
*/
//@{
/**
* Broadcast the shape of the xindex_view to the specified parameter.
* @param shape the result shape
* @param reuse_cache parameter for internal optimization
* @return a boolean indicating whether the broadcasting is trivial
*/
template <class CT, class I>
template <class O>
inline bool xindex_view<CT, I>::broadcast_shape(O& shape, bool) const
{
return xt::broadcast_shape(m_shape, shape);
}
/**
* 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
*/
template <class CT, class I>
template <class O>
inline bool xindex_view<CT, I>::is_trivial_broadcast(const O& /*strides*/) const noexcept
{
return false;
}
//@}
/***************
* stepper api *
***************/
template <class CT, class I>
template <class ST>
inline auto xindex_view<CT, I>::stepper_begin(const ST& shape) -> stepper
{
size_type offset = shape.size() - dimension();
return stepper(this, offset);
}
template <class CT, class I>
template <class ST>
inline auto xindex_view<CT, I>::stepper_end(const ST& shape, layout_type) -> stepper
{
size_type offset = shape.size() - dimension();
return stepper(this, offset, true);
}
template <class CT, class I>
template <class ST>
inline auto xindex_view<CT, I>::stepper_begin(const ST& shape) const -> const_stepper
{
size_type offset = shape.size() - dimension();
return const_stepper(this, offset);
}
template <class CT, class I>
template <class ST>
inline auto xindex_view<CT, I>::stepper_end(const ST& shape, layout_type) const -> const_stepper
{
size_type offset = shape.size() - dimension();
return const_stepper(this, offset, true);
}
/******************************
* xfiltration implementation *
******************************/
/**
* @name Constructor
*/
//@{
/**
* Constructs a xfiltration on the given expression \c e, selecting
* the elements matching the specified \c condition.
*
* @param e the \ref xexpression to filter.
* @param condition the filtering \ref xexpression to apply.
*/
template <class ECT, class CCT>
template <class ECTA, class CCTA>
inline xfiltration<ECT, CCT>::xfiltration(ECTA&& e, CCTA&& condition)
: m_e(std::forward<ECTA>(e)), m_condition(std::forward<CCTA>(condition))
{
}
//@}
/**
* @name Extended copy semantic
*/
//@{
/**
* Assigns the scalar \c e to \c *this.
* @param e the scalar to assign.
* @return a reference to \ *this.
*/
template <class ECT, class CCT>
template <class E>
inline auto xfiltration<ECT, CCT>::operator=(const E& e) -> disable_xexpression<E, self_type&>
{
return apply([this, &e](const_reference v, bool cond) { return cond ? e : v; });
}
//@}
/**
* @name Computed assignement
*/
//@{
/**
* Adds the scalar \c e to \c *this.
* @param e the scalar to add.
* @return a reference to \c *this.
*/
template <class ECT, class CCT>
template <class E>
inline auto xfiltration<ECT, CCT>::operator+=(const E& e) -> disable_xexpression<E, self_type&>
{
return apply([this, &e](const_reference v, bool cond) { return cond ? v + e : v; });
}
/**
* Subtracts the scalar \c e from \c *this.
* @param e the scalar to subtract.
* @return a reference to \c *this.
*/
template <class ECT, class CCT>
template <class E>
inline auto xfiltration<ECT, CCT>::operator-=(const E& e) -> disable_xexpression<E, self_type&>
{
return apply([this, &e](const_reference v, bool cond) { return cond ? v - e : v; });
}
/**
* Multiplies \c *this with the scalar \c e.
* @param e the scalar involved in the operation.
* @return a reference to \c *this.
*/
template <class ECT, class CCT>
template <class E>
inline auto xfiltration<ECT, CCT>::operator*=(const E& e) -> disable_xexpression<E, self_type&>
{
return apply([this, &e](const_reference v, bool cond) { return cond ? v * e : v; });
}
/**
* Divides \c *this by the scalar \c e.
* @param e the scalar involved in the operation.
* @return a reference to \c *this.
*/
template <class ECT, class CCT>
template <class E>
inline auto xfiltration<ECT, CCT>::operator/=(const E& e) -> disable_xexpression<E, self_type&>
{
return apply([this, &e](const_reference v, bool cond) { return cond ? v / e : v; });
}
/**
* Computes the remainder of \c *this after division by the scalar \c e.
* @param e the scalar involved in the operation.
* @return a reference to \c *this.
*/
template <class ECT, class CCT>
template <class E>
inline auto xfiltration<ECT, CCT>::operator%=(const E& e) -> disable_xexpression<E, self_type&>
{
return apply([this, &e](const_reference v, bool cond) { return cond ? v % e : v; });
}
template <class ECT, class CCT>
template <class F>
inline auto xfiltration<ECT, CCT>::apply(F&& func) -> self_type&
{
std::transform(m_e.cbegin(), m_e.cend(), m_condition.cbegin(), m_e.begin(), func);
return *this;
}
/**
* @brief creates an indexview from a container of indices.
*
* Returns a 1D view with the elements at \a indices selected.
*
* @param e the underlying xexpression
* @param indices the indices to select
*
* \code{.cpp}
* xarray<double> a = {{1,5,3}, {4,5,6}};
* b = index_view(a, {{0, 0}, {1, 0}, {1, 1}});
* std::cout << b << std::endl; // {1, 4, 5}
* b += 100;
* std::cout << a << std::endl; // {{101, 5, 3}, {104, 105, 6}}
* \endcode
*/
template <class E, class I>
inline auto index_view(E&& e, I&& indices) noexcept
{
using view_type = xindex_view<xclosure_t<E>, std::decay_t<I>>;
return view_type(std::forward<E>(e), std::forward<I>(indices));
}
#ifdef X_OLD_CLANG
template <class E, class I>
inline auto index_view(E&& e, std::initializer_list<std::initializer_list<I>> indices) noexcept
{
std::vector<xindex> idx;
for (auto it = indices.begin(); it != indices.end(); ++it)
{
idx.emplace_back(xindex(it->begin(), it->end()));
}
using view_type = xindex_view<xclosure_t<E>, std::vector<xindex>>;
return view_type(std::forward<E>(e), std::move(idx));
}
#else
template <class E, std::size_t L>
inline auto index_view(E&& e, const xindex (&indices)[L]) noexcept
{
using view_type = xindex_view<xclosure_t<E>, std::array<xindex, L>>;
return view_type(std::forward<E>(e), to_array(indices));
}
#endif
/**
* @brief creates a view into \a e filtered by \a condition.
*
* Returns a 1D view with the elements selected where \a condition evaluates to \em true.
* This is equivalent to \verbatim{index_view(e, where(condition));}\endverbatim
* The returned view is not optimal if you just want to assign a scalar to the filtered
* elements. In that case, you should consider using the \ref filtration function
* instead.
*
* @param e the underlying xexpression
* @param condition xexpression with shape of \a e which selects indices
*
* \code{.cpp}
* xarray<double> a = {{1,5,3}, {4,5,6}};
* b = filter(a, a >= 5);
* std::cout << b << std::endl; // {5, 5, 6}
* \endcode
*
* \sa filtration
*/
template <class E, class O>
inline auto filter(E&& e, O&& condition) noexcept
{
auto indices = where(std::forward<O>(condition));
using view_type = xindex_view<xclosure_t<E>, decltype(indices)>;
return view_type(std::forward<E>(e), std::move(indices));
}
/**
* @brief creates a filtration of \c e filtered by \a condition.
*
* Returns a lazy filtration optimized for scalar assignment.
* Actually, scalar assignment and computed scalar assignments
* are the only available methods of the filtration, the filtration
* IS NOT an \ref xexpression.
*
* @param e the \ref xexpression to filter
* @param condition the filtering \ref xexpression
*
* \code{.cpp}
* xarray<double> a = {{1,5,3}, {4,5,6}};
* filtration(a, a >= 5) += 2;
* std::cout << a << std::endl; // {{1, 7, 3}, {4, 7, 8}}
* \endcode
*/
template <class E, class C>
inline auto filtration(E&& e, C&& condition) noexcept
{
using filtration_type = xfiltration<xclosure_t<E>, xclosure_t<C>>;
return filtration_type(std::forward<E>(e), std::forward<C>(condition));
}
}
#endif

139
vendor/xtensor/include/xtensor/xinfo.hpp vendored Normal file
View file

@ -0,0 +1,139 @@
/***************************************************************************
* 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_INFO_HPP
#define XTENSOR_INFO_HPP
#include <string>
#ifndef _MSC_VER
# if __cplusplus < 201103
# define CONSTEXPR11_TN
# define CONSTEXPR14_TN
# define NOEXCEPT_TN
# elif __cplusplus < 201402
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN
# define NOEXCEPT_TN noexcept
# else
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN constexpr
# define NOEXCEPT_TN noexcept
# endif
#else // _MSC_VER
# if _MSC_VER < 1900
# define CONSTEXPR11_TN
# define CONSTEXPR14_TN
# define NOEXCEPT_TN
# elif _MSC_VER < 2000
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN
# define NOEXCEPT_TN noexcept
# else
# define CONSTEXPR11_TN constexpr
# define CONSTEXPR14_TN constexpr
# define NOEXCEPT_TN noexcept
# endif
#endif
namespace xt
{
// see http://stackoverflow.com/a/20170989
struct static_string
{
template <std::size_t N>
explicit CONSTEXPR11_TN static_string(const char (&a)[N]) NOEXCEPT_TN
: data(a), size(N - 1)
{
}
CONSTEXPR11_TN static_string(const char* a, const std::size_t sz) NOEXCEPT_TN
: data(a), size(sz)
{
}
const char* const data;
const std::size_t size;
};
template <class T>
CONSTEXPR14_TN static_string type_name()
{
#ifdef __clang__
static_string p(__PRETTY_FUNCTION__);
return static_string(p.data + 39, p.size - 39 - 1);
#elif defined(__GNUC__)
static_string p(__PRETTY_FUNCTION__);
#if __cplusplus < 201402
return static_string(p.data + 36, p.size - 36 - 1);
#else
return static_string(p.data + 54, p.size - 54 - 1);
#endif
#elif defined(_MSC_VER)
static const static_string p(__FUNCSIG__);
return static_string(p.data + 47, p.size - 47 - 7);
#endif
}
template <class T>
std::string type_to_string()
{
static_string static_name = type_name<T>();
return std::string(static_name.data, static_name.size);
}
template <class T>
std::string info(const T& t)
{
std::string s;
s += "\nValue type: " + type_to_string<typename T::value_type>();
s += "\nLayout: ";
if (t.layout() == layout_type::row_major)
{
s += "row_major";
}
else if (t.layout() == layout_type::column_major)
{
s += "column_major";
}
else if (t.layout() == layout_type::dynamic)
{
s += "dynamic";
}
else
{
s += "any";
}
s += "\nShape: (";
bool first = true;
for (const auto& el : t.shape())
{
if (!first)
{
s += ", ";
}
first = false;
s += std::to_string(el);
}
s += ")\nStrides: (";
first = true;
for (const auto& el : t.strides())
{
if (!first)
{
s += ", ";
}
first = false;
s += std::to_string(el);
}
s += ")\nSize: " + std::to_string(t.size()) + "\n";
return s;
}
}
#endif

634
vendor/xtensor/include/xtensor/xio.hpp vendored Normal file
View file

@ -0,0 +1,634 @@
/***************************************************************************
* 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_IO_HPP
#define XTENSOR_IO_HPP
#include <complex>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <sstream>
#include <string>
#include "xexpression.hpp"
#include "xmath.hpp"
#include "xstrided_view.hpp"
namespace xt
{
template <class E>
inline std::ostream& operator<<(std::ostream& out, const xexpression<E>& e);
namespace print_options
{
struct print_options_impl
{
std::size_t edgeitems = 3;
std::size_t line_width = 75;
std::size_t threshold = 1000;
std::streamsize precision = -1; // default precision
};
inline print_options_impl& print_options()
{
static print_options_impl po;
return po;
}
/**
* @brief Sets the line width. After \a line_width chars,
* a new line is added.
*
* @param line_width The line width
*/
inline void set_line_width(std::size_t line_width)
{
print_options().line_width = line_width;
}
/**
* @brief Sets the threshold after which summarization is triggered (default: 1000).
*
* @param threshold The number of elements in the xexpression that triggers
* summarization in the output
*/
inline void set_threshold(std::size_t threshold)
{
print_options().threshold = threshold;
}
/**
* @brief Sets the number of edge items. If the summarization is
* triggered, this value defines how many items of each dimension
* are printed.
*
* @param edgeitems The number of edge items
*/
inline void set_edgeitems(std::size_t edgeitems)
{
print_options().edgeitems = edgeitems;
}
/**
* @brief Sets the precision for printing floating point values.
*
* @param precision The number of digits for floating point output
*/
inline void set_precision(std::streamsize precision)
{
print_options().precision = precision;
}
}
/**************************************
* xexpression ostream implementation *
**************************************/
namespace detail
{
template <class E, class F>
std::ostream& xoutput(std::ostream& out, const E& e,
xstrided_slice_vector& slices, F& printer, std::size_t blanks,
std::streamsize element_width, std::size_t edgeitems, std::size_t line_width)
{
using size_type = typename E::size_type;
const auto view = xt::strided_view(e, slices);
if (view.dimension() == 0)
{
printer.print_next(out);
}
else
{
std::string indents(blanks, ' ');
size_type i = 0;
size_type elems_on_line = 0;
size_type ewp2 = static_cast<size_type>(element_width) + size_type(2);
size_type line_lim = static_cast<size_type>(std::floor(line_width / ewp2));
out << '{';
for (; i != size_type(view.shape()[0] - 1); ++i)
{
if (edgeitems && size_type(view.shape()[0]) > (edgeitems * 2) && i == edgeitems)
{
out << "..., ";
if (view.dimension() > 1)
{
elems_on_line = 0;
out << std::endl
<< indents;
}
i = size_type(view.shape()[0]) - edgeitems;
}
if (view.dimension() == 1 && line_lim != 0 && elems_on_line >= line_lim)
{
out << std::endl
<< indents;
elems_on_line = 0;
}
slices.push_back(static_cast<int>(i));
xoutput(out, e, slices, printer, blanks + 1, element_width, edgeitems, line_width) << ',';
slices.pop_back();
elems_on_line++;
if (view.dimension() == 1)
{
out << ' ';
}
else
{
out << std::endl
<< indents;
}
}
if (view.dimension() == 1 && line_lim != 0 && elems_on_line >= line_lim)
{
out << std::endl
<< indents;
}
slices.push_back(static_cast<int>(i));
xoutput(out, e, slices, printer, blanks + 1, element_width, edgeitems, line_width) << '}';
slices.pop_back();
}
return out;
}
template <class F, class E>
static void recurser_run(F& fn, const E& e, xstrided_slice_vector& slices, std::size_t lim = 0)
{
using size_type = typename E::size_type;
const auto view = strided_view(e, slices);
if (view.dimension() == 0)
{
fn.update(view());
}
else
{
size_type i = 0;
for (; i != static_cast<size_type>(view.shape()[0] - 1); ++i)
{
if (lim && size_type(view.shape()[0]) > (lim * 2) && i == lim)
{
i = static_cast<size_type>(view.shape()[0]) - lim;
}
slices.push_back(static_cast<int>(i));
recurser_run(fn, e, slices, lim);
slices.pop_back();
}
slices.push_back(static_cast<int>(i));
recurser_run(fn, e, slices, lim);
slices.pop_back();
}
}
template <class T, class E = void>
struct printer;
template <class T>
struct printer<T, std::enable_if_t<std::is_floating_point<typename T::value_type>::value>>
{
using value_type = std::decay_t<typename T::value_type>;
using cache_type = std::vector<value_type>;
using cache_iterator = typename cache_type::const_iterator;
explicit printer(std::streamsize precision)
: m_precision(precision)
{
}
void init()
{
m_precision = m_required_precision < m_precision ? m_required_precision : m_precision;
m_it = m_cache.cbegin();
if (m_scientific)
{
// 3 = sign, number and dot and 4 = "e+00"
m_width = m_precision + 7;
if (m_large_exponent)
{
// = e+000 (additional number)
m_width += 1;
}
}
else
{
std::streamsize decimals = 1; // print a leading 0
if (std::floor(m_max) != 0)
{
decimals += std::streamsize(std::log10(std::floor(m_max)));
}
// 2 => sign and dot
m_width = 2 + decimals + m_precision;
}
if (!m_required_precision)
{
--m_width;
}
}
std::ostream& print_next(std::ostream& out)
{
if (!m_scientific)
{
std::stringstream buf;
buf.width(m_width);
buf << std::fixed;
buf.precision(m_precision);
buf << (*m_it);
if (!m_required_precision)
{
buf << '.';
}
std::string res = buf.str();
auto sit = res.rbegin();
while (*sit == '0')
{
*sit = ' ';
++sit;
}
out << res;
}
else
{
if (!m_large_exponent)
{
out << std::scientific;
out.width(m_width);
out << (*m_it);
}
else
{
std::stringstream buf;
buf.width(m_width);
buf << std::scientific;
buf.precision(m_precision);
buf << (*m_it);
std::string res = buf.str();
if (res[res.size() - 4] == 'e')
{
res.erase(0, 1);
res.insert(res.size() - 2, "0");
}
out << res;
}
}
++m_it;
return out;
}
void update(const value_type& val)
{
if (val != 0 && !std::isinf(val) && !std::isnan(val))
{
if (!m_scientific || !m_large_exponent)
{
int exponent = 1 + int(std::log10(math::abs(val)));
if (exponent <= -5 || exponent > 7)
{
m_scientific = true;
m_required_precision = m_precision;
if (exponent <= -100 || exponent >= 100)
{
m_large_exponent = true;
}
}
}
if (math::abs(val) > m_max)
{
m_max = math::abs(val);
}
if (m_required_precision < m_precision)
{
while (std::floor(val * std::pow(10, m_required_precision)) != val * std::pow(10, m_required_precision))
{
m_required_precision++;
}
}
}
m_cache.push_back(val);
}
std::streamsize width()
{
return m_width;
}
private:
bool m_large_exponent = false;
bool m_scientific = false;
std::streamsize m_width = 9;
std::streamsize m_precision;
std::streamsize m_required_precision = 0;
value_type m_max = 0;
cache_type m_cache;
cache_iterator m_it;
};
template <class T>
struct printer<T, std::enable_if_t<std::is_integral<typename T::value_type>::value && !std::is_same<typename T::value_type, bool>::value>>
{
using value_type = std::decay_t<typename T::value_type>;
using cache_type = std::vector<value_type>;
using cache_iterator = typename cache_type::const_iterator;
explicit printer(std::streamsize)
{
}
void init()
{
m_it = m_cache.cbegin();
m_width = 1 + std::streamsize(std::log10(m_max)) + m_sign;
}
std::ostream& print_next(std::ostream& out)
{
// + enables printing of chars etc. as numbers
// TODO should chars be printed as numbers?
out.width(m_width);
out << +(*m_it);
++m_it;
return out;
}
void update(const value_type& val)
{
if (math::abs(val) > m_max)
{
m_max = math::abs(val);
}
if (std::is_signed<value_type>::value && val < 0)
{
m_sign = true;
}
m_cache.push_back(val);
}
std::streamsize width()
{
return m_width;
}
private:
std::streamsize m_width;
bool m_sign = false;
value_type m_max = 0;
cache_type m_cache;
cache_iterator m_it;
};
template <class T>
struct printer<T, std::enable_if_t<std::is_same<typename T::value_type, bool>::value>>
{
using value_type = bool;
using cache_type = std::vector<bool>;
using cache_iterator = typename cache_type::const_iterator;
explicit printer(std::streamsize)
{
}
void init()
{
m_it = m_cache.cbegin();
}
std::ostream& print_next(std::ostream& out)
{
if (*m_it)
{
out << " true";
}
else
{
out << "false";
}
// TODO: the following std::setw(5) isn't working correctly on OSX.
//out << std::boolalpha << std::setw(m_width) << (*m_it);
++m_it;
return out;
}
void update(const value_type& val)
{
m_cache.push_back(val);
}
std::streamsize width()
{
return m_width;
}
private:
std::streamsize m_width = 5;
cache_type m_cache;
cache_iterator m_it;
};
template <class T>
struct printer<T, std::enable_if_t<xtl::is_complex<typename T::value_type>::value>>
{
using value_type = std::decay_t<typename T::value_type>;
using cache_type = std::vector<bool>;
using cache_iterator = typename cache_type::const_iterator;
explicit printer(std::streamsize precision)
: real_printer(precision), imag_printer(precision)
{
}
void init()
{
real_printer.init();
imag_printer.init();
m_it = m_signs.cbegin();
}
std::ostream& print_next(std::ostream& out)
{
real_printer.print_next(out);
if (*m_it)
{
out << "-";
}
else
{
out << "+";
}
std::stringstream buf;
imag_printer.print_next(buf);
std::string s = buf.str();
if (s[0] == ' ')
{
s.erase(0, 1); // erase space for +/-
}
// insert j at end of number
std::size_t idx = s.find_last_not_of(" ");
s.insert(idx + 1, "i");
out << s;
++m_it;
return out;
}
void update(const value_type& val)
{
real_printer.update(val.real());
imag_printer.update(std::abs(val.imag()));
m_signs.push_back(std::signbit(val.imag()));
}
std::streamsize width()
{
return real_printer.width() + imag_printer.width() + 2;
}
private:
printer<value_type> real_printer, imag_printer;
cache_type m_signs;
cache_iterator m_it;
};
template <class T>
struct printer<T, std::enable_if_t<!std::is_fundamental<typename T::value_type>::value && !xtl::is_complex<typename T::value_type>::value>>
{
using value_type = std::decay_t<typename T::value_type>;
using cache_type = std::vector<std::string>;
using cache_iterator = typename cache_type::const_iterator;
explicit printer(std::streamsize)
{
}
void init()
{
m_it = m_cache.cbegin();
if (m_width > 20)
{
m_width = 0;
}
}
std::ostream& print_next(std::ostream& out)
{
out.width(m_width);
out << *m_it;
++m_it;
return out;
}
void update(const value_type& val)
{
std::stringstream buf;
buf << val;
std::string s = buf.str();
if (int(s.size()) > m_width)
{
m_width = std::streamsize(s.size());
}
m_cache.push_back(s);
}
std::streamsize width()
{
return m_width;
}
private:
std::streamsize m_width = 0;
cache_type m_cache;
cache_iterator m_it;
};
template <class E>
struct custom_formatter
{
using value_type = std::decay_t<typename E::value_type>;
template <class F>
custom_formatter(F&& func)
: m_func(func)
{
}
std::string operator()(const value_type& val) const
{
return m_func(val);
}
private:
std::function<std::string(const value_type&)> m_func;
};
}
template <class E, class F>
std::ostream& pretty_print(const xexpression<E>& e, F&& func, std::ostream& out = std::cout)
{
xfunction<detail::custom_formatter<E>, std::string, const_xclosure_t<E>> print_fun(detail::custom_formatter<E>(std::forward<F>(func)), e);
return pretty_print(print_fun, out);
}
template <class E>
std::ostream& pretty_print(const xexpression<E>& e, std::ostream& out = std::cout)
{
const E& d = e.derived_cast();
size_t lim = 0;
std::size_t sz = compute_size(d.shape());
if (sz > print_options::print_options().threshold)
{
lim = print_options::print_options().edgeitems;
}
if (sz == 0)
{
out << "{}";
return out;
}
auto temp_precision = out.precision();
auto precision = temp_precision;
if (print_options::print_options().precision != -1)
{
out.precision(print_options::print_options().precision);
precision = print_options::print_options().precision;
}
detail::printer<E> p(precision);
xstrided_slice_vector sv;
detail::recurser_run(p, d, sv, lim);
p.init();
sv.clear();
xoutput(out, d, sv, p, 1, p.width(), lim, print_options::print_options().line_width);
out.precision(temp_precision); // restore precision
return out;
}
template <class E>
inline std::ostream& operator<<(std::ostream& out, const xexpression<E>& e)
{
return pretty_print(e, out);
}
}
#endif

View file

@ -0,0 +1,824 @@
/***************************************************************************
* 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_ITERABLE_HPP
#define XTENSOR_ITERABLE_HPP
#include "xiterator.hpp"
namespace xt
{
/*******************
* xconst_iterable *
*******************/
template <class D>
struct xiterable_inner_types;
#define DL XTENSOR_DEFAULT_LAYOUT
/**
* @class xconst_iterable
* @brief Base class for multidimensional iterable constant expressions
*
* The xconst_iterable class defines the interface for multidimensional
* constant expressions that can be iterated.
*
* @tparam D The derived type, i.e. the inheriting class for which xconst_iterable
* provides the interface.
*/
template <class D>
class xconst_iterable
{
public:
using derived_type = D;
using iterable_types = xiterable_inner_types<D>;
using inner_shape_type = typename iterable_types::inner_shape_type;
using stepper = typename iterable_types::stepper;
using const_stepper = typename iterable_types::const_stepper;
template <layout_type L>
using layout_iterator = xiterator<stepper, inner_shape_type*, L>;
template <layout_type L>
using const_layout_iterator = xiterator<const_stepper, inner_shape_type*, L>;
template <layout_type L>
using reverse_layout_iterator = std::reverse_iterator<layout_iterator<L>>;
template <layout_type L>
using const_reverse_layout_iterator = std::reverse_iterator<const_layout_iterator<L>>;
template <class S, layout_type L>
using broadcast_iterator = xiterator<stepper, S, L>;
template <class S, layout_type L>
using const_broadcast_iterator = xiterator<const_stepper, S, L>;
template <class S, layout_type L>
using reverse_broadcast_iterator = std::reverse_iterator<broadcast_iterator<S, L>>;
template <class S, layout_type L>
using const_reverse_broadcast_iterator = std::reverse_iterator<const_broadcast_iterator<S, L>>;
using storage_iterator = layout_iterator<DL>;
using const_storage_iterator = const_layout_iterator<DL>;
using reverse_storage_iterator = reverse_layout_iterator<DL>;
using const_reverse_storage_iterator = const_reverse_layout_iterator<DL>;
using iterator = layout_iterator<DL>;
using const_iterator = const_layout_iterator<DL>;
using reverse_iterator = reverse_layout_iterator<DL>;
using const_reverse_iterator = const_reverse_layout_iterator<DL>;
template <layout_type L = DL>
const_layout_iterator<L> begin() const noexcept;
template <layout_type L = DL>
const_layout_iterator<L> end() const noexcept;
template <layout_type L = DL>
const_layout_iterator<L> cbegin() const noexcept;
template <layout_type L = DL>
const_layout_iterator<L> cend() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> rbegin() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> rend() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> crbegin() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> crend() const noexcept;
template <class S, layout_type L = DL>
const_broadcast_iterator<S, L> begin(const S& shape) const noexcept;
template <class S, layout_type L = DL>
const_broadcast_iterator<S, L> end(const S& shape) const noexcept;
template <class S, layout_type L = DL>
const_broadcast_iterator<S, L> cbegin(const S& shape) const noexcept;
template <class S, layout_type L = DL>
const_broadcast_iterator<S, L> cend(const S& shape) const noexcept;
template <class S, layout_type L = DL>
const_reverse_broadcast_iterator<S, L> rbegin(const S& shape) const noexcept;
template <class S, layout_type L = DL>
const_reverse_broadcast_iterator<S, L> rend(const S& shape) const noexcept;
template <class S, layout_type L = DL>
const_reverse_broadcast_iterator<S, L> crbegin(const S& shape) const noexcept;
template <class S, layout_type L = DL>
const_reverse_broadcast_iterator<S, L> crend(const S& shape) const noexcept;
template <layout_type L = DL>
const_layout_iterator<L> storage_begin() const noexcept;
template <layout_type L = DL>
const_layout_iterator<L> storage_end() const noexcept;
template <layout_type L = DL>
const_layout_iterator<L> storage_cbegin() const noexcept;
template <layout_type L = DL>
const_layout_iterator<L> storage_cend() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> storage_rbegin() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> storage_rend() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> storage_crbegin() const noexcept;
template <layout_type L = DL>
const_reverse_layout_iterator<L> storage_crend() const noexcept;
protected:
const inner_shape_type& get_shape() const;
private:
template <layout_type L>
const_layout_iterator<L> get_cbegin(bool end_index) const noexcept;
template <layout_type L>
const_layout_iterator<L> get_cend(bool end_index) const noexcept;
template <class S, layout_type L>
const_broadcast_iterator<S, L> get_cbegin(const S& shape, bool end_index) const noexcept;
template <class S, layout_type L>
const_broadcast_iterator<S, L> get_cend(const S& shape, bool end_index) const noexcept;
template <class S>
const_stepper get_stepper_begin(const S& shape) const noexcept;
template <class S>
const_stepper get_stepper_end(const S& shape, layout_type l) const noexcept;
const derived_type& derived_cast() const;
};
/*************
* xiterable *
*************/
/**
* @class xiterable
* @brief Base class for multidimensional iterable expressions
*
* The xiterable class defines the interface for multidimensional
* expressions that can be iterated.
*
* @tparam D The derived type, i.e. the inheriting class for which xiterable
* provides the interface.
*/
template <class D>
class xiterable : public xconst_iterable<D>
{
public:
using derived_type = D;
using base_type = xconst_iterable<D>;
using inner_shape_type = typename base_type::inner_shape_type;
using stepper = typename base_type::stepper;
using const_stepper = typename base_type::const_stepper;
template <layout_type L>
using layout_iterator = typename base_type::template layout_iterator<L>;
template <layout_type L>
using const_layout_iterator = typename base_type::template const_layout_iterator<L>;
template <layout_type L>
using reverse_layout_iterator = typename base_type::template reverse_layout_iterator<L>;
template <layout_type L>
using const_reverse_layout_iterator = typename base_type::template const_reverse_layout_iterator<L>;
template <class S, layout_type L>
using broadcast_iterator = typename base_type::template broadcast_iterator<S, L>;
template <class S, layout_type L>
using const_broadcast_iterator = typename base_type::template const_broadcast_iterator<S, L>;
template <class S, layout_type L>
using reverse_broadcast_iterator = typename base_type::template reverse_broadcast_iterator<S, L>;
template <class S, layout_type L>
using const_reverse_broadcast_iterator = typename base_type::template const_reverse_broadcast_iterator<S, L>;
using iterator = typename base_type::iterator;
using const_iterator = typename base_type::const_iterator;
using reverse_iterator = typename base_type::reverse_iterator;
using const_reverse_iterator = typename base_type::const_reverse_iterator;
using base_type::begin;
using base_type::end;
using base_type::rbegin;
using base_type::rend;
using base_type::storage_begin;
using base_type::storage_end;
template <layout_type L = DL>
layout_iterator<L> begin() noexcept;
template <layout_type L = DL>
layout_iterator<L> end() noexcept;
template <layout_type L = DL>
reverse_layout_iterator<L> rbegin() noexcept;
template <layout_type L = DL>
reverse_layout_iterator<L> rend() noexcept;
template <class S, layout_type L = DL>
broadcast_iterator<S, L> begin(const S& shape) noexcept;
template <class S, layout_type L = DL>
broadcast_iterator<S, L> end(const S& shape) noexcept;
template <class S, layout_type L = DL>
reverse_broadcast_iterator<S, L> rbegin(const S& shape) noexcept;
template <class S, layout_type L = DL>
reverse_broadcast_iterator<S, L> rend(const S& shape) noexcept;
template <layout_type L = DL>
layout_iterator<L> storage_begin() noexcept;
template <layout_type L = DL>
layout_iterator<L> storage_end() noexcept;
template <layout_type L = DL>
reverse_layout_iterator<L> storage_rbegin() noexcept;
template <layout_type L = DL>
reverse_layout_iterator<L> storage_rend() noexcept;
private:
template <layout_type L>
layout_iterator<L> get_begin(bool end_index) noexcept;
template <layout_type L>
layout_iterator<L> get_end(bool end_index) noexcept;
template <class S, layout_type L>
broadcast_iterator<S, L> get_begin(const S& shape, bool end_index) noexcept;
template <class S, layout_type L>
broadcast_iterator<S, L> get_end(const S& shape, bool end_index) noexcept;
template <class S>
stepper get_stepper_begin(const S& shape) noexcept;
template <class S>
stepper get_stepper_end(const S& shape, layout_type l) noexcept;
template <class S>
const_stepper get_stepper_begin(const S& shape) const noexcept;
template <class S>
const_stepper get_stepper_end(const S& shape, layout_type l) const noexcept;
derived_type& derived_cast();
};
#undef DL
/**********************************
* xconst_iterable implementation *
**********************************/
/**
* @name Constant iterators
*/
//@{
/**
* Returns a constant iterator to the first element of the expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::begin() const noexcept -> const_layout_iterator<L>
{
return this->template cbegin<L>();
}
/**
* Returns a constant iterator to the element following the last element
* of the expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::end() const noexcept -> const_layout_iterator<L>
{
return this->template cend<L>();
}
/**
* Returns a constant iterator to the first element of the expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::cbegin() const noexcept -> const_layout_iterator<L>
{
return this->template get_cbegin<L>(false);
}
/**
* Returns a constant iterator to the element following the last element
* of the expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::cend() const noexcept -> const_layout_iterator<L>
{
return this->template get_cend<L>(true);
}
//@}
/**
* @name Constant reverse iterators
*/
//@{
/**
* Returns a constant iterator to the first element of the reversed expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::rbegin() const noexcept -> const_reverse_layout_iterator<L>
{
return this->template crbegin<L>();
}
/**
* Returns a constant iterator to the element following the last element
* of the reversed expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::rend() const noexcept -> const_reverse_layout_iterator<L>
{
return this->template crend<L>();
}
/**
* Returns a constant iterator to the first element of the reversed expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::crbegin() const noexcept -> const_reverse_layout_iterator<L>
{
return const_reverse_layout_iterator<L>(get_cend<L>(true));
}
/**
* Returns a constant iterator to the element following the last element
* of the reversed expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::crend() const noexcept -> const_reverse_layout_iterator<L>
{
return const_reverse_layout_iterator<L>(get_cbegin<L>(false));
}
//@}
/**
* @name Constant broadcast iterators
*/
//@{
/**
* Returns a constant iterator to the first element of the expression. The
* iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::begin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
{
return cbegin<S, L>(shape);
}
/**
* Returns a constant iterator to the element following the last element of the
* expression. The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::end(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
{
return cend<S, L>(shape);
}
/**
* Returns a constant iterator to the first element of the expression. The
* iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::cbegin(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
{
return get_cbegin<S, L>(shape, false);
}
/**
* Returns a constant iterator to the element following the last element of the
* expression. The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::cend(const S& shape) const noexcept -> const_broadcast_iterator<S, L>
{
return get_cend<S, L>(shape, true);
}
//@}
/**
* @name Constant reverse broadcast iterators
*/
//@{
/**
* Returns a constant iterator to the first element of the reversed expression.
* The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
{
return crbegin<S, L>(shape);
}
/**
* Returns a constant iterator to the element following the last element of the
* reversed expression. The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
{
return crend<S, L>(shape);
}
/**
* Returns a constant iterator to the first element of the reversed expression.
* The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
{
return const_reverse_broadcast_iterator<S, L>(get_cend<S, L>(shape, true));
}
/**
* Returns a constant iterator to the element following the last element of the
* reversed expression. The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator<S, L>
{
return const_reverse_broadcast_iterator<S, L>(get_cbegin<S, L>(shape, false));
}
//@}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_begin() const noexcept -> const_layout_iterator<L>
{
return this->template cbegin<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_end() const noexcept -> const_layout_iterator<L>
{
return this->template cend<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_cbegin() const noexcept -> const_layout_iterator<L>
{
return this->template cbegin<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_cend() const noexcept -> const_layout_iterator<L>
{
return this->template cend<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_rbegin() const noexcept -> const_reverse_layout_iterator<L>
{
return this->template crbegin<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_rend() const noexcept -> const_reverse_layout_iterator<L>
{
return this->template crend<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_crbegin() const noexcept -> const_reverse_layout_iterator<L>
{
return this->template crbegin<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::storage_crend() const noexcept -> const_reverse_layout_iterator<L>
{
return this->template crend<L>();
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::get_cbegin(bool end_index) const noexcept -> const_layout_iterator<L>
{
return const_layout_iterator<L>(get_stepper_begin(get_shape()), &get_shape(), end_index);
}
template <class D>
template <layout_type L>
inline auto xconst_iterable<D>::get_cend(bool end_index) const noexcept -> const_layout_iterator<L>
{
return const_layout_iterator<L>(get_stepper_end(get_shape(), L), &get_shape(), end_index);
}
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::get_cbegin(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator<S, L>
{
return const_broadcast_iterator<S, L>(get_stepper_begin(shape), shape, end_index);
}
template <class D>
template <class S, layout_type L>
inline auto xconst_iterable<D>::get_cend(const S& shape, bool end_index) const noexcept -> const_broadcast_iterator<S, L>
{
return const_broadcast_iterator<S, L>(get_stepper_end(shape, L), shape, end_index);
}
template <class D>
template <class S>
inline auto xconst_iterable<D>::get_stepper_begin(const S& shape) const noexcept -> const_stepper
{
return derived_cast().stepper_begin(shape);
}
template <class D>
template <class S>
inline auto xconst_iterable<D>::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper
{
return derived_cast().stepper_end(shape, l);
}
template <class D>
inline auto xconst_iterable<D>::get_shape() const -> const inner_shape_type&
{
return derived_cast().shape();
}
template <class D>
inline auto xconst_iterable<D>::derived_cast() const -> const derived_type&
{
return *static_cast<const derived_type*>(this);
}
/****************************
* xiterable implementation *
****************************/
/**
* @name Iterators
*/
//@{
/**
* Returns an iterator to the first element of the expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xiterable<D>::begin() noexcept -> layout_iterator<L>
{
return get_begin<L>(false);
}
/**
* Returns an iterator to the element following the last element
* of the expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xiterable<D>::end() noexcept -> layout_iterator<L>
{
return get_end<L>(true);
}
//@}
/**
* @name Reverse iterators
*/
//@{
/**
* Returns an iterator to the first element of the reversed expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xiterable<D>::rbegin() noexcept -> reverse_layout_iterator<L>
{
return reverse_layout_iterator<L>(get_end<L>(true));
}
/**
* Returns an iterator to the element following the last element
* of the reversed expression.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <layout_type L>
inline auto xiterable<D>::rend() noexcept -> reverse_layout_iterator<L>
{
return reverse_layout_iterator<L>(get_begin<L>(false));
}
//@}
/**
* @name Broadcast iterators
*/
//@{
/**
* Returns an iterator to the first element of the expression. The
* iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xiterable<D>::begin(const S& shape) noexcept -> broadcast_iterator<S, L>
{
return get_begin<S, L>(shape, false);
}
/**
* Returns an iterator to the element following the last element of the
* expression. The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xiterable<D>::end(const S& shape) noexcept -> broadcast_iterator<S, L>
{
return get_end<S, L>(shape, true);
}
//@}
/**
* @name Reverse broadcast iterators
*/
//@{
/**
* Returns an iterator to the first element of the reversed expression. The
* iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xiterable<D>::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
{
return reverse_broadcast_iterator<S, L>(get_end<S, L>(shape, true));
}
/**
* Returns an iterator to the element following the last element of the
* reversed expression. The iteration is broadcasted to the specified shape.
* @param shape the shape used for broadcasting
* @tparam S type of the \c shape parameter.
* @tparam L layout used for the traversal. Default value is \c XTENSOR_DEFAULT_LAYOUT.
*/
template <class D>
template <class S, layout_type L>
inline auto xiterable<D>::rend(const S& shape) noexcept -> reverse_broadcast_iterator<S, L>
{
return reverse_broadcast_iterator<S, L>(get_begin<S, L>(shape, false));
}
//@}
template <class D>
template <layout_type L>
inline auto xiterable<D>::storage_begin() noexcept -> layout_iterator<L>
{
return this->template begin<L>();
}
template <class D>
template <layout_type L>
inline auto xiterable<D>::storage_end() noexcept -> layout_iterator<L>
{
return this->template end<L>();
}
template <class D>
template <layout_type L>
inline auto xiterable<D>::storage_rbegin() noexcept -> reverse_layout_iterator<L>
{
return this->template rbegin<L>();
}
template <class D>
template <layout_type L>
inline auto xiterable<D>::storage_rend() noexcept -> reverse_layout_iterator<L>
{
return this->template rend<L>();
}
template <class D>
template <layout_type L>
inline auto xiterable<D>::get_begin(bool end_index) noexcept -> layout_iterator<L>
{
return layout_iterator<L>(get_stepper_begin(this->get_shape()), &(this->get_shape()), end_index);
}
template <class D>
template <layout_type L>
inline auto xiterable<D>::get_end(bool end_index) noexcept -> layout_iterator<L>
{
return layout_iterator<L>(get_stepper_end(this->get_shape(), L), &(this->get_shape()), end_index);
}
template <class D>
template <class S, layout_type L>
inline auto xiterable<D>::get_begin(const S& shape, bool end_index) noexcept -> broadcast_iterator<S, L>
{
return broadcast_iterator<S, L>(get_stepper_begin(shape), shape, end_index);
}
template <class D>
template <class S, layout_type L>
inline auto xiterable<D>::get_end(const S& shape, bool end_index) noexcept -> broadcast_iterator<S, L>
{
return broadcast_iterator<S, L>(get_stepper_end(shape, L), shape, end_index);
}
template <class D>
template <class S>
inline auto xiterable<D>::get_stepper_begin(const S& shape) noexcept -> stepper
{
return derived_cast().stepper_begin(shape);
}
template <class D>
template <class S>
inline auto xiterable<D>::get_stepper_end(const S& shape, layout_type l) noexcept -> stepper
{
return derived_cast().stepper_end(shape, l);
}
template <class D>
template <class S>
inline auto xiterable<D>::get_stepper_begin(const S& shape) const noexcept -> const_stepper
{
return derived_cast().stepper_begin(shape);
}
template <class D>
template <class S>
inline auto xiterable<D>::get_stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper
{
return derived_cast().stepper_end(shape, l);
}
template <class D>
inline auto xiterable<D>::derived_cast() -> derived_type&
{
return *static_cast<derived_type*>(this);
}
}
#endif

File diff suppressed because it is too large Load diff

183
vendor/xtensor/include/xtensor/xjson.hpp vendored Normal file
View file

@ -0,0 +1,183 @@
/***************************************************************************
* 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_JSON_HPP
#define XTENSOR_JSON_HPP
#include <cstddef>
#include <stdexcept>
#include <utility>
#include <nlohmann/json.hpp>
#include "xstrided_view.hpp"
namespace xt
{
/*************************************
* to_json and from_json declaration *
*************************************/
template <class E>
enable_xexpression<E> to_json(nlohmann::json&, const E&);
template <class E>
enable_xcontainer_semantics<E> from_json(const nlohmann::json&, E&);
/// @cond DOXYGEN_INCLUDE_SFINAE
template <class E>
enable_xview_semantics<E> from_json(const nlohmann::json&, E&);
/// @endcond
/****************************************
* to_json and from_json implementation *
****************************************/
namespace detail
{
template <class D>
void to_json_impl(nlohmann::json& j, const xexpression<D>& e, xstrided_slice_vector& slices)
{
const auto view = strided_view(e.derived_cast(), slices);
if (view.dimension() == 0)
{
j = view();
}
else
{
j = nlohmann::json::array();
using size_type = typename D::size_type;
size_type nrows = view.shape()[0];
for (size_type i = 0; i != nrows; ++i)
{
slices.push_back(i);
nlohmann::json k;
to_json_impl(k, e, slices);
j.push_back(std::move(k));
slices.pop_back();
}
}
}
template <class D>
inline void from_json_impl(const nlohmann::json& j, xexpression<D>& e, xstrided_slice_vector& slices)
{
auto view = strided_view(e.derived_cast(), slices);
if (view.dimension() == 0)
{
view() = j;
}
else
{
using size_type = typename D::size_type;
size_type nrows = view.shape()[0];
for (size_type i = 0; i != nrows; ++i)
{
slices.push_back(i);
const nlohmann::json& k = j[i];
from_json_impl(k, e, slices);
slices.pop_back();
}
}
}
inline unsigned int json_dimension(const nlohmann::json& j)
{
if (j.is_array() && j.size())
{
return 1 + json_dimension(j[0]);
}
else
{
return 0;
}
}
template <class S>
inline void json_shape(const nlohmann::json& j, S& s, std::size_t pos = 0)
{
if (j.is_array())
{
auto size = j.size();
s[pos] = size;
if (size)
{
json_shape(j[0], s, pos + 1);
}
}
}
}
/**
* @brief JSON serialization of an xtensor expression.
*
* The to_json method is used by the nlohmann_json package for automatic
* serialization of user-defined types. The method is picked up by
* argument-dependent lookup.
*
* @param j a JSON object
* @param e a const \ref xexpression
*/
template <class E>
inline enable_xexpression<E> to_json(nlohmann::json& j, const E& e)
{
auto sv = xstrided_slice_vector();
detail::to_json_impl(j, e, sv);
}
/**
* @brief JSON deserialization of a xtensor expression with a container or
* a view semantics.
*
* The from_json method is used by the nlohmann_json library for automatic
* serialization of user-defined types. The method is picked up by
* argument-dependent lookup.
*
* Note: for converting a JSON object to a value, nlohmann_json requiress
* the value type to be default constructible, which is typically not the
* case for expressions with a view semantics. In this case, from_json can
* be called directly.
*
* @param j a const JSON object
* @param e an \ref xexpression
*/
template <class E>
inline enable_xcontainer_semantics<E> from_json(const nlohmann::json& j, E& e)
{
auto dimension = detail::json_dimension(j);
auto s = xtl::make_sequence<typename E::shape_type>(dimension);
detail::json_shape(j, s);
// In the case of a container, we resize the container.
e.resize(s);
auto sv = xstrided_slice_vector();
detail::from_json_impl(j, e, sv);
}
/// @cond DOXYGEN_INCLUDE_SFINAE
template <class E>
inline enable_xview_semantics<E> from_json(const nlohmann::json& j, E& e)
{
typename E::shape_type s;
detail::json_shape(j, s);
// In the case of a view, we check the size of the container.
if (!std::equal(s.cbegin(), s.cend(), e.shape().cbegin()))
{
throw std::runtime_error("Shape mismatch when deserializing JSON to view");
}
auto sv = xstrided_slice_vector();
detail::from_json_impl(j, e, sv);
}
/// @endcond
}
#endif

View file

@ -0,0 +1,93 @@
/***************************************************************************
* 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_LAYOUT_HPP
#define XTENSOR_LAYOUT_HPP
#include "xtensor_config.hpp"
namespace xt
{
/*! layout_type enum for xcontainer based xexpressions */
enum class layout_type
{
/*! dynamic layout_type: you can resize to row major, column major, or use custom strides */
dynamic = 0x00,
/*! layout_type compatible with all others */
any = 0xFF,
/*! row major layout_type */
row_major = 0x01,
/*! column major layout_type */
column_major = 0x02
};
/**
* Implementation of the following logical table:
*
* @verbatim
| d | a | r | c |
--+---+---+---+---+
d | d | d | d | d |
a | d | a | r | c |
r | d | r | r | d |
c | d | c | d | c |
d = dynamic, a = any, r = row_major, c = column_major.
@endverbatim
* Using bitmasks to avoid nested if-else statements.
*
* @param args the input layouts.
* @return the output layout, computed with the previous logical table.
*/
template <class... Args>
constexpr layout_type compute_layout(Args... args) noexcept;
constexpr layout_type default_assignable_layout(layout_type l) noexcept;
/******************
* Implementation *
******************/
namespace detail
{
constexpr layout_type compute_layout_impl() noexcept
{
return layout_type::any;
}
constexpr layout_type compute_layout_impl(layout_type l) noexcept
{
return l;
}
constexpr layout_type compute_layout_impl(layout_type lhs, layout_type rhs) noexcept
{
using type = std::underlying_type_t<layout_type>;
return layout_type(static_cast<type>(lhs) & static_cast<type>(rhs));
}
template <class... Args>
constexpr layout_type compute_layout_impl(layout_type lhs, Args... args) noexcept
{
return compute_layout_impl(lhs, compute_layout_impl(args...));
}
}
template <class... Args>
constexpr layout_type compute_layout(Args... args) noexcept
{
return detail::compute_layout_impl(args...);
}
constexpr layout_type default_assignable_layout(layout_type l) noexcept
{
return (l == layout_type::row_major || l == layout_type::column_major) ?
l : XTENSOR_DEFAULT_LAYOUT;
}
}
#endif

2146
vendor/xtensor/include/xtensor/xmath.hpp vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,110 @@
/***************************************************************************
* 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_NOALIAS_HPP
#define XTENSOR_NOALIAS_HPP
#include "xsemantic.hpp"
namespace xt
{
template <class A>
class noalias_proxy
{
public:
noalias_proxy(A& a) noexcept;
template <class E>
A& operator=(const xexpression<E>& e);
template <class E>
A& operator+=(const xexpression<E>& e);
template <class E>
A& operator-=(const xexpression<E>& e);
template <class E>
A& operator*=(const xexpression<E>& e);
template <class E>
A& operator/=(const xexpression<E>& e);
template <class E>
A& operator%=(const xexpression<E>& e);
private:
A& m_array;
};
template <class A>
noalias_proxy<A> noalias(A& a) noexcept;
/********************************
* noalias_proxy implementation *
********************************/
template <class A>
inline noalias_proxy<A>::noalias_proxy(A& a) noexcept
: m_array(a)
{
}
template <class A>
template <class E>
inline A& noalias_proxy<A>::operator=(const xexpression<E>& e)
{
return m_array.assign(e);
}
template <class A>
template <class E>
inline A& noalias_proxy<A>::operator+=(const xexpression<E>& e)
{
return m_array.plus_assign(e);
}
template <class A>
template <class E>
inline A& noalias_proxy<A>::operator-=(const xexpression<E>& e)
{
return m_array.minus_assign(e);
}
template <class A>
template <class E>
inline A& noalias_proxy<A>::operator*=(const xexpression<E>& e)
{
return m_array.multiplies_assign(e);
}
template <class A>
template <class E>
inline A& noalias_proxy<A>::operator/=(const xexpression<E>& e)
{
return m_array.divides_assign(e);
}
template <class A>
template <class E>
inline A& noalias_proxy<A>::operator%=(const xexpression<E>& e)
{
return m_array.modulus_assign(e);
}
template <class A>
inline noalias_proxy<A> noalias(A& a) noexcept
{
return noalias_proxy<A>(a);
}
}
#endif

477
vendor/xtensor/include/xtensor/xnorm.hpp vendored Normal file
View file

@ -0,0 +1,477 @@
/***************************************************************************
* Copyright (c) 2017, Ullrich Koethe *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#ifndef XTENSOR_NORM_HPP
#define XTENSOR_NORM_HPP
#include <cmath>
// std::abs(int) prior to C++ 17
#include <complex>
#include <cstdlib>
#include "xconcepts.hpp"
#include "xmath.hpp"
#include "xoperation.hpp"
#include "xutils.hpp"
namespace xt
{
template <class X>
using disable_evaluation_strategy = std::enable_if_t<!std::is_base_of<evaluation_strategy::base, std::decay_t<X>>::value, int>;
/*************************************
* norm functions for built-in types *
*************************************/
///@cond DOXYGEN_INCLUDE_SFINAE
#define XTENSOR_DEFINE_SIGNED_NORMS(T) \
inline auto \
norm_lp(T t, double p) noexcept \
{ \
using rt = decltype(std::abs(t)); \
return p == 0.0 \
? static_cast<rt>(t != 0) \
: std::abs(t); \
} \
inline auto \
norm_lp_to_p(T t, double p) noexcept \
{ \
using rt = real_promote_type_t<T>; \
return p == 0.0 \
? static_cast<rt>(t != 0) \
: std::pow(static_cast<rt>(std::abs(t)), \
static_cast<rt>(p)); \
} \
inline size_t norm_l0(T t) noexcept { return (t != 0); } \
inline auto norm_l1(T t) noexcept { return std::abs(t); } \
inline auto norm_l2(T t) noexcept { return std::abs(t); } \
inline auto norm_linf(T t) noexcept { return std::abs(t); } \
inline auto norm_sq(T t) noexcept { return t * t; }
XTENSOR_DEFINE_SIGNED_NORMS(signed char)
XTENSOR_DEFINE_SIGNED_NORMS(short)
XTENSOR_DEFINE_SIGNED_NORMS(int)
XTENSOR_DEFINE_SIGNED_NORMS(long)
XTENSOR_DEFINE_SIGNED_NORMS(long long)
XTENSOR_DEFINE_SIGNED_NORMS(float)
XTENSOR_DEFINE_SIGNED_NORMS(double)
XTENSOR_DEFINE_SIGNED_NORMS(long double)
#undef XTENSOR_DEFINE_SIGNED_NORMS
#define XTENSOR_DEFINE_UNSIGNED_NORMS(T) \
inline T norm_lp(T t, double p) noexcept \
{ \
return p == 0.0 \
? (t != 0) \
: t; \
} \
inline auto \
norm_lp_to_p(T t, double p) noexcept \
{ \
using rt = real_promote_type_t<T>; \
return p == 0.0 \
? static_cast<rt>(t != 0) \
: std::pow(static_cast<rt>(t), \
static_cast<rt>(p)); \
} \
inline T norm_l0(T t) noexcept { return t != 0 ? 1 : 0; } \
inline T norm_l1(T t) noexcept { return t; } \
inline T norm_l2(T t) noexcept { return t; } \
inline T norm_linf(T t) noexcept { return t; } \
inline auto norm_sq(T t) noexcept { return t * t; }
XTENSOR_DEFINE_UNSIGNED_NORMS(unsigned char)
XTENSOR_DEFINE_UNSIGNED_NORMS(unsigned short)
XTENSOR_DEFINE_UNSIGNED_NORMS(unsigned int)
XTENSOR_DEFINE_UNSIGNED_NORMS(unsigned long)
XTENSOR_DEFINE_UNSIGNED_NORMS(unsigned long long)
#undef XTENSOR_DEFINE_UNSIGNED_NORMS
/***********************************
* norm functions for std::complex *
***********************************/
/**
* \brief L0 pseudo-norm of a complex number.
* Equivalent to <tt>t != 0</tt>.
*/
template <class T>
inline uint64_t norm_l0(const std::complex<T>& t) noexcept
{
return t.real() != 0 || t.imag() != 0;
}
/**
* \brief L1 norm of a complex number.
*/
template <class T>
inline auto norm_l1(const std::complex<T>& t) noexcept
{
return std::abs(t.real()) + std::abs(t.imag());
}
/**
* \brief L2 norm of a complex number.
* Equivalent to <tt>std::abs(t)</tt>.
*/
template <class T>
inline auto norm_l2(const std::complex<T>& t) noexcept
{
return std::abs(t);
}
/**
* \brief Squared norm of a complex number.
* Equivalent to <tt>std::norm(t)</tt> (yes, the C++ standard really defines
* <tt>norm()</tt> to compute the squared norm).
*/
template <class T>
inline auto norm_sq(const std::complex<T>& t) noexcept
{
return std::norm(t);
}
/**
* \brief L-infinity norm of a complex number.
*/
template <class T>
inline auto norm_linf(const std::complex<T>& t) noexcept
{
return (std::max)(std::abs(t.real()), std::abs(t.imag()));
}
/**
* \brief p-th power of the Lp norm of a complex number.
*/
template <class T>
inline auto norm_lp_to_p(const std::complex<T>& t, double p) noexcept
{
using rt = decltype(std::pow(std::abs(t.real()), static_cast<T>(p)));
return p == 0
? static_cast<rt>(t.real() != 0 || t.imag() != 0)
: std::pow(std::abs(t.real()), static_cast<T>(p)) +
std::pow(std::abs(t.imag()), static_cast<T>(p));
}
/**
* \brief Lp norm of a complex number.
*/
template <class T>
inline auto norm_lp(const std::complex<T>& t, double p) noexcept
{
return p == 0
? norm_lp_to_p(t, p)
: std::pow(norm_lp_to_p(t, p), 1.0 / p);
}
/***********************************
* norm functions for xexpressions *
***********************************/
#ifdef X_OLD_CLANG
#define XTENSOR_NORM_FUNCTION_AXES(NAME) \
template <class E, class I, class EVS = DEFAULT_STRATEGY_REDUCERS> \
inline auto NAME(E&& e, std::initializer_list<I> axes, EVS es = EVS()) noexcept \
{ \
using axes_type = std::vector<typename std::decay_t<E>::size_type>; \
return NAME(std::forward<E>(e), xtl::forward_sequence<axes_type>(axes), es); \
}
#else
#define XTENSOR_NORM_FUNCTION_AXES(NAME) \
template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS> \
inline auto NAME(E&& e, const I(&axes)[N], EVS es = EVS()) noexcept \
{ \
using axes_type = std::array<typename std::decay_t<E>::size_type, N>; \
return NAME(std::forward<E>(e), xtl::forward_sequence<axes_type>(axes), es); \
}
#endif
#define XTENSOR_EMPTY
#define XTENSOR_COMMA ,
#define XTENSOR_NORM_FUNCTION(NAME, RESULT_TYPE, REDUCE_EXPR, REDUCE_OP, MERGE_FUNC) \
template <class E, class X, class EVS = DEFAULT_STRATEGY_REDUCERS, \
class = disable_evaluation_strategy<X>> \
inline auto NAME(E&& e, X&& axes, EVS es = EVS()) noexcept \
{ \
using value_type = typename std::decay_t<E>::value_type; \
using result_type = RESULT_TYPE; \
\
auto reduce_func = [](result_type const& r, value_type const& v) { \
return REDUCE_EXPR(r REDUCE_OP NAME(v)); \
}; \
auto init_func = [](value_type const& v) { \
return NAME(v); \
}; \
return reduce(make_xreducer_functor(std::move(reduce_func), \
std::move(init_func), \
MERGE_FUNC<result_type>()), \
std::forward<E>(e), std::forward<X>(axes), es); \
} \
\
template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, \
XTENSOR_REQUIRE<is_xexpression<E>::value>> \
inline auto NAME(E&& e, EVS es = EVS()) noexcept \
{ \
return NAME(std::forward<E>(e), arange(e.dimension()), es); \
} \
XTENSOR_NORM_FUNCTION_AXES(NAME)
XTENSOR_NORM_FUNCTION(norm_l0, unsigned long long, XTENSOR_EMPTY, +, std::plus)
XTENSOR_NORM_FUNCTION(norm_l1, big_promote_type_t<value_type>, XTENSOR_EMPTY, +, std::plus)
XTENSOR_NORM_FUNCTION(norm_sq, big_promote_type_t<value_type>, XTENSOR_EMPTY, +, std::plus)
XTENSOR_NORM_FUNCTION(norm_linf, decltype(norm_linf(std::declval<value_type>())), (std::max<result_type>), XTENSOR_COMMA, math::maximum)
#undef XTENSOR_EMPTY
#undef XTENSOR_COMMA
#undef XTENSOR_NORM_FUNCTION
#undef XTENSOR_NORM_FUNCTION_AXES
/// @endcond
/**
* @ingroup red_functions
* @brief L0 (count) pseudo-norm of an array-like argument over given axes.
*
* Returns an \ref xreducer for the L0 pseudo-norm of the elements across given \em axes.
* @param e an \ref xexpression
* @param axes the axes along which the norm is computed (optional)
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
* When no axes are provided, the norm is calculated over the entire array. In this case,
* the reducer represents a scalar result, otherwise an array of appropriate dimension.
*/
template <class E, class X, class EVS, class>
auto norm_l0(E&& e, X&& axes, EVS es) noexcept;
/**
* @ingroup red_functions
* @brief L1 norm of an array-like argument over given axes.
*
* Returns an \ref xreducer for the L1 norm of the elements across given \em axes.
* @param e an \ref xexpression
* @param axes the axes along which the norm is computed (optional)
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
* When no axes are provided, the norm is calculated over the entire array. In this case,
* the reducer represents a scalar result, otherwise an array of appropriate dimension.
*/
template <class E, class X, class EVS, class>
auto norm_l1(E&& e, X&& axes, EVS es) noexcept;
/**
* @ingroup red_functions
* @brief Squared L2 norm of an array-like argument over given axes.
*
* Returns an \ref xreducer for the squared L2 norm of the elements across given \em axes.
* @param e an \ref xexpression
* @param axes the axes along which the norm is computed (optional)
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
* When no axes are provided, the norm is calculated over the entire array. In this case,
* the reducer represents a scalar result, otherwise an array of appropriate dimension.
*/
template <class E, class X, class EVS, class>
auto norm_sq(E&& e, X&& axes, EVS es) noexcept;
/**
* @ingroup red_functions
* @brief L2 norm of a scalar or array-like argument.
* @param e an xexpression
* @param es evaluation strategy to use (lazy (default), or immediate)
* For scalar types: implemented as <tt>abs(t)</tt><br>
* otherwise: implemented as <tt>sqrt(norm_sq(t))</tt>.
*/
template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTENSOR_REQUIRE<is_xexpression<E>::value>>
inline auto norm_l2(E&& e, EVS es = EVS()) noexcept
{
using std::sqrt;
return sqrt(norm_sq(std::forward<E>(e), es));
}
/**
* @ingroup red_functions
* @brief L2 norm of an array-like argument over given axes.
*
* Returns an \ref xreducer for the L2 norm of the elements across given \em axes.
* @param e an \ref xexpression
* @param es evaluation strategy to use (lazy (default), or immediate)
* @param axes the axes along which the norm is computed
* @return an \ref xreducer (specifically: <tt>sqrt(norm_sq(e, axes))</tt>) (or xcontainer, depending on evaluation strategy)
*/
template <class E, class X, class EVS = DEFAULT_STRATEGY_REDUCERS,
XTENSOR_REQUIRE<is_xexpression<E>::value>, class = disable_evaluation_strategy<X>>
inline auto norm_l2(E&& e, X&& axes, EVS es = EVS()) noexcept
{
return sqrt(norm_sq(std::forward<E>(e), std::forward<X>(axes), es));
}
#ifdef X_OLD_CLANG
template <class E, class I, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_l2(E&& e, std::initializer_list<I> axes, EVS es = EVS()) noexcept
{
using axes_type = std::vector<typename std::decay_t<E>::size_type>;
return sqrt(norm_sq(std::forward<E>(e), xtl::forward_sequence<axes_type>(axes), es));
}
#else
template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_l2(E&& e, const I (&axes)[N], EVS es = EVS()) noexcept
{
using axes_type = std::array<typename std::decay_t<E>::size_type, N>;
return sqrt(norm_sq(std::forward<E>(e), xtl::forward_sequence<axes_type>(axes), es));
}
#endif
/**
* @ingroup red_functions
* @brief Infinity (maximum) norm of an array-like argument over given axes.
*
* Returns an \ref xreducer for the infinity norm of the elements across given \em axes.
* @param e an \ref xexpression
* @param axes the axes along which the norm is computed (optional)
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
* When no axes are provided, the norm is calculated over the entire array. In this case,
* the reducer represents a scalar result, otherwise an array of appropriate dimension.
*/
template <class E, class X, class EVS, class>
auto norm_linf(E&& e, X&& axes, EVS es) noexcept;
/**
* @ingroup red_functions
* @brief p-th power of the Lp norm of an array-like argument over given axes.
*
* Returns an \ref xreducer for the p-th power of the Lp norm of the elements across given \em axes.
* @param e an \ref xexpression
* @param p
* @param axes the axes along which the norm is computed (optional)
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
* When no axes are provided, the norm is calculated over the entire array. In this case,
* the reducer represents a scalar result, otherwise an array of appropriate dimension.
*/
template <class E, class X, class EVS = DEFAULT_STRATEGY_REDUCERS, class = disable_evaluation_strategy<X>>
inline auto norm_lp_to_p(E&& e, double p, X&& axes, EVS es = EVS()) noexcept
{
using value_type = typename std::decay_t<E>::value_type;
using result_type = norm_type_t<std::decay_t<E>>;
auto reduce_func = [p](result_type const& r, value_type const& v) {
return r + norm_lp_to_p(v, p);
};
auto init_func = [p](value_type const& v) {
return norm_lp_to_p(v, p);
};
return reduce(make_xreducer_functor(std::move(reduce_func), std::move(init_func), std::plus<result_type>()),
std::forward<E>(e), std::forward<X>(axes), es);
}
template <class E, XTENSOR_REQUIRE<is_xexpression<E>::value>, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_lp_to_p(E&& e, double p, EVS es = EVS()) noexcept
{
return norm_lp_to_p(std::forward<E>(e), p, arange(e.dimension()), es);
}
#ifdef X_OLD_CLANG
template <class E, class I, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_lp_to_p(E&& e, double p, std::initializer_list<I> axes, EVS es = EVS()) noexcept
{
using axes_type = std::vector<typename std::decay_t<E>::size_type>;
return norm_lp_to_p(std::forward<E>(e), p, xtl::forward_sequence<axes_type>(axes), es);
}
#else
template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_lp_to_p(E&& e, double p, const I (&axes)[N], EVS es = EVS()) noexcept
{
using axes_type = std::array<typename std::decay_t<E>::size_type, N>;
return norm_lp_to_p(std::forward<E>(e), p, xtl::forward_sequence<axes_type>(axes), es);
}
#endif
/**
* @ingroup red_functions
* @brief Lp norm of an array-like argument over given axes.
*
* Returns an \ref xreducer for the Lp norm (p != 0) of the elements across given \em axes.
* @param e an \ref xexpression
* @param p
* @param axes the axes along which the norm is computed (optional)
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
* When no axes are provided, the norm is calculated over the entire array. In this case,
* the reducer represents a scalar result, otherwise an array of appropriate dimension.
*/
template <class E, class X, class EVS = DEFAULT_STRATEGY_REDUCERS, class = disable_evaluation_strategy<X>>
inline auto norm_lp(E&& e, double p, X&& axes, EVS es = EVS())
{
XTENSOR_PRECONDITION(p != 0,
"norm_lp(): p must be nonzero, use norm_l0() instead.");
return pow(norm_lp_to_p(std::forward<E>(e), p, std::forward<X>(axes), es), 1.0 / p);
}
template <class E, XTENSOR_REQUIRE<is_xexpression<E>::value>, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_lp(E&& e, double p, EVS es = EVS())
{
return norm_lp(std::forward<E>(e), p, arange(e.dimension()), es);
}
#ifdef X_OLD_CLANG
template <class E, class I, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_lp(E&& e, double p, std::initializer_list<I> axes, EVS es = EVS())
{
using axes_type = std::vector<typename std::decay_t<E>::size_type>;
return norm_lp(std::forward<E>(e), p, xtl::forward_sequence<axes_type>(axes), es);
}
#else
template <class E, class I, std::size_t N, class EVS = DEFAULT_STRATEGY_REDUCERS>
inline auto norm_lp(E&& e, double p, const I (&axes)[N], EVS es = EVS())
{
using axes_type = std::array<typename std::decay_t<E>::size_type, N>;
return norm_lp(std::forward<E>(e), p, xtl::forward_sequence<axes_type>(axes), es);
}
#endif
/**
* @ingroup red_functions
* @brief Induced L1 norm of a matrix.
*
* Returns an \ref xreducer for the induced L1 norm (i.e. the maximum of the L1 norms of e's columns).
* @param e a 2D \ref xexpression
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
*/
template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTENSOR_REQUIRE<is_xexpression<E>::value>>
inline auto norm_induced_l1(E&& e, EVS es = EVS())
{
XTENSOR_PRECONDITION(e.dimension() == 2,
"norm_induced_l1(): only applicable to matrices (e.dimension() must be 2).");
return norm_linf(norm_l1(std::forward<E>(e), {0}, es), es);
}
/**
* @ingroup red_functions
* @brief Induced L-infinity norm of a matrix.
*
* Returns an \ref xreducer for the induced L-infinity norm (i.e. the maximum of the L1 norms of e's rows).
* @param e a 2D \ref xexpression
* @param es evaluation strategy to use (lazy (default), or immediate)
* @return an \ref xreducer (or xcontainer, depending on evaluation strategy)
*/
template <class E, class EVS = DEFAULT_STRATEGY_REDUCERS, XTENSOR_REQUIRE<is_xexpression<E>::value>>
inline auto norm_induced_linf(E&& e, EVS es = EVS())
{
XTENSOR_PRECONDITION(e.dimension() == 2,
"norm_induced_linf(): only applicable to matrices (e.dimension() must be 2).");
return norm_linf(norm_l1(std::forward<E>(e), {1}, es), es);
}
} // namespace xt
#endif

Some files were not shown because too many files have changed in this diff Show more